第七届省赛真题模拟液位检测告警系统
第七届省赛真题主函数部分的代码功能实现(不包含各模块初始化代码)第七届省赛真题
主函数部分的代码功能实现(不包含各模块初始化代码)
#include "main.h"#include "rcc.h"#include "led_key.h"#include "lcd.h"#include "adc.h"#include "i2c.h"#include "usart.h"//***执行速度控制变量***//__IO uint32_t uwTick_LED_Speed_Ctrl;__IO uint32_t uwTick_KEY_Speed_Ctrl;__IO uint32_t uwTick_LCD_Speed_Ctrl;__IO uint32_t uwTick_UART_Speed_Ctrl;__IO uint32_t uwTick_ADC_Speed_Ctrl;//***全局变量区***//uint8_t ucLED;uint8_t key_value,key_up,key_down;static uint8_t key_old;uint8_t LCD_String_Disp[21];uint8_t rx_buffer;uint8_t RX_BUF[200];uint8_t rx_count;_Bool Interface_Ctrl; //0-液位检测界面 1-阈值设定界面uint8_t Threshold_Disp[3]={30 , 50 , 70}; //设备初始液位值 用于显示uint8_t Threshold_Ctrl[4]={30 , 50 , 70}; //存入EEPROM 用于控制uint8_t Threshold_choose = 0;//1-阈值1 2-阈值2 3-阈值3 默认为0不选择 无高亮文本uint8_t Height_value; //液位值uint8_t Level_value; //液位等级static uint8_t Level_value_old;float ADC_Value_once; //adc每次采集的电压值 100ms更新一次uint8_t ADC_Value_num; //用于记录采集ADC电压的次数float ADC_Value_sum;//10次电压采集之和float ADC_Volt; //最终中值滤波后的电压值uint8_t LD1_Count;uint8_t LD2_Ctrl;uint8_t LD2_twinkle_Count;uint8_t LD3_Ctrl;uint8_t LD3_twinkle_Count;//***子函数声明区***///* Private function prototypes -----------------------------------------------*/void SystemClock_Config(void);void LED_Proc(void);void KEY_Proc(void);void LCD_Proc(void);int fputc(int ch, FILE * f);void UART_Proc(void);void ADC_Collect_Volt(void);/*** @brief The application entry point.* @retval int*/int main(void){HAL_Init();SystemClock_Config();//***外设模块初始化区***//LED_KEY_Init();LCD_Init();LCD_Clear(Black);LCD_SetBackColor(Black);LCD_SetTextColor(White);ADC2_Init();USART1_UART_Init();HAL_UART_Receive_IT(&huart1 , (uint8_t *)(&rx_buffer) , 1); //开启串口中断I2CInit();I2C_24c02_Read((uint8_t *)&Threshold_Ctrl[3] , 0x37 ,1); //随便读取EEPROM中的数用于判断是否是第一次上电HAL_Delay(10);if(Threshold_Ctrl[3] != 9) //初次上电 阈值为30 50 70{Threshold_Ctrl[3] = 9; //将该位的值改为9写入eeprom中 用于判断非第一次上电 确保再次上电读取eeprom中设置的阈值I2C_24c02_Write((uint8_t *)&Threshold_Ctrl[3] , 0x37 , 1);HAL_Delay(10);I2C_24c02_Write((uint8_t *)Threshold_Ctrl , 0x00, 3); //将阈值写入EEPROM中}else //再次上电读取eeprom中设置的阈值 更新显示的阈值{I2C_24c02_Read(Threshold_Ctrl , 0x00 ,3); //读取EEPROM中的值HAL_Delay(10);Threshold_Disp[0] = Threshold_Ctrl[0];Threshold_Disp[1] = Threshold_Ctrl[1];Threshold_Disp[2] = Threshold_Ctrl[2];}while (1){LED_Proc();KEY_Proc();LCD_Proc();UART_Proc();ADC_Collect_Volt();}}//***LED处理子函数***//void LED_Proc(void){if((uwTick - uwTick_LED_Speed_Ctrl)<200) return;uwTick_LED_Speed_Ctrl = uwTick; //200ms执行一次//*LD1-运行状态指示灯-以1s为间隔亮灭闪烁LD1_Count++;if(LD1_Count == 5){ucLED ^= 0x01;LD1_Count = 0;}//*LD2-液位等级变化指示灯-以0.2s为间隔闪烁五次if(LD2_Ctrl == 1){LD2_twinkle_Count++;ucLED ^= 0x02;if(LD2_twinkle_Count == 10){LD2_twinkle_Count = 0;LD2_Ctrl = 0;}}elseucLED &= 0x05; //保持LD1和LD3的状态在LD2_Ctrl为0时关闭LD2//*LD3-查询状态指示灯-以0.2s为间隔闪烁五次if(LD3_Ctrl == 1){LD3_twinkle_Count++;ucLED ^= 0x04;if(LD3_twinkle_Count == 10){LD3_twinkle_Count = 0;LD3_Ctrl = 0;}}elseucLED &= 0x03;//保持LD1和LD2的状态 在LD3_Ctrl为0时关闭LD3LED_Disp(ucLED);//调用LED显示函数}//***按键处理子函数void KEY_Proc(void){if((uwTick - uwTick_KEY_Speed_Ctrl)<50) return;uwTick_KEY_Speed_Ctrl = uwTick; //50ms执行一次//***按键三行代码***//key_value = KEY_Scan();key_down = key_value & (key_value ^ key_old);key_up= ~key_value & (key_value ^ key_old);key_old = key_value;switch(key_down){case 1: //按键B1有效Interface_Ctrl ^= 1;if(!Interface_Ctrl) //切换到液位检测界面{Threshold_Ctrl[0] = Threshold_Disp[0];Threshold_Ctrl[1] = Threshold_Disp[1];Threshold_Ctrl[2] = Threshold_Disp[2];I2C_24c02_Write(Threshold_Ctrl , 0x00 ,3); //每次切换将液位值存入EEPROM}LCD_Clear(Black);break;case 2: //按键B2有效if(Interface_Ctrl) //仅在阈值设定界面有效{Threshold_choose ++; //选择需要设定的阈值if(Threshold_choose == 4)Threshold_choose = 0;}break;case 3: //按键B3有效 ”加“按键if(Interface_Ctrl) //仅在阈值设定界面有效{if(Threshold_choose == 1) //阈值1{Threshold_Disp[0] += 5;if(Threshold_Disp[0] == Threshold_Disp[1]) //阈值1不能大于阈值2Threshold_Disp[0] = Threshold_Disp[1] - 5;if(Threshold_Disp[0] == 100)Threshold_Disp[0] = 95;}else if(Threshold_choose == 2) //阈值2{Threshold_Disp[1] += 5;if(Threshold_Disp[1] == Threshold_Disp[2]) //阈值2不能大于阈值3Threshold_Disp[1] = Threshold_Disp[2] - 5;if(Threshold_Disp[1] == 100)Threshold_Disp[1] = 95;}else if(Threshold_choose == 3) //阈值3{Threshold_Disp[2] += 5;if(Threshold_Disp[2] == 100)Threshold_Disp[2] = 95;}}break;case 4: //按键B4有效 ”减“按键if(Interface_Ctrl) //仅在阈值设定界面有效{if(Threshold_choose == 1) //阈值1{Threshold_Disp[0] -= 5;if(Threshold_Disp[0] == 0)Threshold_Disp[0] = 5;}else if(Threshold_choose == 2) //阈值2{Threshold_Disp[1] -= 5;if(Threshold_Disp[1] == Threshold_Disp[0]) //阈值2不能小于阈值1Threshold_Disp[1] = Threshold_Disp[0] + 5;if(Threshold_Disp[1] == 0)Threshold_Disp[1] = 5;}else if(Threshold_choose == 3) //阈值3{Threshold_Disp[2] -= 5;if(Threshold_Disp[2] == Threshold_Disp[1]) //阈值3不能小于阈值2Threshold_Disp[2] = Threshold_Disp[1] + 5;if(Threshold_Disp[2] == 0)Threshold_Disp[2] = 5;}}break;}}//***软件中值滤波法得到ADC的电压值***//void ADC_Collect_Volt(void){//没100ms采集一次 当采集到十次达到1s时得到ADC经中值滤波后的电压值if((uwTick - uwTick_ADC_Speed_Ctrl)<100) return;uwTick_ADC_Speed_Ctrl = uwTick;//100ms执行一次ADC_Value_once = (3.3*Get_ADC_Value())/4096;for(ADC_Value_num=0 ; ADC_Value_num<10 ; ADC_Value_num++){ADC_Value_sum += ADC_Value_once;}if(ADC_Value_num == 10)ADC_Volt = ADC_Value_sum/10;ADC_Value_sum = 0;}//***LCD处理子函数***//void LCD_Proc(void){if((uwTick - uwTick_LCD_Speed_Ctrl)<200) return;uwTick_LCD_Speed_Ctrl = uwTick;//200ms执行一次I2C_24c02_Read(Threshold_Ctrl , 0x00 ,3); //读取EEPROM中的值Height_value = (uint8_t)(ADC_Volt*100/3.3f); //液位高度 H=V*K 当V=3.3V H=100 则K=100/3.3Level_value_old = Level_value; //记录上一次的液位等级 写在液位判断的上面 先赋值再判断//根据三个阈值判别液位等级if(Height_value <= Threshold_Ctrl[0]) //小于等于阈值1{Level_value = 0; //液位等级0}else if((Height_value > Threshold_Ctrl[0]) && (Height_value <= Threshold_Ctrl[1])) //大于阈值1小于等于阈值2{Level_value = 1; //液位等级1}else if((Height_value > Threshold_Ctrl[1]) && (Height_value <= Threshold_Ctrl[2])) //大于阈值2小于等于阈值3{Level_value = 2; //液位等级2}else //大于阈值3{Level_value = 3; //液位等级3}//输出功能if(Level_value != Level_value_old) //液位等级发生变化{LD2_Ctrl = 1;if(Level_value > Level_value_old){printf("A:H%02d+L%1d+U\r\n",Height_value , Level_value);}else{printf("A:H%02d+L%1d+D\r\n",Height_value , Level_value);}}if(!Interface_Ctrl) //液位检测界面{LCD_SetTextColor(White);//设定该界面下文本颜色 防止受上一个对文本颜色的改变影响memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串sprintf((char*)LCD_String_Disp , "Liquid Level"); //打印所要显示的字符给字符显示数组LCD_DisplayStringLine(Line2 , LCD_String_Disp);memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串sprintf((char*)LCD_String_Disp , " Height: %02dcm ",Height_value); //打印液位高度给字符显示数组LCD_DisplayStringLine(Line4 , LCD_String_Disp);memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串sprintf((char*)LCD_String_Disp , " ADC: %4.2fV ",ADC_Volt); //打印电位给字符显示数组LCD_DisplayStringLine(Line6 , LCD_String_Disp);memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串sprintf((char*)LCD_String_Disp , " Level: %1d ",Level_value); //打印液位等级给字符显示数组LCD_DisplayStringLine(Line8 , LCD_String_Disp);}else//阈值设定界面{LCD_SetTextColor(White);//初始文本颜色 防止受上一个对文本颜色的改变影响memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串sprintf((char*)LCD_String_Disp , " Parameter Setup"); //打印所要显示的字符给字符显示数组LCD_DisplayStringLine(Line2 , LCD_String_Disp);memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串sprintf((char*)LCD_String_Disp , " Threshold 1: %dcm ",Threshold_Disp[0]); //打印阈值1给字符显示数组if(Threshold_choose == 1)//选择阈值1-文本颜色改变LCD_SetTextColor(Green);elseLCD_SetTextColor(White); //否则文本颜色不改变LCD_DisplayStringLine(Line4 , LCD_String_Disp);memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串sprintf((char*)LCD_String_Disp , " Threshold 2: %dcm ",Threshold_Disp[1]); //打印阈值2给字符显示数组if(Threshold_choose == 2)LCD_SetTextColor(Green);//选择阈值2-文本颜色改变elseLCD_SetTextColor(White);LCD_DisplayStringLine(Line6 , LCD_String_Disp);memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp)); //清空字符串sprintf((char*)LCD_String_Disp , " Threshold 3: %dcm ",Threshold_Disp[2]); //打印阈值3给字符显示数组if(Threshold_choose == 3)//选择阈值3-文本颜色改变LCD_SetTextColor(Green);elseLCD_SetTextColor(White);LCD_DisplayStringLine(Line8 , LCD_String_Disp);}}//***串口处理子函数***//void UART_Proc(void){if((uwTick - uwTick_UART_Speed_Ctrl)<300) return;uwTick_UART_Speed_Ctrl = uwTick;//300ms执行一次//查询功能if(RX_BUF[0]== 'C'){LD3_Ctrl = 1;//接收到查询指令 打开LD3printf("C:H%02d+L%1d\r\n",Height_value , Level_value);}if(RX_BUF[0] == 'S'){LD3_Ctrl = 1;//接收到查询指令 打开LD3printf("S:TL%02d+TM%02d+TH%02d\r\n",Threshold_Ctrl[0],Threshold_Ctrl[1],Threshold_Ctrl[2]);}memset(RX_BUF , 0 , sizeof(RX_BUF));rx_count = 0;}//***串口中断回调函数***//void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){RX_BUF[rx_count] = rx_buffer;rx_count++;HAL_UART_Receive_IT(&huart1 , (uint8_t *)(&rx_buffer) , 1);}//***printf重定向为串口发送***//int fputc(int ch, FILE * f){char c = ch;HAL_UART_Transmit(&huart1 , (uint8_t *)&c , 1 , 50);return ch;}