GPIO内部上拉较弱,可根据满足电路需求选择是用内部的上拉还是自己外接上拉。
根据原理图可知,当按键松开时,单片机引脚连接在高电平上,GPIO口输入高电平。
当按键按下时,单片机引脚通过按键接地,GPIO口输入低电平。
在程序中,通过读取GPIO口的电平状态,就可以知道按键是否被按下。
由于按键是机械弹性开关,由于机械触电的弹性作用,按键在闭合及断开的瞬间均伴随有一连串的抖动。抖动会导致CPU在按键一次动作内发生多次响应,所以要对按键进行消抖处理。
通常对于按键消抖有两种方法,一种软件消抖,在按键程序中,延时10-20ms左右,等按键状态稳定了再去读取电平;另一种是硬件消抖,在按键两端并联个电容。
按键轮询的原理就是在循环中,不断读取按键引脚的电平,当读取到低电平的时候,认为按键按下,然后执行操作。
时钟和LED的相关配置之前已经介绍过了,这里不再介绍。
配置按键的GPIO。
主程序轮询。
在循环中,先第一次判断按键是否按下,若按键按下,延时10ms(作用是消抖),消抖之后再判断一个按键状态,确认按键是否真的按下了,若读取引脚状态还是低电平,则认为按键是真的被按下了,然后执行操作函数,打开LED。
外部中断,从名字上看就是由于外部变化而在单片机内产生的中断。
单片机通过GPIO口接收外部数据,STM32F103的所有GPIO口都可以设置为外部中断模式。
前面介绍过NVIC控制芯片的所有中断,外部中断也不例外,但外部中断不是直接受控于NVIC,而是通过一个外部中断/事件控制器EXTI(External interrupt/event controller)与NVIC相连。而内部中断源比如串口、ADC等是直接和NVIC连接的。
STM32F103共有A-G7组GPIO,每一组有0-15共16个引脚,STM32F103支持19个外部中断/事件请求(互联型系列支持20个),每个GPIO组的相同位置的引脚位于同一个EXTIX(X = 0-15)中,比如所有GPIO的GPIO_PIN_0都在EXTI0中。同一时刻,只能有一个引脚被使能,也就是说加入配置了GPIOA_PIN_0为外部中断/事件,剩余的GPIOB—GPIOG的PIN_0引脚就不能设置为外部中断/事件模式了。
外部中断线共有20个,除了16个GPIO的,还有四条。
第16条是控制PVD(掉电检测)输出的。
第17条是RTC报警事件中断。
第18条是USB唤醒事件。
第19条是以太网唤醒事件。这个只有在互联型设备上才有。
根据上图从左到右推断可知,要想使能引脚的外部中断,首先要配置GPIO引脚,并设置成AFIO复用功能模式,然后配置EXTI寄存器,然后设置NVIC寄存器配置优先级即可完成外部中断的设置。
上图中每条线上的19表示这样的线有19条,也就是每个EXTI都有一条这样的线。
上图可知,外部中断分为外部中断和外部事件两种情况。
简单的区分就是外部中断是当产生外部中断之后,现象表现在软件方面,产生中断后,程序调用外部中断函数,在中断函数中操作其他任务。外部事件表现在硬件方面,当发生中断后,在硬件上打开其他外设,比如定时器,ADC。这种情况不占用CPU资源。
中断和事件的输入都是一块的,通过引脚输入,首先通过边缘检测电路,判断是上升沿触发还是下降沿,然后通过一个或门输出,若事件屏蔽寄存器输出为1,产生事件,与门2打开,连接脉冲发生器产生脉冲,脉冲发生器在与其他外设连接。整体流程如上图黄色路线。
对于中断而言,当边缘检测电路检测到引脚状态改变了,或者软件中断寄存器置1了,或门输出为1,连接与门1,若中断屏蔽寄存器输出1,则与门1打通,发生中断,中断挂起寄存器中对应中断位就置为1,然后发送给NVIC进行处理中断函数。
了解了以上流程就知道如何配置外部中断了。
1、设置边缘检测方式,下降沿、上升沿、双边缘。
2、配置软件中断事件寄存器,因为它连接的是或门,所以这个是可选的,不是必须设置的。
3、选择打开中断屏蔽寄存器还是事件屏蔽寄存器。
4、将中断挂起寄存器置位,将信号发送给NVIC。
5、在中断程序里面编写对应程序。若是选择中断事件,则事件发送一个脉冲响应。
在介绍GPIO的时候说过,GPIO可以作为简单的输入输出口用,也可以作为一些协议,ADC、DAC等外设的引脚,当GPIO作为后者使用的时候,就是GPIO的复用。
上图中,绿色就是GPIO的复用功能(Alternate functions),红色是引脚在复位之后的默认功能,就是做为普通的输入输出引脚使用。篮筐中的FT代表的是这个IO口是5V耐压的,也就是他是可以连接5V使用的(正常单片机的工作电压是3.3V)。
在复用功能中,有分为两类,一个是默认功能Default。注意一个引脚的复用功能可以不止一个,可以有多种复用功能。如上图PB14既可以作为PSI2_MISO使用,又可以作为TIM1_CH2使用,还可以作为USART3_RTS使用。
第二种是重映射Remap,他是把有特殊功能的引脚分配给其他引脚。也就是把A引脚的默认复用功能X分配给B引脚,这样B引脚只能使用复用功能X,A引脚只能使用除了X功能之外的其他复用功能。
举个例子,下图PB13引脚,可以把TIN1_CH1N的复用功能重映射给PA7使用,这样PA7只能使用TIM1_CH1N功能,不能使用默认的SPI_MOSI等功能;而PB13引脚的复用功能,不能使用TIM1_CH1N功能,只能使用剩下的三个功能。
GPIO中的关于外部中断的主要函数有两个,他们的作用跟之前中断系统中介绍的是一样的,是在系统默认的中断服务函数中调用的。
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN);``HAL_GPIO_EXTI_Callback(GPIO_Pin);
HAL_NVIC_SetPriority(EXTI0_IRQn, 0, 0);
设置中断函数两个优先级。
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
使能具体的外部中断函数。
较于之前的实验,这里只新增了两部分,设置复用功能和配置EXTI,对于其他的比如时钟配置,LED配置这理解不在讲解了。
在设置引脚复用功能是,只需要把GPIO结构体中的Mode成员的参数选择为具体的复用功能就行,如GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING;
设置GPIO的工作模式为下降沿触发的中断复用模式。
GPIO配置完成要配置EXTI。这里要注意,不是每个EXTI都有自己独立的中断函数,在官方的文件中可以看到,只有EXTI0、1、2、3、4的中断函数是单独的,EXTI5—9(共5个)和EXTI10—15(共6个)他们的中断函数是合在一起的,也就是说,EXTI5、6、7、8、9他们发生中断时,程序内执行的中断函数是同一个函数。而EXTI0、1、2、3、4他们每个都有自己的中断函数。
下图可以看到,对于不同的EXTI,他们的系统中断服务函数也不同,EXTI3有自己的独立函数,而EXTI13和EXTI15只能挤在同一个函数中。
对于EXTI的配置,主要的寄存器有两种,中断/事件屏蔽寄存器和触发沿选择寄存器。
中断屏蔽寄存器用到了低20位,分别控制20个EXTI的中断请求,置1则允许中断,否则会将中断屏蔽掉,即使满足中断条件,程序也不会执行中断服务函数。对于事件屏蔽寄存器跟中断屏蔽寄存器是一样的。
触发沿设置寄存器。
这两个是设置选择上升沿触发还是下降沿触发的。
当发生了选择的边沿事件,该寄存器的对应位置就会置1。相当于一个标志位,像该寄存器写1则清除它。