当前位置: 首页 > news >正文

【蓝桥杯嵌入式】【模块】二、LED相关配置及代码模板

 1. 前言

最近在准备16届的蓝桥杯嵌入式赛道的国赛,打算出一个系列的博客,记录STM32G431RBT6这块比赛用板上所有模块可能涉及到的所有考点,如果有错误或者遗漏欢迎各位大佬斧正。

本系列博客会分为以下两大类:

1.1. 单独模块的讲解

在这部分,我会分享自己总结的各个模块的相关配置、代码书写模板,涉及到的大致框架如下:

这个框架后续可能会不断更新,欢迎各位给出建议。

这一大类相关的文章链接如下(持续补充中):

【蓝桥杯嵌入式】【模块】一、系统初始化-CSDN博客

【蓝桥杯嵌入式】【模块】二、LED相关配置及代码模板-CSDN博客

1.2. 蓝桥杯各届的真题、模拟题复盘及个人答案

在这一部分,我会分享个人练过的所有题的复盘思路及代码。

这一大类相关的文章链接如下(持续补充中):


以下是本篇博客正文内容:

2. 在cubemx中配置led

根据开发板手册,与led相关的gpio口如图红框圈出的所示。

其中,PC8-PC15是LED的输出引脚,分别对应LD1到LD8,低电平有效;PD2则是锁存器,电平拉高时进行数据传输。

为什么会有一个锁存器呢?翻看手册可以发现,LCD与LED的PC8-PC15引脚是公用的:

所以,当对PC8-PC15进行电平赋值时,可能会同时对led和lcd造成影响,为了避免这种情况,需要用一个锁存器PD2,当对led的电平做赋值后,需要先拉高,让数据通过,赋值成功,再拉低,将数据锁住,即便 PC8~PC15 后续因lcd变化,led仍显示原数据。

在左侧gpio栏做一些基本的gpio配置,可以将PC8-PC15先初始化成高电平,这样最开始的灯就是灭掉的。


3. led的初始化、点亮和熄灭

3.1. 代码放置位置

由于led相关的操作是基于gpio的,所以我习惯直接将相关代码放在gpio.c文件下,省去了新建文件的麻烦。

3.2. 初始化代码

初始化代码如下:

