本帖最后由 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 测试效果
|