stm32f103_lvgl_8080lcd: finish touchscreen calibration code

This commit is contained in:
wangyz1997 2024-01-09 14:22:34 +08:00
parent 500130bf8a
commit 9b8e1db906
7 changed files with 243 additions and 50 deletions

View File

@ -4,6 +4,10 @@
#include "stm32f1xx_hal.h" #include "stm32f1xx_hal.h"
#define BSP_XPT2046_SPI hspi2 #define BSP_XPT2046_SPI hspi2
#define BSP_XPT2046_EEPROM_I2C hi2c2
#define BSP_XPT2046_EEPROM_I2C_OFFSET 0
#define BSP_XPT2046_AVG_SAMPLES 16 //必须是偶数
HAL_StatusTypeDef bsp_xpt2046_get_touch_status(void); HAL_StatusTypeDef bsp_xpt2046_get_touch_status(void);
void bsp_xpt2046_get_adc(uint16_t *x_adc, uint16_t *y_adc); void bsp_xpt2046_get_adc(uint16_t *x_adc, uint16_t *y_adc);

View File

@ -1,6 +1,7 @@
#include "bsp_xpt2046.h" #include "bsp_xpt2046.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include "main.h" #include "main.h"
#include "util_delay_us.h" #include "util_delay_us.h"
@ -15,7 +16,7 @@ static uint16_t bsp_xpt2046_conv(uint8_t cmd)
HAL_GPIO_WritePin(T_CS_GPIO_Port, T_CS_Pin, GPIO_PIN_RESET); //选中芯片 HAL_GPIO_WritePin(T_CS_GPIO_Port, T_CS_Pin, GPIO_PIN_RESET); //选中芯片
HAL_SPI_Transmit(&BSP_XPT2046_SPI, &cmd, 1, 200); //发送指令 HAL_SPI_Transmit(&BSP_XPT2046_SPI, &cmd, 1, 200); //发送指令
delay_us(4); //等待转换完成 delay_us(2); //等待转换完成 实际延时超过所需最短延时4us
uint8_t received_data[2]; uint8_t received_data[2];
uint8_t transmit_data[2] = { 0x00, 0x00 }; //接收时MOSI必须保持固定电平 否则数据出错 uint8_t transmit_data[2] = { 0x00, 0x00 }; //接收时MOSI必须保持固定电平 否则数据出错
@ -25,10 +26,30 @@ static uint16_t bsp_xpt2046_conv(uint8_t cmd)
return ((uint16_t)received_data[0] << 8 | received_data[1]) >> 4; return ((uint16_t)received_data[0] << 8 | received_data[1]) >> 4;
} }
static int qsort_comparator(const void *a, const void *b)
{
return *(uint16_t *)a - *(uint16_t *)b;
}
void bsp_xpt2046_get_adc(uint16_t *x_adc, uint16_t *y_adc) void bsp_xpt2046_get_adc(uint16_t *x_adc, uint16_t *y_adc)
{ {
*x_adc = bsp_xpt2046_conv(BSP_XPT2046_CMD_CONV_X); uint16_t x_adcs[BSP_XPT2046_AVG_SAMPLES], y_adcs[BSP_XPT2046_AVG_SAMPLES];
*y_adc = bsp_xpt2046_conv(BSP_XPT2046_CMD_CONV_Y); for (uint8_t i = 0; i < BSP_XPT2046_AVG_SAMPLES; i ++) {
x_adcs[i] = bsp_xpt2046_conv(BSP_XPT2046_CMD_CONV_X);
y_adcs[i] = bsp_xpt2046_conv(BSP_XPT2046_CMD_CONV_Y);
}
qsort(x_adcs, BSP_XPT2046_AVG_SAMPLES, sizeof(x_adcs[0]), qsort_comparator);
qsort(y_adcs, BSP_XPT2046_AVG_SAMPLES, sizeof(y_adcs[0]), qsort_comparator); //升序排序
uint32_t x_adc_sum = 0, y_adc_sum = 0; //求中间n/2个数的平均值
for (uint8_t i = BSP_XPT2046_AVG_SAMPLES / 4; i < BSP_XPT2046_AVG_SAMPLES - BSP_XPT2046_AVG_SAMPLES / 4; i ++) {
x_adc_sum += x_adcs[i];
y_adc_sum += y_adcs[i];
}
*x_adc = x_adc_sum / (BSP_XPT2046_AVG_SAMPLES / 2);
*y_adc = y_adc_sum / (BSP_XPT2046_AVG_SAMPLES / 2);
} }
HAL_StatusTypeDef bsp_xpt2046_get_touch_status(void) HAL_StatusTypeDef bsp_xpt2046_get_touch_status(void)
@ -38,8 +59,7 @@ HAL_StatusTypeDef bsp_xpt2046_get_touch_status(void)
HAL_StatusTypeDef bsp_xpt2046_get_coord(uint16_t *x, uint16_t *y) HAL_StatusTypeDef bsp_xpt2046_get_coord(uint16_t *x, uint16_t *y)
{ {
if (tp_x_factor == 0 || tp_x_offset == 0 || tp_y_factor == 0 || tp_y_offset == 0 || if (tp_x_factor == 0 || tp_y_factor == 0 || tp_lcd_x_pixels == 0) {
tp_lcd_x_pixels == 0 || tp_lcd_y_pixels == 0) {
return HAL_ERROR; return HAL_ERROR;
} }
@ -60,17 +80,49 @@ HAL_StatusTypeDef bsp_xpt2046_calibrate(const uint16_t x_pos[], const uint16_t y
tp_y_factor = (float)(y_pos[1] - y_pos[0]) / (y_val[1] - y_val[0]); tp_y_factor = (float)(y_pos[1] - y_pos[0]) / (y_val[1] - y_val[0]);
tp_y_offset = (float)y_pos[0] - tp_y_factor * y_val[0]; tp_y_offset = (float)y_pos[0] - tp_y_factor * y_val[0];
//将校准值写入EEPROM printf("tp_x_factor=%.3f, tp_x_offset=%.3f\n", tp_x_factor, tp_x_offset);
printf("tp_x_factor=%.3f, tp_x_offset=%.3f\r\n", tp_x_factor, tp_x_offset); printf("tp_y_factor=%.3f, tp_y_offset=%.3f\n", tp_y_factor, tp_y_offset);
printf("tp_y_factor=%.3f, tp_y_offset=%.3f\r\n", tp_y_factor, tp_y_offset);
return HAL_OK; //将校准值写入EEPROM
HAL_StatusTypeDef status;
uint8_t addr = BSP_XPT2046_EEPROM_I2C_OFFSET;
status |= HAL_I2C_Mem_Write(&BSP_XPT2046_EEPROM_I2C, 0x50 << 1, addr, 1, (uint8_t *)&tp_x_factor, sizeof(tp_x_factor), 200);
addr += sizeof(tp_x_factor);
HAL_Delay(2); //EEPROM写入比较慢
status |= HAL_I2C_Mem_Write(&BSP_XPT2046_EEPROM_I2C, 0x50 << 1, addr, 1, (uint8_t *)&tp_x_offset, sizeof(tp_x_offset), 200);
addr += sizeof(tp_x_offset);
HAL_Delay(2);
status |= HAL_I2C_Mem_Write(&BSP_XPT2046_EEPROM_I2C, 0x50 << 1, addr, 1, (uint8_t *)&tp_y_factor, sizeof(tp_y_factor), 200);
addr += sizeof(tp_y_factor);
HAL_Delay(2);
status |= HAL_I2C_Mem_Write(&BSP_XPT2046_EEPROM_I2C, 0x50 << 1, addr, 1, (uint8_t *)&tp_y_offset, sizeof(tp_y_offset), 200);
return status;
} }
HAL_StatusTypeDef bsp_xpt2046_load_calib_data(uint16_t lcd_x_pixels, uint16_t lcd_y_pixels) HAL_StatusTypeDef bsp_xpt2046_load_calib_data(uint16_t lcd_x_pixels, uint16_t lcd_y_pixels)
{ {
if (lcd_x_pixels == 0 || lcd_y_pixels == 0) {
return HAL_ERROR;
}
tp_lcd_x_pixels = lcd_x_pixels; tp_lcd_x_pixels = lcd_x_pixels;
tp_lcd_y_pixels = lcd_y_pixels; tp_lcd_y_pixels = lcd_y_pixels;
HAL_StatusTypeDef status;
uint8_t addr = BSP_XPT2046_EEPROM_I2C_OFFSET;
status |= HAL_I2C_Mem_Read(&BSP_XPT2046_EEPROM_I2C, 0x50 << 1, addr, 1, (uint8_t *)&tp_x_factor, sizeof(tp_x_factor), 200);
addr += sizeof(tp_x_factor);
status |= HAL_I2C_Mem_Read(&BSP_XPT2046_EEPROM_I2C, 0x50 << 1, addr, 1, (uint8_t *)&tp_x_offset, sizeof(tp_x_offset), 200);
addr += sizeof(tp_x_offset);
status |= HAL_I2C_Mem_Read(&BSP_XPT2046_EEPROM_I2C, 0x50 << 1, addr, 1, (uint8_t *)&tp_y_factor, sizeof(tp_y_factor), 200);
addr += sizeof(tp_y_factor);
status |= HAL_I2C_Mem_Read(&BSP_XPT2046_EEPROM_I2C, 0x50 << 1, addr, 1, (uint8_t *)&tp_y_offset, sizeof(tp_y_offset), 200);
if (tp_x_factor == 0 || tp_y_factor == 0 || *(uint32_t *)&tp_x_factor == 0xFFFFFFFF || *(uint32_t *)&tp_y_factor == 0xFFFFFFFF ||
tp_x_offset == 0 || tp_y_offset == 0 || *(uint32_t *)&tp_x_offset == 0xFFFFFFFF || *(uint32_t *)&tp_y_offset == 0xFFFFFFFF) {
return HAL_ERROR;
} else {
return HAL_OK; return HAL_OK;
} }
}

View File

@ -1,6 +1,5 @@
#include "lv_port_indev.h" #include "lv_port_indev.h"
#include "main.h"
#include "bsp_xpt2046.h" #include "bsp_xpt2046.h"
lv_indev_t *indev_touchpad; lv_indev_t *indev_touchpad;
@ -10,12 +9,17 @@ static void touchpad_read(lv_indev_drv_t * indev_drv, lv_indev_data_t * data)
static lv_coord_t last_x = 0; static lv_coord_t last_x = 0;
static lv_coord_t last_y = 0; static lv_coord_t last_y = 0;
if(bsp_xpt2046_get_touch_status() == HAL_OK) {
if(HAL_GPIO_ReadPin(T_PEN_GPIO_Port, T_PEN_Pin) == GPIO_PIN_RESET) {
uint16_t x_coord, y_coord; uint16_t x_coord, y_coord;
bsp_xpt2046_get_coord(&x_coord, &y_coord); HAL_StatusTypeDef status = bsp_xpt2046_get_coord(&x_coord, &y_coord);
if (status == HAL_OK) {
last_x = x_coord; last_y = y_coord; last_x = x_coord; last_y = y_coord;
data->state = LV_INDEV_STATE_PR; data->state = LV_INDEV_STATE_PR;
} else {
data->state = LV_INDEV_STATE_REL;
LV_LOG_ERROR("Touchscreen is not properly calibrated!");
}
} else { } else {
data->state = LV_INDEV_STATE_REL; data->state = LV_INDEV_STATE_REL;
} }

View File

@ -2,6 +2,7 @@
#include <stdio.h> #include <stdio.h>
#include "main.h" #include "main.h"
#include "lvgl.h"
#include "bsp_lcd_ili9341.h" #include "bsp_lcd_ili9341.h"
#include "bsp_xpt2046.h" #include "bsp_xpt2046.h"
@ -20,25 +21,72 @@ void draw_cross(uint16_t x_center, uint16_t y_center)
void touchscreen_calibration(uint8_t force) void touchscreen_calibration(uint8_t force)
{ {
uint16_t x_pos[2] = { 20, BSP_LCD_X_PIXELS - 20 }, y_pos[2] = { 20, BSP_LCD_Y_PIXELS - 20 }; HAL_StatusTypeDef status = bsp_xpt2046_load_calib_data(BSP_LCD_X_PIXELS, BSP_LCD_Y_PIXELS);
uint16_t x_val[2], y_val[2]; if (status == HAL_OK && force == 0) {
printf("load touchscreen calibration data from eeprom success\n");
draw_cross(x_pos[0], y_pos[0]); return;
while (bsp_xpt2046_get_touch_status() == HAL_ERROR); } else {
HAL_Delay(50); printf("load touchscreen calibration data from eeprom failed, re-calibrating\n");
bsp_xpt2046_get_adc(&x_val[0], &y_val[0]); }
printf("x: 0x%03X, y: 0x%03X\r\n", x_val[0], y_val[0]);
HAL_Delay(50); uint16_t x_pos[2], y_pos[2], x_val[2], y_val[2];
while (bsp_xpt2046_get_touch_status() == HAL_OK);
lv_obj_t *cross = lv_obj_create(lv_scr_act());
draw_cross(x_pos[1], y_pos[1]); lv_obj_set_size(cross, 59, 59); //创建一个59x59大小的容器
while (bsp_xpt2046_get_touch_status() == HAL_ERROR); lv_obj_clear_flag(cross, LV_OBJ_FLAG_SCROLLABLE); //防止出现滚动条
HAL_Delay(50); lv_obj_set_style_bg_opa(cross, LV_OPA_TRANSP, 0);
bsp_xpt2046_get_adc(&x_val[1], &y_val[1]); lv_obj_set_style_border_opa(cross, LV_OPA_TRANSP, 0); //设置容器完全透明
printf("x: 0x%03X, y: 0x%03X\r\n", x_val[1], y_val[1]);
HAL_Delay(50); lv_style_t style_line;
while (bsp_xpt2046_get_touch_status() == HAL_OK); lv_style_init(&style_line); //创建线条样式
lv_style_set_line_width(&style_line, 3);
bsp_xpt2046_calibrate(x_pos, y_pos, x_val, y_val); lv_style_set_line_color(&style_line, lv_palette_main(LV_PALETTE_RED)); //红色 3像素宽
bsp_xpt2046_load_calib_data(BSP_LCD_X_PIXELS, BSP_LCD_Y_PIXELS);
const static lv_point_t cross_ver_line_points[2] = { { 0, 0 }, { 0, 30 } };
lv_obj_t *cross_ver_line = lv_line_create(cross); //十字中的竖线
lv_line_set_points(cross_ver_line, cross_ver_line_points, 2);
lv_obj_add_style(cross_ver_line, &style_line, 0);
lv_obj_center(cross_ver_line); //居中对齐
const static lv_point_t cross_hor_line_points[2] = { { 0, 0 }, { 30, 0 } };
lv_obj_t *cross_hor_line = lv_line_create(cross); //十字中的横线
lv_line_set_points(cross_hor_line, cross_hor_line_points, 2);
lv_obj_add_style(cross_hor_line, &style_line, 0);
lv_obj_center(cross_hor_line);
lv_obj_align(cross, LV_ALIGN_TOP_LEFT, 0, 0); //十字首先置于左上角
lv_area_t cross_obj_area;
lv_obj_update_layout(cross); //需要先重新计算布局才能获取容器尺寸
lv_obj_get_content_coords(cross, &cross_obj_area); //获取容器尺寸
x_pos[0] = (cross_obj_area.x1 + cross_obj_area.x2) / 2;
y_pos[0] = (cross_obj_area.y1 + cross_obj_area.y2) / 2; //计算得到十字中点坐标
while (bsp_xpt2046_get_touch_status() != HAL_OK) {
lv_task_handler();
}
bsp_xpt2046_get_adc(&x_val[0], &y_val[0]);
while (bsp_xpt2046_get_touch_status() == HAL_OK);
lv_obj_align(cross, LV_ALIGN_BOTTOM_RIGHT, 0, 0); //然后将置于右下角
lv_obj_update_layout(cross); //需要先重新计算布局才能获取容器尺寸
lv_obj_get_content_coords(cross, &cross_obj_area); //获取容器尺寸
x_pos[1] = (cross_obj_area.x1 + cross_obj_area.x2) / 2;
y_pos[1] = (cross_obj_area.y1 + cross_obj_area.y2) / 2; //计算得到十字中点坐标
while (bsp_xpt2046_get_touch_status() != HAL_OK) {
lv_task_handler();
}
bsp_xpt2046_get_adc(&x_val[1], &y_val[1]);
while (bsp_xpt2046_get_touch_status() == HAL_OK);
status = bsp_xpt2046_calibrate(x_pos, y_pos, x_val, y_val);
if (status != HAL_OK) {
printf("error while saving calibration data to eeprom, code=%d\n", status);
} else {
printf("successfully saved calibration data to eeprom\n");
}
lv_obj_del(cross);
} }

View File

@ -153,7 +153,102 @@
<Name>UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_512 -FS08000000 -FL080000 -FP0($$Device:STM32F103ZE$Flash\STM32F10x_512.FLM))</Name> <Name>UL2CM3(-S0 -C0 -P0 -FD20000000 -FC1000 -FN1 -FF0STM32F10x_512 -FS08000000 -FL080000 -FP0($$Device:STM32F103ZE$Flash\STM32F10x_512.FLM))</Name>
</SetRegEntry> </SetRegEntry>
</TargetDriverDllRegistry> </TargetDriverDllRegistry>
<Breakpoint/> <Breakpoint>
<Bp>
<Number>0</Number>
<Type>0</Type>
<LineNumber>106</LineNumber>
<EnabledFlag>1</EnabledFlag>
<Address>0</Address>
<ByteObject>0</ByteObject>
<HtxType>0</HtxType>
<ManyObjects>0</ManyObjects>
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\Core\Src\bsp_xpt2046.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
<Bp>
<Number>1</Number>
<Type>0</Type>
<LineNumber>99</LineNumber>
<EnabledFlag>1</EnabledFlag>
<Address>0</Address>
<ByteObject>0</ByteObject>
<HtxType>0</HtxType>
<ManyObjects>0</ManyObjects>
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\Core\Src\bsp_xpt2046.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
<Bp>
<Number>2</Number>
<Type>0</Type>
<LineNumber>44</LineNumber>
<EnabledFlag>1</EnabledFlag>
<Address>0</Address>
<ByteObject>0</ByteObject>
<HtxType>0</HtxType>
<ManyObjects>0</ManyObjects>
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>..\Core\Src\bsp_xpt2046.c</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
<Bp>
<Number>3</Number>
<Type>0</Type>
<LineNumber>117</LineNumber>
<EnabledFlag>1</EnabledFlag>
<Address>0</Address>
<ByteObject>0</ByteObject>
<HtxType>0</HtxType>
<ManyObjects>0</ManyObjects>
<SizeOfObject>0</SizeOfObject>
<BreakByAccess>0</BreakByAccess>
<BreakIfRCount>0</BreakIfRCount>
<Filename>startup_stm32f103xe.s</Filename>
<ExecCommand></ExecCommand>
<Expression></Expression>
</Bp>
</Breakpoint>
<WatchWindow1>
<Ww>
<count>0</count>
<WinNumber>1</WinNumber>
<ItemText>tp_x_factor</ItemText>
</Ww>
<Ww>
<count>1</count>
<WinNumber>1</WinNumber>
<ItemText>tp_x_offset</ItemText>
</Ww>
<Ww>
<count>2</count>
<WinNumber>1</WinNumber>
<ItemText>tp_y_factor</ItemText>
</Ww>
<Ww>
<count>3</count>
<WinNumber>1</WinNumber>
<ItemText>tp_y_offset</ItemText>
</Ww>
</WatchWindow1>
<MemoryWindow1>
<Mm>
<WinNumber>1</WinNumber>
<SubType>0</SubType>
<ItemText>tp_calib_data</ItemText>
<AccSizeX>0</AccSizeX>
</Mm>
</MemoryWindow1>
<Tracepoint> <Tracepoint>
<THDelay>0</THDelay> <THDelay>0</THDelay>
</Tracepoint> </Tracepoint>
@ -196,16 +291,6 @@
<pszMrulep></pszMrulep> <pszMrulep></pszMrulep>
<pSingCmdsp></pSingCmdsp> <pSingCmdsp></pSingCmdsp>
<pMultCmdsp></pMultCmdsp> <pMultCmdsp></pMultCmdsp>
<SystemViewers>
<Entry>
<Name>System Viewer\DMA1</Name>
<WinId>35905</WinId>
</Entry>
<Entry>
<Name>System Viewer\FSMC</Name>
<WinId>35904</WinId>
</Entry>
</SystemViewers>
<DebugDescription> <DebugDescription>
<Enable>1</Enable> <Enable>1</Enable>
<EnableFlashSeq>1</EnableFlashSeq> <EnableFlashSeq>1</EnableFlashSeq>

View File

@ -313,7 +313,7 @@
</ArmAdsMisc> </ArmAdsMisc>
<Cads> <Cads>
<interw>1</interw> <interw>1</interw>
<Optim>5</Optim> <Optim>2</Optim>
<oTime>0</oTime> <oTime>0</oTime>
<SplitLS>0</SplitLS> <SplitLS>0</SplitLS>
<OneElfS>1</OneElfS> <OneElfS>1</OneElfS>