从零开始学习FreeRTOS之在STM32上移植FreeRTOS(五)
这次我们已经将上次的屏幕换成了240*320的触摸屏,不知道怎么移植触摸屏的可以看我的另一篇文章:
电容触摸屏移植: 电容触摸屏移植
注意每个卖家卖的触摸屏驱动IC不一定一样,但是通讯方式都是大同小异的,所以记得问卖家要资料,然后再根据通讯方式修改。
本期我们要实现的目标是用GUI_guider软件实现一个温控灯界面,还可以显示温度和湿度的界面框架。
一、 GUI_GUIDER的安装
安装包链接如下:
GUI_GUIDER官网链接: GUI_GUIDER官网链接
离线安装包如下:
GUI_GUIDER离线安装包: GUI_GUIDER离线安装包
建议大家还是用官网链接,因为LVGL的版本一直在变,新的和旧的可能不兼容。
打开界面是这样的:
从上到下分别是:创建一个新项目,打开一个最近的项目,导入一个当地的项目。我们先创建一个新项目。
版本选择8.3.10
这里可以选择你的运行环境,因为NXP公司自己也出板子,所以这里提供了很多他们公司自己的板子。但是我们现在用的是STM32,所以我们就选Simulator(仿真)
在这里可以选择很多软件提供的DEMO,我这里用的是EMPTY_UI。
再点击creat就可以成功创建出来了。
你可以在软件右上角将语言调成中文。
二、 用GUI_GUIDER设计UI界面
- 开始创建容器。
- 添加拾色器
- 添加其他标签
- 添加文本
- 添加按钮
- 添加事件
右键点击按钮,选择添加事件。看中下方。
以此类推,创建其他两个按钮和事件。
- 运行验证
运行的结果和预想一致。
三、 将GUI_GUIDER生成的代码接入STM32
-
导出代码
在左上角,如图:
点进生成文件的src文件夹里,里面应该如图:
我们要将这两个文件移植到上一章我们完成的项目里。
我将他们放在了APP文件夹内。 -
接入项目
将custom和generated文件夹里面的所有C文件加入项目中。
头文件如下:
有些人会出现以下定义报错:
因为实际上我们没使用到,所以我们定义一个空的数据类型让他调用。
我们点开这个函数之前调用的回调函数,然后定义一个如下的数据类型:
//delete,new defination
typedef void (*lv_anim_deleted_cb_t)(struct _lv_anim_t * anim);
然后再在event_init.c文件中定义一个变量:
lv_ui guider_ui;
注意这里变量名尽量不要变,他是被gui_guider.h头文件声明了可被外部引用的:
extern lv_ui guider_ui;
此时我们再编译就没有报错了。
打开生成的代码文件中的main.c文件
将以下两句复制过来:
setup_ui(&guider_ui);
events_init(&guider_ui);
再在FreeRTOS中将lvgl的运行程序改为:
/**
* @brief LVGL运行例程
* @param pvParameters : 传入参数(未用到)
* @retval 无
*/
void lv_demo_task(void *pvParameters)
{
pvParameters = pvParameters;
setup_ui(&guider_ui);
events_init(&guider_ui);
while(1)
{
lv_timer_handler(); /* LVGL计时器 */
vTaskDelay(5);
}
}
(不得不说,FreeRTOS移植是真的好爽)
再在main.c中复制头文件:
#include "../generated/gui_guider.h"
#include "../generated/events_init.h"
然后修改以下加载到项目头文件中:
#include "gui_guider.h"
#include "events_init.h"
如果现在烧录到单片机上,你可以通过三个按钮来控制当前颜色。
- 修改生成代码
事件触发主要由event_init.c这个文件控制,我们可以打开它看看。
static void screen_btn_1_event_handler (lv_event_t *e)
{
// 获取事件代码
lv_event_code_t code = lv_event_get_code(e);
switch (code) {
case LV_EVENT_PRESSED:
{
// 设置屏幕的背景颜色为0xff0000
lv_obj_set_style_bg_color(guider_ui.screen_temp_color, lv_color_hex(0xff0000), LV_PART_MAIN);
break;
}
default:
break;
}
}
这是红色按钮的事件回调函数,注释已经写好了。
然后在下面的函数中将回调函数和对应的对象链接在一起:
void events_init_screen (lv_ui *ui)
{
lv_obj_add_event_cb(ui->screen_temp_color, screen_temp_color_event_handler, LV_EVENT_ALL, ui);
lv_obj_add_event_cb(ui->screen_btn_1, screen_btn_1_event_handler, LV_EVENT_ALL, ui);
lv_obj_add_event_cb(ui->screen_btn_2, screen_btn_2_event_handler, LV_EVENT_ALL, ui);
lv_obj_add_event_cb(ui->screen_btn_3, screen_btn_3_event_handler, LV_EVENT_ALL, ui);
}
打开函数原型,如下:
struct _lv_event_dsc_t * lv_obj_add_event_cb(lv_obj_t * obj, lv_event_cb_t event_cb, lv_event_code_t filter,
void * user_data)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_obj_allocate_spec_attr(obj);
obj->spec_attr->event_dsc_cnt++;
obj->spec_attr->event_dsc = lv_mem_realloc(obj->spec_attr->event_dsc,
obj->spec_attr->event_dsc_cnt * sizeof(lv_event_dsc_t));
LV_ASSERT_MALLOC(obj->spec_attr->event_dsc);
obj->spec_attr->event_dsc[obj->spec_attr->event_dsc_cnt - 1].cb = event_cb;
obj->spec_attr->event_dsc[obj->spec_attr->event_dsc_cnt - 1].filter = filter;
obj->spec_attr->event_dsc[obj->spec_attr->event_dsc_cnt - 1].user_data = user_data;
return &obj->spec_attr->event_dsc[obj->spec_attr->event_dsc_cnt - 1];
}
很明显第一个是我们需要控制的对象,第二个是事件回调函数,第三个是行为事件定义,第四个是是将数据传给回调函数的参数。
我们现在想通过控制拾色器来控制当前颜色,那么我们就需要在这这个函数的基础上再写一个函数:
// 颜色拾取器的事件处理函数
static void screen_cpicker_event_handler(lv_event_t *e)
{
// 获取当前的事件代码
lv_event_code_t code = lv_event_get_code(e);
switch (code) {
case LV_EVENT_VALUE_CHANGED: // 颜色变化事件
{
// 获取颜色拾取器对象
lv_obj_t * colorwheel = lv_event_get_target(e);
// 获取当前选中的颜色
lv_color_t selected_color = lv_colorwheel_get_rgb(colorwheel);
// 将选中的颜色应用到便签背景颜色上
lv_obj_set_style_bg_color(guider_ui.screen_temp_color, selected_color, LV_PART_MAIN);
break;
}
default:
break;
}
}
然后再在注册函数中添加:
lv_obj_add_event_cb(ui->screen_cpicker_1, screen_cpicker_event_handler, LV_EVENT_VALUE_CHANGED, NULL);
编译无报错,实验结果如下:
LVGL_4: LVGL_4
文章参考视频:https://www.bilibili.com/video/BV1vn4y197HW/?spm_id_from=333.880.my_history.page.click
作者:YUki又叫6777