草庐IT

第十三届蓝桥杯嵌入式省赛第二场真题(基于HAL库的巨简代码+超级详解)

魏丶 2023-06-18 原文

文章目录


前言

相关说明:

开发板:CT117E-M4(STM32G431RBT6)
开发环境: CubeMX+Keil5
涉及题目:第十三届蓝桥杯嵌入式省赛第二场真题


CubeMX配置、主要函数代码及说明:

一、CubeMX配置(第十三届省赛第二场真题)

1.使能外部高速时钟:

2.配置时钟树:

3.GPIO:

4.TIM2(通道2 PA1输出脉冲信号):

5.UART:

6.NVIC优先级配置


二、代码相关定义、声明

1.变量声明

unsigned char x[3]={0,10,10};//定义商品X数组 并分别对应初始化为购买数量、10倍单价、库存数量
unsigned char y[3]={0,10,10};//定义商品Y数组 并分别对应初始化为购买数量、10倍单价、库存数量
unsigned char jiemian;//显示界面  0为商品购买界面  1为商品价格界面  2为库存信息界面
unsigned char uled;//LED显示参数
unsigned char tx[21],rx,rx_buf[7],dex;//串口相关变量
unsigned char pwm;//初始为0  默认输出占空比5%脉冲  1为输出占空比30%的脉冲
unsigned char e2prom[7];//将从E2PROM中读出的数据暂存此数组中
__IO uint32_t PWM_Tick;//计时脉冲输出时间
__IO uint32_t LED_Tick;//计时LED显示时间

2.函数声明

void Key_Proc();
void Lcd_Proc();
void Uart_Proc();
void Led_Proc();

三、主要函数

1.main函数

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  LCD_Init();
  LCD_Clear(Black);
  LCD_SetBackColor(Black);
  LCD_SetTextColor(White);
  I2CInit();
	
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
  HAL_UART_Receive_IT(&huart1,&rx,1);
	
  IIC_Read(e2prom,0,7);//读出E2PROM存储的商品信息和是否第一次运行标志位
  HAL_Delay(100);
  if((e2prom[4]==0x77)&&(e2prom[5]==0x7A)&&(e2prom[6]==0x64))//STM32不是第一次运行
  {
	 x[2]=e2prom[0];//商品信息数据交换
 	 y[2]=e2prom[1];
	 x[1]=e2prom[2];
	 y[1]=e2prom[3];
  }
  else//STM32第一次运行
  {
	 e2prom[4]=0x77;e2prom[5]=0x7A;e2prom[6]=0x64;//博主自定义的信息  表示STM正在运行第一次
	 e2prom[0]=x[2];e2prom[1]=y[2];e2prom[2]=x[1];e2prom[3]=y[1];//将初始的商品库存和价格按规定的位置写入E2PROM
	 IIC_Write(e2prom,0,7);
  }
	
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	Key_Proc();
    Lcd_Proc();
    Uart_Proc();
    Led_Proc();
  }
  /* USER CODE END 3 */
}

2.按键扫描、E2PROM存储、打印购买信息

void Key_Proc()
{
	static __IO uint32_t Key_Tick;//减速变量
	static unsigned char key_old;
	unsigned char key_down,key_value;
	
	if(uwTick-Key_Tick<50)
		return;
	Key_Tick=uwTick;
	
	key_value=Key_Scan();
	key_down=key_value&(key_value^key_old);
	key_old=key_value;
	
	switch(key_down)
	{
		case 1:
			if(++jiemian>2)//界面切换
				jiemian=0;
			LCD_Clear(Black);//切换屏幕时清屏
		break;
		
		case 2://商品x
			if(jiemian==0)//商品购买界面
			{
				if(++x[0]>x[2])
					x[0]=0;
			}
			else if(jiemian==1)//商品价格界面
			{
				if(++x[1]>20)
					x[1]=10;
				IIC_Write(&x[1],2,1);//写入E2PROM商品x单价
			}
			else//商品库存界面
			{
				x[2]++;
				IIC_Write(&x[2],0,1);//写入E2PROM商品x库存数量
			}
		break;
		
		case 3://商品y
			if(jiemian==0)//商品购买界面
			{
				if(++y[0]>y[2])
					y[0]=0;
			}
			else if(jiemian==1)//商品价格界面
			{
				if(++y[1]>20)
					y[1]=10;
				IIC_Write(&y[1],3,1);//写入E2PROM商品y单价
			}
			else//商品库存界面
			{
				y[2]++;
				IIC_Write(&y[2],1,1);//写入E2PROM商品y库存数量
			}
		break;
		
		case 4://商品确认键
			if(jiemian==0)//商品购买界面
			{
				x[2]=x[2]-x[0];//商品x库存减少
				y[2]=y[2]-y[0];//商品y库存减少
				if(x[0]!=0)//商品X购买数量不为0  库存发生变化
			        IIC_Write(&x[2],0,1);//写入E2PROM商品x库存数量
				sprintf((char*)tx,"X:%d,Y:%d,Z:%0.1f\n",x[0],y[0],0.1*x[0]*x[1]+0.1*y[0]*y[1]);//打印总价、发送购买信息
				HAL_UART_Transmit(&huart1,tx,strlen(tx),50);
				uled|=0x01;//指示灯LED1点亮
				LED_Tick=uwTick;//LED显示计时开始
				pwm=1;//输出2kHz  占空比30%脉冲
				PWM_Tick=uwTick;//输出脉冲计时开始
				if(y[0]!=0)//商品Y购买数量不为0  库存发生变化
				    IIC_Write(&y[2],1,1);//写入E2PROM商品y库存数量
				x[0]=y[0]=0;//商品购买数量重置为0
			}
		break;
	}
}

