STM32 GPIO学习笔记:江协科技视角下的技术解析

目录

1、工程结构

2、系统结构

3、GPIO位结构

4、GPIO模式

5、ELD和蜂鸣器

6、标准库中常见的GPIO函数及其用法


1、工程结构

2、系统结构

在STM32中,所有的GPIO都是挂载在APB2外设总线上的。

APB1(Advanced Peripheral Bus 1)和APB2,它们是AHB(Advanced High-performance Bus)的从属总线。两个AHB/APB桥在AHB和2个APB总线间提供同步连接。APB1操作速度限于36MHz,APB2操作于全速(最高72MHz)。

注意: 当对
APB
寄存器进行
8
位或者
16
位访问时,该访问会被自动转换成
32
位的访问:桥会自动将
8

或者
32
位的数据扩展以配合
32
位的向量

3、GPIO位结构

(1)施密特触发器:对输入电压进行整形。其执行逻辑为:如果输入电压大于某一阈值,输出就会瞬间升为高电平

(2)模拟输入:这个是连接到ADC(片上外设)上的,因为ADC需要接收模拟量,所以接到施密特触发器前面。

(3)复用功能输入:这个是连接到其他需要读取端口的外设上的,比如串口的输入引脚等,这根线接收的是数字量,所以接到施密特触发器后面。

(4)输出数据寄存器(ODR):写其的某一位就可以操作对应的某个端口。

