4寸电阻LCD标准库改为HAL库

一,屏幕概述

最近在学习lvgl,发现正点的屏幕实在是有点贵,就买了这块屏幕,但发现商家提供的源码是标准库的,这对于一个HAL库的使用者是一件十分头疼的事情,这里笔者给想省钱的读者提供一个HAL驱动的源码。

lcd驱动芯片:ST7796S

触摸芯片:XPT2046

二,修改后源码 

lcd.h

#ifndef __LCD_H
#define __LCD_H	

/* 头文件 */
#include "main.h"	 
#include "stdlib.h"
#include "spi.h"

/* 变量别名 */
typedef int32_t  s32;
typedef int16_t s16;
typedef int8_t  s8;
typedef const int32_t sc32;  /*!< Read Only */
typedef const int16_t sc16;  /*!< Read Only */
typedef const int8_t sc8;   /*!< Read Only */
typedef __IO int32_t  vs32;
typedef __IO int16_t  vs16;
typedef __IO int8_t   vs8;
typedef __I int32_t vsc32;  /*!< Read Only */
typedef __I int16_t vsc16;  /*!< Read Only */
typedef __I int8_t vsc8;   /*!< Read Only */
typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;
typedef const uint32_t uc32;  /*!< Read Only */
typedef const uint16_t uc16;  /*!< Read Only */
typedef const uint8_t uc8;   /*!< Read Only */
typedef __IO uint32_t  vu32;
typedef __IO uint16_t vu16;
typedef __IO uint8_t  vu8;
typedef __I uint32_t vuc32;  /*!< Read Only */
typedef __I uint16_t vuc16;  /*!< Read Only */
typedef __I uint8_t vuc8;   /*!< Read Only */

/* LCD重要参数集 */
typedef struct  
{	
	//LCD 宽度
	u16 width;
	//LCD 高度
	u16 height;
	//LCD ID
	u16 id;
	//横屏还是竖屏控制:0竖屏 1横屏
	u8  dir;	
	//开始写gram指令
	u16	 wramcmd;
	//设置x坐标指令
	u16  setxcmd;
	//设置y坐标指令
	u16  setycmd;			 
}_lcd_dev; 	

/* 管理LCD重要参数结构体外部声明 */
extern _lcd_dev lcddev;	



/***********************************用户配置区*******************************************/

//定义液晶屏顺时针旋转方向 	0为0度旋转,1为90度旋转,2为180度旋转,3为270度旋转
#define USE_HORIZONTAL  	 1  
//定义LCD的尺寸
#define LCD_W 320
#define LCD_H 480
//笔颜色变量外部声明	   
extern u16  POINT_COLOR;
//背景颜色变量外部声明
extern u16  BACK_COLOR; 

/***********************************用户配置区结*****************************************/




/***********************************移植需要更改选项开始**********************************/

//GPIO组类型
#define GPIO_TYPE  	GPIOB 
//背光控制引脚管脚类型随便,还可以接PWM调节亮度        PC13
#define LED      		GPIO_PIN_13
//片选引脚,管脚类型必需为GPIO_TYPE  				   PB4
#define LCD_CS   		GPIO_PIN_4
//寄存器/数据选择引脚,管脚类型必需为GPIO_TYPE 	   PB8
#define LCD_RS   		GPIO_PIN_8 
//复位引脚,管脚类型必需为GPIO_TYPE 				   PB6
#define LCD_RST  		GPIO_PIN_6        

/***********************************移植需要更改选项结束**********************************/
 
 
 
 
/***********************************GPIO输出函数定义开始**********************************/

//GPIO置位(拉高)
#define	LCD_CS_SET  GPIO_TYPE->BSRR=LCD_CS    
#define	LCD_RS_SET	GPIO_TYPE->BSRR=LCD_RS    
#define	LCD_RST_SET	GPIO_TYPE->BSRR=LCD_RST  

//GPIO复位(拉低)							    
#define	LCD_CS_CLR  GPIO_TYPE->BSRR=(LCD_CS<<16)   
#define	LCD_RS_CLR	GPIO_TYPE->BSRR=(LCD_RS<<16) 		
#define	LCD_RST_CLR	GPIO_TYPE->BSRR=(LCD_RST<<16)   

/***********************************GPIO输出函数定义结束**********************************/




/***********************************颜色定义开始*****************************************/

//画笔颜色
#define WHITE       0xFFFF
#define BLACK      	0x0000	  
#define BLUE       	0x001F  
#define BRED        0XF81F
#define GRED 		0XFFE0
#define GBLUE		0X07FF
#define RED         0xF800
#define MAGENTA     0xF81F
#define GREEN       0x07E0
#define CYAN        0x7FFF
#define YELLOW      0xFFE0
//棕色
#define BROWN 		0XBC40
//棕红色
#define BRRED 		0XFC07
//灰色
#define GRAY  		0X8430 
//深蓝色
#define DARKBLUE    0X01CF	
//浅蓝色  
#define LIGHTBLUE   0X7D7C
//灰蓝色
#define GRAYBLUE    0X5458 
//浅绿色
#define LIGHTGREEN  0X841F 
//浅灰色
#define LIGHTGRAY   0XEF5B 
//浅灰色,窗体背景色
#define LGRAY 		0XC618 
//浅灰蓝色
#define LGRAYBLUE   0XA651
//浅棕蓝色
#define LBBLUE      0X2B12 

/***********************************颜色定义结束****************************************/




/***********************************函数声明开始*****************************************/

/*
********************************************LCD上层函数
*/

/* 初始化函数 */
void LCD_Init(void);

/* 清屏函数 */
void LCD_Clear(u16 Color);

/* 坐标设置函数 */
void LCD_SetCursor(u16 Xpos, u16 Ypos);

/* 画点函数 */
void LCD_DrawPoint(u16 x,u16 y);

/* 设置显示窗口函数 */
void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd);

/* 屏幕方向设置函数 */
void LCD_direction(u8 direction );

/* 块填充函数 */
void LCD_Color_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16* color);

/* 画十字函数 */
void lcd_draw_cross( u16 x, u16 y );


/*
********************************************LCD基本驱动函数
*/

void LCD_WR_REG(u8 data);
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue);
void LCD_WR_DATA(u8 data);
void LCD_WriteRAM_Prepare(void);
void Lcd_WriteData_16Bit(u16 Data);

/***********************************函数声明结束*****************************************/




#endif  

lcd.c

/* 我的LCD头文件 */
#include "lcd.h"
	   
/* 初始化LCD参数结构体 */
_lcd_dev lcddev;
/* 设置画笔颜色 */
u16 POINT_COLOR = RED;
/* 设置背景颜色 */
u16 BACK_COLOR = 0xFFFF; 


/*
********************************************LCD基本驱动函数
*/

/*
 * 名字:LCD_WR_REG
 * 功能:将8位命令写入LCD屏幕
 * 参数data:要写入的命令值
 * 返回值:无
*/
void LCD_WR_REG(u8 data)
{ 
   u8 d[1];
   d[0] = data;
   LCD_CS_CLR;     
   LCD_RS_CLR;
   HAL_SPI_Transmit( &hspi2, d, 1, 50 );
   LCD_CS_SET;	
}


/*
 * 名字:LCD_WR_DATA
 * 功能:将8位数据写入LCD屏幕
 * 参数data:要写入的数据值
 * 返回值:无
*/
void LCD_WR_DATA(u8 data)
{
   u8 d[1];
   d[0] = data;
   LCD_CS_CLR;
   LCD_RS_SET;
   HAL_SPI_Transmit( &hspi2, d, 1, 50 );
   LCD_CS_SET;
}


/*
 * 名字:LCD_WriteReg
 * 功能:将数据写入寄存器
 * 参数LCD_Reg:寄存器地址
 * 参数LCD_RegValue:要写入的数据
 * 返回值:无
*/
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{	
	LCD_WR_REG(LCD_Reg);  
	LCD_WR_DATA(LCD_RegValue);	    		 
}	   


