之前用过FSMC驱动TFT,实在太浪费IO了,何不用SPI驱动试试.但是,访问不同设备时候,SPI速度不一样,所以,还要掌握速度位的控制.比如慢速器件如LIS302DL,其中SPI的CR1->BR就是分频位,分别从2,4,8,16,32,64,128,256进行分频.而且这个位可以直接用.举个例子:
/* 设置成4分频以便访问LIS302DL */
SPI1->CR1 |= (0x01 << 3);
LIS302DL_Read(Buffer, LIS302DL_OUT_X_ADDR, 6);
X_Offset = Buffer[0];
Y_Offset = Buffer[2];
Z_Offset = Buffer[4];
printf("X = %d,Y = %d,Z = %d
", X_Offset, Y_Offset, Z_Offset);
Delay(500);
/* 设置成2分频以便访问TFT */
SPI1->CR1 |= (0x00 << 3);
TFT SPI也是极其简陋,没写什么太多东西:
void LCD_IO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = LCD_CE | LCD_DC;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIOA->BSRRL = LCD_CE;
}
//DC = 0 => CMD
//DC = 1 => DATA
uint8_t LCD_WriteReg(uint8_t Data)
{
uint8_t p;
GPIOA->BSRRH = LCD_DC;
p = SPI1_SendByte(Data);
return p;
}
uint8_t LCD_WriteData(uint8_t Data)
{
uint8_t p;
GPIOA->BSRRL = LCD_DC;
p = SPI1_SendByte(Data);
return p;
}
但是,其实屏幕不读也可以的,可以直接只写不读.读有时候是为了屏幕ID,分辨批次,这个目前学习,也就偷懒.给一段ILI9341 SPI参考初始化:
void LCD_Init(void)
{
LCD_WriteReg(0xCF);
LCD_WriteData(0x00);
LCD_WriteData(0xD9);
LCD_WriteData(0X30);
LCD_WriteReg(0xED);
LCD_WriteData(0x64);
LCD_WriteData(0x03);
LCD_WriteData(0X12);
LCD_WriteData(0X81);
LCD_WriteReg(0xE8);
LCD_WriteData(0x85);
LCD_WriteData(0x10);
LCD_WriteData(0x78);
LCD_WriteReg(0xCB);
LCD_WriteData(0x39);
LCD_WriteData(0x2C);
LCD_WriteData(0x00);
LCD_WriteData(0x34);
LCD_WriteData(0x02);
LCD_WriteReg(0xF7);
LCD_WriteData(0x20);
LCD_WriteReg(0xEA);
LCD_WriteData(0x00);
LCD_WriteData(0x00);
LCD_WriteReg(0xC0); //Power control
LCD_WriteData(0x21); //VRH[5:0]
LCD_WriteReg(0xC1); //Power control
LCD_WriteData(0x12); //SAP[2:0];BT[3:0]
LCD_WriteReg(0xC5); //VCM control
LCD_WriteData(0x32);
LCD_WriteData(0x3C);
LCD_WriteReg(0xC7); //VCM control2
LCD_WriteData(0XC1);
LCD_WriteReg(0x36); // Memory Access Control
LCD_WriteData(0x08);
LCD_WriteReg(0x3A);
LCD_WriteData(0x55);
LCD_WriteReg(0xB1);
LCD_WriteData(0x00);
LCD_WriteData(0x18);
LCD_WriteReg(0xB6); // Display Function Control
LCD_WriteData(0x0A);
LCD_WriteData(0xA2);
LCD_WriteReg(0xF2); // 3Gamma Function Disable
LCD_WriteData(0x00);
LCD_WriteReg(0x26); //Gamma curve selected
LCD_WriteData(0x01);
LCD_WriteReg(0xE0); //Set Gamma
LCD_WriteData(0x0F);
LCD_WriteData(0x20);
LCD_WriteData(0x1E);
LCD_WriteData(0x09);
LCD_WriteData(0x12);
LCD_WriteData(0x0B);
LCD_WriteData(0x50);
LCD_WriteData(0XBA);
LCD_WriteData(0x44);
LCD_WriteData(0x09);
LCD_WriteData(0x14);
LCD_WriteData(0x05);
LCD_WriteData(0x23);
LCD_WriteData(0x21);
LCD_WriteData(0x00);
LCD_WriteReg(0XE1); //Set Gamma
LCD_WriteData(0x00);
LCD_WriteData(0x19);
LCD_WriteData(0x19);
LCD_WriteData(0x00);
LCD_WriteData(0x12);
LCD_WriteData(0x07);
LCD_WriteData(0x2D);
LCD_WriteData(0x28);
LCD_WriteData(0x3F);
LCD_WriteData(0x02);
LCD_WriteData(0x0A);
LCD_WriteData(0x08);
LCD_WriteData(0x25);
LCD_WriteData(0x2D);
LCD_WriteData(0x0F);
LCD_WriteReg(0x11); //Exit Sleep
Delay(120);
LCD_WriteReg(0x29); //Display on
}
然后要写入地址范围寄存器,我做好的函数是LCD_Set_Addr,传入X开始,Y开始,X结束,Y结束.然后清屏也可以实现:
void LCD_Set_Addr(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye)
{
LCD_WriteReg(0x2a);
LCD_WriteData(xs >> 8);
LCD_WriteData(xs);
LCD_WriteData(xe >> 8);
LCD_WriteData(xe);
LCD_WriteReg(0x2b);
LCD_WriteData(ys >> 8);
LCD_WriteData(ys);
LCD_WriteData(ye >> 8);
LCD_WriteData(ye);
LCD_WriteReg(0x2C);
}
void LCD_Clear(uint16_t color)
{
uint8_t VH, VL;
uint16_t i, j;
VH = color >> 8;
VL = color;
LCD_Set_Addr(0, 0, 239, 319);
for(i = 0; i < 240; i++)
{
for (j = 0; j < 320; j++)
{
LCD_WriteData(VH);
LCD_WriteData(VL);
}
}
}
如果这都能实现,画圆,画点,画线,画矩形就不是什么问题了.然而实现字体显示呢?就不是那样子了哦.当然需要取模了.用一个很古老但是很好用的软件,叫PCtoLCD2002,生成方法是这样的.首先输入ASCII表,注意第一个是空格:
点击上面的选项,然后如图设置:
注意一下宽高就可以生成了哦.
主程序:
#include "stm32f4xx.h"
#include "SysTick.h"
#include "DUART.h"
#include "SPI1_Dev.h"
#include "TFT_SPI.h"
int main(void)
{
/* 打开所有IO端口时钟的脑残大法. */
RCC->AHB1ENR = 0x001000F7;
SysTick_Init();
DUSART_Init();
SPI1_LowLevel_Init();
LCD_IO_Init();
while (1)
{
/* 设置成2分频以便访问TFT */
SPI1_DivChange(SPI_BaudRatePrescaler_4);
LCD_Init();
LCD_Clear(0x003F);
LCD_Fill(100, 100, 200, 200, 0xfe00);
LCD_DrawLine(10, 50, 70, 60, 0xf3ff);
LCD_DrawRectangle(70, 70, 110, 250, 0x00ef);
Draw_Circle(50, 90, 30, 0xffff);
LCD_ShowNum(90, 90, 10086, 5, 12, 0x0A0A, 0xCCFF);
LCD_ShowNum(120, 90, 10086, 5, 16, 0x0A0A, 0xBBFF);
LCD_ShowNum(160, 90, 10086, 5, 24, 0x0A0A, 0xAAFF);
LCD_ShowString(90, 130, 60, 12, 12, "Tater", 0xFFCC, 0xAE00);
LCD_ShowString(90, 170, 80, 16, 16, "Tater", 0xFFCC, 0xAEFF);
LCD_ShowString(90, 210, 100, 16, 24, "Tater", 0x00FE, 0xFFAE);
while(1)
{
}
}
}
屏幕质量不好见笑了:
程序下载(接线见TFT头文件):
附上取模工具:



