一、学习STM32芯片
1、存储器映射
存储器本身不具有地址信息,它的地址是由芯片厂商或用户分配,给存储器分配地址 的过程就称为存储器映射
下图为STM32F10xxx中内置外设的起始地址。
2、以GPIOx为例讲解相关寄存器
将已经分配好地址的有特定功能的内存单元取别名的过程就叫寄存器映射。
(1)、找到GPIOx的地址,通过上图可看到GPIOA的地址为0x40010800
(2)GPIO端口低寄存器 这是存储数据的地址。方法为端口起始地址+偏移地址。所以GPIOA_CRL的储存数据的位置为0x40010800+0x00=0x40010800。 每个寄存器含有32位,每4位用来设置1个GPIO引脚功能。GPIOx_CRL/GPIOx_CRH 两个寄存器共含有64位,因此可完成对GPIO015的设定。其中GPIOx_CRL用于设置GPIO07引脚,GPIOx_CRH用于设置GPIO8~15引脚。
(3)GPIO端口配置高寄存器 推挽输出:可以输出高,低电平,连接数字器件;推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止。 开漏输出:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行,适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
GPIOA_CRH=0xFFFFFFF0;
GPIO_CRH|=0x00000003;
十六进制中的3换成二进制00 11 前两位00表示推挽输出,后两位11表示输出频率50Mhz。 (4)GPIO端口输入数据寄存器
uint16_t temp;
temp = GPIOB->IDR;
(5)GPIO端口输出数据寄存器 该地址偏移为:0x0C。 低16位有效,每一个位对应一个IO,控制引脚输出状态。ODR寄存器可读可写:既能控制管脚为高电平,也能控制管脚为低电平。 (6)GPIO端口位设置/清除寄存器 BSRR 只写寄存器:[color=Red]既能控制管脚为高电平,也能控制管脚为低电平。对寄存器高 16bit 写1 对应管脚为低电平,对寄存器低16bit写1对应管脚为高电平。写 0 ,无动作。 (7)开启外设时钟
开启 GPIOB 端口 时钟
RCC_APB2ENR |= (1<<3);
由于 STM32的 外设很多,为了降低功耗,每个外设都对应着一个时钟,在芯片刚 上电的时候这些时钟都是被关闭的,如果想要外设工作,必须把相应的时钟打开。 (8)GPIO端口初始化 以GPIOB为例。
GPIOB_CRL &= ~( 0x0F<< (4*4));
GPIOB_CRL |= (1<<4*4);
GPIOB_ODR |= (0<<4);
二、寄存器实现LED灯点亮
1、代码编写
(1)C语言
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018)
#define GPIOB_CRL *((unsigned volatile int*)0x40010C00)
#define GPIOB_ODR *((unsigned volatile int*)0x40010C0C)
#define GPIOA_CRL *((unsigned volatile int*)0x40010800)
#define GPIOA_ODR *((unsigned volatile int*)0x4001080C)
#define GPIOC_CRH *((unsigned volatile int*)0x40011004)
#define GPIOC_ODR *((unsigned volatile int*)0x4001100C)
void delay( )
{
unsigned long x;
for(x=0;x<5000000;x++);
}
int main()
{
RCC_APB2ENR|=1<<4;
RCC_APB2ENR|=1<<3;
RCC_APB2ENR|=1<<2;
GPIOB_CRL&=0xFFFF0FFF;
GPIOB_CRL|=0x02000000;
GPIOB_ODR|=1<<6;
GPIOA_CRL&=0xFF0FFFFF;
GPIOA_CRL|=0x00200000;
GPIOA_ODR|=1<<5;
GPIOC_CRH&=0xF0FFFFFF;
GPIOC_CRH|=0x02000000;
GPIOC_ODR|=1<<14;
while(1)
{
GPIOC_ODR|=1<<14;
delay();
GPIOC_ODR&=~(1<<14);
delay();
GPIOB_ODR|=1<<6;
delay();
GPIOB_ODR&=~(1<<6);
delay();
GPIOA_ODR|=1<<5;
delay();
GPIOA_ODR&=~(1<<5);
delay();
}
unsigned int *pRCC_APB2ENR = (unsigned int *)0x40021018;
在编译器看来0x40021018只是一个普通的变量,是一个立即数,要想让编译器也认为是指针,我们的强行类型转换,把它转成指针,即(unsigned int *)0x40021018;,然后再对这个指针进行 *操作。 1、按位操作 上述C语言中有许多按位操作,按位操作的作用是可以优化代码,让代码简单易懂。
X=10100000的低4位置1 ,用 X | 0000 1111 = 1010 1111即可得到。 PBn就改为GPIOB->CRL |= 0x2<<(n*4);第n个引脚输出0。 <<左移运算符,RCC -> AHB1ENR |= 1<<2;1<<2 应该读作1向左移动2位,即AHB1ENR寄存器的第2位置1。 设X=10101110, 取X的低4位,用 X & 0000 1111 = 0000 1110 即可得到;所以GPIOB_ODR&=~(1<<6);先左移为1000000再取反为0111111再进行&为0111111再赋值给GPIOB_ODR为低电平。
(2)汇编语言
AREA MYDATA, DATA
AREA MYCODE, CODE
ENTRY
EXPORT led
led
;使能A,B,C
ldr r0, =0x40021018
ldr r1, =0x0000001c
str r1, [r0]
;配置端口A4
ldr r0, =0x40010800
ldr r1, [r0]
bic r1, r1, #0x000f0000
orr r1, r1, #0x00010000
str r1, [r0]
;配置端口B5
ldr r0, =0x40010c00
ldr r1, [r0]
bic r1, r1, #0x00f00000
orr r1, r1, #0x00100000
str r1, [r0]
;配置端口C14
ldr r0, =0x40011004
ldr r1, [r0]
bic r1, r1, #0x0f000000
orr r1, r1, #0x01000000
str r1, [r0]
;初始为A4亮灯
ldr r0, =0x4001080c
ldr r1, =0x00000010
str r1, [r0]
ldr r0, =5000000;频率
ldr r1, =0
;循环亮灯
blink
add r1, r1, #1
cmp r1, r0
blt blink
;A4灭
ldr r1, =0x4001080c
ldr r2, [r1]
eor r2, r2, #0x00000010
str r2, [r1]
;B5亮
ldr r1, =0x40010c0c
ldr r2, [r1]
eor r2, r2, #0x00000020
str r2, [r1]
ldr r1, =0
blink1
add r1, r1, #1
cmp r1, r0
blt blink1
;B5灭
ldr r1, =0x40010c0c
ldr r2, [r1]
eor r2, r2, #0x00000020
str r2, [r1]
;C14亮
ldr r1, =0x4001100c
ldr r2, [r1]
eor r2, r2, #0x00004000
str r2, [r1]
ldr r1, =0
blink2
add r1, r1, #1
cmp r1, r0
blt blink2
;C14灭
ldr r1, =0x4001100c
ldr r2, [r1]
eor r2, r2, #0x00004000
str r2, [r1]
;A4亮
ldr r1, =0x4001080c
ldr r2, [r1]
eor r2, r2, #0x00000010
str r2, [r1]
ldr r1, =0
b blink
END
2、STM32接线
根据程序中的GPIO的输出接口进行接线,GPIOA_ODR|=1<<5 接A5口,GPIOB_ODR|=1<<6; 接B6口,GPIOC_ODR|=1<<14 ; 接C14口。TXD接A10口,RXD接A9口,电源接3.3v。接线过程中记得查看流水灯是否接地,并检查连接是否有遗漏。连接图如下:
3、实验结果
1、生成.hex文件,使用软件烧录程序 此步骤可参考我上篇文章:STM32串口下载程序。 在此步骤可能会出现一些问题,在烧录时一直连接不到芯片,是因为接线问题不稳定,连接不上。所以最好采用公母接头的线进行接线,在烧录过程一定要检查连线是否有问题,它可能导致后续观察不到实验结果。 2、实验视频 (1)仿真器 (2)流水灯视频
三、实验总结
通过本次实验,我明白了stm32的点灯过程是通过使能外设GPIO时钟,发出指令给外设GPIO,外设GPIO收到指令后,着手配置自己的寄存器,然后给IO口模式。对于寄存器操作,在上学期的单片机原理中学过但是已经全部忘记了,寄存器数据储存操作对于我这个新手来说有点困难,我学习了很久查了很多资料,从最开始的GPIO端口的学习再到后面编写代码时的优化问题。该实验我还进行了一次仿真在连接的硬件。keil的仿真过程也是文明需要学习的,只有仿真没有错误硬件的显示才会没有错误。实验途中遇到了很多问题,在老师和同学的帮助下都一一解决了,对于STM32的流水灯实验是我们了解STM32的开始,随着我们实验难度的加深,对STM32芯片的使用也更加熟悉。
四、参考文献
【1】STM32中文参考手册 【2】寄存器讲解 【3】零死角玩转STM32-F103指南者
|