题目
逻辑
代码编写
cube外设配置就不写了
adc采集
uint16_t ADC_GetValue(ADC_HandleTypeDef *hadc)
{
uint16_t Value;
HAL_ADC_Start(hadc);
Value=HAL_ADC_GetValue(hadc);
return Value;
}
EEPROM
void EEPROM_Write(uint8_t WriteAddr,uint8_t* writedata,uint8_t Len)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(WriteAddr);
I2CWaitAck();
while(Len--)
{
I2CSendByte(*writedata++);
I2CWaitAck();
}
I2CStop();
HAL_Delay(5);
}
void EEPROM_Read(uint8_t ReadAddr,uint8_t* ReadData,uint8_t Len)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(ReadAddr);
I2CWaitAck();
I2CStart();
I2CSendByte(0xa1);
I2CWaitAck();
while(Len--)
{
*ReadData++=I2CReceiveByte();
if(Len)
{
I2CSendAck();
}
else
{
I2CSendNotAck();
}
}
I2CStop();
HAL_Delay(5);
}
LED
void led_display(uint8_t data)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_All, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOC, data<<8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
按键
这里用的状态机
结构体定义
extern struct keys key[4];
struct keys
{
bool signed_flag;//短按
bool long_flag; //长按
bool double_flag;//双击
bool key_status; //端口电平状态
uint8_t click_status;//按键按下是否稳定(消抖)
int click_time; //按键按下时长
uint8_t double_status;//判断双击与否
int doube_time;//按键之间间隔
};
//定时器扫描按键(10ms)
//采用状态机方式
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM6)
{
//读取端口电平
key[0].key_status=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_status=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_status=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_status=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
//4个按键 进行四次循环
for(uint8_t i=0;i<4;i++)
{
switch(key[i].click_status)
{
case 0:
if(key[i].key_status==GPIO_PIN_RESET)
{
key[i].click_status=1;
}
break;
//端口电平稳定,等效于消抖,进入状态2,按下计时清零,准备使用
case 1:
if(key[i].key_status==GPIO_PIN_RESET)
{
key[i].click_status=2;
key[i].click_time=0;
}
else //如果是高电平相当于不稳定,还在抖动
{
key[i].click_status=0;
}
break;
case 2:
if(key[i].key_status==GPIO_PIN_RESET) //低电平 计时增加
{
key[i].click_time++;
}
//如果检测到高电平—松手并且按下时间大于某某值
if(key[i].key_status==GPIO_PIN_SET&&key[i].click_time>=70)
{
key[i].long_flag=1; //长按标志位
key[i].click_status=0; //按键状态变量恢复初始状态
}
//否则检测到高电平—松手并且按下时间小于某某值
else if(key[i].key_status==GPIO_PIN_SET&&key[i].click_time<70)
{
//双击和短按判断
switch(key[i].double_status)
{
case 0:
key[i].double_status=1; //双击状态置一,第一次按下 松手
key[i].doube_time=0;
break;
case 1:
key[i].double_flag=1; //双击置一
key[i].double_status=0;
break;
}
key[i].click_status=0;
}
break;
}
//四次循环每次都会进入这里判断,这里是为了判断是否短按
if(key[i].double_status==1)//如果双击状态为一,就是按了一下
{
key[i].doube_time++; //双击计时增加
if(key[i].doube_time>=35) //如果大于某某值
{
key[i].signed_flag=1; //短按标志位置一
key[i].double_status=0; //双击状态恢复初始状态
}
}
}
主程序
#include "main.h"
#include "gpio.h"
#include "bsp\adc.h"
#include "bsp\lcd.h"
#include "bsp\led.h"
#include "bsp\key.h"
#include "bsp\rtc.h"
#include "bsp\usart1.h"
#include "bsp\eeprom.h"
#include <string.h>
//函数声明区
void SystemClock_Config(void);
void LCD_display(void);
void UART_SendByte(void);
void led_baojing(void);
//LCD变量
char lcd_data[20];
//串口变量
char str[40]; //发送数据缓存区
uint8_t rx_buffer[6]; //接收数据缓存区
uint8_t rx_index=0; //数据往buf写的顺序
uint8_t Start_Flag=0; //起始判断标志
//题目比例系数
uint8_t K=1;
//减速延时变量
__IO uint32_t uwTick_LED_Time=0;
__IO uint32_t uwTick_LCD_Time=0;
__IO uint32_t uwTick_LCD_interface_Num=0;
//EEPROM读取存储变量
uint8_t eeprom_read;
//设置 时分秒下标
uint8_t i=0;
//报警标志
uint8_t baojing_flag=1;
//RTC闹钟变量
uint8_t clock_moren[3]={0,0,0};//上报闹钟
uint8_t clock_spendone_flag=0; //上报一次标志位
//设置界面变量区
uint8_t interface=0;//0x00显示界面 0x01设置时间界面
uint8_t interface_Num=0;//0--秒 1--分 2--时
uint8_t lcd_clear_flag=0;//界面切换清贫标志
int main(void)
{
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
LCD_Init();
LCD_Clear(White);
LCD_SetTextColor(Blue);
LCD_SetBackColor(White);
LED_GPIO_Init();
ADC2_Init();
Key_GPIO_Init();
Key_TIM();
HAL_TIM_Base_Start_IT(&htim6);
RTC_Init();
USART1_UART_Init();
HAL_UART_Receive_IT(&huart1,rx_buffer,6);
I2CInit();
EEPROM_Read(0,&K,1);
while (1)
{
LCD_display();
RTC_GetTime();
led_baojing();
UART_SendByte();
}
}
//报警函数
void led_baojing(void)
{
if(baojing_flag==1)//报警标志位
{
if((ADC_GetValue(&hadc2)*3.3/4096)>(float)(3.3*K*0.1))//超过阈值
{
if(uwTick-uwTick_LED_Time>=200)//0.2s闪烁
{
uwTick_LED_Time=uwTick;
led_display(0x01);
}
else{led_display(0x00);}
}
}
}
//串口上报函数
void UART_SendByte(void)
{
//到了上报时间
if(RTC_Time.Hours==clock_moren[0]&&RTC_Time.Minutes==clock_moren[1]&&RTC_Time.Seconds==clock_moren[2])
{
if(clock_spendone_flag==0)//只上报一次
{
clock_spendone_flag=1;//只上报一次标志位 置一
sprintf(str,"%.2lf+%.1f+%2d%2d%2d\r\n",(ADC_GetValue(&hadc2)*3.3/4096),(K*0.1),RTC_Time.Hours,RTC_Time.Minutes,RTC_Time.Seconds);
HAL_UART_Transmit(&huart1,(uint8_t*)str,strlen(str),50);
}
}
else //如果不为1
{
clock_spendone_flag=0;
}
}
//LCD显示
void LCD_display(void)
{
// if((uwTick-uwTick_LCD_Time)<500)return; //加入此段代码会让LED变暗,可能因为会影响GPIO操作
// uwTick_LCD_Time=uwTick;
if(interface==0)//如果为界面一
{
sprintf((char*)lcd_data," V1:%1.2fV",(ADC_GetValue(&hadc2)*3.3/4096));
LCD_DisplayStringLine(Line1,(uint8_t *)lcd_data);
sprintf((char*)lcd_data," k:%.1f",(K*0.1));//(K*0.1)
LCD_DisplayStringLine(Line2,(uint8_t*)lcd_data);
sprintf((char*)lcd_data," T:%02d-%02d-%02d",RTC_Time.Hours,RTC_Time.Minutes,RTC_Time.Seconds);
LCD_DisplayStringLine(Line4,(uint8_t *)lcd_data);
if(baojing_flag)
{
sprintf((char*)lcd_data," LED:ON ");
LCD_DisplayStringLine(Line3,(uint8_t *)lcd_data);
}
else
{
sprintf((char*)lcd_data," LED:OFF ");
LCD_DisplayStringLine(Line3,(uint8_t *)lcd_data);
}
if(lcd_clear_flag==1) //如果切换界面 清屏
{
LCD_Clear(White);
lcd_clear_flag=0;
}
}
else if(interface==1)//设置界面
{
sprintf((char*)lcd_data," Setting");
LCD_DisplayStringLine(Line1,(uint8_t *)lcd_data);
sprintf((char*)lcd_data," %02d-%02d-%02d",clock_moren[0],clock_moren[1],clock_moren[2]);
LCD_DisplayStringLine(Line3,(uint8_t *)lcd_data);
if((uwTick-uwTick_LCD_interface_Num)>=200)
{
uwTick_LCD_interface_Num=uwTick;
}
//根据时分秒下标 选择闪烁
switch(interface_Num)
{
case 0:
lcd_data[11]=' ';
lcd_data[10]=' ';
break;
case 1:
lcd_data[8]=' ';
lcd_data[7]=' ';
break;
case 2:
lcd_data[5]=' ';
lcd_data[4]=' ';
break;
}
LCD_DisplayStringLine(Line3,(uint8_t *)lcd_data);
}
if(lcd_clear_flag==1)
{
LCD_Clear(White);
lcd_clear_flag=0;
}
}
//定时器扫描按键(10ms)
//采用状态机方式
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim->Instance==TIM6)
{
//读取端口电平
key[0].key_status=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
key[1].key_status=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
key[2].key_status=HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
key[3].key_status=HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
//4个按键 进行四次循环
for(uint8_t i=0;i<4;i++)
{
switch(key[i].click_status)
{
case 0:
if(key[i].key_status==GPIO_PIN_RESET)
{
key[i].click_status=1;
}
break;
//端口电平稳定,等效于消抖,进入状态2,按下计时清零,准备使用
case 1:
if(key[i].key_status==GPIO_PIN_RESET)
{
key[i].click_status=2;
key[i].click_time=0;
}
else //如果是高电平相当于不稳定,还在抖动
{
key[i].click_status=0;
}
break;
case 2:
if(key[i].key_status==GPIO_PIN_RESET) //低电平 计时增加
{
key[i].click_time++;
}
//如果检测到高电平—松手并且按下时间大于某某值
if(key[i].key_status==GPIO_PIN_SET&&key[i].click_time>=70)
{
key[i].long_flag=1; //长按标志位
key[i].click_status=0; //按键状态变量恢复初始状态
}
//否则检测到高电平—松手并且按下时间小于某某值
else if(key[i].key_status==GPIO_PIN_SET&&key[i].click_time<70)
{
//双击和短按判断
switch(key[i].double_status)
{
case 0:
key[i].double_status=1; //双击状态置一,第一次按下 松手
key[i].doube_time=0;
break;
case 1:
key[i].double_flag=1; //双击置一
key[i].double_status=0;
break;
}
key[i].click_status=0;
}
break;
}
//四次循环每次都会进入这里判断,这里是为了判断是否短按
if(key[i].double_status==1)//如果双击状态为一,就是按了一下
{
key[i].doube_time++; //双击计时增加
if(key[i].doube_time>=35) //如果大于某某值
{
key[i].signed_flag=1; //短按标志位置一
key[i].double_status=0; //双击状态恢复初始状态
}
}
}
//按键按下事件
if(key[0].signed_flag==1) //按键一
{
baojing_flag^=1; //报警
key[0].signed_flag=0;
}
else if(key[1].signed_flag==1) //按键二
{
interface^=1; //界面切换
lcd_clear_flag^=1; //界面切换 清屏
key[1].signed_flag=0;
}
else if(key[2].signed_flag==1) //按键三
{
interface_Num++; //切换设置时分秒 下标
if(interface_Num==3)
{
interface_Num=0;
}
key[2].signed_flag=0;
}
else if(key[3].signed_flag==1) //设置时分秒
{
if(interface_Num==0)
{
clock_moren[2]+=1;
if(clock_moren[2]>=60)
{
clock_moren[2]=0;
}
}
if(interface_Num==1)
{
clock_moren[1]++;
if(clock_moren[1]>=60)
{
clock_moren[1]=0;
}
}
if(interface_Num==2)
{
clock_moren[0]++;
if(clock_moren[0]>=24)
{
clock_moren[0]=0;
}
}
key[3].signed_flag=0;
}
HAL_TIM_Base_Start_IT(&htim6);
}
}
//串口回调函数
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
HAL_UART_Receive_IT(&huart1,rx_buffer,6);
//检验格式
if((rx_buffer[0]=='k')&&(rx_buffer[1]=='0')&&(rx_buffer[2]=='.')&&(rx_buffer[4]=='\\')&&(rx_buffer[5]=='n'))
{
if((rx_buffer[3]>='1')&&(rx_buffer[3]<='9'))
{
K=rx_buffer[3]-0X30;//将字符数字格式转换为整数
HAL_UART_Transmit(&huart1,(uint8_t*)"OK\r",strlen("OK\r"),50);
EEPROM_Write(0,&K,1);
}
}
}