转发自wuyujun的CSDN博客,关于GPIO的八种模式的解读和中断的应用

一、GPIO 8种工作模式

输入模式:

1. GPIO_Mode_AIN 模拟输入

2. GPIO_Mode_IN_FLOATING 浮空输入

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 复用推挽输出

施密特触发器:当输入电压高于正向阈值电压,输出为高;当输入电压低于负向阈值电压,输出为低;当输入在正负向阈值电压之间,输出不改变,只有当输入电压发生足够的变化时,输出才会变化

GPIO_Mode_IN_FLOATING 浮空输入

外部通过IO口输入电平,传输到施密特触发器(此时施密特触发器为打开状态),直接进入输入数据寄存器,CPU通过读输入数据寄存器实现读取外部输入电平值,在输入浮空模式下可以读取外部输入电平。如果在该引脚悬空(在无信号输入)的情况下,读取该端口的电平是不确定的。

GPIO_Mode_IPU 上拉输入

上拉电阻的开关闭合,上拉电阻连接到VDD,在I/O端口悬空(在无信号输入)的情况下,外部输入通过上拉电阻,施密特触发器存入输入数据寄存器,被CPU读取出高电平,当I/O端口输入为低电平的时候,施密特触发器触发存入输入数据寄存器,CPU读取出低电平;

GPIO_Mode_IPD 下拉输入

 

下拉电阻的开关闭合,在I/O端口悬空(在无信号输入)的情况下,下拉电阻连接到VSS,外部输入通过下拉电阻,施密特触发器存入输入数据寄存器,被CPU读取出低电平,当I/O端口输入为高电平的时候,下拉电阻处的电压为高电平,施密特触发器触发存入数据寄存器,CPU读取出高电平

GPIO_Mode_AIN 模拟输入

 模拟输入通道的配置则更加简单,信号从左边编号1的端口进入,从右边编号2的一端直接模拟输入至片上外设模块。上拉、下拉电阻和施密特触发器,均处于断开状态,IO口外部电压为模拟量,电压形式为非电平形式。

GPIO_Mode_Out_OD 开漏输出

开漏输出模式下,通过设置 位设置/清除寄存器或者输出数据寄存器的值,途经N-MOS管,最终输出到I/O端口。这里要注意N-MOS管,当设置输出的值为高电平的时候,N-MOS管处于截止状态,此时I/O端口的电平就不会由输出的高低电平决定,而是由I/O端口外部的上拉或者下拉决定;当设置输出的值为低电平的时候,N-MOS管处于导通状态,此时I/O端口的电平就是低电平。同时,I/O端口的电平也可以通过输入电路进行读取;注意,I/O端口的电平不一定是输出的电平。

GPIO_Mode_Out_PP 推挽输出

推挽电路(push-pull)就是两个不同极性晶体管间连接的输出电路。推挽电路采用两个参数相同的MOSFET管,电路工作时,两只对称的功率开关管每次只有一个导通,所以导通损耗小效率高。当设置输出的值为为高电平时,P-MOS导通,N-MOS截止,此时I/O端口的电平就由P-MOS管决定为高电平;当设置输出的值为低电平的时候,P-MOS管处于截止状态,N-MOS管处于导通状态,此时I/O端口的电平就由N-MOS管决定为低电平,同时IO口输出的电平可以通过输入电路读取,此时I/O端口的电平一定是输出的电平。

GPIO_Mode_AF_OD 复用开漏输出

与开漏输出模式唯一区别在于输出控制电平之前电平的来源,开漏输出模式的输出电平是由CPU写入输出数据寄存器控制的,开漏复用输出模式的输出电平是由复用功能外设输出决定的。其他与开漏输出相似。

控制电路输出高电平:N-MOS截止,IO口电平由外部上拉/下拉决定

控制电路输出低电平:N-MOS开启,IO口输出低电平

 

 

GPIO_Mode_AF_PP 复用推挽输出

与推挽输出模式唯一区别在于输出控制电路之前电平的来源。开漏输出模式的输出电平是CPU写入输出数据寄存器的,推挽复用输出模式的输出电平是由复用功能外设输出决定的。

 

应用场合

模拟输入:应用ADC模拟输入,或者低功耗下省电  

