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


前言

相关说明:

开发板: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库的巨简代码+超级详解)

  • 28
    点赞
  • 131
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 135
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

魏丶

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

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

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

打赏作者

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

抵扣说明:

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

余额充值