void led_init(void)
{HAL_GPIO_WritePin(GPIOC, GPIO_PIN_All, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

 1. 首先,将PC的所有引脚置高电平,这一步会让led相关的PC8-PC15引脚置高电平,造成led熄灭,实际这一步可有可不有,因为在之前配置cubemx时就已经拉高过了。

2. 后面两步,先让PD2拉高再拉低,这样led引脚的赋值才会有效,后续对led的引脚电平改变都需要加这两句。

3.3. led的亮灭

相关代码如下:

uint8_t led_8bits = 0;
void led_on_by_8bits(void)
{for (int i = 0; i < 8; i++) {uint16_t pin = GPIO_PIN_8 << i; // PC8~PC15GPIO_PinState state = (led_8bits >> i) & 1 ? GPIO_PIN_RESET : GPIO_PIN_SET;HAL_GPIO_WritePin(GPIOC, pin, state);}// 锁存刷新HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
}

我喜欢采用上述方法,用一个8位数据的0到7位来记录LD1到LD8的亮灭情况,想让哪个灯亮,对这个8位数据的对应位置1即可,反之清0可让对应灯熄灭。

这样处理的好处时,采用了异步的思想,外部只处理led_8bits 这个标志位中的0-7位,寄存器的赋值放到统一的函数中进行,避免了外部函数在需要对led做操作时直接操作寄存器造成混乱(我有时这样操作会发现其会与lcd相互影响)。

举个例子:

// 示例
void led_task(void)
{led_8bits = ((MODE == 0) ? led_8bits  (1 << 7) : led_8bits & ~(1 << 7));led_8bits = ((GEAR == 1) ? led_8bits | (1 << 0) : led_8bits & ~(1 << 0));led_8bits = ((GEAR == 2) ? led_8bits | (1 << 1) : led_8bits & ~(1 << 1));led_8bits = ((GEAR == 3) ? led_8bits | (1 << 2) : led_8bits & ~(1 << 2));led_8bits = ((usart_flag == 1) ? led_8bits | (1 << 3) : led_8bits & ~(1 << 3));led_on_by_8bits();
}

1. 当外部的函数需要点亮LD8时,使用下面的语句即可:

led_8bits |= (1 << 7);

这一步会让该标志位的最后一位置1,在后面的led_on_by_8bits函数中会让对应的LD8点亮。

2. 如果要让LD8熄灭的话,用下面的语句:

led_8bits &= ~(1 << 7);

这一步会让该标志位的最后一位清0,在后面的led_on_by_8bits函数中会让对应的LD8熄灭。


 4. led的闪烁

闪烁的本质实际就是led的亮、灭定时切换,基于HAL_Delay延时函数即可做到想要的效果,但这样在蓝桥杯比赛中是万万不行的,因为HAL_Delay会阻塞系统的运行,影响其他功能的实现。所以,正确的办法是使用定时器中断。

4.1. 在cubemx中配置一个定时器中断

步骤如下:

在timer中选择一个TIM来用作中断源,我比较喜欢用TIM4,因为根据经验来看,许多届的考题都没有涉及到过TIM4的使用,其他的TIM2、TIM3等常常会被用来做PWM相关的东西,所以我觉得选用TIM4来单独的作为定时器中断用来实现led闪烁、长亮、按键检测是一个不错的选择。

如图上步骤所示,我使用TIM4定时器,预分频系数为10,重装载值为10000,由此生成了一个频率为(80000000 / 00 / 10000 = 100)HZ的定时器,也就是每隔1 / 100 = 0.01s = 10ms会进一次中断回调函数。 

记得要使能中断,之后点击生成代码即可。

 4.2. 在定时器中断中书写led闪烁逻辑

首先,在初始化中,需要加入定时器中断的开启逻辑:

HAL_TIM_Base_Start_IT(&htim4);

(同理,定时器相关的函数逻辑我建议放在tim.c文件里)。

之后,重写中断回调函数,在内部书写led闪烁的逻辑:

这里以让LD2以500ms为周期闪烁为例:

extern uint8_t led_8bits;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM4){static uint32_t ld1_cnt = 0;if(ld1_cnt == 50){ld1_cnt = 0;led_8bits ^= (1 << 1);}else{ld1_cnt++;}}
}

每10ms,都会进该中断回调函数内执行逻辑,使用了一个计数器,当进该中断50次,即花费50 * 10 = 500ms = 0.5s后,会触发一次led_8bits 第1位的电平反转,也就是LD2的亮灭切换。

之后,在led_task中加入对应的处理逻辑

void led_task(void)
{led_on_by_8bits();
}

后续将led_task放入主循环,便可实现LD2每隔0.5s闪烁一次。


5. led亮一段时间后熄灭

这个实际与led闪烁很像,依旧也是基于定时器,代码如下:

5.1. 在定时器中断中书写逻辑

以让LD2亮5s后熄灭为例。

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if(htim->Instance == TIM4){static uint32_t ld1_cnt = 0;if(ld1_cnt < 500){ld1_cnt++;led_8bits |= (1 << 1);}else{led_8bits &= ~(1 << 1);}}
}

如上所示,在进定时器中断的前500次内都让LD2亮,即亮500 * 0.01 = 5s,之后熄灭,便达到了需求。


总结

本文介绍了led相关操作的模板代码,主要是基于异步思想,实现led亮灭、闪烁、长亮后熄灭。

http://www.xdnf.cn/news/413299.html

相关文章:

  • 关于输入法重码率的计算
  • web 自动化之 Unittest 应用:测试报告装饰器断言
  • 基于大模型研究技术方案清单
  • 【markdown】介绍如何在markdown中绘制流程图
  • 在嵌入式调试中IAR提示Fatal error: CPU did not power up Session aborted!怎么回事?怎么解决?
  • C++中类中const知识应用详解
  • PyCharm历史版本下载说明
  • Java大师成长计划之第20天:Spring Framework基础
  • Qt/C++面试【速通笔记九】—视图框架机制
  • EHS 安全管理有效落地,五步实施方法解析
  • 基于SpringBoot的博客系统测试报告
  • slackel系统详解
  • MACH-ETH:汽车网络接口的卓越之选
  • steam OS详细讲解
  • yolov5s.pt这类的后续是pt的文件用什么软件可以打开看
  • STM32F103_LL库+寄存器学习笔记12.1 - 串口DMA高效收发实战:引入ringbuffer结构
  • STM32实现循环队列
  • 系统架构-通信系统架构设计
  • 如何理解“数组也是对象“——Java中的数组
  • old kali网站下载链接爬取-Kali linux 全部版本镜像下载--Index of /kali-images
  • 基于STM32、HAL库的DPS368XTSA1气压传感器 驱动程序设计
  • [Windows] Honeyview V5.53
  • 深度解析Crawl4AI:面向大模型的新一代智能爬虫
  • 2025系统架构师考试押题总结
  • 学习黑客Windows 任务管理器详解
  • 解决WSL、Ubuntu的.ico图标不正确显示缩略图
  • VBA会被Python代替吗
  • LeetCode:513、找树左下角的值
  • 滑动窗口/单调队列
  • [网络层]ICMP协议