STM32移植STemWin后使用四点或两点触摸校准(电阻屏校准,电容屏无需校准)

STM32移植STemWin后使用四点或两点触摸校准(电阻屏校准,电容屏无需校准)_第1张图片


测试开发板的连接:https://item.taobao.com/item.htm?id=557618550100


开发板PCB完整工程连接:http://www.cirmall.com/circuit/7 ... F%EF%BC%81#/details


这是校准.c文件



/*
文件说明:


1.屏幕校准程序的扫描要用一个定时器中断来扫描


2.校准后可以直接是调用TOUCH_Scan()即可,GUI_TOUCH_X_MeasureX();,GUI_TOUCH_X_MeasureY();
可以不用,同时LCDConf_FlexColor_Template.c中的LCD_X_Config();函数中的两个GUI_TOUCH_Calibrate();
也可以注释

*/


#include "TFTLCD_Check.h"


/* 触屏模块用到的全局变量 */
TOUCH_T g_tTP;
extern void Delay(__IO uint32_t nCount);
extern int32_t TOUCH_Abs(int32_t x);
static uint8_t TOUCH_PressValid(uint16_t _usX, uint16_t _usY);
u16 LCD_GetWidth(void);
u16 LCD_GetHeight(void);
extern Bool TOUCH_ReadAdcXOY(void);
extern uint8_t g_LcdDirection; /* 显示方向.0,1,2,3 */
GUI_PID_STATE State;




/* 每1ms扫描一次坐标 */
#define DOWN_VALID 30/* 按下30ms 后, 开始统计ADC */
#define SAMPLE_COUNT 10/* 按下后连续采集40个样本 */


/*
触摸屏校准点相对屏幕像素四角的偏移像素
第1个点 : x1 = CALIB_OFFSET, y1 = CALIB_OFFSET
第2个点 : x2 = LCD_GetWidth() - CALIB_OFFSET, y2 = LCD_GetHeight() - CALIB_OFFSET
*/
#define CALIB_OFFSET 20
#define TP_X1 CALIB_OFFSET
#define TP_Y1 CALIB_OFFSET


#define TP_X2 (LCD_GetWidth() - CALIB_OFFSET)
#define TP_Y2 (LCD_GetHeight() - CALIB_OFFSET)


#define TP_X3 CALIB_OFFSET
#define TP_Y3 (LCD_GetHeight() - CALIB_OFFSET)


#define TP_X4 (LCD_GetWidth() - CALIB_OFFSET)
#define TP_Y4 CALIB_OFFSET


/* 有效ADC值的判断门限. 太接近ADC临界值的坐标认为无效 */
#define ADC_VALID_OFFSET 2


/*****************************************************************
* 函 数 名: LCD_GetWidth
* 功能说明: 获得液晶屏的宽度
* 形    参: 无
* 返 回 值: 无
*****************************************************************/
u16 LCD_GetWidth(void) {
return g_LcdWidth;
}
/*****************************************************************
* 函 数 名: LCD_GetHeight
* 功能说明: 获得液晶屏的高读
* 形    参: 无
* 返 回 值: 无
*****************************************************************/
u16 LCD_GetHeight(void) {
return g_LcdHeight;
}
/*****************************************************************
* 函 数 名: bsp_DelayMS
* 功能说明: ms级延迟,延迟精度为正负1ms
* 形    参:  n : 延迟长度,单位1 ms。 n 应大于2
* 返 回 值: 无
*****************************************************************/
volatile uint32_t s_uiDelayCount = 0;
static volatile uint8_t s_ucTimeOutFlag = 0;


//void bsp_DelayMS(uint32_t n) {
// if (n == 0) {
// return;
// }
//__set_PRIMASK(1);
//// DISABLE_INT();  /* 关中断 */
// s_uiDelayCount = n;
// s_ucTimeOutFlag = 0;
//__set_PRIMASK(0);
//// ENABLE_INT();  /* 开中断 */
// TIM_Cmd(TIM2, ENABLE);
// while (s_uiDelayCount) {
//
// }
//}
/*****************************************************************
* 函 数 名: CalTwoPoint
* 功能说明: 根据2点直线方程,计算Y值
* 形    参:  2个点的坐标和x输入量
* 返 回 值: x对应的y值
******************************************************************/
static int32_t CalTwoPoint(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t x) {
return y1 + ((int32_t)(y2 - y1) * (x - x1)) / (x2 - x1);
}


/*****************************************************************
* 函 数 名: TOUCH_TransX
* 功能说明: 将触摸ADC值转换为像素坐标
* 形    参:  无
* 返 回 值: X 坐标值,允许负值
*****************************************************************/
static int16_t TOUCH_TransX(uint16_t _usAdcX, uint16_t _usAdcY) {
#if CALIB_POINT_COUNT == 2 /* 2点校准 */
uint16_t x;
int32_t y;


if (g_tTP.XYChange == 0) {
x = _usAdcX;
if (x == 0) {
y = 0;
} else {
//y = CalTwoPoint(g_tTP.usAdcX1, TP_X1, g_tTP.usAdcX2, TP_X2, x);
y = CalTwoPoint(g_tTP.usAdcX1, g_tTP.usLcdX1, g_tTP.usAdcX2, g_tTP.usLcdX2, x);
}
} else {
x = _usAdcY;
if (x == 0) {
y = 0;
} else {
//y = CalTwoPoint(g_tTP.usAdcY1, TP_X1, g_tTP.usAdcY2, TP_X2, x);
y = CalTwoPoint(g_tTP.usAdcY1, g_tTP.usLcdX1, g_tTP.usAdcY2, g_tTP.usLcdX2, x);
}
}
return y;
#else /* 4点校准 */
uint16_t x, x1, x2;
int32_t y;


if (g_tTP.XYChange == 0) {/* X Y 坐标不交换 */
x = _usAdcX;
/* 根据 Y ADC 实时计算直线方程的参考点x1, x2
if  _usAdcY = usAdcY1 then  取点 = (AdcX1, TP_X1, AdcX4, TP_X4, _usAdcY)
if  _usAdcY = usAdcY2 then  取点 = (AdcX3, TP_X3, AdcX2, TP_X2, _usAdcY)


其中 TP_X1 = TP_X3;  TP_X4 = TP_X1 , 这是程序设定的校准位置的像素坐标, 是固定的。
我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
*/
x1 = CalTwoPoint(g_tTP.usAdcY1, g_tTP.usAdcX1, g_tTP.usAdcY2,  g_tTP.usAdcX3, _usAdcY);
x2 = CalTwoPoint(g_tTP.usAdcY1, g_tTP.usAdcX4, g_tTP.usAdcY2,  g_tTP.usAdcX2, _usAdcY);
} else { /* X Y 坐标交换 */
x = _usAdcY;
/* 根据 X ADC 实时计算直线方程的参考点x1, x2
if  _usAdcX = usAdcX1 then  取点 = (AdcY1, TP_X1, AdcY4, TP_X4, _usAdcX)
if  _usAdcX = usAdcX2 then  取点 = (AdcY3, TP_X3, AdcY2, TP_X2, _usAdcX)


其中 TP_X1 = TP_X3;  TP_X4 = TP_X1 , 这是程序设定的校准位置的像素坐标, 是固定的。
我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
*/
x1 = CalTwoPoint(g_tTP.usAdcX1, g_tTP.usAdcY1, g_tTP.usAdcX2,  g_tTP.usAdcY3, _usAdcX);
x2 = CalTwoPoint(g_tTP.usAdcX1, g_tTP.usAdcY4, g_tTP.usAdcX2,  g_tTP.usAdcY2, _usAdcX);
}
if (x == 0) {
y = 0;
} else {
/* 根据2点直线方程,计算坐标 */
// y = CalTwoPoint(x1, TP_X1, x2, TP_X2, x);
y = CalTwoPoint(x1, g_tTP.usLcdX1, x2, g_tTP.usLcdX2, x);
}
return y;
#endif
}


/*****************************************************************
* 函 数 名: TOUCH_ReadAdcX
* 功能说明: 获得触摸板X方向ADC采样值, 已进行滤波处理
* 形    参:  无
* 返 回 值: X 方向ADC值
*****************************************************************/
uint16_t TOUCH_ReadAdcX(void) {
uint16_t usAdc;


__set_PRIMASK(1);  /* 关中断 */
usAdc = g_tTP.usAdcNowX;
__set_PRIMASK(0);  /* 开中断 */


return usAdc;
}