/*
 * 名字LCD_WriteRAM_Prepare
 * 功能:写GRAM前的准备函数
 * 参数:无
 * 返回值:无
*/	 
void LCD_WriteRAM_Prepare(void)
{
	LCD_WR_REG(lcddev.wramcmd);
}	 


/*
 * 名字:Lcd_WriteData_16Bit
 * 功能:将16位数据写入LCD屏幕
 * 参数Data:要写入的数据
 * 返回值:无
*/	 
void Lcd_WriteData_16Bit(u16 Data)
{	 
	 u8 buf[2];
	 buf[0] = Data>>8;
	 buf[1] = Data;
	 LCD_CS_CLR;
	 LCD_RS_SET;
     HAL_SPI_Transmit( &hspi2, buf, 2, 50 );
	 LCD_CS_SET;
}


/*
********************************************LCD上层函数
*/


/*
 * 名字:画点函数
 * 功能:在指定位置写入像素数据
 * 参数x:像素的x坐标
 * 参数y:像素的y坐标
 * 返回值:无
*/	
void LCD_DrawPoint(u16 x,u16 y)
{
	//设置光标位置 
	LCD_SetCursor(x,y);
	Lcd_WriteData_16Bit(POINT_COLOR); 
}


/*
 * 名字:清屏函数
 * 功能:全屏填充LCD屏幕
 * 参数color:填充颜色
 * 返回值:无
*/	
void LCD_Clear(u16 Color)
{
    unsigned int i,m;  
	LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);   
	LCD_CS_CLR;
	LCD_RS_SET;
	for(i=0;i<lcddev.height;i++)
	{
        for(m=0;m<lcddev.width;m++)
        {	
			Lcd_WriteData_16Bit(Color);
		}
	}
	LCD_CS_SET;
} 	


/*
 * 名字:复位函数 
 * 功能:复位lcd
 * 参数:无
 * 返回值:无
*/	
void LCD_RESET(void)
{
	LCD_RST_CLR;
	HAL_Delay(100);	
	LCD_RST_SET;
	HAL_Delay(50);
}


/*
 * 名字:LCD初始化函数
 * 功能:初始化LCD屏幕
 * 参数:无
 * 返回值:无
*/	 	 
void LCD_Init(void)
{  	
	/* LCD 复位 */
 	LCD_RESET(); 
	/* ST7796S初始化 */
	LCD_WR_REG(0xF0);
	LCD_WR_DATA(0xC3);
	LCD_WR_REG(0xF0);
	LCD_WR_DATA(0x96);
	LCD_WR_REG(0x36);
	LCD_WR_DATA(0x68);	
	LCD_WR_REG(0x3A);
	LCD_WR_DATA(0x05);	
	LCD_WR_REG(0xB0);
	LCD_WR_DATA(0x80);	
	LCD_WR_REG(0xB6);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x02);	
	LCD_WR_REG(0xB5);
	LCD_WR_DATA(0x02);
	LCD_WR_DATA(0x03);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x04);
	LCD_WR_REG(0xB1);
	LCD_WR_DATA(0x80);	
	LCD_WR_DATA(0x10);	
	LCD_WR_REG(0xB4);
	LCD_WR_DATA(0x00);
	LCD_WR_REG(0xB7);
	LCD_WR_DATA(0xC6);
	LCD_WR_REG(0xC5);
	LCD_WR_DATA(0x24);
	LCD_WR_REG(0xE4);
	LCD_WR_DATA(0x31);
	LCD_WR_REG(0xE8);
	LCD_WR_DATA(0x40);
	LCD_WR_DATA(0x8A);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x00);
	LCD_WR_DATA(0x29);
	LCD_WR_DATA(0x19);
	LCD_WR_DATA(0xA5);
	LCD_WR_DATA(0x33);
	LCD_WR_REG(0xC2);
	LCD_WR_REG(0xA7);
	
	LCD_WR_REG(0xE0);
	LCD_WR_DATA(0xF0);
	LCD_WR_DATA(0x09);
	LCD_WR_DATA(0x13);
	LCD_WR_DATA(0x12);
	LCD_WR_DATA(0x12);
	LCD_WR_DATA(0x2B);
	LCD_WR_DATA(0x3C);
	LCD_WR_DATA(0x44);
	LCD_WR_DATA(0x4B);
	LCD_WR_DATA(0x1B);
	LCD_WR_DATA(0x18);
	LCD_WR_DATA(0x17);
	LCD_WR_DATA(0x1D);
	LCD_WR_DATA(0x21);

	LCD_WR_REG(0XE1);
	LCD_WR_DATA(0xF0);
	LCD_WR_DATA(0x09);
	LCD_WR_DATA(0x13);
	LCD_WR_DATA(0x0C);
	LCD_WR_DATA(0x0D);
	LCD_WR_DATA(0x27);
	LCD_WR_DATA(0x3B);
	LCD_WR_DATA(0x44);
	LCD_WR_DATA(0x4D);
	LCD_WR_DATA(0x0B);
	LCD_WR_DATA(0x17);
	LCD_WR_DATA(0x17);
	LCD_WR_DATA(0x1D);
	LCD_WR_DATA(0x21);

    LCD_WR_REG(0X36);
	LCD_WR_DATA(0xEC);
	LCD_WR_REG(0xF0);
	LCD_WR_DATA(0xC3);
	LCD_WR_REG(0xF0);
	LCD_WR_DATA(0x69);
	LCD_WR_REG(0X13);
	LCD_WR_REG(0X11);
	LCD_WR_REG(0X29);
	
	/* 设置LCD显示方向 */
    LCD_direction(USE_HORIZONTAL);
	/* 清全屏 */
	LCD_Clear(LIGHTBLUE);
}
 

