stm32开发之threadx+guix组合记录

前言

  1. 做个threadx+guix的简单记录
  2. guix使用的内存分配采用外部sram

代码

GUIX组件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-22     shchl   first version
 */
#include "includes.h"


#if 1

#include "appgui_specifications.h"
/*
*******************************************************************************************************
*                               外部引入变量
*******************************************************************************************************
*/

/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*/

/*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*                                      外部函数
*********************************************************************************************************
*/
/*
*********************************************************************************************************
*	                                        动态内存分配
*********************************************************************************************************
*/
GX_COLOR *canvas_mem;// 画布内存
/*
*********************************************************************************************************
*	                                          变量
*********************************************************************************************************
*/
extern GX_STUDIO_DISPLAY_INFO appgui_display_table[1];

/*
*********************************************************************************************************
*	                                       动态内存函数
*********************************************************************************************************
*/
VOID *memory_allocate(ULONG size) {
    return app_sram_malloc(size);
}

void memory_free(VOID *mem) {

    app_free(mem);
}


int gui_gx_application_define(void) {

    /* 分配画布内存 */
    canvas_mem = app_sram_malloc(320 * 480 * 2);
    /* 初始化GUIX */
    gx_system_initialize();
    /* 注册动态内存申请和释放函数 */
    gx_system_memory_allocator_set(memory_allocate, memory_free);
    /* 自适应不同分辨率显示屏 */
    appgui_display_table[0].x_resolution = 320;
    appgui_display_table[0].y_resolution = 480;
    appgui_display_table[0].canvas_memory = (GX_COLOR *) canvas_mem;


    return FX_SUCCESS;
}

TX_APP_DEFINE_EXPORT(gui_gx_application_define); /*首先创建模块应用*/
/*
*********************************************************************************************************
*                                      内部函数
*********************************************************************************************************
*/






#endif

GUIX 任务线程 (主要是用于配置guix和监听触摸驱动)

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-20     shchl   first version
 */
#include "includes.h"
#include "appgui_specifications.h"
#include "appgui_resources.h"
#include "gx_stm32_display_driver_16bpp.h"


#if 1

#include "bsp_touch.h"

#define APP_TASK_GUI_GX_PRIO 15
#define APP_TASK_GUI_GX_STK_SIZE 4096


/*
*******************************************************************************************************
*                               外部引入变量
*******************************************************************************************************
*/

/*
*******************************************************************************************************
*                               变量
*******************************************************************************************************
*/
GX_WINDOW *pScreen;
GX_WINDOW_ROOT *root;
TX_THREAD gui_gx_thread;
VOID *gui_thread_stack_area;
/*
*********************************************************************************************************
*                                       静态全局变量
*********************************************************************************************************
*/



/*
*********************************************************************************************************
*                                      函数声明
*********************************************************************************************************
*/
static VOID gui_gx_thread_entry(ULONG input);

static void gx_touch_event_call(uint8_t event_id, uint16_t x, uint16_t y);
/*
*********************************************************************************************************
*                                      外部函数
*********************************************************************************************************
*/
/**
 * @brief cpu 状态任务
 * @param first_thread 第一个启动的任务线程首地址
 */
int tx_task_gui_gx_create() {
    UINT status;
    gui_thread_stack_area = app_malloc(APP_TASK_GUI_GX_STK_SIZE);
    if (!gui_thread_stack_area) {
        tx_printf("app malloc error\r\n");
        return -1;
    }
    status = tx_thread_create(&gui_gx_thread,              /* 任务控制块地址 */
                              "gui gx thread",               /* 任务名 */
                              gui_gx_thread_entry,                  /* 启动任务函数地址 */
                              0,                             /* 传递给任务的参数 */
                              gui_thread_stack_area,            /* 堆栈基地址 */
                              APP_TASK_GUI_GX_STK_SIZE,    /* 堆栈空间大小 */
                              APP_TASK_GUI_GX_PRIO,        /* 任务优先级*/
                              APP_TASK_GUI_GX_PRIO,        /* 任务抢占阀值 */
                              TX_NO_TIME_SLICE,               /* 不开启时间片 */
                              TX_AUTO_START);                 /* 创建后立即启动 */
    if (status) {
        tx_printf("create error:%d\r\n", status);
    }
    /*配置触摸驱动,使用事件方式*/
    g_lcd_touch.touch_send_event = gx_touch_event_call;

    return TX_SUCCESS;
}

TX_THREAD_EXPORT(tx_task_gui_gx_create);

/*
*********************************************************************************************************
*                                      内部函数
*********************************************************************************************************
*/


