• 【ElfBoard】基于 Linux 的智能家居小项目


    大家好,我是 Hello阿尔法,这段时间参与了保定飞凌嵌入式技术有限公司举办的 ElfBoard 共创社招募活动,并有幸成为了一名共创官,官方寄来了一块 ELF 1 开发板,开箱看这里 ELF 1 开箱初体验

    作为共创官,我使用 ELF 1 完成了一个智能家居的小项目。除了 ELF 1 开发板之外,还使用了一块其他厂商的 Linux 开发板 IMX6U,主要原因是在多次抽奖中都没有抽中显示屏,只有我的 IMX6U 有屏幕,其实这样也正好符合项目背景,带有屏幕的 IMX6U 作为智能家居的控制面板,ELF 1 作为被控终端设备,它可以是电灯、电扇、空调器,也可以是冰箱、彩电、洗衣机……实现效果如下图所示:

    项目简介

    IMX6U 模拟智能家居中的主控面板,实时刷新显示时间、天气、空气质量、温湿度等信息,实现对家居设备电灯、窗帘、通风扇的控制,天气数据来自于心知天气;ELF 1 模拟终端设备,三个 LED 分别代表电灯、窗帘、通风扇,ADC 模拟空气质量检测器,温湿度则用来检测环境中的温湿度。IMX6U 和 ELF 1 两者通过以太网实现交互,ELF 1 和 IMX6U 均基于 Linux 系统开发,资源使用情况如下所示:

    • ELF 1 开发板:3 个 LED、ADC、温湿度传感器、以太网口
    • IMX6U 开发板:5inch RGB 显示屏、以太网口

    IMX6U 工程

    • IMX6U 源码工程结构如图所示:

    app

    // weather.c
    int weather_init(void)
    {
        weather_client_fd = client_init_socket();
        /* 组合 GET 请求 */
        sprintf(weather_buffer, GET_REQUEST_PACKAGE, DAILY_JSON, API_KEY, WUHAN);
        /* 发送请求 */
        client_send_data(weather_client_fd, weather_buffer, strlen(weather_buffer));
        /* 接收天气数据 JSON 格式*/
        client_receive_data(weather_client_fd, weather_json, &weather_json_size);
        /* 解析天气数据 */
        cJSON_Daily_WeatherParse(weather_json, &Weather_now);
        /* 更新天气显示 */
        memset(weather_buffer, 0, BUFFER_SIZE);
        sprintf(weather_buffer, "%s / %s", Weather_now.text_day[0], Weather_now.text_night[0]);
        lv_label_set_text(ui_TextDay, weather_buffer);
        lv_label_set_text(ui_MinTemp, Weather_now.low[0]);
        lv_label_set_text(ui_MaxTemp, Weather_now.high[0]);
        lv_label_set_text(ui_outHum, Weather_now.humidity[0]);
        /* 更新天气图片 */
        int code = *Weather_now.code_day[0] - 48;
        switch (code)
        {
        case 0: lv_img_set_src(ui_weatherImg, &ui_img_icons_00_png); break;
        ...
        
        ...
        case 99: lv_img_set_src(ui_weatherImg, &ui_img_icons_99_png); break;
        default: break;
        }
    
        client_close_socket(weather_client_fd);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 以按键为例,实现数据打包、发送相关代码:
    static void led_ryg_turn(int cmd, int code)
    {
        /* 组合命令 */
        msg_frame_t led_msg_frame;
        led_msg_frame.type = LED_RYG;
        led_msg_frame.cmd = cmd;
        led_msg_frame.code = code;
        led_msg_frame.datalen = 0;
        /* 打包命令 */
        msg_buf_t *_msg_buf = pkg_frame(&led_msg_frame);
        /* 发送按键命令 */
        server_send_data(client_fd, (char *)_msg_buf->buf_ptr, _msg_buf->buf_size);
    }
    
    static void btn1_click_cb(lv_event_t *event) 
    {
        printf("Button1 clicked\n");
        static char flag = 0;
    
        if(flag == 0)
        {
            flag = 1;
            led_ryg_turn(LED_R, LED_ON);
        }
        else
        {
            flag = 0;
            led_ryg_turn(LED_R, LED_OFF);
        }
    }
    
    static void btn2_click_cb(lv_event_t *event) 
    {
        // ...
    }
    
    static void btn3_click_cb(lv_event_t *event) 
    {
        // ...
    }
    
    int button_init(void)
    {
        lv_obj_add_event_cb(ui_Button1, btn1_click_cb, LV_EVENT_CLICKED, NULL);
        lv_obj_add_event_cb(ui_Button2, btn2_click_cb, LV_EVENT_CLICKED, NULL);
        lv_obj_add_event_cb(ui_Button3, btn3_click_cb, LV_EVENT_CLICKED, NULL);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 数据接收、解析、命令执行相关代码:
    static int ctrl_dev_aht20(msg_frame_t *_msg_pack)
    {
        // ...
        
        return 0;
    }
    
    static int ctrl_dev_adc(msg_frame_t *_msg_pack)
    {
        printf("--- ctrl_dev_adc ---\r\n");
    
        uint16_t adc_raw = (uint16_t)(_msg_pack->data[0] << 8) + _msg_pack->data[1];
        uint8_t pm2_5 = adc_raw / 16;
        char pm2_5_src[4];
    
        printf("adc raw value: %d, pm2_5 value: %d \r\n", adc_raw, pm2_5);
    
        lv_arc_set_value(ui_Air, pm2_5);
    
        snprintf(pm2_5_src, sizeof(pm2_5_src), "%d", pm2_5);
        lv_label_set_text(ui_AirValue, pm2_5_src);
    
        return 0;
    }
    
    static int ctrl_cmd_func(const msg_pkg_t *_msg_pkg)
    {
        printf("--- ctrl_cmd_func ---\r\n");
        
        switch(_msg_pkg->pkg->type)
        {
            case AHT20: ctrl_dev_aht20(_msg_pkg->pkg); break;
            case ADC: ctrl_dev_adc(_msg_pkg->pkg); break;
            default: return -1;
        }
    
        return 0; 
    }
    
    static void *recv_thread(void *arg)
    {
        recv_msg_buf->buf_ptr=recv_msg_buf->buf;
        while(1)
        {
            if(server_receive_data(client_fd, (char *)recv_msg_buf->buf_ptr, (ssize_t *)&recv_msg_buf->buf_size) == 0)
            {
                printf("thread recv \r\n");
                msg_buf_print(recv_msg_buf);
                /* 解析数据包命令 */
                msg_pkg_t *_msg_pkg = unpkg_frame(recv_msg_buf->buf_ptr, recv_msg_buf->buf_size);
                /* 执行命令 */
                ctrl_cmd_func(_msg_pkg);
            } 
        }
        return NULL;
    }
    
    /* 线程创建 */
    pthread_create(&recv_thread_id, NULL, recv_thread, NULL);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    ELF 1 工程

    • ELF 1 源码工程结构如图所示:

    • src 文件夹存放源文件,inc 文件夹存放头文件,obj 为编译输出目录;
    • 客户端创建、数据打包、发送、接收、命令执行与 IMX6U 工程实现类似,不再介绍,数据采集、LED 控制采用文件操作实现。

    功能演示

    更多内容

  • 相关阅读:
    YOLO目标检测——口罩规范佩戴数据集+已标注xml和txt格式标签下载分享
    脉冲发生器助力雷达系统开发的关键应用
    配置一个nextjs_react项目
    每日一题leetcode--删除并获得点数(DP)
    NET 6 实现滑动验证码(三)、接口
    【VTK】关于VTK图像的系列功能
    Matlab图像处理基础(2):区域处理,边沿检测
    RL — 强化学习算法概述
    【深度学习】DDoS-Detection-Challenge aitrans2024 入侵检测,基于机器学习(深度学习)判断网络入侵
    Rookit系列二【文件隐藏】【支持Win7 x32/x64 ~ Win10 x32/x64平台的NTFS文件系统】
  • 原文地址:https://blog.csdn.net/weixin_44550536/article/details/136345525