/*
 * 名字:窗口设置函数
 * 功能:设置LCD显示窗口大小
 * 参数xStar:LCD显示窗口的开始x坐标
 * 参数yStar:LCD显示窗口的开始y坐标
 * 参数xEnd:LCD显示窗口的结束x坐标
 * 参数yEnd:LCD显示窗口的结束y坐标
 * 返回值:无
*/ 
void LCD_SetWindows(u16 xStar, u16 yStar,u16 xEnd,u16 yEnd)
{	
	LCD_WR_REG(lcddev.setxcmd);	
	LCD_WR_DATA(xStar>>8);
	LCD_WR_DATA(0x00FF&xStar);		
	LCD_WR_DATA(xEnd>>8);
	LCD_WR_DATA(0x00FF&xEnd);

	LCD_WR_REG(lcddev.setycmd);	
	LCD_WR_DATA(yStar>>8);
	LCD_WR_DATA(0x00FF&yStar);		
	LCD_WR_DATA(yEnd>>8);
	LCD_WR_DATA(0x00FF&yEnd);
	//开始写入GRAM	
	LCD_WriteRAM_Prepare();			
}   


/*
 * 名字:设置光标函数
 * 功能:设置光标位置
 * 参数Xpos:x坐标
 * 参数Ypos:y坐标
 * 返回值:无
*/ 
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{	  	    			
	LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);	
} 


/*
 * 名字:LCD方向函数
 * 功能:设置LCD的显示方向
 * 参数direction:为0不旋转
 * 参数direction:为1旋转90度
 * 参数direction:为2旋转180度
 * 参数direction:为3旋转270度
 * 返回值:无
*/ 
void LCD_direction(u8 direction)
{ 
	lcddev.setxcmd=0x2A;
	lcddev.setycmd=0x2B;
	lcddev.wramcmd=0x2C;
	switch(direction){		  
		case 0:						 	 		
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;		
			LCD_WriteReg(0x36,(1<<3)|(1<<6));
		break;
		case 1:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			LCD_WriteReg(0x36,(1<<3)|(1<<5));
		break;
		case 2:						 	 		
			lcddev.width=LCD_W;
			lcddev.height=LCD_H;	
			LCD_WriteReg(0x36,(1<<3)|(1<<7));
		break;
		case 3:
			lcddev.width=LCD_H;
			lcddev.height=LCD_W;
			LCD_WriteReg(0x36,(1<<3)|(1<<7)|(1<<6)|(1<<5));
		break;	
		default:break;
	}		
}