static VOID gui_gx_thread_entry(ULONG input) {
    /* 配置显示屏 */
    gx_studio_display_configure(DISPLAY_1, stm32f4_graphics_driver_setup_565rgb,
                                LANGUAGE_CHINESE, DISPLAY_1_THEME_1, &root);
    /* 创建窗口 */
    gx_studio_named_widget_create("window", (GX_WIDGET *) root, (GX_WIDGET **) &pScreen);

    /* 显示根窗口 */
    gx_widget_show(root);

    /* 启动GUIX */
    gx_system_start();

    while (1) {
        lcd_touch_scan2();
        tx_thread_sleep(5);
    }

}

static void gx_touch_event_call(uint8_t event_id, uint16_t x, uint16_t y) {
    GX_VALUE xx, yy;
    GX_EVENT event;
    /* 无需转换, 直接是坐标值 */
    xx = (GX_VALUE)x;
    yy = (GX_VALUE)y;
    /* 横屏和竖屏方向识别 */
    switch (event_id) {
        case TOUCH_DOWN_EVENT_ID:
            event.gx_event_type = GX_EVENT_PEN_DOWN;
            event.gx_event_payload.gx_event_pointdata.gx_point_x = xx;
            event.gx_event_payload.gx_event_pointdata.gx_point_y = yy;
            event.gx_event_sender = 0;
            event.gx_event_target = 0;
            event.gx_event_display_handle = STM32_SCREEN_HANDLE; // 显示屏标识符,自定义的,保证在驱动中注册的一致
            gx_system_event_send(&event);
            break;

        case TOUCH_MOVE_EVENT_ID:
            event.gx_event_type = GX_EVENT_PEN_DRAG;
            event.gx_event_payload.gx_event_pointdata.gx_point_x = xx;
            event.gx_event_payload.gx_event_pointdata.gx_point_y = yy;
            event.gx_event_sender = 0;
            event.gx_event_target = 0;
            event.gx_event_display_handle = STM32_SCREEN_HANDLE;
            gx_system_event_fold(&event);
            break;

        case TOUCH_RELEASE_EVENT_ID:
            event.gx_event_type = GX_EVENT_PEN_UP;
            event.gx_event_payload.gx_event_pointdata.gx_point_x = xx;
            event.gx_event_payload.gx_event_pointdata.gx_point_y = yy;
            event.gx_event_sender = 0;
            event.gx_event_target = 0;
            event.gx_event_display_handle = STM32_SCREEN_HANDLE;
            gx_system_event_send(&event);
            break;

        default:
            break;
    }


}

#endif

## GUIX显示屏驱动(弃用,最新见最后)

  1. guix和屏幕之间的驱动,这里提供了两个,一个是屏幕全部刷新,一个是脏数据区域刷新(也是局部刷新;这个在本地测试有问题,出现问题的直接原因就是在数据计算指针的问题。如果有知道是什么原因,麻烦告知一下)。
#include "includes.h"

#if 1

#include "gx_stm32_display_driver_16bpp.h"
#include "tx_api.h"
#include "gx_api.h"
#include "gx_display.h"
#include "gx_utility.h"

/*
*********************************************************************************************************
*                                           变量和函数
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*	函 数 名: stm32f4_565rgb_buffer_toggle
*	功能说明: 更新canvas内容到LCD显存
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/

static INLINE_DECLARE void dbg_rectangle_inf(char *name, GX_RECTANGLE *rec) {
    tx_printf("%s:(%d,%d)-----(%d,%d)\r\n", name,
              rec->gx_rectangle_left, rec->gx_rectangle_top, /*左上顶点*/
              rec->gx_rectangle_right, rec->gx_rectangle_bottom /*右下顶点*/
    );
}

/**
 * @brief lcd 局部刷新
 * @param canvas
 * @param dirty
 */
static void stm32f4_565rgb_buffer_toggle(GX_CANVAS *canvas, GX_RECTANGLE *dirty) {
    GX_RECTANGLE Limit;
    ULONG offset;
    INT copy_width;
    INT copy_height;

    gx_utility_rectangle_define(&Limit, 0, 0,
                                (GX_VALUE) (canvas->gx_canvas_x_resolution - 1),
                                (GX_VALUE) (canvas->gx_canvas_y_resolution - 1));
    if (gx_utility_rectangle_overlap_detect(&Limit, dirty, dirty)) {

        dirty->gx_rectangle_left &= 0xfffe;
        dirty->gx_rectangle_right |= 0x01;
        /*重新刷新区域*/
        // 设置绘画区域
        copy_width = dirty->gx_rectangle_right - dirty->gx_rectangle_left;
        copy_height = dirty->gx_rectangle_bottom - dirty->gx_rectangle_top;
        // 计算偏移地址
        dbg_rectangle_inf("dirty", dirty);


        // 画布内存大小为(宽*高*像素大小(2字节))
        uint16_t *color_ptr = (uint16_t *) canvas->gx_canvas_memory; /*颜色数据首地址:数组*/
        offset = (dirty->gx_rectangle_top * canvas->gx_canvas_x_resolution); // 行偏移量
        offset += dirty->gx_rectangle_left; // 列偏移量
        color_ptr += offset; /*起始偏移位置*/

        lcd_tft_setWin(dirty->gx_rectangle_left, dirty->gx_rectangle_top,
                       copy_width, copy_height);
        lcd_tft_write_ram_prepare();
        for (int i = dirty->gx_rectangle_top; i <= dirty->gx_rectangle_bottom; i++) { // 刷新行数
            for (int j = 0; j <= copy_width; j++) { // 列数据
                // 从左到右
                lcd_tft_write_color(color_ptr[j]);
            }
            // 换行(在地址上进行地址显示屏宽度-->这里是宽度*2: uint16* 偏移跨度为2字节)
            color_ptr += canvas->gx_canvas_x_resolution;
        }
    }
}

