草庐IT

蓝桥杯2022年第十三届嵌入式详解

锄头挖鸡蛋 2023-04-11 原文

        此前也发了关于蓝桥杯的题目,昨天刚比完赛,放松了一下,没来得及整理,早上我就把我所有的思路整理了一下,发出来,希望能帮到大家。当然也有很多不足的地方,希望大家能提出,我们一起讨论。

首先,关于题目的功能,我基本全部实现,一开始发题目,花了10分钟读题整理逻辑,记得是在2小时左右,我基本上都编出来了,就是led那里出了点小bug,后面也是顺利找出来了,然后再把代码完善了一下,后面也是顺利交卷。

今年的题目不算太难,考的模块涉及主要是串口,定时器。附上框图

cubemx配置如下:

由于配置都很简单我就不做多讲,但是由于我用的是G431新板子,必须要配置PD2为输出,保证led的功能正常运行,详细的可以去看我上一篇停车场的介绍,那里有关于这个引脚的详细说明

我将从4个部分进行讲解:led_key--LCD--PWM--串口(uart)

详细的设计要求我就不发出来了,大家可以去官网找,13届蓝桥杯试题

目录

整体代码

key和led

LCD

PWM

串口(uart


先附上main函数整体代码

整体代码


#include "main.h"
#include "lcd\lcd.h"
#include "ledkey\bsp_ledkey.h"
#include "tim\bsp_tim.h"
#include "uart\bsp_uart.h"
#include "stdio.h"
#include "string.h"





uint8_t   B1='@',B2='@',B3='@';//密码初始化
uint8_t   time=0,i=0;//控制报警灯参数
uint8_t   mauce[30];//lcd显示数组
uint8_t   ucled=0x00;
uint8_t   lcd_land=0;//屏幕标志位
uint8_t   vuale,key_up,key_down,key_old;//按键检测相关变量
uint16_t    freqq_HZ,Duty;
__IO uint32_t uwTick_key=0,uwTick_pwm=0,uwTick_lcd=0,uwTick_led=0,uwTick_uart=0;//减速变量

uint8_t    buffer;//缓冲接收字符
uint8_t    scree=0;//密码是否正确
uint8_t    buff[10];//接收的字符放在这里面
uint8_t    cout=0;//计数变量
uint8_t   yuan_mi[3]={1,2,3};
void SystemClock_Config(void);

void keyledjuel_project(void);
void lcd_project(void);
void uart_rx(void);

int main(void)
{

  HAL_Init();
  SystemClock_Config();
  ledkey_Init();
  TIM2_Init();
  UART_Init();
  LCD_Init();
  led_paly(0x00);
  LCD_SetTextColor(White);
  LCD_SetBackColor(Black);
  LCD_Clear(Black);
  HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
  UART_Start_Receive_IT(&huart1, (uint8_t*)&buffer, 1);
	
	
	while (1)
  {

     keyledjuel_project();
		 lcd_project();
		 uart_rx();
  }

}



//报警执行5s,led2以0.1s间隔闪烁
void led_start(){

if(uwTick-uwTick_led<100)
	uwTick_led=uwTick;
if(i<50){
ucled^=0x02;
i++;
}




}

void uart_rx(){

	if(uwTick-uwTick_uart<100)return;
	uwTick_uart=uwTick;
//判断是否有7个字符传进来了
	if(cout==7){
		//判断格式是否合格
	if( buff[3]=='-'&&buff[2]<='9'&&buff[2]>='0'
	&&buff[1]<='9'&&buff[1]>='0'
	&&buff[0]<='9'&&buff[0]>='0'
	&&buff[4]<='9'&&buff[4]>='0'
	&&buff[5]<='9'&&buff[5]>='0'
	&&buff[6]<='9'&&buff[6]>='0'
	)
	{
	
		//将字符转化成为数字
		buff[0]-=0x30;buff[1]-=0x30;buff[2]-=0x30;
		//判断串口给的原密码是否符合
		if(buff[0]==yuan_mi[0]&&buff[1]==yuan_mi[1]&&buff[2]==yuan_mi[2])//验证成功
		{
			//修改密码
		yuan_mi[0]=buff[4]-0x30;
		yuan_mi[1]=buff[5]-0x30;
		yuan_mi[2]=buff[6]-0x30;
	
		}
		
	cout=0;
	}

	else
	cout=0;

}
	

}

void keyledjuel_project(){

	if(uwTick-uwTick_key<50)return;//减速
	uwTick_key=uwTick;

    vuale=key_paly();	
	key_down=vuale&(vuale^key_old);
	key_up=~vuale&(vuale^key_old);
	key_old=vuale;


switch(key_down){

	case 1:
		
	if(lcd_land==0){

	if(B1=='@')
	B1=0;
	if(B1++==9)
	B1=0;
	
}
		break;
	case 2:

	if(lcd_land==0){

	if(B2=='@')
	B2=0;
	if(B2++==9)
	B2=0;
	
}
		break;

	case 3:

	if(lcd_land==0){

	if(B3=='@')
	B3=0;
	if(B3++==9)
	B3=0;
	
}
		break;


	case 4:

	if(B1==yuan_mi[0]&&B2==yuan_mi[1]&&B3==yuan_mi[2])
	scree=1; 
	time++;//每进来一次代表,验证密码的次数,当超过三次或等于三次,进行0.1s报警

	if(scree==1)//验证正确
	{
	time=0;
	uwTick_pwm=uwTick;
	}
	
	break;


}


if(scree==1){
		if(uwTick-uwTick_pwm<5000){
	    ucled|=0x01;
		__HAL_TIM_SET_AUTORELOAD(&htim2,499);
	    __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,50);
			
		if(lcd_land!=1)
	    LCD_Clear(Black);
	    lcd_land=1;
		}
		
		
	else{
		ucled&=~0x01;
	    __HAL_TIM_SET_AUTORELOAD(&htim2,999);
	    __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,0);
		if(lcd_land!=0)
		LCD_Clear(Black);
		
		lcd_land=0;
		B1='@';
		B2='@';
		B3='@';
		__HAL_TIM_SET_AUTORELOAD(&htim2,999);
		__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,500);
	    scree=0;
		
	}
	
	
}	
	//判断当输入密码是否连续错了三次及以上
	if(time>2){
	led_start();
		if(i==50)
		{
			time--;
			i=0;
		}
	}
	
	//执行led工作
