嵌入式系统开发07——STM32F103C8T6下C语言寄存器方式实现LED流水灯

本文主要描述如何使用STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿黄LED搭建电路,并通过GPIOA-5、GPIOB-9、GPIOC-14 这3个引脚来控制控制LED灯轮流闪烁。

一、题目要求

假设你手中已有 STM32最小系统核心板(STM32F103C8T6)+面板板+3只红绿蓝LED,并搭建了电路,分别 GPIOA-5、GPIOB-9、GPIOC-14 这3个引脚上控制LED灯(最高时钟 2Mhz ),轮流闪烁,间隔时长1秒
1)写出程序设计思路,包括GPIOx端口的各寄存器地址和详细参数;
2)用C语言 寄存器方式 编程实现。

二、设计思路

需要在 STM32F103C8T6 上面通过 初始化GPIO 来实现点亮 LED 灯。
外设实现的功能可能是完全不同的,但是,多数情况下,我们在设计程序的时候不需要考虑外设具体如何怎样实现功能,只需要给外设接在哪里、高电平有效还是低电平有效。因此,完成题目要求的时候,只需要找到 GPIOA-5、GPIOB-9、GPIOC-14 的地址,然后通过 GPIO的初始化,控制寄存器将片外引脚(我们称之为 IO口)拉低拉高, 输出高低电平,以控制LED亮灭。

点灯是所有学单片机的人都应该学会的一项技能。C51单片机和 stm32 点灯类似。

  • 51单片机的点灯是,通过控制寄存器将片外引脚(我们称之为IO口)拉低拉高,输出高低电平,以控制LED亮灭。
    其过程:单片机给指令->控制寄存器->给IO口电平->控制LED亮灭
  • stm32的点灯则是,通过使能外设GPIO时钟,发出指令给外设GPIO,外设GPIO收到指令后,着手配置自己的寄存器,然后给IO口模式,让其实现各种功能。其过程:CPU给指令->GPIO收到指令->配置内部寄存器->配置IO口模式(注意是模式)->控制LED亮灭

STM32开发板中包含较多寄存器,实现流水灯操作,需要对相应的引脚进行操作,对相应的引脚进行时钟配置、输入输出模式设置、最大速率设置。
于是利用 STM32F103C8T6 实现流水灯,要经过以下步骤:

  • 时钟配置
  • 输入输出模式设置
  • 最大速率设置
  • 烧录程序
  • 运行

三、STM简介

STM32,ST 是意法半导体,M 是 Microelectronics 的缩写,32 表示32 位,合起来理解STM32就是指 ST 公司开发的 32 位微控制器。
STM32 本质上来说是一个微控制器,自带了各种常用通信接口,比如 USART、I2C、SPI 等,可连接非常多的传感器,可以控制很多的设备。现实生活中,我们接触到的很多电器产品都有 STM32 的身影,比如智能手环,微型四轴飞行器,平衡车、移动 POST 机,智能电饭锅,3D 打印机等等。
STM32 有很多系列,可以满足市场的各种需求,从内核上分有 Cortex-M0、M3、M4和 M7 这几种,每个内核又大致分为主流、高性能和低功耗。
单纯从学习的角度出发,可以选择 F1和 F4,F1代表了基础型,基于 Cortex-M3内核,主频为 72MHZ,F4 代表了高性能,基于 Cortex-M4 内核,主频 180M。

STM32F103C8T6芯片介绍
1
STM32F103C8T6 是一款基于ARM Cortex-M 内核 STM32系列 的 32位 的微控制器,程序存储器容量是 64KB,需要电压 2V~3.6V,工作温度为 -40°C ~ 85°C。具体参数如下:
2

四、实现过程

1、时钟配置

  • 找到时钟使能寄存器映射基地址
    4
  • 找到端口偏移地址以及对应端口所在位置
    5
  • 外设时钟使能寄存器,偏移量为0x18,起始地址0x4002 1000,该寄存器地址为0x4002 1018
  • 使能对应端口时钟
    查询数据手册可发现,外设时钟使能寄存器,设偏移量为0x18,起始地址0x4002 1000,该寄存器地址为0x4002 1018
