本帖最后由 jinglixixi 于 2025-6-2 09:42 编辑
#申请原创#
前面介绍了以硬件I2C驱动OLED的方法,这里再介绍一下以硬件SPI来驱动TFT显示屏的方法。
对于SPI的学习完全可以借鉴官方所提供的SPI例程,然后根据自身的需要予以相应的补充。
根据TFT屏的需要,对SPI及所用引脚的配置函数为:
void tft_config(void)
{
gpio_init_type gpio_initstructure;
spi_init_type spi_init_struct;
crm_periph_clock_enable(CRM_GPIOB_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_GPIOC_PERIPH_CLOCK, TRUE);
crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
/* software cs, pb12 as a general io to control flash cs */
gpio_initstructure.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
gpio_initstructure.gpio_pull = GPIO_PULL_NONE;
gpio_initstructure.gpio_mode = GPIO_MODE_OUTPUT;
gpio_initstructure.gpio_drive_strength = GPIO_DRIVE_STRENGTH_STRONGER;
gpio_initstructure.gpio_pins = GPIO_PINS_12;
gpio_init(GPIOB, &gpio_initstructure);
在进行TFT屏连接时,可充分利用J7接口来完成。
具体的连接关系为:
LCD-CS --> PB12
LCD-RST --> PB11
LCD-DC --> PB10
LCD-SDI --> PB15
LCD-SCK --> PB13
LCD-BK --> PB9
图1 引脚定义
图2 所用接口
SPI发送字节数据的函数为:
void lcd_spi2_write(uint8_t data)
{
uint32_t retry = 0;
while (spi_i2s_flag_get(SPI2, SPI_I2S_TDBE_FLAG) == RESET)
{
retry++;
if(retry > 10000)
return;
}
spi_i2s_data_transmit(SPI2, data);
retry = 0;
while (spi_i2s_flag_get(SPI2, SPI_I2S_BF_FLAG) == SET)
{
retry++;
if(retry > 0xFFFFF)
return;
}
}
向寄存器发送内容的函数为:
static void LCD_WR_REG(uint8_t reg)
{
LCD_DC_CLR;
LCD_CS_CLR;
lcd_spi2_write(reg);
LCD_CS_SET;
LCD_DC_SET;
}
发送数据内容的函数为:
static void LCD_WR_DATA(uint8_t data)
{
LCD_DC_SET;
LCD_CS_CLR;
lcd_spi2_write(data);
LCD_CS_SET;
}
向寄存器发送数据的函数为:
static void LCD_WriteReg(uint8_t reg, uint16_t regdata)
{
LCD_WR_REG(reg);
LCD_WR_DATA(regdata);
}
这样就完成了以SPI进行TFT屏显示驱动的准备工作,随后就可利用TFT屏的相应功能函数。
该TFT显示屏的初始化函数为:
void tft_Init(void)
{
// ili9220
LCD_RESET();
LCD_CS_CLR;
LCD_WR_REG(0xCB);
LCD_WR_DATA(0x39);
LCD_WR_DATA(0x2C);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x34);
LCD_WR_DATA(0x02);
LCD_WR_REG(0xCF);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0XC1);
LCD_WR_DATA(0X30);
LCD_WR_REG(0xE8);
LCD_WR_DATA(0x85);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x78);
LCD_WR_REG(0xEA);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_REG(0xED);
LCD_WR_DATA(0x64);
LCD_WR_DATA(0x03);
LCD_WR_DATA(0X12);
LCD_WR_DATA(0X81);
LCD_WR_REG(0xF7);
LCD_WR_DATA(0x20);
LCD_WR_REG(0xC0);
LCD_WR_DATA(0x23);
LCD_WR_REG(0xC1);
LCD_WR_DATA(0x10);
LCD_WR_REG(0xC5);
LCD_WR_DATA(0x3e);
LCD_WR_DATA(0x28);
LCD_WR_REG(0xC7);
LCD_WR_DATA(0x86);
LCD_WR_REG(0x36);
LCD_WR_DATA(0x48);
LCD_WR_REG(0x3A);
LCD_WR_DATA(0x55);
LCD_WR_REG(0xB1);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x18);
LCD_WR_REG(0xB6);
LCD_WR_DATA(0x08);
LCD_WR_DATA(0x82);
LCD_WR_DATA(0x27);
LCD_WR_REG(0xF2);
LCD_WR_DATA(0x00);
LCD_WR_REG(0x26);
LCD_WR_DATA(0x01);
LCD_WR_REG(0xE0);
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x31);
LCD_WR_DATA(0x2B);
LCD_WR_DATA(0x0C);
LCD_WR_DATA(0x0E);
LCD_WR_DATA(0x08);
LCD_WR_DATA(0x4E);
LCD_WR_DATA(0xF1);
LCD_WR_DATA(0x37);
LCD_WR_DATA(0x07);
LCD_WR_DATA(0x10);
LCD_WR_DATA(0x03);
LCD_WR_DATA(0x0E);
LCD_WR_DATA(0x09);
LCD_WR_DATA(0x00);
LCD_WR_REG(0XE1);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x0E);
LCD_WR_DATA(0x14);
LCD_WR_DATA(0x03);
LCD_WR_DATA(0x11);
LCD_WR_DATA(0x07);
LCD_WR_DATA(0x31);
LCD_WR_DATA(0xC1);
LCD_WR_DATA(0x48);
LCD_WR_DATA(0x08);
LCD_WR_DATA(0x0F);
LCD_WR_DATA(0x0C);
LCD_WR_DATA(0x31);
LCD_WR_DATA(0x36);
LCD_WR_DATA(0x0F);
LCD_WR_REG(0x11);
delay_ms(120);
LCD_WR_REG(0x29);
LCD_WR_REG(0x2c);
LCD_BK_SET;
}
调整显示屏方向的函数为:
void LCD_direction(uint8_t direction)
{
switch (direction)
{
case 0:
LCD_W = 240;
LCD_H = 320;
LCD_WriteReg(0x36,0x48);
break;
case 1:
LCD_W = 320;
LCD_H = 240;
LCD_WriteReg(0x36, 0x28);
break;
case 2:
LCD_W = 240;
LCD_H = 320;
LCD_WriteReg(0x36, 0x88);
break;
case 3:
LCD_W = 320;
LCD_H = 240;
LCD_WriteReg(0x36, 0x68);
break;
default:
break;
}
}
实现字符显示的函数为:
void LCD_ShowChar(unsigned int x,unsigned int y,char num,char mode)
{
char temp;
char pos,t;
unsigned int x0=x;
unsigned int colortemp=POINT_COLOR;
if(x>LCD_W-16||y>LCD_H-16) return;
num=num-' ';
LCD_SetWindows(x,y,x+8-1,y+16-1);
if(!mode)
{
for(pos=0;pos<16;pos++)
{
temp=asc2_1608[(unsigned int)num*16+pos];
for(t=0;t<8;t++)
{
if(temp&0x01) POINT_COLOR=colortemp;
else
POINT_COLOR=BACK_COLOR;
LCD_WR_DATA(POINT_COLOR);
temp>>=1;
x++;
}
x=x0;
y++;
}
}
else
{
for(pos=0;pos<16;pos++)
{
temp=asc2_1608[(unsigned int)num*16+pos];
for(t=0;t<8;t++)
{
if(temp&0x01) lcd_draw_point(x+t,y+pos,POINT_COLOR);
temp>>=1;
}
}
}
POINT_COLOR=colortemp;
}
实现字符串显示的函数为:
void LCD_ShowString(unsigned int x,unsigned int y,const char *p)
{
while(*p!='\0')
{
if(x>LCD_W-16)
{
x=0;
y+=16;
}
if(y>LCD_H-16)
{
y=x=0;
}
LCD_ShowChar(x,y,*p,1);
x+=8;
p++;
}
}
测试驱动效果的主程序为:
int main(void)
{
system_clock_config();
delay_init();
tft_config();
LCD_RESET();
tft_Init();
LCD_direction(2);
lcd_spi_test();
delay_ms(500);
LCD_Clear(RED);
BACK_COLOR=RED;
POINT_COLOR=WHITE;
LCD_ShowString(30,20,"AT32M413");
LCD_ShowString(30,40,"LCD TEST");
while(1);
}
经程序的编译及下载,其测试效果如图3所示,说明驱动正常且有效。
图3 测试效果
|