触摸屏接口设置-洋桃百科

触摸屏接口设置-洋桃百科

电路设计

image

触摸屏的组成:

  • PCB板层:是电子设备中用于支撑和连接电子元件的基板。

  • 显示层:是LCD触摸屏的核心部分,负责生成视觉图像。它由以下部分组成:

    • 液晶层:包含液晶材料,通过改变电场来控制光线的通过,从而显示图像。
    • 偏振片:贴在液晶层的两侧,与液晶材料一起工作,控制光线的偏振状态,以实现图像的明暗和色彩变化。
    • 彩色滤光片:位于液晶层上方,包含红、绿、蓝三种颜色的滤光点,与液晶层配合产生全彩显示。
    • 背光单元:通常位于LCD面板的背面,提供均匀的光源,使图像可见。背光可以是LED、CCFL或其他类型的光源。
  • 触摸层:位于显示层的最上方,允许用户通过触摸与设备交互。

    触摸层的类型和结构因技术而异:

    • 电阻式触摸层:由两层导电材料组成,当用户触摸屏幕时,两层接触,形成电压变化,检测触摸位置。
    • 电容式触摸层:利用人体电场与电容的变化来检测触摸。这层通常由导电材料(如ITO,氧化铟锡)制成,分布在保护玻璃的内侧。
    • 触摸控制器:一个专用的集成电路或微控制器,处理触摸信号并转换为位置数据,然后发送给主控制系统。
    • 传感器矩阵:在电容式触摸屏中,传感器矩阵由多个水平和垂直传感器组成,以高精度检测触摸点。

image

对显示层原件的详细介绍:

  • 反光板:其作用是将光线反射到屏幕正面,增加可见度。

  • 棱镜板:棱镜板通过微小的棱镜结构来聚集光线,使光线更集中地射向观看者,这样可以提高屏幕的亮度和清晰度。

  • 黑色液晶板:是液晶屏的显示区域,液晶层是LCD屏幕的核心部分,由液晶材料和电极组成。液晶材料可以根据电场的变化改变其分子排列,从而控制光线的通过。

  • 背光灯:紧贴导光板,形成均匀白色背光。通过提供均匀的白色背景光来照亮屏幕,使得图像可见。通常使用LED作为背光灯,因为它们比传统的冷阴极荧光灯(CCFL)更节能、更薄,并且寿命更长。

    image

  • 导光板:导光板位于背光灯上方,其作用是将背光灯的光线均匀分布到整个屏幕。它通常由透明的塑料材料制成,并通过特殊的纹理或结构设计来散射和引导光线。​​

image

技术理论

image

image

触摸屏接口定义

显示部分

image

触摸部分

image

image

手指的位置数据是需要单片机主动询问触摸屏,才会得到数据,如果一直询问就会占用大量资源,为了解决占用资源问题,才设置了INT引脚。

在没有触摸的时候,INT引脚始终是高电平,有触摸的时候变成低电平。

需要把INT引脚接到单片机的EXTI接口:

image

image

背光

image

FSMC接口

image

TFT_LCD本身就是一个1152KB的存储器。

image

这里用LCD接口接到FSMC接口上面,操作FSMC就可以控制LCD,显示屏的显示区域就变成单片机的内部区域了。

image

通信协议

FSMC

FSMC简述

image

