通过TFTLCD中位于边缘两端的两个电极(X+,X-,Y+,Y-),形成2个相互垂直的5V的电场,当有物体触摸液晶屏时,由于下方的电阻丝的分压效应,触摸点处的电压将是一个0-5V的电压,且这个电压是与触摸的位置成一次函数关系的,我们只需通过校准后得知X0,Y0 处的电压值和该直线的斜率,我们就可以通过其他点触摸时的电压换算出其位置。
原子采用的是四点校准的方式,即通过点击四角的四个点,计算这四个点击点位置,距离关系是否符合四角的位置关系来确定上面的两个截距xoff,yoff,xfac,yfac。并且将这四个点储存在AT24C02这个EEPROM里 (这样就不需要每次使用前都需要校准) 。
根据上方的指令集,有12位分辨率模式下,0xD0为读取X坐标;0x90为读取Y坐标。
需要AT24C02的地址40到54,来储存已经调试好的参数 X0,Xfac 等变量,所以需include"24cxx.h" ;
tp_dev.init();触摸屏初始化函数,原子为了兼容不同屏幕,将不同屏幕的使用函数,按检测LCD的不同,将其指针赋给结构体的对应函数;
tp_dev.scan(0),此函数参数使用时, 常为0,此时读出结构体中的x[0],y[0]坐标为校正后的屏幕坐标, (参数为1时,为物理坐标,用于校准), 其返回值用于判断是否读取成功 。
TP_Adjust(),调用其。开始屏幕校准过程;
原子定义的电阻屏结构体中:
tpdev.sta,[7] 标志触摸与否;[6]标志第一次触摸与否;
如果上次按完立即松开,按另一处,tpdev.x[4]和tpdev.y[4]储存的是上一次按下的坐标,tpdev.x[0]和tpdev.y[0]表示这一次按下时的坐标;
如果上一次按下后未松开,接着按另一处(因为我们使用函数两次检测按下的时间间隔是安排为20ms的),即划线的状态, 那么此时(我们这个线松开后):tpdev.x[4]和tpdev.y[4]储存的是线的起始的坐标,tpdev.x[0]和tpdev.y[0]表示线的结束的坐标(且这个坐标如果在按下时检测是随移动变化的) ;常为此种情况,因为我们很少能在10ms内,按下,松开,再按另一处;
所以,通常原子函数的使用模板如下:(改自原子的函数)
tp_dev.init();
while(1)//轮询状态(即循环scan),以实时检查变化
{
//注意,读点应为tp_dev.x[0]这样,以下注释中简写为x[0]
key=KEY_Scan(0);//key0用于检测校准
tp_dev.scan(0); //扫描一次,接下来x[0],[0]才为坐标
if(tp_dev.sta&TP_PRES_DOWN) //检测触摸屏被按下与否,该宏用来检测最高位
{
/*
这里检测时x[0],y[0]为实时按下的点(假设笔触相对于10ms缓慢移动)
对实时画点的操作,应该在此处进行
*/
}
else if(/*自定义限制条件*/)
{
/*
此处读点x[0],y[0],为笔迹结束点;x[4],y[4],为笔迹开始点
需要始末点(如画⚪,画方框)的操作,应在此处进行
*/
}
else delay_ms(10);
//没有按键按下的时候,避免过快检测,同时延迟也为笔迹检测的最低间隔时间
if(key==KEY0_PRES) //KEY0按下,则执行校准程序
{
LCD_Clear(CYAN);//清屏
TP_Adjust(); //屏幕校准调用
}
i++;
if(i%20==0)LED0=!LED0;//指示灯,当按下时由于跳过了20ms的延时,指示灯快速频闪
}
项目:LCD涂鸦板,可调色,可画方框,可橡皮擦;项目开源在gitee上,连接如下:码云仓库project2文件夹
整个工程可以去Gitee上下载;如果不想的话,也可以直接用原子LCD电阻触摸屏的例程(zet6精英板+3.5寸LCD),将main.c文件换为下方的main.c即可:
main.c和文件lcd.c的改动如下:(我将其中不需要使用的电容屏部分删除了)
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"
#include "24cxx.h"
#include "w25qxx.h"
#include "touch.h"
#define Point_eraser 0x00
#define Point_Pencial 0x01
#define Point_Select_Rectangle 0x02
#define Point_Start_Rectangle 0x03
//因为方框只有在画笔松开后才能确定最后一个点作为方框的结束顶点,所以方框的绘制只能在触屏松开时进行绘制,
//也因为在需要在触屏松开时绘制,所以方框,即使选择了方框模式也不能马上进入方框的绘制,需要等待下一次触摸时输入的两个顶点坐标,
//所以这儿采用将其制定为两种模式,即两个标志位,Select和Start
u8 Point_TYPE=0x01;//1:pencil,0:Eraser ;2:select_recyangle,3:Start_recyangle
typedef struct _color_board{
u8 width;
u8 length;
u16 color_type[7];
}ColorBoard;//制定调色板的宽度,长度,及颜色
ColorBoard my_color_board={
24,
40,
{RED,BRRED,YELLOW,GREEN,CYAN,BLUE,LBBLUE}//找不到紫色,最后一个用海蓝色
//七色赋值
};//初始化调色板结构体
/*******************************************************************************
@函 数 名 : void Color_Board_Init()
@函数功能 :调色板初始化,即在上方显示调色板的函数
@输 入 : 无
@输 出 : 无
@说 明 : 无
*******************************************************************************/
void Color_Board_Init()
{
u8 i=0;
for(i=0;i<7;i++)
{
LCD_Fill(my_color_board.length*i,0,my_color_board.length*(i+1),my_color_board.width,(my_color_board.color_type[i]));
}
}
/*******************************************************************************
@函 数 名 : void tools_Show()
@函数功能 :工具栏显示,即在下方显示工具栏的函数
@输 入 : 输入参数为当前pencil栏的指示颜色
@输 出 : 无
@说 明 : 无
*******************************************************************************/
void tools_Show(u16 temp_color)
{
POINT_COLOR=RED;
LCD_DrawRectangle(0,lcddev.height-40,120,lcddev.height);
LCD_DrawRectangle(120,lcddev.height-40,200,lcddev.height);
LCD_DrawRectangle(200,lcddev.height-40,320,lcddev.height);//底部三个框
LCD_ShowString(220,lcddev.height-36,80,24,24,"Eraser");//'Eraser'符号
//将不需要调色的部分先绘制
if(Point_TYPE==Point_eraser)LCD_Fill(295,lcddev.height-36,310,lcddev.height-12,RED);
else LCD_Fill(295,lcddev.height-36,310,lcddev.height-12,WHITE);//显示eraser的提示符————一个实心的方框,提示当前触摸为eraser
if(Point_TYPE==Point_Select_Rectangle||Point_TYPE==Point_Start_Rectangle)
{
LCD_Fill(121,lcddev.height-39,199,lcddev.height,temp_color);//口选中填对应色
if(temp_color==RED)
{
POINT_COLOR=BLUE;//防止指示红色栏时导致方框符消失消失;
LCD_DrawLine(120,lcddev.height-40,120,lcddev.height);//重绘制 pencil 和 口 分割线,一开始默认红色边框带来的麻烦
}
}
else LCD_Fill(121,lcddev.height-39,199,lcddev.height,WHITE);//没选中 口 方框填白色
LCD_DrawRectangle(140,lcddev.height-30,180,lcddev.height-10);//绘制 ‘口 ’ 符号
LCD_Fill(1,lcddev.height-39,119,lcddev.height,temp_color);//填充pencil框指示色
if(temp_color==RED)POINT_COLOR=BLUE;//防止指示红色栏时导致Pencil字样消失;
LCD_ShowString(20,lcddev.height-36,80,24,24,"Pencil");
POINT_COLOR=RED;//字体默认红色重置
}
//清空屏幕并在右上角显示"RST"和调色板及tools栏
void Load_Drow_Dialog(u16 temp_color)
{
LCD_Clear(WHITE); //清屏
POINT_COLOR=BLUE; //设置字体为蓝色
LCD_ShowString(lcddev.width-36,0,200,24,24,"RST");//显示清屏区域
Color_Board_Init();//清屏后显示调色版
tools_Show(temp_color);//清屏后显示工具栏
POINT_COLOR=RED; //设置字体红色
}
//电阻触摸屏测试函数
void rtp_test(void)
{
u8 key;
u8 i=0;
u16 My_Point_Color=BLACK;
u16 temp_color=BLACK;//初始化,画笔默认黑色
while(1)
{
key=KEY_Scan(0);
tp_dev.scan(0);
if(tp_dev.sta&TP_PRES_DOWN) //触摸屏被按下
{
if(tp_dev.x[0]<(lcddev.width-40)&&tp_dev.y[0]<my_color_board.width&& (Point_TYPE&0x01) )//检测调色板范围,Eraser是无法选择更改颜色
{
for (i=0;i<7;i++)
{
if(tp_dev.x[0]>( my_color_board.length*i )&&tp_dev.x[0]<( my_color_board.length*(i+1) )&&tp_dev.y[0]<24)
My_Point_Color=my_color_board.color_type[i];//检查选中哪块色板,改变画笔颜色
}
temp_color=My_Point_Color;//暂存选中的画笔颜色,方便从erser切换回来
tools_Show(temp_color);//更新tools栏的指示颜色
}
else if(tp_dev.x[0]>(lcddev.width-36)&&tp_dev.y[0]<24)
{
Load_Drow_Dialog(BLACK);//清除
My_Point_Color=BLACK;//清屏后画笔默认黑色
temp_color=BLACK;//清屏后画笔默认黑色
}
else if(tp_dev.x[0]<lcddev.width&&tp_dev.y[0]>lcddev.height-36)//检测工具栏pencil和Eraser,rectangle的切换
{
if(tp_dev.x[0]< 120 ){Point_TYPE=Point_Pencial;My_Point_Color=temp_color;}//select pencil
if(tp_dev.x[0]> 120&&tp_dev.x[0]< 200 )
{
Point_TYPE=Point_Select_Rectangle;
My_Point_Color=WHITE;//隐藏画线,防止start取点时有线的阴影。
}//隐藏画线//select rectangle
if(tp_dev.x[0]> 200 ){Point_TYPE=Point_eraser;My_Point_Color=BACK_COLOR;}//select Eraser
tools_Show(temp_color);//更改tools后更新工具栏;
}
else
{
if(Point_TYPE==Point_Select_Rectangle)Point_TYPE=Point_Start_Rectangle;
//用于Select_rectangle后获取两个顶点坐标,并切换进start_rectangle
TP_Draw_Big_Point(tp_dev.x[0],tp_dev.y[0],My_Point_Color); //画图
}
}
else if( (Point_TYPE==Point_Start_Rectangle) )//画框开始,检测触摸屏松开后
{
if(tp_dev.y[0]>36&&tp_dev.y[0]<lcddev.height-36)//保证画框顶点在可绘画区域
{
POINT_COLOR=temp_color;//更改系统颜色,为画不同色的框
My_Point_Color=BACK_COLOR;//隐藏画笔颜色;
LCD_DrawRectangle(tp_dev.x[4],tp_dev.y[4],tp_dev.x[0],tp_dev.y[0]);
POINT_COLOR=RED;//重置字体颜色为红
Point_TYPE=Point_Pencial;
//切换回pencil模式,为下一次检测做准备,也可改为连续画框(取消下方注释,连续画框模式)
// Point_TYPE=Point_Select_Rectangle;
// 考虑,通常不会频繁画框,所以默认设为,画完即退回pencil模式
if(Point_TYPE!=Point_Select_Rectangle)My_Point_Color=temp_color;//之后不连续画框,恢复画笔颜色
tools_Show(temp_color);//更新指示框
}
}
else delay_ms(10); //没有按键按下的时候,避免过快检测
if(key==KEY0_PRES) //KEY0按下,则执行校准程序
{
LCD_Clear(CYAN);//清屏
TP_Adjust(); //屏幕校准
Load_Drow_Dialog(BLACK);//清屏重绘
}
i++;
if(i%20==0)LED0=!LED0;//指示灯,当按下时由于跳过了20ms的延时,指示灯快速频闪
}
}
int main(void)
{
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
LCD_Init();
KEY_Init();
tp_dev.init();//触摸屏初始化
POINT_COLOR=RED;//设置字体为红色
LCD_ShowString(60,130,200,16,16,"Press KEY0 to Adjust");
delay_ms(1500);
Load_Drow_Dialog(BLACK);//显示RST,初始化时,默认画笔为黑色,所以指示也为黑色
rtp_test(); //电阻屏测试
}
除了将上述main.c替换原来的main.c外,还需将lcd.c最后一个函数LCD_ShowString()中的LCD_ShowChar(x,y,*p,size,0);的0换为1,如下图。(只是为了字符串显示好看)