一、前言
了解过STM32的GPIO相关的理论知识,这样在应用GPIO开发过程中,能更好的理解GPIO的特点,应用起来会更加的得心应手。
图1 GPIO应用设计
二、API函数
图2 GPIO库函数接口分类
1、关键参数
(1、GPIO_TypeDef* GPIOx
(2、GPIO_InitTypeDef* GPIO_InitStruct
(a、GPIO端口的引脚:可选范围为GPIO_Pin_0~GPIO_Pin_15,也可以选所有引脚GPIO_Pin_All。
(c、GPIO的输出速度频率:当GPIO引脚用于普通功能输出或复用功能输出时,GPIO的输出速度频率,可选的输出速率如下。
速度高的IO耗电大、噪声也大,速度低的IO耗电小、噪声也小。使用合适的速度可以降低功耗和噪声。高频的驱动电路,噪声也高,当不需要高的输出频率时,请选用低频驱动电路,这样非常有利于提高系统的EMI性能,也可以降低功耗。当然如果要输出较高频率的信号,但却选用了较低频率的速度,很可能会得到失真的输出信号。关键是GPIO的引脚速度跟应用匹配。
推挽输出时,可以输出高或者低电平;开漏输出时,如果要输出高电平,则需要在芯片内部配置上拉电阻(弱上拉)或者在芯片IO外部连接上拉电阻。
STM32芯片GPIO的上拉电阻和下拉电阻最小值,典型值和最大值如下:
(3、uint16_t GPIO_PinSource和uint8_t GPIO_AF
GPIO_PinSource:指需配置的复用功能引脚源,可选范围GPIO_PinSource0~GPIO_PinSource15。
2、函数接口
下面就对具体的函数接口进行逐个的介绍。由于使用的是STM32的标准库,GPIO 相关的函数及配置定义和可以调用的接口放置在官方提供的标准库文件 stm32fxx_gpio.c和头文件 stm32fxx_gpio.h 文件中。
(1、void GPIO_DeInit(GPIO_TypeDef* GPIOx;
举例:GPIO_DeInit(GPIOA,将GPIOA端口所有引脚复位到默认状态。
(2、void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct;
举例:将GPIOA的pin1引脚设为普通输出功能,IO驱动速率可达50MHz,推挽模式,带上拉电阻。
(3、void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct;
举例:使用gpio_InitStruct快速获取到了引脚的默认状态值。
(4、void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin;
举例:锁定GPIOA的管脚pin1配置不被修改。
(5、uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin;
举例:读取GPIOA的pin1引脚输入电平值。
(6、uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx;
举例:读取GPIOA端口所有引脚的输入电平值。
(7、uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin;
举例:读取GPIOA的pin1引脚输出电平值。
(8、uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx;
举例:读取GPIOA端口所有引脚的输出电平值。
(9、void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin;
举例:将GPIOA的pin1管脚电平置为1。
也可以用于多个引脚电平的置位。
1 GPIO_SetBits(GPIOA, GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
(10、void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin;
举例:将GPIOA的pin1管脚电平置为0。
也可以用于多个引脚电平的清零。
(11、void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal;
举例:将GPIOA的pin1管脚电平置为1。
也可以用于多个引脚电平操作。
(12、void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal;
举例:将GPIOA端口的所有管脚电平置为1。
(13、void GPIO_ToggleBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin;
举例:翻转GPIOA的pin1管脚电平值。
(14、void GPIO_PinAFConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_PinSource, uint8_t GPIO_AF;
举例:将GPIOA的pin9管脚配置成串口USART1的功能管脚。
三、配置流程
配置流程主要在实际的驱动配置中对GPIO进行初始化的操作,根据实际项目应用开发中的芯片GPIO引脚的定义,进行合理的配置。图3所示为GPIO的基本配置操作流程。
图3 GPIO配置流程
(1、使能对应GPIO的时钟
关于STM32芯片内部整体的时钟系统,可以回顾之前明解STM32时钟系统的文章介绍。STM32的GPIO模块是挂载在芯片内部AHB1总线(AHB:高级高性能总线)上的外设,因此就需要打开GPIO在AHB1总线上对应的时钟。AHB1总线上的外设时钟开关在STM32提供的标准库函数中通过函数 RCC_AHB1PeriphClockCmd (来实现的。例如调用:
这样就将GPIOA的时钟打开,也可以同时打开多个GPIO端口的时钟:
(2、引脚功能配置
用于普通IO输出时:
需要注意的是,初始化输出电平时,需要先调用写引脚电平接口,再做初始化操作,这是因为GPIO_WriteBit是将输出的值写入寄存器输出置位/复位寄存器BSRR,BSRR寄存器复位值是0,GPIO_Init相当于将GPIO引脚初始化完打开输出开关。如果需要输出的是高电平,GPIO_WriteBit在前,GPIO_Init在后相当于在没打开开关之前就将1在BSRR中放置好,GPIO_Init将开关一打开就可以输出高电平;如果GPIO_Init在前,GPIO_WriteBit在后,GPIO_Init完会将BSRR中的0先输出,过了一个函数指令周期后调用GPIO_WriteBit才输出高电平,因此若驱动时序对函数指令周期敏感的外围器件时,可能带来驱动时序问题!
用于普通IO输入时:
用于复用功能时:
用于模拟管脚时:
当STM32需要进行 AD( 模数 转换采样时,需要把引脚设置为模拟输入模式,模拟输入模式下,不需要连接上拉和下拉电阻,因为GPIO用于模拟功能时,引脚的上、下拉电阻是不起作用的。这个时候即使在配置了上拉或下拉电阻,也不会影响到模拟信号的输入。
(3、对GPIO引脚进行操作
用于普通IO输出时:
也可以调用相关GPIO读接口对输出类型的GPIO进行读取引脚电平的操作GPIO_ReadOutputDataBit。
用于普通IO输入时:
用于复用功能时:
用于模拟管脚时:
四、使用技巧
在日常程序开发调试的过程中,可以简单有效的利用GPIO驱动输出高低电平来进行辅助的测试及验证工作。下面介绍几个较为常用的使用场景,如果有其它可以利用GPIO的方法和技巧,也请大家积极留言,我们一起探讨。
(3、在不同的程序段中使用多个IO,输出高电平,通过示波器测量IO口之间输出高电平的间隔,可以确定两个程序段之间运行的准确时间。
(4、在板卡上没有LED进行闪烁指示的情况或没有使用外部看门狗芯片的情况下,为了确认程序是否仍然在正常运行,需要留出一个IO口,用于翻转高低电平输出,后续就可以用示波器测量该信号的有无来判断程序是否死机。
(6、在测试验证阶段,可以将某个IO引脚配置成输入模式,利用外部给的激励信号,在程序中判断读到的信号电平的高低状态,去作为逻辑判断条件进行一些代码段的验证测试。
五、总结
更多技术内容和书籍资料获取,入群技术交流敬请关注“明解嵌入式”