3.屏幕显示、PWM输出

void Lcd_Proc()
{
	static __IO uint32_t Lcd_Tick;//减速变量
	
	unsigned char lcd_string[21];
	
	if(uwTick-Lcd_Tick<100)
		return;
	Lcd_Tick=uwTick;
	
	if(pwm==0)//输出2kHz  占空比5%脉冲
		__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,25);
	else//输出2kHz  占空比30%脉冲
		__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,150);
	
	if(uwTick-PWM_Tick>5000)//脉冲输出时间达到5秒
		pwm=0;//输出5秒后转换为占空比5%的脉冲
	
	if(jiemian==0)//商品购买界面时
	{
		sprintf((char*)lcd_string,"        SHOP");
		LCD_DisplayStringLine(Line1,lcd_string);
		sprintf((char*)lcd_string,"     X:%d",x[0]);//显示商品X的购买数量
		LCD_DisplayStringLine(Line3,lcd_string);
		sprintf((char*)lcd_string,"     Y:%d",y[0]);//显示商品Y的购买数量
		LCD_DisplayStringLine(Line4,lcd_string);
	}
	else if(jiemian==1)//商品价格界面时
	{
		sprintf((char*)lcd_string,"        PRICE");
		LCD_DisplayStringLine(Line1,lcd_string);
		sprintf((char*)lcd_string,"     X:%3.1f",0.1*x[1]);
		LCD_DisplayStringLine(Line3,lcd_string);
		sprintf((char*)lcd_string,"     Y:%3.1f",0.1*y[1]);
		LCD_DisplayStringLine(Line4,lcd_string);
	}
	else
	{
		sprintf((char*)lcd_string,"        REP");
		LCD_DisplayStringLine(Line1,lcd_string);
		sprintf((char*)lcd_string,"     X:%d   ",x[2]);
		LCD_DisplayStringLine(Line3,lcd_string);
		sprintf((char*)lcd_string,"     Y:%d   ",y[2]);
		LCD_DisplayStringLine(Line4,lcd_string);
	}
}

4.判断串口接收数据是否合法

unsigned char isRxCplt()//接收数据合法时返回值为1
{
	unsigned char i;
	
	if(dex==0)//未接收到数据
		return 0;
	if(dex!=1)//接收数据不为1个ASCII时不合法
		return 2;
	if(rx_buf[0]==0x3F)//接收数据为'?'时
		return 1;
	else//接收数据不为'?'时不合法
		return 2;
}

5.查询当前商品价格

void Uart_Proc()
{
	static __IO uint32_t Uart_Tick;//减速变量
	
	if(uwTick-Uart_Tick<100)
		return;
	Uart_Tick=uwTick;
	
	if(isRxCplt()==1)//接收数据合法
	{
		sprintf((char*)tx,"X:%3.1f,Y:%3.1f\n",0.1*x[1],0.1*y[1]);
		HAL_UART_Transmit(&huart1,tx,strlen(tx),50);//向上位机发送OK表示修改成功
	}
	else if(isRxCplt()==2)//接收数据不合法
	{
		sprintf((char*)tx,"Query format error\n");
		HAL_UART_Transmit(&huart1,tx,strlen(tx),50);//向上位机发送Error表示修改失败
	}
	
	dex=0;//清除串口接收数组索引
}

