当前位置:   article > 正文

【开源】嵌入式Linux(IMX6U)应用层综合项目(2)--智能家居APP

【开源】嵌入式Linux(IMX6U)应用层综合项目(2)--智能家居APP

目录

1.简介

1.1功能介绍

1.2技术栈介绍

1.3演示视频

1.4硬件介绍

2.软件设计

2.1智能家居UI设计

2.2.main函数

3.结尾(附网盘链接)


1.简介

此文章并不是教程,只能当作笔者的学习分享,只会做一些简单的介绍,其他的各位结合着代码和运行现象自己分析吧,相信通过函数名和注释,基本上是不难看懂代码的,其中涉及到的一些技术栈,也请各位学习到的时候多查阅资料。

本篇的内容为嵌入式Linux应用层的一个综合性比较强的项目,结尾会将源码放在网盘中开源出来,笔者能力有限,只是简单的把功能实现了,代码开源供大家一起交流学习,有什么好的建议,请各位一定不吝赐教!!!

1.1功能介绍

项目包括了四个app:

1.云平台的调试窗口,用于查看订阅主题所下发的数据,另一个为输入Json格式的数据来控制STM32单片机上的外设。

2.智能家居的界面,有4个图片按钮用于控制STM32板子上的LED灯、门(舵机)、蜂鸣器,量计分别为温度、湿度和亮度的值,同样是STM32获取发布到云平台的。

3.通过一个摄像头模块做的一个相机功能,可以拍照、录像,以及查看拍摄的照片,和播放录制视频的回放。

4.简易的音乐播放器:能够切换歌曲,以及暂停播放音乐。

1.2技术栈介绍

虽然项目简单,但是所涉及到的技术栈还是比较杂,我简单在此列出:

 1.LVGL库用于绘制UI。

2.MQTT协议,连接阿里云平台与STM32通讯。

3.alsa库用于音频处理。

4.LED、BEEP

5.V4L2 摄像头应用编程

1.3演示视频

【开源】嵌入式Linux应用层物联网小项目|通过MQTT协议与STM32通讯_哔哩哔哩_bilibili

1.4硬件介绍

硬件使用的是正点原子的阿尔法开发板,芯片是IMX6U,类似开发板应该都可以运行。

2.软件设计

2.1智能家居UI设计

