蓝桥杯嵌入式STM32G431——第九届省赛真题电子定时器

该代码是第九届省赛电子定时器的主函数,包括LED、按键和LCD模块的处理。使用了STM32的定时器、I2C通信和LCD显示功能,实现了时间设置、存储、显示及倒计时功能。通过按键操作可切换存储位置、调整时间,并通过LED闪烁指示运行状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

第九届省赛真题

在这里插入图片描述
在这里插入图片描述

主函数代码(不包含各模块初始化代码)

#include "main.h"
#include "rcc.h"
#include "led_key.h"
#include "lcd.h"
#include "tim.h"
#include "i2c.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_KEY_Time_Count;
__IO uint32_t uwTick_Time_Count_down_Crtl;
__IO uint32_t uwTick_LED_BuLingBuLing_Crtl;

//***全局变量区
uint8_t ucLED; //控制LED的变量
//*按键三行代码变量
uint8_t key_value,key_up,key_down;
static uint8_t key_old;

uint8_t LCD_String_Disp[21];

uint8_t Status_Selection = 0; //状态选择变量 默认为0
uint8_t Storage_Location = 1; //存储位置 1-2-3-4-5-1 默认为1

uint8_t Time_Set[3]; //时间设置

__IO uint32_t Time_Count_down_temp; //开始计时时用于存储总秒数的变量

//*子函数声明区
void SystemClock_Config(void);
void LED_Proc(void);
void KEY_Proc(void);
void LCD_Proc(void);
void KEY_B3_Proc(void);



//***主函数区
int main(void)
{
  HAL_Init();

  SystemClock_Config();

	//*初始化函数区
	LED_KEY_Init();
	
	LCD_Init();
	LCD_Clear(Black);
	LCD_SetBackColor(Black);
	LCD_SetTextColor(Magenta);
	
	TIM3_Init();
	//HAL_TIM_PWM_Start(&htim3 , TIM_CHANNEL_1);
	I2CInit();
	
	//*掉电重启后 显示存储位置1的定时时间
	I2C_24c02_read(Time_Set , 0 , 3);	//将默认为存储位置1的数据读入Time_Set
	
  while (1)
  {
    LED_Proc();
		KEY_Proc();
		LCD_Proc();
  }

}

//***子函数区

//*LED处理子函数
void LED_Proc(void)
{
	if((uwTick - uwTick_LED_Speed_Ctrl)<100) return;
		uwTick_LED_Speed_Ctrl = uwTick;	//控制子函数执行速度为100ms
	
	
	LED_Disp(ucLED);
	
}

//*按键B3处理
void KEY_B3_Proc(void)
{
	if(Status_Selection == 1) //高亮小时状态
	{
		Time_Set[0]+=1;  //小时+1
		if(Time_Set[0] == 24)
			Time_Set[0] = 0;
	}
	
	else if(Status_Selection == 2) //高亮分钟状态
	{
		Time_Set[1]+=1;  //分钟+1
		if(Time_Set[1] == 60)
			Time_Set[1] = 0;
	}
	
	else if(Status_Selection == 3) //高亮秒状态
	{
		Time_Set[2]+=1;  //秒+1
		if(Time_Set[2] == 60)
			Time_Set[2] = 0;
	}
	
	
}

//*KEY处理子函数
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;
	
	if(key_down)
	{
		uwTick_KEY_Time_Count = uwTick;
	}
	
	if((uwTick - uwTick_KEY_Time_Count) < 800) //短按
	{
		switch(key_up)
		{
			case 1:	//B1按下 切换存储位置 
				if(Status_Selection == 0)
				{
					if( ++Storage_Location == 6)
						Storage_Location = 1;
					I2C_24c02_read(Time_Set, 3*(Storage_Location-1) ,3); //将对应存储位置的值从EEPROM中读出
				}
				
				break;
			
			case 2:	//B2短按 来回切换时分秒的高亮位置
					if( ++Status_Selection == 4)
						Status_Selection = 1;
				
				break;
				
			case 3:	//B3短按 对应选中的高亮时间+1
					KEY_B3_Proc();
				break;
				
			case 4:	//B4短按 在除Running状态下的任何状态下按下着切换到Running状态 在Running状态下按下则切换至Pause状态
				if(Status_Selection != 4)
				{
					Status_Selection = 4;
					HAL_TIM_PWM_Start(&htim3 , TIM_CHANNEL_1); //定时器开启 PA6口输出PWM信号
				}
				else 
				{
					Status_Selection = 5;
					HAL_TIM_PWM_Stop(&htim3 , TIM_CHANNEL_1); //定时器暂停 停止输出PWM信号
					ucLED = 0x00; //关闭LED
				}
				uwTick_Time_Count_down_Crtl = uwTick; //在B4按下后便开始计时 
				Time_Count_down_temp = Time_Set[0]*3600 + Time_Set[1]*60 + Time_Set[2]; //计时时间的总秒数

				break;
		}
		
		
	}
	else //长按
	{
		switch(key_value)
		{
			
			case 2:	//长按B2 状态选择从时间Seeting界面进入Standby界面 并存储设置的时间
				if(Status_Selection == 1||Status_Selection == 2||Status_Selection == 3)
				{
					Status_Selection = 0; //切换到状态0-Standby界面
					
					//将设置状态的时间写入EEPROM对应的存储位置中 显示在Standby状态的相应存储位置
					I2C_24c02_write(Time_Set, 3*(Storage_Location-1) ,3);						
				}

			
				break;
			
			
			case 3: //B3长按 对应选中的高亮时间持续+1
				KEY_B3_Proc();		
				break;
			
			case 4:	//短按B4 退出Running界面 进入Standby界面
				Status_Selection = 0;
			
				//将EEPROM存储在对应位置的定时时间读入Time_Set
				I2C_24c02_read(Time_Set, 3*(Storage_Location-1) ,3); 
			
				HAL_TIM_PWM_Stop(&htim3 , TIM_CHANNEL_1); //定时器关闭 停止输出PWM信号
				ucLED = 0x00; //关闭LED
				break;
			
		}

	}
}


