STM32HAL库【G431】--【蓝桥杯嵌入式第十三届省赛题】第一场

2024-02-15 18:40

本文主要是介绍STM32HAL库【G431】--【蓝桥杯嵌入式第十三届省赛题】第一场,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

完整工程(百度网盘免费下载,提取码:0403)和演示视频在文章末尾,需要请移步至文章末尾。

第十三届第一场省赛题目

在这里插入图片描述

题目分析

个人观点:笔者读完题目,发现使用的模块涉及到短按按键LED串口LCD
大概注意的内容:

  1. 串口只做数据接收处理,不返回任何东西。
  2. 密码输入错误大于等于三次LED2以0.1s间隔闪烁5s后熄灭。
  3. 密码输入正确LED1点亮5s
  4. 串口接收固定7字符的内容。

涉及模块主要代码

主要变量与结构体

struct keys//按键结构体
{uchar judge;bool sta;bool single;
};
struct keys key[4]={0,0,0};uint freq=0;//PWM输出的频率
uchar duty=0;//PWM输出的占空比
uint ntimer=0;//定时计数
uchar LED_timer=0;// LED0.1s闪烁计数
bool led_flicker=0;//LED闪烁标志位
bool over_fault=0;//次数超过3此标志位uchar password[3] = {1,2,3};//密码初始化
uchar pass_in[3] = {0,0,0};//输入的密码
char lcd_buffer[30]={0};//LCD显示缓存uchar fault_count =0;//密码错误次数计数bool scene_flag=0;//0:输入密码界面 1:密码正确跳转的界面
bool a_flag=1;//界面显示@的标志位,默认显示,按下按键就置0,不显示char Rxdata[10]={0};//串口接收数组
char Txdata[10]={0};//串口发送数组
char rxdat=0;//串口缓存
uchar rx_count=0;//串口接收计数
uchar rx_timer=0;//串口是否接收完毕时间计数
bool finish_rx_flag=0;//串口完成接收标志位

按键扫描与按键处理

由于此次赛题只涉及短按,所以相对简单。我们采用定时器每10ms进行一次按键扫描。代码如下:

