【全能小网关|CH32V208】--4.LCD显示
<div class='showpostmsg'> 本帖最后由 dirty 于 2024-6-29 21:59 编辑<p> 本篇讲述使用沁恒CH32V208驱动LCD屏显示。</p>
<p><strong><span style="color:#0000ff;">一.硬件准备</span></strong></p>
<p> 准备一块SPI接口LCD屏,分辨率128*160,驱动芯片ST7735。使用主控SPI2接口,硬件连接如下:</p>
<div style="text-align: center;"></div>
<div style="text-align: center;">图1:LCD连接</div>
<p> LCD_BLK -- PB9<br />
LCD_DC -- PB10<br />
LCD_RST -- PB11<br />
LCD_CS -- PB12<br />
LCD_SCL -- PB13(SPI2_SCK) <br />
LCD_SDA -- PB15(SPI2_MOSI) </p>
<p> </p>
<p><strong><span style="color:#0000ff;">二.代码准备</span></strong></p>
<p>1.引脚宏定义与初始化</p>
<pre>
<code>#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
*
* <a href="home.php?mod=space&uid=159083" target="_blank">@brief </a>Initialize SPI2
*
* <a href="home.php?mod=space&uid=784970" target="_blank">@return </a>none
*/
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure = {0};
SPI_InitTypeDefSPI_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
*
* @returnnone
*/
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
*
* @returnnone
*/
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);
}
</code></pre>
<p>2.LCD写命令函数</p>
<pre>
<code>/*********************************************************************
* @fn SPI2_Write
*
* @brief send one byte
*
* @param data -the data to send
*
* @returnnone
*/
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
*
* @returnnone
*/
static void LCD_WR_REG(uint8_t data)
{
LCD_CS_CLR;
LCD_DC_CLR;
SPI2_Write(data);
LCD_CS_SET;
}</code></pre>
<p>3.LCD写数据函数</p>
<pre>
<code>/*********************************************************************
* @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;
}</code></pre>
<p>4.LCD设置显示方向及像素宏定义。</p>
<pre>
<code>/* LCD Screen Definition */
#define USE_HORIZONTAL 0
#define LCD_W (128u)//(240u)
#define LCD_H (160u)//(320u)
/*********************************************************************
* @fn LCD_Init
*
* @brief Initialization LCD screen
*
* @returnnone
*/
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
}
</code></pre>
<p>5.清屏</p>
<pre>
<code>/*********************************************************************
* @fn LCD_Clear
*
* @brief Full screen filled LCD screen
*
* @param Color - Filled color
*
* @returnnone
*/
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;
}</code></pre>
<p>6.设置区域</p>
<pre>
<code>/*********************************************************************
* @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
*
* @returnnone
*/
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);
}
</code></pre>
<p>7.显示图片。使用图片取模软件Img2Lcd生成图片字模数组。</p>
<pre>
<code>/******************************************************************************
函数说明:显示图片
入口数据: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++;
}
}
}
</code></pre>
<p>8.设计显示界面,开机刷屏红、绿、蓝,然后显示沁恒LOGO及开发板照片。</p>
<pre>
<code>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);
// }
}
}</code></pre>
<p> </p>
<p><strong><span style="color:#0000ff;">三.测验</span></strong></p>
<p> 编译烧录后,LCD竖屏显示红、绿、蓝,最后显示图片界面。</p>
<div style="text-align: center;">
<div style="text-align: center;"></div>
<p> </p>
</div>
<div style="text-align: center;">图2:LCD显示</div>
<div style="text-align: center;">38f2312badca0396cd4b29c6746164b1<br />
</div>
<p> 至此,实现LCD驱动显示。</p>
<p> </p>
</div><script> var loginstr = '<div class="locked">查看本帖全部内容,请<a href="javascript:;" style="color:#e60000" class="loginf">登录</a>或者<a href="https://bbs.eeworld.com.cn/member.php?mod=register_eeworld.php&action=wechat" style="color:#e60000" target="_blank">注册</a></div>';
if(parseInt(discuz_uid)==0){
(function($){
var postHeight = getTextHeight(400);
$(".showpostmsg").html($(".showpostmsg").html());
$(".showpostmsg").after(loginstr);
$(".showpostmsg").css({height:postHeight,overflow:"hidden"});
})(jQuery);
} </script><script type="text/javascript">(function(d,c){var a=d.createElement("script"),m=d.getElementsByTagName("script"),eewurl="//counter.eeworld.com.cn/pv/count/";a.src=eewurl+c;m.parentNode.insertBefore(a,m)})(document,523)</script> 看起来刷新的速度非常快呀。 <p>内部Flash是不是存不了多少图片?</p>
<p>感觉LCD显示功能不是全能小网关|CH32V208的主要对象</p>
wangerxian 发表于 2024-6-30 11:44
内部Flash是不是存不了多少图片?
<p>有些小技巧,在Link.ld文件做下配置修改</p>
lugl4313820 发表于 2024-6-30 06:59
看起来刷新的速度非常快呀。
<p>硬件spi,速度还是可以的</p>
页:
[1]