打印
[uCOS/RTOS]

【RTOS】RT-Thread创新大赛——基于麻雀一号的智能门铃(二)

[复制链接]
2416|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
    本次分享项目智能门铃的软件框架流程。通过按键和简单的菜单选择不同功能,菜单主要是四部分:
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);








使用特权

评论回复

相关帖子

沙发
WoodData|  楼主 | 2020-6-14 15:02 | 只看该作者


终于搞定了LCD和网页同时显示了。

使用特权

评论回复
板凳
ly87802541| | 2020-6-17 13:24 | 只看该作者
很牛X,可视门铃鸭

使用特权

评论回复
地板
hu9jj| | 2020-6-18 19:15 | 只看该作者
好思路,学习了。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

119

主题

4603

帖子

27

粉丝