测试开发板的连接: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