news 2026/6/10 23:30:23

从零开始学嵌入式之STM32——8.流水灯

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
从零开始学嵌入式之STM32——8.流水灯

目录

前言

一、需求

二、硬件电路

三、分析

1.电路原理

2. 结论

四、代码模块化设计思路

前言

本文以 STM32F103 单片机为核心,采用纯寄存器编程方式实现经典的流水灯案例,直接操作寄存器配置 GPIO 外设。通过从底层硬件原理出发,拆解 GPIO 时钟使能、工作模式配置、电平控制的完整流程,帮助读者摆脱 “库函数黑盒”,深入理解 STM32 GPIO 外设的工作机制;同时结合模块化编程思想,将 LED 控制、延时功能拆分为独立模块,既兼顾代码的可移植性与可读性,也为嵌入式入门开发者建立规范的底层编程思维。

一、需求

嵌入式入门经典案例 —— 使用 STM32F103 的 GPIOA0、GPIOA1、GPIOA8 引脚驱动 3 路 LED(LED1/LED2/LED3)实现流水灯效果,要求代码模块化、可移植、易扩展。

二、硬件电路

三、分析

1.电路原理

LED1、LED2、LED3 的阳极通过 2K 排阻接 3.3V 高电平,阴极分别接 GPIOA0、GPIOA1、GPIOA8 引脚:

点亮 LED:对应 GPIO 引脚输出低电平(阴极拉低,形成导通回路);

熄灭 LED:对应 GPIO 引脚输出高电平(阴极拉高,回路断开)。

2. 结论

需要将 GPIOA0、GPIOA1、GPIOA8 配置为推挽输出模式(可选50MHz 最大速度),通过控制引脚高低电平实现 LED 亮灭。

四、代码模块化设计思路

按照结构化的设计对代码进行划分和优化,将代码按照功能进行模块化,按照功能功能包装成函数。这样可以增加代码的可移植性和可读性。

首先,LED控制部分的源代码可以单独封装成一个.c文件:led.c,并且与之匹配一个led.h文件,以便提供相应的接口。

配置端口模式、初始状态的代码部分可以封装成一个初始化函数

led.h文件:

代码中通过使用#define将单片机的GPIO寄存器名称重命名为LED1\2\3,增加了代码的可读性。

#ifndef __LED_H #define __LED_H //包含需要用到的头文件 #include "stm32f10x.h" // LED接口宏定义 增加代码的可读性 #define LED1 GPIO_ODR_ODR0 #define LED2 GPIO_ODR_ODR1 #define LED3 GPIO_ODR_ODR8 // LED初始化 void LED_Init(void); // 打开或关闭某一个LED void LED_On(uint16_t led); void LED_Off(uint16_t led); // 翻转某一位的LED void LED_Turn(uint16_t led); // 全部打开或关闭 void LED_All_On(uint16_t leds[], uint8_t size); void LED_All_Off(uint16_t leds[], uint8_t size); #endif

led.c文件

在led.c文件中,直接操作寄存器来配置对应GPIO端口的工作模式和状态,以达到控制LED灯的工作状态。并将对应的操作封装成函数,在整体逻辑中直接调用函数来实现具体的功能。

注意:如果在for循环中定义并初始化循环变量,需要在keil中设置支持C99。 for(uint8_t i = 0; i < led; i++)

#include "led.h" // LED初始化 void LED_Init(void) { //1.打开GPIOA的时钟 RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; //2.设置GPIOA的A1、A2、A3口为推挽输出模式,最高频率为50MHz GPIOA->CRL &= ~GPIO_CRL_CNF0;//在寄存器MODE为输出模式的时候,CNF寄存器 0 0 表示推挽输出模式 GPIOA->CRL |= GPIO_CRL_MODE0;//MODE寄存器 1 1 表示输出模式,最高频率为50MHz GPIOA->CRL &= ~GPIO_CRL_CNF1; GPIOA->CRL |= GPIO_CRL_MODE1; GPIOA->CRH &= ~GPIO_CRH_CNF8; GPIOA->CRH |= GPIO_CRH_MODE8; LED_Off(LED1); LED_Off(LED2); LED_Off(LED3); } // 打开或关闭某一个LED void LED_On(uint16_t led) { GPIOA->ODR &= ~led; } void LED_Off(uint16_t led) { GPIOA->ODR |= led; } // 翻转某一位的LED void LED_Turn(uint16_t led) { if((GPIOA->IDR & led) == 0)//端口的输出的状态可以在IDR中读取,注意:这里不能判断是否为1,因为是不同的位 { LED_Off(led); } else { LED_On(led); } } // 全部打开或关闭 void LED_All_On(uint16_t leds[], uint8_t led_num) { for(uint8_t i = 0; i < led_num; i++) { LED_On(leds[i]); } } void LED_All_Off(uint16_t leds[], uint8_t led_num) { for(uint8_t i = 0; i < led; i++) { LED_Off(leds[i]); } }

