蓝桥杯嵌入式——第三届省赛题-“里程仪”

蓝桥杯嵌入式——第三届省赛题-“里程仪”

博主最近也是在从0开始学习蓝桥杯嵌入式,蓝桥杯各个模块的分析可以看我的博客,其中比较 重要的模块几乎都涉及到了,以及如何写初始化的代码,以及遇到的一些问题,基本上都做了解释,需要的话可以参考专栏https://blog.csdn.net/qq_43715171/category_10751749.html。说一点题外话,由于博主也是刚开始学习,所以在做配置的时候,会遇到一些小问题,这些小问题可能也是废了很久的时间才找到的,做一些总结,在以后写的时候,就会有印象了,一来自己避免自己以后再犯这些错误,二来可能有些朋友们也会遇到同样的问题,看一看就不会再自己找很久的错误了。

一、赛题分析

这应该是蓝桥杯嵌入式的首届赛题吧,赛题内容是设计一个里程仪。总体来说,没有什么难度,在逻辑部分也没有什么比较纠结的,在速度的转换方面注意一下就行了。如果写的过程中,如果基础掌握好了,各个模块的初始化都是基础如i2c,输入捕获,输出PWM,能够写出来没有错误的话,那基本上就不会存在什么问题了。

二、赛题总结

  1. 检测按键的上升沿下降沿,以及按键当前的状态
    检测按键的下降沿是&,上升沿是*rising_flag = (!key_temp) * (key_temp ^ key_state); falling_flag = key_temp & (key_temp ^ key_state);
#define key_read (GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) << 0) | \
									(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_8) << 1) | \
									(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1) << 2) | \
									(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_2) << 3)
void Key_Read(void)
{
    
    
	uint8_t key_temp = 0xf0;
	key_temp |= key_read;
	key_temp ^= 0xff;
	rising_flag = (!key_temp) * (key_temp ^ key_state);
	falling_flag = key_temp & (key_temp ^ key_state);
	key_state = key_temp;
}
  1. eeprom的读写函数
    根据数据手册里面的时序图直接调用函数写即可。在这里插入图片描述在这里插入图片描述
    需要注意的是,不要忘记在,main函数中,调用i2c的初始化的函数。
void Write_AT24C02(uint8_t add,uint8_t dat)
{
    
    
	I2CStart();
	I2CSendByte(0xA0);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}
uint8_t Read_AT24C02(uint8_t add)
{
    
    
	uint8_t dat;
	I2CStart();
	I2CSendByte(0xA0);
	I2CWaitAck();
	I2CSendByte(add);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xA1);
	I2CWaitAck();
	dat = I2CReceiveByte();
	I2CSendNotAck();
	I2CStop();
	
	return dat;
}

  1. 使用memset要包含头文件string.h
  2. 在赛题中要求输出0Hz,0Hz就是电平不发生变化,首先我想的是,把定时器3的中断关闭了,即TIM_ITConfig(TIM3, TIM_IT_CC1, DISABLE);但是我发现,只要关闭了定时器的中断之后,然后想要再打开就不行了,至于具体的原因我没有找到。于是我换了一种方法,直接关闭定时器TIM_Cmd(TIM3, DISABLE);来输出0Hz,要输出0Hz以上的方波的时候再打开TIM_Cmd(TIM3, ENABLE);
  3. 输入捕获的代码中,犯了一个很小的错误,导致测出来的方波的周期总是要高一倍,而我一直在定时器的时钟的频率上面找问题,又经过了很久之后,才发现是计数值清零的位置没有写对,下面就来分析一下。

/**
  * @brief  This function handles TIM2 global interrupt request.
  * @param  None
  * @retval None
  */
void TIM2_IRQHandler(void)
{
    
     
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) 
  {
    
    
    /* Clear TIM2 Capture compare interrupt pending bit */
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    Tim2_Update_Cnt++;
  }
	
  if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET) 
  {
    
    
		total_meter_now++;
    /* Clear TIM2 Capture compare interrupt pending bit */
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
    if(Time2_CaptureNumber == 0)
    {
    
    
      /* Get the Input Capture value */
      Time2_IC2ReadValue1 = TIM_GetCapture2(TIM2);
      Time2_CaptureNumber = 1;
    }
    else if(Time2_CaptureNumber == 1)
    {
    
    
      /* Get the Input Capture value */
      Time2_IC2ReadValue2 = TIM_GetCapture2(TIM2); 
      
      Time2_Capture = ( Tim2_Update_Cnt * (0xFFFF) + Time2_IC2ReadValue2 - Time2_IC2ReadValue1);
      
      /* Frequency computation */ 
      TIM2Freq = (uint32_t) ((SystemCoreClock * 1.0 / Time2_Capture) + 0.5);
      Time2_CaptureNumber = 0;
			Tim2_Update_Cnt = 0;
    }
  }
}

这是最开始的有一点小错误的代码,可以看到我把 Tim2_Update_Cnt = 0;放在了第二次检测到上升沿中。来模拟一遍是程序怎么运行的,首先第一次捕获到上升沿,此时Tim2_Update_Cnt = 0,然后第二次捕获到上升沿,这就是一个周期了,程序正常计数一个周期,然后此刻我们将Tim2_Update_Cnt 清零,然后下一次上升沿到来的时候,又认为是第一个上升沿(因为之前已经过了一个周期了所以就从头开始),这个时候Tim2_Update_Cnt没有清零,所以继续计时,在第二次上升沿的时候,表示一个周期完毕,将Tim2_Update_Cnt 清零了,可以发现,实际上是经过了两个周期,所以测出来的肯定要大一倍,那么正确的代码应该是把Tim2_Update_Cnt 在第一次检测到上升沿的时候,就清零了,就没有问题了。下面是正确的代码,实际上就是换了一下位置而已。


/**
  * @brief  This function handles TIM2 global interrupt request.
  * @param  None
  * @retval None
  */
void TIM2_IRQHandler(void)
{
    
     
	if(TIM_GetITStatus(TIM2, TIM_IT_Update) == SET) 
  {
    
    
    /* Clear TIM2 Capture compare interrupt pending bit */
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
    Tim2_Update_Cnt++;
  }
	
  if(TIM_GetITStatus(TIM2, TIM_IT_CC2) == SET) 
  {
    
    
		total_meter_now++;
    /* Clear TIM2 Capture compare interrupt pending bit */
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC2);
    if(Time2_CaptureNumber == 0)
    {
    
    
      /* Get the Input Capture value */
			Tim2_Update_Cnt = 0;
      Time2_IC2ReadValue1 = TIM_GetCapture2(TIM2);
      Time2_CaptureNumber = 1;
    }
    else if(Time2_CaptureNumber == 1)
    {
    
    
      /* Get the Input Capture value */
      Time2_IC2ReadValue2 = TIM_GetCapture2(TIM2); 
      
      Time2_Capture = ( Tim2_Update_Cnt * (0xFFFF) + Time2_IC2ReadValue2 - Time2_IC2ReadValue1);
      
      /* Frequency computation */ 
      TIM2Freq = (uint32_t) ((SystemCoreClock * 1.0 / Time2_Capture) + 0.5);
      Time2_CaptureNumber = 0;
    }
  }
}

三、代码

代码比较多,在这里就不贴出来了,可以直接去我的github或者码云上面看到,代码付有详细的注释。

GitHub

码云

猜你喜欢

转载自blog.csdn.net/qq_43715171/article/details/113571788