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

news2024/11/16 3:25:08

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

第十三届省赛主要是制作一个可由串口设置密码的密码锁。本实验中,我们将用到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)里写省事一点!
在这里插入图片描述
最后,小编在此处附上获取我的源码链接:第十三届蓝桥杯嵌入式真题

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Linux_IMX6ULL应用开发]-hello程序的交叉编译

目录 【开发板、虚拟机和PC的三者联通】 使用串口连接到开发板 连接Ubuntu虚拟机 互ping测试 【交叉编译hello.c文件】 Ubuntu编译无法在板子运行问题 使用交叉编译链编译hello.c 【开发板、虚拟机和PC的三者联通】 在这里我们使用IMX6ULL-PRO开发板进行学习&#xff0c;…

python+requests接口自动化框架的实现

为什么要做接口自动化框架 1、业务与配置的分离 2、数据与程序的分离&#xff1b;数据的变更不影响程序 3、有日志功能&#xff0c;实现无人值守 4、自动发送测试报告 5、不懂编程的测试人员也可以进行测试 正常接口测试的流程是什么&#xff1f; 确定接口测试使用的工具…

内部应用解耦神器-Spring事件

大家好&#xff0c;我是程序员牛牛&#xff0c;《AI超级个体: ChatGPT与AIGC实战指南》的参与人&#xff0c;10年Java编程程序员。 1. 概述 在做业务开发过程中&#xff0c;有些复杂点的逻辑&#xff0c;可能代码逻辑会很冗长&#xff0c;举一个很简单的例子&#xff0c;如&am…

windows解决nodejs版本冲突:安装版本管理器nvm,可根据不同项目一键切换适配版本

windows解决nodejs版本冲突&#xff1a;安装版本管理器nvm&#xff0c;可根据不同项目一键切换适配版本 参考来源&#xff1a;在本机 Windows 上设置 NodeJS | Microsoft Learn 建议安装版本管理器 nvm-windows&#xff0c;再用它来安装 Node.js 和 npm&#xff0c;这样可以根据…

C++学习笔记:红黑树

红黑树 什么是红黑树红黑树的规则红黑树节点的定义红黑树的插入空树插入非空插入条件判断新插入的节点 cur 不为 root 且 parent->_col 为红就需要调整父节点为左 grandf->left parent当uncle节点为红色时,只需要进行颜色调整,即可当uncle为空 或 者存在但是为黑parent …

Midjourney能让角色保持一致了

Midjourney发布新功能&#xff0c;网友直呼“不可思议”&#xff01; 现在你可以让生成的图像几乎保持角色一致&#xff0c;belike&#xff1a; 所有超级英雄长一个模样盯着你。 甚至动漫风、写实风等跨风格生成也同样适用&#xff1a; 保持同一风格&#xff0c;感jio配上文字…

【FPGA】DDR3学习笔记(一)丨SDRAM原理详解

本篇文章包含的内容 一、DDR3简介1.1 DDR3 SDRAM概述1.2 SDRAM的基础结构 二、 SDRAM操作时序2.1 SDRAM操作指令2.2 模式寄存器&#xff08;LOAD MODE REGISTER&#xff09;2.3 SDRAM操作时序示例2.3.1 SDRAM初始化时序2.3.2 突发读时序2.3.3 随机读时序2.3.4 突发写时序2.3.5 …

Java基础-接口

文章目录 1.快速入门代码&#xff1a;结果&#xff1a; 2.接口基本介绍1.语法注意&#xff1a;在jdk1.8以后接口才可以有静态方法&#xff0c;默认方法 2.代码实例 3.接口的应用场景1.场景介绍2.代码实例4.接口使用细节 5.接口课堂练习题目&#xff1a;答案&#xff1a;注意&am…

深入理解,java标识符?类型转换?

1、标识符 下面这张图是中国的一些姓氏 中国人起名字的规则都是以姓开头&#xff0c;名结尾。通过这个规则可以起&#xff1a;刘爱国、张三等&#xff0c;都是以汉字起的。但是不会起李ad、王123等名字&#xff0c;因为不符合规则。 所以&#xff0c;java在给变量、方法、类等…

【C++进阶】C++继承概念详解