delay.h文件

#ifndef __DELAY_H #define __DELAY_H #include "stm32f10x.h" void Delay_nms(uint16_t nms); void Delay_nus(uint16_t nus); #endif

delay.c文件

#include "delay.h" void Delay_nus(uint16_t nus) { //使用系统的滴答计时器实现,滴答计时器可以实现一个机器周期减一个数,减到零的时候会将寄存器的SysTick_CTRL_COUNTFLAG位置1 SysTick->LOAD = nus * 72; //时钟周期为72MHz,一个机器周期是1/72us SysTick->CTRL |= 0x05; //使用系统时钟(1);计数结束时不产生中断(0);使能定时器 while((SysTick->CTRL & SysTick_CTRL_COUNTFLAG) == 0)//检测计数是否结束 {} //关闭定时器 SysTick->CTRL &= ~SysTick_CTRL_ENABLE; } void Delay_nms(uint16_t nms) { while(nms--) { Delay_nus(1000);//产生1ms的延时 } }

main.c文件

#include "stm32f10x.h" #include "delay.h" #include "led.h" #define DELAY_TIME 300 //LED等的闪烁间隔 int main(void) { //1.初始化 LED_Init(); //2.创建一个LED灯的数组 uint16_t leds[3] = {LED1, LED2, LED3}; //3.在一个while循环中实现流水灯 while(1) { for(uint16_t i = 0; i < 3; i++) { LED_On(leds[i]); Delay_nms(DELAY_TIME); LED_Off(leds[i]); } } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 12:28:27

打造自己的大模型-02篇|LoRA微调大模型的评测和导出

在之前的的文章《打造自己的大模型&#xff5c;01篇LLaMA-Factory微调Llama3和其占用资源分析》&#xff0c;我们通过训练了9.5小时&#xff0c;完成了Llama3-8B-Instruct的LoRA 微调训练。 本篇文章&#xff0c;我们将继续利用LLaMA-Factory&#xff0c;进行大模型的评测和导出…

作者头像 李华
网站建设 2026/6/10 3:15:09

别卷Prompt了!Agent才是大模型时代程序员的终极外挂

MCP、A2A两个词在AI界火爆&#xff01;你都知道是什么吗&#xff1f; **2025 年&#xff0c;**注定是 Agent 从技术概念走向商业主流的转折点。无论是企业还是个人&#xff0c;若想在这场智能化浪潮中不被淘汰&#xff0c;拥抱 Agent 已不再是选择题&#xff0c;而是生存题。 …

作者头像 李华
网站建设 2026/6/10 4:40:20

Shell脚本if elif语法与MySQL数据库操作实用教程

在Shell脚本中结合条件判断与MySQL操作&#xff0c;是自动化运维和数据处理中的常见需求。通过if-elif-else结构&#xff0c;我们可以根据不同的条件执行相应的数据库操作&#xff0c;实现流程控制和错误处理。掌握这一组合技能&#xff0c;能有效提升脚本的健壮性和实用性。 S…

作者头像 李华
网站建设 2026/6/10 13:09:22

【异常】Antigravity IDE 登录异常与网络连接错误排查指南

在使用 Google 推出的 AI 原生 IDE Antigravity 时,部分用户可能会遇到身份验证失效与网络环境冲突导致的叠加错误。本文将针对此类典型故障提供完整的解决思路。 一、 报错内容 在 IDE 的通知栏或输出面板中,通常会同时出现以下两条错误提示: 网络连接错误: Check your i…

作者头像 李华
网站建设 2026/6/10 3:29:12

库克反击中国手机,大量安卓用户转买iPhone,真是风水轮流转!

在以往中国手机品牌都喜欢说苹果用户舍弃iPhone购买他们的手机&#xff0c;苹果往往都不会回应&#xff0c;而这次苹果CEO库克专门提到中国市场“从安卓阵营转入的用户数量创下新高”&#xff0c;这无疑就是在回敬中国手机。库克当然有理由高兴&#xff0c;因为2025年四季度苹果…

作者头像 李华