真题-设计任务
STM32CubeMx配置
代码撰写
1.按键
uint8_t key1_flag=0;
uint8_t key2_flag=0;
uint8_t key3_flag=0;
uint8_t key4_flag=0;
uint8_t key1_state=1;
uint8_t key2_state=1;
uint8_t key3_state=1;
uint8_t key4_state=1;
uint8_t key1_state_last=1;
uint8_t key2_state_last=1;
uint8_t key3_state_last=1;
uint8_t key4_state_last=1;
/*
* @函 数: KEY_SCAN
* @功 能: 按键扫描
*/
void KEY_SCAN(void)
{
key1_state = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key2_state = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key3_state = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key4_state = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
if(key1_state_last && !key1_state ) key1_flag = 1;
if(key2_state_last && !key2_state ) key2_flag = 1;
if(key3_state_last && !key3_state ) key3_flag = 1;
if(key4_state_last && !key4_state ) key4_flag = 1;
key1_state_last=key1_state;
key2_state_last=key2_state;
key3_state_last=key3_state;
key4_state_last=key4_state;
}
2.LED
/*
* @函 数: KEY_SCAN
* @功 能: 按键扫描
*/
void LED_Disp(uint8_t ucled)
{
//将所有的灯熄灭
HAL_GPIO_WritePin(GPIOC, 0xff<<8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
//根据ucLed的数值点亮相应的灯
HAL_GPIO_WritePin(GPIOC, ucled<<8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}
3.I2C读写
void I2C_Write_EEPROM(uint8_t addr,uint8_t *data,uint8_t len)
{
I2CStart();
I2CSendByte(0XA0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
while(len--)
{
I2CSendByte(*data);
I2CWaitAck();
data++;
}
I2CStop();
delay1(500);
}
void I2C_Read_EEPROM(uint8_t addr,uint8_t *data,uint8_t len)
{
I2CStart();
I2CSendByte(0XA0);
I2CWaitAck();
I2CSendByte(addr);
I2CWaitAck();
I2CStart();
I2CSendByte(0XA1);
I2CWaitAck();
while(len--)
{
*data = I2CReceiveByte();
data++;
if(len)
I2CSendAck();
else
I2CSendNotAck();
}
I2CStop();
}
4.全局变量和函数声明
#define UP 1
#define DOWN 2
//LED相关变量
__IO uint32_t uwTick_LED_Set_Point=0;
uint8_t LED1_Flag=0,LED2_Flag=0,LED3_Flag=0;
//按键相关变量
uint8_t Param_Threshold_Change = 0;
//串口相关变量
uint8_t UART_Receive_Right_Flag = 0;//正确接收为1
uint8_t UART_Receive_Flag = 0;
uint8_t UART_Receive_Buff = 0;
uint8_t UART_Transmit_Buff_C[10]="C:H00+L0\r\n";
uint8_t UART_Transmit_Buff_S[18]="S:TL00+TM00+TH00\r\n";
uint8_t UART_Transmit_Buff_A[12]="A:H00+L0+U\r\n";
//LCD 相关变量
uint8_t LCD_Buff[40];
uint8_t LCD_Page = 0;
uint8_t LCD_Parameter=1;
//ADC 相关变量
uint16_t ADC_REG_Value=0;
uint32_t ADC_REG_Value_Sum=0;
float ADC_Value_R37=0;
__IO uint32_t uwTick_ADC_Set_Point=0;
uint8_t Liquid_Height = 0;
uint8_t Liquid_Level = 0;
uint8_t Liquid_Level_last;
uint8_t Liquid_Level_Change=0;
//阈值结构体
typedef struct
{
uint8_t Threshold1;
uint8_t Threshold2;
uint8_t Threshold3;
}Threshold;
//声明一个阈值结构体
Threshold Thres={30,50,70};
//按键相关变量
__IO uint32_t uwTick_Key_Pro = 0;
//函数声明
void LCD_UI(void);
void Get_ADC_Value(void);
void Key_Process(void);
void UART_Process(void);
void Write_Threshold_To_EEPROM(void);
void Read_Threshold_From_EEPROM(void);
void LED_Process(void);
5.主函数编写
/* 关闭所有LED */
LED_Disp(0X00);
/* 屏幕初始化 */
LCD_Init();
LCD_SetTextColor(White);
LCD_SetBackColor(Black);
LCD_Clear(Black);
//I2C初始化
I2CInit();
//从EEPROM读取数据,也有更好的操作在后几篇中会提到
//Write_Threshold_To_EEPROM();//第一次运行的时候可以先执行写入
Read_Threshold_From_EEPROM();//写入过才能读取
//开启串口接收中断
HAL_UART_Receive_IT(&huart1,(uint8_t*)&UART_Receive_Buff,1);
while (1)
{
//按键处理
Key_Process();
//获取电压值
Get_ADC_Value();
//LED处理
LED_Process();
//串口处理
UART_Process();
//LCD UI控制
LCD_UI();
//写数据到EEPROM
Write_Threshold_To_EEPROM();
}
6、LCD显示
/*
* @函 数: LCD_UI
* @功 能: 屏幕显示界面
*/
void LCD_UI(void)
{
if(!LCD_Page)
{
LCD_SetBackColor(Black);
LCD_DisplayStringLine(Line0,(uint8_t*)" Liquid Level ");
sprintf((char*)LCD_Buff," Height: %d ",Liquid_Height);
LCD_DisplayStringLine(Line3,(uint8_t*)LCD_Buff);
sprintf((char*)LCD_Buff," ADC: %.2f ",ADC_Value_R37);
LCD_DisplayStringLine(Line5,(uint8_t*)LCD_Buff);
sprintf((char*)LCD_Buff," Level: %d ",Liquid_Level);
LCD_DisplayStringLine(Line7,(uint8_t*)LCD_Buff);
}
else
{
LCD_SetBackColor(Black);
LCD_DisplayStringLine(Line0,(uint8_t*)" Parameter Setup");
if(LCD_Parameter==1) { LCD_SetBackColor(Red); }
else { LCD_SetBackColor(Black);}
sprintf((char*)LCD_Buff," Threshold 1: %d ",Thres.Threshold1);
LCD_DisplayStringLine(Line3,(uint8_t*)LCD_Buff);
if(LCD_Parameter==2) { LCD_SetBackColor(Red); }
else { LCD_SetBackColor(Black);}
sprintf((char*)LCD_Buff," Threshold 2: %d ",Thres.Threshold2);
LCD_DisplayStringLine(Line5,(uint8_t*)LCD_Buff);
if(LCD_Parameter==3) { LCD_SetBackColor(Red); }
else { LCD_SetBackColor(Black);}
sprintf((char*)LCD_Buff," Threshold 3: %d ",Thres.Threshold3);
LCD_DisplayStringLine(Line7,(uint8_t*)LCD_Buff);
}
}
7、ADC读取
/*
* @函 数: Get_ADC_Value
* @功 能: 获取 R37 的电压值并判断
*/
void Get_ADC_Value(void)
{
if(uwTick - uwTick_ADC_Set_Point<1000) return;
uwTick_ADC_Set_Point = uwTick;
/* 启动 ADC */
HAL_ADC_Start(&hadc2);
//中值滤波
ADC_REG_Value_Sum = 0;
for(int i=0;i<10;i++)
{//采集10次电压值
ADC_REG_Value_Sum += HAL_ADC_GetValue(&hadc2);
}
//对采集的10次的原始数据求均值
ADC_REG_Value = ADC_REG_Value_Sum/10;
//计算实际电压值
ADC_Value_R37 = ADC_REG_Value*3.3/4096;
/*************数据处理***************/
//液体高度
Liquid_Height = 100.0*ADC_Value_R37/3.3;
if(Liquid_Height>100) Liquid_Height = 100;//限幅
//液位等级判断 30 50 70
if (Liquid_Height<=Thres.Threshold1) Liquid_Level = 0;
else if(Liquid_Height<=Thres.Threshold2) Liquid_Level = 1;
else if(Liquid_Height<=Thres.Threshold3) Liquid_Level = 2;
else Liquid_Level = 3;
//判断液位等级是否发生变换
if(Liquid_Level>Liquid_Level_last) Liquid_Level_Change = UP;
else if(Liquid_Level_last>Liquid_Level) Liquid_Level_Change = DOWN;
//保存前一次液位等级
Liquid_Level_last = Liquid_Level;
}
8、LED处理
/*
* @函 数: LED_Process
* @功 能: LED处理
*/
void LED_Process(void)
{
if(Liquid_Level_Change)//当液位等级发生改变时,LED2_Flag=1
{
LED2_Flag = 1;
}
if(UART_Receive_Right_Flag)//当串口接收到正确数据时,LED3_Flag=1
{
UART_Receive_Right_Flag = 0;
LED3_Flag = 1;
}
if((uwTick-uwTick_LED_Set_Point)<200) return;//每隔200ms进入一次
uwTick_LED_Set_Point = uwTick;
static uint8_t LED_Ctrl = 0;
static uint8_t LED1_1S=0,LED2_200MS=0,LED3_200MS=0;
LED1_1S++;
if(LED2_Flag) //控制10次取反
{
LED2_200MS++;
if(LED2_200MS==11)//10次取反,不需要第11次,第十一次的时候全部置零
{
LED2_200MS = 0;
LED2_Flag = 0;
}
}
if(LED3_Flag) //同上
{
LED3_200MS++;
if(LED3_200MS==11)
{
LED3_200MS = 0;
LED3_Flag = 0;
}
}
if(LED1_1S==5){ LED1_1S=0;LED_Ctrl^=0x01;}//每隔1s取一次反
if(LED2_200MS){ LED_Ctrl^=0x02; } //每隔200ms取一次反
if(LED3_200MS){ LED_Ctrl^=0X04; } //每隔200ms取一次反
LED_Disp(LED_Ctrl);
}
9、按键处理
/*
* @函 数: Key_Process
* @功 能: 获取按键状态进行相并处理
*/
void Key_Process(void)
{
if((uwTick-uwTick_Key_Pro)<100) return;
uwTick_Key_Pro = uwTick;
//进行按键扫描
KEY_SCAN();
//通过扫描获得的状态进行按键处理
if(key1_flag)
{
key1_flag = 0;
LCD_Page = !LCD_Page;
}
else if(key2_flag)
{
key2_flag = 0;
if(LCD_Page)
LCD_Parameter++;
if(LCD_Parameter>3)LCD_Parameter=1;
}
else if(key3_flag)
{
key3_flag = 0;
if(LCD_Page) Param_Threshold_Change = 1;
if(LCD_Parameter==1)
{
Thres.Threshold1 +=5; Thres.Threshold1 = (Thres.Threshold1>95)?95:Thres.Threshold1;
}
else if(LCD_Parameter==2)
{
Thres.Threshold2 +=5; Thres.Threshold2 = (Thres.Threshold2>95)?95:Thres.Threshold2;
}
else if(LCD_Parameter==3)
{
Thres.Threshold3 +=5; Thres.Threshold3 = (Thres.Threshold3>95)?95:Thres.Threshold3;
}
}
else if(key4_flag)
{
if(LCD_Page) Param_Threshold_Change = 1;
key4_flag = 0;
if(LCD_Parameter==1)
{
Thres.Threshold1 -=5; Thres.Threshold1 = (Thres.Threshold1<5)?5:Thres.Threshold1;
}
else if(LCD_Parameter==2)
{
Thres.Threshold2 -=5; Thres.Threshold2 = (Thres.Threshold2<5)?5:Thres.Threshold2;
}
else if(LCD_Parameter==3)
{
Thres.Threshold3 -=5; Thres.Threshold3 = (Thres.Threshold3<5)?5:Thres.Threshold3;
}
}
}
10、当阈值变化时写入EEPROM
/*
* @函 数: Write_Threshold_To_EEPROM
* @功 能: 将阈值存到EEPROM里面
*/
void Write_Threshold_To_EEPROM(void)
{
if(Param_Threshold_Change)
{
//满足改液位阈值条件才写入EEPROM
if(Thres.Threshold1<Thres.Threshold2 &&
Thres.Threshold1<Thres.Threshold3 &&Thres.Threshold2<Thres.Threshold3 )
{
uint8_t temp[3]={Thres.Threshold1,Thres.Threshold2,Thres.Threshold3};
I2C_Write_EEPROM(0,temp,3);
HAL_Delay(10);
Param_Threshold_Change = 0;
}
}
}
11、读取EEPROM的值
/*
* @函 数: Read_Threshold_From_EEPROM
* @功 能: 单片机上电后从RRPROM中读取数据
*/
void Read_Threshold_From_EEPROM(void)
{
uint8_t temp[3];
I2C_Read_EEPROM(0,temp,3);
Thres.Threshold1= temp[0];
Thres.Threshold2= temp[1];
Thres.Threshold3= temp[2];
}
12、串口相关处理
/*
* @函 数: UART_Process
* @功 能: 串口处理
*/
void UART_Process(void)
{
if(Liquid_Level_Change)//判断液位等级发生变换
{
UART_Transmit_Buff_A[3] = Liquid_Height /10%10+ '0';
UART_Transmit_Buff_A[4] = Liquid_Height %10 + '0';
UART_Transmit_Buff_A[7] = Liquid_Level + '0';
if(Liquid_Level_Change == UP) { UART_Transmit_Buff_A[9] = 'U'; }
else if(Liquid_Level_Change == DOWN) { UART_Transmit_Buff_A[9] = 'D'; }
HAL_UART_Transmit(&huart1,(uint8_t*)&UART_Transmit_Buff_A,12,5000);
Liquid_Level_Change = 0;
}
if(UART_Receive_Flag==1) //判断串口是否接收到数据
{
UART_Receive_Flag = 0;
if(UART_Receive_Buff=='C')
{
UART_Receive_Right_Flag = 1;
UART_Transmit_Buff_C[3] = Liquid_Height /10%10+ '0';
UART_Transmit_Buff_C[4] = Liquid_Height %10 + '0';
UART_Transmit_Buff_C[7] = Liquid_Level + '0';
HAL_UART_Transmit(&huart1,(uint8_t*)&UART_Transmit_Buff_C,10,5000);
}
if(UART_Receive_Buff=='S')
{
UART_Receive_Right_Flag = 1;
UART_Transmit_Buff_S[4] = Thres.Threshold1 /10%10+ '0';
UART_Transmit_Buff_S[5] = Thres.Threshold1 %10 + '0';
UART_Transmit_Buff_S[9] = Thres.Threshold2 /10%10+ '0';
UART_Transmit_Buff_S[10] = Thres.Threshold2 %10 + '0';
UART_Transmit_Buff_S[14] = Thres.Threshold3 /10%10+ '0';
UART_Transmit_Buff_S[15] = Thres.Threshold3 %10 + '0';
HAL_UART_Transmit(&huart1,(uint8_t*)&UART_Transmit_Buff_S,18,5000);
}
}
}
/*
* @函 数: HAL_UART_RxCpltCallback
* @功 能: 串口中断回调函数
*/
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
UART_Receive_Flag = 1;
HAL_UART_Receive_IT(&huart1,(uint8_t*)&UART_Receive_Buff,1);
}
|