(5)位设置/清除寄存器:可用来单独操作输出数据寄存器的某一位,而不是影响其他位。因为输出数据寄存器同时控制16个端口,并且这个寄存器只能整体读写,所以想单独控制其中某一个端口而不影响其他端口的话,就需要一些特殊的方式:

  • 先读出这个寄存器,然后用按位与和按位或的方式更改某一位(&=  |=),最后再将更改后的数据写回去。但这种方法效率不高且麻烦,对IO口的操作而言不太合适

  • 通过设置这个位设置/清除寄存器,如果我们要对某一位置1,在位设置寄存器的对应位写1即可,剩下不需要操作的位写0,这样它内部就会有电路自动将位设置寄存器中对应位置1,而剩下写0的位保持不变。保证了只操作其中某一位而不影响其它位,并且这是一步到位的操作。如果想对某一位进行清0的操作,就在位清除寄存器的对应位写1即可,内部电路会把这一位清0.

  • 读写STM32中的“位带”区域,这个位带的作用跟51单片机的位寻址作用差不多。在STM32中,专门分配有一段地址区域,这段地址映射了RAM和外设寄存器所有的位,读取这段地址中的数据,就相当于读写所映射位置的某一位,这就是位带的操作方式。

  • 输出模式

    控制开关

    工作方式

    特点

    推挽输出

    P-MOS、N-MOS均有效

    数据寄存器为1时,上管导通,下管断开,输出直接接到VDD,即高电平;反之则是低电平

    这种模式下,高低电平均有较强的驱动能力,所以推挽输出模式也可以叫强推输出模式(STM32对IO口具有绝对的控制权,高低电平都由STM32说了算)

    开漏输出

    P-MOS无效、N-MOS均有效

    数据寄存器为1时,下管断开,下管断开,输出相当于断开,即高阻模式。数据寄存器为0时,下管导通,输出直接接到VSS,即输出低电平。这种模式下,只有低电平有驱动能力,高电平没有驱动能力。

    这个开漏模式可以作为通信协议的驱动方式,比如I2C通信的引脚,就是使用的开漏模式。在多机通信的情况下,这个模式可以避免各个设备的相互干扰。另外开漏模式还可以用于输出5V的电平信号。

    关闭

    P-MOS、N-MOS均有效

    当引脚配置为输入模式的时候,输出关闭,端口的电平由外部信号来控制

    4、GPIO模式

    (1)1、2、3模式的电路结构基本一样,区别就是上拉电阻和下拉电阻的连接。

    (浮空输入下,端口一定要接上一个连续的驱动源,不能出现悬空的状态)

    (2)

    (3)

    (4)

    GPIO_Mode_AIN

    Analog In–模拟输入

    GPIO_Mode_IN_FLOATING

    Floating–浮空输入

    GPIO_Mode_IPD

    In Pull Down–下拉输入

    GPIO_Mode_IPU

    In Pull Up–上拉输入

    GPIO_Mode_OUT_OD

    Out Open Drain–开漏输出

    GPIO_Mode_OUT_PP

    Out Push Pull–推挽输出(点灯 )

    GPIO_Mode_AF_OD

    Atl Open Drain–复用开漏

    GPIO_Mode_AF_PP

    Atl Push Pull–复用推挽

    5、ELD和蜂鸣器

    LED:长正短负,小正大负。

    以上图为例,将P1^2引脚接低电平,蜂鸣器响,接高电平,蜂鸣器关闭(低电平触发)。

    (1)低电平驱动LED:当PA0输出低电平时,LED两端就会产生电压差,从而形成正向导通的电流,LED点亮。 

    该GPIO在推挽输出模式下,高低电平均有比较强的驱动能力,故两种接法均可。但在单片机的电路里,一般使用低电平驱动,因为很多单片机或者芯片都使用了“高电平弱驱动,低电平强驱动”的规则。

    (2)蜂鸣器电路使用了三极管开关的驱动方案(最简单的驱动电路)(对于功率稍微大一点的电路,直接用IO口驱动会导致STM32负担过重)。三极管左边的是基极,带箭头的是发射极,剩下的是集电极。

    PNP三极管:基极给低电平三极管导通, 蜂鸣器有电流,反之没有。

    NPN三极管:相反。

    (PNP的三极管接在蜂鸣器上面,而NPN的三极管接在蜂鸣器下面,因为三极管的通断需要在发射极和基极直接产生一定的开启电压,若反过来可能导致三极管不能开启)

    (3)在PA0口输出高低电平,驱动LED闪烁

    (注意因为配置的是GPIO,所以要使用APB2外设总线)

    #include "stm32f10x.h"                  					// Device header
    #include "Delay.h"
    
    int main(void)
    {
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);   // RCC的APB2外设时钟控制函数(PA0-GPIOA,使能)
    	
    	GPIO_InitTypeDef GPIO_InitStructure;	
    	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;		//推挽输出
    	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;				//选择0号端口
    	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//IO口速度为50MHz
    	GPIO_Init(GPIOA, &GPIO_InitStructure);					// GPIO初始化(GPOIX, )第二个参数是一个结构体,需要先把结构体类型复制下来,再在前面定义
    	
    //	GPIO_ResetBits(GPIOA, GPIO_Pin_0);						// 设置指定端口为低电平
    //	GPIO_SetBits(GPIOA, GPIO_Pin_0);						// 设置指定端口为高电平
    //	GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);			// 设置指定端口为高电平
    //	GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);				// 设置指定端口为低电平
    //	GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);			// 将0强制转换为BitAction的枚举类型,低电平
    //	GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);			// 将1强制转换为BitAction的枚举类型,高电平
    	
    	while(1)
    	{
    		GPIO_ResetBits(GPIOA, GPIO_Pin_0);
    		Delay_ms(500);
    		GPIO_SetBits(GPIOA, GPIO_Pin_0);
    		Delay_ms(500);
    		
    		//直接法
    		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET);
    		Delay_ms(500);
    		GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET);
    		Delay_ms(500);
    		
    		//枚举法
    		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);
    		Delay_ms(500);
    		GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
    		Delay_ms(500);
    	}
    }
    

    6、标准库中常见的GPIO函数及其用法

    uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

    读取输入数据寄存器某引脚的输入值

    uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);

    读取输入数据寄存器全部的输入值

    uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

    读取输出数据寄存器某引脚的输入值

    uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);

    读取输入数据寄存器全部的输入值

    void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

    设置指定端口为低电平

    void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);

    设置指定端口为高电平

    void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);

    一般可以实现批量或者同时控制多个 GPIO 引脚的输出状态

    void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);

    用来单独设置某一个特定的 GPIO 引脚的输出状态

    作者:YE_lou

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32 GPIO学习笔记:江协科技视角下的技术解析

    发表回复