浮空输入:可以做KEY识别,外部按键输入,IO的电平状态是不确定,完全由外部输入决定

下拉输入:IO内部下拉电阻输入

上拉输入:IO内部上拉电阻输入

推挽输出(Push-Pull):可以输出高、低电平,连接数字器件  

开漏输出(Open-Drain):开漏引脚不连接外部的上拉电阻时,只能输出低电平;如果需要同时具备输出高电平的功能,则需要接上拉电阻。  

对于相应的复用模式(复用输出来源片上外设),则是根据GPIO的复用功能来选择,如GPIO的引脚用作串口的输出(USART/SPI/CAN),则使用复用推挽输出模式。如果用在I2C、SMBUS这些需要线与功能的复用场合,就使用复用开漏模式。

二、中断

中断简而言之是暂时中止当前的工作,而去处理更为急需处理的事情,把急需处理的事情处理完毕之后,再回头来继续原来的事情。

stm32的中断分为抢占优先级和响应优先级。抢占优先级高的中断,可以打断抢占优先级低的中断。抢占优先级相同的中断,响应优先级高的可以优先执行。

中断向量表:中断向量是中断服务程序的入口地址,在计算机中中断向量的地址存放一条跳转到中断服务程序的跳转指令。中断地址是存储中断向量的内存单元。中断向量表是用来存放中断向量

嵌套中断:中断系统正在执行一个中断服务时,有另一个优先级更高的中断提出中断请求,这时会暂时终止当前正在执行的级别较低的中断源的服务程序,去处理级别更高的中断源,待处理完毕,再返回到被中断了的中断服务程序继续执行,这个过程就是中断嵌套。如果中断里调用HAL_Delay就会停在那里,因为根本不会进入那个级别更低的中断。CUBE生成的程序中, SysTick是中断型延时,SysTick是内核中断,优先级别默认最低。

 

三、STM32按键

按键需要上拉电阻,当按键按下时接到地,CPU读取出低电平知道按键按下。

Priority Group默认为4,抢占优先权有2^4(0~15)可选而响应优先权只能是0;为3时,抢占优先权有2^3(0~7)可选,响应优先权只有2^1(0,1)可选,其他同理,根据自己的需求选择

 

配置使能MCU外部晶振:

 

配置MCU工作主频为80MHz

接着就生成代码

在MDK-ARM目录下面可以找到中断向量表,在(startup_stm32l433xx.s)其中标明了中断处理函数的名称,不能随意定义。

先是内核中断(异常)

有Reset复位,NMI不可屏蔽中断,HardFault硬件错误等。

 

 

接着是外部中断,显而易见EXTI0的中断服务函数的函数名是:EXTI0_IRQHandler

EXTI0~EXTI4是独立的,9~5共用中断源,15~10共用中断源,9~5和15~10的中断需要在中断函数中判断是哪个中断引脚。

异常和中断向量表只能用汇编语言编写

 

在生成的代码gpio.c里有中断的设置

HAL_NVIC_SetPriority();设置中断优先级

HAL_NVIC_EnableIRQ();使能中断

为防止抖动产生的下降沿误触进入中断需要加个延时消抖,前面说过如果中断里调用HAL_Delay就会停在那里,中断不会进入级别更低的中断。所以需要读取SysTick产生延时函数(下面函数是网上找的)

 void delay_ms(int32_t nms)

 {

  int32_t temp;

  SysTick->LOAD = 8000*nms;

  SysTick->VAL=0X00;//清空计数器

  SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源

  do

  {

       temp=SysTick->CTRL;//读取当前倒计数值

  }

     while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达

     

     SysTick->CTRL=0x00; //关闭计数器

     SysTick->VAL =0X00; //清空计数器

 }

 

找到HAL_GPIO_EXTI_IRQHandler()函数

HAL_GPIO_EXTI_IPQHandler()里,如果GPIO引脚还是低电平,清除状态位然后调用回调函数,回调函数HAL_GPIO_EXTI_Callback()是个虚函数,需要重新写,改写回调函数为你想要的中断功能。

posted @ 2021-01-24 15:48  braveheart007  阅读(1499)  评论(0编辑  收藏  举报