STM32----摸石头过河系列(二)
今天將要學習關于按鍵相關的兩個點,一個是按鍵的輸入,另一個是外部中端。話不多說進入今天的正題:
一、按鍵的輸入
今天我們想要實現的是利用兩個按鍵來控制板子上的LED的亮滅。當第一個按鍵按下時LED點亮,當另一個按鍵按下時LED關閉。要實現的功能清除了,接下來讓我們來看看原理圖(在一中有我黏貼的原理圖)。在原理圖中,查看兩個按鍵所連接的引腳,在我的板子中是PC1和PC13,同時需要查看兩個按鍵所連接的另一端連接的GND還是vcc,一會用來判斷按鍵是否被按下。至于LED的開關在上一講中已經講過了。
下面就是迫不及待的源代碼了:
#include<stm32f10x_rcc.h> #include<stm32f10x_gpio.h>void Config_Key(void) {GPIO_InitTypeDef gpio_struct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);gpio_struct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_13;gpio_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOC,&gpio_struct); }void Config_Light(void) {GPIO_InitTypeDef gpio_struct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);gpio_struct.GPIO_Pin = GPIO_Pin_8;gpio_struct.GPIO_Mode = GPIO_Mode_Out_PP;gpio_struct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&gpio_struct); }int KeyScan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin) {if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == 0){return 1;}if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == 1){return 0;}return 0; }int main() {Config_Key();Config_Light();GPIO_SetBits(GPIOA,GPIO_Pin_8);while(1){if(KeyScan(GPIOC,GPIO_Pin_1) == 1){GPIO_ResetBits(GPIOA,GPIO_Pin_8);}if(KeyScan(GPIOC,GPIO_Pin_13) == 1){GPIO_SetBits(GPIOA,GPIO_Pin_8);}} }我們分函數模塊來分析一下代碼:
void Config_Key(void) {GPIO_InitTypeDef gpio_struct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);gpio_struct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_13;gpio_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOC,&gpio_struct); }按鍵所連接的GPIO端口的配置,同樣的定義GPIO的結構體變量gpio_struct同時開啟端口C的時鐘。接下來就是對結構變量中元素進行配置,首先兩個按鍵的引腳所連接的為PC1和PC13,所以GPIO_Pin的值如上設置。因為讀取按鍵的狀態所以將引腳的模式設置為浮空輸入。GPIO_Speed變量不需要進行配置。最后將配置應用到端口C上。
LED燈的配置,上節已經配置過了。
接下來是本節的重點按鍵掃描:
int KeyScan(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin) {if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == 0){return 1;}if(GPIO_ReadInputDataBit(GPIOx,GPIO_Pin) == 1){return 0;}return 0; }著重分析該函數,函數的返回類型是整型,返回0或者1.當返回1時表示按鍵按下,當按下0時表示按鍵沒有被按下。函數中的形參有兩個,分別為端口和引腳(這個地方可以去函數調用的地方看一下就會很清楚了)。接下來閃亮登場的是有標準庫提供的函數GPIO_ReadInputDataBit(),兩個參數分別為端口、引腳和KeyScan()傳入的參數一致,該函數用來讀取某個端口,某個引腳的電平高低,高為1,低為0.最后就是在主函數中各個函數的調用以及一個簡單的邏輯。
?
二、按鍵作為外部中端的輸入源
首先會51的一定明白中斷的含義,可能在32不會實施。在51中簡單粗暴,打開中斷允許位,設置觸發方式,最后書寫中斷服務函數即發生中斷所執行的代碼。在32中51中復雜了許多,剛開始感覺WTF,怎么和51比起來難了這么多。但這并不影響我們去掌握它。流程和51大致相似,先是配置,然后設置觸發方式,最后是中斷服務函數。說了這么多廢話,趕緊上源代碼:
#include<stm32f10x.h> #include<stm32f10x_rcc.h> #include<stm32f10x_gpio.h> #include<stm32f10x_exti.h>void Config_Light(void) {GPIO_InitTypeDef gpio_struct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);gpio_struct.GPIO_Pin = GPIO_Pin_8;gpio_struct.GPIO_Mode = GPIO_Mode_Out_PP;gpio_struct.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&gpio_struct); }void Config_NVIC(void) {NVIC_InitTypeDef nvic_struct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);nvic_struct.NVIC_IRQChannel = EXTI1_IRQn;nvic_struct.NVIC_IRQChannelPreemptionPriority = 1;nvic_struct.NVIC_IRQChannelSubPriority = 1;nvic_struct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&nvic_struct);nvic_struct.NVIC_IRQChannel = EXTI15_10_IRQn;nvic_struct.NVIC_IRQChannelPreemptionPriority = 2;nvic_struct.NVIC_IRQChannelSubPriority = 1;nvic_struct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&nvic_struct); }void Config_Exti(void) {GPIO_InitTypeDef gpio_struct;EXTI_InitTypeDef exti_struct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);Config_NVIC();gpio_struct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_13;gpio_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOC,&gpio_struct);GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource1);exti_struct.EXTI_Line = EXTI_Line1;exti_struct.EXTI_Mode = EXTI_Mode_Interrupt;exti_struct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;exti_struct.EXTI_LineCmd = ENABLE;EXTI_Init(&exti_struct);GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);exti_struct.EXTI_Line = EXTI_Line13;exti_struct.EXTI_Mode = EXTI_Mode_Interrupt;exti_struct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;exti_struct.EXTI_LineCmd = ENABLE;EXTI_Init(&exti_struct); }int main() {Config_Light();Config_Exti();while(1); }void EXTI1_IRQHandler() {if(EXTI_GetITStatus(EXTI_Line1) != RESET){GPIO_ResetBits(GPIOA,GPIO_Pin_8);EXTI_ClearITPendingBit(EXTI_Line1);} }void EXTI15_10_IRQHandler() {if(EXTI_GetITStatus(EXTI_Line13) != RESET){GPIO_SetBits(GPIOA,GPIO_Pin_8);EXTI_ClearITPendingBit(EXTI_Line13);} }接下來,讓我們化作一個小小芯片,身心體會配置過程。
void Config_NVIC(void) {NVIC_InitTypeDef nvic_struct;NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);nvic_struct.NVIC_IRQChannel = EXTI1_IRQn;nvic_struct.NVIC_IRQChannelPreemptionPriority = 1;nvic_struct.NVIC_IRQChannelSubPriority = 1;nvic_struct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&nvic_struct);nvic_struct.NVIC_IRQChannel = EXTI15_10_IRQn;nvic_struct.NVIC_IRQChannelPreemptionPriority = 2;nvic_struct.NVIC_IRQChannelSubPriority = 1;nvic_struct.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&nvic_struct); }無論我們使用哪種中斷我們可能都無法逃離這段代碼。這段代碼主要用來配置某個中斷通道的優先級,以及中斷通道的使能。類似于51的中斷標志位使能。(理解不一定準確)
接下來實觸發方式的設置:
void Config_Exti(void) {GPIO_InitTypeDef gpio_struct;EXTI_InitTypeDef exti_struct;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);Config_NVIC();gpio_struct.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_13;gpio_struct.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOC,&gpio_struct);GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource1);exti_struct.EXTI_Line = EXTI_Line1;exti_struct.EXTI_Mode = EXTI_Mode_Interrupt;exti_struct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;exti_struct.EXTI_LineCmd = ENABLE;EXTI_Init(&exti_struct);GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource13);exti_struct.EXTI_Line = EXTI_Line13;exti_struct.EXTI_Mode = EXTI_Mode_Interrupt;exti_struct.EXTI_Trigger = EXTI_Trigger_Rising_Falling;exti_struct.EXTI_LineCmd = ENABLE;EXTI_Init(&exti_struct); }需要開啟外部中斷時鐘RCC_APB2Periph_AFIO。兩個按鍵引腳設置為輸入模式利用函數GPIO_EXTILineConfig()來選擇要作為中斷輸入的引腳,接下來在中斷配置結構體中EXTI_Line用來設置中斷源,EXTI_Mode設置是觸發中斷還是事件,此處可以直接設成中斷,其他以后會慢慢遇到理解。EXTI_Trigger用來設置觸發方式,上升沿,下降沿,邊沿觸發等三種模式,使能該中斷源。最后初始化中斷配置應用。
最后書寫中斷服務函數:
void EXTI1_IRQHandler() {if(EXTI_GetITStatus(EXTI_Line1) != RESET){GPIO_ResetBits(GPIOA,GPIO_Pin_8);EXTI_ClearITPendingBit(EXTI_Line1);} }void EXTI15_10_IRQHandler() {if(EXTI_GetITStatus(EXTI_Line13) != RESET){GPIO_SetBits(GPIOA,GPIO_Pin_8);EXTI_ClearITPendingBit(EXTI_Line13);} }在中斷服務函數中利用EXTI_GetITStatus()函數來得到中斷標志位狀態,當狀態不為RESET時,中斷觸發成功,執行相關的操作,最后記得清楚中斷標志位。利用庫提供的函數EXTI_ClearITPendingBit()來清楚中斷標志位,然后退出中斷服務函數,等待下次觸發進入。
受水平所限,很多地方沒有分析清楚,內心實在惶恐。
總結
以上是生活随笔為你收集整理的STM32----摸石头过河系列(二)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常见测量矩阵的MATLAB实现
- 下一篇: fatal error LNK1123: