STM32F103的流水灯点亮版本1(寄存器地址操作)

STM32F103的流水灯点亮版本1(寄存器地址操作) 这是我第一次进行有关STM32的比较全面的编程。在编程过程中还有着不小的困难。在学习之前就要了解STM32的芯片系列,引脚功能、外设和时钟等功能。了解如何设置开发环境,选择合适的开发工具如(Keil MDK或STM32CubeIDE)、如何创建和配置项目,以及如何下载和调试代码。烧录工具也有着不熟悉的问题。在串口以及跳线上还不熟悉。总体来说,在STM32上还有着较大的困难,还要继续学习。 阅读详情

一、STM32F103C8T6 最小系统核心板介绍

STM32F103C8T6 是 ST 意法半导体推出的Cortex‑M3 内核 32 位高性能单片机,LQFP‑48 封装,是学生嵌入式学习最常用的最小系统核心板。

在这里插入图片描述

(一)核心参数

(1)内核:ARM Cortex-M3,最高工作频率 72MHz

(2)存储:Flash 64KB(存放程序代码),SRAM 20KB(程序运行临时变量)

(3)供电:工作电压 2.0~3.6V,一般外部使用 3.3V 供电;支持 VBAT 纽扣电池给 RTC 实时时钟备份供电

(4)外设资源:GPIO 通用 IO 口、ADC、定时器、USART 串口、I2C、SPI、CAN、USB 等

(二)最小系统板必备电路

(1)电源电路:外部 5V 输入,AMS1117-3.3V 稳压芯片输出 3.3V 给主芯片供电

(2)复位电路 NRST:RC 复位,按键按下低电平,芯片系统复位

(3)高速外部晶振 HSE:8MHz 无源晶振,经 PLL 倍频得到 72MHz 系统时钟

(4)低速外部晶振 LSE:32.768KHz,为 RTC 实时时钟提供时钟

(5)BOOT 启动选择引脚:

  • BOOT0=0:从Flash 启动(正常下载程序模式,日常使用)
  • BOOT0=1:从系统存储器启动(串口 ISP 下载)

(6)下载调试电路:集成 SWD 调试接口(PA13-SWDIO、PA14-SWCLK),使用 ST-Link 下载调试

(7)板载 LED::核心板自带 LED,LED 阳极接 3.3V,引脚输出低电平点亮 LED,高电平熄灭

二、相关概念的学习

(一)GPIOx端口

GPIO = General‑Purpose Input Output,通用输入输出端口。
GPIOx 中,x 是端口标识符,代表不同端口组,在 STM32F103 芯片中可以是 A、B、C、D、E,于是就有 GPIOA、GPIOB、GPIOC、GPIOD、GPIOE。而且每一个 GPIOx 端口,固定拥有最多 16 个 IO 引脚:Px0 ~ Px15。GPIOA、GPIOB、GPIOC 挂载在 APB2 外设总线上。所以必须操作RCC_APB2ENR寄存器,把对应端口时钟打开;时钟不开启,GPIO 完全失效,读写寄存器无效。bit2 置 1 → 开启GPIOA时钟,bit4 置 1 → 开启GPIOC时钟。每组端口拥有自己独立的寄存器,地址互不相同,GPIOA 的寄存器只会控制 A 组引脚,不能控制 GPIOC 引脚。

在这里插入图片描述

(二)寄存器

在 STM32 单片机里,寄存器是 MCU 芯片内部、拥有固定物理地址的硬件存储单元,是 CPU 和硬件外设(GPIO、定时器、串口等)沟通的唯一桥梁。普通 C 语言变量是放在 RAM 内存里,只是软件临时数据;寄存器是真实硬件电路,对寄存器读写,直接改变芯片硬件行为。

核心特点

a.每个寄存器都有唯一固定物理地址
例如:

  • GPIOA_CRL 地址:0x40010800
  • GPIOA_ODR 地址:0x4001080C

CPU 通过访问这个地址,读写寄存器里面的数据。

b.寄存器由很多二进制位(bit)组成 STM32 的 GPIO 寄存器大多是 32 位,也就是 32 个 0/1 开关。 每一个 bit 或者连续几个 bit,专门控制硬件某一项功能。 比如GPIOA_CRL中,每 4 个 bit 控制 1 个 PA 端口引脚,用来设置引脚模式、输出速度。

c.每组 GPIOx 端口,都自带一套独立寄存器 GPIOA、GPIOB、GPIOC 各自拥有一套 CRL、CRH、ODR、IDR 寄存器。

  • 写 GPIOA 的寄存器,只会修改 PA 引脚,不会影响 PB、PC 引脚;
  • 写 GPIOC 寄存器,只修改 PC 引脚(本实验 PC13 板载 LED 就在 GPIOC)。

在这里插入图片描述

1、地址查找

每个 GPIO 端口都有一个基地址,CRL寄存器的偏移 = 0x00,真实物理地址 = GPIO端口基地址 + 偏移0x00

在这里插入图片描述

2、端口配置低寄存器

是GPIO 通用输入输出口,总线APB2,只控制该端口的 Px0 ~ Px7(低 8 个 IO 引脚),Px8‑Px15 由GPIOx_CRH端口配置高寄存器控制。x 代表端口A/B/C/D/E,例如 GPIOA_CRL 控制 PA0‑PA7;GPIOB_CRL控制 PB0‑PB7。修改单个引脚配置时,先把该引脚对应的 4 位清零 &= ~(0x0F << (4*n)),再写入新配置,不能直接给 CRL 整个寄存器赋值,否则会覆盖其他引脚;复用功能模式下,ODR 寄存器不再控制引脚电平,由片内外设(定时器、串口、SPI)控制引脚输出;输入上拉 / 下拉:CNF 只开启功能选择,真正电阻开关由GPIOx_ODR输出寄存器对应位控制。

在这里插入图片描述

3、GPIOx_CRH 端口配置高寄存器

CRH 只管 Px8‑Px15,Px0‑Px7 交给 CRL,不要搞混寄存器,修改单个高引脚应该先把该引脚对应的 4 位掩码0x0F移位清零,再写配置,禁止直接GPIOA->CRH = xxx,会覆盖 PA8‑PA15 全部引脚。上拉 / 下拉时CNF 只选择模式,必须配合 ODR 寄存器对应位,内部电阻才生效。复用功能输出时,ODR 不再控制引脚电平,由外设(TIM/USART/SPI)接管引脚。

在这里插入图片描述

4、APB2ENR

属于 RCC(复位和时钟控制)模块,必须先开启 GPIO 时钟,GPIO 寄存器才能正常工作。相对 RCC 基地址偏移地址是0x18,RCC 基地址为0x40021000所以 RCC_APB2ENR 物理地址 = 0x40021000 + 0x18 = 0x40021018,可读可写,每一位控制一个 APB2 总线上外设的时钟开关,写1时打开该外设时钟(使能),写0时关闭该外设时钟(复位默认,省电)

在这里插入图片描述

5、IDR、ODR
对比项GPIOx_IDRGPIOx_ODR
偏移0x080x0C
读写属性只读,写无效可读可写
含义读外部引脚实际电平读写内部输出锁存值
用途读取按键、外部输入信号设置输出电平;输入模式控制上下拉电阻
风险无,只管读修改单 bit 存在中断干扰风险

在这里插入图片描述
在这里插入图片描述

三、基于寄存器实现流水灯

(一)实验目的

理解 STM32 GPIO 外设工作原理,学习直接操作寄存器地址方式控制 IO 口,掌握 RCC 时钟使能,懂得 STM32 外设必须开启时钟才可以工作读懂 CRL、CRH、ODR 寄存器功能,掌握位操作 ,使用GPIOA、GPIOB、GPIOC这3种端口的任意引脚控制3个LED灯(这里用到的是PA1,PA3,PA5),结合最小系统板自带 PC13 板载 LED,实现 4 个 LED 轮流流水闪烁,间隔 1 秒

(二)软硬件准备

1.硬件

STM32F103C8T6 开发板,ST‑Link 下载调试器,USB 数据线、杜邦线,LED灯

2.软件

Keil MDK5 用写、编译、调试代码,初学 STM32,第一步就是搞定 Keil MDK5 开发环境。这块步骤繁琐,截图多,这里就不重复写长篇安装图文了,网上成熟教程资源非常多,要学会利用资源,跟着一步步操作效率更高。

STM32 入门教程‑2023 版 细致讲解 中文字幕‑哔哩哔哩

3.程序设计与实现

(1)代码思路

A.寄存器地址宏定义:

使用volatile uint32_t强制映射硬件寄存器真实物理地址。volatile告诉编译器:该地址是硬件寄存器,不要做缓存优化,每次都要真实读写内存。把RCC_APB2ENR、GPIOA_CRL、GPIOA_ODR、GPIOC_CRH、GPIOC_ODR定义成宏,后面代码直接写名字访问寄存器。

B.delay_1s 软件延时函数:

两层 for 空循环,靠 CPU 循环消耗时间,粗略实现 1 秒延时。循环变量加volatile,防止 Keil 高优化等级直接把空循环删掉,导致延时失效。

C.LED_GPIO_Init () 初始化函数:

