开头
过了这么久,总算有了一段时间能暂缓脚步,能抽出一些时间来完成一些专业能力提升的事情了,希望这一次能够一战成硕。接下来,我做的一个小项目是基于stm32f103的简易密码锁(二),这一次我用TFTLCD触摸屏来试试,只有在做的时候才能发现自己的能力有多弱,有多浮躁,想起唐叔那句话,慢慢来,才更快。
一、所需材料
主要采用的是stm32f103zet6的开发板、正点原子的4.3寸TFTLCD触摸屏,一个继电器,可手动焊接一个3.3v转为5v的电路板(因为开发板的IO口是3.3v,而我之前买的电磁锁是5v驱动,所以我需要)、一个电磁锁模块。(注:代码是根据在正点原子触摸屏程序上改写的)
二、演示
三、TFTLCD介绍
电阻触摸屏的主要部分是一块与显示器表面非常配合的电阻薄膜屏,这是一种多层的复合薄膜,它以一层玻璃或硬塑料平板作为基层,表面涂有一层透明氧化金属(透明的导电电阻)导电层,上面再盖有一层外表面硬化处理、光滑防擦的塑料层、它的内表面也涂有一层涂层、在他们之间有许多细小的(小于 1/1000 英寸)的透明隔离点把两层导电层隔开绝缘。 当手指触摸屏幕时,两层导电层在触摸点位置就有了接触,电阻发生变化,在 X 和 Y 两个方向上产生信号,然后送触摸屏控制器。控制器侦测到这一接触并计算出(X,Y)的位置,再根据获得的位置模拟鼠标的方式运作。这就是电阻技术触摸屏的最基本的原理。
电容式触摸屏主要分为两种:
1、 表面电容式电容触摸屏。
2、 投射式电容触摸屏。
正点原子的4.3寸TFTLCD触摸屏是电容触摸屏,ALIENTEK 所选择的电容触摸屏,也是采用的是投射式电容屏(交互电容类型)。ATK—4.3寸 TFTLCD模块,分辨率:480*800 驱动IC:NT35510(ID5510) 电容触摸屏 16位并口驱动
注意其参数:
四、部分程序
1.主程序
代码如下(示例):
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();
delay_ms(1500);
Load_Drow_Dialog();
KEY_LED();
ctp_test(); //电容屏测试
}
2.构建虚拟键盘
代码如下(示例):
void KEY_LED()
{
POINT_COLOR=BLUE;
LCD_DrawRectangle(90,550,400,600); //画一个矩形
//在矩形里面分割成小格,1,2,3,4,5....
LCD_ShowNum(100,100,1,1,32);
LCD_ShowNum(200,100,2,1,32);
LCD_ShowNum(300,100,3,1,32);
LCD_ShowChar(400,100,'@',32,1);
LCD_ShowNum(100,200,4,1,32);
LCD_ShowNum(200,200,5,1,32);
LCD_ShowNum(300,200,6,1,32);
LCD_ShowChar(400,200,'#',32,1);
LCD_ShowNum(100,300,7,1,32);
LCD_ShowNum(200,300,8,1,32);
LCD_ShowNum(300,300,9,1,32);
LCD_ShowChar(400,300,'*',32,1);
LCD_ShowNum(100,400,0,1,32);
LCD_ShowChar(200,400,'.',32,1);
LCD_ShowString(300,400,200,24,32,"OK");
LCD_ShowString(400,400,200,24,32,"NO");
//行线
LCD_DrawLine(0,75,480,75);
LCD_DrawLine(0,175,480,175);
LCD_DrawLine(0,275,480,275);
LCD_DrawLine(0,375,480,375);
LCD_DrawLine(0,475,480,475);
//列线
LCD_DrawLine(50,75,50,475);
LCD_DrawLine(150,75,150,475);
LCD_DrawLine(250,75,250,475);
LCD_DrawLine(350,75,350,475);
}
画的是一个虚拟键盘,只不过画的有那么一点点丑,大家改的时候可以优化一下,让它在屏幕中对称,主要是后面我有点懒了。
2.对键盘扫描
//键盘按键处理
if(n<8)
{
if(tp_dev.x[t]>50&&tp_dev.x[t]<150&&tp_dev.y[t]>75&&tp_dev.y[t]<175) //如果按下1
{
while(tp_dev.x[t]>50&&tp_dev.x[t]<150&&tp_dev.y[t]>75&&tp_dev.y[t]<175) //这三行代码主要是防止一直按着或者按着同一个数字过长,形成按一次一个数字
{
tp_dev.scan(0);
}
key[n]='1';
n++;
}
if(tp_dev.x[t]>150&&tp_dev.x[t]<250&&tp_dev.y[t]>75&&tp_dev.y[t]<175) //如果按下2
{
while(tp_dev.x[t]>150&&tp_dev.x[t]<250&&tp_dev.y[t]>75&&tp_dev.y[t]<175)
{
tp_dev.scan(0);
}
key[n]='2';
n++;
}
if(tp_dev.x[t]>250&&tp_dev.x[t]<350&&tp_dev.y[t]>75&&tp_dev.y[t]<175) //如果按下3
{
while(tp_dev.x[t]>250&&tp_dev.x[t]<350&&tp_dev.y[t]>75&&tp_dev.y[t]<175)
{
tp_dev.scan(0);
}
key[n]='3';
n++;
}
if(tp_dev.x[t]>350&&tp_dev.x[t]<470&&tp_dev.y[t]>75&&tp_dev.y[t]<175) //如果按下5
{
while(tp_dev.x[t]>350&&tp_dev.x[t]<470&&tp_dev.y[t]>75&&tp_dev.y[t]<175)
{
tp_dev.scan(0);
}
key[n]='@';
n++;
}
if(tp_dev.x[t]>50&&tp_dev.x[t]<150&&tp_dev.y[t]>175&&tp_dev.y[t]<275) //如果按下4
{
while(tp_dev.x[t]>50&&tp_dev.x[t]<150&&tp_dev.y[t]>175&&tp_dev.y[t]<275)
{
tp_dev.scan(0);
}
key[n]='4';
n++;
}
if(tp_dev.x[t]>150&&tp_dev.x[t]<250&&tp_dev.y[t]>175&&tp_dev.y[t]<275) //如果按下5
{
while(tp_dev.x[t]>150&&tp_dev.x[t]<250&&tp_dev.y[t]>175&&tp_dev.y[t]<275)
{
tp_dev.scan(0);
}
key[n]='5';
n++;
}
if(tp_dev.x[t]>250&&tp_dev.x[t]<350&&tp_dev.y[t]>175&&tp_dev.y[t]<275) //如果按下6
{
while(tp_dev.x[t]>250&&tp_dev.x[t]<350&&tp_dev.y[t]>175&&tp_dev.y[t]<275)
{
tp_dev.scan(0);
}
key[n]='6';
n++;
}
if(tp_dev.x[t]>350&&tp_dev.x[t]<470&&tp_dev.y[t]>175&&tp_dev.y[t]<275) //如果按下'#'
{
while(tp_dev.x[t]>350&&tp_dev.x[t]<470&&tp_dev.y[t]>175&&tp_dev.y[t]<275)
{
tp_dev.scan(0);
}
key[n]='#';
n++;
}
if(tp_dev.x[t]>50&&tp_dev.x[t]<150&&tp_dev.y[t]>275&&tp_dev.y[t]<375) //如果按下7
{
while(tp_dev.x[t]>50&&tp_dev.x[t]<150&&tp_dev.y[t]>275&&tp_dev.y[t]<375)
{
tp_dev.scan(0);
}
key[n]='7';
n++;
}
if(tp_dev.x[t]>160&&tp_dev.x[t]<240&&tp_dev.y[t]>275&&tp_dev.y[t]<375) //如果按下8
{
while(tp_dev.x[t]>160&&tp_dev.x[t]<240&&tp_dev.y[t]>275&&tp_dev.y[t]<375)
{
tp_dev.scan(0);
}
key[n]='8';
n++;
}
if(tp_dev.x[t]>260&&tp_dev.x[t]<340&&tp_dev.y[t]>275&&tp_dev.y[t]<375) //如果按下9
{
while(tp_dev.x[t]>260&&tp_dev.x[t]<340&&tp_dev.y[t]>275&&tp_dev.y[t]<375)
{
tp_dev.scan(0);
}
key[n]='9';
n++;
}
if(tp_dev.x[t]>50&&tp_dev.x[t]<150&&tp_dev.y[t]>375&&tp_dev.y[t]<475) //如果按下0
{
while(tp_dev.x[t]>50&&tp_dev.x[t]<150&&tp_dev.y[t]>375&&tp_dev.y[t]<475)
{
tp_dev.scan(0);
}
key[n]='0';
n++;
}
if(tp_dev.x[t]>150&&tp_dev.x[t]<250&&tp_dev.y[t]>375&&tp_dev.y[t]<475) //如果按下.
{
while(tp_dev.x[t]>150&&tp_dev.x[t]<250&&tp_dev.y[t]>375&&tp_dev.y[t]<475)
{
tp_dev.scan(0);
}
key[n]='.';
n++;
}
}
else
n=8;
这里我建议可以改成那种51单片机里面那种行列矩阵键盘的形式进行赋值,看起来会更简洁一点,因为每一个赋值都有重复的在里面,当时主要是我感觉写完第一个赋值,然后接下来的就复制粘贴起来会很快又是无脑操作。
3.功能键
if(tp_dev.x[t]>250&&tp_dev.x[t]<350&&tp_dev.y[t]>375&&tp_dev.y[t]<475) //如果按下ok
{
while(tp_dev.x[t]>250&&tp_dev.x[t]<350&&tp_dev.y[t]>375&&tp_dev.y[t]<475)
{
tp_dev.scan(0);
}
for(a=0;a<8;a++)
{
if(key[a]==mima[a])
{
key_flag=key_flag+1;
}
}
if(key_flag==8)//显示密码正确
{
LCD_Fill(130,625,300,700,WHITE);
ShowChinese(150,650,0,32,RED,BLUE,1);
ShowChinese(185,650,1,32,RED,BLUE,1);
ShowChinese(220,650,2,32,RED,BLUE,1);
ShowChinese(255,650,3,32,RED,BLUE,1);
GPIO_ResetBits(GPIOF,GPIO_Pin_13);
key_flag=0;
}
else //显示密码错误
{
LCD_Fill(130,625,300,700,WHITE);
ShowChinese(150,650,4,32,RED,BLUE,1);
ShowChinese(185,650,5,32,RED,BLUE,1);
ShowChinese(220,650,6,32,RED,BLUE,1);
ShowChinese(255,650,7,32,RED,BLUE,1);
GPIO_SetBits(GPIOF,GPIO_Pin_13);
key_flag=0;
}
LED1=!LED1;
}
if(tp_dev.x[t]>350&&tp_dev.x[t]<470&&tp_dev.y[t]>375&&tp_dev.y[t]<475) //如果按下NO,撤销按键
{
while(tp_dev.x[t]>350&&tp_dev.x[t]<470&&tp_dev.y[t]>375&&tp_dev.y[t]<475)
{
tp_dev.scan(0);
}
for(clear=n-1;clear<n;clear++)
{
n--;
key[n]=' ';
}
}
if(tp_dev.x[t]>350&&tp_dev.x[t]<470&&tp_dev.y[t]>275&&tp_dev.y[t]<375) //如果按下'*'按键实现清除
{
while(tp_dev.x[t]>350&&tp_dev.x[t]<470&&tp_dev.y[t]>275&&tp_dev.y[t]<375)
{
tp_dev.scan(0);
}
for(m=0;m<9;m++)
{
key[m]=' ';
}
n=0;
LCD_Fill(130,625,300,700,WHITE);
}
LCD_ShowString(100,560,240,32,32,key);
}
}
else
lastpos[t][0]=0XFFFF;
}
delay_ms(5);i++; //加上这两行可以知道程序在运行
if(i%20==0)LED0=!LED0;
}
像showchinese数组可以利用pctolcd2002来处理会很方便,我会把它放在文章最后提供给大家。
4.在指定位置显示一个中文字函数
//在指定位置显示一个字符
//x,y:起始坐标
//num:要显示的字符:" "--->"~"
//size:字体大小 12/16/24
//mode:叠加方式(1)还是非叠加方式(0)
//pointcolor 字的颜色
void ShowChinese(u16 x,u16 y,u8 index,u8 size,u16 pointcolor,u16 backcolor,u8 mode)
{
u8 temp,t1,t;
u16 y0=y;
u8 csize=(size/8+((size%8)?1:0))*(size); //得到一个汉字对应点阵集所占的字节数
for(t=0;t<csize;t++)
{
if(size==32)
temp=chinese[index][t];
for(t1=0;t1<8;t1++)
{
if(temp&0x80)
LCD_Fast_DrawPoint(x,y,pointcolor);
else if(mode==0)
LCD_Fast_DrawPoint(x,y,backcolor);
temp<<=1;
y++;
if(y>=lcddev.height)return; //超区域了
if((y-y0)==size)
{
y=y0;
x++;
if(x>=lcddev.width)return; //超区域了
break;
}
}
}
}
大家可以根据正点原子提供的代码,然后看懂后,在此基础上改就可以,我参照在指定位置显示一个字符然后改写一个在指定位置显示一个中文字,注意更改代码时候,csize要变化,因为一个中文字等于两个字符的大小。
五、相关解释及注意事项
- 正点原子代码里有一个数组可以这样定义,我把它记下来:
typedef给变量类型定义一个别名。
typedef struct
{
int a;
int b;
}MY_TYPE;
这里把一个未命名结构直接取了一个叫MY_TYPE的别名, 这样如果你想定义结构的实例的时候就可以这样:
MY_TYPE tmp; - ASCⅡ码的高度是宽度的一倍,两个ASCⅡ就是一个汉字的宽高度
例如:在font.h文件中const unsigned char asc2_2412【95】【36】(一个ASCⅡ是高度为24,宽度为12),然而取模软件上是8个字节8个字节的取,所以所需字节数为:24/8=3,则一个字的数组包含数量个数为:3*12=36 - for(初始化语句;判断条件语句;控制条件语句){
循环体语句;
}
A:执行初始化语句
B:执行判断条件语句,看其结果是true还是false
如果是false,循环结束。
如果是true,继续执行。
C:执行循环体语句
D:执行控制条件语句
E:回到B继续 - 我不知道你们会不会遇到在keil中打中文字出现乱码情况,然后我网上找到了一个解决办法:
Edit - Configuration - 注意里面的定义输入密码的数组是u8 key[9]不能定义为u8 key[8],因为这是字符串数组,字符串数组最后一位是‘/0’,只是它并没有显示出来,要区分字符串数组与字符数组,你也可以看第二张图片这一行,打印出来的是字符串数组,可知key为字符串数组,
这一行才是字符数组,字符数组不用考虑‘/0’,中括号里面可以直接写位数就行。
六、总结
其实这还能加很多功能,如果说加上掉电不丢失功能,更改密码存储功能等,可以移植简易密码(一)里面的部分代码,稍加修改就能用,主要我想试一下TFTLCD触摸屏是怎么用的,这些是基础的代码,我建议初学者可以试着去看看触摸屏的底层程序,也不需要全都看懂,能大部分看明白就很不错了,最重要的是要看懂那几个基本的调用的函数,之前我还想硬刚底层程序,差点没让我就直接躺平不搞了,底层程序太难,我还是没有这种能力,所以对于像我这样的初学者就一定要学会调用基本函数了,大家如果有时间也可以弄弄ucgui,这个弄起人机交互界面来会很方便,不像这种画一个矩形虚拟键盘都有点繁琐,之前弄了四五天的样子,才弄到能移植ucgui到TFTLCD屏幕上可以实现显示,但还没移植成功利用ucgui来完成触摸,希望有大神弄好了,可以让我借鉴一下,万分感谢。
相关程序全部资料
程序代码提供:
链接:https://pan.baidu.com/s/1rlSgVnYvlpUHsYwSUBK4ig
提取码:like
取模软件提供:
链接:https://pan.baidu.com/s/1ybg_BqiWpOmG7V1rGfQmag
提取码:like