【DIY教程】用D1实现提醒器
-
人体红外传感器坏了,那便手动设置GPIO吧,原理一样,硬件换上去就好了。
先看看效果图(没有UI)。。。
程序的大概组成:BOA实现web服务器,实现对提醒内容的配置。
LVGL程序实现UI,实现逻辑,蜂鸣器的,红外传感器的控制与读取。内核增加NFS支持
为了调试程序方便,打开NFS功能,方便板卡和服务器交换文件。
在
tina-d1-open/device/config/chips/d1/configs/nezha/linux-5.4
目录中,备份原始配置。cp config-5.4 config-5.4.bk
在
tina-d1-open/out/d1-nezha/compile_dir/target/linux-d1-nezha/linux-5.4.61
目录下make ARCH=riscv menuconfig #把如下选项打开 File systems ---> [*] Network File Systems ---> <*> NFS client support [*] NFS client support for NFS version 3 [*] NFS client support for the NFSv3 ACL protocol extension [*] NFS client support for NFS version 4 (EXPERIMENTAL) [*] NFS client support for NFSv4.1 (DEVELOPER ONLY)
修改完成后,将该目录下的
.config
复制为tina-d1-open/device/config/chips/d1/configs/nezha/linux-5.4/config-5.4
mboot;mkernel #重新编译uboot以及内核 make -j4 pack
增加NTP--网络对时
在tina-d1-open下执行如下:
source build/envsetup.sh lunch d1_nezha-tina make menuconfig
使用
/
可以在目录中进行查找,找到ntpd,打开后保存退出。make -j4 pack
LVGL支持
采用坛友的工程,在这个工程上进行修改。
链接:https://bbs.aw-ol.com/topic/303/哪吒d1开发板-lvgl7-源码下载-带git仓库/4
网页服务器
采用BOA作为网页服务器。
下载 boa-0.94.13.tar.gz
解压后进入src目录执行:
./configure --prefix=../../riscv-boa/ --host=riscv-linux
修改生成的Makefile
CC = riscv64-unknown-linux-gnu-gcc CPP = riscv64-unknown-linux-gnu-gcc -E
修改源码:
vi compat.h +120
#define TIMEZONE_OFFSET(foo) foo##->tm_gmtoff
编译后,生成的boa,复制到D1的/bin目录下,在D1根目录下新建
/WWW (这个目录下,放index.html)
/www/cgi-bin (这个目录下放运行cgi的bin文件)
/etc/boa/boa.conf //附件提供
运行时 可能会产生缺少mime.types的错误,直接将ubuntu的/etc/mime.types复制到D1的ETC目录。
HDMI的开关
//找到驱动定义 enum disp_output_type { DISP_OUTPUT_TYPE_NONE = 0, DISP_OUTPUT_TYPE_LCD = 1, DISP_OUTPUT_TYPE_TV = 2, DISP_OUTPUT_TYPE_HDMI = 4, DISP_OUTPUT_TYPE_VGA = 8, DISP_OUTPUT_TYPE_EDP = 32, /*16 for vdpo*/ };
打开HDMI
cd /sys/kernel/debug/dispdbg echo disp0 > name; echo switch1 > command; echo 4 10 0 0 0x4 0x101 0 0 0 8 > param; echo 1 > start;
关闭HDMI
cd /sys/kernel/debug/dispdbg echo disp0 > name; echo switch1 > command; echo 0 10 0 0 0x4 0x101 0 0 0 8 > param; echo 1 > start;
注意:echo 1 4 0 0 0x4 0x101 0 0 0 8 > param;——此处的第一个参数 1 代表MIPI-DSI输出,如果是要切换为HDMI输出,则改为 4,关闭则改为0
GPIO 操作
echo 65 > /sys/class/gpio/export echo out > /sys/class/gpio/gpio65/direction echo 1 > /sys/class/gpio/gpio65/value
web源码:
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>简易个人信息提醒器配置页面</title> </head> <body> <h1>简易个人信息提醒器配置页面</h1> <form name="form1" action="/cgi-bin/pass.cgi" method="POST"> <table> <tr> <td>提醒时间段0:</td> </tr> <tr> <td><input type="text" name="hour0"></td> <td>时</td> <td><input type="text" name="min0"></td> <td>分至</td> <td><input type="text" name="hour1"></td> <td>时</td> <td><input type="text" name="min1"></td> <td>分</td> </tr> <tr> <td>提醒内容:</td> </tr> <tr> <td><input type="text" name="data0"></td> </tr> <tr> <td>提醒时间段1:</td> </tr> <tr> <td><input type="text" name="hour2"></td> <td>时</td> <td><input type="text" name="min2"></td> <td>分至</td> <td><input type="text" name="hour3"></td> <td>时</td> <td><input type="text" name="min3"></td> <td>分</td> </tr> <tr> <td>提醒内容:</td> </tr> <tr> <td><input type="text" name="data1"></td> </tr> <tr> <td><input type="submit" value="提交"></td> </tr> </table> </form> </body> </html>
cgi程序源码:
#include <stdio.h> #include <stdlib.h> #include <string.h> char* getcgidata(FILE* fp, char* requestmethod); char ToChar(char a, char b) { char c = 0; if(a >= '0' && a <= '9') { c = a - '0'; } else if(a >= 'a' && a <= 'z') { c = a - 'a' + 10; } else if(a >= 'A' && a <= 'Z') { c = a - 'A' + 10; } if(b >= '0' && b <= '9') { c = c * 16 + b - '0'; } else if(b >= 'a' && b <= 'z') { c = c * 16 + b - 'a' + 10; } else if(b >= 'A' && b <= 'Z') { c = c * 16 + b - 'A' + 10; } return c; } int AToI(const char *src, char *des) { if(NULL == src || NULL == des) { return -1; } int i, j; int strLen = strlen(src); for(i = 0, j = 0; i < strLen; ) { if(src[i] == '%') { des[j++] = ToChar(src[i + 1], src[i + 2]); i += 3; } else { des[j++] = src[i++]; } } return 0; } int main() { char *input; char *req_method; int hour0,min0,hour1,min1,hour2,min2,hour3,min3; char data0[128] = {0}; char data1[128] = {0}; char utf8_data0[128] = {0}; char utf8_data1[128] = {0}; time_t *timep; printf("Content-type: text/html;charset=utf-8\n\n"); timep = malloc(sizeof(*timep)); time(timep); char *s = ctime(timep); printf("<br>当前时间:%s</br>", s); printf("<br>配置成功!</br>"); req_method = getenv("REQUEST_METHOD"); input = getcgidata(stdin, req_method); sscanf(input,"hour0=%d&min0=%d&hour1=%d&min1=%d&data0=%[^&]&hour2=%d&min2=%d&hour3=%d&min3=%d&data1=%s",&hour0, &min0, &hour1, &min1, data0, &hour2, &min2, &hour3, &min3, data1); AToI(data0, utf8_data0); AToI(data1, utf8_data1); printf("<br>从%d:%d到%d点%d提醒内容为:%s</br>", hour0, min0, hour1, min1, utf8_data0); printf("<br>从%d:%d到%d点%d提醒内容为:%s</br>", hour2, min2, hour3, min3, utf8_data1); free(input); return 0; } char* getcgidata(FILE* fp, char* requestmethod) { char* input; int len; int size = 1024; int i = 0; if (!strcmp(requestmethod, "GET")) { input = getenv("QUERY_STRING"); return input; } else if (!strcmp(requestmethod, "POST")) { len = atoi(getenv("CONTENT_LENGTH")); input = (char*)malloc(sizeof(char)*(size + 1)); if (len == 0) { input[0] = '\0'; return input; } while(1) { input[i] = (char)fgetc(fp); if (i == size) { input[i+1] = '\0'; return input; } --len; if (feof(fp) || (!(len))) { i++; input[i] = '\0'; return input; } i++; } } return NULL; }
lvgl 主要代码:
#include "lvgl/lvgl.h" #include "lv_drivers/display/fbdev.h" #include "lv_drivers/indev/evdev.h" #include "lv_examples/lv_examples.h" #include <unistd.h> #include <pthread.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #include <fcntl.h> #include <errno.h> #include <unistd.h> #include <time.h> #define DISP_DEVICE_SWITCH 0x0F enum disp_output_type { DISP_OUTPUT_TYPE_NONE = 0, DISP_OUTPUT_TYPE_LCD = 1, DISP_OUTPUT_TYPE_TV = 2, DISP_OUTPUT_TYPE_HDMI = 4, DISP_OUTPUT_TYPE_VGA = 8, DISP_OUTPUT_TYPE_EDP = 32, /*16 for vdpo*/ }; #define DISP_BUF_SIZE (80 * LV_HOR_RES_MAX) LV_FONT_DECLARE(myFont1); char read_data[512]; void IR_init(void) { system("echo 118 > /sys/class/gpio/export"); system("echo in > /sys/class/gpio/gpio118/direction"); } int getGpioValue(int n) { char path[64]; char value_str[3]; int fd; snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", n); fd = open(path, O_RDONLY); if (fd < 0) { perror("Failed to open gpio value for reading!"); return -1; } if (read(fd, value_str, 3) < 0) { perror("Failed to read value!"); return -1; } close(fd); return (atoi(value_str)); } void buzzer_on(void) { system("echo 65 > /sys/class/gpio/export"); system("echo out > /sys/class/gpio/gpio65/direction"); system("echo 1 > /sys/class/gpio/gpio65/value"); } void buzzer_off(void) { system("echo 65 > /sys/class/gpio/export"); system("echo out > /sys/class/gpio/gpio65/direction"); system("echo 0 > /sys/class/gpio/gpio65/value"); } int main(void) { IR_init(); /*LittlevGL init*/ lv_init(); /*Linux frame buffer device init*/ fbdev_init(); /*A small buffer for LittlevGL to draw the screen's content*/ static lv_color_t buf[DISP_BUF_SIZE]; /*Initialize a descriptor for the buffer*/ static lv_disp_buf_t disp_buf; lv_disp_buf_init(&disp_buf, buf, NULL, DISP_BUF_SIZE); /*Initialize and register a display driver*/ lv_disp_drv_t disp_drv; lv_disp_drv_init(&disp_drv); disp_drv.buffer = &disp_buf; disp_drv.flush_cb = fbdev_flush; lv_disp_drv_register(&disp_drv); static lv_style_t style1; lv_style_init(&style1); lv_style_set_bg_color(&style1, LV_STATE_DEFAULT, LV_COLOR_GRAY); lv_style_set_bg_opa(&style1, LV_STATE_DEFAULT, LV_OPA_50); lv_style_set_text_color(&style1, LV_STATE_DEFAULT, LV_COLOR_BLUE); lv_style_set_text_font(&style1, LV_STATE_DEFAULT, &myFont1); lv_obj_t * label = lv_label_create(lv_scr_act(), NULL); lv_obj_align(label, NULL, LV_ALIGN_CENTER, -650, -100); lv_obj_set_style_local_text_color(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_BLUE); lv_obj_set_style_local_text_font(label, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &myFont1); lv_obj_t * label1 = lv_label_create(lv_scr_act(), NULL); lv_obj_align(label1, NULL, LV_ALIGN_CENTER, -300, 200); lv_obj_set_style_local_text_color(label1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, LV_COLOR_RED); lv_obj_set_style_local_text_font(label1, LV_LABEL_PART_MAIN, LV_STATE_DEFAULT, &myFont1); int fd = open("/www/cgi-bin/web.log", O_RDONLY); if(fd < 0) { printf("error\n:%d\n", fd); } read(fd, read_data, sizeof(read_data)); printf("data:%s\n", read_data); close(fd); char time_now_data [256]; time_t *timep; struct tm *p; timep = malloc(sizeof(*timep)); time(timep); char *s = ctime(timep); p = localtime(timep); sprintf(time_now_data, "%s", s); lv_label_set_text(label1, time_now_data); int hour0, min0, hour1, min1; int hour2, min2, hour3, min3; char data0[256] = {}; char data1[256] = {}; sscanf(read_data,"%d:%d:%d:%d:%[^:]:%d:%d:%d:%d:%s",&hour0, &min0, &hour1, &min1, data0, &hour2, &min2, &hour3, &min3, data1); lv_label_set_text(label, data0); lv_task_handler(); int buzzer_status = 0; while(1) { sleep(1); int ir_status = getGpioValue(118); printf("check ir:%d\n", ir_status); if(ir_status == 1) { system("echo disp0 > /sys/kernel/debug/dispdbg/name"); system("echo switch1 > /sys/kernel/debug/dispdbg/command"); system("echo 4 10 0 0 0x4 0x101 0 0 0 8 > /sys/kernel/debug/dispdbg/param"); system("echo 1 > /sys/kernel/debug/dispdbg/start"); if(buzzer_status == 0) { buzzer_on(); buzzer_status = 1; sleep(2); buzzer_off(); } sleep(1); if(((p->tm_hour + 12) > hour0) && ((p->tm_hour + 12) < hour1)) { lv_label_set_text(label, data0); } if(((p->tm_hour + 12) > hour2) && ((p->tm_hour + 12) < hour3)) { lv_label_set_text(label, data1); } lv_task_handler(); sleep(10); } else if(ir_status == 0) { system("echo disp0 > /sys/kernel/debug/dispdbg/name"); system("echo switch1 > /sys/kernel/debug/dispdbg/command"); system("echo 0 10 0 0 0x4 0x101 0 0 0 8 > /sys/kernel/debug/dispdbg/param"); system("echo 1 > /sys/kernel/debug/dispdbg/start"); sleep(3); buzzer_status = 0; } } return 0; } /*Set in lv_conf.h as `LV_TICK_CUSTOM_SYS_TIME_EXPR`*/ uint32_t custom_tick_get(void) { static uint64_t start_ms = 0; if(start_ms == 0) { struct timeval tv_start; gettimeofday(&tv_start, NULL); start_ms = (tv_start.tv_sec * 1000000 + tv_start.tv_usec) / 1000; } struct timeval tv_now; gettimeofday(&tv_now, NULL); uint64_t now_ms; now_ms = (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000; uint32_t time_ms = now_ms - start_ms; return time_ms; }
新手上路。。。。。有待完善。。。。。
-
Copyright © 2024 深圳全志在线有限公司 粤ICP备2021084185号 粤公网安备44030502007680号