蓝桥杯嵌入式——第十届蓝桥杯嵌入式国赛
Posted FILWY_M
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了蓝桥杯嵌入式——第十届蓝桥杯嵌入式国赛相关的知识,希望对你有一定的参考价值。
蓝桥杯嵌入式——第十届蓝桥杯嵌入式国赛
一、赛题
上一次做了第十一届的国赛赛题,感觉很容易。然后这两天做了第十届的赛题,感觉第十届的赛题是十一届难度的两倍。这一届的赛题考察的内容特别多,并且逻辑方面相比十一届也是难度大一些的,所以正式比赛的时候,如果不是特别熟悉,还有可能不能把全部的功能都实现。这一届考察的内容大致如下:
LED |
---|
LCD,LCD的高亮显示 |
独立按键,长按 |
双通道ADC转换 |
定时器的输入捕获,检测占空比 |
EEPROM数据的读写,使用EEPEOM存放16位数据 |
DS18B20,精确到两位小数 |
USAR串口的收发 |
数码管显示 |
这一届的题目还是挺有意义的,难度有一丢丢大,拿来赛前练手挺好的。
二、CubeMX模块配置
-
DMA的配置
用到一个DMA,用于ADC2的双通道转换
-
GPIO的配置
-
中断的配置
打开相应的中断,注意图上标红的地方,要关闭ADC的DMA中断,否则会不断的进入中断,打断CPU的执行。 -
ADC2的配置
主要注意一下,我们用到了ADC2的两个通道,所以这里我们使用了DMA,每个通道转换完成的数据就会由DMA直接将对应的数据存放到相应的存储器中,所以我们后面只需要读取对应的存储器的值即可。如果不使用DMA也是可以的, 要麻烦一点,网上有很多资料,这里就不多说。
ADC配置需要注意的是,要先添加DMA,然后才能在ADC的参数设置中使能ADC DMA转换,除此之外还要使能扫描转换,以及连续转换模式,否则只能自动转换一次ADC的数据,后面的每一次都要重新使能。
-
定时器输入捕获
其中81 - 1 分频是将定时器的时钟配置为1MHz。因为在系统时钟为80MHz。重转载计数器一定要设置为最大,对于16位的寄存器最大值也就是65535。
-
串口的配置
三、部分模块代码
- 数码管
#define SEG_H HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_SET)
#define SEG_L HAL_GPIO_WritePin(GPIOA,GPIO_PIN_1,GPIO_PIN_RESET)
#define RCK_H HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET)
#define RCK_L HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_RESET)
#define SCK_H HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET)
#define SCK_L HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_RESET)
uint
8_t seg_buf[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x39,0x77,0x00};
void seg_set(uint8_t seg1,uint8_t seg2,uint8_t seg3)
{
uint32_t seg = (seg_buf[seg3] << 16) | (seg_buf[seg2] << 8) | seg_buf[seg1];
uint8_t i;
for(i = 0; i < 24; i++)
{
if(seg & 0x800000)
SEG_H;
else
SEG_L;
seg <<= 1;
SCK_H;
SCK_L;
}
RCK_H;
RCK_L;
}
- LCD高亮显示
关于高亮显示的具体原理可以参考我的另一篇博客https://blog.csdn.net/qq_43715171/article/details/115238360
void highlight(u8 Line, u8 *ptr)
{
u32 i = 0;
u16 refcolumn = 319;//319;
while ((*ptr != 0) && (i < 20)) // 20
{
if(((Line == Line3 && select == 0) || (Line == Line4 && select == 1)) && (i > 0 && i < 18))
LCD_SetBackColor(Yellow);
else
LCD_SetBackColor(Black);
LCD_DisplayChar(Line, refcolumn, *ptr);
refcolumn -= 16;
ptr++;
i++;
}
}
- 按键的长按检测
这里要解释一下,下面这一段程序是放在key_scan()里面,10ms扫描一次。
以B3为例,假设此前是松开状态,如果B3按下,key_cnt就加1,加到90的时候,就触发长按,也就是90*10 = 900ms。然后将key_cnt设置为80,等到下一次到达90的时候,经过了(90-80)*10 = 100ms,也就是长按触发之后,没100ms将temp_upper_temp加1。如果没有按键按下要将key_cnt清零,以等待下一次的检测。
if(key_state == B3 && interface == PARA && select == 0 && ++key_cnt == 90)
{
key_cnt = 80;
if(temp_upper_temp < 40)
temp_upper_temp++;
}
if(key_state == B4 && interface == PARA && select == 0 && ++key_cnt == 90)
{
key_cnt = 80;
if(temp_upper_temp > 20)
temp_upper_temp--;
}
if(key_state == 0)
{
key_cnt = 0;
}
- 占空比检测的代码
核心程序就在这里回调函数中了。
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim -> Instance == TIM3)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_2)
{
if(CaptureNumber == 0)
{
/* Get the Input Capture value */
IC3ReadValue1 = TIM3->CCR2;
CaptureNumber = 1;
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_FALLING);
}
else if(CaptureNumber == 1)
{
/* Get the Input Capture value */
IC3ReadValue2 = TIM3->CCR2;
CaptureNumber = 2;
__HAL_TIM_SET_CAPTUREPOLARITY(htim,TIM_CHANNEL_2,TIM_INPUTCHANNELPOLARITY_RISING);
if (IC3ReadValue2 > IC3ReadValue1)
{
Capture_High = (IC3ReadValue2 - IC3ReadValue1);
}
else
{
Capture_High = ((0xFFFF - IC3ReadValue1) + IC3ReadValue2);
}
IC3ReadValue1 = IC3ReadValue2;
}
else if(CaptureNumber == 2)
{
/* Get the Input Capture value */
IC3ReadValue2 = TIM3->CCR2;
CaptureNumber = 0;
if (IC3ReadValue2 > IC3ReadValue1)
{
Capture_Low = (IC3ReadValue2 - IC3ReadValue1);
}
else
{
Capture_Low = ((0xFFFF - IC3ReadValue1) + IC3ReadValue2);
}
/* Frequency computation */
TIM3Freq = (uint32_t) 1000000 / (Capture_Low + Capture_High);
TIM3Duty = Capture_High * 1.0 / (Capture_Low + Capture_High);
pwm2 = TIM3Duty;
}
}
}
}
- 串口的不定长数据接收以及数据的处理
在我最近的一篇博客中,比较详细的讲解了使用IDLE+RXNE实现的串口的不定长数据接收 ,这里就不展开讲解啦。
https://blog.csdn.net/qq_43715171/article/details/117132151
数据的处理代码如下:
void usart_proc(void)
{
if(channel_x == A01 && a01 > pwm2 * 3.3 && usart_flag)
{
usart_flag = 0;
printf("$%.2f\\r\\n",temperature);
}
else if(channel_x == A02 && a02 > pwm2 * 3.3 && usart_flag)
{
usart_flag = 0;
printf("$%.2f\\r\\n",temperature);
}
if((channel_x == A01 && a01 <= pwm2 * 3.3) || (channel_x == A02 && a02 <= pwm2 * 3.3))
{
usart_flag = 0;
usart_tick = 0;
}
if(UART1_IDLE_Flag)
{
UART1_IDLE_Flag = 0;
// memset(lcd_str,0,sizeof(lcd_str));
// snprintf((char*)lcd_str,20,"%s",RxBuffer);
// LCD_DisplayStringLine(Line9, lcd_str);
if(strcmp((const char *)RxBuffer,"ST\\r\\n") == 0)
{
printf("$%.2f\\r\\n",temperature);
}
else if(strcmp((const char *)RxBuffer,"PARA\\r\\n") == 0)
{
printf("#%d,AO%d\\r\\n",temp_upper,channel_x + 1);
}
memset(RxBuffer,0,sizeof(RxBuffer));
RxCounter = 0;
}
}
四、完整代码下载
以上是关于蓝桥杯嵌入式——第十届蓝桥杯嵌入式国赛的主要内容,如果未能解决你的问题,请参考以下文章