操作RCC_APB2ENR,置位 bit2 打开 GPIOA 时钟,置位 bit4 打开 GPIOC 时钟。配置GPIOA_CRL:PA1、PA3、PA5 属于 PA0‑PA7,CRL 每 4 位控制 1 个引脚。先&= ~掩码:把对应引脚的 4 位全部清零;再|= 配置值:写入0001,设置为推挽输出,速度 2MHz。配置GPIOC_CRH:PC13 属于 PC8‑PC15,在 CRH 寄存器,同样先清 4 位,再写 0001 推挽输出。配置初始电平:操作 ODR,所有 LED 初始熄灭。PA1/PA3/PA5 外接 LED输出低电平熄灭;PC13 板载 LED:输出高电平熄灭。

D.main 主函数

先调用LED_GPIO_Init()完成端口初始化。进入while(1)死循环,循环是单片机程序主体,永远不会退出。分 4 个步骤轮流点亮单个 LED,其余全部熄灭:修改GPIOA_ODR、GPIOC_ODR控制引脚高低电平;每点亮一组,调用delay_1s()停留 1 秒;依次:PA1 亮 → PA3 亮 → PA5 亮 → PC13 亮,往复循环。

(2)点亮3个LED灯

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{		
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//开启GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);

	// PA1 PA3 PA5 推挽输出 50MHz
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);

	//初始全部熄灭(输出高电平,低电平点亮LED)
	GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5);
	
	while(1)
	{
		//点亮PA1,其余熄灭
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);
		GPIO_SetBits(GPIOA, GPIO_Pin_3);
		GPIO_SetBits(GPIOA, GPIO_Pin_5);
		Delay_ms(1000);
		
		//点亮PA3,其余熄灭
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
		GPIO_ResetBits(GPIOA, GPIO_Pin_3);
		GPIO_SetBits(GPIOA, GPIO_Pin_5);
		Delay_ms(1000);
		
		//点亮PA5,其余熄灭
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
		GPIO_SetBits(GPIOA, GPIO_Pin_3);
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
		Delay_ms(1000);
	}
}

(3)用PC13验证自己烧录的代码是否正常运行

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
int main(void)
{		
	GPIO_InitTypeDef GPIO_InitStructure;
	
	//开启GPIOA、GPIOC时钟(PA1 PA3 PA5属于GPIOA,PC14属于GPIOC)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC, ENABLE);

	// PA1 PA3 PA5 推挽输出 50MHz
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	// PC14 推挽输出 50MHz
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
	GPIO_Init(GPIOC, &GPIO_InitStructure);

	//初始全部熄灭(输出高电平,低电平点亮LED)
	GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_3 | GPIO_Pin_5);
	GPIO_SetBits(GPIOC, GPIO_Pin_14);
	
	while(1)
	{
		//点亮PA1,其余熄灭
		GPIO_ResetBits(GPIOA, GPIO_Pin_1);
		GPIO_SetBits(GPIOA, GPIO_Pin_3);
		GPIO_SetBits(GPIOA, GPIO_Pin_5);
		GPIO_SetBits(GPIOC, GPIO_Pin_14);
		Delay_ms(1000);
		
		//点亮PA3,其余熄灭
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
		GPIO_ResetBits(GPIOA, GPIO_Pin_3);
		GPIO_SetBits(GPIOA, GPIO_Pin_5);
		GPIO_SetBits(GPIOC, GPIO_Pin_14);
		Delay_ms(1000);
		
		//点亮PA5,其余熄灭
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
		GPIO_SetBits(GPIOA, GPIO_Pin_3);
		GPIO_ResetBits(GPIOA, GPIO_Pin_5);
		GPIO_SetBits(GPIOC, GPIO_Pin_14);
		Delay_ms(1000);

		//点亮PC14,其余熄灭
		GPIO_SetBits(GPIOA, GPIO_Pin_1);
		GPIO_SetBits(GPIOA, GPIO_Pin_3);
		GPIO_SetBits(GPIOA, GPIO_Pin_5);
		GPIO_ResetBits(GPIOC, GPIO_Pin_13);
		Delay_ms(1000);
	}
}

4.实验现象

LED灯

LED灯

四、总结

本次STM32裸寄存器流水灯实验,可以掌握了GPIO相关寄存器的配置方法,明白STM32外设上电后时钟默认关闭,使用前必须开启对应时钟。实验中学会使用Keil调试功能,单步运行观察寄存器数值变化,直观验证代码效果。也认识到软件空循环延时精度较差,仅适合实验演示。编写代码不能直接复制照搬,要弄懂每一行代码对应的硬件操作。

KEIL-MDK代码美化神器:AStyle配置全攻略(附常用参数详解) 本文详细介绍了如何在KEIL-MDK中配置和使用AStyle代码格式化工具,包括基础参数设置、高级格式控制、团队协作方案以及KEIL深度集成技巧。通过合理的AStyle配置,开发者可以显著提升代码风格一致性,优化团队协作效率,特别适合嵌入式开发项目。 阅读详情

