前言
- 图形化开发界面选择(awizard)
- emwin使用的版本是6.10
- 芯片采用的是stm32f407zgt6
- 这里使用的开发板是普中麒麟f4系列的
lcd驱动文件(基于提供的源码修改)
1、这里是剔除了很多兼容其他显示屏部分的代码,只保留具体信号的代码,把一些全局变量放到结构体中
头文件
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-6 shchl first version
*/
#ifndef APP_NO_OS_BSP_TFT_LCD_HX8357D_H
#define APP_NO_OS_BSP_TFT_LCD_HX8357D_H
#include "bsp_includes.h"
//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
#define DARKBLUE 0X01CF //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458 //灰蓝色
#define LIGHTGREEN 0X841F //浅绿色
#define LIGHTGRAY 0XEF5B //浅灰色(PANNEL)
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
#define LCD_TFT_DIR 0
#if LCD_TFT_DIR == 1
#define LCD_TFT_WIDTH 480
#define LCD_TFT_HIGH 320
#else
#define LCD_TFT_WIDTH 320
#define LCD_TFT_HIGH 480
#endif
typedef struct tft_lcd_struct {
volatile uint16_t reg;
volatile uint16_t ram;
} tft_lcd;
//TFTLCD重要参数集
typedef struct tft_lcd_data_struct {
uint16_t width; //LCD 宽度
uint16_t height; //LCD 高度
uint16_t id; //LCD ID
uint8_t dir; //LCD 方向
uint16_t front_color; /*前景色*/
uint16_t back_color; /*背景色*/
} tft_lcd_data;
//使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A6作为数据命令区分线
//注意设置时STM32内部会右移一位对齐! 111 1110=0X7E
#define TFTLCD_BASE ((uint32_t)(0x6C000000 | 0x0000007E))
extern tft_lcd_data g_tft_lcd_data; //管理LCD重要参数
void bsp_InitTftLCD(void);
void lcd_tft_set_backlight(uint8_t pwm);
void lcd_tft_write_color(uint16_t color);
uint16_t lcd_tft_read_color(uint16_t x, uint16_t y);
void lcd_tft_draw_point(uint16_t x, uint16_t y);
void lcd_tft_draw_point_ex(uint16_t x, uint16_t y, uint16_t color);
void lcd_tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
void lcd_tft_draw_line_ex(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color);
void lcd_tft_draw_circle(uint16_t x0, uint16_t y0, uint8_t r);
void lcd_tft_draw_circle_ex(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color);
void lcd_tft_set_dir(uint8_t dir);
void lcd_tft_write_ram_prepare(void);
void lcd_tft_fill_color(uint16_t color);
void lcd_tft_fill_area_color(uint16_t xState, uint16_t yState, uint16_t xEnd, uint16_t yEnd, uint16_t color);
void lcd_tft_setWin(uint16_t sx, uint16_t sy, uint16_t width, uint16_t height);
#if 1
void lcd_tft_show_char(uint16_t x, uint16_t y, uint8_t num, uint8_t size, uint8_t mode);
void lcd_tft_show_str(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, uint8_t *p);
#endif
#endif //APP_NO_OS_BSP_TFT_LCD_HX8357D_H
源文件
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-6 shchl first version
*/
#include "bsp_tft_lcd_hx8357d.h"
#include "font.H"
#include "bsp_fsmc_lcd.h"
#ifdef HAL_SRAM_MODULE_ENABLED
#define tft ((volatile tft_lcd *) TFTLCD_BASE)
#define tft_delay_ms bsp_DelayDWTMS
static inline void tft_lcd_cmd_init();
tft_lcd_data g_tft_lcd_data = {
.back_color =WHITE,
.front_color=BLACK,
.dir = LCD_TFT_DIR,
.width = LCD_TFT_WIDTH,
.height = LCD_TFT_HIGH
};
//写寄存器函数
//cmd:寄存器值
static inline void write_cmd(uint16_t cmd) { tft->reg = cmd; }
//写数据
//data:要写入的值
static inline void write_data(uint16_t data) { tft->ram = data; }
static inline uint16_t read_data(void) { return tft->ram; }
static void back_led_gpio_init(void) {
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_GPIOB_CLK_ENABLE(); //开启GPIOB时钟
GPIO_Initure.Pin = GPIO_PIN_15; //PB15,背光控制
GPIO_Initure.Mode = GPIO_MODE_OUTPUT_PP; //推挽输出
GPIO_Initure.Pull = GPIO_PULLUP; //上拉
GPIO_Initure.Speed = GPIO_SPEED_HIGH; //高速
HAL_GPIO_Init(GPIOB, &GPIO_Initure);
}
void bsp_InitTftLCD(void) {
back_led_gpio_init();
bsp_InitExLCD();
tft_delay_ms(50);
// 读id,这个根据手册上描述,需要开启扩展指令,否则读取的数据是不正确的。
// 如果你发现读取的id全部为 0xffff,就是没有开启扩展指令.这里由于影响不大,就不做处理
write_cmd(0Xd0);
g_tft_lcd_data.id = read_data(); //dummy read
g_tft_lcd_data.id = read_data();
tft_lcd_cmd_init(); /*出厂指令初始化*/
lcd_tft_set_dir(g_tft_lcd_data.dir); /*设置方向*/
lcd_tft_fill_color(g_tft_lcd_data.back_color);
}
//SSD1963 背光设置
//pwm:背光等级,0~100.越大越亮.
void lcd_tft_set_backlight(uint8_t pwm) {
write_cmd(0xBE); //配置PWM输出
write_data(0x05); //1设置PWM频率
write_data(pwm * 2.55);//2设置PWM占空比
write_data(0x01); //3设置C
write_data(0xFF); //4设置D
write_data(0x00); //5设置E
write_data(0x00); //6设置F
}
void lcd_tft_write_color(uint16_t color) {
write_data(color >> 8);
write_data(color & 0xff);
}
//读取个某点的颜色值
//x,y:坐标
//返回值:此点的颜色
uint16_t lcd_tft_read_color(uint16_t x, uint16_t y) {
uint16_t r = 0, g = 0, b = 0;
if (x >= g_tft_lcd_data.width || y >= g_tft_lcd_data.height)return 0; //超过了范围,直接返回
lcd_tft_setWin(x, y, x, y);
write_cmd(0X2E);
r = tft->ram;
r = tft->ram;
g = tft->ram;
b = tft->ram;
r = r << 8 | (g & 0xff);
return r;
}
//画点
//x,y:坐标
//FRONT_COLOR:此点的颜色
void lcd_tft_draw_point(uint16_t x, uint16_t y) {
lcd_tft_setWin(x, y, x, y); //设置点的位置
lcd_tft_write_ram_prepare();
lcd_tft_write_color(g_tft_lcd_data.front_color);
}
//画点
//x,y:坐标
//color:颜色
void lcd_tft_draw_point_ex(uint16_t x, uint16_t y, uint16_t color) {
uint16_t old = g_tft_lcd_data.front_color;
g_tft_lcd_data.front_color = color;
lcd_tft_draw_point(x, y);
g_tft_lcd_data.front_color = old;
}
//画线
//x1,y1:起点坐标
//x2,y2:终点坐标
void lcd_tft_draw_line(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2) {
uint16_t t;
int xerr = 0, yerr = 0, delta_x, delta_y, distance;
int incx, incy, uRow, uCol;
delta_x = x2 - x1; //计算坐标增量
delta_y = y2 - y1;
uRow = x1;
uCol = y1;
if (delta_x > 0)incx = 1; //设置单步方向
else if (delta_x == 0)incx = 0;//垂直线
else {
incx = -1;
delta_x = -delta_x;
}
if (delta_y > 0)incy = 1;
else if (delta_y == 0)incy = 0;//水平线
else {
incy = -1;
delta_y = -delta_y;
}
if (delta_x > delta_y)distance = delta_x; //选取基本增量坐标轴
else distance = delta_y;
for (t = 0; t <= distance + 1; t++)//画线输出
{
lcd_tft_draw_point(uRow, uCol);//画点
xerr += delta_x;
yerr += delta_y;
if (xerr > distance) {
xerr -= distance;
uRow += incx;
}
if (yerr > distance) {
yerr -= distance;
uCol += incy;
}
}
}
void lcd_tft_draw_line_ex(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t color) {
uint16_t old = g_tft_lcd_data.front_color;
g_tft_lcd_data.front_color = color;
lcd_tft_draw_line(x1, y1, x2, y2);
g_tft_lcd_data.front_color = old;
}
//在指定位置画一个指定大小的圆
//(x,y):中心点
//r :半径
void lcd_tft_draw_circle(uint16_t x0, uint16_t y0, uint8_t r) {
int a, b;
int di;
a = 0;
b = r;
di = 3 - (r << 1); //判断下个点位置的标志
while (a <= b) {
lcd_tft_draw_point(x0 + a, y0 - b); //5
lcd_tft_draw_point(x0 + b, y0 - a); //0
lcd_tft_draw_point(x0 + b, y0 + a); //4
lcd_tft_draw_point(x0 + a, y0 + b); //6
lcd_tft_draw_point(x0 - a, y0 + b); //1
lcd_tft_draw_point(x0 - b, y0 + a);
lcd_tft_draw_point(x0 - a, y0 - b); //2
lcd_tft_draw_point(x0 - b, y0 - a); //7
a++;
//使用Bresenham算法画圆
if (di < 0)di += 4 * a + 6;
else {
di += 10 + 4 * (a - b);
b--;
}
}
}
void lcd_tft_draw_circle_ex(uint16_t x0, uint16_t y0, uint8_t r, uint16_t color) {
uint16_t old = g_tft_lcd_data.front_color;
g_tft_lcd_data.front_color = color;
lcd_tft_draw_circle(x0, y0, r);
g_tft_lcd_data.front_color = old;
}
//设置LCD显示方向
//dir:0,竖屏;1,横屏
void lcd_tft_set_dir(uint8_t dir) {
g_tft_lcd_data.dir = dir; //横屏/竖屏
if (dir == 0) //默认竖屏方向
{
write_cmd(0x36); //设置彩屏显示方向的寄存器
write_data(0x4c);
g_tft_lcd_data.height = 480;
g_tft_lcd_data.width = 320;
} else {
write_cmd(0x36);
write_data(0x2c);
g_tft_lcd_data.height = 320;
g_tft_lcd_data.width = 480;
}
}
//设置窗口,并自动设置画点坐标到窗口左上角(sx,sy).
//sx,sy:窗口起始坐标(左上角)
//width,height:窗口宽度和高度,必须大于0!!
//窗体大小:width*height.
void lcd_tft_setWin(uint16_t sx, uint16_t sy, uint16_t width, uint16_t height) {
write_cmd(0x2a);
write_data(sx >> 8);
write_data(sx & 0XFF);
write_data(width >> 8);
write_data(width & 0XFF);
write_cmd(0x2b);
write_data(sy >> 8);
write_data(sy & 0XFF);
write_data(height >> 8);
write_data(height & 0XFF);
}
/**
* @brief 发送开始写ram 的指令,配合@see lcd_tft_setWin 函数一起使用
* @note
* lcd_tft_setWin(0,0,120,120);
* lcd_tft_write_ram_prepare();
*
*
*
*/
void lcd_tft_write_ram_prepare(void) {
write_cmd(0x2c);
}
/**
* @brief 全屏填充颜色
* @param color 要清屏的填充色
*/
void lcd_tft_fill_color(uint16_t color) {
uint16_t i, j;
lcd_tft_setWin(0, 0, g_tft_lcd_data.width - 1, g_tft_lcd_data.height - 1); //作用区域
lcd_tft_write_ram_prepare();
for (i = 0; i < g_tft_lcd_data.width; i++) {
for (j = 0; j < g_tft_lcd_data.height; j++) {
lcd_tft_write_color(color);
}
}
}
void lcd_tft_fill_area_color(uint16_t xState, uint16_t yState, uint16_t xEnd, uint16_t yEnd, uint16_t color){
uint16_t temp;
if((xState > xEnd) || (yState > yEnd))
{
return;
}
lcd_tft_setWin(xState, yState, xEnd, yEnd);
lcd_tft_write_ram_prepare();
xState = xEnd - xState + 1;
yState = yEnd - yState + 1;
while(xState--)
{
temp = yState;
while (temp--)
{
lcd_tft_write_color(color);
}
}
}
#if 1
//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24
//mode:叠加方式(1)还是非叠加方式(0)
void lcd_tft_show_char(uint16_t x, uint16_t y, uint8_t num, uint8_t size, uint8_t mode) {
uint8_t temp, t1, t;
uint16_t y0 = y;
uint8_t csize = (size / 8 + ((size % 8) ? 1 : 0)) * (size / 2); //得到字体一个字符对应点阵集所占的字节数
num = num - ' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
for (t = 0; t < csize; t++) {
if (size == 12)temp = ascii_1206[num][t]; //调用1206字体
else if (size == 16)temp = ascii_1608[num][t]; //调用1608字体
else if (size == 24)temp = ascii_2412[num][t]; //调用2412字体
else return; //没有的字库
for (t1 = 0; t1 < 8; t1++) {
if (temp & 0x80)lcd_tft_draw_point_ex(x, y, g_tft_lcd_data.front_color);
else if (mode == 0)lcd_tft_draw_point_ex(x, y, g_tft_lcd_data.back_color);
temp <<= 1;
y++;
if (y >= g_tft_lcd_data.height)return; //超区域了
if ((y - y0) == size) {
y = y0;
x++;
if (x >= g_tft_lcd_data.width)return; //超区域了
break;
}
}
}
}
//显示字符串
//x,y:起点坐标
//width,height:区域大小
//size:字体大小
//*p:字符串起始地址
void lcd_tft_show_str(uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t size, uint8_t *p) {
uint8_t x0 = x;
width += x;
height += y;
while ((*p <= '~') && (*p >= ' '))//判断是不是非法字符!
{
if (x >= width) {
x = x0;
y += size;
}
if (y >= height)break;//退出
lcd_tft_show_char(x, y, *p, size, 0);
x += size / 2;
p++;
}
}
#endif
static inline void tft_lcd_cmd_init() {
write_cmd(0xE9);
write_data(0x20);
write_cmd(0x11); //Exit Sleep
tft_delay_ms(120);
write_cmd(0x3A);
write_data(0x55); //16Bit colors
write_cmd(0xD1);
write_data(0x00);
write_data(0x65); //调试此值改善水纹
write_data(0x1F);
write_cmd(0xD0);
write_data(0x07);
write_data(0x07);
write_data(0x80);
write_cmd(0x36); //Set_address_mode
write_data(0x4c); //4c
write_cmd(0xC1);
write_data(0x10);
write_data(0x10);
write_data(0x02);
write_data(0x02);
write_cmd(0xC0); //Set Default Gamma
write_data(0x00);
write_data(0x35);
write_data(0x00);
write_data(0x00);
write_data(0x01);
write_data(0x02);
write_cmd(0xC4);
write_data(0x03);
write_cmd(0xC5); //Set frame rate
write_data(0x01);
write_cmd(0xD2); //power setting
write_data(0x01);
write_data(0x22);
write_cmd(0xE7);
write_data(0x38);
write_cmd(0xF3);
write_data(0x08);
write_data(0x12);
write_data(0x12);
write_data(0x08);
write_cmd(0xC8); //Set Gamma
write_data(0x01);
write_data(0x52);
write_data(0x37);
write_data(0x10);
write_data(0x0d);
write_data(0x01);
write_data(0x04);
write_data(0x51);
write_data(0x77);
write_data(0x01);
write_data(0x01);
write_data(0x0d);
write_data(0x08);
write_data(0x80);
write_data(0x00);
write_cmd(0x29);
}
#endif
硬件初始化
SRAM_HandleTypeDef TFTSRAM_Handler; //SRAM句柄(用于控制LCD)
void fsmc_norsram_bank4_msp_init() {
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_FSMC_CLK_ENABLE(); //使能FSMC时钟
__HAL_RCC_GPIOD_CLK_ENABLE(); //使能GPIOD时钟
__HAL_RCC_GPIOE_CLK_ENABLE(); //使能GPIOE时钟
__HAL_RCC_GPIOF_CLK_ENABLE(); //使能GPIOF时钟
__HAL_RCC_GPIOG_CLK_ENABLE(); //使能GPIOG时钟
//初始化PD0,1,4,5,8,9,10,14,15
GPIO_Initure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_8 |
GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 | GPIO_PIN_15;
GPIO_Initure.Mode = GPIO_MODE_AF_PP; //推挽复用
GPIO_Initure.Pull = GPIO_PULLUP; //上拉
GPIO_Initure.Speed = GPIO_SPEED_HIGH; //高速
GPIO_Initure.Alternate = GPIO_AF12_FSMC; //复用为FSMC
HAL_GPIO_Init(GPIOD, &GPIO_Initure); //初始化
//初始化PE7,8,9,10,11,12,13,14,15
GPIO_Initure.Pin = GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_11 |
GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 | GPIO_PIN_15;
HAL_GPIO_Init(GPIOE, &GPIO_Initure);
//初始化PF12
GPIO_Initure.Pin = GPIO_PIN_12;
HAL_GPIO_Init(GPIOF, &GPIO_Initure);
//初始化PG12
GPIO_Initure.Pin = GPIO_PIN_12;
HAL_GPIO_Init(GPIOG, &GPIO_Initure);
}
void bsp_InitExLCD(void) {
FSMC_NORSRAM_TimingTypeDef FSMC_ReadWriteTim;
FSMC_NORSRAM_TimingTypeDef FSMC_WriteTim;
TFTSRAM_Handler.Instance = FSMC_NORSRAM_DEVICE;
TFTSRAM_Handler.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
TFTSRAM_Handler.Init.NSBank = FSMC_NORSRAM_BANK4; //使用NE4
TFTSRAM_Handler.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE; //地址/数据线不复用
TFTSRAM_Handler.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM; //SRAM
TFTSRAM_Handler.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16; //16位数据宽度
TFTSRAM_Handler.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE; //是否使能突发访问,仅对同步突发存储器有效,此处未用到
TFTSRAM_Handler.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;//等待信号的极性,仅在突发模式访问下有用
TFTSRAM_Handler.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS; //存储器是在等待周期之前的一个时钟周期还是等待周期期间使能NWAIT
TFTSRAM_Handler.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE; //存储器写使能
TFTSRAM_Handler.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE; //等待使能位,此处未用到
TFTSRAM_Handler.Init.ExtendedMode = FSMC_EXTENDED_MODE_ENABLE; //读写使用不同的时序
TFTSRAM_Handler.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;//是否使能同步传输模式下的等待信号,此处未用到
TFTSRAM_Handler.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE; //禁止突发写
TFTSRAM_Handler.Init.ContinuousClock = FSMC_CONTINUOUS_CLOCK_SYNC_ASYNC;
//FMC读时序控制寄存器
FSMC_ReadWriteTim.AddressSetupTime = 0x0F; //地址建立时间(ADDSET)为16个HCLK 1/168M=6ns*16=96ns
FSMC_ReadWriteTim.AddressHoldTime = 0;
FSMC_ReadWriteTim.DataSetupTime = 60; //数据保存时间为60个HCLK =6*60=360ns
FSMC_ReadWriteTim.AccessMode = FSMC_ACCESS_MODE_A;//模式A
//FMC写时序控制寄存器
FSMC_WriteTim.BusTurnAroundDuration = 0; //总线周转阶段持续时间为0,此变量不赋值的话会莫名其妙的自动修改为4。导致程序运行正常
FSMC_WriteTim.AddressSetupTime = 9; //地址建立时间(ADDSET)为9个HCLK =54ns
FSMC_WriteTim.AddressHoldTime = 0;
FSMC_WriteTim.DataSetupTime = 8; //数据保存时间为6ns*9个HCLK=54n
FSMC_WriteTim.AccessMode = FSMC_ACCESS_MODE_A; //模式A
HAL_SRAM_Init(&TFTSRAM_Handler, &FSMC_ReadWriteTim, &FSMC_WriteTim);
}
触摸驱动(基于源文件修改)
头文件
/*
* 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) {
static uint8_t s_tp_down = 0;
static uint16_t x_save, y_save;
static uint8_t s_count = 0;
uint16_t x = 0, y = 0;
if (PEN == 1) { // 没有按键按下
/* 持续按下时,INT电平是脉冲信号。每隔18ms出现1个宽度4ms的高电平。 */
if (s_tp_down == 1) {
if (++s_count > 2) {
s_count = 0;
s_tp_down = 0;
//释放
if (g_lcd_touch.touch_send_event) {
BSP_Printf("TOUCH_RELEASE_EVENT_ID:%d,%d\r\n", x_save, y_save);
g_lcd_touch.touch_send_event(TOUCH_RELEASE_EVENT_ID, x_save, y_save);
}
}
}
return;
}
s_count = 0;
if (lcd_touch_read_xy2(&x, &y))//读取屏幕坐标
{
x = (uint16_t) (g_lcd_touch.xfac * x) + g_lcd_touch.xoff;//将结果转换为屏幕坐标
y = (uint16_t) (g_lcd_touch.yfac * y) + g_lcd_touch.yoff;
} else {
return; /*数据无效*/
}
x_save = x; /* 保存坐标,用于释放事件 */
y_save = y;
if (s_tp_down == 0) {
s_tp_down = 1;
if (g_lcd_touch.touch_send_event) {
BSP_Printf("TOUCH_DOWN_EVENT_ID:%d,%d\r\n", x_save, y_save);
g_lcd_touch.touch_send_event(TOUCH_DOWN_EVENT_ID, x_save, y_save);
} else {
if (g_lcd_touch.touch_send_event) {
BSP_Printf("TOUCH_MOVE_EVENT_ID:%d,%d\r\n", x_save, y_save);
g_lcd_touch.touch_send_event(TOUCH_MOVE_EVENT_ID, x_save, y_save);
}
}
}
}
项目添加emwin头文件和链接静态库(采用CMakeLists来管理的)
根节点CMakeLists文件
对应的EmWin6的CMakeList文件
target_link_directories(${PROJECT_NAME}.elf
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/Libs
)
target_link_libraries(${PROJECT_NAME}.elf
PRIVATE
libGUI_v7em_fpv4_sp_d16_hard_OS0.a
)
target_sources(${PROJECT_NAME}.elf
PRIVATE
${CMAKE_CURRENT_LIST_DIR}/OS/GUI_X_OS.c
${CMAKE_CURRENT_LIST_DIR}/OS/GUI_X_Touch_Analog.c
${CMAKE_CURRENT_LIST_DIR}/OS/GUIConf.c
${CMAKE_CURRENT_LIST_DIR}/OS/GUIDRV_Template.c
${CMAKE_CURRENT_LIST_DIR}/OS/LCDConf_FlexColor_Template.c
)
target_include_directories(${PROJECT_NAME}.elf
PUBLIC
${CMAKE_CURRENT_LIST_DIR}/Inc
)
EmWIn源码实现
GUI_X_OS.c (与os相关的)
/*********************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1996 - 2017 SEGGER Microcontroller GmbH & Co. KG *
* *
* Internet: www.segger.com Support: support@segger.com *
* *
**********************************************************************
** emWin V5.44 - Graphical user interface for embedded applications **
All Intellectual Property rights in the Software belongs to SEGGER.
emWin is protected by international copyright laws. Knowledge of the
source code may not be used to write a similar product. This file may
only be used in accordance with the following terms:
The software has been licensed to STMicroelectronics International
N.V. a Dutch company with a Swiss branch and its headquarters in Plan-
les-Ouates, Geneva, 39 Chemin du Champ des Filles, Switzerland for the
purposes of creating libraries for ARM Cortex-M-based 32-bit microcon_
troller products commercialized by Licensee only, sublicensed and dis_
tributed under the terms and conditions of the End User License Agree_
ment supplied by STMicroelectronics International N.V.
Full source code is available at: www.segger.com
We appreciate your understanding and fairness.
----------------------------------------------------------------------
File : GUI_X_OS.C
Purpose : This file provides emWin Interface with FreeRTOS
---------------------------END-OF-HEADER------------------------------
*/
/**
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2018 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license SLA0044,
* the "License"; You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
* http://www.st.com/SLA0044
*
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "GUI.h"
#include "includes.h"
/*********************************************************************
*
* Global data
*/
static TX_MUTEX osMutex;
static TX_SEMAPHORE osSemaphore;
static TX_SEMAPHORE KeySem;
static int KeyPressed;
static char KeyIsInited = TX_FALSE;
/*********************************************************************
*
* Timing:
* GUI_X_GetTime()
* GUI_X_Delay(int)
Some timing dependent routines require a GetTime
and delay function. Default time unit (tick), normally is
1 ms.
*/
int GUI_X_GetTime(void) {
return ((int) tx_time_get());
}
void GUI_X_Delay(int ms) {
tx_thread_sleep(ms);
}
/*********************************************************************
*
* GUI_X_ExecIdle
*
* Note:
* Called if WM is in idle state
*/
void GUI_X_ExecIdle(void) {
GUI_X_Delay(1);
}
/*********************************************************************
*
* Multitasking:
*
* GUI_X_InitOS()
* GUI_X_GetTaskId()
* GUI_X_Lock()
* GUI_X_Unlock()
*
* Note:
* The following routines are required only if emWin is used in a
* true multi task environment, which means you have more than one
* thread using the emWin API.
* In this case the
* #define GUI_OS 1
* needs to be in GUIConf.h
*/
/* Init OS */
void GUI_X_InitOS(void) {
/* Create the Mutex used by the two threads */
tx_mutex_create(&osMutex, "emWinMutex", TX_NO_INHERIT);
/* Create the Semaphore used by the two threads */
tx_semaphore_create(&osSemaphore, "emWinSem", 1);
}
void GUI_X_Unlock(void) {
tx_mutex_put(&osMutex);
}
void GUI_X_Lock(void) {
tx_mutex_get(&osMutex, TX_WAIT_FOREVER);
}
/* Get Task handle */
U32 GUI_X_GetTaskId(void) {
return tx_thread_identify()->tx_thread_id;
}
void GUI_X_WaitEvent(void) {
tx_semaphore_get(&osSemaphore, TX_WAIT_FOREVER);
}
void GUI_X_SignalEvent(void) {
tx_semaphore_put(&osSemaphore);
}
/*
*********************************************************************************************************
* KEYBOARD INTERFACE FUNCTIONS
*
* Purpose: The keyboard routines are required only by some widgets.
* If widgets are not used, they may be eliminated.
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* CheckInit()
*
* Description : Initialize the GUI keyboard if it is not already done.
*
* Argument(s) : none.
*
* Return(s) : none.
*
* Caller(s) : GUI_X_WaitKey().
* GUI_X_GetKey().
*
* Note(s) : none.
*********************************************************************************************************
*/
void CheckInit(void) {
if (KeyIsInited == TX_FALSE) {
KeyIsInited = TX_TRUE;
GUI_X_Init();
}
}
/*********************************************************************
*
* GUI_X_Init()
*
* Note:
* GUI_X_Init() is called from GUI_Init is a possibility to init
* some hardware which needs to be up and running before the GUI.
* If not required, leave this routine blank.
*/
void GUI_X_Init(void) {
tx_semaphore_create(&KeySem, "keySem", 0);
}
/*
*********************************************************************************************************
* GUI_X_GetKey()
*
* Description : Get the pressed key.
*
* Argument(s) : none.
*
* Return(s) : Pressed key.
*
* Caller(s) : various.
*
* Note(s) : none.
*********************************************************************************************************
*/
int GUI_X_GetKey(void) {
int r;
r = KeyPressed;
CheckInit();
KeyPressed = 0;
return (r);
}
/*
*********************************************************************************************************
* GUI_X_WaitKey()
*
* Description : Wait for a key to be pressed and return it.
*
* Argument(s) : none.
*
* Return(s) : Pressed key.
*
* Caller(s) : various.
*
* Note(s) : none.
*********************************************************************************************************
*/
int GUI_X_WaitKey(void) {
int r;
CheckInit();
if (KeyPressed == 0) {
tx_semaphore_get(&KeySem, TX_WAIT_FOREVER);
}
r = KeyPressed;
KeyPressed = 0;
return (r);
}
/*
*********************************************************************************************************
* GUI_X_StoreKey()
*
* Description : Store the pressed key.
*
* Argument(s) : Pressed key.
*
* Return(s) : none.
*
* Caller(s) : various.
*
* Note(s) : none.
*********************************************************************************************************
*/
void GUI_X_StoreKey(int k) //--------------( 14)
{
KeyPressed = k;
tx_semaphore_put(&KeySem);
}
/*********************************************************************
*
* Logging: OS dependent
Note:
Logging is used in higher debug levels only. The typical target
build does not use logging and does therefor not require any of
the logging routines below. For a release build without logging
the routines below may be eliminated to save some space.
(If the linker is not function aware and eliminates unreferenced
functions automatically)
*/
void GUI_X_Log(const char *s) {}
void GUI_X_Warn(const char *s) {}
void GUI_X_ErrorOut(const char *s) {}
/*************************** End of file ****************************/
GUIConf.c 配置相关
/*********************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1996 - 2017 SEGGER Microcontroller GmbH & Co. KG *
* *
* Internet: www.segger.com Support: support@segger.com *
* *
**********************************************************************
** emWin V5.44 - Graphical user interface for embedded applications **
All Intellectual Property rights in the Software belongs to SEGGER.
emWin is protected by international copyright laws. Knowledge of the
source code may not be used to write a similar product. This file may
only be used in accordance with the following terms:
The software has been licensed to STMicroelectronics International
N.V. a Dutch company with a Swiss branch and its headquarters in Plan-
les-Ouates, Geneva, 39 Chemin du Champ des Filles, Switzerland for the
purposes of creating libraries for ARM Cortex-M-based 32-bit microcon_
troller products commercialized by Licensee only, sublicensed and dis_
tributed under the terms and conditions of the End User License Agree_
ment supplied by STMicroelectronics International N.V.
Full source code is available at: www.segger.com
We appreciate your understanding and fairness.
----------------------------------------------------------------------
File : GUIConf.c
Purpose : Display controller initialization
---------------------------END-OF-HEADER------------------------------
*/
/**
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2018 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license SLA0044,
* the "License"; You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
* http://www.st.com/SLA0044
*
******************************************************************************
*/
#include "GUI.h"
#include "includes.h"
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
//
// Define the available number of bytes available for the GUI
//
#define GUI_NUMBYTES (PKG_STEMWIN_MEM_SIZE)
/* Define the average block size */
#define GUI_BLOCKSIZE 0x80
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* GUI_X_Config
*
* Purpose:
* Called during the initialization process in order to set up the
* available memory for the GUI.
*/
void GUI_X_Config(void) {
#if 0
//
// 32 bit aligned memory area
//
static U32 aMemory[GUI_NUMBYTES / 4];
//
// Assign memory to emWin
//
GUI_ALLOC_AssignMemory(aMemory, GUI_NUMBYTES);
GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSIZE);
#else /*外部sram*/
#define EMWIN_MEM_SIZE 500*1024
extern struct rt_memheap ex_ram_heap;
static U32 *aMemory;
aMemory = (U32 *) bsp_malloc(EMWIN_MEM_SIZE);
/* Assign memory to emWin */
GUI_ALLOC_AssignMemory(aMemory, EMWIN_MEM_SIZE);
GUI_ALLOC_SetAvBlockSize(GUI_BLOCKSIZE);
#endif
//
// Set default font
//
GUI_SetDefaultFont(GUI_FONT_6X8);
}
/*************************** End of file ****************************/
void APPW_X_FS_Init(void) {
}
GUIDRV_Template.c (驱动,画点,读点)
/*********************************************************************
* Portions COPYRIGHT 2013 STMicroelectronics *
* Portions SEGGER Microcontroller GmbH & Co. KG *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1996 - 2013 SEGGER Microcontroller GmbH & Co. KG *
* *
* Internet: www.segger.com Support: support@segger.com *
* *
**********************************************************************
** emWin V5.22 - Graphical user interface for embedded applications **
All Intellectual Property rights in the Software belongs to SEGGER.
emWin is protected by international copyright laws. Knowledge of the
source code may not be used to write a similar product. This file may
only be used in accordance with the following terms:
The software has been licensed to STMicroelectronics International
N.V. a Dutch company with a Swiss branch and its headquarters in Plan-
les-Ouates, Geneva, 39 Chemin du Champ des Filles, Switzerland for the
purposes of creating libraries for ARM Cortex-M-based 32-bit microcon_
troller products commercialized by Licensee only, sublicensed and dis_
tributed under the terms and conditions of the End User License Agree_
ment supplied by STMicroelectronics International N.V.
Full source code is available at: www.segger.com
We appreciate your understanding and fairness.
----------------------------------------------------------------------
File : GUIDRV_Template.c
Purpose : Template driver, could be used as starting point for new
simple display drivers supporting only one color depth.
---------------------------END-OF-HEADER------------------------------
*/
/**
******************************************************************************
* @attention
*
* Licensed under MCD-ST Liberty SW License Agreement V2, (the "License");
* You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
*
* http://www.st.com/software_license_agreement_liberty_v2
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
******************************************************************************
*/
#include <stddef.h>
#include "LCD_Private.h"
#include "GUI_Private.h"
#include "LCD_ConfDefaults.h"
#include "includes.h"
/*********************************************************************
*
* Defines
*
**********************************************************************
*/
/*********************************************************************
*
* Macros for MIRROR_, SWAP_ and LUT_
*/
#if (!defined (LCD_LUT_COM) && !defined(LCD_LUT_SEG))
#if (!LCD_MIRROR_X && !LCD_MIRROR_Y && !LCD_SWAP_XY)
#define LOG2PHYS_X(x, y) x
#define LOG2PHYS_Y(x, y) y
#elif (!LCD_MIRROR_X && !LCD_MIRROR_Y && LCD_SWAP_XY)
#define LOG2PHYS_X(x, y) y
#define LOG2PHYS_Y(x, y) x
#elif (!LCD_MIRROR_X && LCD_MIRROR_Y && !LCD_SWAP_XY)
#define LOG2PHYS_X(x, y) x
#define LOG2PHYS_Y(x, y) LCD_YSIZE - 1 - (y)
#elif (!LCD_MIRROR_X && LCD_MIRROR_Y && LCD_SWAP_XY)
#define LOG2PHYS_X(x, y) y
#define LOG2PHYS_Y(x, y) LCD_XSIZE - 1 - (x)
#elif ( LCD_MIRROR_X && !LCD_MIRROR_Y && !LCD_SWAP_XY)
#define LOG2PHYS_X(x, y) LCD_XSIZE - 1 - (x)
#define LOG2PHYS_Y(x, y) y
#elif ( LCD_MIRROR_X && !LCD_MIRROR_Y && LCD_SWAP_XY)
#define LOG2PHYS_X(x, y) LCD_YSIZE - 1 - (y)
#define LOG2PHYS_Y(x, y) x
#elif ( LCD_MIRROR_X && LCD_MIRROR_Y && !LCD_SWAP_XY)
#define LOG2PHYS_X(x, y) LCD_XSIZE - 1 - (x)
#define LOG2PHYS_Y(x, y) LCD_YSIZE - 1 - (y)
#elif ( LCD_MIRROR_X && LCD_MIRROR_Y && LCD_SWAP_XY)
#define LOG2PHYS_X(x, y) LCD_YSIZE - 1 - (y)
#define LOG2PHYS_Y(x, y) LCD_XSIZE - 1 - (x)
#endif
#else
#if ( defined (LCD_LUT_COM) && !defined(LCD_LUT_SEG))
#define LOG2PHYS_X(x, y) x
#define LOG2PHYS_Y(x, y) LCD__aLine2Com0[y]
#elif (!defined (LCD_LUT_COM) && defined(LCD_LUT_SEG))
#define LOG2PHYS_X(x, y) LCD__aCol2Seg0[x]
#define LOG2PHYS_Y(x, y) y
#elif ( defined (LCD_LUT_COM) && defined(LCD_LUT_SEG))
#define LOG2PHYS_X(x, y) LCD__aCol2Seg0[x]
#define LOG2PHYS_Y(x, y) LCD__aLine2Com0[y]
#endif
#endif
/*********************************************************************
*
* Types
*
**********************************************************************
*/
typedef struct {
U32 VRAMAddr;
int xSize, ySize;
int vxSize, vySize;
int vxSizePhys;
int BitsPerPixel;
} DRIVER_CONTEXT_TEMPLATE;
/*********************************************************************
*
* Static functions
*
**********************************************************************
*/
/*********************************************************************
打点函数
*/
static void _SetPixelIndex(GUI_DEVICE * pDevice, int x, int y, int PixelIndex) {
lcd_tft_draw_point_ex(x,y,PixelIndex); //调用tftlcd.c文件中的打点函数
}
/*********************************************************************
*
读点函数
*/
static unsigned int _GetPixelIndex(GUI_DEVICE * pDevice, int x, int y) {
unsigned int PixelIndex;
#if (LCD_MIRROR_X == 1) || (LCD_MIRROR_Y == 1) || (LCD_SWAP_XY == 1)
int xPhys, yPhys;
xPhys = LOG2PHYS_X(x, y);
yPhys = LOG2PHYS_Y(x, y);
#else
#define xPhys x
#define yPhys y
#endif
GUI_USE_PARA(pDevice);
GUI_USE_PARA(x);
GUI_USE_PARA(y);
{
PixelIndex = lcd_tft_read_color(x,y);
}
#if (LCD_MIRROR_X == 0) && (LCD_MIRROR_Y == 0) && (LCD_SWAP_XY == 0)
#undef xPhys
#undef yPhys
#endif
return PixelIndex;
}
/*********************************************************************
*
* _XorPixel
*/
static void _XorPixel(GUI_DEVICE * pDevice, int x, int y) {
LCD_PIXELINDEX PixelIndex;
LCD_PIXELINDEX IndexMask;
PixelIndex = _GetPixelIndex(pDevice, x, y);
IndexMask = pDevice->pColorConvAPI->pfGetIndexMask();
_SetPixelIndex(pDevice, x, y, PixelIndex ^ IndexMask);
}
/*********************************************************************
*
* _FillRect
*/
static void _FillRect(GUI_DEVICE * pDevice, int x0, int y0, int x1, int y1) {
lcd_tft_fill_area_color(x0,y0,x1,y1,LCD_COLORINDEX);
}
/*********************************************************************
*
* _DrawHLine
*/
static void _DrawHLine(GUI_DEVICE * pDevice, int x0, int y, int x1) {
_FillRect(pDevice, x0, y, x1, y);
}
/*********************************************************************
*
* _DrawVLine, not optimized
*/
static void _DrawVLine(GUI_DEVICE * pDevice, int x, int y0, int y1) {
_FillRect(pDevice, x, y0, x, y1);
}
/*********************************************************************
*
* Draw Bitmap 1 BPP
*/
static void _DrawBitLine1BPP(GUI_DEVICE * pDevice, int x, int y, U8 const GUI_UNI_PTR * p, int Diff, int xsize, const LCD_PIXELINDEX * pTrans) {
LCD_PIXELINDEX IndexMask, Index0, Index1, Pixel;
Index0 = *(pTrans + 0);
Index1 = *(pTrans + 1);
x += Diff;
switch (GUI_pContext->DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) {
case 0:
do {
_SetPixelIndex(pDevice, x++, y, (*p & (0x80 >> Diff)) ? Index1 : Index0);
if (++Diff == 8) {
Diff = 0;
p++;
}
} while (--xsize);
break;
case LCD_DRAWMODE_TRANS:
do {
if (*p & (0x80 >> Diff))
_SetPixelIndex(pDevice, x, y, Index1);
x++;
if (++Diff == 8) {
Diff = 0;
p++;
}
} while (--xsize);
break;
case LCD_DRAWMODE_XOR | LCD_DRAWMODE_TRANS:
case LCD_DRAWMODE_XOR:
IndexMask = pDevice->pColorConvAPI->pfGetIndexMask();
do {
if (*p & (0x80 >> Diff)) {
Pixel = _GetPixelIndex(pDevice, x, y);
_SetPixelIndex(pDevice, x, y, Pixel ^ IndexMask);
}
x++;
if (++Diff == 8) {
Diff = 0;
p++;
}
} while (--xsize);
break;
}
}
/*********************************************************************
*
* Draw Bitmap 2 BPP
*/
static void _DrawBitLine2BPP(GUI_DEVICE * pDevice, int x, int y, U8 const GUI_UNI_PTR * p, int Diff, int xsize, const LCD_PIXELINDEX * pTrans) {
LCD_PIXELINDEX Pixels, PixelIndex;
int CurrentPixel, Shift, Index;
Pixels = *p;
CurrentPixel = Diff;
x += Diff;
switch (GUI_pContext->DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) {
case 0:
if (pTrans) {
do {
Shift = (3 - CurrentPixel) << 1;
Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift;
PixelIndex = *(pTrans + Index);
_SetPixelIndex(pDevice, x++, y, PixelIndex);
if (++CurrentPixel == 4) {
CurrentPixel = 0;
Pixels = *(++p);
}
} while (--xsize);
} else {
do {
Shift = (3 - CurrentPixel) << 1;
Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift;
_SetPixelIndex(pDevice, x++, y, Index);
if (++CurrentPixel == 4) {
CurrentPixel = 0;
Pixels = *(++p);
}
} while (--xsize);
}
break;
case LCD_DRAWMODE_TRANS:
if (pTrans) {
do {
Shift = (3 - CurrentPixel) << 1;
Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift;
if (Index) {
PixelIndex = *(pTrans + Index);
_SetPixelIndex(pDevice, x, y, PixelIndex);
}
x++;
if (++CurrentPixel == 4) {
CurrentPixel = 0;
Pixels = *(++p);
}
} while (--xsize);
} else {
do {
Shift = (3 - CurrentPixel) << 1;
Index = (Pixels & (0xC0 >> (6 - Shift))) >> Shift;
if (Index) {
_SetPixelIndex(pDevice, x, y, Index);
}
x++;
if (++CurrentPixel == 4) {
CurrentPixel = 0;
Pixels = *(++p);
}
} while (--xsize);
}
break;
}
}
/*********************************************************************
*
* Draw Bitmap 4 BPP
*/
static void _DrawBitLine4BPP(GUI_DEVICE * pDevice, int x, int y, U8 const GUI_UNI_PTR * p, int Diff, int xsize, const LCD_PIXELINDEX * pTrans) {
LCD_PIXELINDEX Pixels, PixelIndex;
int CurrentPixel, Shift, Index;
Pixels = *p;
CurrentPixel = Diff;
x += Diff;
switch (GUI_pContext->DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) {
case 0:
if (pTrans) {
do {
Shift = (1 - CurrentPixel) << 2;
Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift;
PixelIndex = *(pTrans + Index);
_SetPixelIndex(pDevice, x++, y, PixelIndex);
if (++CurrentPixel == 2) {
CurrentPixel = 0;
Pixels = *(++p);
}
} while (--xsize);
} else {
do {
Shift = (1 - CurrentPixel) << 2;
Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift;
_SetPixelIndex(pDevice, x++, y, Index);
if (++CurrentPixel == 2) {
CurrentPixel = 0;
Pixels = *(++p);
}
} while (--xsize);
}
break;
case LCD_DRAWMODE_TRANS:
if (pTrans) {
do {
Shift = (1 - CurrentPixel) << 2;
Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift;
if (Index) {
PixelIndex = *(pTrans + Index);
_SetPixelIndex(pDevice, x, y, PixelIndex);
}
x++;
if (++CurrentPixel == 2) {
CurrentPixel = 0;
Pixels = *(++p);
}
} while (--xsize);
} else {
do {
Shift = (1 - CurrentPixel) << 2;
Index = (Pixels & (0xF0 >> (4 - Shift))) >> Shift;
if (Index) {
_SetPixelIndex(pDevice, x, y, Index);
}
x++;
if (++CurrentPixel == 2) {
CurrentPixel = 0;
Pixels = *(++p);
}
} while (--xsize);
}
break;
}
}
/*********************************************************************
*
* Draw Bitmap 8 BPP
*/
static void _DrawBitLine8BPP(GUI_DEVICE * pDevice, int x, int y, U8 const GUI_UNI_PTR * p, int xsize, const LCD_PIXELINDEX * pTrans) {
LCD_PIXELINDEX Pixel;
switch (GUI_pContext->DrawMode & (LCD_DRAWMODE_TRANS | LCD_DRAWMODE_XOR)) {
case 0:
if (pTrans) {
for (; xsize > 0; xsize--, x++, p++) {
Pixel = *p;
_SetPixelIndex(pDevice, x, y, *(pTrans + Pixel));
}
} else {
for (; xsize > 0; xsize--, x++, p++) {
_SetPixelIndex(pDevice, x, y, *p);
}
}
break;
case LCD_DRAWMODE_TRANS:
if (pTrans) {
for (; xsize > 0; xsize--, x++, p++) {
Pixel = *p;
if (Pixel) {
_SetPixelIndex(pDevice, x, y, *(pTrans + Pixel));
}
}
} else {
for (; xsize > 0; xsize--, x++, p++) {
Pixel = *p;
if (Pixel) {
_SetPixelIndex(pDevice, x, y, Pixel);
}
}
}
break;
}
}
/*********************************************************************
*
* Draw Bitmap 16 BPP, not optimized
*
* Purpose:
* Drawing of 16bpp high color bitmaps.
* Only required for 16bpp color depth of target. Should be removed otherwise.
*/
static void _DrawBitLine16BPP(GUI_DEVICE * pDevice, int x, int y, U16 const GUI_UNI_PTR * p, int xsize) {
LCD_PIXELINDEX pixel;
for (;xsize > 0; xsize--, x++, p++)
{
if(xsize>g_tft_lcd_data.width)y++;
lcd_tft_setWin(x,y,g_tft_lcd_data.width-xsize,y);
lcd_tft_write_ram_prepare();
pixel = *p;
lcd_tft_write_color(pixel);
//led2=0;
//printf("x=%d y=%d pixel=%x\r\n",x,y,pixel);
}
}
/*********************************************************************
*
* Draw Bitmap 32 BPP, not optimized
*
* Purpose:
* Drawing of 32bpp true color bitmaps.
* Only required for 32bpp color depth of target. Should be removed otherwise.
*/
static void _DrawBitLine32BPP(GUI_DEVICE * pDevice, int x, int y, U32 const GUI_UNI_PTR * p, int xsize) {
for (;xsize > 0; xsize--, x++, p++) {
_SetPixelIndex(pDevice, x, y, *p);
}
}
/*********************************************************************
*
* _DrawBitmap
*/
static void _DrawBitmap(GUI_DEVICE * pDevice, int x0, int y0,
int xSize, int ySize,
int BitsPerPixel,
int BytesPerLine,
const U8 GUI_UNI_PTR * pData, int Diff,
const LCD_PIXELINDEX * pTrans) {
int i;
switch (BitsPerPixel) {
case 1:
for (i = 0; i < ySize; i++) {
_DrawBitLine1BPP(pDevice, x0, i + y0, pData, Diff, xSize, pTrans);
pData += BytesPerLine;
}
break;
case 2:
for (i = 0; i < ySize; i++) {
_DrawBitLine2BPP(pDevice, x0, i + y0, pData, Diff, xSize, pTrans);
pData += BytesPerLine;
}
break;
case 4:
for (i = 0; i < ySize; i++) {
_DrawBitLine4BPP(pDevice, x0, i + y0, pData, Diff, xSize, pTrans);
pData += BytesPerLine;
}
break;
case 8:
for (i = 0; i < ySize; i++) {
_DrawBitLine8BPP(pDevice, x0, i + y0, pData, xSize, pTrans);
pData += BytesPerLine;
}
break;
//
// Only required for 16bpp color depth of target. Should be removed otherwise.
//
case 16:
for (i = 0; i < ySize; i++) {
_DrawBitLine16BPP(pDevice, x0, i + y0, (const U16 *)pData, xSize);
pData += BytesPerLine;
}
break;
//
// Only required for 32bpp color depth of target. Should be removed otherwise.
//
case 32:
for (i = 0; i < ySize; i++) {
_DrawBitLine32BPP(pDevice, x0, i + y0, (const U32 *)pData, xSize);
pData += BytesPerLine;
}
break;
}
}
/*********************************************************************
*
* _InitOnce
*
* Purpose:
* Allocates a fixed block for the context of the driver
*
* Return value:
* 0 on success, 1 on error
*/
static int _InitOnce(GUI_DEVICE * pDevice) {
DRIVER_CONTEXT_TEMPLATE * pContext;
if (pDevice->u.pContext == NULL) {
pDevice->u.pContext = GUI_ALLOC_GetFixedBlock(sizeof(DRIVER_CONTEXT_TEMPLATE));
pContext = (DRIVER_CONTEXT_TEMPLATE *)pDevice->u.pContext;
pContext->BitsPerPixel = LCD__GetBPP(pDevice->pColorConvAPI->pfGetIndexMask());
}
return pDevice->u.pContext ? 0 : 1;
}
/*********************************************************************
*
* _GetDevProp
*/
static I32 _GetDevProp(GUI_DEVICE * pDevice, int Index) {
DRIVER_CONTEXT_TEMPLATE * pContext;
pContext = (DRIVER_CONTEXT_TEMPLATE *)pDevice->u.pContext;
switch (Index) {
case LCD_DEVCAP_XSIZE:
return pContext->xSize;
case LCD_DEVCAP_YSIZE:
return pContext->ySize;
case LCD_DEVCAP_VXSIZE:
return pContext->vxSize;
case LCD_DEVCAP_VYSIZE:
return pContext->vySize;
case LCD_DEVCAP_BITSPERPIXEL:
return pContext->BitsPerPixel;
case LCD_DEVCAP_NUMCOLORS:
return 0;
case LCD_DEVCAP_XMAG:
return 1;
case LCD_DEVCAP_YMAG:
return 1;
case LCD_DEVCAP_MIRROR_X:
return 0;
case LCD_DEVCAP_MIRROR_Y:
return 0;
case LCD_DEVCAP_SWAP_XY:
return 0;
}
return -1;
}
/*********************************************************************
*
* _GetDevData
*/
static void * _GetDevData(GUI_DEVICE * pDevice, int Index) {
GUI_USE_PARA(pDevice);
#if GUI_SUPPORT_MEMDEV
switch (Index) {
case LCD_DEVDATA_MEMDEV:
return (void *)&GUI_MEMDEV_DEVICE_16; // TBD: Has to be adapted to the right memory device depending on the used color depth!
}
#else
GUI_USE_PARA(Index);
#endif
return NULL;
}
/*********************************************************************
*
* _GetRect
*/
static void _GetRect(GUI_DEVICE * pDevice, LCD_RECT * pRect) {
DRIVER_CONTEXT_TEMPLATE * pContext;
pContext = (DRIVER_CONTEXT_TEMPLATE *)pDevice->u.pContext;
pRect->x0 = 0;
pRect->y0 = 0;
pRect->x1 = pContext->vxSize - 1;
pRect->y1 = pContext->vySize - 1;
}
/*********************************************************************
*
* _SetOrg
*/
static void _SetOrg(GUI_DEVICE * pDevice, int x, int y) {
LCD_X_SETORG_INFO Data = {0};
Data.xPos = x;
Data.yPos = y;
LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_SETORG, (void *)&Data);
}
/*********************************************************************
*
* Static code: Functions available by _GetDevFunc()
*
**********************************************************************
*/
/*********************************************************************
*
* _SetVRAMAddr
*/
static void _SetVRAMAddr(GUI_DEVICE * pDevice, void * pVRAM) {
DRIVER_CONTEXT_TEMPLATE * pContext;
LCD_X_SETVRAMADDR_INFO Data = {0};
_InitOnce(pDevice);
if (pDevice->u.pContext) {
pContext = (DRIVER_CONTEXT_TEMPLATE *)pDevice->u.pContext;
pContext->VRAMAddr = (U32)pVRAM;
Data.pVRAM = pVRAM;
LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_SETVRAMADDR, (void *)&Data);
}
}
/*********************************************************************
*
* _SetVSize
*/
static void _SetVSize(GUI_DEVICE * pDevice, int xSize, int ySize) {
DRIVER_CONTEXT_TEMPLATE * pContext;
_InitOnce(pDevice);
if (pDevice->u.pContext) {
pContext = (DRIVER_CONTEXT_TEMPLATE *)pDevice->u.pContext;
pContext->vxSize = xSize;
pContext->vySize = ySize;
pContext->vxSizePhys = xSize;
}
}
/*********************************************************************
*
* _SetSize
*/
static void _SetSize(GUI_DEVICE * pDevice, int xSize, int ySize) {
DRIVER_CONTEXT_TEMPLATE * pContext;
LCD_X_SETSIZE_INFO Data = {0};
_InitOnce(pDevice);
if (pDevice->u.pContext) {
pContext = (DRIVER_CONTEXT_TEMPLATE *)pDevice->u.pContext;
pContext->vxSizePhys = (pContext->vxSizePhys == 0) ? xSize : pContext->vxSizePhys;
pContext->xSize = xSize;
pContext->ySize = ySize;
Data.xSize = xSize;
Data.ySize = ySize;
LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_SETSIZE, (void *)&Data);
}
}
/*********************************************************************
*
* _Init
*/
static int _Init(GUI_DEVICE * pDevice) {
int r;
r = _InitOnce(pDevice);
r |= LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_INITCONTROLLER, NULL);
return r;
}
/*********************************************************************
*
* _On
*/
static void _On (GUI_DEVICE * pDevice) {
LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_ON, NULL);
}
/*********************************************************************
*
* _Off
*/
static void _Off (GUI_DEVICE * pDevice) {
LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_OFF, NULL);
}
/*********************************************************************
*
* _SetLUTEntry
*/
static void _SetLUTEntry(GUI_DEVICE * pDevice, U8 Pos, LCD_COLOR Color) {
LCD_X_SETLUTENTRY_INFO Data = {0};
Data.Pos = Pos;
Data.Color = Color;
LCD_X_DisplayDriver(pDevice->LayerIndex, LCD_X_SETLUTENTRY, (void *)&Data);
}
/*********************************************************************
*
* _GetDevFunc
*/
static void (* _GetDevFunc(GUI_DEVICE ** ppDevice, int Index))(void) {
GUI_USE_PARA(ppDevice);
switch (Index) {
case LCD_DEVFUNC_SET_VRAM_ADDR:
return (void (*)(void))_SetVRAMAddr;
case LCD_DEVFUNC_SET_VSIZE:
return (void (*)(void))_SetVSize;
case LCD_DEVFUNC_SET_SIZE:
return (void (*)(void))_SetSize;
case LCD_DEVFUNC_INIT:
return (void (*)(void))_Init;
case LCD_DEVFUNC_ON:
return (void (*)(void))_On;
case LCD_DEVFUNC_OFF:
return (void (*)(void))_Off;
case LCD_DEVFUNC_SETLUTENTRY:
return (void (*)(void))_SetLUTEntry;
}
return NULL;
}
/*********************************************************************
*
* Public data
*
**********************************************************************
*/
/*********************************************************************
*
* GUI_DEVICE_API structure
*/
const GUI_DEVICE_API GUIDRV_Template_API = {
//
// Data
//
DEVICE_CLASS_DRIVER,
//
// Drawing functions
//
_DrawBitmap,
_DrawHLine,
_DrawVLine,
_FillRect,
(unsigned long (*)(GUI_DEVICE *, int, int)) _GetPixelIndex,
(void (*)(GUI_DEVICE *, int, int, unsigned long)) _SetPixelIndex,
_XorPixel,
//
// Set origin
//
_SetOrg,
//
// Request information
//
_GetDevFunc,
_GetDevProp,
_GetDevData,
_GetRect,
};
/*************************** End of file ****************************/
显示屏相关配置
/*********************************************************************
* SEGGER Microcontroller GmbH & Co. KG *
* Solutions for real time microcontroller applications *
**********************************************************************
* *
* (c) 1996 - 2017 SEGGER Microcontroller GmbH & Co. KG *
* *
* Internet: www.segger.com Support: support@segger.com *
* *
**********************************************************************
** emWin V5.44 - Graphical user interface for embedded applications **
All Intellectual Property rights in the Software belongs to SEGGER.
emWin is protected by international copyright laws. Knowledge of the
source code may not be used to write a similar product. This file may
only be used in accordance with the following terms:
The software has been licensed to STMicroelectronics International
N.V. a Dutch company with a Swiss branch and its headquarters in Plan-
les-Ouates, Geneva, 39 Chemin du Champ des Filles, Switzerland for the
purposes of creating libraries for ARM Cortex-M-based 32-bit microcon_
troller products commercialized by Licensee only, sublicensed and dis_
tributed under the terms and conditions of the End User License Agree_
ment supplied by STMicroelectronics International N.V.
Full source code is available at: www.segger.com
We appreciate your understanding and fairness.
----------------------------------------------------------------------
File : LCDConf_FlexColor_Template.c
Purpose : Display controller configuration (single layer)
---------------------------END-OF-HEADER------------------------------
*/
/**
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2018 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license SLA0044,
* the "License"; You may not use this file except in compliance with the License.
* You may obtain a copy of the License at:
* http://www.st.com/SLA0044
*
******************************************************************************
*/
#include "GUI.h"
#include "GUIDRV_FlexColor.h"
#include "includes.h"
#define TOUCH_AD_TOP 225 //
#define TOUCH_AD_BOTTOM 3837 //
#define TOUCH_AD_LEFT 3896 //
#define TOUCH_AD_RIGHT 193 //
/*********************************************************************
*
* Public functions
*
**********************************************************************
*/
#define XSIZE_PHYS 320
#define YSIZE_PHYS 480
#define VXSIZE_PHYS 480
#define VYSIZE_PHYS 320
/*********************************************************************
*
* LCD_X_Config
*
* Function description:
* Called during the initialization process in order to set up the
* display driver configuration.
*
*/
void LCD_X_Config(void) {
GUI_DEVICE_CreateAndLink(&GUIDRV_Template_API, GUICC_M565, 0, 0);
LCD_SetSizeEx(0, g_tft_lcd_data.width, g_tft_lcd_data.height);
LCD_SetVSizeEx(0, g_tft_lcd_data.width, g_tft_lcd_data.height);
/*第4部分,设置触摸原点 */
GUI_TOUCH_SetOrientation((GUI_MIRROR_X * LCD_GetMirrorXEx(0)) |
(GUI_MIRROR_Y * LCD_GetMirrorYEx(0)) | (GUI_SWAP_XY * LCD_GetSwapXYEx(0)));
if (g_tft_lcd_data.dir == 0) {
GUI_TOUCH_Calibrate(GUI_COORD_X, 0, g_tft_lcd_data.width - 1, TOUCH_AD_LEFT, TOUCH_AD_RIGHT);
GUI_TOUCH_Calibrate(GUI_COORD_Y, 0, g_tft_lcd_data.height - 1, TOUCH_AD_BOTTOM, TOUCH_AD_TOP);
} else {
GUI_TOUCH_SetOrientation(GUI_SWAP_XY | GUI_MIRROR_X);
GUI_TOUCH_Calibrate(GUI_COORD_X, 0, g_tft_lcd_data.height, 155, 3903);
GUI_TOUCH_Calibrate(GUI_COORD_Y, 0, g_tft_lcd_data.width, 188, 3935);
}
}
/*********************************************************************
*
* LCD_X_DisplayDriver
*
* Function description:
* This function is called by the display driver for several purposes.
* To support the according task the routine needs to be adapted to
* the display controller. Please note that the commands marked with
* 'optional' are not cogently required and should only be adapted if
* the display controller supports these features.
*
* Parameter:
* LayerIndex - Index of layer to be configured
* Cmd - Please refer to the details in the switch statement below
* pData - Pointer to a LCD_X_DATA structure
*
* Return Value:
* < -1 - Error
* -1 - Command not handled
* 0 - Ok
*/
int LCD_X_DisplayDriver(unsigned LayerIndex, unsigned Cmd, void * pData)
{
int r;
switch (Cmd)
{
case LCD_X_INITCONTROLLER:
{
//
// Called during the initialization process in order to set up the
// display controller and put it into operation. If the display
// controller is not initialized by any external routine this needs
// to be adapted by the customer...
//
// ...
//
return 0;
}
case LCD_X_SETVRAMADDR:
{
//
// Required for setting the address of the video RAM for drivers
// with memory mapped video RAM which is passed in the 'pVRAM' element of p
//
LCD_X_SETVRAMADDR_INFO * p;
(void)p;
p = (LCD_X_SETVRAMADDR_INFO *)pData;
//...
return 0;
}
case LCD_X_SETORG:
{
//
// Required for setting the display origin which is passed in the 'xPos' and 'yPos' element of p
//
LCD_X_SETORG_INFO * p;
(void)p;
p = (LCD_X_SETORG_INFO *)pData;
//...
return 0;
}
case LCD_X_SHOWBUFFER:
{
//
// Required if multiple buffers are used. The 'Index' element of p contains the buffer index.
//
LCD_X_SHOWBUFFER_INFO * p;
(void)p;
p = (LCD_X_SHOWBUFFER_INFO *)pData;
//...
return 0;
}
case LCD_X_SETLUTENTRY:
{
//
// Required for setting a lookup table entry which is passed in the 'Pos' and 'Color' element of p
//
LCD_X_SETLUTENTRY_INFO * p;
(void)p;
p = (LCD_X_SETLUTENTRY_INFO *)pData;
//...
return 0;
}
case LCD_X_ON:
{
//
// Required if the display controller should support switching on and off
//
return 0;
}
case LCD_X_OFF:
{
//
// Required if the display controller should support switching on and off
//
// ...
return 0;
}
default:
r = -1;
}
return r;
}
/*************************** End of file ****************************/
触摸配置
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024/3/23 shchl first version
*/
#include "GUI.h"
#include "bsp_touch.h"
void GUI_TOUCH_X_ActivateX(void)
{
// XPT2046_WriteCMD(0x90);
}
void GUI_TOUCH_X_ActivateY(void)
{
//XPT2046_WriteCMD(0xd0);
}
int GUI_TOUCH_X_MeasureX(void)
{
return lcd_touch_read_ad(g_lcd_touch.CNF.rd_x_cmd) ; //CMD_RDX=0XD0
}
int GUI_TOUCH_X_MeasureY(void)
{
return lcd_touch_read_ad(g_lcd_touch.CNF.rd_y_cmd) ; //CMD_RDY=0X90
}
与threadx 项目组合
GUI组件(app_gui_emwin_component.c)
- 初始化GUI_Init()之前,要先调用crc初始化
/*
* Copyright (c) 2024-2024,shchl
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2024-4-20 shchl em win demo
*/
#include "includes.h"
#if 1
#include "GUI.h"
/*
*******************************************************************************************************
* 外部引入变量
*******************************************************************************************************
*/
/*
*******************************************************************************************************
* 变量
*******************************************************************************************************
*/
/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 函数声明
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 外部函数
*********************************************************************************************************
*/
int gui_emwin_application_define(void) {
CRC_HandleTypeDef CrcHandle;
CrcHandle.Instance = CRC;
HAL_CRC_Init(&CrcHandle);
GUI_Init();
GUI_SetBkColor(BLACK);
GUI_Clear();
return FX_SUCCESS;
}
TX_APP_DEFINE_LV1(gui_emwin_application_define); /*首先创建模块应用*/
/*
*********************************************************************************************************
* 内部函数
*********************************************************************************************************
*/
#endif
创建GUI任务线程(包含显示,和触摸)
/*
* 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"
#if 1
#include "GUI.h"
#define APP_TASK_GUI_EMWIN_PRIO 15
#define APP_TASK_GUI_EMWIN_STK_SIZE 2048
#define APP_TASK_TOUCH_EMWIN_PRIO 10
#define APP_TASK_TOUCH_EMWIN_STK_SIZE 2048
/*
*******************************************************************************************************
* 外部引入变量
*******************************************************************************************************
*/
/*
*******************************************************************************************************
* 变量
*******************************************************************************************************
*/
TX_THREAD gui_thread;
TX_THREAD touch_thread;
VOID *gui_thread_stack_area;
VOID *touch_thread_stack_area;
/*
*********************************************************************************************************
* 静态全局变量
*********************************************************************************************************
*/
/*
*********************************************************************************************************
* 函数声明
*********************************************************************************************************
*/
static VOID gui_thread_entry(ULONG input);
static VOID touch_thread_entry(ULONG input);
/*
*********************************************************************************************************
* 外部函数
*********************************************************************************************************
*/
/**
* @brief cpu 状态任务
* @param first_thread 第一个启动的任务线程首地址
*/
int tx_task_gui_emwin_create() {
gui_thread_stack_area = app_malloc(APP_TASK_GUI_EMWIN_STK_SIZE);
touch_thread_stack_area = app_malloc(APP_TASK_TOUCH_EMWIN_STK_SIZE);
tx_thread_create(&gui_thread, /* 任务控制块地址 */
"gui thread", /* 任务名 */
gui_thread_entry, /* 启动任务函数地址 */
0, /* 传递给任务的参数 */
gui_thread_stack_area, /* 堆栈基地址 */
APP_TASK_GUI_EMWIN_STK_SIZE, /* 堆栈空间大小 */
APP_TASK_GUI_EMWIN_PRIO, /* 任务优先级*/
APP_TASK_GUI_EMWIN_PRIO, /* 任务抢占阀值 */
TX_NO_TIME_SLICE, /* 不开启时间片 */
TX_AUTO_START); /* 创建后立即启动 */
tx_thread_create(&touch_thread, /* 任务控制块地址 */
"touch thread", /* 任务名 */
touch_thread_entry, /* 启动任务函数地址 */
0, /* 传递给任务的参数 */
touch_thread_stack_area, /* 堆栈基地址 */
APP_TASK_TOUCH_EMWIN_STK_SIZE, /* 堆栈空间大小 */
APP_TASK_TOUCH_EMWIN_PRIO, /* 任务优先级*/
APP_TASK_TOUCH_EMWIN_PRIO, /* 任务抢占阀值 */
TX_NO_TIME_SLICE, /* 不开启时间片 */
TX_AUTO_START); /* 创建后立即启动 */
return TX_SUCCESS;
}
TX_THREAD_EXPORT(tx_task_gui_emwin_create);
/*
*********************************************************************************************************
* 内部函数
*********************************************************************************************************
*/
static VOID gui_thread_entry(ULONG input) {
MainTask();
while (1) {
}
}
static VOID touch_thread_entry(ULONG input) {
while (1) {
GUI_TOUCH_Exec();
GUI_X_Delay(50);
}
}
#endif