第十三届蓝桥杯嵌入式省赛程序设计详细题解

第十三届蓝桥杯嵌入式省赛题目相对于第十二届较为简单,没有那么多串口的数据处理以及判断!

第十三届省赛主要是制作一个可由串口设置密码的密码锁。本实验中,我们将用到LED模块、按键模块、串口模块、定时器的PWM模块以及官方会提供源码的LCD模块。

文末有小编写的代码

一、CubeMX配置

1.使能外部高速时钟:
在这里插入图片描述
2.配置时钟树:
在这里插入图片描述
3.GPIO输出
在这里插入图片描述

4.GPIO输入
在这里插入图片描述
5. TIM定时器

5.1 TIM2输出PWM脉冲
在这里插入图片描述
设置默认Pluse为50,即占空比为50%
在这里插入图片描述
5.2 TIM4实现定时5s

在这里插入图片描述

在这里插入图片描述

5.3 TIM3定时器实现微妙(us)延迟
在这里插入图片描述

6.USART(通信)

USART串口接收数据,我使用两种方法实现,大家选取其中一种即可!

1.定长接收数据
在这里插入图片描述

在这里插入图片描述
2,不定长接收数据+DMA方式
此种方法的核心是空闲中断!
在这里插入图片描述

二、代码实现

2.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();
  MX_TIM3_Init();
  MX_TIM4_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
  LCD_Init();
  LCD_Clear(Black);
  LCD_SetBackColor(Black);
  LCD_SetTextColor(White);
	HAL_TIM_PWM_Start(&htim2,TIM_CHANNEL_2);
	led(1,0);
	led(2,0);
	led(3,0);
	led(4,0);
	led(5,0);
	led(6,0);
	led(7,0);
	led(8,0);
    HAL_UART_Receive_IT(&huart1, buff, 7);
	HAL_TIM_Base_Start_IT(&htim4);
  /* USER CODE END 2 */

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

    /* USER CODE BEGIN 3 */

	  Key_handle();
	  lcd();
	  if(key4_count>=3&&led_flag==0)
	  {

		led(2,1);
		delay_us(50000);
		delay_us(50000);
		led(2,0);
		delay_us(50000);
		delay_us(50000);
	  }
  }
  /* USER CODE END 3 */
}

2.2 lcd函数实现

void lcd()
{
	if(pass_flag==1)
	{
		show_output();	
		if(systick-PWMTick>5000)
		{
			led(1,0);
			pwm1();
			first='@';
			first_flag=-1;

			second='@';
			second_flag=-1;

			third='@';
			third_flag=-1;
		
			pass_flag=0;
			LCD_Clear(Black);
		}	
	}
	if(pass_flag==0)
	{
		show_input();		
	}
}

void show_input()
{
	LCD_DisplayStringLine(Line1,"       PSD             ");
	sprintf(B1,"    B1:%c",first);
	LCD_DisplayStringLine(Line3,B1);
	sprintf(B2,"    B2:%c",second);
	LCD_DisplayStringLine(Line4,B2);
	sprintf(B3,"    B3:%c",third);
	LCD_DisplayStringLine(Line5,B3);
}

char pl[50];
char zkb[50];
int c_pl;
int c_ARR;
int c_zkb;
int c_pluse;
void show_output()
{
	LCD_DisplayStringLine(Line1,"       STA             ");
	c_ARR=__HAL_TIM_GET_AUTORELOAD(&htim2);
	c_pl=100000/(c_ARR+1);
	sprintf(pl,"    F:%dHz",c_pl);
	LCD_DisplayStringLine(Line3,pl);
	
	c_pluse=__HAL_TIM_GET_COMPARE(&htim2,TIM_CHANNEL_2);
	c_zkb=c_pluse*100/(c_ARR+1);
	sprintf(zkb,"    S:%d%%",c_zkb);
	LCD_DisplayStringLine(Line4,zkb);
}

2.3 按键扫描功能实现

int Keynum()
{
	int key=0;
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0)==0)
	{
		HAL_Delay(5);
		if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0)==0)
		{
			key=1;
			  LCD_Clear(Black);
		}
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_0)==0);
	}
	
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)==0)
	{
		HAL_Delay(5);
		if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)==0)
		{
			key=2;
			  LCD_Clear(Black);
		}
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1)==0);
	}
	
	if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2)==0)
	{
		HAL_Delay(5);
		if(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2)==0)
		{
			key=3;
			  LCD_Clear(Black);
		}
		while(HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_2)==0);
	}
	
	if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==0)
	{
		HAL_Delay(5);
		if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==0)
		{
			key=4;
			 LCD_Clear(Black);
		}
		while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==0);
	}
	
	return key;
}



