相较于OLED屏,LCD屏在色彩表现力和显示规格上都有较大的优势,对于LCD屏来说多采用SPI接口的方式工作。在显示驱动方面,除采用硬件的驱动方式,也可以模拟的方式来进行。该显示屏是一款1.8寸显示屏,其控制芯片为ST7735。
为此,需在RASC中先对所用的引脚加以配置,并生成以KEIL工程。
然后,在回到KEIL中进行程序的设计。
LCD屏的引脚连接关系为:
CS ----P209
REST----P206
DC ----P207
SDI ----P211
SCK ----P210
BL ----P208
为便于高低电平的输出控制,所进行的语句定义有:
#define LCD_CS_Set() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_09,BSP_IO_LEVEL_HIGH)
#define LCD_CS_Reset() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_09,BSP_IO_LEVEL_LOW)
#define LCD_REST_Set() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_06,BSP_IO_LEVEL_HIGH)
#define LCD_REST_Reset() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_06,BSP_IO_LEVEL_LOW)
#define LCD_DC_Set() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_07,BSP_IO_LEVEL_HIGH)
#define LCD_DC_Reset() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_07,BSP_IO_LEVEL_LOW)
#define LCD_SDI_Set() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_11,BSP_IO_LEVEL_HIGH)
#define LCD_SDI_Reset() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_11,BSP_IO_LEVEL_LOW)
#define LCD_SCK_Set() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_10,BSP_IO_LEVEL_HIGH)
#define LCD_SCK_Reset() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_10,BSP_IO_LEVEL_LOW)
#define LCD_BL_Set() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_08,BSP_IO_LEVEL_HIGH)
#define LCD_BL_Reset() R_IOPORT_PinWrite(&g_ioport_ctrl, BSP_IO_PORT_02_PIN_08,BSP_IO_LEVEL_LOW)
模拟SPI发送字节数据的函数为:
void LCD_SendByte(unsigned char com)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(com & 0x80)
{
LCD_SDI_Set();
}
else
{
LCD_SDI_Reset();
}
com = com << 1;
R_BSP_SoftwareDelay (3, BSP_DELAY_UNITS_MICROSECONDS);
LCD_SCK_Reset();
LCD_SCK_Set();
}
}
显示屏的初始化函数为:
void LCD_Init(void)
{
LCD_WR_REG(0x11);
R_BSP_SoftwareDelay(120 ,BSP_DELAY_UNITS_MILLISECONDS);
LCD_WR_REG(0xB1);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x2C);
LCD_WR_DATA8(0x2D);
LCD_WR_REG(0xB2);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x2C);
LCD_WR_DATA8(0x2D);
LCD_WR_REG(0xB3);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x2C);
LCD_WR_DATA8(0x2D);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x2C);
LCD_WR_DATA8(0x2D);
LCD_WR_REG(0xB4);
LCD_WR_DATA8(0x07);
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0xA2);
LCD_WR_DATA8(0x02);
LCD_WR_DATA8(0x84);
LCD_WR_REG(0xC1);
LCD_WR_DATA8(0xC5);
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0x0A);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x8A);
LCD_WR_DATA8(0x2A);
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x8A);
LCD_WR_DATA8(0xEE);
LCD_WR_REG(0xC5);
LCD_WR_DATA8(0x0E);
LCD_WR_REG(0x36);
LCD_WR_DATA8(0xC0);
LCD_WR_REG(0xe0);
LCD_WR_DATA8(0x0f);
LCD_WR_DATA8(0x1a);
LCD_WR_DATA8(0x0f);
LCD_WR_DATA8(0x18);
LCD_WR_DATA8(0x2f);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x20);
LCD_WR_DATA8(0x22);
LCD_WR_DATA8(0x1f);
LCD_WR_DATA8(0x1b);
LCD_WR_DATA8(0x23);
LCD_WR_DATA8(0x37);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x02);
LCD_WR_DATA8(0x10);
LCD_WR_REG(0xe1);
LCD_WR_DATA8(0x0f);
LCD_WR_DATA8(0x1b);
LCD_WR_DATA8(0x0f);
LCD_WR_DATA8(0x17);
LCD_WR_DATA8(0x33);
LCD_WR_DATA8(0x2c);
LCD_WR_DATA8(0x29);
LCD_WR_DATA8(0x2e);
LCD_WR_DATA8(0x30);
LCD_WR_DATA8(0x30);
LCD_WR_DATA8(0x39);
LCD_WR_DATA8(0x3f);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x10);
LCD_WR_REG(0x2a);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x7f);
LCD_WR_REG(0x2b);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x9f);
LCD_WR_REG(0xF0);
LCD_WR_DATA8(0x01);
LCD_WR_REG(0xF6);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x05);
LCD_WR_REG(0x29);
}
以色彩填充显示屏的函数为:
void LCD_Fill(uint16_t xsta,uint16_t ysta,uint16_t xend,uint16_t yend,uint16_t color)
{
uint16_t i,j;
LCD_Address_Set(xsta,ysta,xend-1,yend-1);
for(i=ysta;i<yend;i++)
{
for(j=xsta;j<xend;j++)
{
LCD_WR_DATA16(color);
}
}
}
字符串的显示函数为:
void LCD_ShowString(uint16_t x,uint16_t y,const uint8_t *p,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{
while(*p!='\\\\0')
{
LCD_ShowChar(x,y,*p,fc,bc,sizey,mode);
x+=sizey/2;
p++;
}
}
数值的显示函数为:
void LCD_ShowIntNum(uint16_t x,uint16_t y,uint16_t num,uint8_t len,uint16_t fc,uint16_t bc,uint8_t sizey)
{
uint8_t t,temp;
uint8_t enshow=0;
uint8_t sizex=sizey/2;
for(t=0;t<len;t++)
{
temp = (num/mypow(10, (uint8_t)(len-t-1)))%10;
if(enshow==0&&t<(len-1))
{
if(temp==0)
{
LCD_ShowChar(x+t*sizex,y,' ',fc,bc,sizey,0);
continue;
}else enshow=1;
}
LCD_ShowChar(x+t*sizex,y, (uint8_t)(temp+48),fc,bc,sizey,0);
}
}
汉字的显示函数为:
void LCD_Showhanzi16(unsigned int x,unsigned int y,unsigned char index,uint16_t fc,uint16_t bc)
{
unsigned char i,j,k;
const unsigned char *temp=hanzi16;
temp+=index*32;
LCD_Address_Set(x,y,x+16-1,y+16-1);
for(j=0;j<16;j++)
{
for(k=0;k<2;k++)
{
for(i=0;i<8;i++)
{
if((*temp&(1<<i))!=0)
{
LCD_WR_DATA16(fc);
}
else
{
LCD_WR_DATA16(bc);
}
}
temp++;
}
}
}
图标的显示函数为:
void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t length,uint16_t width, uint8_t *pic)
{
uint16_t i,j,c;
uint32_t k=0;
LCD_Address_Set(x,y,length-1,width-1);
for(i=0;i<length;i++)
{
for(j=0;j<width;j++)
{
c=pic[k*2]*256+pic[k*2+1];
LCD_WR_DATA16(c);
k++;
}
}
}
实现驱动测试的主程序为:
void hal_entry(void)
{
LCD_REST_Reset();
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_MILLISECONDS);
LCD_REST_Set();
R_BSP_SoftwareDelay(150, BSP_DELAY_UNITS_MILLISECONDS);
LCD_LED_Set();
LCD_Init();
LCD_Fill(0,0,LCD_W,LCD_H,BLUE);
R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS);
LCD_Fill(0,0,LCD_W,LCD_H,YELLOW);
R_BSP_SoftwareDelay(500, BSP_DELAY_UNITS_MILLISECONDS);
LCD_Fill(0,0,LCD_W,LCD_H,BLACK);
LCD_ShowString(32,50,(uint8_t *)"RA6M4",RED,BLACK,24,0);
LCD_ShowString(0,80,(uint8_t *)"SPI-LCD",BLUE,BLACK,32,0);
LCD_ShowIntNum(60,20,123,3,YELLOW,BLACK,16);
LCD_Showhanzi16(100,20,4,GREEN,BLACK);
LCD_Showhanzi16(100,40,5,GREEN,BLACK);
LCD_ShowPicture(0,0,40,40, Image_1);
while(1);
}
经程序的编译和下载,其测试效果如图2所示,说明驱动控制有效。

