树莓派led key开发

    xiaoxiao2024-01-08  162

    raspberry-key-led-controller

    input.c文件是利用sysfs导出的树莓派gpio内核驱动,来实现的按键检测、led控制程序。 具备按键去抖动,gpio防重复写入 使用到多线程、位图、poll()监测、sysfs、lrt库->定时器技术。

    邮箱:1650727278@qq.com 作者:唐公子 日期:2018.10.12 这个代码是之前就写了,然后由于需要在csdn上面做一些技术分析,所以粘贴过来,我这篇文章会对树莓派gpio驱动的开发很有帮助和启发意义。

    #include <stdlib.h> #include <stdio.h> #include <string.h> #include <unistd.h> #include <fcntl.h> #include <poll.h> #include <signal.h> #include <assert.h> #include <unistd.h> #include <time.h> #include <pthread.h> #include <sys/time.h> #define MSG(args ...) printf(args) #if 0 #define KEY2 27 #define KEY3 17 #define LED1 4 #define LED2 22 #define LED3 18 #define LED4 23 #endif #define KEY2 4 #define KEY3 17 #define LED1 27 #define LED2 2 #define LED3 18 #define LED4 3 #define LED1_LIGHT 1 #define LED1_OFF 0 #define LED2_LIGHT 0 #define LED2_OFF 1 #define LED3_LIGHT 0 #define LED3_OFF 1 #define LED4_LIGHT 0 #define LED4_OFF 1 struct gpio_tbl { unsigned int gpio; unsigned int dir; unsigned int init_level; unsigned int edge; }; //led 配置表 struct gpio_tbl led_tbl[] = { {LED1, 1, 0}, {LED2, 1, 0}, {LED3, 1, 0}, {LED4, 1, 0}, }; //按键 配置表 struct gpio_tbl key_tbl[] = { {KEY2, 0, 0, 2}, {KEY3, 0, 0, 2}, }; static int fd_key2, fd_key3; static unsigned char timer_active = 0; static signed char timer_key2_busy = -1, timer_key3_busy = -1; static timer_t timerid_key2, timerid_key3; static struct sigevent sev; static struct itimerspec its_key2, its_key3; #define FILTER_PERIOD 20 //unit: ms #define KEY2_PERIOD (5000 / FILTER_PERIOD) //unit: ms #define KEY3_PERIOD (5000 / FILTER_PERIOD) //unit: ms //static int expire_cnt2 = 0, expire_cnt3 = 0; #define errExit(msg) do { perror(msg); exit(EXIT_FAILURE); \ } while (0) static int gpio_export(int pin) { char buffer[64]; int len; int fd; fd = open("/sys/class/gpio/export", O_WRONLY); if (fd < 0) { MSG("Failed to open export for writing!\n"); return (-1); } len = snprintf(buffer, sizeof(buffer), "%d", pin); if (write(fd, buffer, len) < 0) { MSG("Failed to export gpio!\r\n"); return - 1; } close(fd); return 0; } static int gpio_unexport(int pin) { char buffer[64]; int len; int fd; fd = open("/sys/class/gpio/unexport", O_WRONLY); if (fd < 0) { //MSG("Failed to open unexport for writing!\n"); return - 1; } len = snprintf(buffer, sizeof(buffer), "%d", pin); if (write(fd, buffer, len) < 0) { //MSG("Failed to unexport gpio!"); return - 1; } close(fd); return 0; } //dir: 0-->IN, 1-->OUT static int gpio_direction(int pin, int dir) { static const char dir_str[] = "in\0out"; char path[64]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/direction", pin); fd = open(path, O_WRONLY); if (fd < 0) { MSG("Failed to open gpio[%d] direction for writing!\n", pin); return - 1; } if (write(fd, &dir_str[dir == 0 ? 0: 3], dir == 0 ? 2: 3) < 0) { MSG("Failed to set direction!\n"); return - 1; } close(fd); return 0; } //value: 0-->LOW, 1-->HIGH static int gpio_write(int pin, int value) { static const char values_str[] = "01"; char path[64]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin); fd = open(path, O_WRONLY); if (fd < 0) { MSG("Failed to open gpio[%d] value for writing!\n", pin); return - 1; } if (write(fd, &values_str[value == 0 ? 0: 1], 1) < 0) { MSG("Failed to write value [%d]!\n", value); return - 1; } close(fd); return 0; } static int gpio_read(int pin) { char path[64]; char value_str[3]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin); fd = open(path, O_RDONLY); if (fd < 0) { MSG("Failed to open gpio[%d] value for reading!\n", pin); return - 1; } if (read(fd, value_str, 3) < 0) { MSG("Failed to read value!\n"); return - 1; } close(fd); return (atoi(value_str)); } // none表示引脚为输入,不是中断引脚 // rising表示引脚为中断输入,上升沿触发 // falling表示引脚为中断输入,下降沿触发 // both表示引脚为中断输入,边沿触发 // 0-->none, 1-->rising, 2-->falling, 3-->both static int gpio_edge(int pin, int edge) { const char dir_str[] = "none\0rising\0falling\0both"; char ptr; char path[64]; int fd; switch (edge) { case 0: ptr = 0; break; case 1: ptr = 5; break; case 2: ptr = 12; break; case 3: ptr = 20; break; default: ptr = 0; } snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/edge", pin); fd = open(path, O_WRONLY); if (fd < 0) { MSG("Failed to open gpio[%d] edge for writing!\n", pin); return - 1; } if (write(fd, &dir_str[ptr], strlen(&dir_str[ptr])) < 0) { MSG("Failed to set edge!\n"); return - 1; } close(fd); return 0; } /** *函数功能: 释放led key资源 */ void sigint_hendler(int a) { int i; close(fd_key2); close(fd_key3); //printf("----------中断信号%d------------\r\n", a); for (i=0; i<sizeof(led_tbl) / sizeof(led_tbl[0]); i++) { gpio_unexport(led_tbl[i].gpio); } for (i=0; i<sizeof(key_tbl) / sizeof(key_tbl[0]); i++) { gpio_unexport(key_tbl[i].gpio); } exit(EXIT_SUCCESS); } void exit_handler(void) { int i; sigint_hendler(0); #if 0 //printf("----------中断信号%d------------\r\n", a); for (i=0; i<sizeof(led_tbl) / sizeof(led_tbl[0]); i++) { gpio_unexport(led_tbl[i].gpio); } for (i=0; i<sizeof(key_tbl) / sizeof(key_tbl[0]); i++) { gpio_unexport(key_tbl[i].gpio); } #endif exit(EXIT_SUCCESS); } /* 定时器回调函数 for key2*/ void key2_timer_handler() { int ret = -1; char buff[2]; static unsigned short low_cnt = 0, high_cnt = 0, shake_win = 0; //printf("timer expire\r\n"); //读取key2按键值 ret = lseek(fd_key2, 0, SEEK_SET); if (ret == -1) MSG("lseek\n"); ret = read(fd_key2, buff, 2); if (ret == -1) { MSG("read\n"); } else { if (0x5a == timer_key2_busy) { low_cnt = 0; high_cnt = 0; shake_win = 5; timer_key2_busy = 0xa5; } if (buff[0] == '1') { low_cnt++; if (high_cnt >= shake_win) { high_cnt -= shake_win; (shake_win > 1) ? (shake_win--) : shake_win; } } else if (buff[0] == '0'){ if (low_cnt >= shake_win) { low_cnt -= shake_win; (shake_win > 1) ? (shake_win--) : shake_win; } high_cnt++; } } if ((high_cnt > low_cnt) && (high_cnt > KEY2_PERIOD * 8 / 10)) { printf("------------key2按下,网关数据复位,仅保留缴费信息\r\n"); printf("--------------删除key2滤波定时器\r\n"); timer_delete(timerid_key2); timer_key2_busy = -1; timer_active &= ~0x02; } else if (low_cnt > KEY2_PERIOD * 1 / 10) { printf("------------key2弹起\r\n"); printf("--------------删除key2滤波定时器\r\n"); timer_delete(timerid_key2); timer_key2_busy = -1; timer_active &= ~0x02; } //exit(EXIT_SUCCESS); return; } /* 定时器回调函数 for key3 */ void key3_timer_handler() { int ret = -1; char buff[2]; static unsigned short low_cnt = 0, high_cnt = 0, shake_win = 0; //printf("timer expire\r\n"); //读取key2按键值 ret = lseek(fd_key3, 0, SEEK_SET); if (ret == -1) MSG("lseek\n"); ret = read(fd_key3, buff, 2); if (ret == -1) { MSG("read\n"); } else { if (0x5a == timer_key3_busy) { low_cnt = 0; high_cnt = 0; shake_win = 5; timer_key3_busy = 0xa5; } if (buff[0] == '0') { low_cnt++; if (high_cnt >= shake_win) { high_cnt -= shake_win; (shake_win > 1) ? (shake_win--) : shake_win; } } else if (buff[0] == '1'){ if (low_cnt >= shake_win) { low_cnt -= shake_win; (shake_win > 1) ? (shake_win--) : shake_win; } high_cnt++; } } if ((high_cnt > low_cnt) && (high_cnt > KEY3_PERIOD * 8 / 10)) { printf("------------key3按下,管理员密码重置\r\n"); printf("--------------删除key3滤波定时器\r\n"); timer_delete(timerid_key3); timer_key3_busy = -1; timer_active &= ~0x04; } else if (low_cnt > KEY3_PERIOD * 1 / 10) { printf("------------key3弹起\r\n"); printf("--------------删除key3滤波定时器\r\n"); timer_delete(timerid_key3); timer_key3_busy = -1; timer_active &= ~0x04; } //exit(EXIT_SUCCESS); return; } static void timer_handler() { if (timer_active & 0x02) { key2_timer_handler(); } if (timer_active & 0x04) { key3_timer_handler(); } } typedef struct __led_status{ unsigned char gateway_type; //1,主网关 0,辅网关 unsigned char online; //1,连接到服务器 0,未连接到服务器 2,tcpip数据流过 unsigned char dhcp; //1,dhcp开 0,dhcp关 unsigned char ziege_all_online; //1,zigbee节点全部在线 0,有zigbee节点掉线 }LED_STATUS; LED_STATUS led_status; void * led_thread(void *arg) { static LED_STATUS prev_state= {0xff, 0xff, 0xff, 0xff}; while(1) { printf("------led thread \r\n"); switch(led_status.gateway_type) { case 0: printf("--------辅助网关\r\n"); if (led_status.gateway_type != prev_state.gateway_type) { gpio_write(LED1, LED1_OFF); prev_state.gateway_type = led_status.gateway_type; } break; case 1: printf("--------主网关\r\n"); if (led_status.gateway_type != prev_state.gateway_type) { gpio_write(LED1, LED1_LIGHT); prev_state.gateway_type = led_status.gateway_type; } break; default: led_status.gateway_type = 0; break; } switch (led_status.online) { case 0: printf("--------未连接到服务器\r\n"); if (led_status.online != prev_state.online) { gpio_write(LED2, LED2_OFF); prev_state.online = led_status.online; } break; case 1: printf("--------已连接到服务器\r\n"); if (led_status.online != prev_state.online) { gpio_write(LED2, LED2_LIGHT); prev_state.online = led_status.online; } break; case 2: printf("--------有tcpip数据流\r\n"); //flash break; default: led_status.online = 0; break; } switch(led_status.dhcp) { case 0: printf("--------dhcp关\r\n"); if (led_status.dhcp != prev_state.dhcp) { gpio_write(LED3, LED3_OFF); prev_state.dhcp = led_status.dhcp; } break; case 1: printf("--------dhcp开\r\n"); if (led_status.dhcp != prev_state.dhcp) { gpio_write(LED3, LED3_LIGHT); prev_state.dhcp = led_status.dhcp; } break; default: led_status.dhcp = 0; break; } switch (led_status.ziege_all_online) { case 0: printf("--------zigbee节点掉线\r\n"); if (led_status.ziege_all_online != prev_state.ziege_all_online) { gpio_write(LED4, LED4_OFF); prev_state.ziege_all_online = led_status.ziege_all_online; } break; case 1: printf("--------zigbee节点全部在线\r\n"); if (led_status.ziege_all_online != prev_state.ziege_all_online) { gpio_write(LED4, LED4_LIGHT); prev_state.ziege_all_online = led_status.ziege_all_online; } break; default: led_status.ziege_all_online = 0; break; } printf("\r\n"); usleep(1000000); } return NULL; } /** * gcc input.c -lrt -lpthread */ int main() { pthread_t pid; int arg = 123; pthread_create(&pid, NULL, led_thread, &arg); //#if 1 int ret; //int a = sysconf(_SC_ATEXIT_MAX); //printf("ATEXIT_MAX = %ld\n", a); ret = atexit(exit_handler); if (ret != 0) { fprintf(stderr, "cannot set exit function\n"); exit(EXIT_FAILURE); } //#else struct sigaction s; memset(&s, 0, sizeof(s)); s.sa_handler = sigint_hendler; sigfillset(&s.sa_mask); //s.sa_flags |= SA_RESTART; assert(sigaction(SIGINT, &s, NULL) != 1); //#endif /* 注册key2定时器信号回调函数 */ sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGUSR1; sev.sigev_value.sival_ptr = &timerid_key2; signal(SIGUSR1, timer_handler); /* 注册key3定时器信号回调函数 */ sev.sigev_notify = SIGEV_SIGNAL; sev.sigev_signo = SIGUSR1; sev.sigev_value.sival_ptr = &timerid_key3; signal(SIGUSR1, timer_handler); struct pollfd fds[2]; char buff[64]; unsigned char cnt = 0; //打开LED资源 int i; for (i=0; i<sizeof(led_tbl) / sizeof(led_tbl[0]); i++) { gpio_export(led_tbl[i].gpio); gpio_direction(led_tbl[i].gpio, led_tbl[i].dir); gpio_write(led_tbl[i].gpio, led_tbl[i].init_level); } //打开按键资源 for (i=0; i<sizeof(key_tbl) / sizeof(key_tbl[0]); i++) { gpio_export(key_tbl[i].gpio); gpio_direction(key_tbl[i].gpio, key_tbl[i].dir); gpio_edge(key_tbl[i].gpio, key_tbl[i].edge); } //打开按键2 sprintf(buff, "/sys/class/gpio/gpio%d/value", KEY2); fd_key2 = open(buff, O_RDONLY); if (fd_key2 < 0) { MSG("Failed to open value!\n"); return - 1; } //打开按键3 sprintf(buff, "/sys/class/gpio/gpio%d/value", KEY3); fd_key3 = open(buff, O_RDONLY); if (fd_key2 < 0) { close(fd_key2); MSG("Failed to open value!\n"); return - 1; } fds[0].fd = fd_key2; fds[0].events = POLLPRI; fds[1].fd = fd_key3; fds[1].events = POLLPRI; ret = read(fd_key2, buff, 10); if (ret == -1) MSG("read\n"); ret = read(fd_key3, buff, 10); if (ret == -1) MSG("read\n"); while (1) { ret = poll(fds, 2, -1); //MSG("------------------------------\r\n"); if (ret == -1) { //MSG("poll\n"); continue; } if (fds[0].revents & POLLPRI) { //MSG("--------key2 input event occured--------\r\n"); ret = lseek(fd_key2, 0, SEEK_SET); if (ret == -1) MSG("lseek\n"); ret = read(fd_key2, buff, 10); if (ret == -1) { //MSG("read key2 fail\n"); } else { //MSG("read key2 ok\n"); } if (-1 == timer_key2_busy) { timer_key2_busy = 0x5a; timer_active |= 0x02; /* 创建定时器 */ if (timer_create(CLOCK_MONOTONIC, &sev, &timerid_key2) == -1) { errExit("timer_create"); } else { printf("-------------创建key2滤波定时器\r\n"); } /* 设置定时器时间参数超时1s */ memset(&its_key2, 0, sizeof(struct itimerspec)); its_key2.it_value.tv_sec = 0; its_key2.it_value.tv_nsec = FILTER_PERIOD * 1000 * 1000; its_key2.it_interval.tv_sec = its_key2.it_value.tv_sec; its_key2.it_interval.tv_nsec = its_key2.it_value.tv_nsec; /* 启动定时器 */ if (timer_settime(timerid_key2, 0, &its_key2, NULL) == -1) { errExit("timer_settime"); } } } else { //MSG("--------------end----------------\r\n"); } if (fds[1].revents & POLLPRI) { //MSG("--------key3 input event occured--------\r\n"); ret = lseek(fd_key3, 0, SEEK_SET); if (ret == -1) MSG("lseek\n"); ret = read(fd_key3, buff, 10); if (ret == -1) { //MSG("read key2 fail\n"); } else { //MSG("read key2 ok\n"); } if (-1 == timer_key3_busy) { timer_key3_busy = 0x5a; timer_active |= 0x04; /* 创建定时器 */ if (timer_create(CLOCK_MONOTONIC, &sev, &timerid_key3) == -1) { errExit("timer_create"); } else { printf("-------------创建key3滤波定时器\r\n"); } /* 设置定时器时间参数超时1s */ memset(&its_key3, 0, sizeof(struct itimerspec)); its_key3.it_value.tv_sec = 0; its_key3.it_value.tv_nsec = FILTER_PERIOD * 1000 * 1000; its_key3.it_interval.tv_sec = its_key3.it_value.tv_sec; its_key3.it_interval.tv_nsec = its_key3.it_value.tv_nsec; /* 启动定时器 */ if (timer_settime(timerid_key3, 0, &its_key3, NULL) == -1) { errExit("timer_settime"); } } } else { //MSG("--------------end----------------\r\n"); } } close(fd_key2); close(fd_key3); pthread_join(pid, NULL); return 0; }

    email:1650727278@qq.com 画笔

    最新回复(0)