char first='@';
int first_flag=-1;

char second='@';
int second_flag=-1;

char third='@';
int third_flag=-1;

char pass1='1';
char pass2='2';
char pass3='3';
int pass_flag=0;

int lcd_flag=0;

int ledTick=0;
void Key_handle()
{
	int keynum=Keynum();
	if(keynum==1)
	{
			first_flag++;
			switch(first_flag%10)
			{
				case 0:first='0';break;
				case 1:first='1';break;
				case 2:first='2';break;
				case 3:first='3';break;
				case 4:first='4';break;
				case 5:first='5';break;
				case 6:first='6';break;
				case 7:first='7';break;
				case 8:first='8';break;
				case 9:first='9';break;
			}
	}
	
	if(keynum==2)
	{
			second_flag++;
			switch(second_flag%10)
			{
				case 0:second='0';break;
				case 1:second='1';break;
				case 2:second='2';break;
				case 3:second='3';break;
				case 4:second='4';break;
				case 5:second='5';break;
				case 6:second='6';break;
				case 7:second='7';break;
				case 8:second='8';break;
				case 9:second='9';break;
			}

	}
	
	
	if(keynum==3)
	{
			third_flag++;
			switch(third_flag%10)
			{
				case 0:third='0';break;
				case 1:third='1';break;
				case 2:third='2';break;
				case 3:third='3';break;
				case 4:third='4';break;
				case 5:third='5';break;
				case 6:third='6';break;
				case 7:third='7';break;
				case 8:third='8';break;
				case 9:third='9';break;
			}
	}

	if(keynum==4)
	{
		led_flag=0;
		key4_count++;
		if(pass1==first&&pass2==second&&pass3==third)
		{
			key4_count=0;
			pass_flag=1;
			pwm2();
			led(1,1);
			//定时器中断在回调函数中清屏函数不起作用
//			__HAL_TIM_CLEAR_FLAG(&htim1,TIM_FLAG_UPDATE);
//		    HAL_TIM_Base_Start_IT(&htim1);
			PWMTick=systick;		
		}
		else
		{
			pass_flag=0;
			first='@';
			first_flag=-1;

			second='@';
			second_flag=-1;

			third='@';
			third_flag=-1;
		}
		
		if(key4_count>=3)
		{
			__HAL_TIM_CLEAR_FLAG(&htim4,TIM_FLAG_UPDATE);
		    HAL_TIM_Base_Start_IT(&htim4);
		}
	}
}

2.4 PWM脉冲转换

void pwm2()
{
	__HAL_TIM_SET_AUTORELOAD(&htim2,50-1);
	__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,5);
}

//方波
void pwm1()
{
	__HAL_TIM_SET_AUTORELOAD(&htim2,100-1);
	__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,50);
}

2.5 某种状态持续5s的两种操作方法

1.利用系统滴答计时器

本实验中 实现输出2KHz 10%占空比的脉冲信号,持续5秒钟,切换为 1KHz 方波信号输出的功能 使用的是系统滴答计时器。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
2.TIM定时器定时5s
本实验中实现 指示灯 LD2 以 0.1秒为间隔亮、灭闪烁报警,5 秒后熄灭的功能使用的是TIM4定时器定时5s。
在这里插入图片描述

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
	if(htim->Instance==TIM4)
	{
			led_flag=1;
			HAL_TIM_Base_Stop_IT(&htim4);	
	}
}

2.6 延迟100ms

delay_us函数实现定时微妙(us)

void delay_us(int delay)
{
	HAL_TIM_Base_Start(&htim3);        // 启动定时器
 	 __HAL_TIM_SET_COUNTER(&htim3, 0);  // 重置计数器
  	while (__HAL_TIM_GET_COUNTER(&htim3) < delay)
	  {}
	 HAL_TIM_Base_Stop(&htim3);         // 停止定时器
}

delay_us(50000)代表延迟50000us即50ms,但因为定时器最大计数值为65535,如果delay_us(100000)就超过了定时器最大计数值,所以可以采取delay_us(50000)两次来实现100ms定时!
在这里插入图片描述

2.7 USART串口与修改密码

USART串口接收数据,我使用两种方法实现,大家选取其中一种即可!

