代码开源,Gitee自取
代码开源,Gitee自取
代码开源,Gitee自取
目录
0 前言
1 展示
1.1 源码
1.2 演示视频
1.3 题目展示
2 工程配置
3 资源配置&代码实现
3.1 定时器
3.2 液位检测
3.3 液位阈值设定
3.4 液位阈值设定
3.5 串口通信
3.6 LCD显示
3.7 LED显示
3.8 逻辑处理
3.9 main函数
原版
修改
4 电路设计
5 总结
0 前言
- 开发板:CT117E-M4(STM32G431RBT6)
- 软件环境:CubeMX + Keil5
- 涉及题目:第十三届蓝桥杯嵌入式省赛第二场真题
1 展示
1.1 源码
Gitee链接:
CSDN下载链接:https://download.csdn.net/download/weixin_63135906/89250289?spm=1001.2014.3001.5501
有需要的同学可以下载源码,对照本文说明使用!
1.2 演示视频
B站链接:
1.3 题目展示
考察内容:
LED、LCD、按键、ADC、RTC、E2PROM
需要用到的外设比较多,但是逻辑非常简单
2 工程配置
下载
使能HSE
失能LSE,LSE不需要配置,如果配置了,那么PC14、PC15就不能配置了,这两个引脚还要控制LED,这里有冲突,所以不能配置LSE!!!
GPIO
时钟设置
24M晶振,80M主频
24M晶振一定要设置好,不然会卡在初始化里一直过不去!!!
3 资源配置&代码实现
3.1 定时器
我这里先配置定时器,分析题目
找一个定时器专门用作按键扫描,再用一个定时器处理各种标志位~
定时器3配置
定时器4配置
我的工程里时钟都是配置了80M,这里预分频系数给80-1,计数值给10000-1
计算一下
80M / 80 / 10000 = 100Hz = 10ms
10ms进入一次中断
我用了定时器4中断做按键的扫描,定时器3中断做各种标志位的处理~
定时器中断回调函数
//定时器中断回调函数
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
static unsigned char tim4_count;
static unsigned char adc_cnt; //1S内检测ADC的标志位
static unsigned char led1_cnt, led2_cnt, led3_cnt;
//每次进入中断回调函数都会判断是哪个中断
if (htim->Instance == TIM3) //如果是定时器3的中断 - ADC - LED
{
adc_cnt ++ ;
if (adc_cnt >= 65) //650ms
{
flag.adc_readtime_ok = 1;
adc_cnt = 0;
}
// 处理LED状态指示
// 这里时间也没有自加,笨比……
if (++ led1_cnt >= 100) //1S
{
flag.LED1_State = ! flag.LED1_State;
led1_cnt = 0; //记得这里一定要软件复位啊,又忘记了,大聪明蛋!
}
if (++ led2_cnt >= 20) //0.2S
{
flag.LED2_State = ! flag.LED2_State;
if (flag.YW_IS_Change_forLED == 1) //如果液位变化
{
if (++ flag.LED2_ON_Cnt >= 10) //闪烁5次以上
{
flag.YW_IS_Change_forLED = 0;
flag.LED2_ON_Cnt = 0;
}
}
led2_cnt = 0;
}
if (++ led3_cnt >= 20) //0.2S
{
flag.LED3_State = ! flag.LED3_State;
if (flag.IS_Receive == 1) //收到查询指令了
{
if ( ++ flag.LED3_ON_Cnt >= 10) //闪烁5次以上
{
flag.IS_Receive = 0; //先清零接收标志位
flag.LED3_ON_Cnt = 0; //再清零闪烁次数,方便下一次闪烁指示
}
}
led3_cnt = 0;
}
}
if (htim->Instance == TIM4) //如果是定时器4的中断 - 按键
{
tim4_count++;
if (tim4_count >= 50) //500ms
{
//led指示灯
}
/* 按键 */
key[0].Key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0); //按键1 PB0
key[1].Key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); //按键2 PB1
key[2].Key_sta = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2); //按键3 PB2
key[3].Key_sta = HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); //按键4 PA0
//轮询按键
for(int i = 0; i < 4; i ++)
{
//状态机
switch (key[i].judge_sta)
{
case 0:
{
if (key[i].Key_sta == 0) //如果按键按下了
{
key[i].judge_sta = 1; //状态置1
key[i].key_time = 0; //按键按下的时间,初次按下先清零
}
}
break;
case 1: //按键消抖
{
if (key[i].Key_sta == 0) //如果状态保持按下
{
key[i].judge_sta = 2; //跳转到状态2
}
else
key[i].judge_sta = 0; //否则按键按下
}
break;
case 2:
{
if (key[i].Key_sta == 1) //如果按键松手
{
key[i].judge_sta = 0; //循环回到最开始
if (key[i].key_time < 70) //短按键
{
key[i].single_flag = 1; //短按标志位置0,松手确认按键按下
key[i].long_flag = 0; //长按标志位置0
key[i].key_time = 0;
}
}
else
{
key[i].key_time++; //按下的时候,一直10ms计时++
if (key[i].key_time >= 70)
{
key[i].long_flag = 1; //长按标志位置1
key[i].single_flag = 0; //短按标志位置0
}
}
}
break;
}
}
}
}
定时器4用作按键扫描,这里的代码是我学习B站up主01stdio的~可以实现长按和短按
定时器3的操作后面慢慢讲
在定时器中断回调函数里要注意计时变量加加,时间到了也要清零,很久不写代码就会忘记这些基本操作
3.2 液位检测
通过电位器R37模拟液位传感器输出电压信号,设备以 1 秒为间隔采集 R37 输出电压, 并与用户设定的液位阈值进行比较。假定液位高度与 R37 输出电压之间具有正比例关系: H = VR37*K,当 VR37=3.3V 时,对应液位高度为 100cm。通过液晶显示当前的液位高度、 传感器(R37)输出状态和液位等级,液位检测显示界面如图 1 所示:
注意题目描述的关键词:
- 1S为间隔采集R37电压
- 液位高度与 R37 输出电压之间具有正比例关系: H = VR37*K
- 当 VR37=3.3V 时,对应液位高度为 100cm
在定时器3的中断里,每隔650ms读取一次
每相隔650ms,将flag.adc_readtime_ok标志位置1
adc_cnt ++ ;
if (adc_cnt >= 65) //650ms
{
flag.adc_readtime_ok = 1;
adc_cnt = 0;
}
if (flag.adc_readtime_ok == 1)
{
Vol_1S = getADC(&hadc2); //ADC采集一次
height = (uint16_t)(Vol_1S / 3.3f * 100);
flag.adc_readtime_ok = 0;
}
ADC读取函数
配置ADC引脚 PB15、PB12
新建关于ADC的.c.h 保存在BSP中,名称不要为adc,稍微修改一下
避免和HAL库自带的adc.c重复 - 报错
使用方法:定时读取调用ADC读取,刷新不用太快,这里我给了800ms
double getADC(ADC_HandleTypeDef *pin)
{
uint adc; //声明变量,ADC读取出来的原始值
HAL_ADC_Start(pin); //开启ADC
adc = HAL_ADC_GetValue(pin); //read adc
return adc*3.355/4096; //12位的ADC电压采集
}
这里有必要说明一下,返回值应该是return adc*3.3/4096;
虽然理论上的ADC电压是3.3V,但是事实上并不会真正的测到3.3V(实测滑动变阻器的拉满采集的最大电压值一直都是3.25V,经过我实际测试了几块蓝桥杯官方的开发板,都是3.25V)那么如果照着正常公式计算的话,最后转换的高度最大将会是98而不会到达100,因为就会面临着向下取整的问题,所以也无法满足保持高电平的要求,这点如果使用机器阅卷的话,不知道会怎么判。
所以我这里修改代码补偿一下硬件问题。虽然……但是……我现在就这样干了
电压显示,没有写题目给的中文
// 显示ADC
sprintf(LCD_Show_text, " ADC: %.2fV ", Vol_1S);
LCD_DisplayStringLine(Line5, (uint8_t *)LCD_Show_text);
3.3 液位阈值设定
设备可设定三个液位阈值,对应四个液位等级,阈值由用户通过按键输入,设备保存阈值,并根据此阈值判断液位等级,假定用户输入的三个液位阈值为 10cm、20cm 和 30cm, 液位高度与液位等级的对应关系如下:
- 液位高度≤10cm 时,液位等级为 0;
- 10cm<液位高度≤20cm 时,液位等级为 1;
- 20cm<液位高度≤30cm 时,液位等级为 2;
- 液位高度>30cm 时,液位等级为 3。
设备初始液位阈值分别为 30cm、50cm 和 70cm,用户修改阈值后,设备应将此参数保存在 E2PROM 中,当设备重新上电时,可从 E2PROM 中获取。
注意这里埋了个大坑:当设备重新上电时,可从 E2PROM 中获取。解决方法就是用E2PROM识别是否是第一次上电,后面讲这个~
3.4 液位阈值设定
- B1 按键:“设置”按键,按下后进入阈值设定界面(如图 2 所示),再次按下 B1 按键时 退出设置界面,保存用户设定的结果到 E2PROM,并返回图 1 所示的液位检测界面。
- B2 按键:切换选择 3 个待修改的阈值,被选中的阈值应突出显示。
- B3 按键:“加”按键,按下后,被选择的阈值增加 5cm,增加到 95cm 为止。
- B4 按键:“减”按键,按下后,被选择的阈值减少 5cm,减少到 5cm 为止。
按键处理函数 void key_proc(void)
void key_proc(void)
{
if(key[0].single_flag == 1) //如果按键1按下 短按
{
key[0].single_flag = 0; //按键清零
lcd_view ++;
if (lcd_view == 2) lcd_view = 0;//界面切换.两个界面
LCD_Clear(White);//清LCD屏
}
if(key[1].single_flag == 1) //如果按键PB2按下 短按
{
key[1].single_flag = 0; //按键清零
if (lcd_view == 1) //如果是阈值设置界面
{
//切换选择 3 个待修改的阈值,被选中的阈值应突出显示
select_param_set ++; //选择参数设置 ++
if (select_param_set == 3) select_param_set = 0;//参数设置切换.3个参数,一个保存写入
}
}
if(key[2].single_flag == 1) //如果按键PB3按下 短按
{
key[2].single_flag = 0; //按键清零
if (select_param_set == 0) //设置第一个参数
{
Threshold_1 += 5;
if (Threshold_1 >= 95)
Threshold_1 = 95;
}
else if (select_param_set == 1) //设置第二个参数
{
Threshold_2 += 5;
if (Threshold_2 >= 95)
Threshold_2 = 95;
}
else if (select_param_set == 2) //设置第三个参数
{
Threshold_3 += 5;
if (Threshold_3 >= 95)
Threshold_3 = 95;
}
}
if(key[3].single_flag == 1) //如果按键PB4按下 短按
{
key[3].single_flag = 0; //按键清零
if (select_param_set == 0) //设置第一个参数
{
Threshold_1 -= 5;
if (Threshold_1 <= 5)
Threshold_1 = 5;
}
else if (select_param_set == 1) //设置第二个参数
{
Threshold_2 -= 5;
if (Threshold_2 <= 5)
Threshold_2 = 5;
}
else if (select_param_set == 2) //设置第三个参数
{
Threshold_3 -= 5;
if (Threshold_3 <= 5)
Threshold_3 = 5;
}
}
}
按键部分比较简单,注意越界判断,注意界面切换要清LCD屏
LCD高亮,这部分是我自己研究的,没有copy别人的代码,写的有些简陋了些
3.5 串口通信
每次接收一个字节
串口接收部分,没什么好讲的,看注释
这里需要使用sprintf函数,可以去菜鸟教程学一下
//串口的接收 回调函数
char rxdata[50];
uint8_t RX_Str_Data;
unsigned char rx_pointer; //自己定义的指针,判断接收到哪了
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == USART1) // 如果是USART1
{
//数据处理部分
if(RX_Str_Data == 'C') //只接收了一个字符,用这个变量判断即可
{
flag.IS_Receive = 1; //收到查询指令了
sprintf(USART_tx_string, "C:H%d+L%d\r\n", height, yewei_level);
HAL_UART_Transmit(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string), 50);
}
else if (RX_Str_Data == 'S')
{
flag.IS_Receive = 1; //收到查询指令了
sprintf(USART_tx_string, "S:TL%d+TM%d+TH%d\r\n", Threshold_1, Threshold_2, Threshold_3);
HAL_UART_Transmit(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string), 50);
}
rxdata[rx_pointer++] = RX_Str_Data; //接收到的字符串存放在这里
HAL_UART_Receive_IT(&huart1, &RX_Str_Data, 1); //最后这个参数只能写1
}
}
3.6 LCD显示
void disp_proc(void)
{
if (lcd_view == 0)
{
sprintf(LCD_Show_text, " Liquid Level ");
LCD_DisplayStringLine(Line1, (uint8_t *)LCD_Show_text);
sprintf(LCD_Show_text, " Height: %dcm ", height);
LCD_DisplayStringLine(Line3, (uint8_t *)LCD_Show_text);
// 显示ADC
sprintf(LCD_Show_text, " ADC: %.2fV ", Vol_1S);
LCD_DisplayStringLine(Line5, (uint8_t *)LCD_Show_text);
sprintf(LCD_Show_text, " Level: %d ", yewei_level);
LCD_DisplayStringLine(Line7, (uint8_t *)LCD_Show_text);
//测试用例,查看数据的,写完用不到了
// sprintf(LCD_Show_text, " LED:%d %d Rx:%c ", flag.LED3_State,flag.LED3_ON_Cnt, RX_Str_Data);
// LCD_DisplayStringLine(Line8, (uint8_t *)LCD_Show_text);
}
//阈值设定界面
if (lcd_view == 1)
{
if (select_param_set == 0) //第一个参数
{
sprintf(LCD_Show_text, " Parameter Setup ");
LCD_DisplayStringLine(Line1, (uint8_t *)LCD_Show_text);
LCD_SetTextColor(Red); // 设置字体颜色
sprintf(LCD_Show_text, " Threshold 1: %dcm ", Threshold_1);
LCD_DisplayStringLine(Line4, (uint8_t *)LCD_Show_text);
LCD_SetTextColor(Blue); // 设置字体颜色
sprintf(LCD_Show_text, " Threshold 2: %dcm ", Threshold_2);
LCD_DisplayStringLine(Line6, (uint8_t *)LCD_Show_text);
sprintf(LCD_Show_text, " Threshold 3: %dcm ", Threshold_3);
LCD_DisplayStringLine(Line8, (uint8_t *)LCD_Show_text);
}
else if (select_param_set == 1) //第二个参数
{
sprintf(LCD_Show_text, " Parameter Setup ");
LCD_DisplayStringLine(Line1, (uint8_t *)LCD_Show_text);
LCD_SetTextColor(Blue); // 设置字体颜色
sprintf(LCD_Show_text, " Threshold 1: %dcm ", Threshold_1);
LCD_DisplayStringLine(Line4, (uint8_t *)LCD_Show_text);
LCD_SetTextColor(Red); // 设置字体颜色
sprintf(LCD_Show_text, " Threshold 2: %dcm ", Threshold_2);
LCD_DisplayStringLine(Line6, (uint8_t *)LCD_Show_text);
LCD_SetTextColor(Blue); // 设置字体颜色
sprintf(LCD_Show_text, " Threshold 3: %dcm ", Threshold_3);
LCD_DisplayStringLine(Line8, (uint8_t *)LCD_Show_text);
}
else if (select_param_set == 2) //第三个参数
{
sprintf(LCD_Show_text, " Parameter Setup ");
LCD_DisplayStringLine(Line1, (uint8_t *)LCD_Show_text);
LCD_SetTextColor(Blue); // 设置字体颜色
sprintf(LCD_Show_text, " Threshold 1: %dcm ", Threshold_1);
LCD_DisplayStringLine(Line4, (uint8_t *)LCD_Show_text);
LCD_SetTextColor(Blue); // 设置字体颜色
sprintf(LCD_Show_text, " Threshold 2: %dcm ", Threshold_2);
LCD_DisplayStringLine(Line6, (uint8_t *)LCD_Show_text);
LCD_SetTextColor(Red); // 设置字体颜色
sprintf(LCD_Show_text, " Threshold 3: %dcm ", Threshold_3);
LCD_DisplayStringLine(Line8, (uint8_t *)LCD_Show_text);
LCD_SetTextColor(Blue); // 设置字体颜色
}
}
}
在不同的界面下显示不同的内容,用到一个标志位即可实现
3.7 LED显示
配置PC8~PC15、PD2
该板子是低电平点亮,8个led灯使用的是高8位所以需要左移8位,led等于几就是将高8位中第几位设置成低电平即点亮,由于led与lcd复用引脚最后打开锁存器让值被写入之后,立刻关闭锁存器防止影响LCD
void LED_proc(void)
{
// LED1 数据
if (flag.LED1_State == 0)
{
flag.LED1_Data = 0x00; //0000 0000
}
else if (flag.LED1_State == 1)
{
flag.LED1_Data = 0x01; //0000 0001
}
// LED2 数据
if (flag.YeWei_IS_change == 1) //如果液位变化
flag.YW_IS_Change_forLED = 1; //液位变化,LED的标志位置1
if (flag.LED2_State == 0)
{
flag.LED2_Data = 0x00; //0000 0000
}
else if (flag.LED2_State == 1)
{
if (flag.YW_IS_Change_forLED == 1) //如果液位变化
{
flag.LED2_Data = 0x02; //0000 0010
}
}
// LED3 数据
if (flag.LED3_State == 0)
{
flag.LED3_Data = 0x00; //0000 0000
}
else if (flag.LED3_State == 1)
{
if (flag.IS_Receive == 1) //收到查询指令了
{
flag.LED3_Data = 0x04; //0000 0100
}
}
// if (flag.IS_Receive == 1) //收到查询指令了
// {
// if (flag.LED3_State == 0) //
// {
// flag.LED3_Data = 0x00; //0000 0000
// }
// else if (flag.LED3_State == 1)
// {
// flag.LED3_Data = 0x04; //0000 0100
// ++ flag.LED3_ON_Cnt;
// if (flag.LED3_ON_Cnt > 5) //闪烁5次以上
// {
// flag.IS_Receive = 0; //先清零接收标志位
// flag.LED3_ON_Cnt = 0; //再清零闪烁次数,方便下一次闪烁指示
// }
// }
// }
LED_Disp(flag.LED1_Data | flag.LED2_Data | flag.LED3_Data);
}
分析:
- LED1以1S为间隔亮灭闪烁:亮1S、灭1S、亮1S、灭1S……
- LED2以0.2S为间隔闪烁5次:0.2S亮灭一次,一秒内亮灭5次
- LED3以0.2S为间隔闪烁5次:0.2S亮灭一次,一秒内亮灭5次
用几个标志位控制LED的闪烁频率和次数,都是51单片机的基础操作,这里我就不多讲了,具体可以看代码~
这里用三个标志位,分别控制三个灯,最后调用LED显示函数,这样操作LED,他们之间互不影响
3.8 逻辑处理
void control_fun(void)
{
if (flag.adc_readtime_ok == 1)
{
Vol_1S = getADC(&hadc2); //ADC采集一次
height = (uint16_t)(Vol_1S / 3.3f * 100);
flag.adc_readtime_ok = 0;
}
//液位等级判断
if (height <= Threshold_1)
yewei_level = 0;
else if (height > Threshold_1 && height <= Threshold_2)
yewei_level = 1;
else if (height > Threshold_2 && height <= Threshold_3)
yewei_level = 2;
else if (height > Threshold_3)
yewei_level = 3;
//液位等级变化 判断,串口发送数据
if (yewei_level - flag.last_YW_state == 0) //液位等级没有变化
{
flag.YeWei_IS_change = 0; //液位是否变化标志位置0
}
else if (yewei_level - flag.last_YW_state > 0) //液位 上升
{
flag.YeWei_IS_change = 1; //液位是否变化标志位置1
flag.YeWei_change_Dir = 1; //上升趋势
}
else if (yewei_level - flag.last_YW_state < 0) //液位 下降
{
flag.YeWei_IS_change = 1; //液位是否变化标志位置1
flag.YeWei_change_Dir = 2; //下降趋势
}
flag.last_YW_state = yewei_level;
if (flag.YeWei_IS_change == 1) //如果液位变化
{
// flag.YW_IS_Change_forLED = 1; //液位变化,LED的标志位置1,放到后面的函数写了
if (flag.YeWei_change_Dir == 1) //上升趋势
{
sprintf(USART_tx_string, "A:H%d+L%d+U\r\n", height, yewei_level);
HAL_UART_Transmit(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string), 50);
}
else if (flag.YeWei_change_Dir == 2) //下降趋势
{
sprintf(USART_tx_string, "A:H%d+L%d+D\r\n", height, yewei_level);
HAL_UART_Transmit(&huart1, (uint8_t *)USART_tx_string, strlen(USART_tx_string), 50);
}
}
//EEPROM读写
if (lcd_view == 0)
{
if (flag.E2PROM_Write == 1)
{
//E2PROM 写入
EEPROM_WriteByte(1, Threshold_1); //写入阈值1
HAL_Delay(10); //延时10ms
EEPROM_WriteByte(2, Threshold_2); //写入阈值2
HAL_Delay(10); //延时10ms
EEPROM_WriteByte(3, Threshold_3); //写入阈值3
HAL_Delay(10); //延时10ms
flag.E2PROM_Write = 0; //复位,写一次即可,放在后面,写完
flag.E2PROM_read = 1;
}
}
else if (lcd_view == 1)
{
flag.E2PROM_Write = 1; //调到阈值设定界面 置1,到第一个界面时候,才存储阈值参数
if (flag.E2PROM_read == 1)
{
//读出来的三个阈值都是95 怀疑有问题,把阈值上下限限制的判断,挪到按键里了,发现读出来的数据都变成255了
//突然想到这里我没有初始化I2C引脚,被自己蠢笑了~~~哈哈哈,初始化PB6、PB7,按键也忘记初始化过...以后先找CubeMX~~~
Threshold_1 = EEPROM_ReadByte(1);
Threshold_2 = EEPROM_ReadByte(2);
Threshold_3 = EEPROM_ReadByte(3);
flag.E2PROM_read = 0;
}
}
}
3.9 main函数
原版
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM4_Init();
MX_ADC2_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
LED_Disp(0x00); //LED初始化,全部熄灭
LCD_Init(); //LCD初始化
//定时器初始化
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_Base_Start_IT(&htim4);
LCD_Clear(White);//清LCD屏
LCD_SetBackColor(White);
LCD_SetTextColor(Blue);
//上电先读取一遍
Threshold_1 = EEPROM_ReadByte(1);
Threshold_2 = EEPROM_ReadByte(2);
Threshold_3 = EEPROM_ReadByte(3);
HAL_UART_Receive_IT(&huart1, &RX_Str_Data, 1); //打开串口接收的初始化
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
key_proc();
disp_proc();
control_fun();
LED_proc();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
初始化这里有点小Bug存在,我第一次写的时候没有解决这个问题,就是用E2PROM检测是否单片机为第一次上电
如果是第一次上电,那就初始化阈值参数,如果不是第一次上电,那就读取E2PROM里的数据作为阈值数据
修改
具体修改过的代码如下,我实际测试过,这样的写法可以实现我们预期效果,比较完美
直接放码过来~
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_TIM4_Init();
MX_ADC2_Init();
MX_TIM3_Init();
MX_USART1_UART_Init();
/* USER CODE BEGIN 2 */
LED_Disp(0x00); //LED初始化,全部熄灭
LCD_Init(); //LCD初始化
//定时器初始化
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_Base_Start_IT(&htim4);
LCD_Clear(White);//清LCD屏
LCD_SetBackColor(White);
LCD_SetTextColor(Blue);
//上电先读取一遍
if (EEPROM_ReadByte(123) != 0xA5)
{
Threshold_1 =30;
Threshold_2 =50;
Threshold_3 =70;
EEPROM_WriteByte(123, 0xA5);
}
else
{
Threshold_1 = EEPROM_ReadByte(1);
Threshold_2 = EEPROM_ReadByte(2);
Threshold_3 = EEPROM_ReadByte(3);
}
HAL_UART_Receive_IT(&huart1, &RX_Str_Data, 1); //打开串口接收的初始化
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
key_proc();
disp_proc();
control_fun();
LED_proc();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
4 电路设计
不会