FSMC(Flexible Static Memory Controller)可以驱动LCD,主要是因为LCD的显存(GRAM)操作与外部静态存储器的操作类似,都是基于地址和数据的读写。FSMC能够模拟与LCD通信所需的接口时序,特别是对于使用8080或类似接口的LCD。以下是FSMC驱动LCD的基本步骤和原理:

  1. 地址映射:首先,需要将LCD的显存地址映射到STM32的地址空间中。这样,通过访问特定的地址,就可以直接与LCD的显存交互。

  2. 接口信号配置:FSMC需要配置相应的信号引脚,包括数据线(D0-D15)、地址线(A0-A25)、控制信号(如片选NE、读使能NOE、写使能NWE等)。

  3. 时序配置:FSMC需要根据LCD的数据手册配置正确的时序参数,包括地址建立时间、数据建立时间、总线转换时间等。这些参数确保数据在读写操作中能够正确同步。

  4. 模式选择:FSMC可以工作在不同的模式下,对于LCD,通常使用模式A或模式B。模式A适用于异步SRAM,模式B适用于异步NOR Flash,但也可以用于LCD,特别是当LCD使用与NOR Flash类似的8080接口时。

  5. 信号极性配置:需要根据LCD的要求配置信号的极性,例如,读使能和写使能的高电平或低电平有效。

  6. 初始化代码编写:编写初始化代码来配置FSMC的控制寄存器,包括FSMC_BCR(Bank Control Register)和FSMC_BTR(Bank Timing Register)等。

  7. 读写函数实现:实现读写函数,使用FSMC的地址映射和控制信号来向LCD发送命令和数据。

  8. 模拟8080接口:如果LCD使用8080接口,FSMC可以通过以下方式模拟此接口:

    • 使用片选信号(NE)作为LCD的CS(Chip Select)信号。
    • 使用读使能(NOE)和写使能(NWE)作为LCD的RD(Read)和WR(Write)信号。
    • 使用地址线(A0-A25)来发送命令和数据。
    • 使用数据线(D0-D15)进行数据传输。
  9. D/CX信号处理:对于8080接口的LCD,D/CX(Data/Command Select)信号用于区分当前传输的是命令还是数据。这可以通过将D/CX连接到FSMC的某个地址线(如A0)来实现,通过设置该地址线的电平来控制传输类型。

  10. 背光和复位控制:LCD的背光和复位通常由GPIO控制,需要额外配置GPIO引脚,并在初始化过程中控制这些引脚以正确设置LCD。

通过上述步骤,FSMC可以有效地驱动LCD,实现图形显示和其他视觉输出功能。在实际应用中,可能还需要考虑其他因素,如LCD的初始化过程、电源管理、中断处理等。

image

显示板掉电后就会丢失数据,所以属于SRAM存储器。

LCD屏接口类型:

image

image

image

FSMC参数设置

这里举例,物联网实战项目用到的:

image

因为bank1是PSRAM区域,所以选择bank1

image

image

image

设置FSMC为高电平,提高通讯的稳定性:

image

FSMC函数介绍

image

image

image

这里对应的:

image

所以FSMC的数据操作地址是算法是按上面的方法来算,洋桃电子视频里面讲的就是A18:

image

I2C接口

image

image

image

I2C读写地址。

RST

image

image

INT

image

image

image​​​

image

BL

  1. 第一种模式,只开关背光,就只用设置GPIO接口

image

image

image

image

  1. 第二种调节背光亮度,设置BL为TIM3_CH2,进入定时器设置PWM

    image

    image

    image

    image

  2. PWM相关函数:

    image

    image

    image

TFT触屏手册

LCD

  • 分辨率信息

    image

  • 色彩模式

    image

  • 接口

    image

  • 内部结构图

    image

  • 引脚定义

    给模块制造商看的

    image

    image

  • 接口设置

    选择驱动方式

    image

    image

  • 色彩方式

    因为我们是16bit数据,所以选择这个:D23-D16是灰色数据。

    image

    65K-color:只用发送一次16bit数据,就可以把一个像素点的色彩全部显示出来。

    262k-color:通过发送三次16bit数据,可以包含两个像素点的6位RGB数据。

    16.7M-color:通过发送三次16bit数据,可以包含两个像素点的8位RGB数据。

  • 显示模式方式

    image

TOUCH IC

image

  • 协议

    一般是I2C协议的话,就带有地址,给出七位地址的计算方法:image

    也有SPI协议方式

  • 寄存器表:

    image

    一般会读取ID编号,触摸状态寄存器、同一时间最多手指数量、触摸点位置寄存器

读取坐标就只有两步:

  1. 读出触摸点数量
  2. 根据数量,去读触摸点X,Y位置,有一个就只用读一个触摸点