/**
 * @brief 更新整个画布区域(直接,效率来说最低)
 * @param canvas
 * @param dirty
 */
static void stm32f4_565rgb_update_canvas_area(GX_CANVAS *canvas, GX_RECTANGLE *dirty) {
    GX_RECTANGLE Limit;
    /*获取限制区域(即当前画布的区域范围),值赋值给 Limit 结构体*/
    gx_utility_rectangle_define(&Limit, 0, 0,
                                (GX_VALUE) (canvas->gx_canvas_x_resolution - 1),
                                (GX_VALUE) (canvas->gx_canvas_y_resolution - 1));
    lcd_tft_draw_fast_rgb_color(Limit.gx_rectangle_left,
                                Limit.gx_rectangle_top,
                                Limit.gx_rectangle_right,
                                Limit.gx_rectangle_bottom,
                                (uint16_t *) canvas->gx_canvas_memory);
}

/*
*********************************************************************************************************
*	函 数 名: stm32f4_graphics_driver_setup_565rgb
*	功能说明: 驱动接口函数
*	形    参: ---
*	返 回 值: GX_SUCCESS
*********************************************************************************************************
*/
UINT stm32f4_graphics_driver_setup_565rgb(GX_DISPLAY *display) {

    _gx_display_driver_565rgb_setup(display, (VOID *) STM32_SCREEN_HANDLE, stm32f4_565rgb_update_canvas_area);

    return (GX_SUCCESS);
}


#endif

触摸驱动(原有基础上,增加回调,在外部进行扩展逻辑)

头文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-7     shchl   first version
 */

#ifndef APP_NO_OS_BSP_TOUCH_H
#define APP_NO_OS_BSP_TOUCH_H

#include "bsp.h"
#define TP_PRES_DOWN 0x80  //触屏被按下
#define TP_CATH_PRES 0x40  //有按键按下了
#define CT_MAX_TOUCH 5    //电容屏支持的点数,固定为5点
#define TOUCH_READ_TIMES             5
#define TOUCH_READ_DISCARD           1
#define ERR_RANGE 50 //误差范围
enum touch_event_id_enum {
    TOUCH_DOWN_EVENT_ID, /*按下事件*/
    TOUCH_MOVE_EVENT_ID, /*移动事件*/
    TOUCH_RELEASE_EVENT_ID, /*释放事件*/
};


//触摸屏控制器
typedef struct lcd_touch_dev_struct {
    uint16_t x[CT_MAX_TOUCH];        //当前坐标
    uint16_t y[CT_MAX_TOUCH];        //电容屏有最多10组坐标,电阻屏则用x[0],y[0]代表:此次扫描时,触屏的坐标,用
    //x[9],y[9]存储第一次按下时的坐标.
    volatile uint16_t sta;                    //笔的状态
    //b15:按下1/松开0;
    //b14:0,没有按键按下;1,有按键按下.
    //b13~b10:保留
    //b9~b0:电容触摸屏按下的点数(0,表示未按下,1表示按下)
/触摸屏校准参数(电容屏不需要校准)//
    float xfac;
    float yfac;
    short xoff;
    short yoff;
//新增的参数,当触摸屏的左右上下完全颠倒时需要用到.
//b0:0,竖屏(适合左右为X坐标,上下为Y坐标的TP)
//   1,横屏(适合左右为Y坐标,上下为X坐标的TP)
//b1~6:保留.
//b7:0,电阻屏
//   1,电容屏
    uint8_t touchtype;

    /**
     * @brief 触摸发送事件
     * @param event_id  事件id
     * @param x x坐标
     * @param y y坐标
     */
    void (*touch_send_event)(uint8_t event_id, uint16_t x, uint16_t y);
    struct {
        uint8_t rd_x_cmd;
        uint8_t rd_y_cmd;
    } CNF;
} lcd_touch_dev;
#define PEN  		PBin(1)  	//T_PEN
#define DOUT 		PBin(2)   	//T_MISO
#define TDIN 		PFout(11)  	//T_MOSI
#define TCLK 		PBout(0)  	//T_SCK
#define TCS  		PCout(13)  	//T_CS
extern lcd_touch_dev g_lcd_touch; /*全局lcd触摸控制器设备*/