主要的内容就是创建了4个开关按键分别对应STM32的LED、舵机、蜂鸣器的控制,第4个空调的按键还没有去完善它。以及3个度量针,用于显示STM32上传传感器数据,对应温度、湿度和光度。

  1. #include "ui_app_smarthome.h"
  2. lv_anim_t temp_anim, light_anim, humi_anim;
  3. lv_obj_t *temp_bar = NULL, *light_bar = NULL, *humi_arc = NULL;
  4. lv_obj_t *temp_bar_label, *light_bar_label, *humi_arc_label;
  5. g_sensor_t g_sensor;
  6. extern void *mqtt_handle;
  7. extern char *pub_topic;
  8. void ui_draw_contrl_bar(lv_coord_t x, lv_coord_t y, const char *t_lab, const char *b_lab, const lv_img_dsc_t *img, const lv_color_t value)
  9. {
  10. ui_draw_backgroud_bar(x, y, 170, 180, value);
  11. lv_obj_t *top_lab = lv_label_create(lv_scr_act());
  12. lv_label_set_text(top_lab, t_lab);
  13. static lv_style_t top_lab_style;
  14. lv_style_init(&top_lab_style);
  15. lv_style_set_text_font(&top_lab_style, &lv_font_montserrat_16); // 设置字体
  16. lv_style_set_text_color(&top_lab_style, lv_color_hex(MY_UI_COLOR_BLUE)); // 设置字体颜色
  17. lv_obj_add_style(top_lab, &top_lab_style, LV_PART_MAIN);
  18. lv_obj_align(top_lab, LV_ALIGN_TOP_LEFT, x + 30, y + 20);
  19. lv_obj_t *img_light_obj = lv_img_create(lv_scr_act());
  20. lv_img_set_src(img_light_obj, img);
  21. lv_obj_set_size(img_light_obj, 64, 64);
  22. lv_obj_align(img_light_obj, LV_ALIGN_TOP_LEFT, x + 15, y + 55);
  23. lv_obj_t *button_lab = lv_label_create(lv_scr_act());
  24. lv_label_set_text(button_lab, b_lab);
  25. static lv_style_t button_lab_style;
  26. lv_style_init(&button_lab_style);
  27. lv_style_set_text_font(&button_lab_style, &lv_font_montserrat_16); // 设置字体
  28. lv_style_set_text_color(&button_lab_style, lv_color_hex(MY_UI_COLOR_BLACK)); // 设置字体颜色
  29. lv_obj_add_style(button_lab, &button_lab_style, LV_PART_MAIN);
  30. lv_obj_align(button_lab, LV_ALIGN_TOP_LEFT, x + 30, y + 140);
  31. }
  32. static lv_obj_t *slider_label;
  33. static void slider_event_cb(lv_event_t *e)
  34. {
  35. lv_obj_t *slider = lv_event_get_target(e);
  36. char buf[8];
  37. lv_snprintf(buf, sizeof(buf), "%d°C", (int)lv_slider_get_value(slider));
  38. lv_label_set_text(slider_label, buf);
  39. lv_obj_align_to(slider_label, slider, LV_ALIGN_OUT_TOP_MID, 25, 65);
  40. }
  41. static void smarthome_light_btn_cb(lv_event_t *e)
  42. {
  43. int res;
  44. char *pub_payload = "{\"LED\":1}";
  45. lv_event_code_t code = lv_event_get_code(e);
  46. lv_obj_t *obj = lv_event_get_target(e);
  47. if (code == LV_EVENT_VALUE_CHANGED)
  48. {
  49. LV_UNUSED(obj);
  50. LV_LOG_USER("State: %s\n", lv_obj_has_state(obj, LV_STATE_CHECKED) ? "On" : "Off");
  51. res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)strlen(pub_payload), 0);
  52. if (res < 0)
  53. {
  54. printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
  55. return -1;
  56. }
  57. }
  58. }
  59. static void smarthome_door_btn_cb(lv_event_t *e)
  60. {
  61. int res;
  62. char *pub_payload = "{\"door\":2}";
  63. lv_event_code_t code = lv_event_get_code(e);
  64. lv_obj_t *obj = lv_event_get_target(e);
  65. if (code == LV_EVENT_VALUE_CHANGED)
  66. {
  67. LV_UNUSED(obj);
  68. LV_LOG_USER("State: %s\n", lv_obj_has_state(obj, LV_STATE_CHECKED) ? "On" : "Off");
  69. res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)strlen(pub_payload), 0);
  70. if (res < 0)
  71. {
  72. printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
  73. return -1;
  74. }
  75. }
  76. }
  77. static void smarthome_beep_btn_cb(lv_event_t *e)
  78. {
  79. int res;
  80. char *pub_payload = "{\"beep\":3}";
  81. lv_event_code_t code = lv_event_get_code(e);
  82. lv_obj_t *obj = lv_event_get_target(e);
  83. if (code == LV_EVENT_VALUE_CHANGED)
  84. {
  85. LV_UNUSED(obj);
  86. LV_LOG_USER("State: %s\n", lv_obj_has_state(obj, LV_STATE_CHECKED) ? "On" : "Off");
  87. res = aiot_mqtt_pub(mqtt_handle, pub_topic, (uint8_t *)pub_payload, (uint32_t)strlen(pub_payload), 0);
  88. if (res < 0)
  89. {
  90. printf("aiot_mqtt_sub failed, res: -0x%04X\n", -res);
  91. return -1;
  92. }
  93. }
  94. }
  95. void ui_smarthome_create_contrl_switch(void)
  96. {
  97. lv_obj_t *light_sw;
  98. light_sw = lv_switch_create(lv_scr_act());
  99. lv_obj_set_size(light_sw, 60, 40);
  100. lv_obj_align(light_sw, LV_ALIGN_TOP_LEFT, 240, 80);
  101. lv_obj_add_event_cb(light_sw, smarthome_light_btn_cb, LV_EVENT_ALL, NULL);
  102. lv_obj_t *door_sw;
  103. door_sw = lv_switch_create(lv_scr_act());
  104. lv_obj_set_size(door_sw, 60, 40);
  105. lv_obj_align(door_sw, LV_ALIGN_TOP_LEFT, 430, 80);
  106. lv_obj_add_event_cb(door_sw, smarthome_door_btn_cb, LV_EVENT_ALL, NULL);
  107. lv_obj_t *beep_sw;
  108. beep_sw = lv_switch_create(lv_scr_act());
  109. lv_obj_set_size(beep_sw, 60, 40);
  110. lv_obj_align(beep_sw, LV_ALIGN_TOP_LEFT, 240, 280);
  111. lv_obj_add_event_cb(beep_sw, smarthome_beep_btn_cb, LV_EVENT_ALL, NULL);
  112. lv_obj_t *air_slider = lv_slider_create(lv_scr_act());
  113. lv_bar_set_range(air_slider, 16, 30);
  114. lv_obj_set_size(air_slider, 10, 120);
  115. lv_obj_align(air_slider, LV_ALIGN_TOP_LEFT, 450, 290);
  116. lv_obj_add_event_cb(air_slider, slider_event_cb, LV_EVENT_VALUE_CHANGED, NULL);
  117. slider_label = lv_label_create(lv_scr_act());
  118. lv_label_set_text(slider_label, "16°C");
  119. lv_obj_align_to(slider_label, air_slider, LV_ALIGN_OUT_TOP_MID, 25, 65);
  120. }
  121. static void set_temp(void *bar, int32_t temp)
  122. {
  123. lv_bar_set_value(bar, temp, LV_ANIM_ON);
  124. // 更新温度标签的文本
  125. if (temp_bar_label != NULL)
  126. {
  127. char temp_str[32];
  128. snprintf(temp_str, sizeof(temp_str), "%d°C", temp);
  129. lv_label_set_text(temp_bar_label, temp_str);
  130. }
  131. }
  132. static void set_light(void *bar, int32_t light)
  133. {
  134. lv_bar_set_value(bar, light, LV_ANIM_ON);
  135. // 更新温度标签的文本
  136. if (light_bar_label != NULL)
  137. {
  138. char light_str[32];
  139. snprintf(light_str, sizeof(light_str), "%dlux", light);
  140. lv_label_set_text(light_bar_label, light_str);
  141. }
  142. }
  143. static void set_humi(void *arc, int32_t humi)
  144. {
  145. lv_arc_set_value(arc, humi);
  146. // 更新温度标签的文本
  147. if (humi_arc_label != NULL)
  148. {
  149. char humi_str[32];
  150. snprintf(humi_str, sizeof(humi_str), "%d%%", humi);
  151. lv_label_set_text(humi_arc_label, humi_str);
  152. }
  153. }
  154. static void temp_update_callback(lv_timer_t *timer)
  155. {
  156. // 读取新的温度值
  157. int32_t new_temp = (int32_t)g_sensor.temp_value;
  158. // printf("new_temp = %d\n", new_temp);
  159. int32_t cur_temp = lv_bar_get_value(temp_bar);
  160. // printf("cur_temp = %d\n", cur_temp);
  161. // 更新动画的目标值
  162. lv_anim_set_values(&temp_anim, cur_temp, new_temp);
  163. // 启动动画
  164. lv_anim_start(&temp_anim);
  165. }
  166. static void light_update_callback(lv_timer_t *timer)
  167. {
  168. int32_t new_light = (int32_t)g_sensor.light_value;
  169. // printf("new_light = %d\n", new_light);
  170. // // 检查light_bar对象是否有效
  171. // if (light_bar == NULL) {
  172. // printf("Error: light_bar is NULL\n");
  173. // return;
  174. // }
  175. int32_t cur_light = lv_bar_get_value(light_bar);
  176. // printf("cur_light = %d\n", cur_light);
  177. // 更新动画的目标值
  178. lv_anim_set_values(&light_anim, cur_light, new_light);
  179. // 启动动画
  180. lv_anim_start(&light_anim);
  181. }
  182. static void humi_update_callback(lv_timer_t *timer)
  183. {
  184. int32_t new_humi = (int32_t)g_sensor.humi_value;
  185. printf("new_humi = %d\r\n", new_humi);
  186. if (humi_arc == NULL)
  187. {
  188. printf("Error: humi_arc is NULL\n");
  189. return;
  190. }
  191. int32_t cur_humi = lv_arc_get_value(humi_arc);
  192. printf("cur_humi = %d\r\n", cur_humi);
  193. // 更新动画的目标值
  194. lv_anim_set_values(&humi_anim, cur_humi, new_humi);
  195. lv_anim_start(&humi_anim);
  196. }
  197. void create_temp_update_timer(void)
  198. {
  199. lv_timer_create(temp_update_callback, 5000, NULL); // 每5秒更新一次
  200. }
  201. void create_light_update_timer(void)
  202. {
  203. lv_timer_create(light_update_callback, 5000, NULL); // 每5秒更新一次
  204. }
  205. void create_humi_update_timer(void)
  206. {
  207. lv_timer_create(humi_update_callback, 5000, NULL); // 每5秒更新一次
  208. }
  209. void ui_smarthome_create_rec_data(void)
  210. {
  211. /* 1.温度计UI */
  212. static lv_style_t temp_scr_act;
  213. lv_style_init(&temp_scr_act);
  214. lv_style_set_bg_opa(&temp_scr_act, LV_OPA_COVER);
  215. lv_style_set_bg_color(&temp_scr_act, lv_palette_main(LV_PALETTE_RED));
  216. temp_bar = lv_bar_create(lv_scr_act());
  217. lv_obj_add_style(temp_bar, &temp_scr_act, LV_PART_INDICATOR);
  218. lv_obj_set_size(temp_bar, 20, 150);
  219. lv_obj_align(temp_bar, LV_ALIGN_TOP_LEFT, 600, 90);
  220. lv_bar_set_range(temp_bar, 0, 40);
  221. // 动画设置
  222. lv_anim_init(&temp_anim);
  223. lv_anim_set_exec_cb(&temp_anim, (lv_anim_exec_xcb_t)set_temp);
  224. lv_anim_set_time(&temp_anim, 1000); // 动画时间1秒
  225. lv_anim_set_var(&temp_anim, temp_bar);
  226. lv_anim_set_repeat_count(&temp_anim, 0); // 只执行一次
  227. LV_IMG_DECLARE(img_temp_48);
  228. lv_obj_t *temp_img = lv_img_create(lv_scr_act());
  229. lv_img_set_src(temp_img, &img_temp_48);
  230. lv_obj_align_to(temp_img, temp_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
  231. lv_obj_set_size(temp_img, 48, 48);
  232. temp_bar_label = lv_label_create(lv_scr_act());
  233. lv_label_set_text(temp_bar_label, "0°C");
  234. // 创建一个样式并设置字体大小
  235. static lv_style_t temp_label_style;
  236. lv_style_init(&temp_label_style);
  237. lv_style_set_text_font(&temp_label_style, &lv_font_montserrat_24); // 设置字体
  238. // 将样式应用到标签
  239. lv_obj_add_style(temp_bar_label, &temp_label_style, LV_PART_MAIN);
  240. // 对齐标签到温度条
  241. lv_obj_align_to(temp_bar_label, temp_bar, LV_ALIGN_OUT_TOP_MID, 0, 0);
  242. // 创建定时器更新温度
  243. create_temp_update_timer();
  244. /* 2.亮度计UI */
  245. static lv_style_t light_scr_act;
  246. lv_style_init(&light_scr_act);
  247. lv_style_set_bg_opa(&light_scr_act, LV_OPA_COVER);
  248. lv_style_set_bg_color(&light_scr_act, lv_palette_main(LV_PALETTE_YELLOW));
  249. light_bar = lv_bar_create(lv_scr_act());
  250. lv_obj_add_style(light_bar, &light_scr_act, LV_PART_INDICATOR);
  251. lv_obj_set_size(light_bar, 20, 150);
  252. lv_obj_align(light_bar, LV_ALIGN_TOP_LEFT, 680, 90);
  253. lv_bar_set_range(light_bar, 0, 200);
  254. lv_anim_init(&light_anim);
  255. lv_anim_set_exec_cb(&light_anim, (lv_anim_exec_xcb_t)set_light);
  256. lv_anim_set_time(&light_anim, 1000); // 动画时间1秒
  257. lv_anim_set_var(&light_anim, light_bar);
  258. lv_anim_set_repeat_count(&light_anim, 0); // 只执行一次
  259. LV_IMG_DECLARE(img_light_48);
  260. lv_obj_t *light_img = lv_img_create(lv_scr_act());
  261. lv_img_set_src(light_img, &img_light_48);
  262. lv_obj_align_to(light_img, light_bar, LV_ALIGN_OUT_BOTTOM_MID, 0, 10);
  263. lv_obj_set_size(light_img, 48, 48);
  264. light_bar_label = lv_label_create(lv_scr_act());
  265. lv_label_set_text(light_bar_label, "0lux");
  266. // 创建一个样式并设置字体大小
  267. static lv_style_t light_label_style;
  268. lv_style_init(&light_label_style);
  269. lv_style_set_text_font(&light_label_style, &lv_font_montserrat_24); // 设置字体
  270. // 将样式应用到标签
  271. lv_obj_add_style(light_bar_label, &light_label_style, LV_PART_MAIN);
  272. // 对齐标签到温度条
  273. lv_obj_align_to(light_bar_label, light_bar, LV_ALIGN_OUT_TOP_MID, 0, 0);
  274. create_light_update_timer();
  275. /* 3.湿度计UI */
  276. static lv_style_t humi_scr_act;
  277. lv_style_init(&humi_scr_act);
  278. // 创建一个圆弧对象
  279. humi_arc = lv_arc_create(lv_scr_act());
  280. lv_obj_add_style(humi_arc, &humi_scr_act, LV_PART_MAIN);
  281. lv_obj_set_size(humi_arc, 150, 150); // 设置圆弧的尺寸
  282. lv_obj_align(humi_arc, LV_ALIGN_TOP_LEFT, 580, 320); // 设置圆弧的位置
  283. lv_arc_set_range(humi_arc, 0, 100); // 设置圆弧的范围,比如0到100的亮度值
  284. lv_arc_set_bg_angles(humi_arc, 135, 45); // 设置背景圆弧的角度范围
  285. lv_arc_set_angles(humi_arc, 0, 0); // 设置当前值的圆弧角度
  286. lv_arc_set_value(humi_arc, 0);
  287. lv_obj_remove_style(humi_arc, NULL, LV_PART_KNOB); /*Be sure the knob is not displayed*/
  288. // 设置指示器样式
  289. static lv_style_t arc_indicator_style;
  290. lv_style_init(&arc_indicator_style);
  291. lv_style_set_line_color(&arc_indicator_style, lv_palette_main(LV_PALETTE_YELLOW)); // 设置线条颜色为黄色
  292. lv_style_set_line_width(&arc_indicator_style, 8); // 设置线条宽度
  293. lv_obj_add_style(humi_arc, &arc_indicator_style, LV_PART_INDICATOR); // 将指示器样式应用到圆弧
  294. LV_IMG_DECLARE(img_humi_48);
  295. lv_obj_t *humi_img = lv_img_create(lv_scr_act());
  296. lv_img_set_src(humi_img, &img_humi_48);
  297. lv_obj_align_to(humi_img, humi_arc, LV_ALIGN_OUT_BOTTOM_MID, 0, -40);
  298. lv_obj_set_size(humi_img, 48, 48);
  299. humi_arc_label = lv_label_create(lv_scr_act());
  300. lv_label_set_text(humi_arc_label, "0%");
  301. static lv_style_t humi_label_style;
  302. lv_style_init(&humi_label_style);
  303. lv_style_set_text_font(&humi_label_style, &lv_font_montserrat_24); // 设置字体
  304. lv_obj_add_style(humi_arc_label, &humi_label_style, LV_PART_MAIN);
  305. lv_obj_align_to(humi_arc_label, humi_arc, LV_ALIGN_OUT_TOP_MID, 0, 75);
  306. // 设置动画
  307. lv_anim_init(&humi_anim);
  308. lv_anim_set_var(&humi_anim, humi_arc);
  309. lv_anim_set_exec_cb(&humi_anim, (lv_anim_exec_xcb_t)set_humi);
  310. lv_anim_set_time(&humi_anim, 1000); // 动画时间1秒
  311. lv_anim_set_repeat_count(&humi_anim, 0); // 只执行一次
  312. create_humi_update_timer();
  313. printf("humi_arc created successfully: %p\n", (void *)humi_arc);
  314. }
  315. void ui_app_smarthome(void)
  316. {
  317. // ui_app_clear_area();
  318. clear_area(0, 0, 800, 480, lv_color_hex(MY_UI_COLOR_DEEP_WHITE));
  319. ui_left_app_bar(20, 70);
  320. lv_obj_t *img = lv_img_create(lv_scr_act());
  321. lv_img_set_src(img, &img_smarthome_on);
  322. lv_obj_align(img, LV_ALIGN_TOP_LEFT, 32, 180);
  323. lv_obj_t *mid_label = lv_label_create(lv_scr_act());
  324. lv_label_set_text(mid_label, "SmartHome");
  325. static lv_style_t mid_label_style;
  326. lv_style_init(&mid_label_style);
  327. lv_style_set_text_font(&mid_label_style, &lv_font_montserrat_24); // 设置字体
  328. lv_style_set_text_color(&mid_label_style, lv_color_hex(MY_UI_COLOR_BLACK)); // 设置字体颜色
  329. lv_obj_add_style(mid_label, &mid_label_style, LV_PART_MAIN);
  330. lv_obj_align(mid_label, LV_ALIGN_TOP_MID, 0, 20);
  331. ui_draw_contrl_bar(160, 70, "off", "light", &img_light, lv_color_hex(MY_UI_COLOR_WHITE));
  332. ui_draw_contrl_bar(350, 70, "off", "door", &img_door, lv_color_hex(MY_UI_COLOR_WHITE));
  333. ui_draw_contrl_bar(160, 270, "off", "beep", &img_beep, lv_color_hex(MY_UI_COLOR_WHITE));
  334. ui_draw_contrl_bar(350, 270, "off", "air", &img_kongtiao, lv_color_hex(MY_UI_COLOR_WHITE));
  335. ui_smarthome_create_contrl_switch();
  336. ui_smarthome_create_rec_data();
  337. }

2.2.main函数

ui_app_smarthome()函数在ui_main.c中被调用,当用户点击其图片按钮,才会切换到此app下。

  1. void ui_page_main(void)
  2. {
  3. destroy_previous_objects();
  4. lv_obj_set_style_bg_color(lv_scr_act(), lv_color_hex(MY_UI_COLOR_DEEP_WHITE), LV_PART_MAIN);
  5. ui_left_app_bar(20, 70);
  6. if (app_index == UI_APP_YUNPINTAI)
  7. {
  8. ui_app_yunpintai();
  9. }
  10. else if (app_index == UI_APP_SMARTHOME)
  11. {
  12. ui_app_smarthome();
  13. }
  14. else if (app_index == UI_APP_CAMERA)
  15. {
  16. ui_app_camera();
  17. }
  18. else if (app_index == UI_APP_MUSIC)
  19. {
  20. ui_app_music();
  21. }
  22. }
  23. void *ds_ui_page_thread(void *args)
  24. {
  25. ui_page_main();
  26. // setup_time_update();
  27. while (1)
  28. {
  29. lv_task_handler();
  30. usleep(5000);
  31. }
  32. return NULL;
  33. }

3.结尾(附网盘链接)

链接:百度网盘 请输入提取码

提取码:2jia

--来自百度网盘超级会员V5的分享

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/923042
推荐阅读
相关标签
  

闽ICP备14008679号