/*
 * 名字:LCD画十字函数
 * 功能:在LCD上画十字
 * 参数x:十字的中心x轴位置
 * 参数y:十字的中心y轴位置
 * 返回值:无
*/
void lcd_draw_cross( u16 x, u16 y )
{
	u16 startX = x-6;
	u16 startY = y-6;
	for( u8 i = 0;i < 12;++i )
	{
		LCD_DrawPoint( startX, y );
		++startX;
	}
	for( u8 j = 0; j < 12;++j )
	{
		LCD_DrawPoint( x, startY );
		++startY;
	}
}


/*
 * 名字:LCD色块填充函数
 * 功能:进行色块填充
 * 参数sx:色块填充的开始x坐标
 * 参数sy:色块填充的开始y坐标
 * 参数ex:色块填充的结束x坐标
 * 参数ey:色块填充的结束y坐标
 * 参数color:要填充的颜色指针
 * 返回值:无
*/
void LCD_Color_Fill(u16 sx, u16 sy, u16 ex, u16 ey, u16* color)
{
	u16 height, width;
	width = ex - sx + 1;            
    height = ey - sy + 1;           
	LCD_SetWindows(sx,sy,ex,ey);
	for(uint32_t y = 0; y <width*height; y++) 
	{
		Lcd_WriteData_16Bit(*color);
		color++;
    }
}

touch.h

#ifndef __TOUCH_H__
#define __TOUCH_H__
#include "main.h"
#include "stdio.h"
#include "stdlib.h"

/*****************************************移植需更改区开始********************************/

//T_PEN为中断引脚0有效,为0即为有按下
#define T_PEN         HAL_GPIO_ReadPin(GPIOG, GPIO_PIN_12)           
#define T_MISO        HAL_GPIO_ReadPin(GPIOD, GPIO_PIN_11)        
#define T_MOSI(x)     do{ x ? \
                          HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_SET) : \
                          HAL_GPIO_WritePin(GPIOD, GPIO_PIN_12, GPIO_PIN_RESET); \
                      }while(0)     

#define T_CLK(x)      do{ x ? \
                          HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_SET) : \
                          HAL_GPIO_WritePin(GPIOC, GPIO_PIN_7, GPIO_PIN_RESET); \
                      }while(0)     

#define T_CS(x)       do{ x ? \
                          HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_SET) : \
                          HAL_GPIO_WritePin(GPIOC, GPIO_PIN_9, GPIO_PIN_RESET); \
                      }while(0)   

/*****************************************移植需更改区结束******************************/
											
/* 未校准坐标获取函数 */
uint16_t tp_write_and_read_ad(uint8_t cmd_data);

/* 校准后的坐标获取函数 */
void myGetX_Y( int xyBuf[2] );
											    
#endif

touch.c

/* 我的触摸头文件 */
#include "touch.h" 

/*
 *名字:MyDelayUs
 *参数us:要延时的时间
 *作用:实现微秒延时
 *返回值:无
*/
void MyDelayUs(uint32_t us)
{
  __IO uint32_t currentTicks = SysTick->VAL;
  const uint32_t tickPerMs = SysTick->LOAD + 1;
  const uint32_t nbTicks = ((us - ((us > 0) ? 1 : 0)) * tickPerMs) / 1000;
  uint32_t elapsedTicks = 0;
  __IO uint32_t oldTicks = currentTicks;
  do {
    currentTicks = SysTick->VAL;
    elapsedTicks += (oldTicks < currentTicks) ? tickPerMs + oldTicks - currentTicks :
                    oldTicks - currentTicks;
    oldTicks = currentTicks;
  } while (nbTicks > elapsedTicks);
}