uint8_t bsp_InitLcdTouch(void);

uint8_t lcd_touch_scan(uint8_t tp);
// 事件驱动扫描
void lcd_touch_scan2(void);

void lcd_touch_adjust(void);

uint16_t lcd_touch_read_ad(uint8_t cmd);

#endif //APP_NO_OS_BSP_TOUCH_H

源文件

/*
 * Copyright (c) 2024-2024,shchl
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2024-4-7     shchl   first version
 */

#include "bsp_touch.h"
#include <math.h>
#include <stdlib.h>


lcd_touch_dev g_lcd_touch = {
        .CNF={0X90, 0XD0}

};
static void spi_us_delay(uint32_t us) { bsp_DelayDWTUS(us); }

//读取一个坐标值(x或者y)
//连续读取READ_TIMES次数据,对这些数据升序排列,
//然后去掉最低和最高LOST_VAL个数,取平均值
//xy:指令(CMD_RDX/CMD_RDY)
//返回值:读到的数据
uint16_t lcd_touch_read(uint8_t cmd) {
    uint16_t i, j;
    uint16_t buf[TOUCH_READ_TIMES];
    uint32_t sum = 0;
    uint16_t temp;
    for (i = 0; i < TOUCH_READ_TIMES; i++) {
        buf[i] = lcd_touch_read_ad(cmd);
    }
    for (i = 0; i < TOUCH_READ_TIMES - 1; i++)//排序
    {
        for (j = i + 1; j < TOUCH_READ_TIMES; j++) {
            if (buf[i] > buf[j])//升序排列
            {
                temp = buf[i];
                buf[i] = buf[j];
                buf[j] = temp;
            }
        }
    }
    sum = 0;
    for (i = TOUCH_READ_DISCARD; i < TOUCH_READ_TIMES - TOUCH_READ_DISCARD; i++)sum += buf[i];
    temp = sum / (TOUCH_READ_TIMES - 2 * TOUCH_READ_DISCARD);
    return temp;
}


//读取x,y坐标
//最小值不能少于100.
//x,y:读取到的坐标值
//返回值:0,失败;1,成功。
uint8_t lcd_touch_read_xy(uint16_t *x, uint16_t *y) {
    uint16_t xtemp, ytemp;
    xtemp = lcd_touch_read(g_lcd_touch.CNF.rd_x_cmd);
    ytemp = lcd_touch_read(g_lcd_touch.CNF.rd_y_cmd);
    if (xtemp < 100 || ytemp < 100)return 0;//读数失败
    *x = xtemp;
    *y = ytemp;
    return 1;//读数成功
}
//连续2次读取触摸屏IC,且这两次的偏差不能超过
//ERR_RANGE,满足条件,则认为读数正确,否则读数错误.
//该函数能大大提高准确度
//x,y:读取到的坐标值
//返回值:0,失败;1,成功。
uint8_t lcd_touch_read_xy2(uint16_t *x, uint16_t *y) {
    uint16_t x1, y1;
    uint16_t x2, y2;
    uint8_t flag;
    flag = lcd_touch_read_xy(&x1, &y1);
    if (flag == 0)return (0);
    flag = lcd_touch_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;
}

/**
 * @brief lcd 触摸初始化
 * @return
 */
uint8_t bsp_InitLcdTouch(void) {
    GPIO_InitTypeDef GPIO_InitStructure;

    __HAL_RCC_GPIOB_CLK_ENABLE();			//开启GPIOB时钟
    __HAL_RCC_GPIOC_CLK_ENABLE();			//开启GPIOC时钟
    __HAL_RCC_GPIOF_CLK_ENABLE();			//开启GPIOF时钟
    //GPIOB1,2初始化设置
    GPIO_InitStructure.Pin=GPIO_PIN_1|GPIO_PIN_2;	//PB1/PB2 设置为上拉输入
    GPIO_InitStructure.Mode=GPIO_MODE_INPUT;  	//输入模式
    GPIO_InitStructure.Pull=GPIO_PULLUP;          //上拉
    GPIO_InitStructure.Speed=GPIO_SPEED_HIGH;     //高速
    HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);     //初始化
    //PB0
    GPIO_InitStructure.Pin=GPIO_PIN_0; 			//PB0设置为推挽输出
    GPIO_InitStructure.Mode=GPIO_MODE_OUTPUT_PP;  //推挽输出
    HAL_GPIO_Init(GPIOB,&GPIO_InitStructure);     //初始化
    //PC13
    GPIO_InitStructure.Pin=GPIO_PIN_13;          	//PC13设置为推挽输出
    HAL_GPIO_Init(GPIOC,&GPIO_InitStructure);     //初始化
    //PF11
    GPIO_InitStructure.Pin=GPIO_PIN_11;          	//PF11设置推挽输出
    HAL_GPIO_Init(GPIOF,&GPIO_InitStructure);     //初始化
    /*初始值*/
    g_lcd_touch.xfac = -0.084720f;
    g_lcd_touch.yfac = -0.12764f;
    g_lcd_touch.xoff = 331;
    g_lcd_touch.yoff = 496;


    return lcd_touch_read_xy(&g_lcd_touch.x[0], &g_lcd_touch.y[0]) == 0 ? BSP_ERROR : BSP_EOK;
}

//触摸按键扫描
//tp:0,屏幕坐标;1,物理坐标(校准等特殊场合用)
//返回值:当前触屏状态.
//0,触屏无触摸;1,触屏有触摸
uint8_t lcd_touch_scan(uint8_t tp){
    if (PEN == 0)//有按键按下
    {
        if (tp)lcd_touch_read_xy2(&g_lcd_touch.x[0], &g_lcd_touch.y[0]);//读取物理坐标
        else if (lcd_touch_read_xy2(&g_lcd_touch.x[0], &g_lcd_touch.y[0]))//读取屏幕坐标
        {
            g_lcd_touch.x[0] = g_lcd_touch.xfac * g_lcd_touch.x[0] + g_lcd_touch.xoff;//将结果转换为屏幕坐标
            g_lcd_touch.y[0] = g_lcd_touch.yfac * g_lcd_touch.y[0] + g_lcd_touch.yoff;
        }
        if ((g_lcd_touch.sta & TP_PRES_DOWN) == 0)//之前没有被按下
        {
            g_lcd_touch.sta = TP_PRES_DOWN | TP_CATH_PRES;//按键按下
            g_lcd_touch.x[4] = g_lcd_touch.x[0];//记录第一次按下时的坐标
            g_lcd_touch.y[4] = g_lcd_touch.y[0];
        }
    } else {
        if (g_lcd_touch.sta & TP_PRES_DOWN)//之前是被按下的
        {
            g_lcd_touch.sta &= ~(1 << 7);//标记按键松开
        } else//之前就没有被按下
        {
            g_lcd_touch.x[4] = 0;
            g_lcd_touch.y[4] = 0;
            g_lcd_touch.x[0] = 0xffff;
            g_lcd_touch.y[0] = 0xffff;
        }
    }
    return g_lcd_touch.sta & TP_PRES_DOWN;//返回当前的触屏状态


}
//提示校准结果(各个参数)
void
TP_Adj_Info_Show(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x3, uint16_t y3,
                 uint16_t fac) {

    BSP_Printf("(%d,%d)----(%d,%d)\r\n(%d,%d)----(%d,%d)\r\n", x0, y0, x1, y1, x2, y2, x3, y3);
    BSP_Printf("fac:%d\r\n", fac);

}
//与LCD部分有关的函数
//画一个触摸点
//用来校准用的
//x,y:坐标
//color:颜色
void TP_Drow_Touch_Point(uint16_t x, uint16_t y, uint16_t color) {
    g_tft_lcd_data.front_color = color;
    lcd_tft_draw_line(x - 12, y, x + 13, y);//横线
    lcd_tft_draw_line(x, y - 12, x, y + 13);//竖线
    lcd_tft_draw_point(x + 1, y + 1);
    lcd_tft_draw_point(x - 1, y + 1);
    lcd_tft_draw_point(x + 1, y - 1);
    lcd_tft_draw_point(x - 1, y - 1);
    lcd_tft_draw_circle(x, y, 6);//画中心圈
}

