蓝桥杯嵌入式第六届

题目

逻辑

代码编写

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);
			}
		}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值