注意!这个主要是给笔者用的,移植经验仅供参考,要根据不同驱动IC进行不同的移植!
一、 笔者所使用的电容触摸屏基本属性:
链接: 电容式触摸屏资料
二、 笔者所使用的单片机和编译环境:
单片机:STM32F407ZET6
环境:KEIL5
三、 详细移植过程:
3.1 移植demo
首先根据上面的WIKI下载对应的示例DEMO,解压后打开如下:
依次打开1-DEMO,Demo_STM32、Demo_MSP2833_MSP2834_STM32F407ZGT6_Hardware_SPI:
STM32F407ZGT6和STM32F407ZET6只是FLASH大小不一样,所以如果引脚允许的话,是可以直接烧录的。打开demo,先编译一遍,如果没有问题,就复制一份作为正式项目。
3.2 修改环境
将复制的一份项目打开,修改硬件:
修改完之后重新编译,应该是0报错,0警告的。
3.3 修改LCD_Init函数
如果只需要驱动LCD屏幕的话,只需要以下的这些引脚。(注意,我这里和DEMO给的不一样,已经进行了修改,接下来我会详细讲怎么用尽可能少的步骤去移植)
3.3.1 修改SPI初始化
其中SDI、SDO、SCK需要对应的SPI线,可以通过查找芯片的数据手册去看哪些引脚支持SPI功能。你可以通过在数据芯片手册里搜索SPI来找对应的引脚,注意虽然大多数封装的引脚定义都是一样的,但是最好还是确定是同一种封装。
如下:
另外的LED、LCD_RS 、LCD_RST、LCD_CS都是简单的GPIO口用法,可以随意选择。
然后我们打开 LCD_Init() 函数,先修改里面的第一句:
SPI2_Init(); //硬件SPI初始化
打开函数定义,修改如下:
/*****************************************************************************
* @name :void SPI2_Init(void)
* @date :2018-08-09
* @function :Initialize the STM32 hardware SPI1
* @parameters :None
* @retvalue :None
******************************************************************************/
void SPI2_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
// 1. 启用 GPIOB 和 GPIOC 的时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); // 启用 GPIOB 时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE); // 启用 GPIOC 时钟
// 2. 启用 SPI2 的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); // 启用 SPI2 时钟
// 3. 初始化 PC2 和 PC3 为 MISO 和 MOSI
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3; // PC2 -> MISO, PC3 -> MOSI
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; // 设置为复用模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; // 推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; // 100MHz 速度
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; // 上拉
GPIO_Init(GPIOC, &GPIO_InitStructure); // 初始化 GPIOC
// 4. 初始化 PB10 为 SCK
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // PB10 -> SCK
GPIO_Init(GPIOB, &GPIO_InitStructure); // 初始化 GPIOB
// 5. 配置引脚的复用功能为 SPI2
GPIO_PinAFConfig(GPIOC, GPIO_PinSource2, GPIO_AF_SPI2); // PC2 -> SPI2_MISO
GPIO_PinAFConfig(GPIOC, GPIO_PinSource3, GPIO_AF_SPI2); // PC3 -> SPI2_MOSI
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_SPI2); // PB10 -> SPI2_SCK
// 6. 初始化 SPI2
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; // 全双工模式
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; // 主模式
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8 位数据帧
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High; // 时钟空闲高电平
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; // 第二个边沿采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; // 软件控制 NSS
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2; // 预分频 2
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; // MSB 先传输
SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC 多项式
SPI_Init(SPI2, &SPI_InitStructure); // 初始化 SPI2
// 7. 启用 SPI2 外设
SPI_Cmd(SPI2, ENABLE); // 使能 SPI2
}
3.3.2 修改GPIO初始化
LCD_GPIOInit();//LCD GPIO初始化
打开函数定义,修改如下:
void LCD_GPIOInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB ,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13|GPIO_Pin_14| GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//普通输出模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);
LCD_LED=1; //点亮背光
}
然后可以打开剩余的函数再看看,可以发现基本上都用的宏定义函数,这里我会直接打开 lcd.h文件,直接修改宏定义。
如果你修改了GPIO口,就修改对应的GPIO_TYPE,如果你修改了引脚,就修改对应的LCD_CS 、LCD_RS、 LCD_RST。
然后用全局搜索功能,将原来的SPI*修改为现在的SPI2(我自己是SPI2)。
执行到这一步,是可以运行main函数测试里除最后一个函数之外的所有函数的。
注意测试的时候最好给用5V的引脚给屏幕供电,否则可能电压不够!!
3.4 修改Touch_Test相关函数
触摸相关的引脚如下:
可以看出触摸用的是I2C通信。
打开Touch_Test的定义,再打开init的定义,会看到以下代码:
/*****************************************************************************
* @name :u8 TP_Init(void)
* @date :2018-08-09
* @function :Initialization touch screen
* @parameters :None
* @retvalue :0-no calibration
1-Has been calibrated
******************************************************************************/
u8 TP_Init(void)
{
if(FT6336_Init())
{
return 1;
}
tp_dev.scan=FT6336_Scan; //扫描函数指向GT911触摸屏扫描
return 0;
}
然后我们再打开**FT6336_Init()**函数
/*****************************************************************************
* @name :u8 FT5426_Init(void)
* @date :2020-05-13
* @function :Initialize the ft5426 touch screen
* @parameters :none
* @retvalue :0-Initialization successful
1-initialization failed
******************************************************************************/
u8 FT6336_Init(void)
{
u8 temp[2];
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC,ENABLE);//使能GPIOB和GPIOC时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PB1->CTP_INT
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PC5->CTP_RST
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出
GPIO_Init(GPIOC, &GPIO_InitStructure);
CTP_IIC_Init(); //初始化电容屏的I2C总线
FT_RST=0; //复位
delay_ms(10);
FT_RST=1; //释放复位
delay_ms(500);
// temp[0]=0;
// FT6336_WR_Reg(FT_DEVIDE_MODE,temp,1); //进入正常操作模式
// FT6336_WR_Reg(FT_ID_G_MODE,temp,1); //查询模式
//temp[0]=40; //触摸有效值,22,越小越灵敏
//FT6336_WR_Reg(FT_ID_G_THGROUP,temp,1); //设置触摸有效值
FT6336_RD_Reg(FT_ID_G_FOCALTECH_ID,&temp[0],1);
if(temp[0]!=0x11)
{
return 1;
}
FT6336_RD_Reg(FT_ID_G_CIPHER_MID,&temp[0],2);
if(temp[0]!=0x26)
{
return 1;
}
if((temp[1]!=0x00)&&(temp[1]!=0x01)&&(temp[1]!=0x02))
{
return 1;
}
FT6336_RD_Reg(FT_ID_G_CIPHER_HIGH,&temp[0],1);
if(temp[0]!=0x64)
{
return 1;
}
// temp[0]=12; //激活周期,不能小于12,最大14
// FT6336_WR_Reg(FT_ID_G_PERIODACTIVE,temp,1);
//读取版本号,参考值:0x3003
// FT6336_RD_Reg(FT_ID_G_LIB_VERSION,&temp[0],2);
// if(temp[0]==0X10&&temp[1]==0X01)//版本:0X3003
// {
// printf("CTP ID:%x\r\n",((u16)temp[0]<<8)+temp[1]);
// return 0;
// }
return 0;
}
由TP_Init可知我们希望它返回0,那么我们看这段函数主要执行了什么操作,主要总结为下:
- 初始化了I2C的四个引脚。
- 向芯片发送命令。
- 读取芯片发回的信息。
- 校验芯片发回的信息。
那么移植的话,只有第一二步是需要修改的。
3.4.1 修改I2C的四个引脚初始化
修改中断和复位引脚:
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOC,ENABLE);//使能GPIOB和GPIOC时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; //PB1->CTP_INT
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//输入
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //PC5->CTP_RST
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //输出
GPIO_Init(GPIOC, &GPIO_InitStructure);
修改SDA和SCL:
/*****************************************************************************
* @name :void CTP_IIC_Init(void)
* @date :2020-05-13
* @function :Initialize IIC
* @parameters :None
* @retvalue :None
******************************************************************************/
void CTP_IIC_Init(void)
{
GPIO_InitTypeDef GPIO_Initure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB|RCC_AHB1Periph_GPIOA, ENABLE);
GPIO_Initure.GPIO_Pin=GPIO_Pin_0; //PB0->CTP_SCL
GPIO_Initure.GPIO_Mode = GPIO_Mode_OUT;//输出
GPIO_Initure.GPIO_OType = GPIO_OType_PP;//推挽
GPIO_Initure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Initure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOB, &GPIO_Initure);
GPIO_Initure.GPIO_Pin=GPIO_Pin_6; //PA6->CTP_SDA
GPIO_Init(GPIOA, &GPIO_Initure);
CTP_IIC_SCL=1;
CTP_IIC_SDA=1;
}
修改宏定义函数:
//IIC IO方向设置
#define CTP_SDA_IN() {GPIOA->MODER &= ~(3 << (6 * 2)); GPIOA->MODER |= 0 << (6 * 2);}
#define CTP_SDA_OUT() {GPIOA->MODER &= ~(3 << (6 * 2)); GPIOA->MODER |= 1 << (6 * 2);}
//IO操作函数
#define CTP_IIC_SCL PBout(0) //SCL
#define CTP_IIC_SDA PAout(6) //SDA
#define CTP_READ_SDA PAin(6) //输入SDA
这些位移操作的原型在sys.c文件中有详细说明。
实验现象: