stm32LCD使用及触摸板
LCD显示名字
一、中文显示原理
已知字模是图形数据,而图形在计算机中是由一个个像素点组成的,所以字模实质是一个个像素点数据。为方便处理,我们把字模定义成方块形的像素点阵,且每个像素点只有0和1这两种状态(可以理解为单色图像数据),下图两个宽、高为16×16的像素点阵组成的两个汉字图形,其中的黑色像素点即为文字的笔迹。计算机要表示这样的图形,只需使用16×16个二进制数据位,每个数据位记录一个像素点的状态,把黑色像素点以“1”表示,无色像素点以“0”表示即可。这样的一个汉字图形,使用16×16/8=32个字节来就可以记录下来。
二、字模的生成
可以使用PCtoLCD2002生成字模
配置字模的解析顺序,解析顺序要和代码配套,否则会显示乱码。
生成后的字模数据如下,以“匠心柳职”为例:
匠(0) 心(1) 柳(2) 职(3) |
|
0x00,0x00,0xFE,0x3F,0x02,0x00,0x02,0x1C,0xE2,0x03,0x22,0x00,0x22,0x00,0xE2,0x3F, |
|
0x22,0x04,0x22,0x04,0x22,0x04,0x12,0x04,0x12,0x04,0x0A,0x04,0xFE,0x7F,0x00,0x00,/*"匠",0*/ |
|
0x00,0x00,0x40,0x00,0x80,0x00,0x00,0x01,0x00,0x01,0x20,0x00,0x20,0x10,0x24,0x20, |
|
0x24,0x20,0x24,0x40,0x22,0x40,0x22,0x48,0x21,0x08,0x20,0x08,0xC0,0x0F,0x00,0x00,/*"心",1*/ |
|
0x08,0x00,0x08,0x01,0xC8,0x78,0x48,0x4A,0x7F,0x4A,0x48,0x4A,0x4C,0x4A,0x5C,0x4A, |
|
0x6A,0x4A,0x4A,0x4B,0xC9,0x5A,0x48,0x2A,0x08,0x09,0x08,0x09,0x88,0x08,0x48,0x08,/*"柳",2*/ |
|
0x00,0x00,0xFF,0x00,0x24,0x3F,0x24,0x21,0x3C,0x21,0x24,0x21,0x24,0x21,0x3C,0x21, |
|
0x24,0x3F,0x24,0x21,0x74,0x00,0x2F,0x12,0x22,0x22,0x20,0x21,0x20,0x41,0xA0,0x40,/*"职",3*/ |
三、字模的使用方式
1、将“lcd_show_zn”模块添加到工程中
2. 创建对应字体
打开lcd_show_zn.c文件,添加如下内容,该内容表示一组名字为“ZN_Font16x16”的字体,这组字体里边一共有“匠心柳职”四个字,如果使用这组字体,只有存在字模数据的字才能正常显示。
编写完后,在头文件中添加:extern znsFONT ZN_Font16x16; 语句,这样就能调用ZN_Font16x16字体了
3.设置字体
使用“LCD_SetZNFont”函数设置字体,一般在main函数中while(1)之前调用一次即可,除非要更换字体则需重新调用。
LCD_SetZNFont(&ZN_Font16x16);
4. 使用字体
调用“LCD_DrawCharCN”函数显示中文字体,注意,必须是由字模数据的字才能显示,没有字模数据的字不会显示,所以想显示哪些中文字体,需要生成这些字模的字体并添加到代码中。
LCD_DrawCharCN(210,220,"匠心柳职"); //在坐标点(210,220)显示“匠心柳职”四个中文字体
5.中文和英文混合显示
LCD_DrawCharCN函数既可以显示中文也可以显示英文
LCD_DrawCharCN(210,220,"匠心柳职 Welcom");//显示 匠心柳职 Welcom
注意,其中的英文字符所使用的字体,由“LCD_SetFont()”函数来设置
一、字体文件的作用
在上一节显示中文时,需要先对要显示的中文字符进行取模,没取模的字符无法显示。如果我们设计一个系统,显示用户输入的文字,我们无法预测用户会输入什么文字,那只能将所有常用的中文字符全部取模,才能保证用户输入的文字能正常显示。
可以将所有常用字体取模并打包成一个文件,这个文件就是字体文件,想要显示哪个字符,就去字体文件里边查找其对应的字模数据,然后读取字模数据并通过显示屏显示,就完成了一个中文字符的显示。
计算机显示文字的原理也是如此,当选择某一种字体后,显示文字时就会去对应的字体文件中寻找文字的字模
Window系统的字体文件存放在C:\Windows\Fonts路径中
从上图中可以看到,同一个字,不同的字体显示的风格是不一样的。
二、生成字体文件
-
字模软件配置
-
设置字体
-
生成字体文件
生成的字体文件后缀名称为“.FON”
三、导入字体文件到keil工程中
显示文字的核心就是将文字的字模通过显示屏显示,所以程序在运行工程中就需要能读取字模,有两种方式可以实现,第1种是将字体文件作为程序的一部分,保存在片内flash中;第二种是将字体文件保存在SD卡或者其他存储介质中,再让芯片去读取SD卡内的字模数据。两种方法各有优缺点,第1种直接下载包含了字体文件的HEX文件即可使用,并且不会因为外部存储设备丢失等问题导致文字显示异常,缺点是芯片存储空间有限(STM32F429片内可用空间位1024KB),字体文件如果太大或者放入多个字体文件时,存储空间就不够了。
第2种优点是SD存储空间很大,可以放很多种字体文件,但是如果SD丢失或者连接失败,那么字体文件就不可用了,也就无法显示字体。
本文使用第1种方法,假设生成的字体文件名字为“GB2312_H2424.FON”,字体文件大小约为576KB,芯片存储空间位1024KB,是可以放得下的。
在keil中新建一个名字为“import_font.s”的文件,并加入到文件列表中。注意:该文件后缀是“.S”,然后在该文件中添加以下内容。
AREA |subr|,DATA,READONLY
EXPORT GB2312_H2424 ;以这个变量表示字库文件
;声明这个变量
GB2312_H2424
incbin .\GB2312_H2424.FON ;包含字库文件
END
程序说明及注意如下图,字体文件和“import_font.s”文件需要再同一个目录下
四、编写使用字体文件的函数
将以下模块添加到工程中
注意事项如下:
五、显示文字
直接调用LCD_DispString_EN_CH()函数即可显示中文字体
调用LCD_DisplayStringLineEx()函数还可以设置显示字体的大小(基于字体缩放实现的)。
注意:因为字体文件有500KB左右,这就导致HEX文件也会变大,所以每次下载程序的时候耗时会变长
触摸屏使用
一、触摸屏分类
触摸屏又称触控面板,它是一种把触摸位置转化成坐标数据的输入设备,根据触摸屏的检测原
理,主要分为电阻式触摸屏和电容式触摸屏。相对来说,电阻屏造价便宜,能适应较恶劣的环境,
但它只支持单点触控 (一次只能检测面板上的一个触摸位置),触摸时需要一定的压力,使用久了
容易造成表面磨损,影响寿命;而电容屏具有支持多点触控、检测精度高的特点,电容屏通过与
导电物体产生的电容效应来检测触摸动作,只能感应导电物体的触摸,湿度较大或屏幕表面有水
珠时会影响电容屏的检测效果。
电阻触摸屏
电容触摸屏
二、电阻触摸屏检测原理
电阻触摸屏主要由2层透明的电阻层组成,两个电阻涂层的两端分别引出 X-、 X+、 Y-、 Y+ 四个电极,当触摸屏被按下时,两个电阻层相互接触,从触点处把电阻层分为两个电阻,且由于电阻层均匀导电,两个电阻的大小与触点离两电极的距离成比例关系,利用这个特性,可通过以下过程来检测坐标,这也正是电阻触摸屏名称的由来
通过分别给X轴和Y轴的接口通电并检测电压,就能计算出触点的位置。
三、电容触摸屏检测原理
与电阻式触摸屏不同,电容式触摸屏不需要通过压力使触点变形,再通过触点处电压值来检测坐标,它的基本原理和前面定时器章节中介绍的电容按键类似,都是利用充电时间检测电容大小,从而通过检测出电容值的变化来获知触摸信号。
X 轴电极与 Y 轴电极在交叉处形成电容,即这两组电极构成了电容的两极,这样的结构覆盖了整个电容屏,每个电容单元在触摸屏中都有其特定的物理位置,即电容的位置就是它在触摸屏的XY 坐标。检测触摸的坐标时,第 1 条 X 轴的电极发出激励信号,而所有 Y 轴的电极同时接收信号,通过检测充电时间可检测出各个 Y 轴与第 1 条 X 轴相交的各个互电容的大小,各个 X 轴依次发出激励信号,重复上述步骤,即可得到整个触摸屏二维平面的所有电容大小。当手指接近时,会导致局部电容改变,根据得到的触摸屏电容量变化的二维数据表,可以得知每个触摸点的坐标,因此电容触摸屏支持多点触控。
一、驱动芯片
电容屏的坐标检测比电阻屏的要复杂,因而它也有专用芯片用于检测过程,下面我们以本章重点讲述的电容屏使用的触控芯片 GT9157 为例进行讲解,关于它的详细说明可从《gt91x编程指南》和《电容触控芯片 GT9157》文档了解。
GT9157的芯片引脚如下:
需要连接到MUC的一共4根线,IIC两根,INT、RSTB
二、MCU读取触摸坐标
MCU通过IIC接口和触摸屏进行通信,IIC和串口一样,是一种串行传输方式,IIC是一种总线传输方式,可以在上边同时连接多个设备,但是同一时间只能和一个设备通信。
因为IIC总线能连接多个设备的缘故,所以IIC读写时要先发送想要通信的设备的地址,双方建立连接后才能进一步通信。
1.添加IIC通信支持文件,该文件用来初始化MCU与触摸屏连接的引脚,并通过IIC发送或者读取数据
这个模块的接口很简单,如下图所示
使用时先调用I2C_Touch_Init()函数进行引脚等初始化,接着就可以使用发送或者读取函数进行数据交互了,至于要发送的数据是什么,由其他模块决定,bsp_i2c_touch模块被称为传输驱动文件,它只提供数据的收发,并不管传输的是什么数据,就好比两个人打电话,手机只是提供了信息交互的通路,至于要传输给对方什么信息,是由打电话的人决定的。
2.添加触摸屏驱动(就是打电话的人)
模块的接口如下图所示:
一、初始化触摸屏
在main函数中调用触摸屏初始化函数
GTP_Init_Panel();
二、获取触摸屏触摸状态
触摸屏被按下是随机的,当被按下时会产生一个中断信号,根据这个中断信号再去读取触摸屏,就能知道是哪个地方被按下了。这里不使用中断信号,使用轮训的方式,每10ms读取一次触摸状态。我们将触摸屏处理函数放在滴答定时器的中断函数中。
在“stm32f4xx_it.c”文件中的SysTick_Handler()函数中调用触摸屏处理函数,每10ms询问触摸屏是否有触摸操作
三、获取触摸操作及坐标
在main.c文件中重新定义以下两个函数,这两个函数在触摸驱动中进行了弱声明
//触摸屏被按下时该函数被调用,x,y是按下时的坐标值
void GTP_Press_Event(int32_t x,int32_t y)
{
uint8_t buf[100] = {0};
sprintf((char*)buf,"Press point:%d %d ",x,y); //构造字符串,显示按下时的坐标
LCD_DisplayStringLine(LINE(0),(uint8_t* )buf);
}
//触摸屏松开时该函数被调用,x,y是松开时的坐标值
void GTP_Release_Event(int32_t x,int32_t y)
{
uint8_t buf[100] = {0};
sprintf((char*)buf,"Release point:%d %d ",x,y);//构造字符串,显示松开时的坐标
LCD_DisplayStringLine(LINE(0),(uint8_t* )buf);
}
代码:
#include "stm32F4xx.h" |
|
#include "stm32f4xx_conf.h" |
|
#include "stdio.h" |
|
#include "led.h" |
|
#include "key.h" |
|
#include "delay.h" |
|
#include "uart.h" |
|
#include "adc.h" |
|
#include "bsp_lcd.h" |
|
#include "lcd_show_zn.h" |
|
#include "lcd_show_zn_font.h" |
|
#include "gt9xx.h" |
|
uint16_t select_index = 0; //表明当前选中哪一个菜单项 |
|
uint8_t beep_state = 0; //表示蜂鸣器的开关状态 0表示关闭 |
|
uint8_t led_state = 0; //表示LED的开关状态 0表示关闭 |
|
//编写中断服务函数 |
|
void EXTI0_IRQHandler() |
|
{ |
|
if(EXTI_GetITStatus(EXTI_Line0) != RESET) //证明触发了中断 |
|
{ |
|
EXTI_ClearITPendingBit(EXTI_Line0); |
|
} |
|
} |
|
void EXTI15_10_IRQHandler() |
|
{ |
|
if(EXTI_GetITStatus(EXTI_Line13) != RESET) //证明触发了中断 |
|
{ |
|
EXTI_ClearITPendingBit(EXTI_Line13); |
|
} |
|
} |
|
//触摸屏按下 |
|
void GTP_Press_Event(int32_t x,int32_t y) |
|
{ |
|
uint8_t buf[100] = {0}; |
|
sprintf((char*)buf,"Press point:%d %d ",x,y); |
|
LCD_DisplayStringLine(LINE(0),(uint8_t* )buf); |
|
|
|
|
|
if(x>100 && x<200 && y>100 && y<160) //判断按下坐标是不是在矩形框内 |
|
{ |
|
LCD_SetColors(LCD_COLOR_BLUE,LCD_COLOR_BLACK); //更改颜色 |
|
LCD_DrawFullRect(100,100,100,60); //画一个新的矩形框覆盖旧的矩形框 |
|
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK); //把颜色改回来 |
|
|
|
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_BLUE); |
|
LCD_DrawCharCN(110,110,"BEEP"); //在矩形框上写字 |
|
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK); |
|
} |
|
else |
|
{ |
|
//LCD_DrawFullRect(100,100,100,60); |
|
} |
|
} |
|
//松开触摸屏 |
|
void GTP_Release_Event(int32_t x,int32_t y) |
|
{ |
|
uint8_t buf[100] = {0}; |
|
sprintf((char*)buf,"Release point:%d %d ",x,y); |
|
LCD_DisplayStringLine(LINE(0),(uint8_t* )buf); |
|
|
|
if(x>100 && x<200 && y>100 && y<160) //判断松开时是不是在矩形框内,松开时在矩形框内才认为单击有效 |
|
{ |
|
if(beep_state == 0) |
|
{ |
|
GPIO_SetBits(GPIOI,GPIO_Pin_11);//开启蜂鸣器 |
|
beep_state = 1;//更新蜂鸣器的状态 |
|
} |
|
else |
|
{ |
|
GPIO_ResetBits(GPIOI,GPIO_Pin_11);//关闭蜂鸣器 |
|
beep_state = 0;//更新蜂鸣器的状态 |
|
} |
|
|
|
//画一个矩形框,作为按键 |
|
LCD_DrawFullRect(100,100,100,60); |
|
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE); |
|
LCD_DrawCharCN(110,110,"BEEP"); //在矩形框上写字 |
|
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK); |
|
|
|
} |
|
} |
|
int main(void) |
|
{ |
|
GPIO_InitTypeDef gpio_info; |
|
GTP_Init_Panel(); |
|
Delay_init(); |
|
UART_init(115200); |
|
LED_init(); |
|
|
|
//屏幕初始化 |
|
LCD_Init(); |
|
//屏幕显示层初始化 |
|
LCD_LayerInit(); |
|
//LTCD外设初始化 |
|
LTDC_Cmd(ENABLE); |
|
// |
|
|
|
/*把背景层刷黑色*/ |
|
//选定控制背景层 |
|
LCD_SetLayer(LCD_BACKGROUND_LAYER); |
|
//清除屏幕并用黑色填充 |
|
LCD_Clear(LCD_COLOR_BLACK); |
|
/*初始化后默认使用前景层*/ |
|
LCD_SetLayer(LCD_FOREGROUND_LAYER); |
|
/*默认设置不透明 ,该函数参数为不透明度,范围 0-0xff ,0为全透明,0xff为不透明*/ |
|
LCD_SetTransparency(0xFF); |
|
//清除屏幕并用黑色填充 |
|
LCD_Clear(LCD_COLOR_BLACK); |
|
|
|
#if 1 |
|
//PI11 蜂鸣器 |
|
//初始化GPIO-I时钟 |
|
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOI,ENABLE); |
|
|
|
gpio_info.GPIO_Mode = GPIO_Mode_OUT; |
|
gpio_info.GPIO_OType = GPIO_OType_PP; |
|
gpio_info.GPIO_Pin = GPIO_Pin_11; |
|
gpio_info.GPIO_PuPd = GPIO_PuPd_UP; |
|
gpio_info.GPIO_Speed = GPIO_Low_Speed; |
|
GPIO_Init(GPIOI,&gpio_info); |
|
#endif |
|
|
|
/*设置字体颜色及字体的背景颜色(此处的背景不是指LCD的背景层!注意区分)*/ |
|
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK); |
|
|
|
/*选择字体*/ |
|
LCD_SetFont(&Font16x24); |
|
|
|
LCD_SetZNFont(&ZN_Font24x24); |
|
|
|
|
|
//画一个矩形框,作为按键 |
|
LCD_DrawFullRect(100,100,100,60); |
|
LCD_SetColors(LCD_COLOR_BLACK,LCD_COLOR_WHITE); |
|
LCD_DrawCharCN(110,110,"BEEP"); //在矩形框上写字 |
|
LCD_SetColors(LCD_COLOR_WHITE,LCD_COLOR_BLACK); |
|
while(1) |
|
{ |
|
} |
|
} |
作者:youtiaonn