STM32最小系统核心板(STM32F103C8T6)实现流水灯

一.题目要求

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

二.STM32简介

关于单片机外设的功能都是完全不同的,但初始化都是大同小异的,点灯是所有学单片机的人都应该学会的第一项技能,这样子才算入门。

  • 51单片机的点灯是,通过控制寄存器将片外引脚(我们称之为IO口)拉低拉高,输出高低电平,以控制LED亮灭,过程为:单片机给指令->控制寄存器->给IO口电平->控制LED亮灭

  • stm32的点灯则是,通过使能外设GPIO时钟,发出指令给外设GPIO,外设GPIO收到指令后,着手配置自己的寄存器,然后给IO口模式,让其实现各种功能,过程为:CPU给指令->GPIO收到指令->配置内部寄存器->配置IO口模式(注意是模式)->控制LED亮灭

STM32

  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。

三.GPIO初始化

1.输入输出模式和输出速率设置

  首先需要知道的是,STM32中对于GPIO口的操作,无非就是操作下面的寄存器而已,所谓的标准库也好,HAL库也好,它们都只是对操作寄存器的过程进行了封装,目的是为了减轻编程时的工作负担:

两个32位的配置寄存器:GPIOx_CRL、GPIOx_CRH

两个32位数据寄存器:GPIOx_IDR、GPIOx_ODR

一个32位的置位/复位寄存器:GPIOx_BSRR

一个16位复位寄存器:GPIOx_BRR

一个32位锁定寄存器:GPIOx_LCKR

  • 本次实验采用通用推挽输出模式,最高输出时钟频率2Mhz。分别用到A5、B9、C14三个引脚。其中A5属于端口配置低寄存器偏移地址为0x00,B9、C13属于端口配置高寄存器偏移地址为0x04。

(1)找到GPIOA、GPIOB、GPIOC的地址

查询数据手册找到GPIOA、GPIOB、GPIOC的地址,可发现本次实验采用GPIOA、B、C三个端口,该三个端口都属于APB2总线
在这里插入图片描述

(2)配置对应引脚寄存器,基地址+偏移量

在这里插入图片描述

在这里插入图片描述
故而配置如下

//----------------GPIOA配置寄存器 -----------------------
#define GPIOA_CRL		*((unsigned volatile int*)0x40010800)
//----------------GPIOB配置寄存器 -----------------------
#define GPIOB_CRL		*((unsigned volatile int*)0x40010C04)
//----------------GPIOC配置寄存器 -----------------------
#define GPIOC_CRH		*((unsigned volatile int*)0x40011004)

(3)设置输出模式为推挽输出,输出速度为2Mhz

在这里插入图片描述

     
	GPIOA->CRL&=0xFF0FFFFF;		//设置位 清零	
	GPIOA->CRL|=0X00200000;		//PA5推挽输出
	GPIOA->ODR|=1<<5;			//设置PA5初始灯为灭
	
	GPIOB->CRH&=0xFFFFFF0F;		//设置位 清零	
	GPIOB->CRH|=0x00000020;		//PB9推挽输出
	GPIOB->ODR|=0x1<<9;			//设置初始灯为灭
	
	GPIOC->CRH&=0xF0FFFFFF;		//设置位 清零
	GPIOC->CRH|=0x02000000;   	//PC14推挽输出
	GPIOC->ODR|=0x1<<14;			//设置初始灯为灭	

例:将GPIOB9配置成推挽输出模式,且最大速度为2MHz
首先,其为GPIOB9端口,其属于端口配置高寄存器模块,则由图8.2.2可知,CNF9和MODE9位为0,其余位为F,即:GPIOB_CRH&=0xFFFFFF0F;又因其为推挽输出模式,且最大速度为2MHz,所以4位寄存器的配置就是CNF9【00】MODE9【10】,0010换成十进制数就是2,即:GPIOB_CRH|=0x00000020

2.时钟地址

时钟控制名字叫做RCC,属于AHB总线。
在这里插入图片描述

在这里插入图片描述

查询数据手册可发现,外设时钟使能寄存器,设偏移量为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;

在这里插入图片描述

三.工程文件模板的建立

1.所需文件

2.创建工程

新建工程work4文件,工程名为led,因为之后实验采用C8T6板,因此这里选择STM32F103C8
之后弹出的添加库文件窗口Manage Run-Time Environment,在这个界面,我们可以添加自己需要的组件,从而方便构建开发环境,不过这里我们不做介绍。选择Cancel即可。至此为止我们还只是建了一个框架,还需要添加启动代码,以及.c 文件等。
在这里插入图片描述

3.启动代码

