外部事件的处理
文章目錄
- 1 外部事件的處理
- 1.1 概述
- 1.2 代碼實(shí)現(xiàn)
1 外部事件的處理
1.1 概述
系統(tǒng)中要監(jiān)控和管理兩個(gè)事件,一是按鍵事件;二是多個(gè)外部中斷事件。我們通過(guò)事件標(biāo)志組來(lái)進(jìn)行處理。
1.2 代碼實(shí)現(xiàn)
button.h:
/*** @brief 按鍵驅(qū)動(dòng)* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權(quán)所有,禁止用于商業(yè)用途*/ #ifndef BUTTON_H #define BUTTON_H#include "appConfig.h"#define BUTTON_MSG_NR 10 // 按鍵消息緩存數(shù)量 #define BUTTON_SCAN_INTERVAL 20 // 安鍵掃描的時(shí)間間隔, ms為單位typedef enum {ButtonNone,ButtonStartStop,Button1,Button2,Button3, }ButtonId;typedef enum {ButtonDown,ButtonUp, }ButtonState;typedef void (*ButtonPressCb) (ButtonId id);void ButtonInit (ButtonPressCb cb); uint32_t ButtonWaitPress (ButtonId * id); uint32_t ButtonGetPressed (ButtonId * id); uint32_t ButtonNoWaitGetPressed (ButtonId * id);#endif //BUTTON_Hbutton.c:
/*** @brief 按鍵驅(qū)動(dòng)* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權(quán)所有,禁止用于商業(yè)用途*/ #include "tinyOS.h" #include "button.h" #include "stm32f10x.h" #include "extevent.h"// 按鍵存儲(chǔ)消息緩沖區(qū) static tMbox buttonMbox; static void * buttonMsgBuffer[BUTTON_MSG_NR];static tTimer buttonTimer; // 按鍵掃描定時(shí)器static ButtonPressCb buttonPressCb;/*** 初始化按鍵硬件*/ static void ButtonHalInit (void) {GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOB, &GPIO_InitStructure); }/*** 獲取哪一個(gè)按鍵按下*/ static ButtonId ButtonGetWhichPress (void) {uint8_t state;ButtonId buttonId = ButtonNone;state = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_1);if (state == Bit_SET) {buttonId = Button1;}state = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_2);if (state == Bit_SET) {buttonId = Button2;}state = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_3);if (state == Bit_SET) {buttonId = Button3;}state = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_0);if (state == Bit_SET) {buttonId = ButtonStartStop;}return buttonId; }/*** 按鍵定時(shí)器掃描處理, 按鍵處理譯碼* @param arg*/ static void timerFunc (void * arg) {static ButtonId prePressedButton = ButtonNone;static enum {NO_DOWN,RECHECK_DOWN,CONFIRMED_DOWN,RECHECK_UP} scanState = NO_DOWN;// 讀取當(dāng)前硬件狀態(tài)ButtonId currPressedButton = ButtonGetWhichPress();switch (scanState) {case NO_DOWN:// 有按鍵按下,進(jìn)入第1次確認(rèn)檢查狀態(tài)if (currPressedButton != ButtonNone) {scanState = RECHECK_DOWN;DEBUG_PRINT("NO_DOWN -> RECHECK_DOWN:%d\n", currPressedButton);}break;case RECHECK_DOWN:if (currPressedButton == ButtonNone) {scanState = NO_DOWN;DEBUG_PRINT("RECHECK_DOWN -> NO_DOWN:%d\n", currPressedButton);} else if (prePressedButton == currPressedButton) {// 發(fā)消息通知,根據(jù)按鍵類(lèi)型,決定如何處理. 可以考慮從某個(gè)配置表中查,這樣可配置多個(gè)按鍵事件的通知行為uint32_t notifyOption = (currPressedButton == ButtonStartStop) ? tMBOXSendFront : tMBOXSendNormal;tMboxNotify(&buttonMbox, (void *)currPressedButton, notifyOption);// 通知事件管理器if (buttonPressCb != NULL) {buttonPressCb(currPressedButton);}scanState = CONFIRMED_DOWN;DEBUG_PRINT("RECHECK_DOWN -> CONFIRMED_DOWN:%d\n", currPressedButton);}break;case CONFIRMED_DOWN:// 進(jìn)入這個(gè)狀態(tài)后,要做的是檢查按鍵是否重復(fù)按下或者等待按鍵釋.這里簡(jiǎn)單起見(jiàn),等待按鍵釋放if (currPressedButton == ButtonNone) {// 發(fā)現(xiàn)按鍵釋放?進(jìn)一步確認(rèn)。但這里要return,否則prePressedButton會(huì)在后面設(shè)置NonescanState = RECHECK_UP;DEBUG_PRINT("CONFIRMED_DOWN -> RECHECK_UP:%d\n", currPressedButton);return;} else if (currPressedButton != prePressedButton) {// 發(fā)現(xiàn)不一樣的按鍵按下,重新確認(rèn)scanState = RECHECK_DOWN;DEBUG_PRINT("CONFIRMED_DOWN -> RECHECK_DOWN:%d\n", currPressedButton);}break;case RECHECK_UP:if (currPressedButton == ButtonNone) {// 確認(rèn)沒(méi)有按鍵按下,已經(jīng)釋放scanState = NO_DOWN;DEBUG_PRINT("RECHECK_UP -> NO_DOWN:%d\n", currPressedButton);} else if (currPressedButton != prePressedButton) {// 發(fā)現(xiàn)不一樣的按鍵按下,重新確認(rèn)是否按下scanState = RECHECK_DOWN;DEBUG_PRINT("RECHECK_UP -> scanState:%d\n", currPressedButton);} else if (currPressedButton == prePressedButton) {// 相同的鍵,噢,前一次可能是誤觸發(fā),再次重新檢查scanState = CONFIRMED_DOWN;DEBUG_PRINT("RECHECK_UP -> CONFIRMED_DOWN:%d\n", currPressedButton);}break;}// 記錄當(dāng)前結(jié)果prePressedButton = currPressedButton; }/*** 按鍵初始化*/ void ButtonInit (ButtonPressCb cb) {buttonPressCb = cb;ButtonHalInit();tMboxInit(&buttonMbox, buttonMsgBuffer, BUTTON_MSG_NR);tTimerInit(&buttonTimer, 0, BUTTON_SCAN_INTERVAL / TINYOS_SYSTICK_MS, timerFunc, 0, TIMER_CONFIG_TYPE_SOFT);tTimerStart(&buttonTimer); }/*** 等待任意按鍵按下* @param id 按鍵是否按下的狀態(tài)* @return 非0,有錯(cuò)誤發(fā)生;0無(wú)錯(cuò)誤*/ uint32_t ButtonWaitPress (ButtonId * id) {uint32_t err = 0;err = tMboxWait(&buttonMbox, (void **)id, 0);return err; }/*** 無(wú)阻塞獲取按下的按鍵* @param id* @return*/ uint32_t ButtonNoWaitGetPressed (ButtonId * id) {uint32_t err = 0;err = tMboxNoWaitGet(&buttonMbox, (void **)id);return err; }extio.h:
/*** @brief 外部IO設(shè)計(jì)* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權(quán)所有,禁止用于商業(yè)用途*/ #ifndef EXTIO_H #define EXTIO_Htypedef enum {ExtIOHigh,ExtIOLow }ExtIOState;typedef enum {ExtIOPin0 = 0,ExtIOPin1,ExtIOPin2,ExtIOPin3,ExtIOPinEnd, }ExtIOPin;typedef enum {ExtIntIOPin4,ExtIntIOPin5,ExtIntIOPin6,ExtIntIOPin7, }ExtIntIOPin;typedef void (*ExtIntIOCb) (ExtIntIOPin pin);void ExtIOInit (ExtIntIOCb cb); void ExtIOSetState (ExtIOPin pin, ExtIOState); ExtIOState ExtIOGetState (ExtIOPin pin); void ExtIOSetDir (ExtIOPin pin, uint8_t isInput); void ExtIOResetInput (void);#endif //PROJECT_EXTIO_Hextio.c:
/*** @brief 外部IO設(shè)計(jì)* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權(quán)所有,禁止用于商業(yè)用途*/ #include "tinyOS.h" #include "extio.h" #include "stm32f10x_gpio.h" // Keil::Device:StdPeriph Drivers:GPIOstatic ExtIntIOCb extIntIOCb;static uint16_t extioMap[ExtIOPinEnd] = {GPIO_Pin_1, // 對(duì)應(yīng)ExtIOPin0,以下類(lèi)堆GPIO_Pin_2,GPIO_Pin_3,GPIO_Pin_4 };/*** 初始化外部IO*/ void ExtIOInit (ExtIntIOCb cb) {GPIO_InitTypeDef GPIO_InitStructure;EXTI_InitTypeDef EXTI_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOA, &GPIO_InitStructure);// 配置GPIO中斷管腳RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;GPIO_Init(GPIOB, &GPIO_InitStructure);RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource5);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource6);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource7);GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource8);EXTI_InitStructure.EXTI_Line = EXTI_Line5 | EXTI_Line6 | EXTI_Line7 | EXTI_Line8;EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure);NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);extIntIOCb = cb; }/*** 設(shè)置指定IO引腳狀態(tài)* @param pin 需配置的IO* @param state 配置的狀態(tài)值*/ void ExtIOSetState (ExtIOPin pin, ExtIOState state) {tTaskCritical_t critical;uint16_t halPin = extioMap[pin];critical = tTaskEnterCritical();if (state == ExtIOHigh) {GPIO_SetBits(GPIOA, halPin);} else {GPIO_ResetBits(GPIOA, halPin);}tTaskExitCritical(critical); }/*** 獲取指定引腳的狀態(tài)* @param pin 需獲取的引腳* @return 引腳的狀態(tài)*/ ExtIOState ExtIOGetState (ExtIOPin pin) {uint16_t halPin = extioMap[pin];uint8_t state = GPIO_ReadInputDataBit(GPIOA, halPin);return (state == Bit_SET) ? ExtIOHigh : ExtIOLow; }/*** 設(shè)置管腳狀態(tài)* @param pin* @param isInput*/ void ExtIOSetDir (ExtIOPin pin, uint8_t isInput) {tTaskCritical_t critical;GPIO_InitTypeDef GPIO_InitStructure;uint16_t halPin = extioMap[pin];critical = tTaskEnterCritical();GPIO_InitStructure.GPIO_Pin = halPin;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;GPIO_InitStructure.GPIO_Mode = isInput ? GPIO_Mode_IPU : GPIO_Mode_Out_PP;GPIO_Init(GPIOA, &GPIO_InitStructure);tTaskExitCritical(critical); }/*** 設(shè)置所有IO為輸入態(tài)*/ void ExtIOResetInput (void) {ExtIOSetDir(ExtIOPin0, 1);ExtIOSetDir(ExtIOPin1, 1);ExtIOSetDir(ExtIOPin2, 1);ExtIOSetDir(ExtIOPin3, 1); }void EXTI9_5_IRQHandler (void) {if (EXTI_GetITStatus(EXTI_Line5) != RESET) {if (extIntIOCb) {extIntIOCb(ExtIntIOPin4);}EXTI_ClearITPendingBit(EXTI_Line5);}if (EXTI_GetITStatus(EXTI_Line6) != RESET) {if (extIntIOCb) {extIntIOCb(ExtIntIOPin5);}EXTI_ClearITPendingBit(EXTI_Line6);}if (EXTI_GetITStatus(EXTI_Line7) != RESET) {if (extIntIOCb) {extIntIOCb(ExtIntIOPin6);}EXTI_ClearITPendingBit(EXTI_Line7);}if (EXTI_GetITStatus(EXTI_Line8) != RESET) {if (extIntIOCb) {extIntIOCb(ExtIntIOPin7);}EXTI_ClearITPendingBit(EXTI_Line8);} }extevent.h:
/*** @brief 按鍵事件處理設(shè)計(jì)* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權(quán)所有,禁止用于商業(yè)用途*/ #ifndef EXTEVENT_H #define EXTEVENT_H#include "extio.h" #include "button.h"#define EXTEVENT_TASK_PRIO 0 #define EXTEVENT_TASK_ENV_SIZE 512void ExtEventInit (void); void ExtEventButtonPress (ButtonId id); void ExtEventExtIOInt (ExtIntIOPin pin);#endif //MONITOR_Hextevent.c:
/*** @brief 監(jiān)控任務(wù)設(shè)計(jì)* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權(quán)所有,禁止用于商業(yè)用途*/ #include <string.h> #include "tinyOS.h" #include "extevent.h" #include "button.h" #include "uart.h" #include "extio.h" #include "WaveGen.h"typedef enum {ExtEventButton = 1 << 0,ExtEventExtIO4 = 1 << 1,ExtEventExtIO5 = 1 << 2,ExtEventExtIO6 = 1 << 3,ExtEventExtIO7 = 1 << 4,ExtEventFlagAll = 0x1F, }ExtEventType;// 任務(wù)相關(guān) static tTaskStack exteventTaskEnv[EXTEVENT_TASK_ENV_SIZE]; static tTask exteventTask;static tFlagGroup flagGroup;/*** @param msg*/ static void showMsg (const char * msg) {UartWrite(msg, strlen(msg)); }/*** 通知按鍵按下*/ void ExtEventButtonPress (ButtonId id) {tFlagGroupNotify(&flagGroup, 1, ExtEventButton); }/*** 通知引腳中斷*/ void ExtEventExtIOInt (ExtIntIOPin pin) {switch (pin) {case ExtIntIOPin4:tFlagGroupNotify(&flagGroup, 1, ExtEventExtIO4);break;case ExtIntIOPin5:tFlagGroupNotify(&flagGroup, 1, ExtEventExtIO5);break;case ExtIntIOPin6:tFlagGroupNotify(&flagGroup, 1, ExtEventExtIO6);break;case ExtIntIOPin7:tFlagGroupNotify(&flagGroup, 1, ExtEventExtIO7);break;} }static void buttonEvent (ButtonId id) {switch (id) {case ButtonStartStop:WaveStopOutput();ExtIOResetInput();showMsg("Start/Stop Button Press\r\n");break;case Button1:showMsg("Button1 Press\r\n");break;case Button2:showMsg("Button2 Press\r\n");break;case Button3:showMsg("Button3 Press\r\n");break;default:break;} }static void extioEvent (uint32_t resultFlag) {if (resultFlag & ExtEventExtIO4) {showMsg("Pin4 Interrupt\r\n");}if (resultFlag & ExtEventExtIO5) {showMsg("Pin5 Interrupt\r\n");}if (resultFlag & ExtEventExtIO6) {showMsg("Pin6 Interrupt\r\n");}if (resultFlag & ExtEventExtIO7) {showMsg("Pin7 Interrupt\r\n");} }/*** 監(jiān)控任務(wù)* @param param*/ void exteventTaskEntry (void * param) {ButtonId buttonId;for (;;) {uint32_t resultFlag;tFlagGroupWait(&flagGroup, TFLAGGROUP_SET_ANY | TFLAGGROUP_CONSUME, ExtEventFlagAll, &resultFlag, 0);if (resultFlag & ExtEventButton) {ButtonNoWaitGetPressed(&buttonId);buttonEvent(buttonId);} else if (resultFlag & (ExtEventExtIO4 | ExtEventExtIO5 | ExtEventExtIO6 | ExtEventExtIO7)) {extioEvent(resultFlag);}} }/*** 監(jiān)控初始化*/ void ExtEventInit (void) {tFlagGroupInit(&flagGroup, 0);tTaskInit(&exteventTask, exteventTaskEntry, (void *) 0x0, EXTEVENT_TASK_PRIO, exteventTaskEnv, sizeof(exteventTaskEnv)); }app.c:
/*** @brief tOS應(yīng)用示例* @details* @author 01課堂 李述銅 http://01ketang.cc* @date 2017-06-01* @version 1.0* @copyright 版權(quán)所有,禁止用于商業(yè)用途*/ #include "tinyOS.h" #include "app.h" #include "hal.h"#include "button.h" #include "uart.h" #include "extio.h" #include "WaveGen.h" #include "cli.h" #include "extevent.h"#include "string.h"static tTaskStack task1Env[TASK1_ENV_SIZE]; // 任務(wù)1的堆棧空間 static tTask task1;void task1Entry (void * param) {for (;;) {tTaskDelay(1);} }/*** App的初始化*/ void tInitApp (void) {halInit();ButtonInit(ExtEventButtonPress);UartInit();ExtIOInit(ExtEventExtIOInt);WaveGenInit();CLIInit();ExtEventInit();tTaskInit(&task1, task1Entry, (void *) 0x0, TASK1_PRIO, task1Env, sizeof(task1Env)); }參考資料:
總結(jié)