STM32IO口的八种工作模式:
1)、GPIO_Mode_IN_FLOATING:浮空输入
2)、GPIO_Mode_AIN:模拟输入
3)、GPIO_Mode_IPD:下拉输入
4)、GPIO_Mode_IPU:上拉输入
5)、GPIO_Mode_Out_OD:开漏输出
6)、GPIO_Mode_Out_PP:推挽输出
7)、GPIO_Mode_AF_OD:复用开漏输出
8)、GPIO_Mode_AF_PP:复用推挽输出
在芯片手册上有每个IO口支持的功能,我们想要知道一个IO都有啥功能时,就芯片手册而言可能手头没有或者懒得去翻。这时STM32CubeMX的便利性就突出来了!下图比如我们想知道PF6这个IO口支持哪些功能,只需要在这个引脚上单击左键,软件就会将该IO目前所支持的功能弹出!
上图为M4的IO口基本结构
1、GPIO输入
STM32的输入相对于输出来说要简单,从字面意思能很容易理解。
IO配置为浮空输入,IO输入的电平会直接到施密特触发器(百度对于施密特触发器的解释)IO口浮空状态时IO处于高阻态,电平状态完全由外部输入电平决定。
IO配置为上拉输入或者下拉输入,
上拉输入IO口会把这个上拉电路(1)接入,在外部无电平输入时,IO口状态为高。
下拉输入IO口会把这个下拉电路(2)接入,在外部无电平输入时,IO口状态为低。,
IO配置为模拟输入,
为模拟输入时,IO口输入的不在是数字量而是模拟量,IO口会关闭施密特触发器,将模拟量送到片上的外设AD去采集,
这四种输入模式我们在什么情况下使用的:
数字电路有三种状态:高电平、低电平、高组态,当不希望出现高阻态时,可以通过上拉电阻或者下拉电阻的方式将不确定的信号通过一个电阻钳位在高电平或者低电平。
简单的说当外围设备自己没有驱动能力时上拉和下拉电阻必不可少,就按键来说按键自己本身无法输出高低电平这时就需要上拉或者下拉电阻,
原子的探索者开发板字上有四个按键,根据原理图可以看出需要检测这四个按键状态,WK_UP需要设置为下拉,其他三个为上拉。理论上来说当外围设备具有驱动能力时,不需要上拉或者下拉浮空就可以。但还是要具体问题具体分析。比如我在原子的论坛里看到一位老哥讲的,在按键和IIC上他从来不用IO的电阻,自己外接电阻。因为他觉得芯片内部集成的电阻,阻值都比较大(几十K),提供的“拉力”不强且难说稳定。那这时他的IO口肯定设置的是浮空状态。(原子论坛里关于这几种方式的讨论)模拟输入这个简单的来说就是我们用ADC功能检测电压这样的模拟量时使用的,会通过模拟通道将模拟量直接送给AD采集。
在STM32CubeMX中
要使用浮空输入或者上拉\下拉时左键单击,在弹出的菜单中选择GPIO_Input,然后在左侧的GPIO选项中单击该IO口,在GPIO Pull-up/Pull-down中选择浮空还是下拉或者上拉。Pull-up为上拉输入模式、Pull-down为下拉输入模式、No Pull-up and No Pull-down 为浮空输入。如下图
要是使用模拟输入时单击左键在弹出的菜单中选择GPIO_Analog,如下图
1、GPIO输出
大体的来看有两种模式:开漏输出和推完输出。
上图有两个MOS
当设置为开漏输出时P-MOS是始终截止的,当输出控制输出0时,N-MOS被导通,这样就会将IO口电平拉低,这时IO的输出状态就是低;当输出控制输出为1时,N-MOS截止,这时候IO的输出状态需要上拉或者下拉电阻来实现,比如开漏输出模式需要输出高电平,那就需要上拉电阻。
当设置为推完输出时,当输出控制输出为0时P-MOS截止,N-MOS导通IO电平被拉低,也就是输出0;当输出控制输出为1时,P-MOS导通,N-MOS截止IO口电平被拉高,也就是输出1。
复用开漏输出和开漏输出原理一样,区别在于输出控制源不同,前者是通过外设后者是通过CPU写寄存器。
复用推挽输出和推挽输出原理一样,区别在于输出控制源不同,前者是通过外设后者是通过CPU写寄存器。
推挽和开漏的使用:
推挽输出:可以输出高,低电平,连接数字器件;
开漏输出:输出端相当于三极管的集电极. 要得到高电平状态需要上拉电阻才行. 适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内).
那种80c51单片机的IO口就是开漏输出,所以在使用51单片机时需要加上拉电阻,
(其他博友对于推挽电路和开漏电路的讲解)具体的选用大家可以在网上详细的查一下两种电路的优缺点,在结合自己实际电路来选择
在STM32CubeMX中
需要用到开漏输出或者推挽输出,左键单击,在弹出的菜单中选择GPIO_Output,然后在左侧的GPIO选项中单击该IO口,在GPIO mode选项中选择模式,Output Push Pull为推挽输出,Out Open Drain为开漏输出。
在当IO口设置为输出时,主要的设置参数有四个,
第一个IO输出的初始状态,Low表示输出0,High表示输出1.
第二个IO的输出模式上面阐述过。
第三个IO是否上拉或下拉上面阐述过。
第四个IO的输出速度,就M4而言有4中最大速度:2MHz、25MHz、50MHz、100MHz。
在选择中有Low、Medium、High、Very High
void MX_GPIO_Init(void)
{
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOF, LED1_Pin|LED2_Pin, GPIO_PIN_RESET);
/*Configure GPIO pins : PFPin PFPin */
GPIO_InitStruct.Pin = LED1_Pin|LED2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOF, &GPIO_InitStruct);
}
/** @defgroup GPIO_speed_define GPIO speed define * @brief GPIO Output Maximum frequency * @{ */
#define GPIO_SPEED_FREQ_LOW 0x00000000U /*!< IO works at 2 MHz, please refer to the product datasheet */
#define GPIO_SPEED_FREQ_MEDIUM 0x00000001U /*!< range 12,5 MHz to 50 MHz, please refer to the product datasheet */
#define GPIO_SPEED_FREQ_HIGH 0x00000002U /*!< range 25 MHz to 100 MHz, please refer to the product datasheet */
#define GPIO_SPEED_FREQ_VERY_HIGH 0x00000003U /*!< range 50 MHz to 200 MHz, please refer to the product datasheet */
通过追溯,可以看到在代码里做了宏定义,
我们对A0、F9、F10三个引脚做了如下配置
生成的IO配置如下
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOF_CLK_ENABLE();
__HAL_RCC_GPIOH_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOF, LED1_Pin|LED2_Pin, GPIO_PIN_SET);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = LED1_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(LED1_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = LED2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(LED2_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = WK_UP_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLDOWN;
HAL_GPIO_Init(WK_UP_GPIO_Port, &GPIO_InitStruct);
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin))//读取Io当前状态,如果为1进入
{
HAL_Delay(100);//延时消抖
if(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin))//再次读取IO当前状态如果为1进入
{
HAL_GPIO_WritePin(LED1_GPIO_Port,LED1_Pin,0);//IO口输出0
HAL_GPIO_WritePin(LED2_GPIO_Port,LED2_Pin,0); //IO输出0
}
}
while(HAL_GPIO_ReadPin(WK_UP_GPIO_Port,WK_UP_Pin));//等待按键松开
}
我们通过按按键来点亮LED,这里的按键防抖和按键松开检测的处理方式很不好,占用资源尤其while,用不好容易卡死在这里,这里只是简单用用,后期我们会用状态机来做。
本文地址:https://blog.csdn.net/qq_23127707/article/details/107945693