/*****************************************************************
* 函 数 名: TOUCH_ReadAdcY
* 功能说明: 获得触摸板Y方向ADC采样值, 已进行滤波处理
* 形    参:  无
* 返 回 值: Y 坐标值,允许负值
*****************************************************************/
uint16_t TOUCH_ReadAdcY(void) {
uint16_t usAdc;


__set_PRIMASK(1);  /* 关中断 */
usAdc = g_tTP.usAdcNowY;
__set_PRIMASK(0);  /* 开中断 */


return usAdc;
}
/****************************************************************
* 函 数 名: TOUCH_TransY
* 功能说明: 将触摸ADC值转换为像素坐标
* 形    参:  无
* 返 回 值: Y 坐标值,允许负值
*****************************************************************/
static int16_t TOUCH_TransY(uint16_t _usAdcX, uint16_t _usAdcY) {
#if CALIB_POINT_COUNT == 2 /* 2点校准 */
int32_t x;
int32_t y;


if (g_tTP.XYChange == 0) {
x = _usAdcY;
if (x == 0) {
y = 0;
} else {
//y = CalTwoPoint(g_tTP.usAdcY1, TP_Y1, g_tTP.usAdcY2, TP_Y2, x);
y = CalTwoPoint(g_tTP.usAdcY1, g_tTP.usLcdY1, g_tTP.usAdcY2, g_tTP.usLcdY2, x);
}
} else {
x = _usAdcX;
if (x == 0) {
y = 0;
} else {
//y = CalTwoPoint(g_tTP.usAdcX1, TP_Y1, g_tTP.usAdcX2, TP_Y2, x);
y = CalTwoPoint(g_tTP.usAdcX1, g_tTP.usLcdY1, g_tTP.usAdcX2, g_tTP.usLcdY2, x);
}
}
return y;
#else /* 4点校准 */
int32_t x, x1, x2;
int32_t y;


if (g_tTP.XYChange == 0) {/* X Y 坐标不交换 */
x = _usAdcY;
/* 根据 X ADC 实时计算直线方程的参考点x1, x2
if  _usAdcX = usAdcX1 then  取点 = (AdcY1, TP_Y1, AdcY3, TP_Y3, _usAdcX)
if  _usAdcX = usAdcX2 then  取点 = (AdcY4, TP_Y4, AdcY2, TP_Y2, _usAdcX)


其中 TP_Y1 = TP_Y4;  TP_Y3 = TP_Y2 , 这是程序设定的校准位置的像素坐标, 是固定的。
我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
*/
x1 = CalTwoPoint(g_tTP.usAdcX1, g_tTP.usAdcY1, g_tTP.usAdcX2,  g_tTP.usAdcY4, _usAdcX);
x2 = CalTwoPoint(g_tTP.usAdcX1, g_tTP.usAdcY3, g_tTP.usAdcX2,  g_tTP.usAdcY2, _usAdcX);
} else { /* X Y 坐标交换 */
x = _usAdcX;


/* 根据 X ADC 实时计算直线方程的参考点x1, x2
if  _usAdcY = usAdcY1 then  取点 = (AdcX1, TP_Y1, AdcX3, TP_Y3, _usAdcY)
if  _usAdcY = usAdcY2 then  取点 = (AdcX4, TP_Y4, AdcX2, TP_Y2, _usAdcY)


其中 TP_Y1 = TP_Y3;  TP_Y4 = TP_Y2 , 这是程序设定的校准位置的像素坐标, 是固定的。
我们仅需要动态计算对第1个和第3个参数。同样采用2点直线方程计算。
*/
x1 = CalTwoPoint(g_tTP.usAdcY1, g_tTP.usAdcX1, g_tTP.usAdcY2,  g_tTP.usAdcX4, _usAdcY);
x2 = CalTwoPoint(g_tTP.usAdcY1, g_tTP.usAdcX3, g_tTP.usAdcY2,  g_tTP.usAdcX2, _usAdcY);
}
if (x == 0) {
y = 0;
} else {
/* 根据2点直线方程,计算坐标 */
// y = CalTwoPoint(x1, TP_Y1, x2, TP_Y2, x);
y = CalTwoPoint(x1, g_tTP.usLcdY1, x2, g_tTP.usLcdY2, x);
}
return y;
#endif
}
/****************************************************************
* 函 数 名: TSC2046_PenInt
* 功能说明: 判断触摸笔中断
* 形    参: 无
* 返 回 值: 1表示触笔按下  0表示释放
*****************************************************************/
Bool TSC2046_PenInt(void) {
if(!TOUCH_INT)
return TRUE;
else
return FALSE;
}
/****************************************************************
* 函 数 名: TOUCH_Scan
* 功能说明: 触摸扫描
* 形    参: 无
* 返 回 值: 无
*****************************************************************/
void TOUCH_Scan(void) {
static uint8_t s_count = 0;
uint16_t usAdcX;
uint16_t usAdcY;


if(TSC2046_PenInt()) {
usAdcX = TPReadXOY(ADC_CH_X);
usAdcY = TPReadXOY(ADC_CH_Y);
} else {
usAdcX = 0;
usAdcY = 0;
g_tTP.usAdcNowX = 0;
g_tTP.usAdcNowY = 0;
}
if(TOUCH_PressValid(usAdcX,usAdcY)) {
if (TOUCH_ReadAdcXOY()) {//采集SAMPLE_COUNT个数据进行滤波
usAdcX = TOUCH_TransX( g_tTP.usAdcNowX, g_tTP.usAdcNowY);//转换成物理坐标
usAdcY = TOUCH_TransY( g_tTP.usAdcNowX, g_tTP.usAdcNowY);
if (g_LcdDirection == 0) {/* 横屏 */
State.x = usAdcX;
State.y = usAdcY;
}
else if (g_LcdDirection == 1){/* 横屏180°*/
State.x = g_LcdWidth - usAdcX - 1;
State.y = g_LcdHeight - usAdcY - 1;
}
else if (g_LcdDirection == 2){/* 竖屏 */
State.y = usAdcX;
State.x =  g_LcdWidth- usAdcY - 1;
}
else if (g_LcdDirection == 3) {/* 竖屏180° */
State.y = g_LcdHeight - usAdcX - 1;
State.x = usAdcY;
}
State.Pressed = 1;
GUI_PID_StoreState(&State);
}
s_count = 5;
} else {
if (s_count > 0) {
if (--s_count == 0) {//要是没有改处理事件,gui的控件没法释放弹起
/* 触摸释放事件 */
State.x = -1;
State.y = -1;
State.Pressed = 0;
GUI_PID_StoreState(&State);
s_count = 0;

g_tTP.usAdcNowX = 0;
g_tTP.usAdcNowY = 0;
}
}
}
}
/****************************************************************
* 函 数 名: TOUCH_DispPoint1
* 功能说明: 显示第1个校准点
* 形    参:  _ucIndex = 0 : 表示第1个点; _ucIndex = 1 表示第2个点;
* 返 回 值: 无
*****************************************************************/
static void TOUCH_DispPoint(uint8_t _ucIndex) {
// FONT_T tFont16;/* 定义一个字体结构体变量,用于设置字体参数 */


/* 设置字体参数 */
{
// tFont16.FontCode = FC_ST_16;/* 字体代码 16点阵 */
// tFont16.FrontColor = CL_WHITE;/* 字体颜色 0 或 1 */
// tFont16.BackColor = CL_BLUE;/* 文字背景颜色 */
// tFont16.Space = 0;/* 文字间距,单位 = 像素 */
}


/*
第1个点 : x1 = CALIB_OFFSET, y1 = CALIB_OFFSET
第2个点 : x2 = LCD_GetHeight() - CALIB_OFFSET, y2 = LCD_GetWidth - CALIB_OFFSET
*/
if (_ucIndex == 0) {
LCD_Clear(CL_BLUE);  /* 清屏,背景蓝色 */


/* 在屏幕边沿绘制2个矩形框(用于检测面板边缘像素是否正常) */
// LCD_DrawRect(0, 0, LCD_GetHeight(), LCD_GetWidth(), CL_WHITE);
// LCD_DrawRect(2, 2, LCD_GetHeight() - 4, LCD_GetWidth() - 4, CL_YELLOW);


// LCD_DispStr(50, 10, "触摸屏四点校准,五秒内不校准将自动返回主界面", &tFont16);/* 在(8,3)坐标处显示一串汉字 */


GUI_Circle(TP_X1, TP_Y1, 6, CL_WHITE,0);
} else if (_ucIndex == 1) {
GUI_Circle(TP_X1, TP_Y1, 6, CL_BLUE,0);/* 擦除第1个点 */
GUI_Circle(TP_X2, TP_Y2, 6, CL_WHITE,0);
} else if (_ucIndex == 2) {
GUI_Circle(TP_X2, TP_Y2, 6, CL_BLUE,0);/* 擦除第2个点 */
GUI_Circle(TP_X3, TP_Y3, 6, CL_WHITE,0);
} else {
GUI_Circle(TP_X3, TP_Y3, 6, CL_BLUE,0);/* 擦除第3个点 */
GUI_Circle(TP_X4, TP_Y4, 6, CL_WHITE,0);
}
}
/****************************************************************
* 函 数 名: TOUCH_PressValid
* 功能说明: 判断按压是否有效,根据X, Y的ADC值进行大致判断
* 形    参:  无
* 返 回 值: 1 表示有效; 0 表示无效
****************************************************************/
static uint8_t TOUCH_PressValid(uint16_t _usX, uint16_t _usY)
{
if ((_usX <= ADC_VALID_OFFSET) || (_usY <= ADC_VALID_OFFSET)
|| (_usX >= g_tTP.usMaxAdc - ADC_VALID_OFFSET)
|| (_usY >= g_tTP.usMaxAdc - ADC_VALID_OFFSET))
{
return 0;
}
else
{
return 1;
}
}
/*
*********************************************************************************************************
* 函 数 名: TOUCH_WaitRelease
* 功能说明: 等待触笔释放
* 形    参:  无
* 返 回 值: 无
*********************************************************************************************************
*/
u8 dsd;
static void TOUCH_WaitRelease(void)
{
uint8_t usCount = 0;


for (;;)
{
if (TOUCH_PressValid(g_tTP.usAdcNowX, g_tTP.usAdcNowY)) {
if (++usCount > 5)
{
return;
}
}
else
{
usCount = 0;
}
delay_ms(5);
}
}
/***************************************************************
* 函 数 名: TOUCH_Calibration
* 功能说明: 触摸屏校准
* 形    参:  无
* 返 回 值: 无
****************************************************************/
void TOUCH_Calibration(void) {
uint16_t usAdcX;
uint16_t usAdcY;
uint8_t usCount;
uint8_t i;
uint32_t n;


TIM_Cmd(TIM2,ENABLE);
for (i = 0; i < CALIB_POINT_COUNT; i++) {
TOUCH_DispPoint(i);/* 显示校准点 */
TOUCH_WaitRelease(); /* 等待触笔释放 */
usCount = 0;
for (n = 0; n < 500; n++) {
usAdcX = g_tTP.usAdcNowX;
usAdcY = g_tTP.usAdcNowY;
if (TOUCH_PressValid(usAdcX,usAdcY)) {
if (++usCount > 5) {
/* 按压有效, 保存校准点ADC采样值 */
if (i == 0) {
g_tTP.usAdcX1 = usAdcX;
g_tTP.usAdcY1 = usAdcY;
  } else if (i == 1) {
g_tTP.usAdcX2 = usAdcX;
g_tTP.usAdcY2 = usAdcY;
} else if (i == 2) {
g_tTP.usAdcX3 = usAdcX;
g_tTP.usAdcY3 = usAdcY;
} else {
g_tTP.usAdcX4 = usAdcX;
g_tTP.usAdcY4 = usAdcY;
}
break;
}
} else {
usCount = 0;
}
delay_ms(10);
}
if (n == 500) {
return;
}
}
/* 识别触摸的 X, Y 和 显示面板的 X,Y 是否需要交换 */
g_tTP.XYChange = 0;/* 1表示X Y需要交换 */
if (LCD_GetHeight() < LCD_GetWidth())
{
if (TOUCH_Abs(g_tTP.usAdcX1 - g_tTP.usAdcX2) < TOUCH_Abs(g_tTP.usAdcY1 - g_tTP.usAdcY2))
{
g_tTP.XYChange = 1;
}
}
else
{
if (TOUCH_Abs(g_tTP.usAdcX1 - g_tTP.usAdcX2) > TOUCH_Abs(g_tTP.usAdcY1 - g_tTP.usAdcY2))
{
g_tTP.XYChange = 1;
}
}
g_tTP.usLcdX1 = TP_X1;
g_tTP.usLcdY1 = TP_Y1;
g_tTP.usLcdX2 = TP_X2;
g_tTP.usLcdY2 = TP_Y2;
g_tTP.usLcdX3 = TP_X3;
g_tTP.usLcdY3 = TP_Y3;
g_tTP.usLcdX4 = TP_X3;
g_tTP.usLcdY4 = TP_Y3;


TIM_Cmd(TIM2,DISABLE);
/* 在最后一步,可以将校准参数保存入Flash 或者EEPROM */
// TOUCH_SaveParam();
}