led_paly(ucled);
	
}





void lcd_project(){


if(uwTick-uwTick_lcd<200)return;
	uwTick_lcd=uwTick;
	

	//算出频率
freqq_HZ = 1000000/(__HAL_TIM_GET_AUTORELOAD(&htim2)+1);
	//算出占空比
Duty=100*((float)__HAL_TIM_GET_COMPARE(&htim2,TIM_CHANNEL_2)/(__HAL_TIM_GET_AUTORELOAD(&htim2)+1));
	
	
	
if(lcd_land==0){
	
	
	
	sprintf((char*)mauce,"       PSD");
	LCD_DisplayStringLine(Line1,mauce);
	
	
  if(B1=='@')
	sprintf((char*)mauce,"    B1:%c",B1);
	else
	sprintf((char*)mauce,"    B1:%d",B1);
	LCD_DisplayStringLine(Line3,mauce);
	
	
	
	if(B2=='@')
	sprintf((char*)mauce,"    B2:%c",B2);
	else
	sprintf((char*)mauce,"    B2:%d",B2);
	LCD_DisplayStringLine(Line4,mauce);
	
	
  if(B3=='@')
	sprintf((char*)mauce,"    B3:%c",B3);
	else
	sprintf((char*)mauce,"    B3:%d",B3);
	LCD_DisplayStringLine(Line5,mauce);
	
	
}


if(lcd_land==1){

	sprintf((char*)mauce,"       STA");
	LCD_DisplayStringLine(Line1,mauce);

	sprintf((char*)mauce,"    F:%dHZ",freqq_HZ);
	LCD_DisplayStringLine(Line3,mauce);
	
	sprintf((char*)mauce,"    D:%d%%",Duty);
	LCD_DisplayStringLine(Line4,mauce);
	
}

}


//接收中断


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){


	
  buff[cout]=buffer;
  cout++;
	
	
  UART_Start_Receive_IT(&huart1, (uint8_t*)&buffer, 1);
	

}


key和led

驱动代码

这两部分代码是放在 bsp_ledkey.c里面的,没有在main.c里面,为了方便我直接在main中调用