1.接收固定长度数据

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	if(buff[0]==pass1&&buff[1]==pass2&&buff[2]&&buff[3]=='-'&&judge()==1)
	{
		pass1=buff[4];
		pass2=buff[5];
		pass3=buff[6];
		HAL_UART_Transmit(&huart1,(unsigned char *)"Success\r\n", 9, 50);
	}
	else
	{
		HAL_UART_Transmit(&huart1,(unsigned char *)"error\r\n", 7, 50);
	}
	HAL_UART_Receive_IT(&huart1, buff, 7);
}

int judge()
{
	for(int i=0;i<6;i++)
	{
		if((buff[i]<'0')||(buff[i]>'9'))//接收数据不为阿拉伯数字时不合法
			return 0;
		else
		{
			return 1;
		}
	}
}

2.接收不定长数据+DMA方式

此种方式使用的是空闲中断
串口空闲帧中断定义:空闲中断(IDLE),俗称帧中断,空闲中断是检测到有数据被接收后,总线上在一个字节的时间内没有再接收到数据的时候发生的。当串口发送数据时是将一帧数据中的字符一个一个连续发送出的,两个字符间隔时间非常短产生不了空闲,正常情况下是第一帧数据接收毕到第二帧数据开始接收期间存在一个空闲状态,检测到此空闲状态后产生空闲空暇中断。优点:空闲中断的优点在于省去了帧头帧尾的检测,进入中断程序即意味着已经接收到一组完整数据,需及时对数据处理或将数据转移出缓冲区即可。

在mian函数中,while(1)之前增加两行代码

	HAL_UART_Receive_DMA(&huart1,rx_buffer,100);    // 开启DMA接收
  __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);      // 开启串口的空闲中断

中断回调函数:
我是写在USART1_IRQHandler(void)这个里面,也可以直接写在由hal库提供的函数
HAL_UART_IRQHandler(&huart1)里面,如果写在HAL_UART_IRQHandler()里面的话,得找个地方放这个函数,所以直接在stm32f4xx_it.c中的这个函数
USART1_IRQHandler(void)里写省事一点!
在这里插入图片描述
最后,小编在此处附上获取我的源码链接:第十三届蓝桥杯嵌入式真题

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/434907.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32CubeIDE基础学习-软件安装,环境搭建

STM32CubeIDE基础学习-软件介绍及环境搭建步骤 文章目录 STM32CubeIDE基础学习-软件介绍及环境搭建步骤前言第1章 STM32CubeIDE 介绍1.1 软件描述1.2 软件支持的功能及特点 第2章 STM32CubeIDE 软件安装2.1 STM32CubeIDE 软件获取方法2.2 STM32CubeIDE 软件安装步骤2.2.1 错误安…

YOLOv9独家原创改进|加入RT-DETR中的HGBlock!

专栏介绍&#xff1a;YOLOv9改进系列 | 包含深度学习最新创新&#xff0c;主力高效涨点&#xff01;&#xff01;&#xff01; 一、改进点介绍 HGBlock是RT-DETR中使用的特征提取模块。 二、HGBlock模块详解 2.1 模块简介 HGBlock的主要思想&#xff1a; 一个并联的卷积模块与…

STM32(19)I2C模块 主机发数据

发送数据&#xff1a; 等待空闲&#xff1a; 发送起始位&#xff1a; 发送地址&#xff1a; 发送数据&#xff1a;

TypeScript学习笔记(上):TypeScript的介绍、安装及常用类型

我对TypeScript的理解就是&#xff0c;TypeScript是增加了类型校验的JavaScript&#xff0c;能够把运行期错误提升至编译期 TypeScript是什么&#xff1f; TypeScript&#xff08;简称&#xff1a;TS&#xff09;是 JavaScript 的超集&#xff08;JS 有的 TS 都有&#xff09…

【牛客】VL65 状态机与时钟分频

描述 题目描述&#xff1a; 使用状态机实现时钟分频&#xff0c;要求对时钟进行四分频&#xff0c;占空比为0.25 信号示意图&#xff1a; clk为时钟 rst为低电平复位 clk_out 信号输出 Ps 本题题解是按照1000的状态转移进行的&#xff0c;不按照此状态进行&#xff0c;编译器…

实现一个网页版的简易猜数字游戏

实现一个网页版的简易猜数字游戏 效果 代码截图 相关代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><t…

3.6作业

作业要求&#xff1a;数据库操作的增、删、改 程序代码&#xff1a; #include<myhead.h> int main(int argc, const char *argv[]) {//定义数据库句柄指针sqlite3 * ppDb NULL;//打开数据库&#xff0c;如果数据库不存在&#xff0c;则创建数据库//将数据库句柄由参数…

【软件工程】软件工程定义、软件危机以及软件生命周期