6.串口中断

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	rx_buf[dex++]=rx;//一位一位存入缓存数组  索引+1
	
	HAL_UART_Receive_IT(&huart1,&rx,1);//重新开启接收中断
}

7.LED指示功能

void Led_Proc()
{
	static __IO uint32_t Led_Tick;//减速变量
	
	if(uwTick-Led_Tick<100)//0.1秒间隔闪烁
		return;
	Led_Tick=uwTick;
	
	if(uwTick-LED_Tick>=5000)//LED1点亮时间达到5秒
		uled&=~0x01;//指示灯LED1熄灭
	
	if((x[2]==0)&&(y[2])==0)//商品x和商品y库存均为0
		uled^=0x02;//LED2以0.1秒间隔闪烁
	else
		uled&=~0x02;//指示灯LED2熄灭
	
	Led_Disp(uled);
}

四、编程感受、细节剖析、赛前预测

   博主参加的是第一场,第二场结束后由于学校统一做核酸,未能及时发布,第一时间收到真题后,便打开了电脑STM32CubeMx软件配置,第二场的题和第一场的很像,万变不离其宗,博主也是很快就写好了代码。
   第二场的串口很简单,只是接收一个字符和发送一个字符串,很常规,难点在于连续改价格和库存时E2PROM的连续读写,但放入按键扫面里面就可以很好的解决这个问题,而且题目要求库存发生变化时才写入E2PROM,所以当购买数量为0时,按下B4键不应进行E2PROM的写入,同时单片机第一次上电的时候需要满足题意的价格1.0,库存10,之后重新上电应保证掉电保存,所以需要判断一下你的单片机是否第一次上电,再者需要注意的是两个库存均为0时LED2才开始以0.1秒间隔闪烁。细节很多,但各个模块都很常规,不难,相信各位大佬都能游刃有余。
   赛前一晚有学弟问我串口相关方面的知识,然后给他预测了一下会考察的模块,今天应征了我的预测,还挺开心的。
   在这里提前预祝各位大佬都能拿下省一,共同进击国赛!


五、链接

1.第十三届蓝桥杯嵌入式省赛第二场真题PDF

2.第十三届蓝桥杯嵌入式国赛真题(基于HAL库的巨简代码+超级详解)

3.第十三届蓝桥杯嵌入式省赛第一场真题(基于HAL库的巨简代码+超级详解)

4.第十二届蓝桥杯嵌入式省赛第一场真题(基于HAL库的巨简代码+超级详解)

