本帖最后由 lulugl 于 2023-11-15 22:50 编辑
#有奖活动# #申请原创# @21小跑堂
【前言】
LVGL能实现非常简约美观的UI界面,前面移植好显示后,这章移植LVGL,实现一个对LED灯控制的小实例。
【开发环境】
- win11。
- STM32CubeIDE + FreeRTOS+LVGL
【硬件环境】
- NUCLEO_STM32U5A5ZJ-Q开发板
- ILI9488电阻触摸屏。
【实现步骤】
- 移植lcd屏驱动,具体的移植,已经在帖子https://bbs.21ic.com/icview-3340004-1-1.html上移植好了。
- freeRTOS,在帖子上移植好,需要的请移步查看:https://bbs.21ic.com/icview-3340310-1-1.html。
- 移植触摸驱动。
- 触摸的芯片是ADS7843,其原理图如下:
屏线接口原理图为:
使用到触的接口主要有TCLK(时钟)、TCS(片选)、TDI(MOSI)、TDO(MISO)、TPEN(中断)。电阻屏的原理就是当触摸屏按下后,取两个点的电压,来判断坐标在哪里,当屏被按下时,TPEN会给出信号。然后通过spi总线读取两个坐标点,计算出按下的坐标。
我们选取spi3为电阻触摸的通信,其接线如下
开发板 电阻屏
PEN PC9 //INT
DOUT PC11 //MISO
TDIN PC12 //MOSI
TCLK PC10 //SCLK
TCS PC8 //CS
驱动程序的实现按下面的步骤来实现:
1、首先,宏定义如下:
#define TCLK_GPIO_Port GPIOC
#define TCLK_PIN GPIO_PIN_10
#define TCLK_L TCLK_GPIO_Port->BRR = TCLK_PIN; //拉低SCK
#define TCLK_H TCLK_GPIO_Port->BSRR = TCLK_PIN; //拉高SCK
#define TDIN_GPIO_Port GPIOC
#define TDIN_PIN GPIO_PIN_12
#define TDIN_L TDIN_GPIO_Port->BRR = TDIN_PIN; //MOSI 低电平
#define TDIN_H TDIN_GPIO_Port->BSRR = TDIN_PIN; //MOSI 高电平
#define TCS_GPIO_Port GPIOC
#define TCS_PIN GPIO_PIN_13
#define TCS_L TCS_GPIO_Port->BRR = TCS_PIN; //cs 低电平
#define TCS_H TCS_GPIO_Port->BSRR = TCS_PIN; //cs 高电平
#define DOUT_GPIO_Port GPIOC
#define DOUT_Pin GPIO_PIN_11
#define PEN HAL_GPIO_ReadPin(PEN_GPIO_Port, PEN_Pin)
#define DOUT HAL_GPIO_ReadPin(DOUT_GPIO_Port, DOUT_Pin)
初始化GPIO,把TCK、TDIN、TCS配置为输出模式,把DOUT、PEN配置为输入模式。
//注意,时钟使能之后,对GPIO的操作才有效
//所以上拉之前,必须使能时钟.才能实现真正的上拉输出
GPIO_InitTypeDefGPIO_InitStruct = {0};
//注意,时钟使能之后,对GPIO的操作才有效
//所以上拉之前,必须使能时钟.才能实现真正的上拉输出
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = TCLK_PIN | TDIN_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(TCLK_GPIO_Port, &GPIO_InitStruct);
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = PEN_Pin | DOUT_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(PEN_GPIO_Port, &GPIO_InitStruct);
2、实现对电阻屏的写一个字节的函数TP_Write_Byte,代码如下:
void TP_Write_Byte(uint8_t num)
{
uint8_t count=0;
for(count=0;count<8;count++)
{
if(num&0x80)
{TDIN_H;}
else
{TDIN_L;}
num<<=1;
TCLK_L;
TCLK_H; //上升沿有效
}
}
3、实现对电阻屏的读一个字节的函数TP_Read_AD(uint8_t CMD),代码如下:
uint16_t TP_Read_AD(uint8_t CMD)
{
uint8_t count=0;
uint16_t Num=0;
TCLK_L; //先拉低时钟
TDIN_L; //拉低数据线
TCS_L; //选中触摸屏IC
TP_Write_Byte(CMD);//发送命令字
delay_us(6);//ADS7846的转换时间最长为6us
TCLK_L;
delay_us(1);
TCLK_H; //给1个时钟,清除BUSY
TCLK_L;
for(count=0;count<16;count++)//读出16位数据,只有高12位有效
{
Num<<=1;
TCLK_L; //下降沿有效
TCLK_H;
if(DOUT)Num++;
}
Num>>=4; //只有高12位有效.
TCS_H; //释放片选
return(Num);
}
4、实现读取指定寄存器的函数 TP_Read_XOY(uint8_t xy),代码如下:
uint16_t TP_Read_XOY(uint8_t xy)
{
uint16_t i, j;
uint16_t buf[READ_TIMES];
uint16_t sum=0;
uint16_t temp;
for(i=0;i<READ_TIMES;i++)buf[i]=TP_Read_AD(xy);
for(i=0;i<READ_TIMES-1; i++)//排序
{
for(j=i+1;j<READ_TIMES;j++)
{
if(buf[i]>buf[j])//升序排列
{
temp=buf[i];
buf[i]=buf[j];
buf[j]=temp;
}
}
}
sum=0;
for(i=LOST_VAL;i<READ_TIMES-LOST_VAL;i++)sum+=buf[i];
temp=sum/(READ_TIMES-2*LOST_VAL);
return temp;
}
5、实现读取指定xy坐标函数TP_Read_XY(uint16_t *x,uint16_t *y),代码如下:
uint8_t TP_Read_XY(uint16_t *x,uint16_t *y)
{
uint16_t xtemp,ytemp;
xtemp=TP_Read_XOY(CMD_RDX);
ytemp=TP_Read_XOY(CMD_RDY);
//if(xtemp<100||ytemp<100)return 0;//读数失败
*x=xtemp;
*y=ytemp;
return 1;//读数成功
}
6、为了准备的读取坐标植,定义了误差值范围为50,进行滤波算法,连续采集5次,丢弃一个,然后做平均,来得出坐标。TP_Read_XY2(uint16_t *x,uint16_t *y),代码如下:
uint8_t TP_Read_XY2(uint16_t *x,uint16_t *y)
{
uint16_t x1,y1;
uint16_t x2,y2;
uint8_t flag;
flag=TP_Read_XY(&x1,&y1);
if(flag==0)return(0);
flag=TP_Read_XY(&x2,&y2);
if(flag==0)return(0);
if(((x2<=x1&&x1<x2+ERR_RANGE)||(x1<=x2&&x2<x1+ERR_RANGE))//前后两次采样在+-50内
&&((y2<=y1&&y1<y2+ERR_RANGE)||(y1<=y2&&y2<y1+ERR_RANGE)))
{
*x=(x1+x2)/2;
*y=(y1+y2)/2;
return 1;
}else return 0;
}
7、电阻屏需要读取4个着的坐标进行屏幕较准,为此驱动设计了四点较准法来对屏幕进行较准,此次的较准点为:
1 (20,20) (x0,y0)
2 (lcddev.width-20,20) (x1,y1)
3 (20,lcddev.height-20) (x2,y2)
4 (lcddev.width-20,lcddev.height-20) (x3,y3)
8、算法步骤:
9、较准函数如下:
/*****************************************************************************
* [url=home.php?mod=space&uid=139335]@name[/url] :uint8_t TP_Get_Adjdata(void)
* [url=home.php?mod=space&uid=212281]@date[/url] :2018-08-09
* [url=home.php?mod=space&uid=42490]@function[/url] :Calibration touch screen and Get 4 calibration parameters
* [url=home.php?mod=space&uid=2814924]@parameters[/url] :None
* @retvalue :None
******************************************************************************/
void TP_Adjust(void)
{
uint16_t pos_temp[4][2];//坐标缓存值
uint8_t cnt=0;
uint16_t d1,d2;
uint32_t tem1,tem2;
float fac;
uint16_t outtime=0;
cnt=0;
fillScreen(ILI9488_WHITE);//清屏
ILI9488_printText("Please use the stylus click the", 10,40,ILI9488_BLACK, ILI9488_WHITE, 2);
ILI9488_printText("cross on the screen.The cross will", 10,56,ILI9488_BLACK, ILI9488_WHITE, 2);
ILI9488_printText("always move until the screen", 10,72,ILI9488_BLACK, ILI9488_WHITE, 2);
ILI9488_printText("adjustment is completed.", 10,88,ILI9488_BLACK, ILI9488_WHITE, 2);
TP_Drow_Touch_Point(20,20,ILI9488_RED);//画点1
tp_dev.sta=0;//消除触发信号
tp_dev.xfac=0;//xfac用来标记是否校准过,所以校准之前必须清掉!以免错误
while(1)//如果连续10秒钟没有按下,则自动退出
{
tp_dev.scan(1);//扫描物理坐标
if((tp_dev.sta&0xc0)==TP_CATH_PRES)//按键按下了一次(此时按键松开了.)
{
outtime=0;
tp_dev.sta&=~(1<<6);//标记按键已经被处理过了.
pos_temp[cnt][0]=tp_dev.x;
pos_temp[cnt][1]=tp_dev.y;
cnt++;
switch(cnt)
{
case 1:
TP_Drow_Touch_Point(20,20,ILI9488_WHITE); //清除点1
TP_Drow_Touch_Point(lcddev.width-20,20,ILI9488_RED); //画点2
break;
case 2:
TP_Drow_Touch_Point(lcddev.width-20,20,ILI9488_WHITE); //清除点2
TP_Drow_Touch_Point(20,lcddev.height-20,ILI9488_RED); //画点3
break;
case 3:
TP_Drow_Touch_Point(20,lcddev.height-20,ILI9488_WHITE); //清除点3
TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,ILI9488_RED); //画点4
break;
case 4: //全部四个点已经得到
//对边相等
tem1=abs(pos_temp[0][0]-pos_temp[1][0]);//x1-x2
tem2=abs(pos_temp[0][1]-pos_temp[1][1]);//y1-y2
tem1*=tem1;
tem2*=tem2;
d1=sqrt(tem1+tem2);//得到1,2的距离
tem1=abs(pos_temp[2][0]-pos_temp[3][0]);//x3-x4
tem2=abs(pos_temp[2][1]-pos_temp[3][1]);//y3-y4
tem1*=tem1;
tem2*=tem2;
d2=sqrt(tem1+tem2);//得到3,4的距离
fac=(float)d1/d2;
if(fac<0.95||fac>1.05||d1==0||d2==0)//不合格
{
cnt=0;
TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,ILI9488_WHITE); //清除点4
TP_Drow_Touch_Point(20,20,ILI9488_RED); //画点1
TP_Adj_Info_Show(pos_temp[0][0],pos_temp[0][1],pos_temp[1][0],pos_temp[1][1],pos_temp[2][0],pos_temp[2][1],pos_temp[3][0],pos_temp[3][1],fac*100);//显示数据
continue;
}
tem1=abs(pos_temp[0][0]-pos_temp[2][0]);//x1-x3
tem2=abs(pos_temp[0][1]-pos_temp[2][1]);//y1-y3
tem1*=tem1;
tem2*=tem2;
d1=sqrt(tem1+tem2);//得到1,3的距离
tem1=abs(pos_temp[1][0]-pos_temp[3][0]);//x2-x4
tem2=abs(pos_temp[1][1]-pos_temp[3][1]);//y2-y4
tem1*=tem1;
tem2*=tem2;
d2=sqrt(tem1+tem2);//得到2,4的距离
fac=(float)d1/d2;
if(fac<0.95||fac>1.05)//不合格
{
cnt=0;
TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,ILI9488_WHITE); //清除点4
TP_Drow_Touch_Point(20,20,ILI9488_RED); //画点1
TP_Adj_Info_Show(pos_temp[0][0],pos_temp[0][1],pos_temp[1][0],pos_temp[1][1],pos_temp[2][0],pos_temp[2][1],pos_temp[3][0],pos_temp[3][1],fac*100);//显示数据
continue;
}//正确了
//对角线相等
tem1=abs(pos_temp[1][0]-pos_temp[2][0]);//x1-x3
tem2=abs(pos_temp[1][1]-pos_temp[2][1]);//y1-y3
tem1*=tem1;
tem2*=tem2;
d1=sqrt(tem1+tem2);//得到1,4的距离
tem1=abs(pos_temp[0][0]-pos_temp[3][0]);//x2-x4
tem2=abs(pos_temp[0][1]-pos_temp[3][1]);//y2-y4
tem1*=tem1;
tem2*=tem2;
d2=sqrt(tem1+tem2);//得到2,3的距离
fac=(float)d1/d2;
if(fac<0.95||fac>1.05)//不合格
{
cnt=0;
TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,ILI9488_WHITE); //清除点4
TP_Drow_Touch_Point(20,20,ILI9488_RED); //画点1
TP_Adj_Info_Show(pos_temp[0][0],pos_temp[0][1],pos_temp[1][0],pos_temp[1][1],pos_temp[2][0],pos_temp[2][1],pos_temp[3][0],pos_temp[3][1],fac*100);//显示数据
continue;
}//正确了
//计算结果
tp_dev.xfac=(float)(lcddev.width-40)/(pos_temp[1][0]-pos_temp[0][0]);//得到xfac
tp_dev.xoff=(lcddev.width-tp_dev.xfac*(pos_temp[1][0]+pos_temp[0][0]))/2;//得到xoff
tp_dev.yfac=(float)(lcddev.height-40)/(pos_temp[2][1]-pos_temp[0][1]);//得到yfac
tp_dev.yoff=(lcddev.height-tp_dev.yfac*(pos_temp[2][1]+pos_temp[0][1]))/2;//得到yoff
if(abs(tp_dev.xfac)>2||abs(tp_dev.yfac)>2)//触屏和预设的相反了.
{
cnt=0;
TP_Drow_Touch_Point(lcddev.width-20,lcddev.height-20,ILI9488_WHITE); //清除点4
TP_Drow_Touch_Point(20,20,ILI9488_RED); //画点1
ILI9488_printText("TP Need readjust!", 40,26,ILI9488_BLACK, ILI9488_WHITE, 2);
tp_dev.touchtype=!tp_dev.touchtype;//修改触屏类型.
if(tp_dev.touchtype)//X,Y方向与屏幕相反
{
CMD_RDX=0X90;
CMD_RDY=0XD0;
}else //X,Y方向与屏幕相同
{
CMD_RDX=0XD0;
CMD_RDY=0X90;
}
continue;
}
fillScreen(ILI9488_WHITE);//清屏
ILI9488_printText("Touch Screen Adjust OK!", 35,110,ILI9488_BLACK, ILI9488_WHITE, 2);
HAL_Delay(1000);
TP_Save_Adjdata();
fillScreen(ILI9488_WHITE);//清屏
return;//校正完成
}
}
HAL_Delay(10);
outtime++;
if(outtime>1000)
{
TP_Get_Adjdata();
break;
}
}
}
10、较准参数的保存
较准参数,工程设计保存到备份寄存器中,stm32U5A5有32个TMP备份寄存器可以用,工程里RTC已初始化好了备份寄存器,并且有HAL的扩展读写函数。RTC已使用了RTC_BKP_DR1-RTC_BKP_DR5,因此此存我们使用RTC_BKP_DR6-11来保存较准因素、X偏移量、Y偏移量、触屏的模竖类型,以及是否较准的标记。具体读写代码如下:
void TP_Save_Adjdata(void)
{
int32_t temp;
//保存校正结果!
temp=tp_dev.xfac*100000000;//保存x校正因素
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR6, temp);
temp=tp_dev.yfac*100000000;//保存y校正因素
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR7, temp);
//保存x偏移量
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR8, tp_dev.xoff);
//保存y偏移量
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR9, tp_dev.yoff);
//保存触屏类型
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR10, tp_dev.touchtype);
temp=0X0A;//标记校准过了
HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR11, temp);
}
/*****************************************************************************
* [url=home.php?mod=space&uid=139335]@name[/url] :uint8_t TP_Get_Adjdata(void)
* [url=home.php?mod=space&uid=212281]@date[/url] :2018-08-09
* [url=home.php?mod=space&uid=42490]@function[/url] :Gets the calibration values stored in the EEPROM
* [url=home.php?mod=space&uid=2814924]@parameters[/url] :None
* @retvalue :1-get the calibration values successfully
0-get the calibration values unsuccessfully and Need to recalibrate
******************************************************************************/
uint8_t TP_Get_Adjdata(void)
{
int32_t tempfac;
tempfac = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR11);
if(tempfac==0X0A)//触摸屏已经校准过了
{
tempfac=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR6);
tp_dev.xfac=(float)tempfac/100000000;//得到x校准参数
tempfac=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR7);
tp_dev.yfac=(float)tempfac/100000000;//得到y校准参数
//得到x偏移量
tp_dev.xoff=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR8);
//得到y偏移量
tp_dev.yoff=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR9);
tp_dev.touchtype=HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR10);//读取触屏类型标记
if(tp_dev.touchtype)//X,Y方向与屏幕相反
{
CMD_RDX=0X90;
CMD_RDY=0XD0;
}else //X,Y方向与屏幕相同
{
CMD_RDX=0XD0;
CMD_RDY=0X90;
}
return 1;
}
return 0;
}
至此,已经实了触摸的驱动,可以正式进入LVGL的移植了。
【LVGL移植】
- 下载lvgl源码,官方下载,https://github.com/lvgl/lvgl。
- 下载好后,我们把lvgl文件,真接粘帖到工程的Middlewares止录下:
3、把文件夹的目录添加到工程里面:
4、复制lv_port_disp_template.h/c、lv_port_indev_template.h/c到src目录下面,并且重命名为lv_port_disp.h/c、lv_port_indev.h/c。
5、打开lv_port_disp.h,把if 0修改为if 1,同时把文件的引用路径修改为#include “lvgl.h”
6、打开lv_port_disp.c,修改if 0,为if 1。添加lcd屏、的头文件引用,添加hspi1、touch、lcd等的变量的扩展声明。
7、在函数lv_port_disp_init中定义宽的参数,以及刷新缓存的方式
8、修改disp_flush函数为内容如下:
static void disp_flush(lv_disp_drv_t * disp_drv, const lv_area_t * area, lv_color_t * color_p)
{
/*The most simple case (but also the slowest) to put all pixels to the screen one-by-one*/
uint32_t i, n, cnt, buf_size,h,w;
uint8_t r,g,b;
w = area->x2- area->x1 +1;
h = area->y2- area->y1 +1;
setAddrWindow(area->x1, area->y1, area->x2, area->y2); //设置显示块大小
n = w*h*3;
//割分发送给屏
if (n <= 65535){
cnt = 1;
buf_size = n;
}
else {
cnt = n/3;
buf_size = 3;
uint8_t min_cnt = n/(65535)+1;
for (i=min_cnt; i < n/3; i++)
{
if(n%i == 0)
{
cnt = i;
buf_size = n/i;
break;
}
}
}
DC_DATA();
CS_A();
while(cnt>0)
{
uint8_t frm_buf[buf_size];
for (i=0; i < buf_size/3; i++)
{
r = (((color_p->full & 0xF800) >> 11) * 255) / 31;
g = (((color_p->full & 0x07E0) >> 5) * 255) / 63;
b = (color_p->full & 0x001F * 255) / 31;
frm_buf[i*3] = r;
frm_buf[i*3+1] = g;
frm_buf[i*3+2] = b;
color_p++;
}
//HAL_SPI_Transmit(&hspi1, frm_buf, buf_size, HAL_MAX_DELAY);
HAL_SPI_Transmit(&hspi1, frm_buf, buf_size, 10);
cnt -= 1;
}
CS_D();
/*IMPORTANT!!!
*Inform the graphics library that you are ready with the flushing*/
lv_disp_flush_ready(disp_drv);
}
10、在disp_init函数中,加入LCD屏初始化,设置屏有横竖类型,同时修改电阻屏的横竖:
11、重命名lvgl目录下的lvgl_conf_template.h为lvgl_conf.h。
12、打开lvgl_conf.h,修改if 0为if 1,打开代码。
13、为lvgl添加freertos的tick心跳包,在第88行左右,找到#define LV_TICK_CUSTOM,把他修改为1,同时修改内容如下,使得lvgl的心跳包为freertos来提供:
#define LV_TICK_CUSTOM 1
#if LV_TICK_CUSTOM
#define LV_TICK_CUSTOM_INCLUDE "FreeRTOS.h"/*Header for the system time function*/
#define LV_TICK_CUSTOM_SYS_TIME_EXPR (xTaskGetTickCount()) /*Expression evaluating to current system time in ms*/
/*If using lvgl as ESP32 component*/
// #define LV_TICK_CUSTOM_INCLUDE "esp_timer.h"
// #define LV_TICK_CUSTOM_SYS_TIME_EXPR ((esp_timer_get_time() / 1000LL))
#endif/*LV_TICK_CUSTOM*/
14、打开lv_port_indev.h 修改if 0为 if 1打开代码。
15、打开lv_port_indev.c,修改if 0 为if 1, 打开代码,同时添加touch.h的头文件引用:
16、修改touchpad_read函数内容如下:
/*Will be called by the library to read the touchpad*/
static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
{
static lv_coord_t last_x = 0;
static lv_coord_t last_y = 0;
TP_Scan(0);
if(tp_dev.sta&TP_PRES_DOWN)
{
last_x = tp_dev.x;
last_y = tp_dev.y;
data->point.x = last_x;
data->point.y = last_y;
data->state = LV_INDEV_STATE_PR;
}
else
{
data->point.x = last_x;
data->point.y = last_y;
data->state = LV_INDEV_STATE_REL;
}
}
到此代码的移植全部完成,编译后有些错误提示,可以根据提示来添加头文件的引用等。
【测试代码】
1、在main.c中,我们需要先添加lcd的初始化与电阻屏的初化与较准。
2、在app_freertos.c文件中,我们在任务中添加一个LED的控制程序,添加一个LED及一个开关部件来实现对板载LED红灯的控制。添加一个label标签,用于展示当前的时间,开启一个定时器,在定时器回调函数中刷定时间显示。
lv_obj_t *led ; //LED�?
lv_obj_t *sw_led; //按键
lv_obj_t *lab_time; //时间显示标签
lv_timer_t * lvgl_task1 = NULL;
lv_obj_t *obj1;
RTC_DateTypeDef GetData; //获取日期结构
RTC_TimeTypeDef GetTime; //获取时间结构
static void switc_led_envet_handler(lv_event_t* e)
{
lv_event_code_t code = lv_event_get_code(e);
if (code == LV_EVENT_VALUE_CHANGED)
{
if(lv_obj_has_state(sw_led, LV_STATE_CHECKED))
{
lv_led_on(led);
HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, SET);
}
else
{
lv_led_off(led);
HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, RESET);
}
}
}
static void lvgl_rtc_cb(lv_timer_t *tmr)
{
HAL_RTC_GetTime(&hrtc, &GetTime, RTC_FORMAT_BIN);
/* Get the RTC current Date */
HAL_RTC_GetDate(&hrtc, &GetData, RTC_FORMAT_BIN);
lv_label_set_text_fmt(lab_time, "%04d/%02d/%02d %02d:%02d:%02d",
2000 + GetData.Year, GetData.Month, GetData.Date, GetTime.Hours, GetTime.Minutes, GetTime.Seconds);
lv_obj_align_to(lab_time,obj1,LV_ALIGN_OUT_BOTTOM_MID,0,20);
}
void StartTask02(void *argument)
{
/* USER CODE BEGIN myTask02 */
lv_init(); /* lvgl系统初始 */
lv_port_disp_init(); /* lvgl显示接口初始�????????,放在lv_init() */
lv_port_indev_init();
obj1 = lv_obj_create(lv_scr_act());
lv_obj_set_size(obj1,200,300);
lv_obj_set_align(obj1, LV_ALIGN_CENTER); //居中
lv_obj_t *label1 = lv_label_create(lv_scr_act());
lv_obj_set_style_text_font(label1,&lv_font_montserrat_24,LV_STATE_DEFAULT);
lv_label_set_text(label1, "STM32U5A5 LED DEMO");
lv_obj_align_to(label1,obj1,LV_ALIGN_OUT_TOP_MID,0,-20);
led = lv_led_create(obj1);
lv_obj_set_size(led,80,80);
lab_time = lv_label_create(lv_scr_act());
lv_obj_set_style_text_font(lab_time, &lv_font_montserrat_24,LV_STATE_DEFAULT);
lv_led_off(led);
sw_led = lv_switch_create(obj1);
lv_obj_set_size(sw_led,100,50);
lv_obj_add_event_cb(sw_led, switc_led_envet_handler,LV_EVENT_VALUE_CHANGED,NULL);
lv_obj_align_to(led,obj1,LV_ALIGN_CENTER,0,-60);
lv_obj_align_to(sw_led,obj1,LV_ALIGN_CENTER,0,60);
lvgl_task1 = lv_timer_create(lvgl_rtc_cb, 1000, 0); // 运行周期为lvgl�?1000个滴答时�?
/* Infinite loop */
for(;;)
{
lv_timer_handler(); /* LVGL计时 */
osDelay(10);
}
/* USER CODE END myTask02 */
}
【实现效果】
【总结】
- 基于LVGL的移植历经一个星期才完成任务。下面谈谈这项目工程的一些经验与心得。
- STM32U5A5拥有大的flash与大内存,编写lvgl时不需要考虑内存是否足够的情况。
- Stm32CubeIDE提供了强大的编程工具,基础的组件基于图形化的工具配置,减少了开发者的复杂的寄存器的配置。生成基础工程非常之方便。国家厂家比如雅特力、TI等也有图形化的配置工程,但是相比stm32cubeIDE还是没有这么全面与方便。
- Stm32cubeIDE的FreeRTOS的移植也是有软件包,虽然在stm32U5下面没有默认的包,但是可以经过手工安装来实现对freeRTOS的简单配置,使得移植工作也是非常的快捷方便。
- 在LVGL的移植工作中,相比keil的移植,也是有相当大的优势,keil中,需要手工添加非常多的.c文件,与头文件的引用,在stm32cubeIDE中只需要把外部的文件夹拷贝进目录就行了,简单的添加编译的路径与工程里就行了。
【源代码】
代码比较大不能上传附件,我分享在网盘链接:https://pan.baidu.com/s/1parn-cC612MZLUbb1F6RCQ?pwd=b1v3
提取码:b1v3
--来自百度网盘超级会员V5的分享
【视频效果】
|
此文章已获得独家原创/原创奖标签,著作权归21ic所有,未经允许禁止转载。
共1人点赞
|