本帖最后由 dirty 于 2024-6-29 21:59 编辑
本篇讲述使用沁恒CH32V208驱动LCD屏显示。
一.硬件准备
准备一块SPI接口LCD屏,分辨率128*160,驱动芯片ST7735。使用主控SPI2接口,硬件连接如下:
图1:LCD连接
LCD_BLK -- PB9
LCD_DC -- PB10
LCD_RST -- PB11
LCD_CS -- PB12
LCD_SCL -- PB13(SPI2_SCK)
LCD_SDA -- PB15(SPI2_MOSI)
二.代码准备
1.引脚宏定义与初始化
#define LCD_LED_RCC RCC_APB2Periph_GPIOB
#define LCD_LED_PORT GPIOB
#define LCD_LED_PIN (GPIO_Pin_9)
#define LCD_DC_RCC RCC_APB2Periph_GPIOB
#define LCD_DC_PORT GPIOB
#define LCD_DC_PIN (GPIO_Pin_10)
#define LCD_RST_RCC RCC_APB2Periph_GPIOB
#define LCD_RST_PORT GPIOB
#define LCD_RST_PIN (GPIO_Pin_11)
#define LCD_CS_RCC RCC_APB2Periph_GPIOB
#define LCD_CS_PORT GPIOB
#define LCD_CS_PIN (GPIO_Pin_12)
/*********************************************************************
* @fn SPI2_Init
*
* @brief Initialize SPI2
*
* @return none
*/
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
SPI_InitTypeDef SPI_InitStructure = {0};
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
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_Low;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);
}
/*********************************************************************
* @fn SPI2_DMA_Init
*
* @brief Initialize DMA for SPI2
*
* @return none
*/
void SPI2_DMA_Init()
{
DMA_InitTypeDef DMA_InitStructure = {0};
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
DMA_DeInit(SPI2_DMA_TX_CH);
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&SPI2->DATAR;
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)NULL;
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize = 0;
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
DMA_Init(SPI2_DMA_TX_CH, &DMA_InitStructure);
SPI_I2S_DMACmd(SPI2, SPI_I2S_DMAReq_Tx, ENABLE);
}
/*********************************************************************
* @fn LCD_GPIOInit
*
* @brief Configuring the control gpio for the lcd screen
*
* @return none
*/
void LCD_GPIOInit(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(LCD_LED_RCC, ENABLE);
RCC_APB2PeriphClockCmd(LCD_DC_RCC, ENABLE);
RCC_APB2PeriphClockCmd(LCD_RST_RCC, ENABLE);
RCC_APB2PeriphClockCmd(LCD_CS_RCC, ENABLE);
GPIO_InitStructure.GPIO_Pin = LCD_LED_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LCD_LED_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD_DC_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LCD_DC_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD_RST_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LCD_RST_PORT, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = LCD_CS_PIN;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(LCD_CS_PORT, &GPIO_InitStructure);
}
2.LCD写命令函数
/*********************************************************************
* @fn SPI2_Write
*
* @brief send one byte
*
* @param data - the data to send
*
* @return none
*/
void SPI2_Write(uint8_t data)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET)
;
SPI_I2S_SendData(SPI2, data);
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_BSY) == SET)
;
}
/*********************************************************************
* @fn LCD_WR_REG
*
* @brief Write an 8-bit command to the LCD screen
*
* @param data - Command value to be written
*
* @return none
*/
static void LCD_WR_REG(uint8_t data)
{
LCD_CS_CLR;
LCD_DC_CLR;
SPI2_Write(data);
LCD_CS_SET;
}
3.LCD写数据函数
/*********************************************************************
* @fn LCD_WR_DATA
*
* @brief Write an 8-bit data to the LCD screen
*
* @param data - the data to write
*
*/
static void LCD_WR_DATA(uint8_t data)
{
LCD_CS_CLR;
LCD_DC_SET;
SPI2_Write(data);
LCD_CS_SET;
}
4.LCD设置显示方向及像素宏定义。
/* LCD Screen Definition */
#define USE_HORIZONTAL 0
#define LCD_W (128u)//(240u)
#define LCD_H (160u)//(320u)
/*********************************************************************
* @fn LCD_Init
*
* @brief Initialization LCD screen
*
* @return none
*/
void LCD_Init(void)
{
SPI2_Init();
SPI2_DMA_Init();
LCD_GPIOInit();
LCD_RESET();
LCD_LED_SET;
//LCD Init For 1.44Inch LCD Panel with ST7735R.
LCD_WR_REG(0x11);//Sleep exit
Delay_Ms(120);
#if 1
LCD_WR_REG(0xB1);
LCD_WR_DATA(0x00);//0x05
LCD_WR_DATA(0x08);//0x3A
LCD_WR_DATA(0x05);//0x3A
LCD_WR_REG(0xB2);
LCD_WR_DATA(0x05);
LCD_WR_DATA(0x3A);
LCD_WR_DATA(0x3A);
LCD_WR_REG(0xB3);
LCD_WR_DATA(0x05);
LCD_WR_DATA(0x3A);
LCD_WR_DATA(0x3A);
LCD_WR_DATA(0x05);
LCD_WR_DATA(0x3A);
LCD_WR_DATA(0x3A);
//------------------------------------End ST7735S Frame Rate-----------------------------------------//
LCD_WR_REG(0xB4); //Dot inversion
LCD_WR_DATA(0x03);
//------------------------------------ST7735S Power Sequence-----------------------------------------//
LCD_WR_REG(0xC0);
LCD_WR_DATA(0x62);
LCD_WR_DATA(0x02);
LCD_WR_DATA(0x04);
LCD_WR_REG(0xC1);
LCD_WR_DATA(0xC0);
LCD_WR_REG(0xC2);
LCD_WR_DATA(0x0D);
LCD_WR_DATA(0x00);
LCD_WR_REG(0xC3);
LCD_WR_DATA(0x8D);
LCD_WR_DATA(0x6A);
LCD_WR_REG(0xC4);
LCD_WR_DATA(0x8D);
LCD_WR_DATA(0xEE);
//---------------------------------End ST7735S Power Sequence-------------------------------------//
LCD_WR_REG(0xC5); //VCOM
LCD_WR_DATA(0x08);//0x12
//------------------------------------ST7735S Gamma Sequence-----------------------------------------//
LCD_WR_REG(0xE0);
LCD_WR_DATA(0x03);
LCD_WR_DATA(0x1B);
LCD_WR_DATA(0x12);
LCD_WR_DATA(0x11);
LCD_WR_DATA(0x3F);
LCD_WR_DATA(0x3A);
LCD_WR_DATA(0x32);
LCD_WR_DATA(0x34);
LCD_WR_DATA(0x2F);
LCD_WR_DATA(0x2B);
LCD_WR_DATA(0x30);
LCD_WR_DATA(0x3A);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x01);
LCD_WR_DATA(0x02);
LCD_WR_DATA(0x05);
LCD_WR_REG(0xE1);
LCD_WR_DATA(0x03);
LCD_WR_DATA(0x1B);
LCD_WR_DATA(0x12);
LCD_WR_DATA(0x11);
LCD_WR_DATA(0x32);
LCD_WR_DATA(0x2F);
LCD_WR_DATA(0x2A);
LCD_WR_DATA(0x2F);
LCD_WR_DATA(0x2E);
LCD_WR_DATA(0x2C);
LCD_WR_DATA(0x35);
LCD_WR_DATA(0x3F);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x01);
LCD_WR_DATA(0x05);
//------------------------------------End ST7735S Gamma Sequence-----------------------------------------//
LCD_WR_REG(0x3A); //65k mode
LCD_WR_DATA(0x05);
//LCD_WR_REG(0x36); //65k mode
//LCD_WR_DATA(0x40);
LCD_direction(USE_HORIZONTAL);//设置图像旋转角度
LCD_WR_REG(0x29); //Display on
LCD_WR_REG(0x2C);
LCD_WR_REG(0x29);//Display on
}
5.清屏
/*********************************************************************
* @fn LCD_Clear
*
* @brief Full screen filled LCD screen
*
* @param Color - Filled color
*
* @return none
*/
void LCD_Clear(uint16_t Color)
{
unsigned int i, m;
LCD_SetWindows(0, 0, width - 1, height - 1);
LCD_CS_CLR;
LCD_DC_SET;
//LCD_WR_REG(0x2C);//add
for (i = 0; i < height; i++)
{
for (m = 0; m < width; m++)
{
LCD_WR_DATA_16Bit(Color);
}
}
LCD_CS_SET;
}
6.设置区域
/*********************************************************************
* @fn LCD_SetWindows
*
* @brief Setting LCD display window
*
* @param xStar - the bebinning x coordinate of the LCD display window
* yStar - the bebinning y coordinate of the LCD display window
* xEnd - the endning x coordinate of the LCD display window
* yEnd - the endning y coordinate of the LCD display window
*
* @return none
*/
void LCD_SetWindows(uint16_t xStar, uint16_t yStar, uint16_t xEnd, uint16_t yEnd)
{
LCD_WR_REG(LCD_SET_X);
LCD_WR_DATA(xStar >> 8);
LCD_WR_DATA(0x00FF & xStar);
LCD_WR_DATA(xEnd >> 8);
LCD_WR_DATA(0x00FF & xEnd);
LCD_WR_REG(LCD_SET_Y);
LCD_WR_DATA(yStar >> 8);
LCD_WR_DATA(0x00FF & yStar);
LCD_WR_DATA(yEnd >> 8);
LCD_WR_DATA(0x00FF & yEnd);
LCD_WR_REG(LCD_MEM_WRITE);
}
7.显示图片。使用图片取模软件Img2Lcd生成图片字模数组。
/******************************************************************************
函数说明:显示图片
入口数据:x,y起点坐标
length 图片长度
width 图片宽度
pic[] 图片数组
返回值: 无
******************************************************************************/
void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t length,uint16_t width,const uint8_t pic[])
{
uint16_t i,j;
uint32_t k=0;
unsigned char picH,picL;
// Lcd_SetRegion(x,y,x+length-1,y+width-1);
LCD_SetWindows(x,y,x+length-1,y+width-1);
for(i=0;i<length;i++)
{
for(j=0;j<width;j++)
{
picL=*(pic+k*2); //数据低位在前
picH=*(pic+k*2+1);
LCD_WR_DATA_16Bit(picH<<8|picL);
k++;
}
}
}
8.设计显示界面,开机刷屏红、绿、蓝,然后显示沁恒LOGO及开发板照片。
int main(void)
{
// uint32_t addr = 0;
// uint16_t i = 0;
SystemCoreClockUpdate();
Delay_Init();
USART_Printf_Init(115200);
printf("SystemClk:%d\r\n", SystemCoreClock);
//SPI_FLASH_Init();
LCD_Init();
printf("LCD_Init\r\n");
LCD_Clear(LCD_RED);
Delay_Ms(1000);
printf("LCD_RED\r\n");
LCD_Clear(LCD_GRED);
Delay_Ms(1000);
printf("LCD_GRED\r\n");
LCD_Clear(LCD_BLUE);
Delay_Ms(1000);
printf("LCD_BLUE\r\n");
LCD_ShowPicture(0,0,128,25,gImage_img_logo);
LCD_ShowPicture(0,25,128,135,gImage_img_board);
while (1)
{
Delay_Ms(2000);
// addr = 0;
// i = 0;
// while (i < 11)
// {
// i++;
// LCD_drawImageWithSize(0, 0, LCD_W, LCD_H, addr);
// addr += (LCD_W * LCD_H * COLOR_BYTE);
// }
}
}
三.测验
编译烧录后,LCD竖屏显示红、绿、蓝,最后显示图片界面。
图2:LCD显示
至此,实现LCD驱动显示。