RT-Thread 学习笔记(十三)--- 开启基于RTGUI的LCD显示功能(3)<触屏屏驱动移植和测试>

rtthread工业使用_RT-Thread三探--LCD驱动移植(使用GUI Engine) 既网络之后又一个比较重要的功能--GUI对于RT-Thread使用的GUI我还没有什么概念,本文只是针对LCD驱动部分的移植,并使用GUI运行本身提供的demo样例。当然还是和ETH一样,在STM32F4xx-HAL的BSP中是没有LCD的驱动文件的,还是从STM32F429 BSP中复制过来,在此基础上移植就好啦。移植步骤:在此可以稍微介绍下RTT基本的结构,RTT这个系统主要由下面几个部分组成... 阅读详情

软件环境:Win7,Keil MDK 4.72a, IAR EWARM 7.2, GCC 4.2,Python 2.7 ,SCons 2.3.2

硬件环境:Armfly STM32F103ZE-EK v3.0开发板

参考文章:RT-Thread编程指南

RT-Thread_1.2.0+lwip+rtgui0.8.0 移植心得

RT-Thread RTOS组件:RTGUI教程 Hello World


前面基本解决了显示驱动问题,接下来将要解决触摸屏的驱动问题。

【1】加入触屏屏的驱动文件

(1)重命名stm32f103ze-ek/drivers目录下touch.c文件,解决重名文件问题

将touch.c从KeilMDK工程中移除,同时将stm32f103ze-ek/drivers目录下的touch.h和touch.c重命名成touch_driver.c和touch_driver.h,然后再将其加入到工程中。

打开touch_driver.c文件,定位到第5行,修改如下:

... ...

#include "board.h"
#include "touch_driver.h"

... ...

(2)修改touch_driver.c文件中的相关硬件接口


上面的原理图中给出了触摸屏SPI接口,触摸屏的片选线PG11,中断线是PC5,Busy线是PB5,所以也要将touch_driver.c中断接口修改过来。定位到17行附近,代码修改如下:

/*
MISO PA6
MOSI PA7
CLK PA5
CS PG11

INT  PC5
BUSY  PB5

*/
#define CS_0() GPIO_ResetBits(GPIOG,GPIO_Pin_11)
#define CS_1() GPIO_SetBits(GPIOG,GPIO_Pin_11)

定位到80行附近修给触摸屏的分辨率

#define X_WIDTH 240
#define Y_WIDTH 400

然后定位到202行附近,修改如下:

/* touch time is too short and we lost the position already. */
if ((!touched_down) && GPIO_ReadInputDataBit(GPIOC, GPIO_Pin_5) != 0)
return;

if (GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5) != 0)
{

... ...

定位到209行附近,代码修改如下:

// PC5 -->  EXTI9_5 

static void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
/* Enable the EXTI9_5 Interrupt */
NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}

rt_inline void EXTI_Enable(rt_uint32_t enable)
{
EXTI_InitTypeDef EXTI_InitStructure;

/* Configure EXTI */
EXTI_InitStructure.EXTI_Line = EXTI_Line5;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//FallingϽµÑØ RisingÉÏÉý
... ...
EXTI_Init(&EXTI_InitStructure);
EXTI_ClearITPendingBit(EXTI_Line5);
}

static void EXTI_Configuration(void)
{
/* PC5 touch INT */
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure);
}

GPIO_EXTILineConfig(GPIO_PortSourceGPIOC, GPIO_PinSource5);

/* Configure EXTI */
EXTI_Enable(1);
}

... ...

定位到351行附近,代码修改如下:

/* RT-Thread Device Interface */
static rt_err_t rtgui_touch_init (rt_device_t dev)
{
NVIC_Configuration();
EXTI_Configuration();

/* PG11 touch CS */
{
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG,ENABLE);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_Init(GPIOG,&GPIO_InitStructure);
CS_1();
}

CS_0();
WriteDataTo7843( 1<<7 ); /*打开中断 */
CS_1();

return RT_EOK;
}

... ...

定位到406行附近,代码修改如下:

/* SPI1 config */
{
#ifndef RT_USING_SPI1
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
... ...
SPI_I2S_DeInit(SPI1);
SPI_Init(SPI1, &SPI_InitStructure);
#endif /* RT_USING_SPI1 */
/* Enable SPI_MASTER */
SPI_Cmd(SPI1, ENABLE);
SPI_CalculateCRC(SPI1, DISABLE);
... ...
} /* SPI1 config */
(3)spi_device_f

修改完成后保存。

【2】修改rt_spi_flash_device.c文件中与SPI1相关部分代码

打开rt_spi_flash_device.c,去掉RT_USING_SPI条件编译,加入RT_USING_SPI1 条件编译。定位到21行附近,代码修改如下:

/*
* SPI1_MOSI: PA7
* SPI1_MISO: PA6
* SPI1_SCK : PA5
*
* SPI Flash CE: PB2
* Touch Panel CS: PG11
*/