有关第十三届蓝桥杯嵌入式省赛第二场真题(基于HAL库的巨简代码+超级详解)的更多相关文章

  1. 华为OD机试真题 C++ 实现【带传送阵的矩阵游离】【2023 Q2 | 200分】 - 2

            所有题目均有五种语言实现。C实现目录、C++实现目录、Python实现目录、Java实现目录、JavaScript实现目录题目n行m列的矩阵,每个位置上有一个元素你可以上下左右行走,代价是前后两个位置元素值差的绝对值.另外,你最多可以使用一次传送阵(只能从一个数跳到另外一个相同的数)求从走上角走到右下角最少需要多少时间。输入描述:第一行两个整数n,m,分别代表矩阵的行和列。后面n行,每行m个整数,分别代表矩阵中的元素。输出描述:一个整数,表示最少需要多少时间。

  2. 蓝桥杯备赛(二) - 2

    目录前言: 一、ASC分析代码实现二、 卡片分析代码实现三、 直线分析代码实现四、货物摆放分析代码实现小结:前言:  在刷题的过程中,发现蓝桥杯的题目和力扣的差别很大。让人有一种不一样的感觉,蓝桥杯题目偏向对于实际问题用编程去的解决,而力扣给人感觉很锻炼自己的编程思维,逻辑能力。两者结合去刷,相信会有不一样的收获。 一、ASC  已知大写字母A的ASCII码为65,请问大写字母L的ASCII码是多少?分析  这道题目看上去很简单,我们需确定自己计算的准确,所以我建议用编程去解决。代码实现publicclassTest8{publicstaticvoidmain(String[]args){Sy

  3. 物联网MQTT协议详解 - 2

    一、什么是MQTT协议MessageQueuingTelemetryTransport:消息队列遥测传输协议。是一种基于客户端-服务端的发布/订阅模式。与HTTP一样,基于TCP/IP协议之上的通讯协议,提供有序、无损、双向连接,由IBM(蓝色巨人)发布。原理:(1)MQTT协议身份和消息格式有三种身份:发布者(Publish)、代理(Broker)(服务器)、订阅者(Subscribe)。其中,消息的发布者和订阅者都是客户端,消息代理是服务器,消息发布者可以同时是订阅者。MQTT传输的消息分为:主题(Topic)和负载(payload)两部分Topic,可以理解为消息的类型,订阅者订阅(Su

  4. STM32的HAL和LL库区别和性能对比 - 2

    LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L

  5. Tcl脚本入门笔记详解(一) - 2

    TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是

  6. 【详解】Docker安装Elasticsearch7.16.1集群 - 2

    开门见山|拉取镜像dockerpullelasticsearch:7.16.1|配置存放的目录#存放配置文件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/config#存放数据的文件夹mkdir-p/opt/docker/elasticsearch/node-1/data#存放运行日志的文件夹mkdir-p/opt/docker/elasticsearch/node-1/log#存放IK分词插件的文件夹mkdir-p/opt/docker/elasticsearch/node-1/plugins若你使用了moba,直接右键新建即可如上图所示依次类推创建

  7. 【Elasticsearch基础】Elasticsearch索引、文档以及映射操作详解 - 2

    文章目录概念索引相关操作创建索引更新副本查看索引删除索引索引的打开与关闭收缩索引索引别名查询索引别名文档相关操作新建文档查询文档更新文档删除文档映射相关操作查询文档映射创建静态映射创建索引并添加映射概念es中有三个概念要清楚,分别为索引、映射和文档(不用死记硬背,大概有个印象就可以)索引可理解为MySQL数据库;映射可理解为MySQL的表结构;文档可理解为MySQL表中的每行数据静态映射和动态映射上面已经介绍了,映射可理解为MySQL的表结构,在MySQL中,向表中插入数据是需要先创建表结构的;但在es中不必这样,可以直接插入文档,es可以根据插入的文档(数据),动态的创建映射(表结构),这就

  8. 蓝桥杯C/C++VIP试题每日一练之报时助手 - 2

    ?作者主页:静Yu?简介:CSDN全栈优质创作者、华为云享专家、阿里云社区博客专家,前端知识交流社区创建者?社区地址:前端知识交流社区?博主的个人博客:静Yu的个人博客?博主的个人笔记本:前端面试题个人笔记本只记录前端领域的面试题目,项目总结,面试技巧等等。接下来会更新蓝桥杯官方系统基础练习的VIP试题,依然包括解题思路,源代码等等。问题描述:给定当前的时间,请用英文的读法将它读出来。时间用时h和分m表示,在英文的读法中,读一个时间的方法是:  如果m为0,则将时读出来,然后加上“o’clock”,如3:00读作“threeo’clock”。  如果m不为0,则将时读出来,然后将分读出来,如5

  9. 最强Http缓存策略之强缓存和协商缓存的详解与应用实例 - 2

    HTTP缓存是指浏览器或者代理服务器将已经请求过的资源保存到本地,以便下次请求时能够直接从缓存中获取资源,从而减少网络请求次数,提高网页的加载速度和用户体验。缓存分为强缓存和协商缓存两种模式。一.强缓存强缓存是指浏览器直接从本地缓存中获取资源,而不需要向web服务器发出网络请求。这是因为浏览器在第一次请求资源时,服务器会在响应头中添加相关缓存的响应头,以表明该资源的缓存策略。常见的强缓存响应头如下所述:Cache-ControlCache-Control响应头是用于控制强制缓存和协商缓存的缓存策略。该响应头中的指令如下:max-age:指定该资源在本地缓存的最长有效时间,以秒为单位。例如:Ca

  10. IDEA 2022 创建 Spring Boot 项目详解 - 2

    如何用IDEA2022创建并初始化一个SpringBoot项目?目录如何用IDEA2022创建并初始化一个SpringBoot项目?0. 环境说明1.  创建SpringBoot项目 2.编写初始化代码0. 环境说明IDEA2022.3.1JDK1.8SpringBoot1.  创建SpringBoot项目        打开IDEA,选择NewProject创建项目。        填写项目名称、项目构建方式、jdk版本,按需要修改项目文件路径等信息。        选择springboot版本以及需要的包,此处只选择了springweb。        此处需特别注意,若你使用的是jdk1

随机推荐