STM32H7使用HAL库驱动3.5寸SPI电容触摸屏幕+DMA刷新

先上效果

VID_20240629_191036

VID_20240701_195036

使用100mhz的SPI频率,在不使用DMA情况下,大约10帧左右,加上DMA后提高到接近40帧.

使用480*320*2大小的缓冲区,如果单纯刷屏可以减小到HAL库SPI发送函数最大长度.因为缓冲区过大所以分几次发送的.

CUBEMX生成代码

一共需要使用3个外设,定时器可以不用

硬件I2C+SPI+串口

首先使能RCC,SPI,USART,I2C

电容触摸

电容触摸芯片GT911,I2C频率最大400khz,STM32开到1000k也无所谓,没有使能DMA和中断,使用外部中断获取触摸信号,读寄存器

对配置好的I2C封装一下,这里沿用了以前的代码,因为GT911有16位寄存器,所以再写一个16位读写函数.

void i2c_write(uint8_t devaddr,uint8_t addr,uint8_t pdata,int len){
  HAL_I2C_Mem_Write(&I2C,devaddr,addr,I2C_MEMADD_SIZE_8BIT,&pdata,len,1000);
}
uint8_t i2c_read(uint8_t devaddr,uint8_t addr)
{ uint8_t data;
  HAL_I2C_Mem_Read(&I2C,devaddr,addr,I2C_MEMADD_SIZE_8BIT,&data,1,1000);
  return data;
}

void i2c_write16(uint8_t devaddr,uint16_t addr,uint8_t pdata,int len){

  HAL_I2C_Mem_Write(&I2C,devaddr,addr,I2C_MEMADD_SIZE_16BIT,&pdata,len,1000);
}
uint8_t i2c_read16(uint8_t devaddr,uint16_t addr)
{ uint8_t data;
  HAL_I2C_Mem_Read(&I2C,devaddr,addr,I2C_MEMADD_SIZE_16BIT,&data,1,1000);
  return data;
}

void i2c_read16n(uint8_t devaddr,uint16_t addr,uint8_t* data,uint8_t n)
{
  HAL_I2C_Mem_Read(&I2C,devaddr,addr,I2C_MEMADD_SIZE_16BIT,data,n,1000);
}
void i2c_write16n(uint8_t devaddr,uint16_t addr,uint8_t* data,uint8_t n)
{
  HAL_I2C_Mem_Write(&I2C,devaddr,addr,I2C_MEMADD_SIZE_16BIT,data,n,1000);
}

GT911初始化

GT911的寄存器表大概就用这几个就好了

#define USE_GT911
#define hi2cx GT911
//#define GT_WRITECFG //写配置表
#define GT_ADDR 0X28
#define GT_CTRL_REG     0X8040       //GT911控制寄存器
#define GT_CFGS_REG     0X8047       //GT911配置起始地址寄存器
#define GT_CHECK_REG     0X80FF       //GT911校验和寄存器
#define GT_PID_REG         0X8140       //GT911产品ID寄存器
#define GT_GSTID_REG     0X814E       //GT911当前检测到的触摸情况

GT911的初始化很简单,不用配置什么,上电就能读取数据,因为我没找到芯片id到底是多少所以没有读id,同时千万别写控制寄存器0x8040,写了就裂开,找厂家要配置表.这里选择了要不要写配置表

void GT911_INIT(){
		HAL_Delay(100);
    uint8_t data;
		#ifdef GT_WRITECFG
		i2c_write16(GT_ADDR,GT_CTRL_REG,2,1);
    i2c_write16n(GT_ADDR,0x8047,(uint8_t *)datacfg,186);
		i2c_write16(GT_ADDR,GT_CTRL_REG,0,1);
		#endif
    touch=0;
    HAL_Delay(100);
		i2c_write16(GT_ADDR,GT_GSTID_REG,0x00,1);
}

随后就是判断是否被触摸以及触摸点数.

通过电容触摸屏GT911、GT928、GT9147的使用_gt911 3.5寸配置文件-CSDN博客得知,当触摸发生时,寄存器0x814E 最高位变成1,同时低四位表示有几个点

例如10000011:触摸按下,有3个点按下,这里我用了两次判断,先判断高位在判断低四位是否不为0,因为触摸结束的时候没有及时清除814E寄存器,第8位还为1,会误入读取坐标,加一个判断能够在触摸结束马上得知.

通过上文得知,坐标寄存器都是挨着的,只用按顺序读就好了氛围高8位和低8位

坐标=高八位*255+低八位

读完以后存储到LIST里面,方便读取.

void GET_NUM(void){
		#ifdef TOUCHOK
		touch=0;
		uint8_t data;
		data=i2c_read16(GT_ADDR,GT_GSTID_REG);
		if((data&0x80)!=0){
			if((data&0X0f)!=0){
			touch=data&0x0F;
			read_point(LIST,touch);
			}
			i2c_write16(GT_ADDR,GT_GSTID_REG,0x00,1);
		}
		return ;
  #endif
		printf("TOUCH ERROR PLEASE TRY LATER\r\n");
}
void read_point(POINT LIST[],uint8_t NUM){
  uint16_t x,y;
  i2c_read16n(GT_ADDR,0x8150,datatemp,8*NUM);
	for(uint8_t i=0;i<NUM;i++){
    x=(datatemp[i*8]+(datatemp[i*8+1]<<8));
    y=(datatemp[i*8+2]+(datatemp[i*8+3]<<8));
    LIST[i].xPos=x;
    LIST[i].yPos=y;
    LIST[i].id=i+1;
		printf("TOUCH %d X->%d Y->%d\r\n",i+1,x,y);
  }
}