这是头文件



#ifndef TFTLCD_CHECK_H
#define TFTLCD_CHECK_H




#include "stm32f10x.h"
#include "TFTLCD_Driver.h"
#include "LCD_Touch.h"
#include "GUI.h"


#define CALIB_POINT_COUNT 4/* 2 = 2点校准; 4 = 四点校准 */


#define CHECK_TOUCH_STATE ENABLE //使能触摸校准
#define TOUCH_FIFO_SIZE 20




typedef struct
{
/* 2点校准 和 4点校准 */
uint16_t usAdcX1;/* 左上角 */
uint16_t usAdcY1;
uint16_t usAdcX2;/* 右下角 */
uint16_t usAdcY2;
uint16_t usAdcX3;/* 左下角 */
uint16_t usAdcY3;
uint16_t usAdcX4;/* 右上角 */
uint16_t usAdcY4;

uint16_t usLcdX1;/* 左上角 */
uint16_t usLcdY1;
uint16_t usLcdX2;/* 右下角 */
uint16_t usLcdY2;
uint16_t usLcdX3;/* 左下角 */
uint16_t usLcdY3;
uint16_t usLcdX4;/* 右上角 */
uint16_t usLcdY4;


uint16_t XYChange;/* X, Y 是否交换  */


uint16_t usMaxAdc;/* 触摸板最大ADC值,用于有效点判断. 最小ADC = 0  */
uint16_t usAdcNowX;
uint16_t usAdcNowY;


uint8_t Enable;/* 触摸检测使能标志 */


uint8_t Event[TOUCH_FIFO_SIZE];/* 触摸事件 */
int16_t XBuf[TOUCH_FIFO_SIZE];/* 触摸坐标缓冲区 */
int16_t YBuf[TOUCH_FIFO_SIZE];/* 触摸坐标缓冲区 */
uint8_t Read; /* 缓冲区读指针 */
uint8_t Write;/* 缓冲区写指针 */
}TOUCH_T;
#define RGB(R,G,B) (((R >> 3) << 11) | ((G >> 2) << 5) | (B >> 3))/* 将8位R,G,B转化为 16位RGB565格式 */
#define RGB565_R(x)  ((x >> 8) & 0xF8)
#define RGB565_G(x)  ((x >> 3) & 0xFC)
#define RGB565_B(x)  ((x << 3) & 0xF8)
enum
{
CL_WHITE        = RGB(255,255,255),/* 白色 */
CL_BLACK        = RGB(  0,  0,  0),/* 黑色 */
CL_RED          = RGB(255,0,  0),/* 红色 */
CL_GREEN        = RGB(  0,255,  0),/* 绿色 */
CL_BLUE         = RGB(  0,0,255),/* 蓝色 */
CL_YELLOW       = RGB(255,255,  0),/* 黄色 */


CL_GREY = RGB( 98, 98, 98), /* 深灰色 */
CL_GREY1 = RGB( 150, 150, 150), /* 浅灰色 */
CL_GREY2 = RGB( 180, 180, 180), /* 浅灰色 */
CL_GREY3 = RGB( 200, 200, 200), /* 最浅灰色 */
CL_GREY4 = RGB( 230, 230, 230), /* 最浅灰色 */


CL_BUTTON_GREY= RGB( 220, 220, 220), /* WINDOWS 按钮表面灰色 */


CL_MAGENTA      = 0xF81F,/* 红紫色,洋红色 */
CL_CYAN         = 0x7FFF,/* 蓝绿色,青色 */


CL_BLUE1        = RGB(  0,  0, 240),/* 深蓝色 */
CL_BLUE2        = RGB(  0,  0, 128),/* 深蓝色 */
CL_BLUE3        = RGB(  68, 68, 255),/* 浅蓝色1 */
CL_BLUE4        = RGB(  0, 64, 128),/* 浅蓝色1 */


/* UI 界面 Windows控件常用色 */
CL_BTN_FACE = RGB(236, 233, 216), /* 按钮表面颜色(灰) */
CL_BOX_BORDER1= RGB(172, 168,153),/* 分组框主线颜色 */
CL_BOX_BORDER2= RGB(255, 255,255),/* 分组框阴影线颜色 */




CL_MASK = 0x9999 /* 颜色掩码,用于文字背景透明 */
};
extern GUI_PID_STATE State;
extern TOUCH_T g_tTP;


