前言
上一次写的文章(蓝桥杯备战(1)——第六届蓝桥杯嵌入式省赛赛题实战)由于经验不足,在写文章的时候排版不是特别好,这回仔细改进了一下排版,应该会比上次好一些。还有就是,我是个嵌入式菜鸟,写的东西有可能会出现一些问题,请大家多多包涵,并在评论区区指出。如果感觉写得还阔以,可以动动小手点个赞(_)。本次仍然是基于CT117E-M4平台,用的CUBEMX与keil开发。
一、第七届蓝桥杯嵌入式省赛赛题展示
第七届省赛赛题第一遍看完以后就有了大致的思路,题目难度不大,很适合练手熟悉熟悉板子。
二、程序流程图
根据题目所要求的功能,我同样绘制了一个程序流程图作为编程参考。
题目大体就是这个流程,难点就是按键判断这块,逻辑能力差点的人(比如我)可能就会蒙圈了。
三、配置所需外设
其实这个在读完赛题以后基本上就确定完了,都是一些常用的外设,例如GPIO,串口,ADC什么的。这里我还是上一个CUBEMX的配置图。
这个配置是很简单的,只需要配置好串口和ADC,外加几个IO口就搞定了,看着板子的手册配置对应引脚即可。需要注意要把串口中断打开。
四、程序编写
这里我按照题目的各个要求的顺序来进行编程。我给出的都是主要代码,整个工程文件的下载链接在文末给出。
1、液位检测
液位测量其实就是根据ADC的值来乘K值算出液位高度,同时要求ADC的值有滤波的过程。K值我相信大多数人都会算,就是100/3.3=30.303。滤波算法我用的是最最偷懒最最方便的求平均值,10个数据一组,求平均值就算滤波了(还有其他很多更好的滤波算法,只是我太懒了),同时将处理玩的ADC的值保留两位小数,不然出来的液面高度会不稳定。液面等级就是比大小,这里不多说了。
代码如下
adc=get_ADC_av()*3.3/4096;//求ADC的值
adc = change_2(adc);//保留两位小时
height=adc*k;//计算液面高度
sprintf((char *)str," ADC:%.2f",adc);
LCD_DisplayStringLine(Line4,str);
sprintf((char *)str1," Height:%.2f",height);
LCD_DisplayStringLine(Line2,str1);
if(height<=h1)
{
LCD_DisplayStringLine(Line6," Level:0");
l=0;//l表示液面高度等级
}
if(height<=h2 && height >h1)
{
LCD_DisplayStringLine(Line6," Level:1");
l=1;
}
if(height<=h3 && height>h2)
{
LCD_DisplayStringLine(Line6," Level:2");
l=2;
}
if(height>h3)
{
LCD_DisplayStringLine(Line6," Level:3");
l=3;
}
uint16_t get_ADC(void)
{
uint16_t adc_data;
HAL_ADC_Start(&hadc2);
adc_data=HAL_ADC_GetValue(&hadc2);
return adc_data;
}
uint16_t get_ADC_av(void)//取十个ADC的值并且求其平均值
{
int t=0;
uint16_t data=0;
while(t++!=10)
{
data = data+get_ADC();
}
data = data/10;
return data;
}
float change_2(float num)//将ADC的值变成两位小数
{
int temp;
temp = (int)(num*100);
num = (float)(temp/100.0);
return num;
}
2、液位阈值设定
阈值设定,只需设置三个变量就行,难点就是处理按键之间的逻辑关系。在修改完以后要将阈值写入E2PROM中,同时在程序进入循环前先读一次E2PROM的数据。这里要注意:==** 数据写入E2PROM后要延迟一会才可以在写入下一条数据,这是由于I2C通信有应答时间。 **==时间不用太长,我这里给的是10毫秒。
代码如下
h1_e = x24c02_read(0);//向E2PROM读数据
HAL_Delay(10);
h2_e = x24c02_read(1);
HAL_Delay(10);
h3_e = x24c02_read(2);
h1 = (int)h1_e;
h2 = (int)h2_e;
h3 = (int)h3_e;
int count=0;
if(HAL_GPIO_ReadPin(SETTING_GPIO_Port,SETTING_Pin)==0)//判断B2是否按下
{
HAL_Delay(50);///消抖
if(HAL_GPIO_ReadPin(SETTING_GPIO_Port,SETTING_Pin)==0)
{
HAL_Delay(500);//防止按久了跳回去
LCD_Clear(White);
LCD_DisplayStringLine(Line0," Parameter Setup");
LCD_SetTextColor(Green);
LCD_DisplayStringLine(Line2," Threshold1:10cm");
LCD_SetTextColor(Black);
LCD_DisplayStringLine(Line4," Threshold2:25cm");
LCD_DisplayStringLine(Line6," Threshold3:30cm");
while(HAL_GPIO_ReadPin(SETTING_GPIO_Port,SETTING_Pin)==1)//如果B2按下,就返回测量界面
{
if(HAL_GPIO_ReadPin(CHANGE_GPIO_Port,CHANGE_Pin)==0)//判断B3是否按下
{
HAL_Delay(100);
if(HAL_GPIO_ReadPin(CHANGE_GPIO_Port,CHANGE_Pin)==0)
{
count = count + 1;
if(count == 3)
{
count = 0;
}
}
}
if(count == 0)
{
LCD_SetTextColor(Green);
LCD_DisplayStringLine(Line2,str2);
LCD_SetTextColor(Black);
LCD_DisplayStringLine(Line4,str3);
LCD_DisplayStringLine(Line6,str4);
}
if(count == 1)
{
LCD_SetTextColor(Black);
LCD_DisplayStringLine(Line2,str2);
LCD_SetTextColor(Green);
LCD_DisplayStringLine(Line4,str3);
LCD_SetTextColor(Black);
LCD_DisplayStringLine(Line6,str4);
}
if(count == 2)
{
LCD_SetTextColor(Black);
LCD_DisplayStringLine(Line2,str2);
LCD_DisplayStringLine(Line4,str3);
LCD_SetTextColor(Green);
LCD_DisplayStringLine(Line6,str4);
}
if(HAL_GPIO_ReadPin(UP_GPIO_Port,UP_Pin)==0)
{
HAL_Delay(100);
if(HAL_GPIO_ReadPin(UP_GPIO_Port,UP_Pin)==0)
{
if(count == 0)
{
h1 = h1+5;
}
if(count == 1)
{
h2 = h2+5;
}
if(count == 2)
{
h3 = h3+5;
}
}
}
if(HAL_GPIO_ReadPin(DOWN_GPIO_Port,DOWN_Pin)==0)//判断B4是否按下
{
HAL_Delay(100);
if(HAL_GPIO_ReadPin(DOWN_GPIO_Port,DOWN_Pin)==0)
{
if(count == 0)
{
h1 = h1-5;
}
if(count == 1)
{
h2 = h2-5;
}
if(count == 2)
{
h3 = h3-5;
}
x24c02_write(0,(uint8_t)h1);//将阈值数据写入E2PROM中
HAL_Delay(10);
x24c02_write(1,(uint8_t)h2);
HAL_Delay(10);
x24c02_write(2,(uint8_t)h3);
}
}
sprintf((char *)str2," Threshold1:%dcm",h1);
sprintf((char *)str3," Threshold2:%dcm",h2);
sprintf((char *)str4," Threshold3:%dcm",h3);
}
LCD_Clear(White);
LCD_SetTextColor(Black);
LCD_DisplayStringLine(Line0," Liquid Level");
x24c02_write(0,(uint8_t)h1);
HAL_Delay(10);
x24c02_write(1,(uint8_t)h2);
HAL_Delay(10);
x24c02_write(2,(uint8_t)h3);
return ;
}
}
3、串口查询与输出功能
这个我就不多说了,按要求处理好逻辑关系就行,直接上代码。
if(l > l_old)//液面等级降低
{
sprintf((char *)str7,"A:H%d+L%d+U\r\n",(int)height,l);
HAL_UART_Transmit(&huart1,str7,sizeof(str7),1000);
l_old = l;
l_c=1;//液面变化标志位,用于指示灯
}
if(l < l_old)
{
sprintf((char *)str8,"A:H%d+L%d+D\r\n",(int)height,l);
HAL_UART_Transmit(&huart1,str8,sizeof(str8),1000);
l_old = l;
l_c=1;
}
RX_State();
void RX_State(void)
{
HAL_UART_Receive_IT(&huart1,rx_buf,1);
if(rx_buf[0] == 'C')
{
sprintf((char *)str5,"C:H%d+L%d\r\n",(int)height,l);
HAL_UART_Transmit(&huart1,str5,sizeof(str5),1000);
memset(rx_buf,0,2); //rx_buf清零
r_c = 1;//串口接收字符标注位,用于指示灯
}
if(rx_buf[0] == 'S')
{
sprintf((char *)str6,"S:TL%d+TM%d+TH%d\r\n",h1,h2,h3);
HAL_UART_Transmit(&huart1,str6,sizeof(str6),1000);
memset(rx_buf,0,2);
r_c = 1;
}
}
4、状态指示
状态指示这边,用的是三个LED灯,这里其实用定时器是很好的,但是这个板子的定时器有点让我蒙,配置好调了好久但是一直不好使,看了例程,里面居然用的寄存器写而不是用HAL库写,难道用了定时器IO口控制要用寄存器写了吗?
因为水平不够(其实是太懒了),所以我只能用HAL_Delay()来做,处理好逻辑关系(这里逻辑关系有些复杂,大脑有些过载),但是还是让我磨出来了,上代码。
if(t1 == 20)//用于运行指示灯,闪烁间隔一秒
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
if(t1 == 40)//每1秒翻转一次
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
t1 = 0;
}
led_l();//液面变化指示灯
led_r();//串口接收指示灯
HAL_Delay(50);
void led_l(void)
{
if(l_c == 1)
{
t2++;
if(t2 == 4)//每0.2秒翻转一次
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
if(t2 == 8)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
t2 = 0;
t2_c++;//闪烁计数
}
if(t2_c == 5)
{
t2_c = 0;
l_c = 0;
t2 = 0;
}
}
}
void led_r(void)
{
if(r_c == 1)
{
t3++;
if(t3 == 4)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
if(t3 == 8)
{
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_10, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
t3 = 0;
t3_c++;
}
if(t3_c == 5)
{
t3_c = 0;
r_c = 0;
t3 = 0;
}
}
}
上面的都是主要代码,工程总体文件在文末的链接中给出,有需要的可以下载。
总结
做了第六届和第七届的赛题以后,对于板子也更加熟悉,但是仍然有一些外设没有搞明白(例如定时器,我一定要把这个定时器整明白的),也算是发现问题,我会在后面进一步地学习这个板子,用惯了祖传的C8T6一下换到这么高级的板子确实有些用不习惯。接下来就是做第八届的赛题了,加油!!
欢迎大家在下方留言,一起学习,一起进步。
这里再附上我的工程项目链接:第七届蓝桥杯嵌入式省赛赛题程序
文章评论