/*
 *名字:tp_write_and_read_ad
 *参数cmd_data:读取命令
 *作用:获取点击的坐标
 *返回值:无
*/
uint16_t tp_write_and_read_ad(uint8_t cmd_data)
{
    uint16_t rd_data = 0;
    /* 开始状态 */
    T_CLK(0);
    T_MOSI(0);
	/* 选中触摸IC */
    T_CS(0);    
    /* MCU向XTP2046发送数据 */
    for(uint8_t i = 0; i < 8; i++ )
    {
		/* MCU开始准备数据 */
        T_CLK(0);   
        /* 数据要取最高位发送,MSB */
        if (cmd_data & 0x80)    
        {
            T_MOSI(1);
        }
        else
        {
            T_MOSI(0);
        }
		MyDelayUs(1);
		/* MCU发送数据,XTP2046开始读取 */
        T_CLK(1); 
		/* XTP2046读取数据完成 */
        MyDelayUs(1);    
        /* 将次高位变为最高位,用于下次取最高位 */
        cmd_data <<= 1; 
    }
    /* 过滤忙信号 */
    T_CLK(0);
    MyDelayUs(1);
    T_CLK(1);
    MyDelayUs(1);
    /* MCU读取XTP2046返回数据 */
    for(uint8_t i = 0; i < 16; i++ )
    {
		/* XTP2046开始准备数据 */
        T_CLK(0);   
        MyDelayUs(1);
		/* MCU开始读取数据 */
        T_CLK(1);   
        /* 空出最低位用来保存读取到的数据 */
        rd_data <<= 1;
		/* MCU读取数据 */
        rd_data |= T_MISO;  
        MyDelayUs(1);
    }
    /* 结束状态 */    
    T_CLK(0);
	/* 取消选中触摸IC */
    T_CS(1);    
    return  (rd_data >>= 4);
}


/*
 *名字:myGetX_Y
 *参数xyBuf:坐标存储数组
 *作用:获取校准后点击的坐标
 *返回值:无
*/
void myGetX_Y( int xyBuf[2] )
{
	//x
	xyBuf[0] = ((4095-tp_write_and_read_ad(0x90))-2015)/7.82+240;
	//y
	xyBuf[1] = ((4095-tp_write_and_read_ad(0xD0))-2150)/12+160;
}

三,移植说明

LCD部分

首先在你将这些.c和.h文件加入你的工程前你需要在cubemx进行一些配置:

1.屏幕LED管脚管脚连接到STM32的任意管脚,笔者选的是GPIOC_13,如果读者要改为别的引脚需要在lcd.h的《移植需要更改选项开始》的注释下进行简单的修改,最后将管脚配置为推挽输出,拉高

2.屏幕的CS、RS、RESET分别配置为GPIOB类型的4号,8号,6号管脚,配置为推挽输出,拉高,速度高。同样要进行修改的话同上需要在lcd.h的《移植需要更改选项开始》的注释下进行简单的修改。CS、RS、RESET分别对应代码的LCD_CS、LCD_RS、LCD_RST。

3.屏幕lcd部分剩下的MOSI、MISO、SCK三个管脚,在cubemx中顺便初始化一个SPI将对应管脚连接即可,笔者采用的是spi2,速度为21MHZ。

4.应为笔者的芯片为STM32F429故《GPIO输出函数定义开始》注释下管脚拉低部分写法为:

//GPIO复位(拉低)							    
#define	LCD_CS_CLR  GPIO_TYPE->BSRR=(LCD_CS<<16)   
#define	LCD_RS_CLR	GPIO_TYPE->BSRR=(LCD_RS<<16) 		
#define	LCD_RST_CLR	GPIO_TYPE->BSRR=(LCD_RST<<16)

如果你的芯片为STM32F1系列或者GPIO有BRR寄存器的芯片你的写法应该为:

//GPIO复位(拉低)							    
#define	LCD_CS_CLR  GPIO_TYPE->BRR=LCD_CS     
#define	LCD_RS_CLR	GPIO_TYPE->BRR=LCD_RS    	 
#define	LCD_RST_CLR	GPIO_TYPE->BRR=LCD_RST    

TOUCH部分

该部分的连接采用的是软件模拟SPI的方式进行连接。

1.T_IQR对应代码的T_PEN宏定义,连接STM32的GPIOG_12管脚,配置为输入模式,拉高。同样需要修改为别的引脚的话需要,在tuoch.h《移植需更改区开始》的注释下进行行相应的简单的宏定义需改。该管脚为中断管脚,按下后该管脚被置0。

2.T_DO对应代码的T_MISO,连接到GPIOD_11,配置为输入模式,无上下拉。需修改管脚同上。

3.T_DIN对应代码的T_MOSI(x),连接到GPIOD_12,配置为推挽输出,无上下拉,速度高。需修改管脚同上。

4.T_CS和T_CLK分别对应代码的T_CS(x)和T_CLK(x),分别连接到GPIOC_9和GPIOC_7,都配置为推挽输出,无上下拉,速度高。需修改管脚同上。

5.tp_write_and_read_ad(0xD0)将返回读到的x坐标,tp_write_and_read_ad(0x90)返回读到的y坐标。

四,触摸功能的校准

笔者采用的是五点校准的办法,首先读者需要调用lcd_draw_cross()函数在屏幕这五个地方显示+的符号。

点击这些地方你会发现读到的坐标和你设置显示的坐标并不一致,例如你调用lcd_draw_cross()设置LCD屏幕右下角(24,24)即1处显示十字,但是你点击该处获取的触摸坐标的可能是(3807,3908)。这也是我们要进行校准的原因。 经过笔者对五个地方的读取发现lcd驱动芯片的坐标体系和触摸驱动芯片的不一致,如上图所示,且范围也不同,触摸的坐标体系X和Y的最大值都是4095,而lcd驱动的坐标体系X的最大值为480,Y的最大值为320。

接下来我们要将坐标进行统一,我们把触摸读到的Y坐标当作X坐标,把触摸读到的X坐标当作Y坐标,并且都用4095减它们,即可完成统一。看代码

x = 4095 - tp_write_and_read_ad(0x90);
y = 4095 - tp_write_and_read_ad(0xD0);

        如果此时你再次点击(24,24)这里它就可能变成了(187,288),点击中间的十字(即5处)就能得到(2015,2150),是不是非常接近了,但比例还有问题,我们需要进一步处理。此时我们就需要用到这个式子来进行校准,它的原理也非常的简单。

  X = ( XL - XLC ) / KX + XC

  Y = ( YL - YLC ) / KY + YC

参数解读:

XL:点击的x值,即上面经过处理的x值,(187,288)中的187

YL:点击的y值,即上面经过处理的y值,(187,288)中的288

YLC:点击五个十字中,中间那个十字的得到的y值,(2015,2150)中的2150

XLC:点击五个十字中,中间那个十字的得到的x值,(2015,2150)中的2015

XC:lcd驱动芯片坐标体系中屏幕中心的x值,如你的屏幕为320*480横屏显示,则该值为240

YC:lcd驱动芯片坐标体系中屏幕中心的y值,如你的屏幕为320*480横屏显示,则该值为160

KX:触摸的坐标体系算出的3和2的距离与lcd驱动的坐标体系算出3和2的距离比值。例如你调用lcd_draw_cross()设置3和2的位置分别为(456,296)和(24,296),而经过坐标轴统一的触摸坐标体系,触摸这两次处的位置分别为(3566,3552)和(187,3552),则KX为7.82左右。

KY:触摸的坐标体系算出的2和1的距离与lcd驱动的坐标体系算出2和1的距离比值

X:校准过后的触摸x坐标值

Y:校准过后的触摸Y坐标值

如果需要更详细的校准介绍可以看这篇文章:STM32f103的电阻触摸屏的五点校正算法 - 知乎

最终代码:

jx = ( x - 2015 )/7.82+240;
jy = ( y - 2150 )/12+160;

五,结束语

有移植问题可以给我留言!!文章有错欢迎纠正!!!!

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值