相关推荐

C#连接数据库报Authentication to host ‘127.0.0.1‘ for user ‘root‘ using method ‘caching_sha2_password‘ fail

所以导致的,除了上边的办法,还可以把这个加密规则修改一下,这个的修改方式有很多,具体原因是因为MySQL8.0以前的加密规则是。

weixin_42209881的博客 4128

STM32F103的流水灯点亮版本1(寄存器地址操作)

STM32,ST 是意法半导体,M 是 Microelectronics 的缩写,32 表示32 位,合起来理解STM32就是指 ST 公司开发的 32 位微控制器。STM32 本质上来说是一个微控制器,自带了各种常用通信接口,比如 USART、I2C、SPI 等,可连接非常多的传感器,可以控制很多的设备。现实生活中,我们接触到的很多电器产品都有 STM32 的身影,比如智能手环,微型四轴飞行器,平衡车、移动 POST 机,智能电饭锅,3D 打印机等等。

m0_64359506的博客 346

基于YOLOv8的多类别检测模型融合实战:从数据集重构到模型训练

本文详细介绍了如何将多个单一类别的YOLOv8检测模型融合为一个高效的多类别检测模型。通过重构数据集、利用预训练模型生成新标签,并重新训练,解决了多模型并行带来的速度慢、资源占用高和部署复杂等问题。实战流程涵盖数据准备、标签生成、模型训练与评估,旨在帮助开发者构建性能优异的YOLOv8多类别检测模型。

kmeans3miner的博客 227

实验1 STM32F103的流水灯点亮版本1(寄存器地址操作)

具体的顺序是A_LED_LIGHT、B_LED_LIGHT、C_LED_LIGHT、D_LED_LIGHT和E_LED_LIGHT。SystemInit函数用于初始化硬件和系统的一些基本设置,而Delay_ms函数用于延迟一定的时间。然后,定义了一些寄存器的映射,例如RCC_APB2ENR、GPIOB_CRL、GPIOC_CRH等,通过这些映射可以方便地访问相应的寄存器。

gasling2003的博客 242

Cadence SIP Layout 简单教程-第二章

[从whp1920 网易博客迁移至优快云] 第一章在正式布线之前做了必须做的准备工作,下面进入正题,打开Candence SIP RF Layout GXL软件。 第一节 导入外形尺寸 打开SIP设置文件保存路径,如下图所示进入导入DXF页面,选中前一章时画好的外框图。打开导入界面后,再进入DXF In Edit/View Layers界面选择所有层,导入Class选择DRAWING FOR...

whp1920的博客 6939

从零搭建IoT数据中台:STM32+WebSocket实现边缘设备与Web端实时双向通信

本文详细介绍了如何从零搭建基于STM32和WebSocket协议的IoT数据中台,实现边缘设备与Web端的实时双向通信。通过硬件选型、协议设计、服务器搭建及安全优化,提供了一套低延迟、高并发的企业级解决方案,适用于智能农业和工业监控等场景。

tea88的博客 749

实验1: STM32F103的流水灯点亮版本1(寄存器地址操作)

通过本次实验我掌握通过STM32最小系统核心板搭建电路的方法,通过GPIOA、GPIOB、GPIOC三个端口控制三只LED灯的闪烁,闪烁间隔为1秒。并熟悉了配置GPIO端口的工作模式和输出模式。在本实验中,使用的是推挽输出模式。然后,需要设置GPIO端口的输出速度。在本实验中,使用的是中速输出模式。接下来,需要设置GPIO端口的输出状态。通过设置GPIO端口的寄存器来实现LED灯的亮灭控制。最后,为了实现轮流闪烁,可以使用延时函数来控制LED灯的亮灭状态切换。

wangyh23的博客 336

川崎机器人总线通信_三菱PLC和发那科机器人进行CCLINK总线通信

三菱CCLINK主站模块采用QJ61BT11N,该模块用在Q系列PLC上,如果是5U或3UPLC,可用FX5-CNV-BUS加FX3U-16CCL-M或FX5-CCL-M模块。本教程以Q系列为例CCLINK接线方法如下模块拨码含义如下接线和拨码设置好后,接着在编程软件上设置CCLINK通信参数打开编程软件,在工程导航栏打开参数——网络参数,选中CCLINK打开。打开如下画面起始IO为模块本体占用I...

weixin_42300398的博客 7549
上一篇: 【下载Vmware,在其中安装Ubuntu 22.04,并用gcc和Makefile编写C语言程序】
下一篇: 标准外设库点亮STM32流水灯
2601_96584202
博客等级 码龄120天 0粉丝 9原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值