触摸画图板开发

背光调节

  while (1)
  {
	  if(KEY_1()){
		__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,0);//设置占空比函数(参数3是PWM比值,范围0~ARR计数周期)
	  }
	  if(KEY_2()){
		__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,100);//设置占空比函数(参数3是PWM比值,范围0~ARR计数周期)
	  }
	  if(KEY_3()){
		__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,200);//设置占空比函数(参数3是PWM比值,范围0~ARR计数周期)
	  }
	  if(KEY_4()){
		__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,499);//设置占空比函数(参数3是PWM比值,范围0~ARR计数周期)
	  }
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }

驱动触摸IC

  • touch.h

    #ifndef __TOUCH_H__
    #define __TOUCH_H__
    
    #include "stm32f4xx_hal.h" //HAL库文件声明
    #include "main.h"
    #include "lcd.h"
    #include "stdlib.h"
    #include "math.h"
    #include "lcd.h"
    
    extern I2C_HandleTypeDef hi2c2;//声明I2C2的HAL库结构体
    #define TOUCH_GT9xxx_ADD	0x28	//GT9147/GT911芯片的I2C器件地址
    #define TOUCH_MAX  5    //电容屏支持的点数,固定为5点
    
    #define Module_Switch1		0x35 //模块配置1(其中低2位控制INT输出方式
    //INT输出方式(0x34上升沿触发,0x35下降沿触发,0x36低电平查询,0x37高电平查询)
    
    extern	uint8_t TOUCH_ID[5];//触摸芯片ID码(TOUCH_Init初始化后可使用,以ASCII码方式的“9147”)
    extern	uint16_t TOUCH_X[TOUCH_MAX];//当前触发时的X坐标
    extern	uint16_t TOUCH_Y[TOUCH_MAX];//当前触发时的Y坐标
    extern	uint8_t  TOUCH_STA;//触摸屏当前触发状态
    //TOUCH_STA低BIT0-BIT3位保存触发点数量,BIT6触摸状态(1触发,0放开),BIT7数据更新状态(1数据已更新,0数据未准备好)
    
    //扫描方向定义(原始方向是以竖屏左上角为基点X坐标=0,Y坐标=0)
    #define Portrait			0  //原始竖屏坐标(竖屏时的左上角向右是X坐标,向下是Y坐标)
    #define Landscape			1  //横屏坐标(竖屏时的右上角向下是X坐标,向左是Y坐标,即横屏)(横屏适用于洋桃2号开发板)
    #define Portrait_reversal	2  //竖屏坐标反转180度
    #define Landscape_reversal	3  //横屏坐标反转180度
    
    //-----------------【GT9147/GT911子地址表】-----------------------//
    //
    #define GT9xxx_COM	 	0X8040   //指令控制。操作内容如下:
    //【GT9xxx_COM说明】
    //0:读坐标状态 //1、2:差值原始值 //3:基准更新 //4:基准校准//5:关屏 //6:进入充电模式 7:退出充电模式8:切换手势唤醒固件
    //0x20:进入从机接近检测模式 //0x21:进入主机接近检测模式 //0x22:进入数据传输模式 //0x23:进入主机传输模式//0x28:退出从机检测模式
    //0x29:退出主机接近检测模式 //0x2A:退出数据传输模式//0xAA:ESD 保护机制使用,由驱动定时写入0xAA 并定时读取检查 //其余值无效
    
    #define GT9xxx_Ver 		0X8047   	//配置文件版本号
    #define GT9xxx_CHKSUM 	0X80FF   	//配置信息校验(0x8047到0x80FE之字节和的补码)
    #define GT9xxx_PID 		0X8140   	//产品ID(从0X8140~0X8143)
    
    #define GT9xxx_STA	 	0X814E   	//触摸屏状态总标志位
    #define GT9xxx_TP1 		0X8150  	//GT9147/GT911芯片第1个触摸点坐标地址
    #define GT9xxx_TP2 		0X8158  	//GT9147/GT911芯片第2个触摸点坐标地址
    #define GT9xxx_TP3 		0X8160		//GT9147/GT911芯片第3个触摸点坐标地址
    #define GT9xxx_TP4 		0X8168		//GT9147/GT911芯片第4个触摸点坐标地址
    #define GT9xxx_TP5 		0X8170		//GT9147/GT911芯片第5个触摸点坐标地址
    //GT9147数据手册有错误,第1个触摸点坐标地址是0X8150(以此类推)
    
    void GT9xxx_Write_Config(uint8_t save);
    uint8_t TOUCH_Init(void);//触摸屏初始化(驱动芯片GT9xxx)(返回1成功,0失败)
    void TOUCH_Read(uint8_t dir);//读取触摸屏当前状态,有触发则改变TOUCH_STA,读出5个触发点坐标在TOUCH_X和TOUCH_Y数组中
    
    #endif
    
    /*********************************************************************************************
     * 洋桃电子 www.doyoung.net
     * 部分程序代码复制自网络开源资料 如有侵权请联系我们处理
     * 洋桃电子原创程序代码部分均未声明版权 可自由复制使用 我们不对代码做任何担保
    *********************************************************************************************/
    
  • touch.c

    /*
     * oled.c
     *
     *  Created on: Jun 11, 2022
     *      Author: Administrator
     */
    
    /*
    //杜洋工作室出品
    //洋桃系列开发板应用程序
    //关注微信公众号:洋桃电子
    //洋桃开发板资料下载 www.DoYoung.net
    //即可免费看所有教学视频,下载技术资料,技术疑难提问
    //更多内容尽在 杜洋工作室主页 www.doyoung.net
    */
    
    #include "touch.h" 
    
    //本驱动程序可支持GT9147和GT911两款芯片(其电路与寄存器地址基本兼容)
    
    uint8_t TOUCH_ID[5]={0};//触摸芯片ID码(TOUCH_Init初始化后可使用,以ASCII码方式的“9147”或“911”)
    uint16_t TOUCH_X[TOUCH_MAX];//当前触发时的X坐标
    uint16_t TOUCH_Y[TOUCH_MAX];//当前触发时的Y坐标
    uint8_t  TOUCH_STA;//触摸屏当前触发状态
    
    const uint16_t GT9xxx_TP_DAT[6]={GT9xxx_TP1,GT9xxx_TP2,GT9xxx_TP3,GT9xxx_TP4,GT9xxx_TP5};//5个触摸点坐标的I2C子地址(包括GT911和GT9xxx地址有错位)
    
    const uint8_t GT9xxx_Config[]={//GT9xxx配置数据(从设置寄存器0x8047地址开始写入,详见《GT9147编程指南》)
    0X60,0XE0,0X01,0X20,0X03,0X05,Module_Switch1,0X00,0X02,0X08,0X1E,0X08,0X50,0X3C,0X0F,0X05,0X00,0X00,0XFF,0X67,0X50,
    0X00,0X00,0X18,0X1A,0X1E,0X14,0X89,0X28,0X0A,0X30,0X2E,0XBB,0X0A,0X03,0X00,0X00,0X02,0X33,0X1D,0X00,0X00,
    0X00,0X00,0X00,0X00,0X00,0X32,0X00,0X00,0X2A,0X1C,0X5A,0X94,0XC5,0X02,0X07,0X00,0X00,0X00,0XB5,0X1F,0X00,
    0X90,0X28,0X00,0X77,0X32,0X00,0X62,0X3F,0X00,0X52,0X50,0X00,0X52,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X0F,0X0F,0X03,0X06,0X10,0X42,
    0XF8,0X0F,0X14,0X00,0X00,0X00,0X00,0X1A,0X18,0X16,0X14,0X12,0X10,0X0E,0X0C,0X0A,0X08,0X00,0X00,0X00,0X00,
    0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X29,0X28,0X24,0X22,0X20,
    0X1F,0X1E,0X1D,0X0E,0X0C,0X0A,0X08,0X06,0X05,0X04,0X02,0X00,0XFF,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
    0X00,0X00,0X00,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF,0XFF
    };
    
    void GT9xxx_Write_Config(uint8_t save){//发送GT9xxx_Config配置数据(初始化时使用)(参数:1保存数据到GT9xxx芯片,0不保存)
    	uint8_t buf[2];
    	uint8_t i=0;
    	buf[0]=0;
    	buf[1]=save;//控制是否将配置数据保存到GT9147/GT911芯片中(0不保存,1保存)
    	for(i=0;i<sizeof(GT9xxx_Config);i++) buf[0]+=GT9xxx_Config[i];//求得配置数据的校验和
        buf[0]=(~buf[0])+1;
    	HAL_I2C_Mem_Write(&hi2c2,TOUCH_GT9xxx_ADD,GT9xxx_COM,I2C_MEMADD_SIZE_16BIT,(uint8_t*)GT9xxx_Config,sizeof(GT9xxx_Config),1000);//发送配置数据
    	HAL_I2C_Mem_Write(&hi2c2,TOUCH_GT9xxx_ADD,GT9xxx_CHKSUM,I2C_MEMADD_SIZE_16BIT,buf,2,1000);//发送校验和结果
    }
    
    uint8_t TOUCH_Init(void){//触摸屏初始化(驱动芯片GT9xxx)(返回1成功,0失败)
    	uint8_t t;
    	GPIO_InitTypeDef GPIO_InitStruct = {0};
    	HAL_GPIO_WritePin(TOUTH_RST_GPIO_Port,TOUTH_RST_Pin, GPIO_PIN_RESET);//向RST复位接口输出10毫秒低电平脉冲
    	HAL_Delay(5);
    	HAL_GPIO_WritePin(TOUTH_RST_GPIO_Port,TOUTH_RST_Pin, GPIO_PIN_SET);//
    	HAL_Delay(10);
    	//器件地址设置完成后,将INT设置为高阻输入
    	GPIO_InitStruct.Pin = TOUCH_INT_Pin;
    	GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    	GPIO_InitStruct.Pull = GPIO_NOPULL;
    	HAL_GPIO_Init(GPIOG, &GPIO_InitStruct);//写入IO设置
    	HAL_Delay(100);
    	TOUCH_STA = HAL_I2C_Mem_Read(&hi2c2,TOUCH_GT9xxx_ADD,GT9xxx_PID,I2C_MEMADD_SIZE_16BIT,TOUCH_ID,4,1000);//读出产品ID
    	if(strcmp((char*)TOUCH_ID,"9147")==0 || strcmp((char*)TOUCH_ID,"911")==0){//判断ID是"9147"或“911”(ASCII码方式的ID)
    		t=0X02;
    		HAL_I2C_Mem_Write(&hi2c2,TOUCH_GT9xxx_ADD,GT9xxx_COM,I2C_MEMADD_SIZE_16BIT,&t,1,1000);//写指令控制:复位芯片
    		HAL_I2C_Mem_Read(&hi2c2,TOUCH_GT9xxx_ADD,GT9xxx_Ver,I2C_MEMADD_SIZE_16BIT,&t,1,1000); //读取配置文件版本号
    		if(t<0X60)GT9xxx_Write_Config(1);//判断版本号过小时//写入配置文件(参数:1保存数据到GT9xxx芯片,0不保存)
    		HAL_Delay(10);//延时
    		t=0;//GT9xxx_COM赋值0:读坐标状态
    		HAL_I2C_Mem_Write(&hi2c2,TOUCH_GT9xxx_ADD,GT9xxx_COM,I2C_MEMADD_SIZE_16BIT,&t,1,1000);//写入指令控制,进入读坐标的工作状态
    		return 1;//返回成功
    	}
    	return 0;//返回失败
    }
    
    void TOUCH_Read(uint8_t dir){//读取触摸屏状态(有触发则改变TOUCH_STA,读出5个触发点坐标在TOUCH_X[]和TOUCH_Y[]数组中)
    	//TOUCH_STA低BIT0-BIT3位保存触发点数量,BIT4触摸状态(1触发,0放开),BIT7数据更新状态(1数据已更新,0数据未准备好)
    	//参数:竖屏或横屏的方向(详见touch.h文件)
    	uint8_t buf[4];
    	uint8_t i=0,STA=0;
    	if(HAL_GPIO_ReadPin(GPIOG,TOUCH_INT_Pin)==GPIO_PIN_RESET){//读INT接口的电平(必须将Module_Switch1设置为0x35下降沿触发)
    		HAL_I2C_Mem_Read(&hi2c2,TOUCH_GT9xxx_ADD,GT9xxx_STA,I2C_MEMADD_SIZE_16BIT,&STA,1,1000); //读取触摸屏状态总标志位
    		if((STA&0X80) && ((STA&0x0F)<=TOUCH_MAX)){//判断BIT7的就绪标志位是不是1,同时BIT0-3的触发点数量要小于最大点数
    			TOUCH_STA = STA;//将总标志位中的数据放入TOUCH_STA全局标志位(可在主函数中使用TOUCH_STA)
    			for(i=0;i<5;i++){//写入坐标之前先清0
    				TOUCH_X[i]=0;TOUCH_Y[i]=0;//寄存器清0
    			}
    			for(i=0;i<(STA&0x0F);i++){//循环读出5个坐标值
    				HAL_I2C_Mem_Read(&hi2c2,TOUCH_GT9xxx_ADD,GT9xxx_TP_DAT[i],I2C_MEMADD_SIZE_16BIT,buf,4,1000); //读取XY坐标值
    				if(dir==Portrait){//判断是横屏还是竖屏(0是竖屏,1是横屏)
    					TOUCH_X[i]=((uint16_t)buf[1]<<8)+buf[0];//写入坐标值到全局X坐标数组(竖屏坐标写入)
    					TOUCH_Y[i]=((uint16_t)buf[3]<<8)+buf[2];//写入坐标值到全局Y坐标数组(竖屏坐标写入)
    				}else if(dir==Landscape){
    					TOUCH_Y[i]=LCD_Width-(((uint16_t)buf[1]<<8)+buf[0]);//写入坐标值到全局X坐标数组(横屏坐标写入)
    					TOUCH_X[i]=((uint16_t)buf[3]<<8)+buf[2];//写入坐标值到全局Y坐标数组(横屏坐标写入)
    				}else if(dir==Portrait_reversal){
    					TOUCH_X[i]=LCD_Width-(((uint16_t)buf[1]<<8)+buf[0]);//写入坐标值到全局X坐标数组(竖屏坐标写入)
    					TOUCH_Y[i]=LCD_Height-(((uint16_t)buf[3]<<8)+buf[2]);//写入坐标值到全局Y坐标数组(竖屏坐标写入)
    				}else if(dir==Landscape_reversal){
    					TOUCH_Y[i]=((uint16_t)buf[1]<<8)+buf[0];//写入坐标值到全局X坐标数组(横屏坐标写入)
    					TOUCH_X[i]=LCD_Height-(((uint16_t)buf[3]<<8)+buf[2]);//写入坐标值到全局Y坐标数组(横屏坐标写入)
    				}
    			}
    			i=0;
    			HAL_I2C_Mem_Write(&hi2c2,TOUCH_GT9xxx_ADD,GT9xxx_STA,I2C_MEMADD_SIZE_16BIT,&i,1,1000);//清除触发标志
    		}
    	}
    }
    
    /*********************************************************************************************
     * 洋桃电子 www.doyoung.net
     * 部分程序代码复制自网络开源资料 如有侵权请联系我们处理
     * 洋桃电子原创程序代码部分均未声明版权 可自由复制使用 我们不对代码做任何担保
    *********************************************************************************************/
    
  • main.c:不同手指数量刷新不同颜色

      TOUCH_Init();//触摸显示部分初始化函数
      /* USER CODE END 2 */
    
      /* Infinite loop */
      /* USER CODE BEGIN WHILE */
      while (1)
      {
    	TOUCH_Read(Landscape);//读出手指数量和X、Y轴坐标(参数是屏幕方向Portrait纵向,Landscape横向)
    
    	if(TOUCH_STA&0x90){//判断有没有触摸屏触发
    		if((TOUCH_STA&0x0F) == 1)LCD_CLEAR(White);判断触摸手指数量,清屏(单色背景)
    		else if((TOUCH_STA&0x0F) == 2)LCD_CLEAR(Purple);
    		else if((TOUCH_STA&0x0F) == 3)LCD_CLEAR(Red);
    		else if((TOUCH_STA&0x0F) == 4)LCD_CLEAR(Green);
    		else if((TOUCH_STA&0x0F) == 5)LCD_CLEAR(Yellow);
    		else LCD_CLEAR(Blue);//清屏(单色背景)
    	}
    	TOUCH_STA=0;//标志位清0
        /* USER CODE END WHILE */
        MX_USB_HOST_Process();
    
        /* USER CODE BEGIN 3 */
      }
    

