dirty 发表于 2024-6-29 21:55

【全能小网关|CH32V208】--4.LCD显示

<div class='showpostmsg'> 本帖最后由 dirty 于 2024-6-29 21:59 编辑

<p>&nbsp; &nbsp; &nbsp; 本篇讲述使用沁恒CH32V208驱动LCD屏显示。</p>

<p><strong><span style="color:#0000ff;">一.硬件准备</span></strong></p>

<p>&nbsp; &nbsp; &nbsp; 准备一块SPI接口LCD屏,分辨率128*160,驱动芯片ST7735。使用主控SPI2接口,硬件连接如下:</p>

<div style="text-align: center;"></div>

<div style="text-align: center;">图1:LCD连接</div>

<p>&nbsp; &nbsp; LCD_BLK&nbsp; &nbsp; -- PB9<br />
&nbsp; &nbsp; LCD_DC &nbsp; &nbsp; -- PB10<br />
&nbsp; &nbsp; LCD_RST &nbsp; &nbsp;-- PB11<br />
&nbsp; &nbsp; LCD_CS &nbsp; &nbsp; -- PB12<br />
&nbsp; &nbsp; LCD_SCL&nbsp; &nbsp; -- PB13(SPI2_SCK)&nbsp; &nbsp;<br />
&nbsp; &nbsp; LCD_SDA&nbsp; &nbsp;-- PB15(SPI2_MOSI)&nbsp;</p>

<p>&nbsp;</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&amp;uid=159083" target="_blank">@brief </a>Initialize SPI2
*
* <a href="home.php?mod=space&amp;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, &amp;GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin= GPIO_Pin_14;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOB, &amp;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, &amp;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, &amp;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)&amp;SPI2-&gt;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, &amp;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, &amp;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, &amp;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, &amp;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, &amp;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 &lt; height; i++)
    {
      for (m = 0; m &lt; 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 &gt;&gt; 8);
    LCD_WR_DATA(0x00FF &amp; xStar);
    LCD_WR_DATA(xEnd &gt;&gt; 8);
    LCD_WR_DATA(0x00FF &amp; xEnd);

    LCD_WR_REG(LCD_SET_Y);
    LCD_WR_DATA(yStar &gt;&gt; 8);
    LCD_WR_DATA(0x00FF &amp; yStar);
    LCD_WR_DATA(yEnd &gt;&gt; 8);
    LCD_WR_DATA(0x00FF &amp; 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&lt;length;i++)
    {
      for(j=0;j&lt;width;j++)
      {
            picL=*(pic+k*2);//数据低位在前
            picH=*(pic+k*2+1);
            LCD_WR_DATA_16Bit(picH&lt;&lt;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 &lt; 11)
//      {
//            i++;
//            LCD_drawImageWithSize(0, 0, LCD_W, LCD_H, addr);
//            addr += (LCD_W * LCD_H * COLOR_BYTE);
//      }
    }
}</code></pre>

<p>&nbsp;</p>

<p><strong><span style="color:#0000ff;">三.测验</span></strong></p>

<p>&nbsp; &nbsp; &nbsp; 编译烧录后,LCD竖屏显示红、绿、蓝,最后显示图片界面。</p>

<div style="text-align: center;">
<div style="text-align: center;"></div>

<p>&nbsp;</p>
</div>

<div style="text-align: center;">图2:LCD显示</div>

<div style="text-align: center;">38f2312badca0396cd4b29c6746164b1<br />
&nbsp;</div>

<p>&nbsp; &nbsp; 至此,实现LCD驱动显示。</p>

<p>&nbsp;</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>

lugl4313820 发表于 2024-6-30 06:59

看起来刷新的速度非常快呀。

wangerxian 发表于 2024-6-30 11:44

<p>内部Flash是不是存不了多少图片?</p>

秦天qintian0303 发表于 2024-7-1 10:21

<p>感觉LCD显示功能不是全能小网关|CH32V208的主要对象</p>

dirty 发表于 2024-7-16 13:41

wangerxian 发表于 2024-6-30 11:44
内部Flash是不是存不了多少图片?

<p>有些小技巧,在Link.ld文件做下配置修改</p>

dirty 发表于 2024-7-16 13:42

lugl4313820 发表于 2024-6-30 06:59
看起来刷新的速度非常快呀。

<p>硬件spi,速度还是可以的</p>
页: [1]
查看完整版本: 【全能小网关|CH32V208】--4.LCD显示