目录
一、准备工作
1、什么是STM32芯片?
STM32,从字面上来理解,ST 是意法半导体,M 是 Microelectronics 的缩写,32 表示32 位,合起来理解,STM32 就是指 ST 公司开发的 32 位微控制器。在如今的 32 位控制器当中,STM32 可以说是最璀璨的新星,它受宠若娇,大受工程师和市场的青睐,无芯能出其右。
STM32 属于一个微控制器,自带了各种常用通信接口,比如 USART、I2C、SPI 等,可连接非常多的传感器,可以控制很多的设备。现实生活中,我们接触到的很多电器产品都有 STM32 的身影,比如智能手环,微型四轴飞行器,平衡车、移动 POST 机,智能电饭锅,3D 打印机等等。
STM32 有很多系列,可以满足市场的各种需求,从内核上分有 Cortex-M0、M3、M4和 M7 这几种,每个内核又大致分为主流、高性能和低功耗。
单纯从学习的角度出发,可以选择 F1和 F4,F1代表了基础型,基于 Cortex-M3内核,主频为 72MHZ,F4 代表了高性能,基于 Cortex-M4 内核,主频 180M。本文则选择的F1下的stm32f103c8t6。
2、GPIO相关的寄存器
首先需要知道的是,STM32中对于GPIO口的操作,无非就是操作下面的寄存器而已,所谓的标准库也好,HAL库也好,它们都只是对操作寄存器的过程进行了封装,目的是为了减轻你编程时的工作负担。因此对于寄存器的描述,你只要稍微了解一下,大概知道每个寄存器是干啥的,有哪些位,是如何配置的就行,除了一些你觉得需要留意的地方,其它的完全没有必要完全记住,用的时候知道在哪里查就行了。
两个32位的配置寄存器:GPIOx_CRL、GPIOx_CRH
两个32位数据寄存器:GPIOx_IDR、GPIOx_ODR
一个32位的置位/复位寄存器:GPIOx_BSRR
一个16位复位寄存器:GPIOx_BRR
一个32位锁定寄存器:GPIOx_LCKR
注:具体的寄存器描述可以参考《STM32F10x-中文参考手册》的GPIO章节的P113页。强烈建议先花几分钟先看一下这一部分的内容。
-
GPIO地址
-
时钟地址
-
初始化地址以及GPIO偏移量
二、GPIO输出的操作
- A0
- C15
- B9
GPIO口有八种模式:
1.输入浮空
2.输入上拉
3.输入下拉
4.模拟输入
5.开漏输出
6.推挽式输出
7.推挽式复用功能
8.开漏复用功能
这里点亮LED灯使用推挽输出。
端口1-7为低,端口8-15为高。每个引脚由四个位控制。
1、初始化GPIO
以GPIOA和0号引脚(A0)为例,将其设置为推挽输出,并设置最大速度为10MHz,则将控制A0的四个位设置为0001。同理从上图可以得到另外两个的设置。
对于GPIOA的A0、GPIOC的C15、GPIOB的B9,初始化设置如下:
#define GPIOB_CRH (*(unsigned int *)0x40010C04)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
// 配置 GPIO 口为推免输出
// GPIOB----最后四位为0001
GPIOB_CRH |= (1<<4); // 最后一位变1
GPIOB_CRH &= ~(0xE<<0); // 倒数2、3、4位变0
// GPIOC----前四位为0001
GPIOC_CRH |= (1<<28); // 第四位变1
GPIOC_CRH &= ~(0xE0000000); // 前三位变0
// GPIOA----最后四位为0001
GPIOA_CRL |= (1<<0); // 最后一位变1
GPIOA_CRL &= ~(0xE<<0); // 倒数2、3、4位变0
2、设置低电平
输出高电平则为1,低电平则为0。
对于GPIOB的B9、GPIOC的C15、GPIOA的A0,设置如下:
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
GPIOB_ODR &= ~(1<<9); //最后一位变为0
GPIOC_ODR &= ~(1<<15); //倒数16位变为0
GPIOA_ODR &= ~(1<<0); //最后一位变为
三、创建项目
1、新建项目
点击Project
下的New uVision Project
,并输入文件名LED
:
选择芯片(这里我用的是STM32F103C8T6
):
添加文件main.c
:
将启动文件从下载的代码包中粘贴到该工程目录下:
(下载地址:野火资料下载中心)
将启动文件导入:
点击魔法棒设置生成HEX文件(后面烧录需要!):
2、编写代码
代码:
//--------------APB2使能时钟寄存器------------------------
#define RCC_AP2ENR *((unsigned volatile int*)0x40021018)
//----------------GPIOA配置寄存器 ------------------------
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
#define GPIOA_ORD *((unsigned volatile int*)0x4001080C)
//----------------GPIOB配置寄存器 ------------------------
#define GPIOB_CRH *((unsigned volatile int*)0x40010C04)
#define GPIOB_ORD *((unsigned volatile int*)0x40010C0C)
//----------------GPIOC配置寄存器 ------------------------
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
#define GPIOC_ORD *((unsigned volatile int*)0x4001100C)
//-------------------简单的延时函数-----------------------
void SystemInit(void);
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<800;i++);
}
void A_LED_LIGHT(){
GPIOA_ORD=0x0<<0; //PA0低电平
GPIOB_ORD=0x1<<9; //PB9高电平
GPIOC_ORD=0x1<<15; //PC15高电平
}
void B_LED_LIGHT(){
GPIOA_ORD=0x1<<0; //PA0高电平
GPIOB_ORD=0x0<<9; //PB9低电平
GPIOC_ORD=0x1<<15; //PC15高电平
}
void C_LED_LIGHT(){
GPIOA_ORD=0x1<<0; //PA0高电平
GPIOB_ORD=0x1<<9; //PB9高电平
GPIOC_ORD=0x0<<15; //PC15低电平
}
//------------------------主函数--------------------------
int main()
{
int j=100;
RCC_AP2ENR|=1<<2; //APB2-GPIOA外设时钟使能
RCC_AP2ENR|=1<<3; //APB2-GPIOB外设时钟使能
RCC_AP2ENR|=1<<4; //APB2-GPIOC外设时钟使能
//这两行代码可以合为 RCC_APB2ENR|=1<<3|1<<4;
GPIOA_CRL&=0xFFFFFFF0; //设置位 清零
GPIOA_CRL|=0x00000002; //PA0推挽输出
GPIOA_ORD|=1<<0; //设置PA0初始灯为灭
GPIOB_CRH&=0xFFFFFF0F; //设置位 清零
GPIOB_CRH|=0x00000020; //PB9推挽输出
GPIOB_ORD|=1<<9; //设置初始灯为灭
GPIOC_CRH&=0x0FFFFFFF; //设置位 清零
GPIOC_CRH|=0x30000000; //PC15推挽输出
GPIOC_ORD|=0x1<<15; //设置初始灯为灭
while(j)
{
A_LED_LIGHT();
Delay_ms(1000000);
B_LED_LIGHT();
Delay_ms(1000000);
C_LED_LIGHT();
Delay_ms(1000000);
}
}
void SystemInit(){
}
将代码写到main.c文件中之后,build一下生成hex文件
四、连接电路
对于USB转TTL模块和STM32F103C8T6连接:
- GND — GND
- 3v3 — 3v3
- TXD — A10
- RXD — A9
连接到电脑,打开FlyMcu,上传HEX文件到STM32F103C8T6上:
-
信号波形图
-
烧录到单片机后得到如下效果:
STM32F103C8T6用C语言实现LED流水灯点亮
五、汇编实现
代码:
Stack_Size EQU 0x00000400;????
AREA STACK, NOINIT, READWRITE, ALIGN=3 ;NOINIT: = NO Init,?????READWRITE : ??,???ALIGN =3 : 2^3 ??,?8?????
Stack_Mem SPACE Stack_Size
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
AREA |.text|, CODE, READONLY
THUMB
REQUIRE8
PRESERVE8
ENTRY
Reset_Handler
bl LED_Init;bl:??????????????????,????(PC)?????LR???
MainLoop BL LED_ON_B
BL Delay
BL LED_OFF_B
BL Delay
BL LED_ON_C
BL Delay
BL LED_OFF_C
BL Delay
BL LED_ON_A
BL Delay
BL LED_OFF_A
BL Delay
B MainLoop;B:??????
LED_Init;LED???
PUSH {R0,R1, LR};R0,R1,LR???????
;????
LDR R0,=0x40021018;LDR???????????(??R0)?
ORR R0,R0,#0x1c
LDR R1,=0x40021018
STR R0,[R1]
;???GPIOA_CRL
LDR R0,=0x40010800
BIC R0,R0,#0x0fffffff;BIC ???????,????
LDR R1,=0x40010800
STR R0,[R1]
LDR R0,=0x40010800
ORR R0,#0x00000001
LDR R1,=0x40010800
STR R0,[R1]
;?PA0?1
MOV R0,#0x01
LDR R1,=0x4001080C
STR R0,[R1]
;???GPIOB_CRL
LDR R0,=0x40010C04
BIC R0,R0,#0xffffff0f;BIC ???????,????
LDR R1,=0x40010C04
STR R0,[R1]
LDR R0,=0x40010C04
ORR R0,#0x00000020
LDR R1,=0x40010C04
STR R0,[R1]
;?PB0?1
MOV R0,#0x200
LDR R1,=0x40010C0C
STR R0,[R1]
;???GPIOC
LDR R0,=0x40011004
BIC R0,R0,#0x0fffffff
LDR R1,=0x40011004
STR R0,[R1]
LDR R0,=0x40011004
ORR R0,#0x20000000
LDR R1,=0x40011004
STR R0,[R1]
;?PC15?1
MOV R0,#0x8000
LDR R1,=0x4001100C
STR R0,[R1]
POP {R0,R1,PC};???????R0,R1,LR?????R0,R1,PC
LED_ON_A
PUSH {R0,R1, LR}
MOV R0,#0x00
LDR R1,=0x4001080C
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF_A
PUSH {R0,R1, LR}
MOV R0,#0x01
LDR R1,=0x4001080C
STR R0,[R1]
POP {R0,R1,PC}
LED_ON_B;??
PUSH {R0,R1, LR}
MOV R0,#0x000
LDR R1,=0x40010C0C
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF_B;??
PUSH {R0,R1, LR}
MOV R0,#0x200
LDR R1,=0x40010C0C
STR R0,[R1]
POP {R0,R1,PC}
LED_ON_C;??
PUSH {R0,R1, LR}
MOV R0,#0x0000
LDR R1,=0x4001100C
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF_C;??
PUSH {R0,R1, LR}
MOV R0,#0x8000
LDR R1,=0x4001100C
STR R0,[R1]
POP {R0,R1,PC}
Delay
PUSH {R0,R1, LR}
MOVS R0,#0
MOVS R1,#0
MOVS R2,#0
DelayLoop0
ADDS R0,R0,#1
CMP R0,#330
BCC DelayLoop0
MOVS R0,#0
ADDS R1,R1,#1
CMP R1,#330
BCC DelayLoop0
MOVS R0,#0
MOVS R1,#0
ADDS R2,R2,#1
CMP R2,#15
BCC DelayLoop0
POP {R0,R1,PC}
NOP
END
建立工程步骤与C语言一致,只是新建文件的时候需要选择.s类型。
- 注意:
这里还需要一个操作,右键点击启动文件选择带魔法棒的选项
取消这两个选项的勾选,否则会出错
然后重复操作就可以得到一样的运行结果了。
六、总结
本次实验点亮LED流水灯就像每个编程语言的入门程序HELLO WORLD一般,是嵌入式编程最基础的东西。通过本次实验了解到了关于GPIO寄存器的相关操作,相信本次实验会对接下来的实验奠定很重要的基础。
七、参考资料
STM32 F103之点亮LED流水灯 (STM32入门学习)
二、STM32的GPIO输出操作
【STM32】GPIO的相关配置寄存器、库函数、位操作(实例:STM32控制跑马灯)
野火产品资料下载中心