static int rt_hw_spi_init(void)
{
#ifdef RT_USING_SPI1
/*SPI1: register spi bus */
{

... ...
stm32_spi_register(SPI1, &stm32_spi, "spi1");
}
#endif /* RT_USING_SPI1 */
/* attach spi flash cs */
#ifdef RT_USING_SPI_FLASH
{
static struct rt_spi_device spi_device;
static struct stm32_spi_cs spi_cs;
... ...
rt_spi_bus_attach_device(&spi_device, "spiflash", "spi1", (void*)&spi_cs);
}
#endif /* RT_USING_SPI_FLASH */

return 0;
... ...
}
INIT_DEVICE_EXPORT(rt_hw_spi_init);


void rt_spi_flash_device_init(void)
{

#if defined(RT_USING_DFS) && defined(RT_USING_DFS_ELMFAT)

w25qxx_init("flash0", "spiflash");

#endif /* RT_USING_DFS && RT_USING_DFS_ELMFAT */

}

修改完成后保存。

(4)在rtconfig.h文件中加入RT_USING_SPI1定义,打开rtconfig.h,定位到93行附近,加入下面代码:

/* SECTION: device filesystem */
#define RT_USING_SPI
#define RT_USING_SPI1
#define RT_USING_SPI_FLASH
#define RT_USING_DFS

... ...
 修改完成后保存。然后重新scons编译,出现错误:Undefined Symbol "rtgui_touch_hw_init",reference to appliction.o. 

解决办法:

打开appliction.c文件,定位到136行附近,修改'RTGUI_USING_TOUCHPANEL 为'RT_USING_TOUCHPANEL,修改如下:

... ...

#ifdef RT_USING_TOUCHPANEL 

/* initilize touch panel */
rtgui_touch_hw_init();
#endif /* RT_USING_TOUCHPANEL */

/* find lcd device */
lcd = rt_device_find("lcd");

... ...

修改完成后保存。

打开touch_device.c文件,定位到492行附近,代码修改如下:

//外部中断PC5
#ifdef RT_USING_TOUCHPANEL
void EXTI9_5_IRQHandler(void)
{
/* disable interrupt */
EXTI_Enable(0);

/* start timer */
rt_timer_start(touch->poll_timer);

EXTI_ClearITPendingBit(EXTI_Line5);

}
#endif /* RT_USING_TOUCHPANEL*/
修改完成后保存。

因为'RTGUI_USING_TOUCHPANEL定义在rtgui_config.h中,不在rtconfig.h中,scons 脚本编译时找不到这个符号,然后删除掉rtgui_config.h中的RTGUI_USING_TOUCHPANEL 定义,在rtconfig.h加入RT_USING_TOUCHPANEL定义,代码如下:

/* SECTION: RT-Thread/GUI */
#define RT_USING_RTGUI
#define RT_USING_TOUCHPANEL
/* name length of RTGUI object */
... ...

修改完成后保存。

然后重新scons编译,编译通过,下载到开发板上,结果显示如下:

\ | /
- RT - Thread Operating System
/ | \ 1.2.2 build Apr 14 2015
2006 - 2013 Copyright by rt-thread team
sdcard init failed
dm9000 id: 0x90000a46
finsh />operating at 100M full duplex mode
lwIP-1.4.1 initialized!
set font size to 16
W25Q64BV or W25Q64CV detection
flash0 mount to /.
sd0 mount to /dev failed.
LCD ID 00005420

finsh />list_device()
device type
-------- ----------
touch SPI Device
lcd Graphic Device
flash0 Block Device
spiflash SPI Device
spi1 SPI Bus
e0 Network Interface
uart3 Character Device
uart2 Character Device
uart1 Character Device
0, 0x00000000
finsh />touch up: (0, 0)
touch up: (0, 0)
touch up: (0, 0)
touch up: (0, 0)

可以看到,输入list_device()命令后,看到了touch设备,在LCD上触摸几下,终端有触摸位置输出,因为还没有矫正,所以输出的点不确定。

【3】触摸屏校正

为了加入触摸屏校正文件calibration.c,需要对相关脚本文件作下修改

(1)用Notepad++打开compenonts/rtgui/Sconscript,导入根目录变量,修改如下:

import os
Import('RTT_ROOT')
from building import *

cwd = GetCurrentDir()
objs = []
list = os.listdir(cwd)

... ...

修改完成后保存。

(2)用Notepad++打开compenonts/rtgui/apps/Sconscript,修改编译选项,代码修改如下:

from building import *
import os

cwd = GetCurrentDir()

if GetDepend('RT_USING_CALIBRATION'):
src = Glob('*.c')
group = DefineGroup('RTGUI', src, depend = ['RT_USING_CALIBRATION'])

... ...

(3)在rtconfig.h中加入RT_USING_CALIBRATION定义,修改如下:

/* SECTION: RT-Thread/GUI */
#define RT_USING_RTGUI
#define RT_USING_TOUCHPANEL
#define RT_USING_CALIBRATION
/* name length of RTGUI object */
#define RTGUI_NAME_MAX 12
/* support 16 weight font */
#define RTGUI_USING_FONT16

... ...

修改完成后保存。

(4)打开rtgui_config.h定位到52行附近,打开注释掉的RTGUI_USING_CALIBRATION定义:

//#define RTGUI_USING_DESKTOP_WINDOW
//#undef RTGUI_USING_SMALL_SIZE