位图和矢量图

位图:

  • 每个像素点需要占用空间
  • 图片是由许多个不同颜色和亮度的像素点拼凑而成

矢量图:

  • 用的几何数学原理,在屏幕上用点和线绘制在特定的数学公式下实时绘制出图形

  • 矢量图中的每个数据都是由数学公式产生的

  • 只需要存放数学公式,在应用中传入公式参数就可以运用了

    位图,20kb:

    image

    矢量图:

    image

    只占用十个字节

关于矢量图函数的解读:

NT35510的LCD函数详解01(洋桃电子-触摸屏开发者笔记)

NT35510的LCD函数详解02(洋桃电子-触摸屏开发者笔记)

图片取模

image

image

imageimage

image

void LCD_DISPLAY_BMP(uint16_t sx,uint16_t sy,uint16_t *COLOR){//绘制BMP位图(参数:左上角X,左上角Y坐标,BMP位图数组)
	uint16_t i,j,h,w;
	w= COLOR[1];//得出绘图宽度(通过Image2lcd软件生成数组时带有的图片头数据得到)
	h= COLOR[2];//得出绘图高度
	for(i=0;i<h;i++){//循环写入行数(高度h)
		LCD_Write_Cursor(sx,sy+i);//设置光标位置
		LCD_Write_COM(SET_GRAM);//开始写入GRAM
		for(j=0;j<w;j++)//循环写入列出(宽度w)
			HAL_SRAM_Write_16b(&hsram1,LCD_DAT,&COLOR[i*w+j+4],1);//向LCD写16位数据(句柄,指令COM/数据DAT,存放寄存器,数量)
	}
}

