STM32HAL库【G431】--【蓝桥杯嵌入式第九届省赛题】

完整工程(百度网盘免费下载,提取码:0403)和演示视频在文章末尾,需要请移步至文章末尾。

第九届嵌入式省赛题目

在这里插入图片描述

涉及模块主要代码

主要变量与结构体

struct keys//按键结构体
{
	uchar key_judge;//按键判断状态
	bool key_sta;//按键实时状态
	uint key_time;//按键持续时间
	bool key_single;//短按按键标志
	bool key_long;//长按按键标志
};
struct times //时间结构体
{
	uchar time_hour;
	uchar time_min;
	uchar time_sec;
	
	uchar time_hms_mode;

};
struct keys key[4]={0,0,0,0,0,0};//初始化按键
uchar ctimer=0;//消抖时间
uint led_ntimer=0;//led闪烁时间变量
bool led_flag=0;//led闪烁标志位
uchar time_No=0;//第几个时间
	
struct times time[5] = {0,1,55,0};//初始化时间变量
char lcd_buffer[20];//lcd显示缓存
uchar key_long_time=0;//长按按键,数值增加的时间
uint count_douwn=0;//倒计时变量

bool run_flag=0; 
uint secs=0;//总秒数

bool cf_1=0,cf_2=0;// 00:standby 01:setting 10:running 11:pause

按键模块

在按键部分,从题目得知,有短按长按,并且有长按连续增加。因此在捣鼓按键中,我利用了状态机的思想,对按键B1,B2,B3,B4按键进行判断,由于题目中,只需要B3按键连续增加,所以我没有让其他按键拥有此功能。
主要代码如下:

#include "stdbool.h"
#define uchar unsigned char
#define uint unsigned int
struct keys
{
	uchar key_judge;//按键判断状态
	bool key_sta;//按键实时状态
	uint key_time;//按键持续时间
	bool key_single;//短按按键标志
	bool key_long;//长按按键标志
};
void Key_Scan(void)//按键判断
{

	key[0].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);
	key[1].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);
	key[2].key_sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);
	key[3].key_sta = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
	
	for(uchar i=0; i<4; i++)//本段逻辑类似于FPGA中的状态机
	{
		switch(key[i].key_judge)
		{
			case 0://状态0
			{
				if(key[i].key_sta==0)
				{
					key[i].key_judge=1;
					key[i].key_time=0;
				}
			}break;
			case 1://状态1,按键消抖
			{
				if(ctimer++>=10)//10ms
				{
					ctimer=0;
					if(key[i].key_sta==0)key[i].key_judge=2;
					else key[i].key_judge =0;
			  }	
			}break;
			case 2://状态2,判断成功按下,处理按键
			{
				if(ctimer++>=10)//10ms
				{
					ctimer=0;
					if(key[i].key_sta==0)key[i].key_time++;//一直按下,时间增加
					if(key[i].key_time<80 && key[i].key_sta==1)//短按
					{
						key[i].key_single=1;
						key[i].key_judge=0;
					}
					else if(key[i].key_time>=80)//长按超过0.8s
					{
						if(key[i].key_sta==0)
						{
							if(i==2)//按键b3,长按一直增加的特殊功能
							{
								key_long_time++;
								if(key_long_time>=10)key[i].key_long=1;//长按时,每隔0.1s把标志位,置1
								key_long_time%=10;
							}
						}
						else//松开按键后,除开B3的特殊功能,把标志位,置1 
						{
							key[i].key_judge=0;
							if(i!=2)key[i].key_long=1;
						}
					}
				}
			}break;
		}
	}

倒计时模块

处理倒计时时,我们可以利用中断进行。其中一个重要的思想就是,将倒计时的时间转化成秒,LCD显示时,再把秒转换成具体时间就可以。根据时间的进制关系,我们可以写出如下代码。

void Time_to_secs(void)//将时间转化成秒,方便倒计时,定义的uint可能不够,可继续扩大
{
	secs = time[time_No].time_hour *3600 + time[time_No].time_min *60 + time[time_No].time_sec;
}
void Secs_to_time(void)//将秒转化成时间
{
	time[time_No].time_hour =secs /3600;
	time[time_No].time_min = secs %3600 /60;
	time[time_No].time_sec = secs %3600 %60;
}
void B4_process(void)//按键b4处理,倒计时处理
{
	if(key[3].key_single==1)
	{
		run_flag=!run_flag;
		if(run_flag){cf_1=1;cf_2=0;}//倒计时启动
		else {cf_1=1;cf_2=1;}//倒计时暂停
		key[3].key_single=0;
		LCD_ClearLine(Line4);
		LCD_ClearLine(Line6);	}
	if(count_douwn>=1000)
	{
		Time_to_secs();
		if(secs !=0)secs--;
		else cf_1=cf_2=0;		
		Secs_to_time();
		count_douwn=0;
	}
}

EEPROM模块

我们将比赛给的资源库中,HAL库的IIC底层代码加入到我们自己的工程中,然后增加如下代码

EEPROM读取

EERPOM地址:图中MSB是最高有效位,LSB是最低有效位,LSB为1时是读取,为0时是写入。
在这里插入图片描述
因为E1,E2,E3全部接地,所以A0,A1,A2全部为0
在这里插入图片描述

读取时序图:
在这里插入图片描述
根据时序写出EEPROM读取代码:

uchar EEPROM_Read(uchar add)//EEPROM读取
{
	uchar temp;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(add);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	
	temp = I2CReceiveByte();
	I2CStop();
	
	return temp;
}

EEPROM写入

写入时序图:
在这里插入图片描述根据时序写出EEPROM写入代码:

void EEPROM_Wite(uchar add, uchar dat)//EEPROM写入
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	
	I2CSendByte(add);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}

LCD移植

LCD原理图
在STM32CudeMx中将图中所有引脚设置为输出模式(除LCD_RST外,不用管LCD_RST,因为它在硬件上连接到了复位引脚),再将赛点资源包中的lcd.c,lcd.h,font.h复制到自己的工程文件下即可。
在这里插入图片描述
在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
在main.c中加入如下代码,点h文件是头文件,其他代码加入main函数即可使用

#include "lcd.h”
LCD_Init();//初始化lcd
LCD_Clear(Black);//设置lcd背景
LCD_SetBackColor(Black);//设置每行背景
LCD_SetTextColor(White);//设置字体颜色
LCD_DisplayStringLine(Line0,"Hello World!");

完整功能演示视频

完整工程文件(HAL库)

嵌入式赛点资源包(2023)

总结

自己写的代码,不喜勿喷,欢迎参考
以上就是本次的全部内容了,第一次写博客,记录一下。
想联系笔者请私信就好。

  • 6
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值