C继承详解 一&#xff0c;继承的概念和定义1.1 继承的概念1.2 继承的定义1.3 继承关系和访问限定符 二&#xff0c;基类和派生类的对象赋值转移三&#xff0c;继承的作用域四&#xff0c;派生类的默认成员函数五&#xff0c;继承和友元&静态成员和继承六&#xff0c;菱形继…

Ansys Lumerical | 激光雷达天线仿真

附件下载 联系工作人员获取附件 在本文中&#xff0c;我们将了解如何根据激光雷达应用需求设计和优化相控阵光栅天线。 概述 激光雷达&#xff08;LIDAR&#xff09;是“light detection and ranging”的简称&#xff0c;近年来由于在机器人、自动驾驶汽车、高精度测绘等领域…

【AcWing】蓝桥杯集训每日一题Day2|前缀和|562.壁画(C++)

562. 壁画 562. 壁画 - AcWing题库难度&#xff1a;中等时/空限制&#xff1a;1s / 64MB总通过数&#xff1a;4154总尝试数&#xff1a;10197来源&#xff1a;Google Kickstart2018 Round H Problem B算法标签 思维题枚举前缀和 题目内容 Thanh 想在一面被均分为 N 段的墙上画…

[java——基础] 双亲委派机制

目录 核心思想&#xff1a; 双亲委派机制的好处&#xff1a; 三种类加载器 解析源代码 双亲委派思想面试总结&#xff1a; 核心思想&#xff1a; 向上搜索&#xff0c;向下加载。 双亲委派机制的好处&#xff1a; 防止Java核心类被篡改&#xff0c;防止类的重复加载。 三…

哈希表|15.三数之和

力扣题目链接 int cmp(const void *a,const void *b) {return *(int*)a - *(int*)b;} int** threeSum(int* nums, int numsSize, int* returnSize, int** returnColumnSizes) {*returnSize 0;if(numsSize < 3)return NULL;qsort(nums, numsSize, sizeof(int),cmp);int **…

C++ Qt开发:QNetworkAccessManager网络接口组件

Qt 是一个跨平台C图形界面开发库&#xff0c;利用Qt可以快速开发跨平台窗体应用程序&#xff0c;在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置&#xff0c;实现图形化开发极大的方便了开发效率&#xff0c;本章将重点介绍如何运用QNetworkAccessManager组件实现Web网…

Java日志框架Log4j 2详解

目录 一、什么是日志&#xff1f; 二、日志的主要用途 三、常用日志框架 1、Apache Log4j 2、Commons Logging 3、SLF4J 4、Logback 5、JUL(Java Util Logging) 6、Log4j 2 四、log4j 2 的优点 五、Log4j 2下载和配置 1、访问Log4j – 下载 Apache Log4j™ 2官网&a…

RHEL9 DNF/YUM仓库管理软件包

DNF/YUM仓库管理软件包 一个基于RPM包的软件包管理器能够从指定的服务器自动下载RPM包并且安装&#xff0c;自动处理依赖性关系&#xff0c;并且一次性安装所有依赖的软件包C/S模式 Server服务端提供RPM软件包与数据库文件repodataClient客户端使用dnf仓库 常用组合 组合参…

你还可以通过“nrm”工具,来自由管理“npm”的镜像

你还可以通过“nrm”工具&#xff0c;来自由管理“npm”的镜像 nrm&#xff08;npm registry manager&#xff09;是npm的镜像管理工具&#xff0c;有时候国外的资源太慢&#xff0c;使用这个就可以快速地在npm源间切换。 1.安装nrm 在命令行执行命令&#xff0c;npm install…

Java 容器启动执行指定任务

1、实现CommandLineRunner接口 实现CommandLineRunner接口&#xff0c;注意做初始化任务的类需要放在扫描路径下&#xff0c;使用Component注入到spring容器中。 import com.zw.service.StudentService; import org.springframework.beans.factory.annotation.Autowired; impo…

网络安全AI智能体公司「云起无垠」获数千万元天使+轮融资,致力于大模型与网络安全深度融合的技术研究

「云起无垠」致力于打造最懂安全的AI智能体&#xff0c;通过持续运营的工具、知识以及记忆引擎&#xff0c;不断提升智能体对用户安全场景的理解&#xff0c;以达到易于使用、自我学习、自主行动的特性&#xff0c;助力企业自动化执行各类安全任务&#xff0c;让软件更安全&…