16bit,就是一次性读取两个字节,所以COLOR[0]是读取的scan和gray值。COLOR[3]是颜色模式,COLOR[4]才是颜色数,所以从这里开始。

文字显示

单个字符显示

image

单个字符显示函数可以显示单个字符,传入‘0’,带引号的就是传入ASCII值。

image

void LCD_DISPLAY_ASCII(uint16_t x,uint16_t y,uint8_t adcii,uint8_t size,uint8_t overlay){//在屏上显示一个字符
	//参数:X坐标,Y坐标,字符内容,字号(12/16/24/32/48),叠加/覆盖(1叠加,0覆盖)
    uint8_t b,r;//b存储当前处理的字节数据,r用作内部循环的索引,表示在当前字节中处理的行
	uint16_t t,z=y;//t用作外部循环的索引,表示字符数据中的字节位置,z用于存储字符显示的起始Y坐标,用于在一行字符绘制完毕后重置Y坐标
	uint16_t csize=(size/8)*(size/2);//得出一个字符所用到的字节数量
	adcii=adcii-' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
	for(t=0;t<csize;t++){
		if(size==12)b=ASCII_1206[adcii][t]; 	 	//调用1206字体
		else if(size==16)b=ASCII_1608[adcii][t];	//调用1608字体
		else if(size==24)b=ASCII_2412[adcii][t];	//调用2412字体
		else if(size==32)b=ASCII_3216[adcii][t];	//调用3216字体
		else if(size==48)b=ASCII_4824[adcii][t];	//调用4824字体
		else b=ASCII_4824[adcii][t];	//如输入字体值错误,则调用4824字体
		for(r=0;r<8;r++){
			if(b&0x80)LCD_Vector_Point2(x,y,ForeColor);
			else if(overlay==0)LCD_Vector_Point2(x,y,BackColor);
			b<<=1;y++;
			if(y>=SET_Height)return;//判断Y方向超出显示区域
			if((y-z)==size){
				y=z;x++;
				if(x>=SET_Width)return;//判断X方向超出显示区域
				break;
			}
		}
	}
}
  1. x​ 和 y​:这两个 uint16_t​ 类型的变量分别代表字符在LCD屏幕上显示的X(水平)和Y(垂直)坐标。
  2. adcii​:这是一个 uint8_t​ 类型的变量,表示要显示的ASCII字符。字符是通过减去空格字符的ASCII码(即 ' '​)来获取字库中的偏移值。
  3. size​:这也是一个 uint8_t​ 类型的变量,表示字符的字号大小,常见的大小有12、16、24、32和48。字号大小决定了字符的像素高度和宽度。
  4. overlay​:一个 uint8_t​ 类型的变量,用于决定字符的显示方式。值为1时表示叠加(overlay),即在现有像素上显示字符;值为0时表示覆盖(overwrite),即用字符覆盖现有像素。
  5. b​:这是一个 uint8_t​ 类型的局部变量,用于存储当前处理的字节数据,即字符的某一部分。
  6. r​:这是另一个 uint8_t​ 类型的局部变量,用作内部循环的索引,表示在当前字节中处理的行。
  7. t​:uint16_t​ 类型的局部变量,用作外部循环的索引,表示字符数据中的字节位置。
  8. z​:uint16_t​ 类型的局部变量,用于存储字符显示的起始Y坐标,用于在一行字符绘制完毕后重置Y坐标。
  9. csize​:uint16_t​ 类型的局部变量,表示一个字符所用到的字节数量,计算公式为 (size/8)*(size/2)​,这个值取决于字号大小。