void  led_paly(uint8_t  ucled1){


  HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15|GPIO_PIN_8
                          |GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|GPIO_PIN_12, GPIO_PIN_SET);
	
	
	
	 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
     HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
	
	
	 HAL_GPIO_WritePin(GPIOC, ucled1<<8, GPIO_PIN_RESET);
	
	 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
	 HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
	

}


uint8_t key_paly(){

uint8_t vuale=0;
	
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0)==0)
  vuale=1;
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)==0)
  vuale=2;
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2)==0)
  vuale=3;
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==0)
  vuale=4;

		return vuale;

}

就是两段驱动代码,不做多讲,大家看看就会明白。

对于key和led的难点,想必就是,输入错误三次及三次以上进行led的报警,key没什么难度。

我们可以在按键四里面设置标志位time,每次进来都+1,但当密码正确就置0(连续已被打断)

后面就可以进行密码错误次数片段,这里面有个小细节,由于输入错误就要闪烁五秒,然后我通过设置i来进行50次的100ms间隔,后面我是将time又减了一次,让程序下一次就执行不到这里,除非密码又输错,然后time的状态应该是3-2-3-2-3-2.......

 闪烁程序

LCD

移植文件

lcd的话主要是'@'显示和数字显示的切换,其实还是比较简单的,只是注意当显示字符时,一定是%c,而不是%d。

PWM

开始产生PWM波

 pwm逻辑主要是集中在密码输入正确的页面也就是第二个页面

scree是判断密码是否正确密码的标志位,我们在判断正确后,开始保持输出页面5s,且设置2000hz的频率,和10的占空比(初始占空比大家随便设置,我一开始就设置的百分之50,但是最好不要设置百分之10),后面在回到初始界面(重新设置为初始值)

 大家可以看一看这段逻辑,

      __HAL_TIM_SET_AUTORELOAD(&htim2,499);
      __HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,50);

关于重装载值的设置和比较值的设置,大家可以去HAL库tim.h中找

串口(uart)

 关于串口部分,逻辑不算难,就是:字符数量是否正确-判断字符合格-判断设置合格-设置密码

 我们开启中断接收一个字符的方式

 

将字符一个个送到buff里面

我们可以先进行判断字符是否进来7个,如果没有再将cout置0-重新接收,如果进来7个,我们再判断格式是否正确,这里也有个小细节,由于通过串口发送的是字符,我们要先转换为数字才能再进行判断串口给的原密码是否正确,然后修改密码。

好了,这大概就是整个工程的讲解,欢迎大家在评论区留言,期待我们一起交流学习。

有关蓝桥杯2022年第十三届嵌入式详解的更多相关文章

  1. 映宇宙2022年营收63亿元:同比下降三成,毛利率提升4.3个百分点 - 2

    3月26日,映宇宙(HK:03700,即“映客”)发布截至2022年12月31日的2022年度业绩财务报告。财报显示,映宇宙2022年的总营收为63.19亿元,较2021年同期的91.76亿元下降31.1%。2022年,映宇宙的经营亏损为4698.7万元,2021年同期则为净利润4.57亿元;期内亏损(净亏损)为1.68亿元,2021年同期的净利润为4.33亿元;非国际财务报告准则经调整净利润为3.88亿元,2021年同期为4.82亿元,同比下降19.6%。 映宇宙在财报中表示,收入减少主要是由于行业竞争加剧,该集团对旗下产品采取更为谨慎的运营策略以应对市场变化。不过,映宇宙的毛利率则有所提升

  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. Tcl脚本入门笔记详解(一) - 2

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

  5. 【详解】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,直接右键新建即可如上图所示依次类推创建

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

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

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

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

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

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

  9. 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

  10. 详解Unity中的粒子系统Particle System (二) - 2

    前言上一篇我们简要讲述了粒子系统是什么,如何添加,以及基本模块的介绍,以及对于曲线和颜色编辑器的讲解。从本篇开始,我们将按照模块结构讲解下去,本篇主要讲粒子系统的主模块,该模块主要是控制粒子的初始状态和全局属性的,以下是关于该模块的介绍,请大家指正。目录前言本系列提要一、粒子系统主模块1.阅读前注意事项2.参考图3.参数讲解DurationLoopingPrewarmStartDelayStartLifetimeStartSpeed3DStartSizeStartSize3DStartRotationStartRotationFlipRotationStartColorGravityModif

随机推荐