#define RCC_AP2ENR	*((unsigned volatile int*)0x40021018) #时钟使能寄存器

手册RCC_APB2ENR,位3是IOPBEN,名字是IO端口B时钟使能,就是我们想要的。把RCC_APB2ENR的位3赋值为1,就是开启GPIOB时钟

RCC->APB2ENR|=1<<2;			//APB2-GPIOA外设时钟使能
RCC->APB2ENR|=1<<3;			//APB2-GPIOB外设时钟使能	
RCC->APB2ENR|=1<<4;			//APB2-GPIOC外设时钟使能
//这两行代码可以合为 RCC_APB2ENR|=1<<3|1<<4;

6

2、输入输出模式设置、最大速率设置

本次实验采用通用推挽输出模式,最高输出时钟频率2Mhz。分别用到GPIOA-5、GPIOB-9、GPIOC-14 这3个引脚上三个引脚。其中A4属于端口配置低寄存器偏移地址为0x00,B9、C14属于端口配置高寄存器偏移地址为0x04。
7
8

  • 找到GPIOx端口基地址
    9
  • 配置对应引脚寄存器,基地址+偏移量
    故而配置如下:
//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL		*((unsigned volatile int*)0x40010800)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRH		*((unsigned volatile int*)0x40010C04)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH		*((unsigned volatile int*)0x40011004)
  • 设置输出模式为推挽输出,输出速度为2Mhz
    例:将GPIOB-9配置成推挽输出模式,且最大速度为2MHz
    首先,其为GPIOB9端口,其属于端口配置高寄存器模块,则由上图可知,CNF9和MODE9位为0,其余位为F,即:GPIOB_CRH&=0xFFFFFF0F;又因其为推挽输出模式,且最大速度为2MHz,所以4位寄存器的配置就是CNF9【00】MODE9【10】,0010换成十进制数就是2,即:GPIOB_CRH|=0x00000020
GPIOA_CRL&=0xFFF0FFFF;		//设置位清零	
GPIOA_CRL|=0X00200000;		//PA5推挽输出,把第23、22、21、20位变为0010
GPIOA->ODR|=1<<5;			//设置PA5初始灯为灭
	
GPIOB_CRH&=0xFF0FFFFF;		//设置位清零	
GPIOB_CRH|=0x00000020;		//PB9推挽输出,把第7、6、5、4变为0010
GPIOB->ODR|=0x1<<9;			//设置初始灯为灭
	 
GPIOC_CRH&=0xFF0FFFFF;		//设置位清零	
GPIOC_CRH|=0x02000000;		//PC14推挽输出,把第27、26、25、24变为0010
GPIOC->ODR|=0x1<<14;			//设置初始灯为灭	

3、代码实现

3.1 创建工程文件

  • 新建 test2 文件夹 —> 点击 Project 下的 New uVision Project —> 输入文件名 test2
    10

  • 因为之后实验采用 STM32F103C8T6 板,因此这里选择 STM32F103C8
    11

  • 创建项目出现弹窗,勾选 CORE 项,点击 OK 完成创建
    12

3.2 添加启动代码

要实现 LED流水灯,还需要添加启动代码,以及.c 文件等。

C8T6 使用的启动文件 startup_stm32f10x_md.s,startup_stm32f10x_md.s 是一个启动文件,里面是使用汇编语言写好的基本程序,当 STM32 芯片上电启动的时候,首先会执行这里的汇编程序,从而建立起来C 语言的运行环境,所以我们把这个文件称为启动文件。C8T6 是中容量的arm芯片,启动文件的大致作用如下:

  • 初始化堆栈指针 SP
  • 初始化程序计数器指针 PC
  • 设置堆、栈的大小
  • 设置中断向量表的入口地址
  • 配置外部 SRAM 作为数据存储器
  • 调用 SystemInit() 函数配置 STM32 的系统时钟
  • 设置 C 库的分支入口 "__main” (最终用来调用 main 函数)