//#define RTGUI_USING_TOUCHPANEL
#define RTGUI_USING_CALIBRATION
#define RTGUI_USING_BRG565

#endif

(5)在命令终端中执行scons --target=mdk4 -s,然后打开keilMDK,可以在RTGUI组中看到calibration.c文件。

打开calibration.c,定位到143附近行和177行开始的地方,将屏幕四个角画点的rtgui_dc_draw_text()的第二个参数的字符串改短一点,不然字符显示不全,当然这是可选的,代码修改如下:

<pre name="code" class="cpp">

struct rtgui_widget *widget = RTGUI_WIDGET(object);
    rtgui_rect_t label_rect = {2, 100, 230, 300};
    switch (event->type)
    {
    case RTGUI_EVENT_PAINT:
    {
        struct rtgui_dc *dc;
        struct rtgui_rect rect;

        dc = rtgui_dc_begin_drawing(widget);
        if (dc == RT_NULL) break;

        /* get rect information */
        rtgui_widget_get_rect(widget, &rect);

        /* clear whole window */
        RTGUI_WIDGET_BACKGROUND(widget) = white;
        rtgui_dc_fill_rect(dc, &rect);

        /* reset color */
        RTGUI_WIDGET_BACKGROUND(widget) = green;
        RTGUI_WIDGET_FOREGROUND(widget) = black;


 
switch (calibration_ptr->step)
        {
        case CALIBRATION_STEP_LEFTTOP:
            rtgui_dc_draw_hline(dc,
                                0,
                                2 * CALIBRATION_WIDTH,
                                CALIBRATION_HEIGHT);
            rtgui_dc_draw_vline(dc,
                                CALIBRATION_WIDTH,
                                0,
                                2 * CALIBRATION_HEIGHT);
            rtgui_dc_draw_text(dc,
                               "Touch the left top!",
                               &label_rect);
            RTGUI_WIDGET_FOREGROUND(widget) = red;
            rtgui_dc_fill_circle(dc,
                                 CALIBRATION_WIDTH,
                                 CALIBRATION_HEIGHT,
                                 4);
            break;

        case CALIBRATION_STEP_RIGHTTOP:
            rtgui_dc_draw_hline(dc,
                                calibration_ptr->width - 2 * CALIBRATION_WIDTH,
                                calibration_ptr->width,
                                CALIBRATION_HEIGHT);
            rtgui_dc_draw_vline(dc,
                                calibration_ptr->width - CALIBRATION_WIDTH,
                                0,
                                2 * CALIBRATION_HEIGHT);
            rtgui_dc_draw_text(dc,
                               "Touch the right top!",
                               &label_rect);
            RTGUI_WIDGET_FOREGROUND(widget) = red;
            rtgui_dc_fill_circle(dc,
                                 calibration_ptr->width - CALIBRATION_WIDTH,
                                 CALIBRATION_HEIGHT,
                                 4);
            break;

        case CALIBRATION_STEP_LEFTBOTTOM:
            rtgui_dc_draw_hline(dc,
                                0,
                                2 * CALIBRATION_WIDTH,
                                calibration_ptr->height - CALIBRATION_HEIGHT);
            rtgui_dc_draw_vline(dc,
                                CALIBRATION_WIDTH,
                                calibration_ptr->height - 2 * CALIBRATION_HEIGHT,
                                calibration_ptr->height);
            rtgui_dc_draw_text(dc,
                               "Touch the left bottom!",
                               &label_rect);
            RTGUI_WIDGET_FOREGROUND(widget) = red;
            rtgui_dc_fill_circle(dc,
                                 CALIBRATION_WIDTH,
                                 calibration_ptr->height - CALIBRATION_HEIGHT,
                                 4);
            break;

        case CALIBRATION_STEP_RIGHTBOTTOM:
            rtgui_dc_draw_hline(dc,
                                calibration_ptr->width - 2 * CALIBRATION_WIDTH,
                                calibration_ptr->width,
                                calibration_ptr->height - CALIBRATION_HEIGHT);
            rtgui_dc_draw_vline(dc,
                                calibration_ptr->width - CALIBRATION_WIDTH,
                                calibration_ptr->height - 2 * CALIBRATION_HEIGHT,
                                calibration_ptr->height);
            rtgui_dc_draw_text(dc,
                               "Touch the right bottom!",
                               &label_rect);
            RTGUI_WIDGET_FOREGROUND(widget) = red;
            rtgui_dc_fill_circle(dc,
                                 calibration_ptr->width - CALIBRATION_WIDTH,
                                 calibration_ptr->height - CALIBRATION_HEIGHT,
                                 4);
            break;

        case CALIBRATION_STEP_CENTER:
            rtgui_dc_draw_hline(dc,
                                calibration_ptr->width / 2 - CALIBRATION_WIDTH,
                                calibration_ptr->width / 2 + CALIBRATION_WIDTH,
                                calibration_ptr->height / 2);
            rtgui_dc_draw_vline(dc,
                                calibration_ptr->width / 2,
                                calibration_ptr->height / 2 - CALIBRATION_HEIGHT,
                                calibration_ptr->height / 2 + CALIBRATION_HEIGHT);
            rtgui_dc_draw_text(dc,
                               "Touch the center to finish Calibration!",
                               &label_rect);
            RTGUI_WIDGET_FOREGROUND(widget) = red;
            rtgui_dc_fill_circle(dc,
                                 calibration_ptr->width / 2,
                                 calibration_ptr->height / 2,
                                 4);
            break;
        }
然后保存并scons编译,下载,复位后,在终端中输入calibration(),可得到如下显示:

finsh />calibration()
0, 0x00000000
finsh />

但是在按下屏幕上红点进行校正时,下面是终端输出的结果:

finsh />calibration()
0, 0x00000000
finsh />touch up: (481, 3773)
touch up: (3511, 3673)
touch up: (3491, 306)
touch up: (423, 285)
touch up: (1895, 2144)
可能是内存分配问题,demo_appliction.c中的控件演示打开的太多,不能正常显示,此问题留待后面解决。

【4】校正数据存储与加载

一个正常的系统不想每次启动时都要在终端输入命令进行校正,需要在一些代码,在系统启动时自动加载存储数据。

(1)新建文件touch_setup.c,并加入下面代码(参考ModiF1的部分代码修改而来):

#include <rtthread.h>
#include <dfs_posix.h>
#include <rtgui/calibration.h>
#include "stdlib.h"//for atoi
#include <touch_setup.h>

#define cali_file    "/cali.ini"

static const char* kn_touch_min_x = "touch_min_x";
static const char* kn_touch_max_x = "touch_max_x";
static const char* kn_touch_min_y = "touch_min_y";
static const char* kn_touch_max_y = "touch_max_y";


static rt_uint32_t read_line(int fd, char* line, rt_uint32_t line_size)
{
    char *pos, *next;
    rt_uint32_t length;

    length = read(fd, line, line_size);
    if (length > 0)
    {
        pos = strstr(line, "\r\n");
        if (pos == RT_NULL)
        {
            pos = strstr(line, "\n");
            next = pos ++;
        }
        else next = pos + 2;

        if (pos != RT_NULL)
        {
            *pos = '\0';

            /* move back */
            lseek(fd, -(length - (next - line)), SEEK_CUR);

            length = pos - line;
        }
        else length = 0;
    }

    return length;
}

static void cali_load_default(void)
{
    /*
    struct calibration_data setup;

    rt_kprintf("cali_load_default!\r\n");
		//OTM4001 default calibration data
    setup.min_x = 0x3aa8;
    setup.max_x = 0x792f;
    setup.min_y = 0xd7f1;
    setup.max_y = 0x573b;

    cali_save(&setup);
    */
}

rt_err_t cali_load(struct calibration_data* setup)
{
    int fd, length;
    char line[64];

    rt_kprintf("Load calibration data\n");

    fd = open(cali_file, O_RDONLY, 0);
    if (fd >= 0)
    {
        length = read_line(fd, line, sizeof(line));
        if (strcmp(line, "[config]") == 0)
        {
            char* begin;

            // touch_min_x
            length = read_line(fd, line, sizeof(line));
            if (length == 0)
            {
                close(fd);
                cali_load_default();
                return RT_EOK;
            }
            if (strncmp(line, kn_touch_min_x, sizeof(kn_touch_min_x) - 1) == 0)
            {
                begin = strchr(line, '=');
                begin++;
                setup->min_x = atoi(begin);
            }

            // touch_max_x
            length = read_line(fd, line, sizeof(line));
            if (length == 0)
            {
                close(fd);
                cali_load_default();
                return RT_EOK;
            }
            if (strncmp(line, kn_touch_max_x, sizeof(kn_touch_max_x) - 1) == 0)
            {
                begin = strchr(line, '=');
                begin++;
                setup->max_x = atoi(begin);
            }

            // touch_min_y
            length = read_line(fd, line, sizeof(line));
            if (length == 0)
            {
                close(fd);
                cali_load_default();
                return RT_EOK;
            }
            if (strncmp(line, kn_touch_min_y, sizeof(kn_touch_min_y) - 1) == 0)
            {
                begin = strchr(line, '=');
                begin++;
                setup->min_y = atoi(begin);
            }

            // touch_max_y
            length = read_line(fd, line, sizeof(line));
            if (length == 0)
            {
                close(fd);
                cali_load_default();
                return RT_EOK;
            }
            if (strncmp(line, kn_touch_max_y, sizeof(kn_touch_max_y) - 1) == 0)
            {
                begin = strchr(line, '=');
                begin++;
                setup->max_y = atoi(begin);
            }
        }
        else
        {
            close(fd);
            cali_load_default();
            return RT_EOK;
        }
    }
    else
    {
        close(fd);
        cali_load_default();
        return -RT_ERROR;
    }

    close(fd);
    return RT_EOK;
}

rt_err_t cali_save(struct calibration_data* cali)
{
    int fd, size;
    char* p_str;
    char* buf = rt_malloc(1024);

    if (buf == RT_NULL)
    {
        rt_kprintf("no memory\r\n");
        return RT_ENOMEM;
    }

    p_str = buf;

    fd = open(cali_file, O_WRONLY | O_TRUNC, 0);
    if (fd >= 0)
    {
        size = sprintf(p_str, "[config]\r\n"); // [config] sprintf(p_str,"")
        p_str += size;

        size = sprintf(p_str, "%s=%d\r\n", kn_touch_min_x, cali->min_x); //touch_min_x
        p_str += size;

        size = sprintf(p_str, "%s=%d\r\n", kn_touch_max_x, cali->max_x); //touch_max_x
        p_str += size;

        size = sprintf(p_str, "%s=%d\r\n", kn_touch_min_y, cali->min_y); //touch_min_y
        p_str += size;

        size = sprintf(p_str, "%s=%d\r\n", kn_touch_max_y, cali->max_y); //touch_max_y
        p_str += size;
    }

    size = write(fd, buf, p_str - buf);
    if (size == (p_str - buf))
    {
        rt_kprintf("file write succeed:\r\n");
    }

    close(fd);
    rt_free(buf);

    return RT_EOK;
}

/** This let the user space to restore the last calibration data.
 *
 * calibration_restore is a callback before calibration started. If it returns
 * RT_TRUE, the calibration won't be started. In this condition, you must setup
 * the calibration_data via something like:
 *
 *     device = rt_device_find("touch");
 *     if(device != RT_NULL)
 *         rt_device_control(device, RT_TOUCH_CALIBRATION_DATA, &data);
 *
 * It it returns RT_FALSE, the normal calibration process will be started. If
 * you don't have such feature, there is no need to call this function. The
 * calibration will always be started by RTGUI.
 */
rt_bool_t calibration_restore(void)
{
    //rt_kprintf("cali setup entered\n");
		struct calibration_data setup; 
		if(cali_load(&setup) == RT_EOK) 
		{ 
			 struct calibration_data data; 
			 rt_device_t device; 
			 /* update the calibration data  */ 
			 data.min_x = setup.min_x; 
			 data.max_x = setup.max_x; 
			 data.min_y = setup.min_y; 
			 data.max_y = setup.max_y; 
			 rt_kprintf("cali finished (%d, %d), (%d, %d)\n",
               data.min_x,
               data.max_x,
               data.min_y,
               data.max_y);
			 device = rt_device_find("touch"); 
			 if(device != RT_NULL) 
					 rt_device_control(device, RT_TOUCH_CALIBRATION_DATA, &data); 
			 return RT_TRUE; 
		} 
		/* if have no the calibration data,return false  */ 
    return RT_FALSE;    
}
/** This provide ways to save the calibration_data to user space.
 *
 * calibration_after is a callback after the calibration has finished.  User
 * space could use this function to save the data to some where else. No need
 * to call this if you don't have such function.
 */
void calibration_store(struct calibration_data *data)
{
		struct calibration_data store; 
		store.min_x = data->min_x; 
		store.max_x = data->max_x; 
		store.min_y = data->min_y; 
		store.max_y = data->max_y; 
		cali_save(&store); 
    rt_kprintf("cali finished (%d, %d), (%d, %d)\n",
               data->min_x,
               data->max_x,
               data->min_y,
               data->max_y);
		
}
(2)新建文件touch_setup.h,加入下面代码:

#ifndef __TOUCH_SETUP_H_
#define __TOUCH_SETUP_H_
#include <rtthread.h>
#include <rtgui/calibration.h>

rt_err_t cali_load(struct calibration_data* setup);
rt_err_t cali_save(struct calibration_data* setup);
rt_bool_t calibration_restore(void);
void calibration_store(struct calibration_data *data);
//the pointer to load user data ,need to initialize
void calibration_set_restore(rt_bool_t (*calibration_restore)(void));
//the pointer to save user data ,need to initialize
void calibration_set_after(void (*calibration_after)(struct calibration_data *data));

#endif
(3)修改application.c文件,定位到136行附近,代码修改如下:

#ifndef RT_USING_COMPONENTS_INIT
/* init rtgui system server */
rtgui_system_server_init();
#endif /*#ifndef RT_USING_COMPONENTS_INIT*/

#ifdef RTGUI_USING_CALIBRATION
calibration_set_restore(calibration_restore);//initialize the pointer to load user data
calibration_set_after(calibration_store); //initialize the poiter to save user data
calibration_init();


#endif /* RTGUI_USING_CALIBRATION */
gui_application_init();

}
#endif /* RT_USING_RTGUI */
(4)打开calibration.c文件,定位到380行附近,如下下面代码:

#ifdef RT_USING_FINSH
#include <finsh.h>
void calibration(void)
{
_cali_restore = RT_NULL;
calibration_init();
}
FINSH_FUNCTION_EXPORT(calibration, perform touch calibration);
#endif
下面我感觉有必要对下面两个接口API函数坐下解释:

static rt_bool_t (*_cali_restore)(void);
void calibration_set_restore(rt_bool_t (*calibration_restore)(void))
{
    _cali_restore = calibration_restore;
}

static void (*_cali_after)(struct calibration_data *data);
void calibration_set_after(void (*calibration_after)(struct calibration_data *data))
{		
    _cali_after = calibration_after;				
}
_cali_restore和_cali_after这两个函数指针在没有实际定义的指针给它们赋值时,指针为空(RT_NULL),为了让calibration.c的342行附近,代码如下:

    if (_cali_after)
        _cali_after(&calibration_ptr->data);
如果_cali_after指针不空,将校正完的数据存储到到用户空间。

在系统启动时,需要从用户空间读取校正数据,如果读取成功,那么通过下面代码将其加入到系统中:

device = rt_device_find("touch"); 
			 if(device != RT_NULL) 
					 rt_device_control(device, RT_TOUCH_CALIBRATION_DATA, &data); 
			 return RT_TRUE; 
所以上面分别给出了 _cali_restore和_cali_after这两个函数接口函数rt_bool_t calibration_restore(void)和void calibration_store(struct calibration_data *data),并在application.c的初始化部分调用了它们。

(5)在MDK中将touch_setup.c加入到Applications中。

系统启动时第一次因为用户空间没有cali.ini文件而读取失败,导致系统初始化时启动校正程序,但校正完成后,校正数据便cali.ini文件的形式存储到用户空间。下次启动时因问用户空间有了cali.ini数据校正文件而不再启动校正程序。
然后编译下载,复位后,按屏幕提示校正,发现可以正常触摸按钮,给开发板复位,发现没有启动触摸屏校正程序,在初始化完成后在触摸屏上按钮可以正常响应。这时终端输出如下:

set font size to 16
W25Q64BV or W25Q64CV detection
flash0 mount to /.
sd0 mount to /dev.
LCD ID 00005420
Load calibration data
cali finished (165, 3774), (3894, 173)
finsh />






【RT-Thread】——GUI服务器 RT-Thread/GUI是一个图形用户界面(Graphic  ) 阅读详情

相关推荐

RT-Thread学习笔记系列之littlevgl GUI(3)

文章目录前言一、资源介绍二、配置过程添加littlevgl2rtt软件包分析过程总结 前言 随着物联网、智能家居、智能控制等行业的极速发展,小而美的且反应迅速且成本低的,模块化,定制化的嵌入式系统的需求越来越大,其中降低使用要求,提高用户体验,人机交互是一个非常好的方法,所以本文记录的是调试rtthread+lcd+littlevgl GUI的记录及流程 一、资源介绍 硬件是自行画的PCB板,资源如下 MCU:STM32F407ZGT6 LCD:3.2寸320*240分辨率,驱动芯片:ILI9341。 引

weixin_39137443的博客 5394

RT-Thread 学习笔记(十四)--- 开启基于RTGUI的LCD显示功能(4)<demo组件的按键响应和焦点支持>

软件环境:Win7,Keil MDK 4.72a, IAR EWARM 7.2, GCC 4.2,Python 2.7 ,SCons 2.3.2 硬件环境:Armfly STM32F103ZE-EK v3.0开发板 参考文章:RT-Thread编程指南 RT-Thread_1.2.0+lwip+rtgui0.8.0 移植心得 RT-Thread RTOS组件:RTGUI

aping_cs_dn的专栏 1862

《rt-thread驱动框架分析》-lcd驱动

简介rt-smart相关文章《rt-smart的第一个应用程序,imx6ull用户态点灯》《rt-smart用户态通过IPC通信玩转传感器数据》rt-thread驱动相关文章《rt-th...

Rice开发经验分享 1882

RT-Thread学习--内核基础2

上一篇博客简单介绍了一下实时内核库包含的一些内容:线程调度、时钟管理、内存管理、I/O设备管理、线程间同步、线程间通信,在这篇博客中,继续内核基础的相关学习。 RT-Thread启动流程 rtthread_startup()函数是RT-Thread规定的统一启动入口。一般执行顺序是:系统先从启动文件开始运行,然后进入 RT-Thread 的启动 rtthread_startup() ,最后进入用户入口main(),如下图所示: 在上图中,先从汇编代码startup_xxx.s开始执行,然后进入rtthre

weixin_45865003的博客 2029

STM32与RTGUI图形界面集成实践指南

STM32微控制器系列,由意法半导体(STMicroelectronics)生产,是基于ARM Cortex-M内核的广泛使用的32位微控制器。它以其高性能、低功耗、丰富的外设和灵活的配置选项而闻名,在工业控制、医疗设备、消费电子产品及物联网等领域有着广泛应用。市场上有许多基于STM32系列的开发板,如Nucleo、Discovery和Eval板,它们为开发者提供了方便的起始平台。这些开发板通常带有丰富的接口和功能,用户可以通过它们快速评估和开发STM32微控制器的应用。

weixin_42298778的博客 902

ENSP从下载到运行:用虚拟机搭建华为认证实验环境全流程(含USG6000V镜像配置)

本文提供了一份详细的华为ENSP仿真平台从下载、安装到配置USG6000V防火墙镜像的完整指南。内容涵盖前置软件安装、ENSP主程序配置、核心设备镜像导入及虚拟机资源分配策略,旨在帮助网络工程师和学习者快速搭建一个稳定、功能齐全的华为认证实验环境,为备考和模拟企业网络部署打下坚实基础。

weixin_29230865的博客 533

RT-Thread使用-----TouchGfx(3)----LTDC

本文介绍如实使能LTDC驱动,进行屏幕点亮及测试工作。 1、屏幕参数及接口整理 我们使用的是正点原子的ATK4342型号的RGB565接口屏幕,屏幕的相关参数如下: 根据正点原子开发板手册可知,屏幕控制相关的LTDC接口定义如下 2、CubeMx配置 打开Cubemx进行LTDC接口的使能及配置 配置时需要保证接口与上表中进行匹配对应 保证配置接口速度为VeryHigh LTDC时钟配置,,本文...

rou252051452的博客 1204

CentOS 7 安装 Python 3.10

我这里已经软链接了,正常未链接之前是python->python2.7而不是python3.10。python2.7默认安装是在 /usr/bin目录中,切换到/usr/bin/更改yum配置,因为其要用到python2才能执行,否则会导致yum不能正常使用。2. 安装 Python 3.10 必需的 openssl >= 1.1.1。默认的centos7是没有安装pip,先添加epel扩展源。/usr/bin/python 修改为如下。添加软链接,将原来的链接备份。添加python3的软链接。

bensonyang888的博客 2905

rtthread studio使用【正点原子ATK阿波罗STM32F429开发板】bsp的Lcd驱动掉过的坑

坑一:bsp文件有drv_lcd.c,但RT-Thread Settings默认没有lcd驱动使能的选项 解决: 1、修改board文件夹下的kconfig文件,添加lcd使能选项 2、在RT-Thread Setting勾选"Enable LCD" 3、 在board/CubeMX_Config/Inc文件夹下stm32f4xx_hal_conf.h下使能LTDC宏 坑二:LCD使能了,编译工程发现提示drv_lcd.c缺少lcd_port.h文件 解决: ...

game334455的博客 2200

OSPF路由协议配置

构建直连连通让R1、R2、R3、R4加入OSPF,实现全网互通。掌握OSPF邻居状态的解读。掌握单区域OSPF的配置。理解OSPF的基本概念。AR3上的OSPF配置。AR4上的OSPF配置。R1上的OSPF配置。R2上的OSPF配置。

SURTR999的博客 7694

【ComfyUI】多模型 户型图风格渲染效果图

本文介绍了一种基于ComfyUI的室内户型图自动渲染工作流,将平面图转换为风格化效果图。该工作流通过RH_Captioner节点识别空间布局,结合Qwen2.5模型优化文本描述,再使用定制室内设计模型生成渲染图。整个流程包含图像输入、空间识别、文本组织、语言生成、风格转换和渲染输出等9个阶段,各节点协同完成从户型图到效果图的全自动转换。系统融合了语言理解和图像生成技术,可广泛应用于室内设计、装修可视化等领域。

Mr数据杨 3007

rt-thread驱动篇(05)---STM32F429单片机STemWin移植与使用

rt-thread驱动篇(05)---STM32F429单片机STemWin移植与使用

hurryddd 1851

基于BERTopic模型的英文20新闻数据集主题聚类及可视化

BERTopic是基于深度学习的一种主题建模方法。BERT是一种用于NLP的预训练策略,它成功地利用了句子的深层语义信息。

Cachel Wood的博客 1460

RT-Thread 柿饼GUI入门课程学习总结

前言 11月中旬的时候,我在RT-Thread的微信公众号推文看到了柿饼UI的入门课程活动。其实也不是第一次看到这个GUI的介绍,但是用Js开发的方式有点吸引我。 https://mp.weixin.qq.com/s/bBMuZ1qmtnI4cH86DR8enw 入门课程一个月左右的时间,一共5次作业,下面是部分我个人比较喜欢的作品: 第二周的基础题: 附加题: 最后一次是在柿饼派上运行的汽车模拟汽车仪表盘: ...

NameisBoy的博客 6718

滑块逆向及流程分析

本文章中所有内容仅供学习交流使用,不用于其他任何目的,不提供完整代码,抓包内容、敏感网址、数据接口等均已做脱敏处理,严禁用于商业用途和非法用途,否则由此产生的一切后果均与作者无关!

pyzzd的博客 8006

Transformer 跨界物理建模:探索模拟动态物理系统方法与实践(PINN、流体力学、有限元)

是一个由 Nicholas Zabaras 团队开发的开源项目,托管于 GitHub,旨在将 Transformer 模型(最初在自然语言处理领域大获成功)应用于物理系统的建模与预测。该项目基于论文 ​*“Transformers for Modeling Physical Systems”*​(Neural Networks, 2022),探索了深度学习中的 Transformer 架构如何通过自注意力机制和 Koopman 嵌入来模拟动态物理系统。

源代码杀手的博客 1190

RTGUI粗讲(个人见解篇之一:基本架构)

声明:因为个人发现在对架构理解上与RTGUI开发人员存在很在分歧,因此该系列所有内容仅限个人见解,与RTGUI原有含义完全无关。 由于个人属于什么都不懂,什么都不怎么会的菜鸟,所以希望在看这些小东东的大侠海涵,对的地方你就看把,不对的地方,你也将就着看吧。 这是这个讲解系列第一篇,一般都不会写得很好,因为思路会很不清晰,当然,也不会保证会有下一篇,因为个人时间真的有限,只能是利用晚上时

xuzhenglim的专栏 5598

高级图像增强——模拟雨天,雾,雪,阳光,阴影,运动模糊,畸变等14种效果,同步扩充标签文件

本文提供了一些高级的,特殊的图像增强方法,具体包括、光。

Limiiiing的博客 1308

rt-thread移植emwin

GUI_X_RTTHREAD.C #include "GUI.h" /* ********************************************************************************************************* * GLOBAL VARIABL...

MIRACLE_! 4065

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

华为的C语言编程规范.pdf

华为技术有限公司内部技术规范。本规范制定了编写C语言程序的基本原则、规则和建议。从代码的清晰、简洁、可测试、安全、程序效率、可移植各个方面对C语言编程作出了具体指导。

RT-Thread Studio上移植GUI-Guider-1.4开发LVGL8.2

这时候我们的工程没有GUI函数进行调用了,我们需要开始自己设计,所以我们打开GUI-Guider-1.4来进行对LVGL8.2的GUI设计,本篇主要讲解如何移植,具体GUI-Guider-1.4的使用方法大家还是上网自己学习。不同版本的GUI Guider可以创建的LVGL版本不一样,按照自己移植的LVGL来选择安装GUI Guider软件即可。由于LVGL的环境是现成的,所以我们就只需要将自带的demo给关闭掉就行了,这样就可以省下很多空间来进行设计。开始最重要的环节,设置我们的屏幕参数了。

qq_45902737的博客 2195

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

RT-Thread 学习笔记(十一)--- 开启基于RTGUI的LCD显示功能(1)<LCD驱动接口移植>

软件环境:Win7,Keil MDK 4.72a, IAR EWARM 7.2, GCC 4.2,Python 2.7 ,SCons 2.3.2 硬件环境:Armfly STM32F103ZE-EK v3.0开发板 参考文章:RT-Thread编程指南 RT-Thread_1.2.0+lwip+rtgui0.8.0 移植心得 RT-Thread RTOS组件:RTGUI

aping_cs_dn的专栏 1万+

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

i2c通信的详细讲解_《rt-thread驱动框架分析》-i2c驱动

驱动分析I2C设备驱动框架图:我们先RT-Thread的I2C框架图(这是我自己理解的框架图,如果不对的地方,请指出):上图是我分析的RTT的I2C框架图。主要分为三层,驱动层-核心层-设备层。如果你分析过Linux的I2C框架,它的层次也是这样子。所以你了解了RTT的I2C之后再去看Linux的I2C框架,其实问题不大。驱动层:分为硬件I2C驱动和软件I2C驱动。核心层: ①其中bit_ops是...

weixin_39631316的博客 905

RTT学习 开发环境搭建

Kconfig用来配置内核,menuconfig命令通过读取工程的各个KConfig文件,生成配置界面供用户配置内核,最后所有配置相关的宏定义都会自动保存到BSP目录里的rtconfig.h文件中,每个BSP都有一个rtconfig.h文件,这也就是BSP的配置信息。同样以上文提到的hello.c和hello.h为例,需要把他们作为一个单独的模块管理,并且在MDK或者IAR的工程文件里有自己的分组,且可以通过menuconfig选中是否使用这个模块。这里要介绍一个新的文件Kconfig。

Caramel_biscuit的博客 1010

STM32F407——基于RT-Thread实现触摸屏按键点灯案例

【补充:关于NVIC的配置,注意:RT-Thread 操作系统重定义 HardFault_Handler、PendSV_Handler、SysTick_Handler 中断函数,为了避免重复定义的问题,在生成工程之前,需要在中断配置中,代码生成的选项中,取消选择三个中断函数(对应注释选项是 Hard fault interrupt, Pendable request, Time base :System tick timer)】配置系统时钟,要挂载在定时器六下面,不然会与RT-Thread 的时钟冲突。

weixin_62514989的博客 2203

[嵌入式系统-16]:RT-Thread -2- 主要功能功能组件详解与API函数说明、API参考手册入口

RT-Thread 提供了一个灵活且易用的设备驱动框架,用于开发和管理各种硬件设备的驱动。该框架旨在简化设备驱动的开发流程,提高设备驱动的可复用性和可移植性。以下是 RT-Thread 设备驱动框架的一些重要概念和组件:设备结构体(struct device):RT-Thread 设备驱动框架使用结构体来表示设备。设备结构体包含了设备的名称、类型、状态等信息,并通过函数指针提供了设备操作的接口函数。设备驱动注册(rt_device_register):设备驱动注册是将设备与设备驱动程序关联起来的过程。

文火冰糖(王文兵)的博客 3041

RTGUI粗讲(个人见解篇之二、RTGUI事件简述)

这是本系列第二篇。本来是准备定WIDGET的,不过后来想想,EVENT还是需要先在WIDGET之前简单讲一下的,毕竟在RTGUI里面,事件是一个比较独立的东西,它派生的基类就是RTGUI EVETN,与widget无关,需要先单独做一个了解,再到后面讲如何搭建自己的widget的时候才会清晰一些。然而我也实在不知道该怎么讲这个,一个是毫无经验,另一个则是不知从何讲起,估计还是会讲的一头雾水吧。

xuzhenglim的专栏 3417
上一篇: RT-Thread 学习笔记(十二)--- 开启基于RTGUI的LCD显示功能(2)<编译测试>
下一篇: 将16进制整型转换十进制字符串
aping_cs_dn
博客等级 码龄19年 188粉丝 50原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

aping_cs_dn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值