RT-Thread信号量实际运用—按键点灯
上面是魔笛开发板上 LED 和按键的 IO 分布,我们通过信号量的方法来同步按键线程和LED 线程,实现当 enter 键按下后,点亮或关闭 LED 的动作。
/********************************************************************************************************** * * 模块名称 : 按键检测模块 * 文件名称 : key.c * 版 本 : V1.0 * 说 明 : * 修改记录 : * 版本号 日期 作者 说明 * * v1.0 2013-4-20 jiezhi320(UP MCU 工作室) * * Copyright (C), 2012-2013, * 淘宝店: http://shop73275611.taobao.com * QQ交流群: 258043068 * **********************************************************************************************************/ #include <rtthread.h> #include "stm32f10x.h" #include "key.h" //#define KEY_DEBUG #ifdef KEY_DEBUG #define printf rt_kprintf /*使用rt_kprintf来输出*/ #else #define printf(...) /*无输出*/ #endif #define KEY_RCC RCC_APB2Periph_GPIOB #define KEY_PORT GPIOB #define KEY_UP_PIN GPIO_Pin_5 #define KEY_DOWN_PIN GPIO_Pin_9 #define KEY_LEFT_PIN GPIO_Pin_8 #define KEY_RIGHT_PIN GPIO_Pin_0 #define KEY_SET_PIN GPIO_Pin_1 #define KEY_ALL_NSET (0x0000|KEY_UP_PIN|KEY_DOWN_PIN|KEY_LEFT_PIN|KEY_RIGHT_PIN|KEY_SET_PIN) extern struct rt_semaphore key_sem; static void key_scan(void); static void rt_hw_key_init(void); void key_thread_entry(void* parameter) { rt_hw_key_init(); while(1) { key_scan(); rt_thread_delay(5); } } void rt_hw_key_init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* Enable the GPIO_LED Clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_AFIO, ENABLE); /* Configure the GPIO_LED pin */ GPIO_InitStructure.GPIO_Pin = KEY_UP_PIN|KEY_DOWN_PIN|KEY_LEFT_PIN|KEY_RIGHT_PIN|KEY_SET_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(KEY_PORT, &GPIO_InitStructure); } void key_scan(void) { static vu16 s_KeyCode;//内部检查按键使用 static vu8 s_key_debounce_count, s_key_long_count; vu16 t_key_code; t_key_code = GPIO_ReadInputData(KEY_PORT) & KEY_ALL_NSET; if((t_key_code == KEY_ALL_NSET)||(t_key_code != s_KeyCode)) { s_key_debounce_count = 0; //第一次 s_key_long_count = 0; } else { if(++s_key_debounce_count == DEBOUNCE_SHORT_TIME) { //短按键 switch(s_KeyCode) { case KEY_ALL_NSET & (~KEY_UP_PIN): //up break; case KEY_ALL_NSET & (~KEY_DOWN_PIN): //down break; case KEY_ALL_NSET & (~KEY_LEFT_PIN): //left break; case KEY_ALL_NSET & (~KEY_RIGHT_PIN): //right break; case KEY_ALL_NSET & (~KEY_SET_PIN): //set /* 释放一次信号量 */ rt_sem_release(&key_sem); break; default: //其他组合不做处理 break; } #ifdef KEY_DEBUG printf("key %d is set\n", s_KeyCode); #endif } if(s_key_debounce_count == DEBOUNCE_COUT_FIRST + DEBOUNCE_COUT_INTERVAL) { //连按键 s_key_debounce_count = DEBOUNCE_COUT_FIRST; ++s_key_long_count; /* switch(s_KeyCode) { case KEY_ALL_NSET & (~KEY_UP_PIN): //up break; case KEY_ALL_NSET & (~KEY_DOWN_PIN): //down break; } */ } if(s_key_long_count == DEBOUNCE_LONG_TIME) { //长按键 s_key_long_count = DEBOUNCE_LONG_TIME; } } s_KeyCode = t_key_code; // 保存本次键值 }
/********************************************************************************************************** * * 模块名称 : LED驱动模块 * 文件名称 : led.c * 版 本 : V1.1 * 说 明 : * 修改记录 : * 版本号 日期 作者 说明 * * v1.0 2013-4-20 jiezhi320(UP MCU 工作室) * * Copyright (C), 2012-2013, * 淘宝店: http://shop73275611.taobao.com * QQ交流群: 258043068 * **********************************************************************************************************/ #include <rtthread.h> #include <stm32f10x.h> #include "led.h" // led define #define led1_rcc RCC_APB2Periph_GPIOF #define led1_gpio GPIOF #define led1_pin (GPIO_Pin_6) #define led2_rcc RCC_APB2Periph_GPIOF #define led2_gpio GPIOF #define led2_pin (GPIO_Pin_7) #define led3_rcc RCC_APB2Periph_GPIOF #define led3_gpio GPIOF #define led3_pin (GPIO_Pin_8) #define led4_rcc RCC_APB2Periph_GPIOF #define led4_gpio GPIOF #define led4_pin (GPIO_Pin_9) extern struct rt_semaphore key_sem; static void rt_hw_led_init(void); void rt_hw_led_init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(led1_rcc|led2_rcc|led3_rcc|led4_rcc,ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Pin = led1_pin; GPIO_Init(led1_gpio, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = led2_pin; GPIO_Init(led2_gpio, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = led3_pin; GPIO_Init(led1_gpio, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = led4_pin; GPIO_Init(led2_gpio, &GPIO_InitStructure); } void led_thread_entry(void* paramete) { vu8 led_state = 0; rt_hw_led_init(); /* 无限循环*/ while (1) { /* 以永久等待方式获取信号量*/ rt_sem_take(&key_sem, RT_WAITING_FOREVER); /* 当得到信号量以后才有可能执行下面程序*/ led_state ^=1; if (led_state!=0) { GPIO_ResetBits(led1_gpio,led1_pin|led2_pin|led3_pin|led4_pin); rt_kprintf(" get semaphore ok, led all on \r\n"); } else { GPIO_SetBits(led1_gpio,led1_pin|led2_pin|led3_pin|led4_pin); rt_kprintf(" get semaphore ok, led all off \r\n"); } } }
在开发板上实际运行程序后,我们看到,信号量确实起到了按键线程和 led 线程之间的同步作用:只有当按键按下后, led 灯才会有动作。