本次分享项目智能门铃的软件框架流程。通过按键和简单的菜单选择不同功能,菜单主要是四部分:
1、门外视频监控。可以在LCD屏上查看门外视屏图像。如果wifi连接成功,还可以同时登录他局域网IP地址查看。可以直接扫描LCD屏上二维码进入局域网监控,或者主动输入IP地址和端口号连接。
PS:这部分由于内存分配不足,LCD无法解码JPG文件数据并显示,后面再优化看看,如果实在不行只能阉割部分功能了。在这顺便说下在TjpgDec软件包的例程中没有对内存分配结果检查,导致开始调试显示图片的时候经常会死机,只能通过无线烧写器烧录初始固件。后面我才发现这个问题,修改了一下才没有再次死机。再就是增加了可以指定显示图片的初始XY坐标位置。
2、查看今日天气。通过webclient和CJSON获取和解析网络天气服务。使用的是心知天气服务,注册心知天气获取一个验证KEY。它的回复数据是JSON数据格式,很方便。
3、开关门记录和访客记录。待完成
4、WIFI声波配网。微信扫描小程序进入声波配网。接收到WIFI路由信息后自动联网并保存参数到SD卡文件中,上电初始化过程会检查是否有wifi配置文件,如果有就自动联网,没有的话直接进入配网界面。如果不想现在配网可以通过按键返回菜单,取消配网。
在声波配网程序那添加保存配网信息。
软件流程:
先在Main线程创建用户菜单显示操作线程User Thread。
User Thread内容:
1、初始化显示——》创建按键和GPIO扫描线程并创建按键邮箱——》创建WIFI连接事件和临时线程等待WIFI连接成功后需要处理的线程——》检查wifi配置——》有wifi配置时自动连接wifi,连接wifi成功后发送WIFI连接成功事件使临时线程继续,并进入主菜单界面。无WIFI配置时进入wifi配网菜单。——》循环等待按键邮箱,获取按键信息并进行相应处理。
进入视屏监控菜单——》创建局域网监控图片和LCD显示图片的线程,还可以通过长按按键保存照片到指定文件夹,按日期时间组合文件名保存。
进入今日天气——》创建定时器每隔10分钟获取一次天气数据。
进入WIFI声波配网——》显示声波配网小程序码,通过微信扫一扫,进入小程序配网。配网部分使用例程代码,在代码中配网成功后保存WIFI配置,自动联网,并在LCD屏上显示配网信息。
2、临时线程首先等待WIFI连接成功——》执行NTP网络服务进行RTC时间同步——》执行创建MQTT网络云连接服务上传信息——》线程结束退出。
3、按键和GPIO扫描线程。使用的是Multi_button软件包,初始化创建了一个邮箱,专门发送按键信息。线程内循环扫描操作按键IO、开关门IO、门铃按键,并发送邮箱数据。
4、NTP服务时间同步使用例程线程。
5、MQTT使用ONENET_MQTT软件包内例程线程。
部分代码:
主用户菜单线程
////////////////////////////////////////////////////////////
rt_event_t wificonn_event = RT_NULL;
#define WIFI_CONN_OK (1<<0)
//temp Thread
static void UserTempApp(void *arg)
{
char mqtt_cmd[]={"onenet_mqtt_init"};
char ntp_cmd[]={"ntp_sync"};
//等待WIFI连接
rt_event_recv(wificonn_event, WIFI_CONN_OK, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, RT_NULL);
//创建时间同步,天气获取,网络云mqtt连接
msh_exec(mqtt_cmd, strlen(mqtt_cmd)); //exec mqtt
msh_exec(ntp_cmd, strlen(ntp_cmd)); //exec ntp
rt_kprintf("ntp and mqtt running......................\n");
}
#define MENU_ITEM_NUM 5
extern uint8_t g_CurMenuIndex;
extern uint8_t g_CurMenuItem;
extern uint8_t MainFunInit(void);
extern uint8_t MainFunLoop(void);
extern uint8_t DoorVedioFunInit(void);
extern uint8_t DoorVedioFunLoop(void);
extern uint8_t WeatherFunInit(void);
extern uint8_t WeatherFunLoop(void);
extern uint8_t DoorReportFunInit(void);
extern uint8_t DoorReportFunLoop(void);
extern uint8_t WifiCfgFunInit(void);
extern uint8_t WifiCfgFunLoop(void);
typedef struct MenuFunCB
{
uint8_t (*MenuItemInit)(void);
uint8_t (*MenuItemFun)(void);
}MenuFunCB;
MenuFunCB MenuFun[MENU_ITEM_NUM]=
{
{MainFunInit,MainFunLoop},
{DoorVedioFunInit,DoorVedioFunLoop},
{WeatherFunInit,WeatherFunLoop},
{DoorReportFunInit,DoorReportFunLoop},
{WifiCfgFunInit,WifiCfgFunLoop},
};
static uint8_t _menu_state;
//User Main Thread
static void UserApp(void *arg)
{
lcd_clear(BLUE);
lcd_set_font(&Font_CH24X24);
lcd_set_font_color(RED,BLUE);
lcd_disp_str_at(66,4,"RT-Thread");
lcd_disp_str_at(24,28,"应用创新设计大赛");
lcd_disp_str_at(108,52,"By WoodData");
lcd_set_font(&Font_CH48X48);
lcd_set_font_color(RED,WHITE);
lcd_disp_str_at(24,80,"智能门铃");
lcd_set_font(&Font_CH24X24);
lcd_set_font_color(RED,WHITE);
lcd_disp_str_at(12,200,"21IC");
lcd_set_font_color(BLUE,WHITE);
lcd_disp_str_at(60,200,"电子网技术论坛");
lcd_set_font(&Font_ASCII16X8);
lcd_set_font_color(RED,WHITE);
lcd_disp_str_at(40,224,"https://bbs.21ic.com");
lcd_show_qrcode(87,130,4,2,"https://bbs.21ic.com",2);
//////////////////
key_init(); //创建按键扫描线程,及按键信息邮箱
//////////////////
wificonn_event = rt_event_create("wifi_conn_event", RT_IPC_FLAG_FIFO);
extern void user_callback_register(void);
user_callback_register();
///////////////////
rt_thread_t tid = RT_NULL;
/* Create background ticks thread */
tid = rt_thread_create("UserTemp", UserTempApp, RT_NULL, 1024, 11, 10);
if(tid != RT_NULL)
{
rt_thread_startup(tid);
}
//////////////////
char wifistr[] = {"wifi"};
int fd = 0;
//检测WIFI连接是否配置
fd = open(WIFI_SETTING_FN,O_RDONLY); //WIFI_SETTING_FN = "/sd/wificonnectcfg.json"
if(fd >= 0)
{
close(fd);
msh_exec(wifistr, strlen(wifistr)); //exec wifi link
rt_kprintf("wifi auto connect.\n");
g_CurMenuItem = 0;
g_CurMenuIndex = 0;
}else
{
rt_kprintf("Open wificonnectcfg.json failed!!!\n");
g_CurMenuItem = 4;
g_CurMenuIndex = 0;
}
_menu_state = 0;
rt_kprintf("Key Scan Thread..............................\n");
rt_thread_mdelay(3000);
while(1)
{
if(g_CurMenuItem < MENU_ITEM_NUM)
{
if(_menu_state == 0)
{
if(MenuFun[g_CurMenuItem].MenuItemInit() == 0)
{
_menu_state = 1;
}
}else
{
if(MenuFun[g_CurMenuItem].MenuItemFun() == 0)
{
_menu_state = 0;
}
}
}
}
}
菜单绘制代码
#include "time.h"
#include "rtthread.h"
#include <dfs.h>
#include <dfs_fs.h>
#if 1
#include "tjpgd.h"
#include "voice_config.h"
#include "lcd_font.h"
#include "key.h"
uint8_t g_CurMenuIndex;
uint8_t g_CurMenuItem;
void WifiCfgDraw(uint16_t index);
void MainPageDraw(uint16_t key);
extern void UserGetCurTime(struct tm *tm_new);
//////////////////////////////////////////////////////////////////////
void MainPageDraw(uint16_t key)
{
if(key&0x8000)
{
lcd_fill(0,0,240,48,BLUE);
lcd_fill(0,48,240,240,GBLUE);
lcd_set_font(&Font_CH48X48);
lcd_set_font_color(RED,BLUE);
lcd_disp_str_at(24,0,"智能门铃");
lcd_set_color(WHITE,BLACK);
lcd_draw_line(0,47,240,47);
}
lcd_set_font(&Font_CH32X32);
if(key&0x0001)
{
lcd_fill(0,48,240,80,BLUE);
lcd_set_font_color(BRED,BLUE);
lcd_disp_str_at(0,48,"视频监控");
}else
{
lcd_fill(0,48,240,80,GBLUE);
lcd_set_font_color(BRED,GBLUE);
lcd_disp_str_at(0,48,"视频监控");
}
if(key&0x0002)
{
lcd_fill(0,80,240,112,BLUE);
lcd_set_font_color(BRED,BLUE);
lcd_disp_str_at(0,80,"今日天气");
}else
{
lcd_fill(0,80,240,112,GBLUE);
lcd_set_font_color(BRED,GBLUE);
lcd_disp_str_at(0,80,"今日天气");
}
if(key&0x0004)
{
lcd_fill(0,112,240,144,BLUE);
lcd_set_font_color(BRED,BLUE);
lcd_disp_str_at(0,112,"开关门记录");
}else
{
lcd_fill(0,112,240,144,GBLUE);
lcd_set_font_color(BRED,GBLUE);
lcd_disp_str_at(0,112,"开关门记录");
}
if(key&0x0008)
{
lcd_fill(0,144,240,176,BLUE);
lcd_set_font_color(BRED,BLUE);
lcd_disp_str_at(0,144,"WIFI声波配网");
}else
{
lcd_fill(0,144,240,176,GBLUE);
lcd_set_font_color(BRED,GBLUE);
lcd_disp_str_at(0,144,"WIFI声波配网");
}
}
uint8_t MainFunInit(void )
{
MainPageDraw(0x8001);
return 0;
}
uint8_t MainFunLoop(void )
{
uint32_t keyvalue;
if(rt_mb_recv(key_mailbox,&keyvalue,RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("Key mailbox recv %0X.\n",keyvalue);
switch((keyvalue &0xffff0000)>>16)
{
case 0x0: //key_m
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
switch(g_CurMenuIndex)
{
case 0:
g_CurMenuIndex = 0;
g_CurMenuItem = 1;
break;
case 1:
g_CurMenuIndex = 0;
g_CurMenuItem = 2;
break;
case 2:
g_CurMenuIndex = 0;
g_CurMenuItem = 3;
break;
case 3:
g_CurMenuIndex = 0;
g_CurMenuItem = 4;
break;
}
return 0;
default:
break;
}
break;
case 0x1: //key_up
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
if(g_CurMenuIndex ) g_CurMenuIndex --;
else g_CurMenuIndex = 3;
MainPageDraw(0x0001<<g_CurMenuIndex);
rt_kprintf("index %u.\n",g_CurMenuIndex);
break;
default:
break;
}
break;
case 0x2: //key_down
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
g_CurMenuIndex++;
if(g_CurMenuIndex == 4) g_CurMenuIndex = 0;
MainPageDraw(0x0001<<g_CurMenuIndex);
rt_kprintf("index %u.\n",g_CurMenuIndex);
break;
default:
break;
}
break;
case 0x5: //门铃键
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x6: //开关门
break;
}
}
return 1;
}
/////////////////////////////////////////////////////
extern void show_photo_test(void);
extern void stop_photo(void);
extern void save_photo(void);
uint8_t DoorVedioFunInit(void)
{
lcd_fill(0,0,240,48,BLUE);
lcd_fill(0,48,240,240,GBLUE);
lcd_set_font(&Font_CH48X48);
lcd_set_font_color(RED,BLUE);
lcd_disp_str_at(0,0,"视频监控");
lcd_set_color(WHITE,BLACK);
lcd_draw_line(0,47,240,47);
show_photo_test();
return 0;
}
uint8_t DoorVedioFunLoop(void)
{
uint32_t keyvalue;
if(rt_mb_recv(key_mailbox,&keyvalue,RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("Key mailbox recv %0X.\n",keyvalue);
switch((keyvalue &0xffff0000)>>16)
{
case 0x0: //key_m
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
g_CurMenuIndex = 0;
g_CurMenuItem = 0;
stop_photo();
return 0;
case LONG_RRESS_START:
save_photo(); //Save jpg file
break;
default:
break;
}
break;
case 0x1: //key_up
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x2: //key_down
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x5: //门铃键
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x6: //开关门
break;
}
}
return 1;
}
/////////////////////////////////////////////////////
static void weather_timer_10min(void * para)
{
char argv[] = {"weather guangzhou"};
msh_exec(argv, strlen(argv)); //exec wifi link
}
static rt_timer_t weather_timer;
uint8_t WeatherFunInit(void)
{
char argv[] = {"weather guangzhou"};
lcd_fill(0,0,240,48,BLUE);
lcd_fill(0,48,240,240,GBLUE);
lcd_set_font(&Font_CH48X48);
lcd_set_font_color(RED,BLUE);
lcd_disp_str_at(0,0,"今日天气");
lcd_set_color(WHITE,BLACK);
lcd_draw_line(0,47,240,47);
weather_timer = rt_timer_create("weather timer",weather_timer_10min,RT_NULL, 10*60*RT_TICK_PER_SECOND,
RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER );
if(weather_timer != RT_NULL)
{
rt_timer_start(weather_timer);
}else
{
rt_kprintf("weather timer fail!!!\n");
}
msh_exec(argv, strlen(argv)); //exec wifi link
return 0;
}
uint8_t WeatherFunLoop(void)
{
uint32_t keyvalue;
if(rt_mb_recv(key_mailbox,&keyvalue,RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("Key mailbox recv %0X.\n",keyvalue);
switch((keyvalue &0xffff0000)>>16)
{
case 0x0: //key_m
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
g_CurMenuIndex = 0;
g_CurMenuItem = 0;
if(weather_timer != RT_NULL)
{
rt_timer_delete(weather_timer);
}
return 0;
default:
break;
}
break;
case 0x1: //key_up
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x2: //key_down
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x5: //门铃键
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x6: //开关门
break;
}
}
return 1;
}
/////////////////////////////////////////////////////
uint8_t DoorReportFunInit(void)
{
lcd_fill(0,0,240,48,BLUE);
lcd_fill(0,48,240,240,GBLUE);
lcd_set_font(&Font_CH48X48);
lcd_set_font_color(RED,BLUE);
lcd_disp_str_at(0,0,"开关门记录");
lcd_set_color(WHITE,BLACK);
lcd_draw_line(0,47,240,47);
return 0;
}
uint8_t DoorReportFunLoop(void)
{
uint32_t keyvalue;
if(rt_mb_recv(key_mailbox,&keyvalue,RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("Key mailbox recv %0X.\n",keyvalue);
switch((keyvalue &0xffff0000)>>16)
{
case 0x0: //key_m
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
g_CurMenuIndex = 0;
g_CurMenuItem = 0;
return 0;
default:
break;
}
break;
case 0x1: //key_up
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x2: //key_down
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x5: //门铃键
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x6: //开关门
break;
}
}
return 1;
}
///////////////////////////////////////////////////////
void WifiCfgDraw(uint16_t index)
{
if(index&0x8000)
{
lcd_fill(0,0,240,48,BLUE);
lcd_fill(0,48,240,240,GBLUE);
lcd_set_font(&Font_CH40X40);
lcd_set_font_color(RED,BLUE);
lcd_disp_str_at(0,0,"WIFI声波配网");
lcd_set_color(WHITE,BLACK);
lcd_draw_line(0,47,240,47);
}
if(index&0x0001)
{
lcd_set_font(&Font_CH16X16);
lcd_set_font_color(BRED,GBLUE);
lcd_disp_str_at(((240-16*7)>>1), 50 ,"打开微信扫一扫");
Decode_Jpg("/sd/voice_wifi.jpg",48,80);
}
}
uint8_t WifiCfgFunInit(void)
{
WifiCfgDraw(0x8001);
voice_config(0,NULL);
return 0;
}
uint8_t WifiCfgFunLoop(void)
{
uint32_t keyvalue;
if(rt_mb_recv(key_mailbox,&keyvalue,RT_WAITING_FOREVER) == RT_EOK)
{
rt_kprintf("Key mailbox recv %0X.\n",keyvalue);
switch((keyvalue &0xffff0000)>>16)
{
case 0x0: //key_m
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
g_CurMenuIndex = 0;
g_CurMenuItem = 0;
voice_config_stop();
rt_thread_mdelay(1000);
return 0;
default:
break;
}
break;
case 0x1: //key_up
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x2: //key_down
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x5: //门铃键
switch (keyvalue&0xffff)
{
case SINGLE_CLICK:
break;
default:
break;
}
break;
case 0x6: //开关门
break;
}
}
return 1;
}
////////////////////////////////////////////////
#endif
按键扫描
#include <rtthread.h>
#include <stdint.h>
#include <rtdevice.h>
#if 1
#include "key.h"
#define KEY_MID (13)
#define KEY_UP (28)
#define KEY_DOWN (19)
#define KEY_LEFT (12)
#define KEY_RIGHT (25)
rt_mailbox_t key_mailbox = RT_NULL;
typedef enum
{
KEY_M = 0, //Middle
KEY_U, //Up
KEY_D, //Down
KEY_L, //Left
KEY_R, //Right
KEY_NUM //key count
} user_button_t;
static struct button user_button[KEY_NUM];
uint32_t KeyValue;
static void btn_0_cb(void *btn)
{
rt_kprintf("btn_0_cb\n");
KeyValue = get_button_event((struct button *)btn);
switch(KeyValue)
{
case PRESS_DOWN:
rt_kprintf("button press down\n");
break;
case PRESS_UP:
rt_kprintf("button press up\n");
break;
case PRESS_REPEAT:
rt_kprintf("button press repeat\n");
break;
case SINGLE_CLICK:
rt_kprintf("button single click\n");
break;
case DOUBLE_CLICK:
rt_kprintf("button double click\n");
break;
case LONG_RRESS_START:
rt_kprintf("button long press start\n");
break;
case LONG_PRESS_HOLD:
rt_kprintf("button long press hold\n");
break;
}
rt_mb_send(key_mailbox,KeyValue);
}
static void btn_1_cb(void *btn)
{
rt_kprintf("btn_1_cb\n");
KeyValue = get_button_event((struct button *)btn);
KeyValue |= 0x010000;
rt_mb_send(key_mailbox,KeyValue);
}
static void btn_2_cb(void *btn)
{
rt_kprintf("btn_2_cb\n");
KeyValue = get_button_event((struct button *)btn);
KeyValue |= 0x020000;
rt_mb_send(key_mailbox,KeyValue);
}
static void btn_3_cb(void *btn)
{
rt_kprintf("btn_3_cb\n");
KeyValue = get_button_event((struct button *)btn);
KeyValue |= 0x030000;
rt_mb_send(key_mailbox,KeyValue);
}
static void btn_4_cb(void *btn)
{
rt_kprintf("btn_4_cb\n");
KeyValue = get_button_event((struct button *)btn);
KeyValue |= 0x040000;
rt_mb_send(key_mailbox,KeyValue);
}
////////////////////////////////////////////////////
//Key Read Value
static uint8_t key_mid_read(void)
{
return rt_pin_read(KEY_MID);
}
static uint8_t key_up_read(void)
{
return rt_pin_read(KEY_UP);
}
static uint8_t key_down_read(void)
{
return rt_pin_read(KEY_DOWN);
}
static uint8_t key_left_read(void)
{
return rt_pin_read(KEY_LEFT);
}
static uint8_t key_right_read(void)
{
return rt_pin_read(KEY_RIGHT);
}
//Key Scan Thread
static void button_scan(void *arg)
{
while(1)
{
/* 5ms */
rt_thread_delay(RT_TICK_PER_SECOND/200);
button_ticks();
}
}
int key_init(void)
{
int i;
rt_thread_t tid = RT_NULL;
rt_pin_mode(KEY_MID, PIN_MODE_INPUT_PULLUP); /* set KEY pin mode to input */
rt_pin_mode(KEY_UP, PIN_MODE_INPUT_PULLUP); /* set KEY pin mode to input */
rt_pin_mode(KEY_DOWN, PIN_MODE_INPUT_PULLUP); /* set KEY pin mode to input */
rt_pin_mode(KEY_LEFT, PIN_MODE_INPUT_PULLUP); /* set KEY pin mode to input */
rt_pin_mode(KEY_RIGHT, PIN_MODE_INPUT_PULLUP); /* set KEY pin mode to input */
//创建按键信息邮箱
key_mailbox = rt_mb_create("KeyMail",16*4,RT_IPC_FLAG_FIFO);
/* Create background ticks thread */
tid = rt_thread_create("KeyScan", button_scan, RT_NULL, 512, 15, 10);
if(tid != RT_NULL)
{
rt_thread_startup(tid);
}
/* low level drive */
button_init (&user_button[KEY_M], key_mid_read, PIN_LOW);
button_attach(&user_button[KEY_M], PRESS_DOWN, btn_0_cb);
button_attach(&user_button[KEY_M], PRESS_UP, btn_0_cb);
button_attach(&user_button[KEY_M], PRESS_REPEAT, btn_0_cb);
button_attach(&user_button[KEY_M], SINGLE_CLICK, btn_0_cb);
button_attach(&user_button[KEY_M], DOUBLE_CLICK, btn_0_cb);
button_attach(&user_button[KEY_M], LONG_RRESS_START, btn_0_cb);
button_attach(&user_button[KEY_M], LONG_PRESS_HOLD, btn_0_cb);
button_start (&user_button[KEY_M]);
button_init (&user_button[KEY_U], key_up_read, PIN_LOW);
button_attach(&user_button[KEY_U], PRESS_DOWN, btn_1_cb);
button_attach(&user_button[KEY_U], PRESS_UP, btn_1_cb);
button_attach(&user_button[KEY_U], PRESS_REPEAT, btn_1_cb);
button_attach(&user_button[KEY_U], SINGLE_CLICK, btn_1_cb);
button_attach(&user_button[KEY_U], DOUBLE_CLICK, btn_1_cb);
button_attach(&user_button[KEY_U], LONG_RRESS_START, btn_1_cb);
button_attach(&user_button[KEY_U], LONG_PRESS_HOLD, btn_1_cb);
button_start (&user_button[KEY_U]);
button_init (&user_button[KEY_D], key_down_read, PIN_LOW);
button_attach(&user_button[KEY_D], PRESS_DOWN, btn_2_cb);
button_attach(&user_button[KEY_D], PRESS_UP, btn_2_cb);
button_attach(&user_button[KEY_D], PRESS_REPEAT, btn_2_cb);
button_attach(&user_button[KEY_D], SINGLE_CLICK, btn_2_cb);
button_attach(&user_button[KEY_D], DOUBLE_CLICK, btn_2_cb);
button_attach(&user_button[KEY_D], LONG_RRESS_START, btn_2_cb);
button_attach(&user_button[KEY_D], LONG_PRESS_HOLD, btn_2_cb);
button_start (&user_button[KEY_D]);
button_init (&user_button[KEY_L], key_left_read, PIN_LOW);
button_attach(&user_button[KEY_L], PRESS_DOWN, btn_3_cb);
button_attach(&user_button[KEY_L], PRESS_UP, btn_3_cb);
button_attach(&user_button[KEY_L], PRESS_REPEAT, btn_3_cb);
button_attach(&user_button[KEY_L], SINGLE_CLICK, btn_3_cb);
button_attach(&user_button[KEY_L], DOUBLE_CLICK, btn_3_cb);
button_attach(&user_button[KEY_L], LONG_RRESS_START, btn_3_cb);
button_attach(&user_button[KEY_L], LONG_PRESS_HOLD, btn_3_cb);
button_start (&user_button[KEY_L]);
button_init (&user_button[KEY_R], key_right_read, PIN_LOW);
button_attach(&user_button[KEY_R], PRESS_DOWN, btn_4_cb);
button_attach(&user_button[KEY_R], PRESS_UP, btn_4_cb);
button_attach(&user_button[KEY_R], PRESS_REPEAT, btn_4_cb);
button_attach(&user_button[KEY_R], SINGLE_CLICK, btn_4_cb);
button_attach(&user_button[KEY_R], DOUBLE_CLICK, btn_4_cb);
button_attach(&user_button[KEY_R], LONG_RRESS_START, btn_4_cb);
button_attach(&user_button[KEY_R], LONG_PRESS_HOLD, btn_4_cb);
button_start (&user_button[KEY_R]);
return 0;
}
#endif
天气获取代码
/*
* File : httpclient.c
*
* Copyright (c) 2006-2018, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2018-07-20 flybreak first version
* 2018-09-05 flybreak Upgrade API to webclient latest version
*/
#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>
#include <dfs.h>
#include <dfs_fs.h>
#include <webclient.h> /* 浣跨敤 HTTP 鍗忚涓庢湇鍔″櫒閫氫俊闇€瑕佸寘鍚澶存枃锟?? */
#include <sys/socket.h> /* 浣跨敤BSD socket锛岄渶瑕佸寘鍚玸ocket.h澶存枃锟?? */
#include <netdb.h>
#include <cJSON.h>
#include "shell.h"
#include <finsh.h>
#if 1
#include "lcd_font.h"
#include "tjpgd.h"
#define GET_HEADER_BUFSZ 1024 //澶撮儴澶у皬
#define GET_RESP_BUFSZ 1024 //鍝嶅簲缂撳啿鍖哄ぇ
#define GET_URL_LEN_MAX 256 //缃戝潃鏈€澶ч暱
#define GET_URI "http://api.seniverse.com/v3/weather/now.json?key=%s&location=%s&language=en&unit=c" //蹇冪煡澶╂皵 API
#define AREA_NAME "guangzhou" //骞垮窞 ID
#define XINZHI_API_KEY "SaFaa9knM7IHfV5kl" //蹇冪煡澶╂皵璁よ瘉 pravite key
/* 澶╂皵鏁版嵁瑙f瀽 */
void weather_data_parse(rt_uint8_t *data)
{
cJSON *root = RT_NULL, *object = RT_NULL, *item = RT_NULL;
cJSON *arrayItem = RT_NULL,*subobject = RT_NULL;
char str[32];
/* set the background color and foreground color */
lcd_fill(0,48,240,240,GBLUE);
lcd_set_font_color(RED, GBLUE);
root = cJSON_Parse((const char *)data);
if (!root)
{
rt_kprintf("\nNo memory for cJSON root!\n");
return;
}
if((arrayItem = cJSON_GetObjectItem(root, "results")) != RT_NULL)
{
//int size = cJSON_GetArraySize(arrayItem); //鑾峰彇鏁扮粍涓璞′釜 3
if((object = cJSON_GetArrayItem(arrayItem,0)) != RT_NULL)//鑾峰彇鐖跺璞″唴
{
/* 鍖归厤瀛愬1 */
if((subobject = cJSON_GetObjectItem(object,"location")) != RT_NULL)
{
item = cJSON_GetObjectItem(subobject, "name");
rt_kprintf("\ncityName:%s \n", item->valuestring);
lcd_set_font(&Font_CH40X40);
lcd_disp_str_at(20, 48, "广州");
}
/* 鍖归厤瀛愬2 */
if((subobject = cJSON_GetObjectItem(object,"now")) != RT_NULL)
{
lcd_set_font(&Font_CH32X32);
item = cJSON_GetObjectItem(subobject, "text");
rt_kprintf("weather:%s \n", item->valuestring);
lcd_disp_str_at(0, 168, item->valuestring);
item = cJSON_GetObjectItem(subobject, "code");
rt_kprintf("code:%s \n", item->valuestring);
rt_snprintf(str,32,"/sd/weather120/%s.jpg",item->valuestring);
Decode_Jpg(str,120,48);
lcd_set_font(&Font_CH40X40);
item = cJSON_GetObjectItem(subobject, "temperature");
rt_kprintf("temperature:%s \n", item->valuestring);
rt_snprintf(str,32,"%s℃",item->valuestring);
lcd_disp_str_at(20, 128, str);
}
/* 鍖归厤瀛愬3 */
if((subobject = cJSON_GetObjectItem(object,"last_update")) != RT_NULL)
{
lcd_set_font(&Font_CH16X16);
lcd_disp_str_at(0, 200, "更新时间:");
rt_kprintf("time:%s \n", subobject->valuestring);
rt_memcpy(str,subobject->valuestring,19);
str[10] = 0x20;
str[19] = 0;
lcd_set_font(&Font_CH24X24);
lcd_disp_str_at(0, 216, str);
}
}
}
if (root != RT_NULL)
cJSON_Delete(root);
}
void weather(int argc, char **argv)
{
rt_uint8_t *buffer = RT_NULL;
int resp_status;
struct webclient_session *session = RT_NULL;
char *weather_url = RT_NULL;
int content_length = -1, bytes_read = 0;
int content_pos = 0;
/* weather_url 鍒嗛厤绌洪棿 */
weather_url = rt_calloc(1, GET_URL_LEN_MAX);
if (weather_url == RT_NULL)
{
rt_kprintf("No memory for weather_url!\n");
goto __exit;
}
/* 鎷兼帴 GET 缃戝潃 */
if(argc > 1)
{
rt_snprintf(weather_url, GET_URL_LEN_MAX, GET_URI,XINZHI_API_KEY, argv[1]);
}else
{
rt_snprintf(weather_url, GET_URL_LEN_MAX, GET_URI,XINZHI_API_KEY, AREA_NAME);
}
rt_kprintf(weather_url);
/* 鍒涘缓浼氳瘽骞朵笖璁剧疆鍝嶅簲鐨勫ぇ */
session = webclient_session_create(GET_HEADER_BUFSZ);
if (session == RT_NULL)
{
rt_kprintf("No memory for get header!\n");
goto __exit;
}
/* 锟?? GET 璇锋眰浣跨敤榛樿鐨勫ご */
if ((resp_status = webclient_get(session, weather_url)) != 200)
{
rt_kprintf("webclient GET request failed, response(%d) error.\n", resp_status);
lcd_set_font_color(RED, GBLUE);
lcd_set_font(&Font_CH40X40);
lcd_disp_str_at(0, 100, " WIFI未连接 ");
lcd_disp_str_at(0, 140, "请先连接WIFI");
goto __exit;
}
/* 鍒嗛厤鐢ㄤ簬瀛樻斁鎺ユ敹鏁版嵁鐨勭紦 */
buffer = rt_calloc(1, GET_RESP_BUFSZ);
if (buffer == RT_NULL)
{
rt_kprintf("No memory for data receive buffer!\n");
goto __exit;
}
content_length = webclient_content_length_get(session);
if (content_length < 0)
{
/* 杩斿洖鐨勬暟鎹槸鍒嗗潡浼犺緭. */
do
{
bytes_read = webclient_read(session, buffer, GET_RESP_BUFSZ);
if (bytes_read <= 0)
{
break;
}
}while (1);
}
else
{
do
{
bytes_read = webclient_read(session, buffer,
content_length - content_pos > GET_RESP_BUFSZ ?
GET_RESP_BUFSZ : content_length - content_pos);
if (bytes_read <= 0)
{
break;
}
content_pos += bytes_read;
}while (content_pos < content_length);
}
/* 澶╂皵鏁版嵁瑙f瀽 */
weather_data_parse(buffer);
__exit:
/* 閲婃斁缃戝潃绌洪棿 */
if (weather_url != RT_NULL)
rt_free(weather_url);
/* 鍏抽棴浼氳瘽 */
if (session != RT_NULL)
webclient_close(session);
/* 閲婃斁缂撳啿鍖虹┖ */
if (buffer != RT_NULL)
rt_free(buffer);
}
MSH_CMD_EXPORT(weather, Get weather by webclient);
#endif
视屏监控
/*
本例程实现摄像头拍摄图片解码后显示到 LCD 屏上
*/
#include <time.h>
#include <string.h>
#include "rtthread.h"
#include "include.h"
#include "app_demo_softap.h"
#include "video_transfer.h"
#include <sys/socket.h>
#include "netdb.h"
#include "lwip/netif.h"
//添加图片解码的头文件
#include "lcd_font.h"
#include "tjpgd.h"
//添加文件操作使用需要的头文�?
#include <dfs_posix.h>
static char* boundary_data = RT_NULL;
static rt_thread_t photo_tid1 = RT_NULL;
static const char resp_header[] =
"HTTP/1.1 200 OK\r\n"
"Content-Type: multipart/x-mixed-replace; boundary=------Boundary-------\r\n\r\n";
void UserGetCurTime(struct tm *tm_new)
{
time_t now;
struct tm *p_tm;
/* get current time */
now = time(RT_NULL);
/* lock scheduler. */
rt_enter_critical();
/* converts calendar time time into local time. */
p_tm = localtime(&now);
/* copy the statically located variable */
memcpy(tm_new, p_tm, sizeof(struct tm));
/* unlock scheduler. */
rt_exit_critical();
}
#if 0
static void hexdump(const rt_uint8_t *p, rt_size_t len)
{
unsigned char *buf = (unsigned char*)p;
int i, j;
rt_kprintf("Dump 0x%.8x %dBytes\n", (int)p, len);
rt_kprintf("Offset 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
for (i=0; i<len; i+=16)
{
rt_kprintf("%08X: ", i+(int)p);
for (j=0; j<16; j++)
{
if (i+j < len)
{
rt_kprintf("%02X ", buf[i+j]);
}
else
{
rt_kprintf(" ");
}
}
rt_kprintf(" ");
for (j=0; j<16; j++)
{
if (i+j < len)
{
rt_kprintf("%c", ((unsigned int)((buf[i+j]) - ' ') < 127u - ' ') ? buf[i+j] : '.');
}
}
rt_kprintf("\n");
}
}
#endif
// 创建 mjpeg 会话的结构体
static struct mjpeg_session
{
int sock;
int connected;
char* buf;
int total_len;
int last_frame_id;
int recv_frame_flag;
rt_tick_t old_tick;
rt_event_t event;
TVIDEO_SETUP_DESC_ST setup;
};
//初始�?
static struct mjpeg_session session = {0};
static void camera_start(void);
//定义一帧图片的大小
#define SEND_FRAME_EVENT (1 << 0)
#define SEND_FRAME_COMPLETE (1 << 1)
#define CLIENT_CONNECT (1 << 2)
#define PORT (5000)
static void get_ip(char* buf)
{
rt_ubase_t index;
struct netif * netif;
rt_enter_critical();
netif = netif_list;
while(netif != RT_NULL)
{
if(netif->flags & NETIF_FLAG_LINK_UP)
{
rt_kprintf("ip address: %s\n", ipaddr_ntoa(&(netif->ip_addr)));
memcpy(buf, ipaddr_ntoa(&(netif->ip_addr)), 16);
}
netif = netif->next;
}
rt_exit_critical();
}
static void tcpserv(void *parameter)
{
char *recv_data;
socklen_t sin_size;
struct sockaddr_in server_addr, client_addr;
int ret;
char ip[20] = {0};
if((session.sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
{
rt_kprintf("socket error\n");
goto __exit;
}
server_addr.sin_family = AF_INET;
server_addr.sin_port = htons(PORT);
server_addr.sin_addr.s_addr = INADDR_ANY;
rt_memset(&(server_addr.sin_zero), 0, sizeof(server_addr.sin_zero));
if(bind(session.sock, (struct sockaddr *)&server_addr, sizeof(struct sockaddr)) == -1)
{
rt_kprintf("unable to bind\n");
goto __exit;
}
if(listen(session.sock, 5) == -1)
{
rt_kprintf("listen error\n");
goto __exit;
}
get_ip(ip);
rt_kprintf("\nTCPServer Waiting for client on %s:%d...\n", ip, PORT);
session.connected = -1;
while(1)
{
sin_size = sizeof(struct sockaddr_in);
session.connected = accept(session.sock, (struct sockaddr *)&client_addr, &sin_size);
if(session.connected < 0)
{
rt_kprintf("accept connection failed! errno = %d\n", errno);
goto __exit;
}
rt_kprintf("I got a connection from (%s , %d)\n", inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port));
send(session.connected, resp_header, strlen(resp_header), 0);
rt_event_send(session.event, CLIENT_CONNECT);
}
__exit:
if(session.sock >= 0)
{
closesocket(session.sock);
session.sock = -1;
}
rt_kprintf("exit tcp server thread\n");
return ;
}
static void start_cb(void)
{
rt_kprintf("start cb\n");
}
static void stop_cb(void)
{
rt_kprintf("stop cb\n");
}
static void pkt_header_cb(TV_HDR_PARAM_PTR param)
{
HDR_PTR elem_tvhdr = (HDR_PTR)param->ptk_ptr;
elem_tvhdr->id = (UINT8)param->frame_id;
elem_tvhdr->is_eof = param->is_eof;
elem_tvhdr->pkt_cnt = param->frame_len;
elem_tvhdr->size = 0;
}
static int tvideo_capture_cb(UINT8 *data, UINT32 pos, UINT32 len, UINT8 is_stop)
{
rt_err_t ret = 0;
int temp = 0;
session.total_len = 0;
session.buf = data;
session.total_len += len;
rt_event_send(session.event, SEND_FRAME_EVENT);
return len;
}
static rt_uint8_t is_start = 0;
static void camera_start(void)
{
if(is_start == 1)
{
rt_kprintf("camera is already start\n");
return;
}
session.setup.send_type = TVIDEO_SND_INTF;
session.setup.send_func = tvideo_capture_cb;
session.setup.start_cb = NULL;
session.setup.end_cb = NULL;
session.setup.pkt_header_size = sizeof(HDR_ST);
session.setup.add_pkt_header = pkt_header_cb;
video_transfer_init(&session.setup);
is_start = 1;
}
static int start_flag = false;
static int save_file_flag = false;
static void showphoto_thread(void* param)
{
rt_thread_t tid1;
rt_err_t err;
uint32_t evt;
int ret;
uint8_t connect_ok = 0;
boundary_data = rt_malloc(1024);
if(boundary_data == RT_NULL)
{
rt_kprintf("malloc boundary_data failed\n");
goto __exit;
}
session.event = rt_event_create("vt_event", RT_IPC_FLAG_FIFO);
tid1 = rt_thread_create("tcpsrv", tcpserv, RT_NULL, 1024*4, 10, 10);
if(tid1 != RT_NULL)
{
rt_thread_startup(tid1);
}
camera_start();
while(1)
{
tvideo_capture(1);
rt_event_recv(session.event, SEND_FRAME_EVENT, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &evt);
if(connect_ok == 0)
{
err = rt_event_recv(session.event, CLIENT_CONNECT, RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_NO, &evt);
if(err == RT_EOK)
{
connect_ok = 1;
}
}
if((connect_ok) &&(session.connected >= 0))
{
// rt_kprintf("send data\n");
rt_memset(boundary_data, 0x0, 1024);
ret = rt_sprintf(boundary_data, "------Boundary-------\r\nContent-Type: image/jpeg\r\nContent-Length: %d\r\n\r\n", session.total_len);
// rt_kprintf("pic len : %d\n", session.total_len);
ret = send(session.connected, boundary_data, ret, 0);
// hexdump(session.buf, 16);
ret = send(session.connected, session.buf, session.total_len, 0);
if(ret <= 0)
{
if(session.connected >= 0) closesocket(session.connected);
session.connected = -1;
}
session.old_tick = rt_tick_get();
session.total_len = 0;
}
if(start_flag)
{
ret = mjpeg_decoder_jpeg(session.buf,40,120);
rt_kprintf("mjpeg_dec res = %d\n", ret);
}
if(save_file_flag)
{
//save *.jpg file
char file_name[128] = {0};
char timestr[64]={0};
int fd, res;
struct tm tm_new;
UserGetCurTime(&tm_new);
rt_sprintf(timestr, "%d_%d_%d-%d_%d_%d",tm_new.tm_year+1900,
tm_new.tm_mon+1,
tm_new.tm_mday,
tm_new.tm_hour,
tm_new.tm_min,
tm_new.tm_sec);
rt_sprintf(file_name, "/sd/video/%s.jpg",timestr);
rt_kprintf("filename = %s \n", file_name);
fd = open(file_name, O_WRONLY | O_CREAT);
if (fd >= 0)
{
write(fd, session.buf, session.total_len);
close(fd);
rt_kprintf("save %s ok!!!\n", file_name);
lcd_set_font(&Font_CH16X16);
lcd_set_font_color(BRED,GBLUE);
lcd_disp_str_at(0,64,"Save OK ");
}
else
{
rt_kprintf("save pic failed!!!\n");
lcd_set_font(&Font_CH16X16);
lcd_set_font_color(BRED,GBLUE);
lcd_disp_str_at(0,64,"Save Fail");
}
save_file_flag = false;
}
tvideo_capture(0);
//if(session.connected < 0) break;
}
rt_kprintf("showphoto_thread exit out!\n");
//video_transfer_deinit();
__exit:
if(session.buf != RT_NULL) rt_free(session.buf);
if(boundary_data != RT_NULL) rt_free(boundary_data);
is_start = 0;
photo_tid1 = RT_NULL;
return;
}
void start_photo(void)
{
char str[64] = {0};
char ip[20] = {0};
start_flag = true;
get_ip(ip);
rt_snprintf(str,64,"http://%s:%d",ip,PORT);
lcd_set_font(&Font_CH16X16);
lcd_set_font_color(BRED,GBLUE);
lcd_disp_str_at(0,48,&str[7]);
lcd_show_qrcode(168,48,4,2,str,2); //qr
}
void stop_photo(void)
{
start_flag = false;
}
void save_photo(void)
{
save_file_flag = true;
}
MSH_CMD_EXPORT(start_photo,start_photo);
MSH_CMD_EXPORT(stop_photo, stop_photo);
MSH_CMD_EXPORT(save_photo, save_photo);
void show_photo_test(void)
{
if(photo_tid1 == RT_NULL)
{
photo_tid1 = rt_thread_create("showphoto_thread", showphoto_thread, RT_NULL, 1024*4, 10, 10);
if(photo_tid1 != RT_NULL)
rt_thread_startup(photo_tid1);
}
start_photo();
}
MSH_CMD_EXPORT(show_photo_test,show camera photo);
|