startup_stm32f10x_hd.s 文件是由ST官方提供的,该文件可以从 KEIL5 安装目录中找到,也可以从 STV3.5 库里面找到,找到该文件后吧启动文件添加到工程里面即可。不同型号的芯片以及不同编译环境使用的汇编文件是不一样的,但功能相同。
keilMDK4 中只有 STM32F10x.s 文件。
在《STM32不完全手册里面》,所有的例程都采用了一个叫 STM32F10x.s 的启动文件,里面定义了 STM32 的堆栈大小以及各种中断的名字及入口函数名称,还有启动相关的汇编代码。
STM32F10x.s 是MDK提供的启动代码,从其里面的内容看来,它只定义了3个串口,4个定时器。实际上STM32的系列产品有5个串口的型号,也只有有2个串口的型号,定时器也是,最多的有8个定时器。比如,如果你用的 STM32F103ZET6,而启动文件用的是STM32F10x.s 的话,你可以正常使用串口1 ~ 3的中断,而串口4和5的中断,则无法正常使用。又比如,你TIM1 ~ 4的中断可以正常使用,而5~8的,则无法使用。
所以 STM32F10x.s 并不能适用所有的STM32型号,这样,我们就得对不同型号的STM32,选择不同的启动文件。ST给我们提供了3个启动文件,分别适用于不同容量的STM32芯片。他们是:
startup_stm32f10x_ld.s
startup_stm32f10x_md.s
startup_stm32f10x_hd.s

其中,ld.s适用于小容量 产品;md.s适用于中等容量产品;hd适用于大容量产品
这里的容量是指FLASH的大小.判断方法如下:
小容量: FLASH≤32K
中容量: 64K≤FLASH≤128K
大容量: 256K≤FLASH
我们开发板使用的是 STM32F103C8T6,FLASH容量为64K,属于中等容量产品,而 STM32F10x.s 刚刚好是满足中等容量型号的启动文件,所以我们使用 STM32F10x.s 是不会有问题的,但是更便于理解,这里还是使用 startup_stm32f10x_md.s。而如果你的是小容量或者大容量的STM32,则相应的选择 startup_stm32f10x_ld.sstartup_stm32f10x_hd.s 即可。
按照上面的解释,最为普通的工程,STM32F10x.s 文件是够用的,但是在复杂的工程中,还是建议ST库文件的几个启动文件。

这里上传这几个启动文件:
链接:https://pan.baidu.com/s/1tYK8A6og03rPp51ZTrVBBw
提取码:plt3

  • 将启动文件拷贝到 test2 工程文件夹下:
    20
  • 点击 Target1→Source Group1→双击→设置打开文件类型为 Asm Source file→选择 startup_stm32f10x_md.s→点击 Add,如下图所示:
    21

3.3 代码编写

  • 在界面左侧的 Project 栏,打开 Target1,鼠标右键单击 Source Group1, 选择 Add New Item to Group ‘Source Group 1’…
    13
  • 添加 test2.c文件
    14
  • 编写代码

//--------------APB2使能时钟寄存器------------------------
#define RCC_APB2ENR		*((unsigned volatile int*)0x40021018)

//----------------GPIOA配置寄存器 ------------------------
#define GPIOA_CRL		*((unsigned volatile int*)0x40010800)
#define	GPIOA_ODR		*((unsigned volatile int*)0x4001080C)
	
//----------------GPIOB配置寄存器 ------------------------
#define GPIOB_CRH		*((unsigned volatile int*)0x40010C04)
#define	GPIOB_ODR		*((unsigned volatile int*)0x40010C0C)
	
//----------------GPIOC配置寄存器 ------------------------
#define GPIOC_CRH		*((unsigned volatile int*)0x40011004)
#define	GPIOC_ODR		*((unsigned volatile int*)0x4001100C)

//函数声明
void Delay_ms(volatile  unsigned  int);
void A_LED_LIGHT(void);
void B_LED_LIGHT(void);
void C_LED_LIGHT(void);

//时延函数
void Delay_ms( volatile  unsigned  int  t)
{
     unsigned  int  i;
     while(t--)
         for (i=0;i<10000;i++);
}