&#x1f338;博主主页&#xff1a;釉色清风&#x1f338;文章专栏&#xff1a;软件工程&#x1f338; 今日语录&#xff1a;What matters isn’t how others think of your ambitions but how fervently you cling to them. 软件工程系列&#xff0c;主要根据老师上课所讲提及…

数字化转型导师坚鹏:金融科技咨询方法论

金融科技咨询方法论 ——方法、做法、演法、心法 课程背景&#xff1a; 数字化转型背景下&#xff0c;很多机构存在以下问题&#xff1a; 不知道先进的金融科技咨询方法论&#xff1f; 不知道如何运作金融科技咨询项目&#xff1f; 不知道如何汇报咨询项目关键成果&…

MyBatis3源码深度解析(三)Connnection

文章目录 前言2.3 Connnection2.3.1 JDBC驱动程序的类型2.3.1.1 JDBC-ODBC Bridge Driver2.3.1.2 Native API Driver2.3.1.3 HDBC-Net Driver2.3.1.4 Native Protocol Driver 2.3.2 java.sql.Driver2.3.2.1 静态代码块加载驱动类2.3.2.2 SPI机制加载驱动类 2.3.3 DriverManager…

使用RabbitMQ实现延时消息自动取消的简单案例

一、流程图 二、导包 <!--消息队列 AMQP依赖&#xff0c;包含RabbitMQ--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-amqp</artifactId> </dependency> 三、配置文件 #消息队列 …

nodejs安装教程(及过程中的易错)

nodejs&#xff1a;Nodejs 是基于 Chrome 的 V8 引擎开发的一个 C 程序&#xff0c;目的是提供一个 JS 的运行环境。 npm&#xff1a;npm 是 Node Package Manager 的缩写&#xff0c;意思是 Node 的包管理系统&#xff0c;是最大的软件包仓库 下载nodejs 首先我们需要在node…

制作高端的电子杂志神器推荐

根据市场调查数据显示&#xff0c;越来越多的消费者开始青睐电子杂志这种阅读方式。相比传统纸质杂志&#xff0c;电子杂志具有更高的阅读体验、更便捷的分享和传播方式以及更环保的阅读方式。此外&#xff0c;越来越多的企业也开始重视电子杂志的宣传作用&#xff0c;将其作为…

一次磁盘组扩容引起的事故

一、备份磁盘头信息 1、mkdir /home/grid/bakasm 2、kfed read /dev/rhdisk /home/grid/backasm/rhdisk.txt 二、赋权 1、chmod 660 /dev/rhdisk 2、chown grid:asmadmin /dev/rhdisk 三、确认没有pvid lspv |grep hdisk 如果存在 chedev -l hdisk -a pvclear 四、调…

状态模式:有案例就这么简单

状态模式是一种行为设计模式&#xff0c;它允许对象在内部状态改变时改变它的行为。这使得对象看起来好像修改了它的类。状态模式主要由三个部分组成&#xff1a;上下文&#xff08;Context&#xff09;、状态接口&#xff08;State Interface&#xff09;和具体状态&#xff0…

使用 AJAX 提升网页数据的动态交互

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

2024年最新Android面试精讲,面试题附答案

一. 开发背景 想要成为一名优秀的Android开发&#xff0c;你需要一份完备的知识体系&#xff0c;在这里&#xff0c;让我们一起成长为自己所想的那样。 Android 相关 1. Android 之 SharedPreferences 内部原理浅析 2. Android 源码分析-消息队列和 Looper 3. Android 源码分析…

第二十一周代码(java + DFS/BFS)

2024/03/04 周一 路径之谜 题目链接 【参考代码】 dfs剪枝 #include <iostream> #include <vector> using namespace std;int n; int dx[] {-1, 0, 1, 0}, dy[] {0, 1, 0, -1}; bool visit[21][21] {false}; int north[21], west[21]; vector<int…

【Apache Camel】基础知识

【Apache Camel】基础知识 Apache Camel是什么Apache Camel基本概念和术语CamelContextEndpointsRoutesRouteBuilderComponentsMessageExchangeProcessorsDomain Specific Language&#xff08;DSL&#xff09; Apache Camel 应用执行步骤Apache Camel 示意图参考 Apache Camel…

智慧农业的新时代

1.智慧农业的发展背景及重要性 随着科技的发展&#xff0c;农业现代化已经成为我国农业发展的必然趋势。智慧农业作为农业现代化的重要组成部分&#xff0c;通过运用物联网、大数据、云计算等先进技术&#xff0c;实现对农业生产、管理和服务的智能化&#xff0c;提高农业生产效…