void Key_Scan(void)//按键扫描
{key[0].sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_0);key[1].sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_1);key[2].sta = HAL_GPIO_ReadPin(GPIOB,GPIO_PIN_2);key[3].sta = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);for(uchar i=0; i<4; i++){switch (key[i].judge){case 0://状态1:判断按键是否按下{if(key[i].sta==0)key[i].judge=1;}break;case 1://状态2:按键消抖{if(key[i].sta==0)key[i].judge=2;else key[i].judge=0;}break;case 2://状态3:确认按键按下,标志位置1{if(key[i].sta==1){key[i].single=1;key[i].judge=0;}}break;}}
}
void Key_process(void)//按键处理
{if(key[0].single==1 && scene_flag==0){//利用C语言顺序执行的规则将a_flag做出的操作写到最后key[0].single=0;if(a1_flag==0)pass_in[0]++;pass_in[0]%=10;a1_flag=0;//按键开始输入,置0}else if(key[1].single==1 && scene_flag==0){key[1].single=0;if(a2_flag==0)pass_in[1]++;pass_in[1]%=10;a2_flag=0;//按键开始输入,置0}else if(key[2].single==1 && scene_flag==0){key[2].single=0;if(a3_flag==0)pass_in[2]++;pass_in[2]%=10;a3_flag=0;//按键开始输入,置0}else if(key[3].single==1){key[3].single=0;key[2].single=0;key[1].single=0;key[0].single=0;if(password[0] == pass_in[0] &&password[1] == pass_in[1]&& password[2] == pass_in[2])//判断密码是否正确{scene_flag=1;//sta界面a1_flag=a2_flag=a3_flag=1;//初始界面显示@fault_count=0;//错误次数请0LCD_Clear(Black);TIM2->ARR=500-1;TIM2->CCR2=50;//设置PWM 2khz 10%}else {a1_flag=a2_flag=a3_flag=1;fault_count++;}if(fault_count>=3)over_fault=1;memset(pass_in,0,sizeof(pass_in));}
}

LED处理

LED就是要注意,在密码输入正确后,对错误次数清零,其他的就是理清逻辑关系就好。

  1. 密码输入正确LED1点亮5s后熄灭
  2. 密码输入错误LED2以0.1间隔闪烁5s后熄灭
void LED_disp(uchar dis)//LED显示
{HAL_GPIO_WritePin(GPIOC,GPIO_PIN_8 |GPIO_PIN_9 |GPIO_PIN_10 |GPIO_PIN_11 |GPIO_PIN_12 |GPIO_PIN_13 |GPIO_PIN_14 |GPIO_PIN_15 ,GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);//LED锁存HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOC,dis <<8,GPIO_PIN_RESET);HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);//LED锁存HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
void LED_proc(void)//LED处理
{if(scene_flag==1)//密码输入成功后,换界面和LED{LED_disp(0x01);if(ntimer>=500)//5s结束,返回初始密码界面{LED_disp(0x00);ntimer=0;scene_flag=0;TIM2->ARR=1000-1;TIM2->CCR2=500;//PWM 1Khz 50%}}else{if(over_fault==1)//错误次数三次以上含三次{if(led_flicker)LED_disp(0x02);else LED_disp(0x00);if(ntimer>=500){ntimer=0;over_fault=0;}//清楚超过错误次数标志位}else LED_disp(0x00);}
}

LCD显示

关于LCD要注意:

  1. 上电默认密码输入界面且B1、B2、B3显示@,按下对应按键后才是0~9循环
    在这里插入图片描述
  2. LCD显示界面切换时,可以不用刷新屏幕或者清理某一行,可以在显示相应字符串时,后面多加几个空格覆盖就行。
  3. 密码输入正确后进入STA界面,5s后返回PSD界面时,也要显示@
    主要代码如下:
void LCD_scene(void)//LCD显示
{if(scene_flag==0)//密码输入界面{LCD_DisplayStringLine(Line1,"       PSD");if(a1_flag)LCD_DisplayStringLine(Line3,"    B1:@      ");//初始状态,没有按下按键else {sprintf(lcd_buffer,"    B1:%d       ",pass_in[0]);LCD_DisplayStringLine(Line3,(uchar *)lcd_buffer);}if(a2_flag)LCD_DisplayStringLine(Line4,"    B2:@      ");//初始状态,没有按下按键else{sprintf(lcd_buffer,"    B2:%d       ",pass_in[1]);LCD_DisplayStringLine(Line4,(uchar *)lcd_buffer);}if(a3_flag)LCD_DisplayStringLine(Line5,"    B3:@      ");//初始状态,没有按下按键else {sprintf(lcd_buffer,"    B3:%d       ",pass_in[2]);LCD_DisplayStringLine(Line5,(uchar *)lcd_buffer);}}else//密码输入正确跳转的界面{freq = 80000000/(TIM2->PSC+1)/(TIM2->ARR+1);//计算频率duty = 100*TIM2->CCR2/(TIM2->ARR+1);//计算占空比LCD_DisplayStringLine(Line1,"       STA");sprintf(lcd_buffer,"    F:%dHz   ",freq);LCD_DisplayStringLine(Line3,(uchar *)lcd_buffer);sprintf(lcd_buffer,"    D:%d%%   ",duty);LCD_DisplayStringLine(Line4,(uchar *)lcd_buffer);}LED_proc();//调用LED处理函数
}

简单讲解一下LCD中的这段代码:

freq = 80000000/(TIM2->PSC+1)/(TIM2->ARR+1);//计算频率
duty = 100*TIM2->CCR2/(TIM2->ARR+1);//计算占空比

上述代码中:

  1. TIM2->PSC是Cudemx中的Prescaler(就是预分频系数,80-1是因为从0开始的,所以到79就是80次了)。
  2. TIM2->ARR是Cudemx中的Counter Period(就是自动重装值,也就是定时的溢出值,溢出时产生一次中断,1000-1与80-1同理)。
  3. TIM2->CCR2是Cudemx中的Pluse(就是定时器2的捕获/比较寄存器的值,因为是PWMmode1,CH polarity是High,所以当计数器的值<Pulse时,对应输出高电平计数器的值>Pulse时,对应输出低电平)。
    在这里插入图片描述

串口处理

因为本题中串口接收的字符串相对较少,在处理串口字符串的时候就直接上条件了。没过多处理,
注意:

  1. 题目中不要求串口返回什么信息,但是我在这里返回了,方便判断是否起作用。
  2. HAL_UART_Transmit_IT()不能连续使用,在十二届赛题中详细讲到,这里就不多讲啦。
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)//串口回调函数
{if(huart->Instance==USART1)//USB转串口对应串口1{rx_timer=0;finish_rx_flag=0;Rxdata[rx_count++] = rxdat;HAL_UART_Receive_IT(&huart1,(uchar *)&rxdat,1);//只能中断一次,连续接收再次打开}
}
void Usart_proc(void)//串口处理
{if(rx_count>0){if(rx_timer>=5)//50ms判断串口是不是还在接收{rx_timer=0;if(Rxdata[rx_count-1] == rxdat)finish_rx_flag=1;//接收完成}if(finish_rx_flag){finish_rx_flag=0;if(rx_count==7){if(Rxdata[3] == '-'&& Rxdata[4] >='0' && Rxdata[4] <='9' && Rxdata[5] >='0' && Rxdata[5] <='9' && Rxdata[6] >='0' && Rxdata[6] <='9' &&Rxdata[0]-'0'==password[0] &&Rxdata[1]-'0'==password[1] &&Rxdata[2]-'0'==password[2])//密码条件判断{password[0]= Rxdata[4] - '0';password[1]= Rxdata[5] - '0';password[2]= Rxdata[6] - '0';HAL_UART_Transmit_IT(&huart1,"Successfully!\r\n",sizeof("Successfully!\r\n"));while(huart1.gState != HAL_UART_STATE_READY);}else{HAL_UART_Transmit_IT(&huart1,"Error!\r\n",sizeof("Error!\r\n"));while(huart1.gState != HAL_UART_STATE_READY);}	}else {HAL_UART_Transmit_IT(&huart1,"Error!\r\n",sizeof("Error!\r\n"));while(huart1.gState != HAL_UART_STATE_READY);}rx_count=0;memset(Rxdata,0,sizeof(Rxdata));}}
}

完整功能演示

完整工程文件

总结

自己写的代码,不喜勿喷,欢迎参考呀
以上就是本次的全部内容了,笔者水平有限,仅供参考。
想联系笔者请私信就好。

这篇关于STM32HAL库【G431】--【蓝桥杯嵌入式第十三届省赛题】第一场的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/712220

相关文章

嵌入式QT开发:构建高效智能的嵌入式系统

摘要: 本文深入探讨了嵌入式 QT 相关的各个方面。从 QT 框架的基础架构和核心概念出发,详细阐述了其在嵌入式环境中的优势与特点。文中分析了嵌入式 QT 的开发环境搭建过程,包括交叉编译工具链的配置等关键步骤。进一步探讨了嵌入式 QT 的界面设计与开发,涵盖了从基本控件的使用到复杂界面布局的构建。同时也深入研究了信号与槽机制在嵌入式系统中的应用,以及嵌入式 QT 与硬件设备的交互,包括输入输出设

荣耀嵌入式面试题及参考答案

在项目中是否有使用过实时操作系统? 在我参与的项目中,有使用过实时操作系统。实时操作系统(RTOS)在对时间要求严格的应用场景中具有重要作用。我曾参与的一个工业自动化控制项目就采用了实时操作系统。在这个项目中,需要对多个传感器的数据进行实时采集和处理,并根据采集到的数据及时控制执行机构的动作。实时操作系统能够提供确定性的响应时间,确保关键任务在规定的时间内完成。 使用实时操作系统的

嵌入式Openharmony系统构建与启动详解

大家好,今天主要给大家分享一下,如何构建Openharmony子系统以及系统的启动过程分解。 第一:OpenHarmony系统构建      首先熟悉一下,构建系统是一种自动化处理工具的集合,通过将源代码文件进行一系列处理,最终生成和用户可以使用的目标文件。这里的目标文件包括静态链接库文件、动态链接库文件、可执行文件、脚本文件、配置文件等。      我们在编写hellowor

嵌入式方向的毕业生,找工作很迷茫

一个应届硕士生的问题: 虽然我明白想成为技术大牛需要日积月累的磨练,但我总感觉自己学习方法或者哪些方面有问题,时间一天天过去,自己也每天不停学习,但总感觉自己没有想象中那样进步,总感觉找不到一个很清晰的学习规划……眼看 9 月份就要参加秋招了,我想毕业了去大城市磨练几年,涨涨见识,拓开眼界多学点东西。但是感觉自己的实力还是很不够,内心慌得不行,总怕浪费了这人生唯一的校招机会,当然我也明白,毕业

深入探索嵌入式 Linux

摘要:本文深入探究嵌入式 Linux。首先回顾其发展历程,从早期尝试到克服诸多困难逐渐成熟。接着阐述其体系结构,涵盖硬件、内核、文件系统和应用层。开发环境方面包括交叉编译工具链、调试工具和集成开发环境。在应用领域,广泛应用于消费电子、工业控制、汽车电子和智能家居等领域。关键技术有内核裁剪与优化、设备驱动程序开发、实时性增强和电源管理等。最后展望其未来发展趋势,如与物联网融合、人工智能应用、安全性与

C语言蓝桥杯

一、语言基础 竞赛常用库函数 最值查询 min_element和max_element在vector(迭代器的使用) nth_element函数的使用 例题lanqiao OJ 497成绩分析 第一种用min_element和max_element函数的写法 第二种用min和max的写法 二分查找 二分查找只能对数组操作 binary_s

嵌入式技术的核心技术有哪些?请详细列举并解释每项技术的主要功能和应用场景。

嵌入式技术的核心技术包括处理器技术、IC技术和设计/验证技术。 1. 处理器技术    通用处理器:这类处理器适用于不同类型的应用,其主要特征是存储程序和通用的数据路径,使其能够处理各种计算任务。例如,在智能家居中,通用处理器可以用于控制和管理家庭设备,如灯光、空调和安全系统。    单用途处理器:这些处理器执行特定程序,如JPEG编解码器,专门用于视频信息的压缩或解压。在数字相机中,单用途

基于微信小程序与嵌入式系统的智能小车开发(详细流程)

一、项目概述 本项目旨在开发一款智能小车,结合微信小程序与嵌入式系统,提供实时图像处理与控制功能。用户可以通过微信小程序远程操控小车,并实时接收摄像头采集的图像。该项目解决了传统遥控小车在图像反馈和控制延迟方面的问题,提升了小车的智能化水平,适用于教育、科研和娱乐等多个领域。 二、系统架构 1. 系统架构设计 本项目的系统架构主要分为以下几个部分: 微信小程序:负责用户界面、控制指令的

嵌入式面试经典30问:二

1. 嵌入式系统中,如何选择合适的微控制器或微处理器? 在嵌入式系统中选择合适的微控制器(MCU)或微处理器(MPU)时,需要考虑多个因素以确保所选组件能够满足项目的具体需求。以下是一些关键步骤和考虑因素: 1.1 确定项目需求 性能要求:根据项目的复杂度、处理速度和数据吞吐量等要求,确定所需的处理器性能。功耗:评估系统的功耗需求,选择低功耗的MCU或MPU以延长电池寿命或减少能源消耗。成本

嵌入式Linux C基本知识点总结

学习这块知识点有好久了,最近借一本书的框架来对基本的知识点进行总结,参考《嵌入式Linux上的C语言编程实践》进行总结记录之。 一、 基本开发环境 Linux下C语言开发环境 使用工具:程序生成工具GCC、程序调试工具GDB、工程管理工具为make和Makefile。 开发流程:使用编辑工具编写C语言源文件,然后编译生成机器代码为主的二进制可执行程序。 编译流程:C语言经过编译-汇