
STM32学习笔记05—GPIO输入输出实验 / d( i, Y7 N$ c. r, ?! k8 |4 a- D) q 5.1 STM32单片机GPIO概述 STM32中每个IO口都有很多个作用,比如这次我们使用的STM32F103ZET6的PA0口,既可以作为IO口使用,还可以作为待机唤醒(WAKEUP),模拟输入(ADC功能)等。根据数据手册中列出的每个I/O端口的特定硬件特征,GPIO端口的每个位可以由软件分别配置成多种模式。: y- [( C. B5 [( V8 U, c" i3 U 4 B: `8 N6 | U7 n. t3 z 3 M3 _: F+ \) a( w4 s9 F (1)输入浮空 (2)输入上拉: f R2 O8 G0 D( ^0 t (3)输入下拉1 e" a- |/ H) x2 P& f/ T (4)模拟输入 (5)开漏输出2 M. t8 K$ M& p _ (6)推挽式输出 (7)推挽式复用功能 (8)开漏复用功能 2 S4 y3 A7 U w7 f4 p m% \ ' ^+ r; ~5 k6 Q! [6 t 每个I/O端口位可以自由编程,然而I/O端口寄存器必须按32位字被访问(不允许半字或字节访问)。GPIOx_BSRR和GPIOx_BRR寄存器允许对任何GPIO寄存器的读/更改的独立访问;这样,在读和更改访问之间产生IRQ时不会产生异常错误。; _# j9 G( M/ l8 q! V2 @ # ~# k$ U* J7 W% z0 X% B% K STM32F103系列的基本IO口结构如下图所示2 [" t" ?" t9 H( x ![]() 1 z$ t# ]7 `" C8 @ / W* v; L# ^) o 从结构图可以看出来,STM32的GPIO口可以配置好几个选项,内部上拉下拉电阻的选择,推挽输出或者开漏输出,对于复用功能,有专门的复用输入支路和输出支路。STM32F103的端口由10个寄存器控制,但是常用的并不多,时钟控制寄存器APB2ENR,模式控制寄存器CRH和CRL,输入寄存器IDR,输出寄存器ODR。 5.2 相关寄存器 5.2.1 APB2 外设时钟使能寄存器:RCC_APB2ENR0 ?+ o n/ c7 ?2 j ![]() Bit 14:串口1时钟使能(写1开启,写0关闭)/ ]# k- S" @5 b9 s- V' i$ K Bit 12:SPI1时钟使能(写1开启,写0关闭)3 K; j6 ^/ Y. ]" C$ ] Bit 11:定时器1时钟使能(写1开启,写0关闭)4 L( k C$ Z) q0 @/ r/ ~, h6 r Bit 10:ADC2时钟使能(写1开启,写0关闭) Bit 9:ADC1时钟使能(写1开启,写0关闭)+ D- H ^" f' E4 S) |2 m( s Bit 6:GPIOE时钟使能(写1开启,写0关闭) Bit 5:GPIOD时钟使能(写1开启,写0关闭)! ?: l9 B! H E7 I5 B# a Bit 4:GPIOC时钟使能(写1开启,写0关闭) Bit 3:GPIOB时钟使能(写1开启,写0关闭) Bit 2:GPIOA时钟使能(写1开启,写0关闭)5 g7 J9 n$ H9 a; E. K5 S Bit 0:辅助时钟IO时钟使能(写1开启,写0关闭) : L' \* `4 Y. W7 w4 }: M8 { G 5.2.2 端口配置低寄存器:GPIOx_CRL(x=A..E) ![]() 端口配置表:0 E- ^2 O5 R3 A9 i6 {% n ![]() 5.2.3 端口配置高寄存器:GPIOx_CRH(x=A..E) ![]() 配置方式和端口配置低寄存器一致。! p0 M3 e7 }( @! J * H4 L2 j; }: a) T 5.2.4 端口输入数据寄存器:GPIOx_IDR(x=A..E) ![]() Bit 15~Bit 0:端口输入数据(这些位属于只读并只能以字的形式读出) " R6 j2 t* ?2 v, m% ]4 W 5.2.5 端口输出数据寄存器:GPIOx_ODR(x=A..E)* w: }( t$ Q2 h8 W& _ ![]() Bit 15~Bit 0:端口输出数据(这些位属于只读并只能以字的形式操作) 注:在输入模式下,ODR的数据可以控制端口内部是上拉还是下拉,写入1意味着端口上拉输入。9 O# [; w2 m; m# d& B 8 Z" D2 b* M% Q- L ; h8 L9 C6 T( v0 K( l 5.3 GPIO的输入与输出例程 我们现在在PA0端口接一个按键,PA端口接一个LED,当按下按键的时候,LED以100ms亮,100ms灭,抬起按键后LED常亮。1 t- T1 j( i2 N, I/ Q ( t2 J& e, N- d/ \) x (1)在stm32f103x.h文件中添加GPIO的结构体和地址映射。 ![]() (2)在HEADERWARE目录下创建GPIO文件夹,并创建gpio.c和gpio.h两个文件1 l0 E }" O$ I* [+ n$ S ![]() (3)在gpio.h文件中输入以下内容:" T# P8 K8 v! V( _ r B ![]() (4)在gpio.c文件中输入以下内容 ![]() (5)将gpio.c文件和gpio.h文件添加进项目 ![]() (6)在1.c文件中输入以下内容: ![]() 注:实验中,按键一端接GND,LED一端接VCC,所以按键是检测到0代表按下,端口输出低电平代表LED点亮。 ! \2 e; _7 ?8 E7 T 5.4 CM3内核的位带操作1 B6 b) n& |8 Z) B) K2 X$ w" c Cortex-M3内核中有一个非常有用的功能,叫做位带操作,支持了位带操作以后,可以使用普通的加载/存储指令来对单一的比特进行读写。在CM3中,有两个区中实现了位带。其中一个是SRAM区的最低1MB范围,第二个则是片内外设区的最低1MB范围。这两个区中的地址除了可以像普通的RAM一样使用外,它们还都有自己的“位带别名区”,位带别名区把每个比特膨胀成一个32位的字。当你通过位带别名区访问这些字时,就可以达到访问原始比特的目的。下图从另一个侧面演示比特的膨胀对应关系。 ![]() 欲设置地址0x20000000中的比特2,则使用位带操作的设置过程如下图所示。 ![]() 30年前其实就已经有位带操作的概念了,自8051单片机开始,到现在的CM3内核,位带操作有什么优越性呢?最容易想到的就是通过GPIO的管脚来单独控制每盏LED的点亮与熄灭。另一方面,也对操作串行接口器件提供了很大的方便(典型如74HC165,CD4094)。位带操作使代码更简洁,这只是位带操作优越性的初等体现,位带操作还有一个重要的好处是在务中,用于实现共享资源在任务间的“互锁”访问。多任务的共享资源必须满足一次只有一个任务访问它——亦即所谓的“原子操作”。, A/ j2 N* S0 g" Q1 q; Z j W4 t! g4 h2 T$ \) H ' I9 r9 A& `% W& ~ 5.5 利用位带操作实现GPIO的输入与输出 现在利用位带操作来实现上一题目中的功能。 9 o7 ]+ T) g9 s5 L% I. i& D (1)在sys.h文件中添加实现位带操作的代码。 ![]() (2)修改gpio.h中的代码如下图所示。; C: Y3 S* [; B. } ![]() (3)修改gpio.c中的代码如下图所示。 l) O2 }( |8 ~: G4 H' | ![]() (4)修改1.c中的代码如下图所示。 ![]() 5.6 外部中断的实现 关于STM32F103的中断机制在之前已经详细讲述过,现在利用外部中断来实现上一题目的功能。 " w! B: b: K6 T! J (1)修改gpio.c中的代码如下图所示。 ![]() (2)添加代码到文件stm32f103.h中。' Y1 l4 W. E0 G) L2 {0 _ ![]() (3)修改1.c中的代码如下图所示。 ![]() 上一篇:1 y* Q6 J$ X# T" I STM32学习笔记04—SysTick时钟 |