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

news2024/9/17 20:59:38

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

电路设计

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​ 字节。这个计算确保了无论字符的字号大小如何,都能正确计算出所需的字节数。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2038607.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

框架盛行,还记得原生JS如何获取表单数据吗?

你好同学&#xff0c;我是沐爸&#xff0c;欢迎点赞、收藏和关注&#xff01;个人知乎 在这个前端框架遍地开花的时代&#xff0c;同学们常常被React、Vue、Angular等现代JavaScript框架的便捷性和高效性所吸引。那么多年过去&#xff0c;你还记得原生JS是如何获取表单数据的吗…

论文分享|MLLMs中多种模态(图像/视频/音频/语音)的tokenizer梳理

本文旨在对任意模态输入-任意模态输出 (X2X) 的LLM的编解码方式进行简单梳理&#xff0c;同时总结一些代表性工作。 注&#xff1a;图像代表Image&#xff0c;视频代表Video&#xff08;不含声音&#xff09;&#xff0c;音频代表 Audio/Music&#xff0c;语音代表Speech 各种…

docker数据卷和资源控制

目录 数据卷 实现数据卷 宿主机和容器之间进行数据共享 容器与容器之间进行数据共享 容器互联 docker容器的资源控制 cpu 1.设置cpu资源控制&#xff08;比重&#xff09; 2. 设置cpu的资源占用比&#xff08;权重&#xff09; 3.设置容器绑定cpu 内存 1.内存限制 …

Docker搭建Minio容器

Docker搭建Minio容器 前言 在上一集我们介绍了分布式文件存储行业解决方案以及技术选型。最终我们决定选用Minio作为分布式文件存储。 那么这集我们就在Docker上搭建Minio容器即可。 Docker搭建Minio容器步骤 创建Minio文件目录 我们选择创建/minio/data目录 修改目录权…

系统编程 day11 进程(线程)3

fork函数的总结&#xff1a; 总结对进程学习之中的回收函数wait wait函数&#xff1a; 1.获取子进程的退出状态 2.回收资源------会让僵尸态的子进程销毁 注&#xff1a;1.wait函数本身是一个阻塞操作&#xff0c;会使调用者阻塞 2.父进程要获得子进程的退出状态 子进程&…

解决STM32G474单片机_HAL_UART_Transmit_IT()连续发送之问题

在使用STM32G474单片机的HAL库时&#xff0c;使用“在中断服务程序中发送数据”和“在中断程序中接收数据”&#xff0c;是一种很常用的方法&#xff0c;特别是RS485通讯中。首次使用&#xff0c;肯定会踩坑。要么出现第一个数据收不到&#xff0c;要么出现连续发送&#xff0c…

米联客-FPGA程序设计Verilog语法入门篇连载-02 Verilog语法_基本设计方法

软件版本&#xff1a;无 操作系统&#xff1a;WIN10 64bit 硬件平台&#xff1a;适用所有系列FPGA 板卡获取平台&#xff1a;https://milianke.tmall.com/ 登录“米联客”FPGA社区 http://www.uisrc.com 视频课程、答疑解惑&#xff01; 1概述 本节主要讲解Verilog的基本设…

【屏驱MCU】增加自定义分区指南

说明&#xff1a;本文主要给出基于该款 点屏 MCU。增加自定义分区指南 屏驱MCU系列文章 【屏显MCU】多媒体接口总结&#xff08;一&#xff09; 【DVP接口】0v5640的DVP接口设计分析&#xff08;硬件&#xff09; 【DVP接口】0v5640的DVP接口设计分析&#xff08;软件&#xff…

CCF-GESP8级考试—图论算法及综合应用(最小生成树)

&#x1f349;1 最小生成树的概念 1.1 连通图 &#x1f388; 连通图用于描述图中顶点之间是否存在路径相连。一个无向图中&#xff0c;如果从图中的任意一个顶点出发&#xff0c;都可以通过边的连接到达图中的任意其他顶点&#xff0c;则该图被称为连通图。 连通图的性质&…

为何众多卖家都选择入驻亚马逊VC?有什么优势?——WAYLI威利跨境助力商家

众多卖家选择入驻亚马逊VC&#xff08;Vendor Central&#xff09;&#xff0c;主要是因为VC平台为卖家提供了一系列显著的优势。VC使卖家与亚马逊建立直接供应关系&#xff0c;提升曝光率和销售机会。作为全球领先电商平台&#xff0c;亚马逊拥有庞大用户群和完善物流体系&…

C#窗体自定义快捷操作键的实现 - 开源研究系列文章

这次想到应用程序的窗体的快捷操作键的使用的问题。 上次发布过一个快捷键的例子(https://www.cnblogs.com/lzhdim/p/18342051)&#xff0c;区别在于它是操作系统全局注册的热键&#xff0c;如果其它应用程序注册了对应的热键&#xff0c;那就会失效。此例子是对某个窗体里的按…

AI驱动人才社区革新:智能化探索与实践

一、引言&#xff1a;AI赋能人才新生态 在21世纪的数字化浪潮中&#xff0c;人工智能&#xff08;AI&#xff09;技术以其强大的数据处理能力、学习优化算法及创新应用模式&#xff0c;正深刻地改变着各行各业的面貌&#xff0c;人才管理领域亦不例外。传统的人才社区&#xf…

yolo中的iou是什么意思

在YOLO&#xff08;You Only Look Once&#xff09;算法中&#xff0c;IoU 是“Intersection over Union”的缩写&#xff0c;中文可以理解为“交并比”。IoU 是一个用于衡量两个边界框&#xff08;bounding box&#xff09;重叠程度的指标。具体来说&#xff0c;IoU 是通过计算…

CUDA-MODE 第二课: PMPP 书的第1-3章

我的课程笔记&#xff0c;欢迎关注&#xff1a;https://github.com/BBuf/how-to-optim-algorithm-in-cuda/tree/master/cuda-mode 第二课: PMPP 书的第1-3章 这节课非常基础&#xff0c;讲的都是基本概念和初级的注意事项&#xff0c;有CUDA基础的朋友可以不用花时间看。 PMPP …

C#语言基础速成Day06

“心之官则思&#xff0c;思则得之&#xff0c;不思则不得也。” 目录 前言文章有误敬请斧正 不胜感恩&#xff01;||Day06 一、C#属性访问器、方法参数属性访问器&#xff08;Property Accessors&#xff09;方法参数&#xff08;Method Parameters&#xff09;综合示例 二、C…

小红书种草推广丨爆品层出不穷,品牌还能怎么「造新」?

当品牌已经被大众熟知&#xff0c;要如何在茫茫消费市场中脱颖而出&#xff0c;再度吸引用户的目光&#xff1f; 当品牌陷入增长困境&#xff0c;要如何再造爆品&#xff0c;打造增长的第二曲线&#xff0c;延长品牌的生命周期&#xff1f; …… 就这个大家关心的这些问题&…

三菱定位控制(一)

下面小编开始开始总结学习定位控制&#xff0c;以Q系列三菱PLC来展开学习&#xff0c;希望对读者或者小白有所帮助&#xff01;&#xff01;&#xff01; 一 三菱PLC定位模块 为什么需要学习定位模块&#xff08;三菱FXCPU能实现一个伺服电机的控制&#xff0c;多个要买定位模…

结构化输出及其使用方法

在 LLM 应用程序中构建稳健性和确定性 图片来自作者 欢迎来到雲闪世界。OpenAI最近宣布其最新的gpt-4o-2024–08–06模型支持结构化输出。与大型语言模型 (LLM) 相关的结构化输出并不是什么新鲜事——开发人员要么使用各种快速工程技术&#xff0c;要么使用第三方工具。 在本文…

异质性空间自回归模型 (HSAR)及 Stata 具体操作步骤

目录 一、引言 二、文献综述 三、理论原理 四、实证模型 五、稳健性检验 六、程序代码及解释 七、代码运行结果 一、引言 在空间计量经济学中&#xff0c;异质性空间自回归模型&#xff08;Heterogeneous Spatial Autoregressive Model&#xff0c;HSAR&#xff09;是一种…

深度优化Nginx负载均衡策略,携手Keepalived打造高可用服务架构新纪元

作者简介&#xff1a;我是团团儿&#xff0c;是一名专注于云计算领域的专业创作者&#xff0c;感谢大家的关注 座右铭&#xff1a; 云端筑梦&#xff0c;数据为翼&#xff0c;探索无限可能&#xff0c;引领云计算新纪元 个人主页&#xff1a;团儿.-CSDN博客 目录 前言&#…