//触摸屏校准代码
//得到四个校准参数
void lcd_touch_adjust(void) {

    uint16_t pos_temp[4][2];//坐标缓存值
    uint8_t cnt = 0;
    uint16_t d1, d2;
    uint32_t tem1, tem2;
    double fac;
    uint16_t outtime = 0;
    cnt = 0;
    lcd_tft_fill_color(WHITE);//清屏
    g_tft_lcd_data.front_color = BLACK;
    TP_Drow_Touch_Point(20, 20, RED);//画点1
    g_lcd_touch.sta = 0;//消除触发信号
    g_lcd_touch.xfac = 0;//xfac用来标记是否校准过,所以校准之前必须清掉!以免错误
    while (1)//如果连续10秒钟没有按下,则自动退出
    {
        lcd_touch_scan(1);//扫描物理坐标
        if ((g_lcd_touch.sta & 0xc0) == TP_CATH_PRES)//按键按下了一次(此时按键松开了.)
        {
            outtime = 0;
            g_lcd_touch.sta &= ~(1 << 6);//标记按键已经被处理过了.

            pos_temp[cnt][0] = g_lcd_touch.x[0];
            pos_temp[cnt][1] = g_lcd_touch.y[0];
            cnt++;
            switch (cnt) {
                case 1:
                    TP_Drow_Touch_Point(20, 20, WHITE);//清除点1
                    TP_Drow_Touch_Point(g_tft_lcd_data.width - 20, 20, RED);    //画点2
                    break;
                case 2:
                    TP_Drow_Touch_Point(g_tft_lcd_data.width - 20, 20, WHITE);    //清除点2
                    TP_Drow_Touch_Point(20, g_tft_lcd_data.height - 20, RED);    //画点3
                    break;
                case 3:
                    TP_Drow_Touch_Point(20, g_tft_lcd_data.height - 20, WHITE);            //清除点3
                    TP_Drow_Touch_Point(g_tft_lcd_data.width - 20, g_tft_lcd_data.height - 20, 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(g_tft_lcd_data.width - 20, g_tft_lcd_data.height - 20, WHITE);    //清除点4
                        TP_Drow_Touch_Point(20, 20, RED);                                //画点1

                        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)//不合格
                    {
                        BSP_Printf("need adjust again\r\n");
                        cnt = 0;
                        TP_Drow_Touch_Point(g_tft_lcd_data.width - 20, g_tft_lcd_data.height - 20, WHITE);    //清除点4
                        TP_Drow_Touch_Point(20, 20, 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_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);//显示数据
                    //对角线相等
                    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(g_tft_lcd_data.width - 20, g_tft_lcd_data.height - 20, WHITE);    //清除点4
                        TP_Drow_Touch_Point(20, 20, 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;
                    }//正确了
                    //计算结果
                    g_lcd_touch.xfac = (float) (g_tft_lcd_data.width - 40) / (pos_temp[1][0] - pos_temp[0][0]);//得到xfac
                    g_lcd_touch.xoff = (g_tft_lcd_data.width - g_lcd_touch.xfac * (pos_temp[1][0] + pos_temp[0][0])) / 2;//得到xoff

                    g_lcd_touch.yfac = (float) (g_tft_lcd_data.height - 40) / (pos_temp[2][1] - pos_temp[0][1]);//得到yfac
                    g_lcd_touch.yoff = (g_tft_lcd_data.height - g_lcd_touch.yfac * (pos_temp[2][1] + pos_temp[0][1])) / 2;//得到yoff
                    if (abs(g_lcd_touch.xfac) > 2.0 || abs(g_lcd_touch.yfac) > 2.0)//触屏和预设的相反了.
                    {
                        cnt = 0;
                        TP_Drow_Touch_Point(g_tft_lcd_data.width - 20, g_tft_lcd_data.height - 20, WHITE);    //清除点4
                        TP_Drow_Touch_Point(20, 20, RED);                                //画点1
                        BSP_Printf("TP Need readjust!TP Need readjust!\r\n");
                        g_lcd_touch.touchtype = !g_lcd_touch.touchtype;//修改触屏类型.
                        if (g_lcd_touch.touchtype)//X,Y方向与屏幕相反
                        {
                            g_lcd_touch.CNF.rd_x_cmd = 0X90;
                            g_lcd_touch.CNF.rd_y_cmd = 0XD0;
                        } else                   //X,Y方向与屏幕相同
                        {
                            g_lcd_touch.CNF.rd_x_cmd = 0XD0;
                            g_lcd_touch.CNF.rd_y_cmd = 0X90;
                        }
                        continue;
                    }
                    g_tft_lcd_data.front_color = BLUE;
                    lcd_tft_fill_color(WHITE);//清屏
                    HAL_Delay(1000);
                    return;//校正完成
            }
        }
        HAL_Delay(10);
//        outtime++;
//        if (outtime > 1000) {
//            break;
//        }
    }

}
/*--------------------------------------------------模拟通讯协议------------------------------------------*/




static inline void spi_write_byte(uint8_t dat);


//SPI读数据
//从触摸屏IC读取adc值
//cmd:指令
//返回值:读到的数据
uint16_t lcd_touch_read_ad(uint8_t cmd) {

    uint8_t count=0;
    uint16_t Num=0;
    TCLK=0;		//先拉低时钟
    TDIN=0; 	//拉低数据线
    TCS=0; 		//选中触摸屏IC
    spi_write_byte(cmd);//发送命令字
    bsp_DelayDWTUS(6);//ADS7846的转换时间最长为6us
    TCLK=0;
    bsp_DelayDWTUS(1);
    TCLK=1;		//给1个时钟,清除BUSY
    bsp_DelayDWTUS(1);
    TCLK=0;
    for(count=0;count<16;count++)//读出16位数据,只有高12位有效
    {
        Num<<=1;
        TCLK=0;	//下降沿有效
        bsp_DelayDWTUS(1);
        TCLK=1;
        if(DOUT)Num++;
    }
    Num>>=4;   	//只有高12位有效.
    TCS=1;		//释放片选
    return(Num);
}

static inline void spi_write_byte(uint8_t dat) {

    uint8_t count=0;
    for(count=0;count<8;count++)
    {
        if(dat&0x80)TDIN=1;
        else TDIN=0;
        dat<<=1;
        TCLK=0;
        bsp_DelayDWTUS(1);
        TCLK=1;		//上升沿有效
    }
}


/**
 * @brief 触摸扫描,事件驱动
 *  @note 需要指定对应的函数回调  @see g_lcd_touch.touch_send_event
 */
void lcd_touch_scan2(void) {

    if (PEN == 0)//有按键按下
    {
        if (lcd_touch_read_xy2(&g_lcd_touch.x[0], &g_lcd_touch.y[0]))//读取屏幕坐标
        {
            g_lcd_touch.x[0] = g_lcd_touch.xfac * g_lcd_touch.x[0] + g_lcd_touch.xoff;//将结果转换为屏幕坐标
            g_lcd_touch.y[0] = g_lcd_touch.yfac * g_lcd_touch.y[0] + g_lcd_touch.yoff;
        }
        if ((g_lcd_touch.sta & TP_PRES_DOWN) == 0)//之前没有被按下--->按下事件
        {
            g_lcd_touch.sta = TP_PRES_DOWN | TP_CATH_PRES;//按键按下
            g_lcd_touch.x[4] = g_lcd_touch.x[0];//记录第一次按下时的坐标
            g_lcd_touch.y[4] = g_lcd_touch.y[0];

            if (g_lcd_touch.touch_send_event) {
//                BSP_Printf("TOUCH_DOWN_EVENT_ID:%d,%d\r\n", g_lcd_touch.x[0], g_lcd_touch.y[0]);
                g_lcd_touch.touch_send_event(TOUCH_DOWN_EVENT_ID, g_lcd_touch.x[0], g_lcd_touch.y[0]);
            }

        } else { // 之前按下--> 移动事件
            if (g_lcd_touch.touch_send_event) {
//                BSP_Printf("TOUCH_MOVE_EVENT_ID:%d,%d\r\n", g_lcd_touch.x[0], g_lcd_touch.y[0]);
                g_lcd_touch.touch_send_event(TOUCH_MOVE_EVENT_ID, g_lcd_touch.x[0], g_lcd_touch.y[0]);
            }
        }
    } else {
        if (g_lcd_touch.sta & TP_PRES_DOWN)//之前是被按下的--释放事件
        {
            g_lcd_touch.sta &= ~(1 << 7);//标记按键松开
            if (g_lcd_touch.touch_send_event) {
//                BSP_Printf("TOUCH_RELEASE_EVENT_ID:%d,%d\r\n", g_lcd_touch.x[0], g_lcd_touch.y[0]);
                g_lcd_touch.touch_send_event(TOUCH_RELEASE_EVENT_ID, g_lcd_touch.x[0], g_lcd_touch.y[0]);
            }


        } else//之前就没有被按下
        {
            g_lcd_touch.x[4] = 0;
            g_lcd_touch.y[4] = 0;
            g_lcd_touch.x[0] = 0xffff;
            g_lcd_touch.y[0] = 0xffff;
        }
    }
}


GUIX 图形化开发工具

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

测试

驱动中添加日志

v

结果

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

问题解决

导致原因(设置窗口区域函数参数)

  1. 原有的提供函数,参数注释后面两个参数代码宽和高,实际上确实代表坐标点
/**
 * @brief 设置窗口
 *
 *  (x1,y1)-------------
 *  --------------------
 *  --------------------
 *  --------------------
 *  --------------(x2,y2)
 *
 *
 *
 * @param sx   左上点(x轴坐标) x1
 * @param sy   左上点(y轴坐标) y1
 * @param ex   右下点(x轴坐标) x2
 * @param ey   右下点(y轴坐标) y2
 */
void lcd_tft_setWin(uint16_t sx, uint16_t sy, uint16_t ex, uint16_t ey) {
    write_cmd(0x2a);
    write_data(sx >> 8);
    write_data(sx & 0XFF);
    write_data(ex >> 8);
    write_data(ex & 0XFF);
    write_cmd(0x2b);
    write_data(sy >> 8);
    write_data(sy & 0XFF);
    write_data(ey>> 8);
    write_data(ey & 0XFF);
}

最新的gx显示屏驱动函数(测试已ok)

#include "includes.h"

#if 1

#include "gx_stm32_display_driver_16bpp.h"
#include "tx_api.h"
#include "gx_api.h"
#include "gx_display.h"
#include "gx_utility.h"

/*
*********************************************************************************************************
*                                           变量和函数
*********************************************************************************************************
*/

/*
*********************************************************************************************************
*	函 数 名: stm32f4_565rgb_buffer_toggle
*	功能说明: 更新canvas内容到LCD显存
*	形    参: 无
*	返 回 值: 无
*********************************************************************************************************
*/

static inline void dbg_rectangle_inf(char *name, GX_RECTANGLE *rec) {
    tx_printf("%s:(%d,%d)-----(%d,%d)\r\n", name,
              rec->gx_rectangle_left, rec->gx_rectangle_top, /*左上顶点*/
              rec->gx_rectangle_right, rec->gx_rectangle_bottom /*右下顶点*/
    );
}



/**
 * @brief 更新整个画布区域(直接,效率来说最低)
 * @param canvas
 * @param dirty
 */
static void stm32f4_565rgb_update_canvas_area(GX_CANVAS *canvas, GX_RECTANGLE *dirty) {
    GX_RECTANGLE Limit;
    /*获取限制区域(即当前画布的区域范围),值赋值给 Limit 结构体*/
    gx_utility_rectangle_define(&Limit, 0, 0,
                                (GX_VALUE) (canvas->gx_canvas_x_resolution - 1),
                                (GX_VALUE) (canvas->gx_canvas_y_resolution - 1));

    // 添加日志
    dbg_rectangle_inf("dirty", dirty);

    lcd_tft_draw_fast_rgb_color(Limit.gx_rectangle_left,
                                Limit.gx_rectangle_top,
                                Limit.gx_rectangle_right,
                                Limit.gx_rectangle_bottom,
                                (uint16_t *) canvas->gx_canvas_memory);
}

/**
 * @brief lcd 局部刷新
 * @param canvas
 * @param dirty
 */
static void stm32f4_565rgb_buffer_toggle(GX_CANVAS *canvas, GX_RECTANGLE *dirty) {
    GX_RECTANGLE Limit;
    GX_RECTANGLE Copy;
    INT copy_width;
    INT copy_height;
    gx_utility_rectangle_define(&Limit, 0, 0,
                                canvas->gx_canvas_x_resolution,
                                canvas->gx_canvas_y_resolution);

    /*脏矩形与限制矩形做比较,得出需要修改的部分*/
    if (gx_utility_rectangle_overlap_detect(dirty, &Limit, &Copy)) {
        USHORT *memptr;
        int xsrc = Copy.gx_rectangle_left;
        int ysrc = Copy.gx_rectangle_top;
        /*修正与显示屏的偏移量*/
        gx_utility_rectangle_shift(&Copy, canvas->gx_canvas_display_offset_x, canvas->gx_canvas_display_offset_y);
        /*限制矩形与修正后的矩形作比较,比较返回结果覆盖原有的矩形数据*/
        if (gx_utility_rectangle_overlap_detect(&Limit, &Copy, &Copy)) {
            /*获取 帆布的内存首地址(内部存储颜色数据)*/
            memptr = (USHORT *) (canvas->gx_canvas_memory);
            memptr += ysrc * canvas->gx_canvas_x_resolution; /*对首地址进行行偏移量递增(这里需要注意指针偏移的计算)*/
            memptr += xsrc;/*进行列偏移量------->这里就得到脏数据颜色的首地址*/
            // 计算 需要覆盖的 矩形的宽和高
            copy_width = Copy.gx_rectangle_right - Copy.gx_rectangle_left + 1;
            copy_height = Copy.gx_rectangle_bottom - Copy.gx_rectangle_top + 1;
//            logInfo("buffer_toggle %p,(%d,%d)--width:%d,height:%d", memptr,
//                    Copy.gx_rectangle_left,Copy.gx_rectangle_top,
//                    copy_width,copy_height);
            lcd_tft_setWin(Copy.gx_rectangle_left,
                           Copy.gx_rectangle_top,
                           Copy.gx_rectangle_right,
                           Copy.gx_rectangle_bottom);
            lcd_tft_write_ram_prepare();
            //gx采用 z字形存储方式
            for (int y = 0; y < copy_height; y++) {
                for (int i = 0; i < copy_width; ++i) {
                    lcd_tft_write_color(memptr[i]);
                }
                memptr += canvas->gx_canvas_x_resolution;
            }
        }

    }
}


/*
*********************************************************************************************************
*	函 数 名: stm32f4_graphics_driver_setup_565rgb
*	功能说明: 驱动接口函数
*	形    参: ---
*	返 回 值: GX_SUCCESS
*********************************************************************************************************
*/
UINT stm32f4_graphics_driver_setup_565rgb(GX_DISPLAY *display) {

    _gx_display_driver_565rgb_setup(display, (VOID *) STM32_SCREEN_HANDLE, stm32f4_565rgb_buffer_toggle);
    return (GX_SUCCESS);
}


#endif

使用说明

在这里插入图片描述

总结

  1. 本次guix的显示驱动测试已经没有问题了,提供了两种方式,一种是全部刷新,一种是局部刷新
  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

詩不诉卿

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

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

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

打赏作者

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

抵扣说明:

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

余额充值