测试,数据也是比较准的

SPI初始化

200mhz 2分频 ,h7就是暴力,直接硬干都有10多帧,8位传输,仅发送,加入DMA,开启SPI DMA中断

其他配置都差不多不用改

封装一下发送函数

void SPI_ReadWriteByte(uint8_t TxData)
{			
      HAL_SPI_Transmit(&SPI,&TxData,1,10);              		    //·µ»ØÊÕµ½µÄÊý¾Ý		
}

void SPI_SetSpeed(uint32_t SPI_BaudRatePrescaler)
{
    assert_param(IS_SPI_BAUDRATE_PRESCALER(SPI_BaudRatePrescaler));//ÅжÏÓÐЧÐÔ
    __HAL_SPI_DISABLE(&SPI);            //¹Ø±ÕSPI
    SPI.Instance->CFG1&=~(0X7<<28);     //λ30-28ÇåÁ㣬ÓÃÀ´ÉèÖò¨ÌØÂÊ
    SPI.Instance->CFG1|=SPI_BaudRatePrescaler;//ÉèÖÃSPIËÙ¶È
    __HAL_SPI_ENABLE(&SPI);             //ʹÄÜSPI
}

引脚,这里使用cubemx的宏定义,方便移植,命名好就能直接使用

DMA

这里是最难绷的,前前后后试了好久,不知道为什么一直发送不成功,返回不是HAL_ERROR就是HAL_BUSY,直到这几天突然看到片文章STM32H7:解决DMA传输无效的问题-CSDN博客

牛莫得,H7默认的程序执行范围起始位置DMA是无法访问的,解决方法也很简单

将起始区域修改为可以的就好了

LCD代码

这里使用了安富莱的LCD代码

lcd.h注释不知道为什么乱码,内容挺好理解的

#ifndef __LCD_H
#define __LCD_H		


#include "stdlib.h"
#include "GPIO.h"
typedef   signed          char int8_t;
typedef   signed short     int int16_t;
typedef   signed           int int32_t;
typedef   signed       long long int64_t;

typedef unsigned          char   uint8_t;
typedef unsigned short     int   uint16_t;
typedef unsigned           int   uint32_t;
typedef unsigned       long long uint64_t;


typedef uint32_t  u32;
typedef uint16_t u16;
typedef uint8_t  u8;

extern uint16_t D_Color;
extern uint16_t B_Color;


/******************************************************************************

  ½Ó¿Ú¶¨Ò壬Çë¸ù¾Ý½ÓÏßÐ޸IJ¢ÐÞ¸ÄÏàÓ¦IO³õʼ»¯--Çý¶¯°å×ÓºÍIOÒª¶ÔÓ¦


//	#define LCD_SDA        	//PD7  //Êý¾ÝÊäÈëÏß
//	#define LCD_SCL        	//PB3  //ʱÖÓÏß
//	#define LCD_CS        	//PB4  //Ƭѡ	
//	#define LCD_RESET     	//PG11  //Êý¾ÝÊä³ö/¸´Î»
//	#define LCD_RS         	//PD6   //ÃüÁî/Êý¾ÝÇл»
//	#define LCD_BLK         //PG14   //±³¹â¿ØÖÆ  

*******************************************************************************/ 



//Òº¾§¿ØÖÆ¿ÚÖÃ1²Ù×÷Óï¾äºê¶¨Òå
#define	LCD_SDA_SET  	HAL_GPIO_WritePin(LCD_MOSI_GPIO_Port,LCD_MOSI_Pin,GPIO_PIN_SET) 	   //PB15ÖÃ1    LCD_SDI£º PB15 //Êý¾ÝÊäÈëÏß

#define	LCD_SCL_SET  	HAL_GPIO_WritePin(LCD_CLK_GPIO_Port,LCD_CLK_Pin,GPIO_PIN_SET)	     //PB13ÖÃ1    LCD_SCL£º PB13 //ʱÖÓÏß

#define	LCD_CS_SET  	HAL_GPIO_WritePin(LCD_CS_GPIO_Port,LCD_CS_Pin,GPIO_PIN_SET)	     //PB12ÖÃ1    LCD_CS£º  PB12 //Ƭѡ	

#define LCD_RST_SET   	HAL_GPIO_WritePin(LCD_RESET_GPIO_Port,LCD_RESET_Pin,GPIO_PIN_SET)	     //PB14ÖÃ1      LCD_SDO £ºPB14 //Êý¾ÝÊä³ö/¸´Î»

#define	LCD_RS_SET  	HAL_GPIO_WritePin(LCD_RS_GPIO_Port,LCD_RS_Pin,GPIO_PIN_SET)		   //PB1ÖÃ1     LCD_RS£º PB1   //ÃüÁî/Êý¾ÝÇл»

#define	LCD_BLK_SET  	HAL_GPIO_WritePin(LCD_BL_GPIO_Port,LCD_BL_Pin,GPIO_PIN_SET) 	     //PB0ÖÃ1     LCD_BLK £ºPB0   //±³¹â¿ØÖÆ  


//Òº¾§¿ØÖÆ¿ÚÖÃ0²Ù×÷Óï¾äºê¶¨Òå

#define	LCD_SDA_CLR  	HAL_GPIO_WritePin(LCD_MOSI_GPIO_Port,LCD_MOSI_Pin
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值