void TOUCH_Calibration(void);
void TFTLCD_CkPoint(void);
void TOUCH_Scan(void);


#endif

程序中使用定时器2进行触摸的扫描和数据的处理


定时器2 的配置

/***************************************************************************
* 名    称:void TIM2_Int_Init(void) 
* 功    能:TIM2 中断配置函数
* 入口参数:无
* 出口参数:无
* 说    明:1mS定时,用来定时剩余时间
* 调用方法:
****************************************************************************/ 
void TIM2_Int_Init(void) {
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);/*时钟使能*/
/*定时器TIM2初始化*/
TIM_TimeBaseStructure.TIM_Period = 999; /*999设置在下一个更新事件装入活动的自动重装载寄存器周期的值*/
TIM_TimeBaseStructure.TIM_Prescaler =72;/*72设置用来作为TIMx时钟频率除数的预分频值1mS定时*/
TIM_TimeBaseStructure.TIM_ClockDivision = 0;/*设置时钟分割:TDTS = Tck_tim,定时的时候不涉及此功能*/
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  /*TIM向上计数模式*/
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);/*根据指定的参数初始化TIMx的时间基数单位*/


TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); /*失能指定的TIM2中断,允许更新中断*/
/*中断优先级NVIC设置*/
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;  /*TIM2中断*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;  /*抢占优先级3级*/
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;/*从优先级0级*/
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;/*IRQ通道被使能*/
NVIC_Init(&NVIC_InitStructure);  /*初始化NVIC寄存器*/
TIM_Cmd(TIM2, ENABLE);  /*使能TIM2*/ 
}

定时器2的中断处理函数



/*******************************************************************************
* Function Name  : TIM2_IRQHandler
* Description    : This function handles TIM2 global interrupt request.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
extern void TOUCH_Scan(void );
__irq void TIM2_IRQHandler(void) {
static u8 cnt = 0;
#if SYSTEM_SUPPORT_OS
CPU_SR_ALLOC();
OS_CRITICAL_ENTER();  //保存全局中断标志,关总中断// Tell uC/OS-II that we are starting an ISR
OSIntNestingCtr++; //用于中断嵌套
OS_CRITICAL_EXIT(); //恢复全局中断标志
#endif

if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {  /*检查TIM2更新中断发生与否*/
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);  /*清除TIMx更新中断标志*/
cnt++;
if(cnt > 5) {
cnt = 0;
TOUCH_Scan();
}
}

#if SYSTEM_SUPPORT_OS
OSIntExit();  //在os_core.c文件里定义,如果有更高优先级的任务就绪了,则执行一次任务切换
#endif
}

程序中只要设置g_tTP.usMaxAdc = 4096;根据触摸AD的采样精度设置

然后调用 TOUCH_Calibration();即可进行触摸校准

注意:使用该触摸校准程序要先注释LCD_X_Config();函数中的

GUI_TOUCH_Calibrate(GUI_COORD_X,0,XSIZE_PHYS,TOUCH_AD_TOP,TOUCH_AD_BOTTOM);
GUI_TOUCH_Calibrate(GUI_COORD_Y,0,VYSIZE_PHYS,TOUCH_AD_LEFT,TOUCH_AD_RIGHT);