//控制灯亮灭
void A_LED_LIGHT()
	{
    GPIOA_ODR=0x0<<5;		//PA5低电平
	GPIOB_ODR=0x1<<9;		//PB9高电平
	GPIOC_ODR=0x1<<14;		//PC14高电平	
}
void B_LED_LIGHT()
	{
	GPIOA_ODR=0x1<<5;		//PA5高电平
	GPIOB_ODR=0x0<<9;		//PB9低电平
	GPIOC_ODR=0x1<<14;		//PC14高电平
}
void C_LED_LIGHT()
	{
	GPIOA_ODR=0x1<<5;		//PA5高电平
	GPIOB_ODR=0x1<<9;		//PB9高电平
	GPIOC_ODR=0x0<<14;		//PC14低电平
}

//------------------------主函数--------------------------
int main(){

	RCC_APB2ENR|=1<<2;			//APB2-GPIOA外设时钟使能
	RCC_APB2ENR|=1<<3;			//APB2-GPIOB外设时钟使能	
	RCC_APB2ENR|=1<<4;			//APB2-GPIOC外设时钟使能
//也可以写成 RCC_APB2ENR|=1<<3|1<<4;
	

  GPIOA_CRL&=0xFFF0FFFF;		//设置位清零	
  GPIOA_CRL|=0X00200000;		//PA5推挽输出,把第23、22、21、20位变为0010
	
  GPIOB_CRH&=0xFF0FFFFF;		//设置位清零	
  GPIOB_CRH|=0x00000020;		//PB9推挽输出,把第7、6、5、4变为0010
	 
  GPIOC_CRH&=0xFF0FFFFF;		//设置位清零	
  GPIOC_CRH|=0x02000000;		//PC14推挽输出,把第27、26、25、24变为0010

	GPIOA_ODR |= (1<<5);  
	GPIOB_ODR |= (1<<9);      //设置灯的初始状态为灭
	GPIOC_ODR |= (1<<14); 
	
	while(1)
		{
		  A_LED_LIGHT();
		  Delay_ms(60);
		  B_LED_LIGHT();
		  Delay_ms(60);
		  C_LED_LIGHT();
		  Delay_ms(60);
	}

}


3.4 编译调试

  • 打开魔术棒,如下图所示勾选 Create HEX File
    21

  • ST-Link/v2 驱动安装
    链接:https://pan.baidu.com/s/1oazATTwP9eGdjANB4FmEng
    提取码:plt3
    点击 .exe 文件进行安装
    25

  • STM32F103C8T6 通过ST-Link 连接到电脑 USB接口上

在这里插入图片描述

  • ST-LinkC8T6 之间通过杜邦线按照下图连接:
    在这里插入图片描述
    在这里插入图片描述
    在这里插入图片描述

  • 点击 魔术棒,在Debug下勾选 Use:ST-Link Debugger
    在这里插入图片描述

  • 点击 Setting ,若此时 C8T6 通过St-link成功连接到了电脑上,就可以看到下图信息;点击 确定-> OK ,保存设置
    在这里插入图片描述

  • 点击编译
    156

  • 将程序烧录到 C8T6
    在这里插入图片描述
    此时可能会弹出以下信息:
    在这里插入图片描述
    点击确定就行了
    在这里插入图片描述

  • 烧录成功后红灯长亮
    在这里插入图片描述

4、硬件连接

使用杜邦线将 A5、B9、C14连接到LED的负极(短脚),将开发板的3.3V输出通过杜邦线连接到LED的正极(长脚)在这里插入图片描述

5、实现效果

建议重新烧录一次,然后按一下开发板上的 reset
在这里插入图片描述

效果如下:

C8T6实现LED流水灯

五、总结

本次主要使用STM32F103C8T6核心板,通过电路搭建实现LED灯轮流闪烁。通过本次实验进一步加深了我对GPIO寄存器的认识与运用,也让我学会了如何配置GPIO。本次实验不难,但是由于刚刚接触到GPIO的初始化以及配置,导致实验的时间拉的很长,希望通过不断学习可以提高自己的动手能力和解决问题的能力。


参考列表:
1.STM32启动文件:startup_stm32f10x_hd.s等启动文件的简单描述
2.STM32F103C8T6寄存器方式借助面包板点亮LED流水灯详解
3.stm32cubeMX使用HAL库点亮LED流水灯
4.stm32寄存器实现流水灯
5.STM32F103C8T6实现流水灯

  • 4
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

6¿6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值