這次的程序使用了中斷、thread、semaphore,按鍵被按下後GPIO的中斷callback被執行,發送semaphore使檢測按鍵的thread得以執行,然後判斷長按或者短按發送相應semaphore讓相應的thread執行,除輸出信息外LED會根據短按或者長按來閃爍1或者2次。
#include <zephyr.h>
#include <board.h>
#include <device.h>
#include <gpio.h>
#include <misc/util.h>
#include <misc/printk.h>
/* define LED and Button pin */
#define LED_PORT LED0_GPIO_PORT
#define LED_PIN LED0_GPIO_PIN
#define LED_FLASH_TIME 100//ms
#define BTN_PORT SW0_GPIO_NAME
#define BTN_PIN SW0_GPIO_PIN
/* define semaphore */
K_SEM_DEFINE(semPress, 0, 1);
K_SEM_DEFINE(semHold, 0, 1);
K_SEM_DEFINE(semBtnIntr, 0, 1);
/* define global device */
struct device *gDevLed;
struct device *gDevBtn;
static struct gpio_callback gpio_cb;
/* define thread parameter */
#define STACKSIZE 1024
#define PRIORITY_EVENT 7
#define PRIORITY_INTR 6
void ledOnOff(uint32_t on)
{
gpio_pin_write(gDevLed, LED_PIN, !on);
}
void ledFlash(uint32_t times)
{
while(times) {
ledOnOff(1);
k_sleep(LED_FLASH_TIME);
ledOnOff(0);
if(--times)
k_sleep(LED_FLASH_TIME);
}
}
uint32_t isKeyDown(void)
{
uint32_t val;
gpio_pin_read(gDevBtn, BTN_PIN, &val);
return !val;
}
void threadPress(void *dummy1, void *dummy2, void *dummy3)
{
ARG_UNUSED(dummy1);
ARG_UNUSED(dummy2);
ARG_UNUSED(dummy3);
while(1) {
k_sem_take(&semPress, K_FOREVER);
printk("btn pressed\n");
ledFlash(1);
}
}
void threadHold(void *dummy1, void *dummy2, void *dummy3)
{
ARG_UNUSED(dummy1);
ARG_UNUSED(dummy2);
ARG_UNUSED(dummy3);
while(1) {
k_sem_take(&semHold, K_FOREVER);
printk("btn hold\n");
ledFlash(2);
}
}
void threadBtnIntr(void *dummy1, void *dummy2, void *dummy3)
{
ARG_UNUSED(dummy1);
ARG_UNUSED(dummy2);
ARG_UNUSED(dummy3);
uint32_t count;
bool bHold;
while(1) {
k_sem_take(&semBtnIntr, K_FOREVER);
count = 0;
bHold = false;
do {
k_sleep(50);
count++;
if(count > 6) {
bHold = true;
break;
}
}while(isKeyDown());
if(bHold)
k_sem_give(&semHold);
else
k_sem_give(&semPress);
}
}
K_THREAD_DEFINE(threadPress_id, STACKSIZE, threadPress, NULL, NULL, NULL,
PRIORITY_EVENT, 0, K_NO_WAIT);
K_THREAD_DEFINE(threadHold_id, STACKSIZE, threadHold, NULL, NULL, NULL,
PRIORITY_EVENT, 0, K_NO_WAIT);
K_THREAD_DEFINE(threadBtnIntr_id, STACKSIZE, threadBtnIntr, NULL, NULL, NULL,
PRIORITY_INTR, 0, K_NO_WAIT);
void btnIntrCb(struct device *gpio, struct gpio_callback *cb, uint32_t pin)
{
k_sem_give(&semBtnIntr);
}
void helloMsg(void)
{
printk("\n************************************************\n");
printk("**\n");
printk("** Welcome to visit http://blog.csdn.net/veabol\n");
printk("** Thread program start!\n");
printk("**\n");
printk("************************************************\n");
}
void main (void)
{
helloMsg();
printk("configure led\n");
gDevLed = device_get_binding(LED_PORT);
if (!gDevLed) {
printk("error\n");
return;
}
gpio_pin_configure(gDevLed, LED_PIN, GPIO_DIR_OUT);
ledOnOff(0);
printk("configure button\n");
gDevBtn = device_get_binding(BTN_PORT);
if (!gDevBtn) {
printk("error\n");
return;
}
gpio_pin_configure(gDevBtn, BTN_PIN,
GPIO_DIR_IN | GPIO_INT | GPIO_INT_EDGE | GPIO_INT_ACTIVE_LOW | GPIO_PUD_PULL_UP);
gpio_init_callback(&gpio_cb, btnIntrCb, BIT(BTN_PIN));
gpio_add_callback(gDevBtn, &gpio_cb);
gpio_pin_enable_callback(gDevBtn, BTN_PIN);
}
通過系統函數K_SEM_DEFINE
定義三個信號量semPress,semHold,semBtnIntr
,K_THREAD_DEFINE
初始化三個thread,分別用於等待按鍵中斷和短按和長按的事件,threadBtnIntr()
等待semBtnIntr
即按鍵中斷的發生,threadPress()
是短按的線程等待semPress
被髮送,threadHold()
是長按的線程等待semHold
被髮送。
main()
函數初始化LED和按鍵,註冊並使能按鍵的callback函數btnIntrCb()
,當中斷髮生時btnIntrCb()
被調用,並且發送信號使threadBtnIntr()
得以繼續執行,根據按鍵持續的時間長短分別發送短按和長按的信號 ,相應的線程也得以執行,測試時對按鍵進行短按和長按能夠看到LED閃爍1次或者2次,通過串口能夠看到如何信息:
************************************************
**
** Welcome to visit http://blog.csdn.net/veabol
** Thread program start!
**
************************************************
configure led
configure button
btn pressed
btn pressed
btn hold
btn hold