这两程序。

XPT2046触摸程序

源文件:



#include "LCD_Touch.h"




int Xre,Yre;


/****************************************************************************
* 名    称:u16 TPReadX(void) 
* 功    能:触摸屏X或Y轴数据读出
* 入口参数:CMD: 0xD0读出X轴数据; CMD: 0x90读出Y轴数据
* 出口参数:无
* 说    明:
* 调用方法:
****************************************************************************/  
u16 TPReadXOY(u8 ADC_CH_XOY) { 
   u16 x=0;
   TP_CS();                  //选择XPT2046 
   SPI2_ReadWrite((1 << 7) | (ADC_CH_XOY << 4)); //设置X轴读取标志
   x = SPI2_ReadWrite(0x00); //连续读取16位的数据 
   x <<= 8;
   x |= SPI2_ReadWrite(0x00);
   TP_DCS(); //禁止XPT2046
   x = x >> 3; //移位换算成12位的有效数据0-4095
   return (x);

/**********************************************************************
* 函 数 名: TOUCH_Abs
* 功能说明: 计算绝对值
* 形    参:无
* 返 回 值: 无
***********************************************************************/
int32_t TOUCH_Abs(int32_t x) {
if (x >= 0) {
return x;
} else {
return -x;
}
}
/***********************************************************************
* 函 数 名: GUI_TOUCH_MeasureXOY
* 功能说明: 循环读取READ_TIMES次触摸ADC值,升序排列后,
* 丢弃前后LOST_VAL最大最小值,再取平均值
* 形    参:CMD:求X或Y的ADC,CMD: 0xD0读出X轴数据; CMD: 0x90读出Y轴数据
* 返 回 值: 
************************************************************************/
#define READ_TIMES 10 //读取次数
#define LOST_VAL 2  //丢弃值
u16 GUI_TOUCH_MeasureXOY(u8 ADC_CH_XOY) {
unsigned char i, j;
u16 buf[READ_TIMES];//数据组
u16 sum = 0;
u16 temp;
 
for(i = 0;i < READ_TIMES;i++){//循环读数 READ_TIMES 次
buf[i] = TPReadXOY(ADC_CH_XOY);
}
//滤波
for(i = 0;i < READ_TIMES - 1;i++) {//将数据X升序排列
for(j = i + 1;j < READ_TIMES;j++) {
if(buf[i] > buf[j]) {//升序排列
temp = buf[i];
buf[i] = buf[j];
buf[j] = temp;
}  
}
}
sum = 0;
for(i = LOST_VAL;i < READ_TIMES - LOST_VAL;i++) {
sum += buf[i];
}
temp = sum / (READ_TIMES - 2 * LOST_VAL);
return (temp);
}
/*********************************************************************
* 函 数 名: TOUCH_ReadAdcXY
* 功能说明: 连续2次读取触摸屏IC,且这两次的偏差不能超过
*           ADC_ERR_RANGE,满足条件,则认为读数正确,否则读数错误.   
*           该函数能大大提高准确度.
* 该滤波函数不能单独读取两次X或Y坐标的值判断,必须连续读取两
* 次X和Y的坐标,然后判断X和Y的误差
* 形    参:CMD:求ADC误差,CMD: 0xD0读出X轴数据; CMD: 0x90读出Y轴数据
* 返 回 值: TRUE: 读取触摸正确, FALSE: 读取触摸错误
**********************************************************************/
/* 误差范围 */
uint8_t ADC_ERR_RANGE = 5;
Bool TOUCH_ReadAdcXOY(void) {
uint16_t usX1,usY1, usX2,usY2;
uint16_t ABSx = 0,ABSy = 0;


usX1 = GUI_TOUCH_MeasureXOY(ADC_CH_Y);
usY1 = GUI_TOUCH_MeasureXOY(ADC_CH_X);
  usX2 = GUI_TOUCH_MeasureXOY(ADC_CH_Y);
  usY2 = GUI_TOUCH_MeasureXOY(ADC_CH_X);
ABSx = TOUCH_Abs(usX1 - usX2);
ABSy = TOUCH_Abs(usY1 - usY2);
if ((ABSx <= ADC_ERR_RANGE) && (ABSy <= ADC_ERR_RANGE)) {// 前后两次采样在+-ERR_RANGE内
Xre = (usX1 >> 1) + (usX2 >> 1);
Yre = (usY1 >> 1) + (usY2 >> 1);
g_tTP.usAdcNowX = Xre;
g_tTP.usAdcNowY = Yre;
return TRUE;
} else {
return FALSE;
}
}
头文件





#ifndef LCD_TOUCH_H
#define LCD_TOUCH_H


#include "stm32f10x.h"
#include "SPI_Config.h"
#include "TFTLCD_Check.h"






/* XPT2046 内部ADC通道号 */
#define ADC_CH_X 1/* X通道,测量X位置 */
#define ADC_CH_Y 5/* Y通道,测量Y位置 */


u16 TPReadXOY(u8 ADC_CH_XOY);
void TOUCH_SCAN(void);




extern int Xre,Yre;


#endif







你可能感兴趣的:(STM32,C语言,STM32,Stemwin,图片,操作系统,uCGUI,Stemwin)