一、题目
二、分析
以按键画出各个状态机的动作和变换:
由于按键控制着状态机的变换,程序主要分为两大部分,一部分以按键控制着状态机的运行,另一部分以程序运行在不同的状态机下,显示不同的数据和产生不同的动作
1.按键(状态机)
void Key_Proc(void)
{
if((uwTick - uwTick_Key_Set_Point)<50) return;//减速函数
uwTick_Key_Set_Point = uwTick;
ucKey_Val = Key_Scan();
unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val);
ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);
ucKey_Old = ucKey_Val;
if(unKey_Down == 1) // 界面切换
{
if(state == 0) {state = 1;LCD_Clear(White);}
else if(state == 1||state == 2||state == 3||state == 4)
{
if(upp_led != low_led && max_v > min_v)
{
state = 0;LCD_Clear(White);
max = max_v*10;min=min_v*10;
iic_24c02_write(&max, 0, 1);HAL_Delay(10);
iic_24c02_write(&min, 1, 1);HAL_Delay(10);
iic_24c02_write(&upp_led, 2, 1);HAL_Delay(10);
iic_24c02_write(&low_led, 3, 1);HAL_Delay(10);
}
else //否则返回不了
{
}
}
}
if(unKey_Down == 2)
{
if(state != 0)//防止在数据界面,按键2其作用
{
if(++state==5)state =1;
}
}
if(unKey_Down == 3) //加
{
switch(state)
{
case 1:
max_v += 0.3;
if((max_v + 0.3)>3.3)max_v=3.3;
break;
case 2:
if((max_v - min_v) > 0.3) min_v += 0.3;
break;
case 3:
if(++upp_led>8)upp_led=8;
if(upp_led == low_led) //相等
{
//下限灯是8,则upp_led =7;
if(low_led==8)upp_led=7;
else //继续加1
if(++upp_led>8)upp_led=8;
}
break;
case 4:
if(++low_led>8)low_led=8;
if(upp_led==low_led)
{
if(upp_led==8)
low_led = 7;
else
if(++low_led>8)low_led=8;
}
break;
}
}
if(unKey_Down == 4) //减
{
switch(state)
{
case 1:
if((max_v-min_v)>0.3)max_v -= 0.3;
break;
case 2:
min_v -= 0.3;
if((min_v-0.3)<0)min_v=0;
break;
case 3:
if(--upp_led==0)upp_led=1;
if(upp_led==low_led)
{
if(low_led==1)
upp_led=2;
else
if(--upp_led==0)upp_led=1;
}
break;
case 4:
if(--low_led==0)low_led=1;
if(upp_led==low_led)
{
if(upp_led==1)
low_led=2;
else
if(--low_led==0)low_led=1;
}
break;
}
}
}
按键部分主要控制各个状态机的变换以及部分动作处理。
按键进行加载时要注意两个阈值之间的大小关系,上阈值一定要大于下阈值,改变灯的下标是不能出现相同的下标,若相同,根据情况(判断另一个灯是否处于最值),做不同的处理。
用EEPROM进行数据的分批次连续读写,最好在每一次读写完之后,进行相应的延时。不然会出现数据存储错误。用EEPROM存储浮点数时,最好将该浮点数进行相应倍数的扩大,使之为整数在存储进行。
2.显示
LED灯显示
void Led_Proc(void)
{
if((uwTick - uwTick_Led_Set_Point)<200) return;//减速函数
uwTick_Led_Set_Point = uwTick;
if(v37>max_v)
{
ucLed=0;
ucLed ^= (1<<(upp_led-1));
disp = 2;
}
else if(v37 <min_v)
{
ucLed =0;
ucLed ^= (1<<(low_led-1));
disp = 0;
}
else if(v37>=min_v && v37<=max_v)
{
ucLed = 0;
disp =1;
}
LED_Disp(ucLed);
}
将8字节变量的某一位进行翻转使用: ^=。
LCD显示:高亮显示部分
if(state==1)LCD_SetBackColor(Green); //是该状态则高亮显示
else LCD_SetBackColor(White);
sprintf((char *)Lcd_Disp_String, "Max Volt: %3.1fV ",max_v);
LCD_DisplayStringLine(Line3, Lcd_Disp_String);
LCD_SetBackColor(White); //使之后的不受这个状态的影响
这里是让背景色高亮显示,也可以设置让文字高亮显示。要注意的是颜色的设置仅对后面的显示起作用,所以在每一次状态下高亮显示后,要进行恢复原来的颜色设置。
.
三、程序
#include "main.h"
#include "RCC\bsp_rcc.h"
#include "KEY_LED\bsp_key_led.h"
#include "LCD\bsp_lcd.h"
#include "UART\bsp_uart.h"
#include "I2C\bsp_i2c.h"
#include "ADC\bsp_adc.h"
//***全局变量声明区
//*减速变量
__IO uint32_t uwTick_Key_Set_Point = 0;//控制Key_Proc的执行速度
__IO uint32_t uwTick_Led_Set_Point = 0;//控制Led_Proc的执行速度
__IO uint32_t uwTick_Lcd_Set_Point = 0;//控制Lcd_Proc的执行速度
//*按键扫描专用变量
uint8_t ucKey_Val, unKey_Down, ucKey_Up, ucKey_Old;
//*LED专用变量
uint8_t ucLed;
//*LCD显示专用变量
uint8_t Lcd_Disp_String[21];//最多显示20个字符
//***子函数声明区
void Key_Proc(void);
void Led_Proc(void);
void Lcd_Proc(void);
void Usart_Proc(void);
float v37;
uint8_t state=0;
float max_v = 2.4;
float min_v = 1.2;
uint8_t max;//存储阈值,以整数形式
uint8_t min;
uint8_t upp_led = 1;
uint8_t low_led = 2;
uint8_t disp; // 0 : 低 1:正常 2:高
//***系统主函数
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/*bsp资源的初始化*/
KEY_LED_Init();
LCD_Init();
LCD_Clear(White);
LCD_SetBackColor(White);
LCD_SetTextColor(Blue);
I2CInit();
ADC2_Init();
//在进行分次连续读写的时候,记得每次读写完进行延时!!!!!
iic_24c02_read(&max, 0, 1); HAL_Delay(10);
iic_24c02_read(&min, 1, 1); HAL_Delay(10);
iic_24c02_read(&upp_led, 2, 1); HAL_Delay(10);
iic_24c02_read(&low_led, 3, 1); HAL_Delay(10);
max_v = max /10.0;min_v = min /10.0;
while (1)
{
Key_Proc();
Led_Proc();
Lcd_Proc();
}
}
//***按键扫描子函数
void Key_Proc(void)
{
if((uwTick - uwTick_Key_Set_Point)<50) return;//减速函数
uwTick_Key_Set_Point = uwTick;
ucKey_Val = Key_Scan();
unKey_Down = ucKey_Val & (ucKey_Old ^ ucKey_Val);
ucKey_Up = ~ucKey_Val & (ucKey_Old ^ ucKey_Val);
ucKey_Old = ucKey_Val;
if(unKey_Down == 1) // 界面切换
{
if(state == 0) {state = 1;LCD_Clear(White);}
else if(state == 1||state == 2||state == 3||state == 4)
{
if(upp_led != low_led && max_v > min_v)
{
state = 0;LCD_Clear(White);
max = max_v*10;min=min_v*10;
iic_24c02_write(&max, 0, 1);HAL_Delay(10);
iic_24c02_write(&min, 1, 1);HAL_Delay(10);
iic_24c02_write(&upp_led, 2, 1);HAL_Delay(10);
iic_24c02_write(&low_led, 3, 1);HAL_Delay(10);
}
else //否则返回不了
{
}
}
}
if(unKey_Down == 2)
{
if(state != 0)//防止在数据界面,按键2其作用
{
if(++state==5)state =1;
}
}
if(unKey_Down == 3) //加
{
switch(state)
{
case 1:
max_v += 0.3;
if((max_v + 0.3)>3.3)max_v=3.3;
break;
case 2:
if((max_v - min_v) > 0.3) min_v += 0.3;
break;
case 3:
if(++upp_led>8)upp_led=8;
if(upp_led == low_led) //相等
{
//下限灯是8,则upp_led =7;
if(low_led==8)upp_led=7;
else //继续加1
if(++upp_led>8)upp_led=8;
}
break;
case 4:
if(++low_led>8)low_led=8;
if(upp_led==low_led)
{
if(upp_led==8)
low_led = 7;
else
if(++low_led>8)low_led=8;
}
break;
}
}
if(unKey_Down == 4) //减
{
switch(state)
{
case 1:
if((max_v-min_v)>0.3)max_v -= 0.3;
break;
case 2:
min_v -= 0.3;
if((min_v-0.3)<0)min_v=0;
break;
case 3:
if(--upp_led==0)upp_led=1;
if(upp_led==low_led)
{
if(low_led==1)
upp_led=2;
else
if(--upp_led==0)upp_led=1;
}
break;
case 4:
if(--low_led==0)low_led=1;
if(upp_led==low_led)
{
if(upp_led==1)
low_led=2;
else
if(--low_led==0)low_led=1;
}
break;
}
}
}
//***LED扫描子函数
void Led_Proc(void)
{
if((uwTick - uwTick_Led_Set_Point)<200) return;//减速函数
uwTick_Led_Set_Point = uwTick;
if(v37>max_v)
{
ucLed=0;
ucLed ^= (1<<(upp_led-1));
disp = 2;
}
else if(v37 <min_v)
{
ucLed =0;
ucLed ^= (1<<(low_led-1));
disp = 0;
}
else if(v37>=min_v && v37<=max_v)
{
ucLed = 0;
disp =1;
}
LED_Disp(ucLed);
}
void Lcd_Proc(void)
{
if((uwTick - uwTick_Lcd_Set_Point)<100) return;//减速函数
uwTick_Lcd_Set_Point = uwTick;
v37 = 3.3*getADC2()/4096;
if(state == 0) //数据显示
{
sprintf((char *)Lcd_Disp_String, " Main ");
LCD_DisplayStringLine(Line2, Lcd_Disp_String);
sprintf((char *)Lcd_Disp_String, " Volt: %4.2f V ",v37);
LCD_DisplayStringLine(Line5, Lcd_Disp_String);
switch(disp)
{
case 0:
sprintf((char *)Lcd_Disp_String, " Status: Lower ");
break;
case 1:
sprintf((char *)Lcd_Disp_String, " Status: Normal ");
break;
case 2:
sprintf((char *)Lcd_Disp_String, " Status: Upper ");
break;
}
LCD_DisplayStringLine(Line7, Lcd_Disp_String);
}
else //设置界面
{
LCD_SetBackColor(White);
sprintf((char *)Lcd_Disp_String, " Setting ");
LCD_DisplayStringLine(Line1, Lcd_Disp_String);
if(state==1)LCD_SetBackColor(Green); //是该状态则高亮显示
else LCD_SetBackColor(White);
sprintf((char *)Lcd_Disp_String, "Max Volt: %3.1fV ",max_v);
LCD_DisplayStringLine(Line3, Lcd_Disp_String);
LCD_SetBackColor(White); //使之后的不受这个状态的影响
if(state==2)LCD_SetBackColor(Green);
else LCD_SetBackColor(White);
sprintf((char *)Lcd_Disp_String, "Min Volt: %3.1fV ",min_v);
LCD_DisplayStringLine(Line5, Lcd_Disp_String);
LCD_SetBackColor(White);
if(state==3)LCD_SetBackColor(Green);
else LCD_SetBackColor(White);
sprintf((char *)Lcd_Disp_String, "Upper: LD%d ",upp_led);
LCD_DisplayStringLine(Line7, Lcd_Disp_String);
LCD_SetBackColor(White);
if(state==4)LCD_SetBackColor(Green);
else LCD_SetBackColor(White);
sprintf((char *)Lcd_Disp_String, "Lower: LD%d ",low_led);
LCD_DisplayStringLine(Line9, Lcd_Disp_String);
LCD_SetBackColor(White);
}
}
void Error_Handler(void)
{
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
}