3.1启动代码介绍

  • 启动代码是一段和硬件相关的汇编代码
    主要作用如下:
    1、堆栈(SP)的初始化
    2、初始化程序计数器(PC)
    3、设置向量表异常事件的入口地址
    4、调用 main 函数

  • 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

查阅C8T8的数据手册,可知C8T6的Flash容量为128K,属于中容量,因此这里采用startup_stm32f10x_md.s作为启动文件
在这里插入图片描述

3.2使用启动代码

在这里插入图片描述

  • 我们找到 Target1→Source Group1→双击→设置打开文件类型为 Asm Source file→选择 startup_stm32f10x_hd.s→点击 Add,如下图所示
    在这里插入图片描述
    下列两个文件ListingsObjects,是 KEIL 自行创建的,用于保存编译过程中生成的一些文件。

  • 而后我们创建USER文件夹存放存放启动文件(startup_stm32f10x_md.s)、工程文件(test.uvprojx)等不可缺少的文件;创建OBJ文件夹存放这些编译过程中产生的中间文件(包括.hex文件也将存放在这个文件夹里面)。然后我们将把Listings 和Objects 文件夹里面的东西全部移到 OBJ 文件夹下。

  • 我们将系统代码 copy 过来放在我们的work4里面(即 SYSTEM文件夹,该文件夹由 ALIENTEK 提供,这些代码在任何 STM32F10x 的芯片上都是通用的,可以用于快速构建自己的工程。注意是寄存器版本
    在这里插入图片描述

3.3完善项目创建

(1)在USER文件夹下面找到 led,打开它,然后在 Target 目录树上点击右键→Manage Project Items,弹出对话框。
在这里插入图片描述

(2)在上面对话框的中间栏,点新建按钮(也可以通过双击下面的空白处实现),新建 USERSYSTEM 两个组。然后点击 Add Files 按钮,把 SYSTEM 文件夹三个子文件夹里面的:sys.c、usart.c、delay.c 加入到 SYSTEM 组中。然后OK,返回界面
在这里插入图片描述
在这里插入图片描述
(3)点击新建文件,新建test.c文件,保存在USER中,然后双击USER,会弹出加载文件的对话框,此时我们在 USER 目录下选择test.c文件,加入到 USER 组下。
在这里插入图片描述

(4)设置路径,点击魔法棒,弹出 Options for Target’Target 1’对话框,选择 Output 选项卡→选中 Create Hex File(用于生成 Hex 文件,后面会用到)→点击 Select Folder for Objects→找到 OBJ 文件夹→点击 OK
在这里插入图片描述
(5)再设置 Listings 文件路径,在上述基础上,打开 Listing 选项卡→点击 Select Folder for Listings→找到 OBJ 文件夹→点击 OK

(6)最后选择c/c++,在Define处输入:STM32F10X_MD,然后点击include Patha添加sys、delay、usart的include路径,如图所示在这里插入图片描述

  • 注意!我们必须根据所用 STM32F1 型号的容量,来输入相关宏定义,对于STM32F103 系列芯片,设置原则如下:
    16KB≤FLASH≤32KB 选择:STM32F10X_LD 64KB≤FLASH≤128KB 选择:STM32F10X_MD
    256KB≤FLASH≤512KB 选择:STM32F10X_HD

至此我们的工程就完全建立好啦,可以开始写入代码了。

四.代码的书写

(1)在wor4文件夹下新建一个HARDWARE文件夹,用来存储以后与硬件相关的代码。
(2)打开程序,新建两个文件led.c led.h,保存在HARDWARE中
(3)将文件添加进入工程,步骤与上述操作一致。在这里插入图片描述
(4)点击魔法棒按照之前步骤,将HARDWARE路径加入,以免报错
在这里插入图片描述

1.led.c

#include "led.h"
void LED_Init(void)
{

    RCC->APB2ENR|=1<<2;			//APB2-GPIOA外设时钟使能
	RCC->APB2ENR|=1<<3;			//APB2-GPIOB外设时钟使能	
	RCC->APB2ENR|=1<<4;			//APB2-GPIOC外设时钟使能
	GPIOA->CRL&=0xFF0FFFFF;		//设置位 清零	
	GPIOA->CRL|=0X00200000;		//PA5推挽输出
	GPIOA->ODR|=1<<5;			//设置PA5初始灯为灭
	
	GPIOB->CRH&=0xFFFFFF0F;		//设置位 清零	
	GPIOB->CRH|=0x00000020;		//PB9推挽输出
	GPIOB->ODR|=0x1<<9;			//设置初始灯为灭
	
	GPIOC->CRH&=0xF0FFFFFF;		//设置位 清零
	GPIOC->CRH|=0x02000000;   	//PC14推挽输出
	GPIOC->ODR|=0x1<<14;			//设置初始灯为灭	

}

2.led.h

#ifndef __LED_H
#define __LED_H	 
#include "sys.h"
//--------------APB2使能时钟寄存器------------------------
#define RCC_AP2ENR	*((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 LED_Init(void);	//初始化		

#endif



3.test.c

#include "sys.h"
#include "usart.h"		
#include "delay.h"	
#include "led.h"
void A_light()
{
	GPIOA_ODR=0x0<<5;		//PA5低电平
	GPIOB_ODR=0x1<<9;		//PB9高电平
	GPIOC_ODR=0x1<<14;		//PC14高电平
}
void B_light()
{
	GPIOA_ODR=0x1<<5;		//PA5低电平
	GPIOB_ODR=0x0<<9;		//PB9高电平
	GPIOC_ODR=0x1<<14;		//PC14高电平
}
void C_light()
{
	GPIOA_ODR=0x1<<5;		//PA5低电平
	GPIOB_ODR=0x1<<9;		//PB9高电平
	GPIOC_ODR=0x0<<14;		//PC14高电平
}
int main(void)
{				  
	Stm32_Clock_Init(9);//系统时钟设置
	delay_init(72);	  	//延时初始化
	LED_Init();		  	//初始化与LED连接的硬件接口
	
	while(1)
	{
	 A_light();
	 delay_ms(1000);
		 B_light();
		delay_ms(1000);
		 C_light();
		delay_ms(1000);
	}	 
}


点击编译发现无错误无警告,成功啦!
在这里插入图片描述

五.调试问题

当我们点击调试按键时会出现如下警告
在这里插入图片描述
我们需要先点击魔法棒找到Debug,勾选Use Simulator(因为我们的电脑没有连接设备);在Utilities中取消勾选Use Debug Driver,点击Settings,选择Reset and Run就可以正常调试啦。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

六.总结

本文带领大家熟悉了一遍寄存器方式编程的基本操作,完成了流水灯实验,笔者在学习期间也遇到过许多困难,但经过查阅资料询问老师同学也解决了问题,受益匪浅,各位在学习途中也不要急于求成要一步一步地来。最后由于笔者暂时还没有面包板故无法进行实物的演示。


参考

1.https://blog.csdn.net/qq_47281915/article/details/120812867
2.https://blog.csdn.net/weixin_47554309/article/details/120810913
3.https://blog.csdn.net/qq_46467126/article/details/120791793?spm=1001.2014.3001.5502
4.https://blog.csdn.net/qq_53112972/article/details/127153401?spm=1001.2014.3001.5502

  • 1
    点赞
  • 43
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
STM32F103C8T6最小系统实现流水灯,你需要准备以下材料和工具: 1. STM32F103C8T6最小系统核心 2. 面包 3. 3只红绿蓝LED灯 4. mcuisp驱动 5. startup驱动 6. STM32CubeMX软件 下面是实现流水灯的步骤: 1. 连接硬件:将STM32F103C8T6最小系统核心插入面包上,并将3只LED灯连接到子上的GPIO引脚上。 2. 安装驱动:将mcuisp和startup驱动复制到合适的位置,确保它们可以被系统访问到。 3. 配置STM32CubeMX:使用STM32CubeMX软件生成初始化代码。打开软件,选择正确的芯片型号(STM32F103C8T6),然后配置GPIO引脚为输出模式,并将它们与LED灯连接起来。 4. 生成代码:在STM32CubeMX软件中生成初始化代码,并将其导出到你的工程目录中。 5. 编写代码:在你的工程目录中创建一个新的C文件,编写代码来控制流水灯的闪烁。你可以使用GPIO库函数来控制LED灯的状态。 6. 编译和下载:使用合适的编译工具编译你的代码,并将生成的二进制文件下载到STM32F103C8T6最小系统核心上。 下面是一个示例代码,用于实现流水灯效果: ```c #include "stm32f1xx.h" void delay(uint32_t time) { while(time--); } int main(void) { // 初始化GPIO引脚 RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // 使能GPIOC时钟 GPIOC->CRH &= ~(GPIO_CRH_MODE13 | GPIO_CRH_CNF13); // 清除PC13的配置 GPIOC->CRH |= GPIO_CRH_MODE13_0; // PC13配置为输出模式 while(1) { // 点亮LED灯 GPIOC->BSRR = GPIO_BSRR_BS13; // PC13置高,点亮LED灯 delay(1000000); // 延时一段时间 // 熄灭LED灯 GPIOC->BSRR = GPIO_BSRR_BR13; // PC13置低,熄灭LED灯 delay(1000000); // 延时一段时间 } } ``` 请注意,以上代码仅供参考,你可能需要根据你的具体硬件和需求进行适当的修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值