在ASCII字符字库中,每个字符通常都是等宽的,这意味着每个字符占用的像素宽度是相同的。在这段代码中,size​ 变量代表了字符的字号大小,也就是字符的像素高度。由于字符是等宽的,字符的宽度通常是高度的一半(对于常见的字号大小,如12、16、24、32等)。

这里的 size/2​ 实际上是用来计算每个字符的宽度(以像素为单位)。例如,如果字符大小是16x16像素,那么每个字符的高度是16像素,宽度则是8像素。因此,size/2​ 就是用来得到这个宽度值。

然后,csize​ 的计算公式 (size/8)*(size/2)​ 表示的是:

  • size/8​ 计算出每个字符一行所需的字节数。因为每个字节包含8位,所以如果字符是8像素宽,那么一行字符所需的字节数就是 size/8​。
  • (size/2)​ 计算出字符的行数,也就是字符的高度(以字节为单位)。

将这两个值相乘,就得到了每个字符所需的总字节数。这个公式适用于等宽字体,其中每个字符的宽度是固定的,高度与字号大小成正比。

例如,对于16x16像素的字符:

  • 宽度(以字节为单位):16 / 8 = 2​ 字节(因为8像素宽,每像素1位,所以是2字节)。
  • 高度(以字节为单位):16 / 2 = 8​ 行(因为16像素高,宽度是8像素,所以是8行)。

所以,每个16x16像素的字符所需的字节数是 2 * 8 = 16​ 字节。这个计算确保了无论字符的字号大小如何,都能正确计算出所需的字节数。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值