本帖最后由 qintian0303 于 2023-10-3 18:32 编辑
显示单元的驱动:本次测试选用的是1.54寸tft作为显示元件,主要参数是240*240分辨率,主控是7789,通过SPI/8080进行通信,在本次测试使用SPI进行通信,同时驱动部分也是对SPI功能的试用。这里面分别使用IO口模拟及硬件SPI来驱动。
我们首先用IO口模拟SPI的方式进行屏幕的驱动:
IO口模拟部分代码如下:#define SPI1_MASTER SPI1
#define SPI1_MASTER_PERIPH RCC_APB2_PERIPH_SPI1
#define SPI1_MASTER_PERIPH_GPIO RCC_APB2Periph_GPIOA
#define SPI1_MASTER_GPIO GPIOA
#define SPI1_MOSI_GPIO_ALTERNATE GPIO_AF1_SPI1
#define SPI1_CLK_GPIO_ALTERNATE GPIO_AF2_SPI1
#define SPI1_MASTER_MISO_PIN GPIO_Pin_6
#define SPI1_MASTER_MOSI_PIN GPIO_Pin_7
#define SPI1_MASTER_CLK_PIN GPIO_Pin_5
#define SPI1_MASTER_NSS_PIN GPIO_Pin_4
#define TFT_BL_GPIO GPIOC
#define TFT_BL_PERIPH_GPIO RCC_APB2Periph_GPIOC
#define TFT_BL_PIN GPIO_Pin_7
#define TFT_RS_PIN GPIO_Pin_16
#define TFT_RESET_PIN GPIO_Pin_17
#define TFT_RS_reset GPIO_WriteBit(TFT_BL_GPIO, TFT_RS_PIN,Bit_RESET)
#define TFT_RS_set GPIO_WriteBit(TFT_BL_GPIO, TFT_RS_PIN,Bit_SET)
#define TFT_RESET_reset GPIO_WriteBit(TFT_BL_GPIO, TFT_RESET_PIN,Bit_RESET)
#define TFT_RESET_set GPIO_WriteBit(TFT_BL_GPIO, TFT_RESET_PIN,Bit_SET)
#define TFT_BL_SET GPIO_WriteBit(TFT_BL_GPIO, TFT_BL_PIN,Bit_SET)
#define TFT_BL_RESET GPIO_WriteBit(TFT_BL_GPIO, TFT_BL_PIN,Bit_RESET)
#define SPI1_CS_OUT0 GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_NSS_PIN,Bit_RESET)
#define SPI1_CS_OUT1 GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_NSS_PIN,Bit_SET)
#define SPI1_MOSI_OUT0 GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_MOSI_PIN,Bit_RESET)
#define SPI1_MOSI_OUT1 GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_MOSI_PIN,Bit_SET)
#define SPI1_CLK_OUT0 GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_CLK_PIN,Bit_RESET)
#define SPI1_CLK_OUT1 GPIO_WriteBit(SPI1_MASTER_GPIO, SPI1_MASTER_CLK_PIN,Bit_SET)
void delay_us(uint32_t Data)
{
Delay_Us(Data);
}
void delay_ms(uint32_t Data)
{
Delay_Ms(Data);
}
//******************************************************************************
//* 函数名称 : SPI1_IOInit()
//* 函数描述 : SPI对应的IO口初始化
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void SPI1_IOInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = SPI1_MASTER_NSS_PIN | SPI1_MASTER_MOSI_PIN | SPI1_MASTER_CLK_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = TFT_BL_PIN |TFT_RS_PIN | TFT_RESET_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
SPI1_CLK_OUT0;
SPI1_MOSI_OUT0;
SPI1_CS_OUT1;
TFT_RS_reset;
TFT_RESET_reset;
TFT_BL_SET;
}
//******************************************************************************
//* 函数名称 : SPI1_Send_Data(uint8_t Data)
//* 函数描述 : SPI1发送8位数据
//* 输入参数 : Data
//* 参数描述 : 具体的指令代码
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void SPI1_Send_Data(uint8_t Data)
{
SPI1_CS_OUT0; //选中该从机
delay_us(2);
uint8_t i;
for (i = 0;i < 8;i++)
{
if ((Data << i) & 0x80)
{
SPI1_MOSI_OUT1;
SPI1_CLK_OUT0;//rising edge
SPI1_CLK_OUT1;
}
else
{
SPI1_MOSI_OUT0;
SPI1_CLK_OUT0;//rising edge
SPI1_CLK_OUT1;
}
}
SPI1_CS_OUT1;
}
屏的驱动初始化程序由于芯片不同而又差异,这里就不做介绍了,只要8位数据时序成功基本上就可以。目前用的到包括SPI的CS/MOSI/CLK对应的也是复用功能的GPIOA的GPIO_Pin_4/GPIO_Pin_7/GPIO_Pin_5,其他控制字引脚就只是普通的IO控制,其中RS为数据/命令引脚(GPIOC-GPIO_Pin_16),复位引脚(GPIOC-GPIO_Pin_17),BL为背光控制引脚(GPIOC-GPIO_Pin_7),效果如下:
可以看出来驱动成功了,不过对于240*240分辨率老说,这个刷新速度是不理想的,主要原因还是因为该芯片的主频只有48MHz,接下来我们看看使用硬件SPI的效果。
然后咱们用硬件SPI体验一下刷屏:
代码如下:
//******************************************************************************
//* 函数名称 : SPI1_IOInit()
//* 函数描述 : SPI1对应的IO口初始化
//* 输入参数 :
//* 参数描述 :
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void SPI1_IOInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
SPI_InitTypeDef SPI_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_SPI1, ENABLE);
GPIO_InitStructure.GPIO_Pin = TFT_BL_PIN | TFT_RS_PIN | TFT_RESET_PIN ;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = SPI1_MASTER_NSS_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
SPI1_CS_OUT1;
TFT_RS_reset;
TFT_RESET_reset;
TFT_BL_SET;
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_4;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI1, &SPI_InitStructure);
SPI_Cmd(SPI1, ENABLE);
}
//******************************************************************************
//* 函数名称 : SPI_Send_Data(uint8_t Data)
//* 函数描述 : SPI发送8位数据
//* 输入参数 : Data
//* 参数描述 : 具体的指令代码
//* 输出参数 : 无
//* 返回值 : 无
//******************************************************************************
void SPI1_Send_Data(uint8_t Data)
{
SPI1_CS_OUT0; //选中该从机
delay_us(1);
SPI_I2S_SendData(SPI1_MASTER, Data);
while(SPI_I2S_GetFlagStatus(SPI1, SPI_I2S_FLAG_TXE) == RESET);
delay_us(1);
SPI1_CS_OUT1;
}
看一看效果:
对比IO口模拟SPI和硬件SPI的效果,使用硬件SPI刷屏的速度还是有明显的提升的。
接下来通过SPI功能深度体验了一下MounRiver Studio这个开发环境,感觉还是很喜欢的。
比如Outline显示框,我们在进行对应文件的编写时,这个框里面就会把当前文件的所有头文件,变量,函数等内容集中显示,这样避免咱们总是上下拉文件来找,尤其是文件比较大的时候,查找会很方便;
添加文件不在需要逐个添加,放到对应的文件夹下,添加一次就会把所有的刷新添加了,有好处也有弊端,好处是便捷,弊端是比如只想添加一个,多个都拉进来了 还得一个一个移除; 下载和调试是分开的,习惯需要重新建立,下载器去除后并没有对应的报警提示;
整体来说MounRiver Studio开发环境还是挺简洁实用的。
|