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

作为共创官,我使用 ELF 1 完成了一个智能家居的小项目。除了 ELF 1 开发板之外,还使用了一块其他厂商的 Linux 开发板 IMX6U,主要原因是在多次抽奖活动中都没有抽中 Elfboard 的官方显示屏,只有我的 IMX6U 有屏幕。

其实这样也正好符合智能家居的项目背景,带有屏幕的 IMX6U 作为智能家居的主控面板,ELF 1 作为被控终端设备,它可以是电灯、电扇、空调器,也可以是冰箱、彩电、洗衣机……实现效果如下图所示:

项目简介

IMX6U 开发板模拟智能家居中的主控面板,GUI 设计采用开源的 LVGL,实时刷新显示时间、天气、室内空气质量、温湿度等信息,实现对家居设备电灯、窗帘、通风扇的控制,天气数据来自于心知天气 API,使用 cJSON 对天气数据进行解析。

ELF 1 开发板模拟终端设备,三个 LED 分别代表电灯、窗帘、通风扇,电位器(ADC)模拟室内空气质量检测器,温湿度传感器则用来检测环境中的温湿度。

IMX6U 和 ELF 1 两者通过以太网实现数据交互,均基于 Linux 系统开发,两个开发板的资源使用情况总体如下所示:

IMX6U 开发板:5inch RGB 800×480 显示屏、以太网口ELF 1 开发板:3 个 LED、电位器(ADC)、温湿度传感器、以太网口

IMX6U 工程

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

IMX6U 源码工程以 LVGL 的 Linux 移植工程为基础,具体实现请阅读 嵌入式 Linux 下的 LVGL 移植;app 文件夹存放应用源码;build 文件夹为编译输出目录;ui 文件夹存放 UI 界面源码,具体实现请阅读 基于 LVGL 使用 SquareLine Studio 快速设计 UI 界面。

app

app 文件夹包括有 cJSON 解析器、通信协议 Protocol、网络编程接口 Socket、天气获取、按键以及时间、温湿度数据更新等;cJSON 是使用了一个开源的、C 语言编写的超轻量级 JSON 解析器;关于 Protocol 具体请阅读 一个简洁实用的自定义通信协议;socket 文件夹主要内容为 TCP 服务端和客户端的创建,请阅读 Linux 下 socket 编程介绍、Linux 下使用 socket 实现 TCP 服务端、Linux 下使用 socket 实现 TCP 客户端;天气数据通过心知天气 API 获取,相关实现代码如下:

// weather.c

int weather_init(void)

{

int weather_client_fd = 0;

int weather_json_size = 0;

/* 创建客户端 */

weather_client_fd = client_init_socket();

/* 组合请求包 */

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);

/* 打印天气信息 */

weather_show_data();

/* 更新天气显示 */

weather_update_ui();

/* 关闭客户端 */

client_close_socket(weather_client_fd);

return 0;

}

以按键为例,实现数据打包、发送相关代码:

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;

}

数据接收、解析、命令执行相关代码:

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);

ELF 1 工程

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

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

功能演示

抖音视频链接

更多内容

CSDN博客:@Hello阿尔法哔哩哔哩:@Hello阿尔法知乎:@Hello阿尔法

参考阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: