打印
[STM32L4+]

【STEVAL-STWINKT1B测评】6、驱动LCD屏

[复制链接]
298|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ev, TE, ST, LCD, CD, win
一、介绍
STEVAL-STWINKT1B开发板虽然没有板载的显示屏,但是预留了40Pin的扩展接口,和一个STMod+的接口,可以很方便地连接一些扩展模块。


本次我们通过40PIN的连接器连接我们的一块LCD屏,通过LCD屏显示之前用到的传感器采集到的信息,本次只做简单的显示功能,并不包含GUI的移植。
GUI又是另外一个大的topic了,不在本次的测评范围内。

二、硬件连接
LCD屏选的是DFROBOT的一款2寸的IPS屏。详细介绍如下:

2.0寸LCD显示模块采用ST7789V驱动芯片,具有320x240个彩色像素点(RGB565)。这是一款IPS显示模块,拥有优秀的可视角度(80/80/80/80);采用SPI(4线)通信方式;支持GDI接口(GDI接口必须和带GDI接口主控配合使用),即插即用。模块具有分辨率高、可视角度广、接线简单等优点,可用于许多显示应用:波形显示器、电子纪念盒、桌面天气摆件等。

2.0寸LCD显示模块支持3.3V和5V,并兼容多个主控:UNO、Leonardo、ESP32、ESP8266、FireBeetle M0等。与M0配合使用GDI接口,即插即用,有效减少接线步骤。模块板载了MicroSD Card卡槽,用户可以显示更多的图片。



引脚说明:

标号
名称
功能描述

1VCC电源正极
2GND电源负极
3SCLK时钟
4MOSI数据(主机发送从机接收)
5MISO数据(主机接收从机发送
6CS屏幕片选
7RES复位
8DC数据/命令
9BL背光。背光设定了默认值,用户不用连接背光引脚也可点亮;此外,连接背光引脚,输入高电平(1)是将背光亮度调到最大,输入低电平(0)是关闭背光
10SDCSSD卡片选
LCD屏与开发板的引脚连接:
序号 LCD引脚 MCU引脚 备注
1 VCC
3.3v 连接器第40脚(SYS)
2 GND GND 连接器第5脚(GND)
3 SCLK PB13 连接器第1脚(SPI2 SCLK)
4 MOSI PB15 连接器第8脚(SPI2 MOSI)
5 MISO PC2 连接器第9脚(SPI2 MISO)
6 CS PG12连接器第17脚(GPIO)
7 RES PG9 连接器第19脚(GPIO)
8 DC PG10 连接器第18脚(GPIO)
9 BL - 悬空
10 SDCS - 悬空


因为开发板是FPC接口,但是LCD显示屏是2.54插针的接口,无法直接通过杜邦线连接,所以用了一个FPC转2.54的一个转接板,整体接线如下:


三、程序
因为该LCD是SPI接口的,所以我们需要对开发板的spi进行配置,SPI选的是SPI2,详细的配置如下:


LCD驱动程序如下:
/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * File Name          : lcd.c
  * Description        : Code for lcd application
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include <string.h>
#include "lcd.h"
#include "spi.h"
#include "FONT.H"
/* Private includes ----------------------------------------------------------*/

/* Private typedef -----------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/

/* Private macro -------------------------------------------------------------*/

/* Private variables ---------------------------------------------------------*/
HAL_StatusTypeDef spi_status = HAL_OK;
/* Private function prototypes -----------------------------------------------*/

/* Private application code --------------------------------------------------*/

/******************************************************************************
      函数说明:LCD串行数据写入函数
      入口数据:dat  要写入的串行数据
      返回值:  无
******************************************************************************/
void LCD_Writ_Bus(uint8_t data)
{       
//        uint8_t i;
        LCD_CS_L;
        spi_status = HAL_SPI_Transmit(&hspi2,&data,1,0xff);
          //spi_status = HAL_SPI_Transmit_DMA(&hspi1,&data,1);
          LCD_CS_H;       
}


/******************************************************************************
      函数说明:LCD写入数据
      入口数据:dat 写入的数据
      返回值:  无
******************************************************************************/
void LCD_WR_DATA8(uint8_t dat)
{
        LCD_Writ_Bus(dat);
}


/******************************************************************************
      函数说明:LCD写入数据
      入口数据:dat 写入的数据
      返回值:  无
******************************************************************************/
void LCD_WR_DATA16(uint16_t dat)
{
        LCD_Writ_Bus(dat>>8);
        LCD_Writ_Bus(dat);
}


/******************************************************************************
      函数说明:LCD写入命令
      入口数据:dat 写入的命令
      返回值:  无
******************************************************************************/
void LCD_WR_CMD(uint8_t dat)
{
        LCD_DC_L;//写命令
        LCD_Writ_Bus(dat);
        LCD_DC_H;//写数据
}


/******************************************************************************
      函数说明:设置起始和结束地址
      入口数据:x1,x2 设置列的起始和结束地址
                y1,y2 设置行的起始和结束地址
      返回值:  无
******************************************************************************/
void LCD_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
if(USE_HORIZONTAL==0)
        {
                LCD_WR_CMD(0x2a);//列地址设置
                LCD_WR_DATA16(x1);
                LCD_WR_DATA16(x2);
                LCD_WR_CMD(0x2b);//行地址设置
                LCD_WR_DATA16(y1);
                LCD_WR_DATA16(y2);
                LCD_WR_CMD(0x2c);//储存器写
        }
        else if(USE_HORIZONTAL==1)
        {
                LCD_WR_CMD(0x2a);//列地址设置
                LCD_WR_DATA16(x1);
                LCD_WR_DATA16(x2);
                LCD_WR_CMD(0x2b);//行地址设置
                LCD_WR_DATA16(y1+80);
                LCD_WR_DATA16(y2+80);
                LCD_WR_CMD(0x2c);//储存器写
        }
        else if(USE_HORIZONTAL==2)
        {
                LCD_WR_CMD(0x2a);//列地址设置
                LCD_WR_DATA16(x1);
                LCD_WR_DATA16(x2);
                LCD_WR_CMD(0x2b);//行地址设置
                LCD_WR_DATA16(y1);
                LCD_WR_DATA16(y2);
                LCD_WR_CMD(0x2c);//储存器写
        }
        else
        {
                LCD_WR_CMD(0x2a);//列地址设置
                LCD_WR_DATA16(x1+80);
                LCD_WR_DATA16(x2+80);
                LCD_WR_CMD(0x2b);//行地址设置
                LCD_WR_DATA16(y1);
                LCD_WR_DATA16(y2);
                LCD_WR_CMD(0x2c);//储存器写
        }
}


/******************************************************************************
      函数说明:液晶初始化
      入口数据:无
      返回值:  无
******************************************************************************/

void LCD_Init(void)
{
//        LCD_GPIO_Init();//初始化GPIO
       
        LCD_RES_L;//复位
        osDelay(100);
        LCD_RES_H;
        osDelay(100);
       
        LCD_WR_CMD(0x11);                                             //无此指令,不能正常初始化芯片,无显示
        osDelay(120);
        LCD_WR_CMD(0x36);                                             //设置内存扫描方向,0X00正常扫描,从上往下,从左往右,RGB方式
        if(USE_HORIZONTAL==0)LCD_WR_DATA8(0x00);
        else if(USE_HORIZONTAL==1)LCD_WR_DATA8(0xC0);
        else if(USE_HORIZONTAL==2)LCD_WR_DATA8(0x70);
        else LCD_WR_DATA8(0xA0);

        LCD_WR_CMD(0x3A);                                             //数据格式,65K色,565
        LCD_WR_DATA8(0x05);

        LCD_WR_CMD(0xB2);                                             //帧频设置
        LCD_WR_DATA8(0x0C);
        LCD_WR_DATA8(0x0C);
        LCD_WR_DATA8(0x00);
        LCD_WR_DATA8(0x33);
        LCD_WR_DATA8(0x33);

  LCD_WR_CMD(0xC6);                                               //正常模式下的帧速率控制
//  LCD_WR_DATA8(0x01);                                            //正常模式下:屏幕刷新率 111Hz
  LCD_WR_DATA8(0x1F);                                            //正常模式下:屏幕刷新率 39Hz
  
        LCD_WR_CMD(0xB7);                                             //GATE 设置
        LCD_WR_DATA8(0x35);  

        LCD_WR_CMD(0xBB);                                             //VCOM设置
        LCD_WR_DATA8(0x19);

        LCD_WR_CMD(0xC0);                                             //LCM设置,默认0x2c
        LCD_WR_DATA8(0x2C);

        LCD_WR_CMD(0xC2);                                             //VDV&VRH SET ,默认0x01
        LCD_WR_DATA8(0x01);

        LCD_WR_CMD(0xC3);                                             //VRHS SET,默认0x0b
        LCD_WR_DATA8(0x12);                                           //此处根据实际情况修正

        LCD_WR_CMD(0xC4);                                             //VDV SET,默认0x20
        LCD_WR_DATA8(0x20);  

        LCD_WR_CMD(0xC6);                                             // FR SET, 默认0x0F
        LCD_WR_DATA8(0x0F);   

        LCD_WR_CMD(0xD0);                                             //电源控制1
        LCD_WR_DATA8(0xA4);                                           //该参数不变  
        LCD_WR_DATA8(0xA1);                                           //此处根据实际情况修改

        LCD_WR_CMD(0xE0);                                             //正极性GAMMA调整
        LCD_WR_DATA8(0xD0);
        LCD_WR_DATA8(0x04);
        LCD_WR_DATA8(0x0D);
        LCD_WR_DATA8(0x11);
        LCD_WR_DATA8(0x13);
        LCD_WR_DATA8(0x2B);
        LCD_WR_DATA8(0x3F);
        LCD_WR_DATA8(0x54);
        LCD_WR_DATA8(0x4C);
        LCD_WR_DATA8(0x18);
        LCD_WR_DATA8(0x0D);
        LCD_WR_DATA8(0x0B);
        LCD_WR_DATA8(0x1F);
        LCD_WR_DATA8(0x23);

        LCD_WR_CMD(0xE1);                                              //负极性GAMMA调整
        LCD_WR_DATA8(0xD0);
        LCD_WR_DATA8(0x04);
        LCD_WR_DATA8(0x0C);
        LCD_WR_DATA8(0x11);
        LCD_WR_DATA8(0x13);
        LCD_WR_DATA8(0x2C);
        LCD_WR_DATA8(0x3F);
        LCD_WR_DATA8(0x44);
        LCD_WR_DATA8(0x51);
        LCD_WR_DATA8(0x2F);
        LCD_WR_DATA8(0x1F);
        LCD_WR_DATA8(0x1F);
        LCD_WR_DATA8(0x20);
        LCD_WR_DATA8(0x23);

        LCD_WR_CMD(0x21);                                             //反显开,默认是0X20,正常模式
  
        LCD_WR_CMD(0x29);                                             //显示开,等待MCU数传送
}


/******************************************************************************
      函数说明:LCD清屏函数
      入口数据:无
      返回值:  无
******************************************************************************/
void LCD_Clear(uint16_t Color)
{
        uint16_t i,j;         
        LCD_Address_Set(0,0,LCD_WIDTH-1,LCD_HEIGHT-1);
    for(i=0;i<LCD_WIDTH;i++)
         {
          for (j=0;j<LCD_HEIGHT;j++)
                   {
                LCD_WR_DATA16(Color);                                  
            }

          }
}


/******************************************************************************
      函数说明:在指定区域填充颜色
      入口数据:xsta,ysta   起始坐标
                xend,yend   终止坐标
                                                                color       要填充的颜色
      返回值:  无
******************************************************************************/
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);
                }
        }                                                       
}

/******************************************************************************
      函数说明:在指定位置画点
      入口数据:x,y 画点坐标
                color 点的颜色
      返回值:  无
******************************************************************************/
void LCD_DrawPoint(uint16_t x,uint16_t y,uint16_t color)
{
        LCD_Address_Set(x,y,x,y);//设置光标位置
        LCD_WR_DATA16(color);
}


/******************************************************************************
      函数说明:画线
      入口数据:x1,y1   起始坐标
                x2,y2   终止坐标
                color   线的颜色
      返回值:  无
******************************************************************************/
void LCD_DrawLine(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t color)
{
        uint16_t t;
        int xerr=0,yerr=0,delta_x,delta_y,distance;
        int incx,incy,uRow,uCol;
        delta_x=x2-x1; //计算坐标增量
        delta_y=y2-y1;
        uRow=x1;//画线起点坐标
        uCol=y1;
        if(delta_x>0)incx=1; //设置单步方向
        else if (delta_x==0)incx=0;//垂直线
        else {incx=-1;delta_x=-delta_x;}
        if(delta_y>0)incy=1;
        else if (delta_y==0)incy=0;//水平线
        else {incy=-1;delta_y=-delta_y;}
        if(delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
        else distance=delta_y;
        for(t=0;t<distance+1;t++)
        {
                LCD_DrawPoint(uRow,uCol,color);//画点
                xerr+=delta_x;
                yerr+=delta_y;
                if(xerr>distance)
                {
                        xerr-=distance;
                        uRow+=incx;
                }
                if(yerr>distance)
                {
                        yerr-=distance;
                        uCol+=incy;
                }
        }
}


/******************************************************************************
      函数说明:画矩形
      入口数据:x1,y1   起始坐标
                x2,y2   终止坐标
                color   矩形的颜色
      返回值:  无
******************************************************************************/
void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2,uint16_t color)
{
        LCD_DrawLine(x1,y1,x2,y1,color);
        LCD_DrawLine(x1,y1,x1,y2,color);
        LCD_DrawLine(x1,y2,x2,y2,color);
        LCD_DrawLine(x2,y1,x2,y2,color);
}


/******************************************************************************
      函数说明:画圆
      入口数据:x0,y0   圆心坐标
                r       半径
                color   圆的颜色
      返回值:  无
******************************************************************************/
void Draw_Circle(uint16_t x0,uint16_t y0,uint8_t r,uint16_t color)
{
        int a,b;
        a=0;b=r;          
        while(a<=b)
        {
                LCD_DrawPoint(x0-b,y0-a,color);             //3           
                LCD_DrawPoint(x0+b,y0-a,color);             //0           
                LCD_DrawPoint(x0-a,y0+b,color);             //1               
                LCD_DrawPoint(x0-a,y0-b,color);             //2            
                LCD_DrawPoint(x0+b,y0+a,color);             //4               
                LCD_DrawPoint(x0+a,y0-b,color);             //5
                LCD_DrawPoint(x0+a,y0+b,color);             //6
                LCD_DrawPoint(x0-b,y0+a,color);             //7
                a++;
                if((a*a+b*b)>(r*r))//判断要画的点是否过远
                {
                        b--;
                }
        }
}

/******************************************************************************
      函数说明:显示单个字符
      入口数据:x,y显示坐标
                num 要显示的字符
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowChar(uint16_t x,uint16_t y,uint8_t num,uint16_t fc,uint16_t bc,uint8_t sizey,uint8_t mode)
{
        uint8_t temp,sizex,t,m=0;
        uint16_t i,TypefaceNum;//一个字符所占字节大小
        uint16_t x0=x;
        sizex=sizey/2;
        TypefaceNum=(sizex/8+((sizex%8)?1:0))*sizey;
        num=num-' ';    //得到偏移后的值
        LCD_Address_Set(x,y,x+sizex-1,y+sizey-1);  //设置光标位置
        for(i=0;i<TypefaceNum;i++)
        {
                if(sizey==12)temp=asc2_1206[num][i];                       //调用6x12字体
                else if(sizey==16)temp=asc2_1608[num][i];                 //调用8x16字体
                // else if(sizey==24)temp=asc2_2412[num][i];                 //调用12x24字体
                // else if(sizey==32)temp=asc2_1206[num][i];                 //调用16x32字体
                else return;
                for(t=0;t<8;t++)
                {
                        if(!mode)//非叠加模式
                        {
                                if(temp&(0x01<<t))LCD_WR_DATA16(fc);
                                else LCD_WR_DATA16(bc);
                                m++;
                                if(m%sizex==0)
                                {
                                        m=0;
                                        break;
                                }
                        }
                        else//叠加模式
                        {
                                if(temp&(0x01<<t))LCD_DrawPoint(x,y,fc);//画一个点
                                x++;
                                if((x-x0)==sizex)
                                {
                                        x=x0;
                                        y++;
                                        break;
                                }
                        }
                }
        }                      
}

/******************************************************************************
      函数说明:显示字符串
      入口数据:x,y显示坐标
                *p 要显示的字符串
                fc 字的颜色
                bc 字的背景色
                sizey 字号
                mode:  0非叠加模式  1叠加模式
      返回值:  无
******************************************************************************/
void LCD_ShowString(uint16_t x,uint16_t y,const char *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++;
        }  
}
然后在主函数中调用显示函数去更新屏幕显示:
#include "lcd.h"
#include "stts751.h"
#include "lps22hh.h"
#include "hts221.h"
#include <stdio.h>

#define DISPLAY_X_POS       (0U)
#define DISPLAY_Y_POS       (80U)
#define DISPLAY_X_STEP      (0U)
#define DISPLAY_Y_STEP      (20U)
#define DISPLAY_Y_BAIS      (20U)

void display_data( void )
{
    uint8_t str_buffer[100];
    //  获取stts751的数据
    float temp = stts751_get_temperature();
    sprintf((char *)str_buffer, "STTS751 Temp:%3.2f C", temp);
    LCD_ShowString(DISPLAY_X_POS, DISPLAY_Y_POS, (char *)str_buffer, BLUE, YELLOW, 16, 0);

    //  获取lps22hh的数据
    temp = lps22hh_get_temperature();
    sprintf((char *)str_buffer, "LPS22HH Temp:%3.2f C", temp);
    LCD_ShowString(DISPLAY_X_POS + DISPLAY_X_STEP, DISPLAY_Y_POS + DISPLAY_Y_STEP + DISPLAY_Y_BAIS, (char *)str_buffer, BLUE, YELLOW, 16, 0);
    temp = lps22hh_get_pressure();
    sprintf((char *)str_buffer, "LPS22HH Press:%3.2f hPa", temp);
    LCD_ShowString(DISPLAY_X_POS + DISPLAY_X_STEP * 2 , DISPLAY_Y_POS + DISPLAY_Y_STEP * 2 + DISPLAY_Y_BAIS, (char *)str_buffer, BLUE, YELLOW, 16, 0);

    //  获取hts221的数据
    temp = hts221_get_humidity();
    sprintf((char *)str_buffer, "HTS221 Humi:%3.2f %%", temp);
    LCD_ShowString(DISPLAY_X_POS + DISPLAY_X_STEP *3 , DISPLAY_Y_POS + DISPLAY_Y_STEP * 3 + DISPLAY_Y_BAIS * 2, (char *)str_buffer, BLUE, YELLOW, 16, 0);
    temp = hts221_get_temperature();
    sprintf((char *)str_buffer, "HTS221 Temp:%3.2f C", temp);
    LCD_ShowString(DISPLAY_X_POS + DISPLAY_X_STEP * 4 , DISPLAY_Y_POS + DISPLAY_Y_STEP * 4 + DISPLAY_Y_BAIS * 2, (char *)str_buffer, BLUE, YELLOW, 16, 0);         
}


四、显示效果




使用特权

评论回复
沙发
xinmeng_wit|  楼主 | 2024-9-16 19:23 | 只看该作者
手机像素不高,转换成gif后更模糊了

使用特权

评论回复
板凳
丙丁先生| | 2024-9-17 14:46 | 只看该作者

使用特权

评论回复
地板
瞎折腾| | 2024-9-17 15:13 | 只看该作者
我用spi驱动屏幕,屏幕的初始化的时候屏幕反应很慢,刷白的时候都能看到过程,咋办呢?

使用特权

评论回复
5
xinmeng_wit|  楼主 | 2024-9-17 19:21 | 只看该作者
瞎折腾 发表于 2024-9-17 15:13
我用spi驱动屏幕,屏幕的初始化的时候屏幕反应很慢,刷白的时候都能看到过程,咋办呢? ...

1、使用硬件spi
2、提高spi的时钟频率

使用特权

评论回复
评论
瞎折腾 2024-9-18 10:56 回复TA
是用的硬件spi,最高频率了,不过就是没用dma,f103的片子 
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

68

主题

233

帖子

1

粉丝