图1 器件连接

图2 显示效果
在此基础上,要实现硬件方式的驱动就有了一定的基础。
先在RASC的Stack中加入SPI,见图3所示。

图3 加入SPI
随后,按图4所示加以配参数置。在点击“Generate Project Content”后,即可生成Keil工程。

图4 配置参数
在完成引脚配置后,即可在生成的Keil工程中进行编程。
在硬件驱动方式下,它与模拟SPI方式的主要区别集中在数据的发送上面。
其替代的函数为:
void LCD_SendByte(uint8_t dat)
{
LCD_CS_Reset();
g_transfer_complete = false;
err = R_SPI_Write(&g_spi1_ctrl, &dat, 1, SPI_BIT_WIDTH_8_BITS);
assert(err == FSP_SUCCESS);
while(g_transfer_complete == false)
{
}
LCD_CS_Set();
}
此外,在初始化方面也有一些变化,就是在初始化显示屏之前,要先打开SPI,其语句为:
err = R_SCI_UART_Open(&g_uart9_ctrl, &g_uart9_cfg);
应注意的是,由于LCD显示屏在使用SPI硬件驱动后,在所引脚上会出现稍许的变动,要要调整引脚的连接。此时,所使用的引脚全集中在J5盒J6上,见图5所示。

图5 所用接口