目录
一、stm32简介
二、stm32 F103介绍
三、流水灯实验
1. 流水灯实验详悉
2.点亮LED灯
3.keil新建项目
4.寄存器映射
5.代码.c语言
6.连接电路
?7.配置环境
四、汇编语言
五、总结
一、stm32简介
从字面意义来看:ST:意法半导体,是一个公司的名字。 M:Microelectronics的缩写,表示微控制器 32:32bit的意思,表示这是一个32bit的微控制器
STM32 属于一个微控制器,适用于控制类,自带了各种常用通信接口,比如 USART、 I2C、 SPI 等,可接非常多的传感器,可以控制很多的设备。现实生活中,我们接触到的很多电器产品都有 STM32 的身影,比如智能手环,微型四轴飞行器,平衡车、移动POS机,智能电饭锅,3D 打印机等等。
stm32是意法半导体(ST)集团生产的。意法半导体(ST)集团于1988年6月成立,是由意大利的SGS微电子公司和法国Thomson半导体公司合并而成。1998年5月,SGS-THOMSON Microelectronics将公司名称改为意法半导体有限公司,是世界最大的半导体公司之一。推出的STM32系列基于专为要求高性能、低成本、低功耗的嵌入式应用专门设计的ARM Cortex?-M0,M0+,M3, M4和M7内核。其实一个芯片是由内核和外设构成的,ST公司是造芯片的,但用的是ARM公司的内核再加上自己的外设构成一个完整的STM芯片,所以用ST命名。
二、stm32 F103介绍
STM32F系列属于中低端的32位ARM微控制器,该系列芯片是意法半导体(ST)公司出品,其内核是Cortex-M3[^1]。 该系列芯片按片内Flash的大小可分为三大类:小容量(16K和32K)、中容量(64K和128K)、大容量(256K、384K和512K)。 芯片集成定时器Timer,CAN,ADC,SPI,I2C,USB,UART等多种外设功能。
三、流水灯实验
1. 流水灯实验详悉
板子供电有两种方式: 通过U3 USB-micro接口提供5V供电,然后经过板载的LDO芯片转为VCC3V3;通过P2 接口,即SWD下载接口中的VCC3V3给核心板供电。 核心板上有两个LED,其中一个为电源指示灯PWR,另外一个LED与PC13引脚相连,当PC13置高时,LED灭;当PC13置低时,LED亮; 核心板上的跳线是为了选择启动模式使用。我们为了让程序以主闪存存储器作为启动区域,需要将BOOT0置低,BOOT1随意,此种启动模式是最常用的用户FLASH启动,为默认启动模式; 核心板上的按键为RESET复位按键; P2接口为SWD下载模式对应的引脚接口。
2.点亮LED灯
需要用到GPIO 端口。
为了点亮LED灯,需要三个步骤:
- 打开GPIO口的时钟
- 初始化GPIO口(选择推挽输出)
- 设置低电平
3.keil新建项目
?
?
?
?
?
?
4.寄存器映射
每个寄存器都是32bit,占用4个Byte即4个存储单元。可以把寄存器看作一个特殊的单元,一个这样的单元占32bit,只要找到这个单元的起始地址就可以对其进行操作。
其映射地址 = 外设总基地址(块基地址)+ 总线相对于外设总基地址的偏移 + 具体外设基地址相对于总线基地址的偏移 + 寄存器相对于具体外设基地址的偏移。
寄存器操作 直接地址操作访问 以GPIOB_ODR寄存器为例:
我们找到 GPIOB 端口的输出数据寄存器 ODR 的地址是 0x4001 0C0C(至于这个地址如何找到可以参考–怎么找到某个寄存器的地址?查看数据手册),ODR 寄存器是 32bit,低 16bit 有效,对应着 16 个外部 IO,写 0/1 对应的的 IO 则输出低/高电平。现在我们通过 C 语言指 针的操作方式,让 GPIOB 的 16 个 IO 都输出高电平。
通过绝对地址访问内存单元
// GPIOB 端口全部输出 高电平
?*(unsigned int*)(0x4001 0C0C) = 0xFFFF;
0x4001 0C0C在我们看来是 GPIOB端口 ODR的地址,但是在编译器看来,这只是一个 普通的变量,是一个立即数,要想让编译器也认为是指针,我们得进行强制类型转换,把 它转换成指针,即(unsigned int *)0x4001 0C0C,然后再对这个指针进行 * 操作。 刚刚我们说了,通过绝对地址访问内存单元不好记忆且容易出错,我们可以通过寄存 器的方式来操作。
通过寄存器别名方式访问内存单元
// GPIOB 端口全部输出 高电平
#define GPIOB_ODR (unsigned int*)(GPIOB_BASE+0x0C)
* GPIOB_ODR = 0xFF;
为了方便操作,我们干脆把指针操作“*”也定义到寄存器别名里面.
// GPIOB 端口全部输出 高电平
#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE+0x0C)
GPIOB_ODR = 0xF
5.代码.c语言
#define GPIOB_BASE 0x40010C00
#define GPIOC_BASE 0x40011000
#define GPIOA_BASE 0x40010800
#define RCC_APB2ENR (*(unsigned int *)0x40021018)
#define GPIOB_CRL (*(unsigned int *)0x40010C00)
#define GPIOC_CRH (*(unsigned int *)0x40011004)
#define GPIOA_CRL (*(unsigned int *)0x40010800)
#define GPIOB_ODR (*(unsigned int *)0x40010C0C)
#define GPIOC_ODR (*(unsigned int *)0x4001100C)
#define GPIOA_ODR (*(unsigned int *)0x4001080C)
void SystemInit(void);
void Delay_ms(volatile unsigned int);
void Delay_ms( volatile unsigned int t)
{
unsigned int i;
while(t--)
for (i=0;i<800;i++);
}
int main(){
// 开启时钟
RCC_APB2ENR |= (1<<3); // 开启 GPIOB 时钟
RCC_APB2ENR |= (1<<4); // 开启 GPIOC 时钟
RCC_APB2ENR |= (1<<2); // 开启 GPIOA 时钟
// 设置 GPIO 为推挽输出
// 设置 GPIOB 最后四位为 0001 (B0)
GPIOB_CRL |= (1<<0); // 最后一位设置为1
GPIOB_CRL &= ~(0xE); // 倒数二、三、四位设置为0
// 设置 GPIOC 前四位为 0001 (C15)
GPIOC_CRH |= (1<<28); // 第四位设置为1
GPIOC_CRH &= ~(0xE0000000); // 前三位设置为0
// 设置 GPIOA 最后四位为 0001 (A0)
GPIOA_CRL |= (1<<0); // 最后一位设置为1
GPIOA_CRL &= ~(0xE); // 倒数二、三、四位设置为0
// 3个LED初始化为不亮(即高点位)
GPIOB_ODR |= (1<<0); // 最后一位设置为1
GPIOC_ODR |= (1<<15); // 倒数第15位设置为1
GPIOA_ODR |= (1<<0); // 最后一位设置为1
while(1){
GPIOB_ODR &= ~(1<<0); // 点灯1
Delay_ms(1000000);
GPIOB_ODR |= (1<<0); // 灭灯1
Delay_ms(1000000);
GPIOC_ODR &= ~(1<<15); // 点灯2
Delay_ms(1000000);
GPIOC_ODR |= (1<<15); // 灭灯2
Delay_ms(1000000);
GPIOA_ODR &= ~(1<<0); // 点灯3
Delay_ms(1000000);
GPIOA_ODR |= (1<<0); // 灭灯3
Delay_ms(1000000);
}
}
void SystemInit(){
}
6.连接电路
?7.配置环境
?
?
?
?
- 连上串口之后要把板子上的boot0置1,boot1置0,并且要在烧录之前按下reset键
?
8.flymcu
?
?
四、汇编语言
- 新建项目,与前面一致 ,稍有不同在于不选择Starup,不然会烧录不成功。
RCC_APB2ENR EQU 0x40021018;配置RCC寄存器,时钟,0x40021018为时钟地址
GPIOB_BASE EQU 0x40010C00
GPIOC_BASE EQU 0x40011000
GPIOA_BASE EQU 0x40010800
GPIOB_CRL EQU 0x40010C00
GPIOC_CRH EQU 0x40011004
GPIOA_CRL EQU 0x40010800
GPIOB_ODR EQU 0x40010C0C
GPIOC_ODR EQU 0x4001100C
GPIOA_ODR EQU 0x4001080C
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_C
BL Delay
BL LED_OFF_C
BL Delay
BL LED_ON_A
BL Delay
BL LED_OFF_A
BL Delay
BL LED_ON_B
BL Delay
BL LED_OFF_B
BL Delay
B MainLoop;B:无条件跳转。
LED_Init;LED初始化
PUSH {R0,R1, LR};R0,R1,LR中的值放入堆栈
;控制时钟
LDR R0,=RCC_APB2ENR;LDR是把地址装载到寄存器中(比如R0)。
ORR R0,R0,#0x1c
LDR R1,=RCC_APB2ENR
STR R0,[R1]
;初始化GPIOA_CRL
LDR R0,=GPIOA_CRL
BIC R0,R0,#0x0fffffff;BIC 先把立即数取反,再按位与
LDR R1,=GPIOA_CRL
STR R0,[R1]
LDR R0,=GPIOA_CRL
ORR R0,#0x00000001
LDR R1,=GPIOA_CRL
STR R0,[R1]
;将PA0置1
MOV R0,#0x01
LDR R1,=GPIOA_ORD
STR R0,[R1]
;初始化GPIOB_CRL
LDR R0,=GPIOB_CRL
BIC R0,R0,#0x0fffffff;BIC 先把立即数取反,再按位与
LDR R1,=GPIOB_CRL
STR R0,[R1]
LDR R0,=GPIOB_CRL
ORR R0,#0x00000001
LDR R1,=GPIOB_CRL
STR R0,[R1]
;将PB0置1
MOV R0,#0x01
LDR R1,=GPIOA_ORD
STR R0,[R1]
;初始化GPIOC
LDR R0,=GPIOC_CRH
BIC R0,R0,#0x0fffffff
LDR R1,=GPIOC_CRH
STR R0,[R1]
LDR R0,=GPIOC_CRH
ORR R0,#0x01000000
LDR R1,=GPIOC_CRH
STR R0,[R1]
;将PC15置1
MOV R0,#0x8000
LDR R1,=GPIOC_ORD
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,=GPIOA_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF_A
PUSH {R0,R1, LR}
MOV R0,#0x01
LDR R1,=GPIOA_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_ON_B;亮灯
PUSH {R0,R1, LR}
MOV R0,#0x00
LDR R1,=GPIOB_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF_B;熄灯
PUSH {R0,R1, LR}
MOV R0,#0x01
LDR R1,=GPIOB_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_ON_C;亮灯
PUSH {R0,R1, LR}
MOV R0,#0x00
LDR R1,=GPIOC_ORD
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF_C;熄灯
PUSH {R0,R1, LR}
MOV R0,#0x0100
LDR R1,=GPIOC_ORD
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
五、总结
通过本次实现,第一次接触硬件上的连接,遇到非常多的麻烦,通过不断查阅资料,完成了本实验。
参考;STM32F103 使用寄存器点亮LED(两个LED的闪烁+流水灯)_qq_42468502的博客-CSDN博客
STM32流水灯-寄存器_渣渣馬的博客-CSDN博客
|