第七届省赛真题模拟液位检测告警系统
第七届省赛真题
主函数部分的代码功能实现(不包含各模块初始化代码)
#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;
}
}
else
ucLED &= 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;
}
}
else
ucLED &= 0x03; //保持LD1和LD2的状态 在LD3_Ctrl为0时关闭LD3
LED_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不能大于阈值2
Threshold_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不能大于阈值3
Threshold_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不能小于阈值1
Threshold_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不能小于阈值2
Threshold_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.3
Level_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);
else
LCD_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-文本颜色改变
else
LCD_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);
else
LCD_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; //接收到查询指令 打开LD3
printf("C:H%02d+L%1d\r\n",Height_value , Level_value);
}
if(RX_BUF[0] == 'S')
{
LD3_Ctrl = 1; //接收到查询指令 打开LD3
printf("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;
}