void LCD_Proc(void)
{
	if((uwTick - uwTick_LCD_Speed_Ctrl)<100) return;
		uwTick_LCD_Speed_Ctrl = uwTick;	//控制子函数执行速度为100ms	
	
	memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp));
	sprintf((char*)LCD_String_Disp , "   No %1d       ",Storage_Location);
	LCD_DisplayStringLine(Line0 , LCD_String_Disp);

	//***只在状态4-Running界面和状态5-Pause界面有效
	if(Status_Selection == 4 || Status_Selection==5)	
	{
		if((uwTick - uwTick_Time_Count_down_Crtl)>=1000)
		{
			uwTick_Time_Count_down_Crtl = uwTick;	//每秒执行一次
			if(Status_Selection == 4) //在状态4-定时器Running状态下 开始倒计时
				Time_Count_down_temp -= 1; //时间减少1s
		}
		//*开启倒计时后以秒为单位变化的时间
		Time_Set[0] = Time_Count_down_temp/3600;			//小时
		Time_Set[1] = Time_Count_down_temp%3600/60;		//分钟
		Time_Set[2] = Time_Count_down_temp%3600%60;		//秒
	}
	
	//***只在状态4定时器开启 Running界面有效
	if(Status_Selection ==4)
	{
		if((uwTick - uwTick_LED_BuLingBuLing_Crtl)>=500)	//定时器开启 LED以0.5s频率闪烁
		{
			uwTick_LED_BuLingBuLing_Crtl = uwTick;		
			ucLED ^=0x01;
		}
	}
	
	
	//void LCD_DisplayChar(u8 Line, u16 Column, u8 Ascii);	//LCD字符显示函数
	//第一个参数代表行 
	//第二个参数代表列第i列的公式为320-(16*i),则代表是i列 
	//第三个参数为需要显示的Ascii码值 数字需要+0x30 字符' '
	
	//***时间显示处理(包含高亮处理)
	if(Status_Selection == 1) LCD_SetBackColor(Blue); //状态1-Seeting状态 高亮显示小时
	LCD_DisplayChar(Line4 , (320 - (16 * 6)) , Time_Set[0]/10 + 0x30);
	LCD_DisplayChar(Line4 , (320 - (16 * 7)) , Time_Set[0]%10 + 0x30);
	LCD_SetBackColor(Black);
	LCD_DisplayChar(Line4 , (320 - (16 * 8)) , ':');
	
	if(Status_Selection == 2) LCD_SetBackColor(Blue); //状态2-Seeting状态 高亮显示分钟
	LCD_DisplayChar(Line4 , (320 - (16 * 9)) , Time_Set[1]/10 + 0x30);
	LCD_DisplayChar(Line4 , (320 - (16 * 10)) , Time_Set[1]%10 + 0x30);
	LCD_SetBackColor(Black);
	LCD_DisplayChar(Line4 , (320 - (16 * 11)) , ':');

	if(Status_Selection == 3) LCD_SetBackColor(Blue); 状态3-Seeting状态 高亮显示秒
	LCD_DisplayChar(Line4 , (320 - (16 * 12)) , Time_Set[2]/10 + 0x30);
	LCD_DisplayChar(Line4 , (320 - (16 * 13)) , Time_Set[2]%10 + 0x30);
	LCD_SetBackColor(Black);
	
	
	//***不同状态对应的界面
	if(Status_Selection == 0) //状态0
	{
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp));
		sprintf((char*)LCD_String_Disp , "       Standby       ");
		LCD_DisplayStringLine(Line7 , LCD_String_Disp);
	}
	else if(Status_Selection == 4)	//状态4
	{
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp));
		sprintf((char*)LCD_String_Disp , "       Running      ");
		LCD_DisplayStringLine(Line7 , LCD_String_Disp);		
	}
	else if(Status_Selection == 5)	//状态4
	{
		
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp));
		sprintf((char*)LCD_String_Disp , "       Pause      ");
		LCD_DisplayStringLine(Line7 , LCD_String_Disp);		
	}
	
	else //状态1-2-3
	{
		memset(LCD_String_Disp , 0 ,sizeof(LCD_String_Disp));
		sprintf((char*)LCD_String_Disp , "       Setting      ");
		LCD_DisplayStringLine(Line7 , LCD_String_Disp);
	}
	
}

按键模块与LCD模块的逻辑图(仅供参考)

在这里插入图片描述

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lzya.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值