你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

NUCLEO-C071RB评测4_模拟和硬件SPI驱动3.5寸TFT彩屏

[复制链接]
老牛洋车 发布时间:2025-5-8 10:48

通过SPI驱动TFT彩屏是我测试计划中的一个部分,使用的是一块3.5寸TFT彩色屏幕,背光控制使用之前在PWM测试时预留的CH3通道,以便在之后的应用中可以自行调节背光的亮度。下图是本次测试过程的照片,TFT彩屏已经安装在一个塑料盒盖上,通过杜邦线连接:

TFT_1.jpg

引脚安排如下:

TFT_0.png

其中的SPI通讯是对应SPI2的PB13、PB14和PB15,其中的SPI_MISO在本次测试中没有使用。

使用模拟SPI驱动时,这三个引脚分别设置为T_SCL、T_SDA和T_SDO。

驱动代码是统一的,在编译时通过是否定义了T_SCL_Pin来判断编译模拟SPI代码还是硬件SPI代码。

下面是硬件SPI的配置:

TFT_3.png

这是GPIO的配置,引脚速度已经配置为最高:

TFT_4.png

这是TFT的驱动代码:

/****************************************************************************************************
//                 硬件SPI驱动
//     LCD模块                STM32C071RB单片机
//=========================================电源接线================================================//
//      VCC                  DC3.3V        //电源
//      GND                   GND          //电源地
//=======================================液晶屏数据线接线==========================================//
//    SDI(MOSI)               PB15         //液晶屏SPI总线数据写信号
//    SDO(MISO)               PB14         //液晶屏SPI总线数据读信号
//       SCK                  PB13         //液晶屏SPI总线时钟信号
//=======================================液晶屏控制线接线==========================================//
//       LED                  PB10         //液晶屏背光控制信号,由TIM3_CH3输出PWM控制
//      DC/RS                 PB1          //液晶屏数据/命令控制信号
//       RST                  PD8          //液晶屏复位控制信号
//       CS                   PC0          //液晶屏片选控制信号
****************************************************************************************************/


#include "lcd.h"
//#include "stdlib.h"
#ifndef T_SCL_Pin
#include "spi.h"
#endif
#include "font.h"

//管理LCD重要参数
//默认为竖屏
_lcd_dev lcddev;

//画笔颜色,背景颜色
uint16_t POINT_COLOR = 0x0000,BACK_COLOR = 0xFFFF;  
//uint16_t DeviceCode;   
//定义颜色数组
//uint16_t ColorTab[5]={RED,GREEN,BLUE,YELLOW,BRED};



/*****************************************************************************
 * 函数名:    void SPI_WriteByte(uint8_t Data)
 * 编制日期:  2025-03-24
 * 作用:      以SPI模式0传输单字节数据
 * 参数:      data   要写入的数据
 * 返回值:    无
 * 备注:     无 
******************************************************************************/
void  SPI_WriteByte(uint8_t Data)
{
#ifdef T_SCL_Pin
  uint8_t i;
  LCD_SCL_SET;
  for(i=8;i>0;i--){
    if(Data&0x80)
      LCD_SDA_SET;      //输出数据
    else
      LCD_SDA_CLR;
    LCD_SCL_CLR;     
    LCD_SCL_SET;
    Data<<=1; 
  }
#else
  HAL_SPI_Transmit(&hspi2,&Data,1,0xffff);
#endif
}

/*****************************************************************************
 * 函数名:    void SPI_WriteBuff(uint8_t *buff,uint8_t len)
 * 编制日期:  2025-03-24
 * 作用:      以SPI模式0传输多字节数据
 * 参数:      buff   要写入的数组指针
 *            len    数组长度
 * 返回值:    无
 * 备注:     无 
******************************************************************************/
void  SPI_WriteBuff(uint8_t *buff,uint8_t len)
{
#ifdef T_SCL_Pin
  uint8_t i,j,d;
  LCD_SCL_SET;
  for(j=0; j<len; j++){
    d = buff[j];
    for(i=8;i>0;i--){
      if(d&0x80)
        LCD_SDA_SET;      //输出数据
      else
        LCD_SDA_CLR;
      LCD_SCL_CLR;     
      LCD_SCL_SET;
      d<<=1; 
    }
  }
#else
  HAL_SPI_Transmit(&hspi2,buff,len,0xffff);
#endif
}


/*****************************************************************************
 * 函数名:    void LCD_WR_REG(uint8_t data)
 * 编制日期:  2025-03-04 
 * 作用:      写入单字节的命令
 * 参数:      data   要写入的命令
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LCD_WR_REG(uint8_t data)
{ 
  LCD_CS_CLR;
  LCD_DC_CLR;
  SPI_WriteByte(data);
  LCD_CS_SET;
}

/*****************************************************************************
 * 函数名:    void LCD_WR_DATA(uint8_t data)
 * 编制日期:  2025-03-04 
 * 作用:      写入单字节的数据
 * 参数:      data   要写入的数据
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LCD_WR_DATA(uint8_t data)
{
  LCD_CS_CLR;
  LCD_DC_SET;
  SPI_WriteByte(data);
  LCD_CS_SET;
}

/*****************************************************************************
 * 函数名:    void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
 * 编制日期:  2025-03-10 
 * 作用:      将双字节数据写入指定的寄存器(地址)
 * 参数:      LCD_Reg      寄存器(地址)
 *            LCD_RegValue 要写入的双字节数据
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LCD_WriteReg(uint8_t LCD_Reg, uint16_t LCD_RegValue)
{
  uint8_t Dat[2];
  Dat[0] = LCD_RegValue>>8;
  Dat[1] = LCD_RegValue&0xff;
  LCD_CS_CLR;
  LCD_DC_CLR;
  SPI_WriteByte(LCD_Reg);
  LCD_DC_SET;
  SPI_WriteBuff(Dat,2);
  LCD_CS_SET;
}      

/*****************************************************************************
 * 函数名:    void Lcd_WriteData_16Bit(uint16_t c)
 * 编制日期:  2025-03-10 
 * 作用:      在当前位置写入像素(颜色)数据
 * 参数:      Data  16位的三基色数据
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void Lcd_WriteData_16Bit(uint16_t c)
{
  uint8_t Dat[3];
  Dat[0] = (c>>8)&0xF8;        //RED
  Dat[1] = (c>>3)&0xFC;        //GREEN
  Dat[2] = c<<3;               //BLUE
  LCD_CS_CLR;
  LCD_DC_SET;
  SPI_WriteBuff(Dat,3);
  LCD_CS_SET;
}

/*****************************************************************************
 * 函数名:    void Lcd_WriteData_16Bit(uint16_t Data)
 * 编制日期:  2025-03-04 
 * 作用:      在指定位置写入像素数据
 * 参数:      x  列坐标点
 *            y  行坐标点
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LCD_DrawPoint(uint16_t x,uint16_t y)
{
    LCD_SetCursor(x,y);                 //设置光标位置 
    Lcd_WriteData_16Bit(POINT_COLOR); 
}

/*****************************************************************************
 * 函数名:    void LcdClear(uint16_t Color)
 * 编制日期:  2025-03-04 
 * 作用:      按指定颜色清屏
 * 参数:      Color  16位颜色
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdClear(uint16_t Color)
{
  uint16_t i, m;
  LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);   
  for(i=0; i<lcddev.height; i++)
  {
    for(m=0; m<lcddev.width; m++)
    {
      Lcd_WriteData_16Bit(Color);
    }
  }
} 

/*****************************************************************************
 * 函数名:    void LCD_RESET(void)
 * 编制日期:  2025-03-04 
 * 作用:      LCD复位
 * 参数:      无
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LCD_RESET(void)
{
    LCD_RST_CLR;
    delay_ms(100);
    LCD_RST_SET;
    delay_ms(50);
}


/*****************************************************************************
 * 函数名:    void LcdInit(void)
 * 编制日期:  2025-03-10 
 * 作用:      LCD初始化
 * 参数:      无
 * 返回值:    无
 * 备注:     无
******************************************************************************/      
void LcdInit(void)
{
  uint8_t Reg,Dat[15];
  LCD_RESET();                  //LCD 复位
//************* ILI9488初始化**********//
/*
  LCD_WR_REG(0xF7);             //02
  LCD_WR_DATA(0xA9);
  LCD_WR_DATA(0x51);
  LCD_WR_DATA(0x2C);
  LCD_WR_DATA(0x82);

  LCD_WR_REG(0xC0);             //功率控制
  LCD_WR_DATA(0x11);
  LCD_WR_DATA(0x09);

  LCD_WR_REG(0xC1);             //功率控制
  LCD_WR_DATA(0x41);

  LCD_WR_REG(0XC5);             //VCOM控制
  LCD_WR_DATA(0x00);
  LCD_WR_DATA(0x0A);
  LCD_WR_DATA(0x80);

  LCD_WR_REG(0xB1);             //帧速率控制(正常模式/全色)
  LCD_WR_DATA(0xB0);
  LCD_WR_DATA(0x11);

  LCD_WR_REG(0xB4);             //显示反转控制
  LCD_WR_DATA(0x02);

  LCD_WR_REG(0xB6);             //显示功能控制
  LCD_WR_DATA(0x02);
  LCD_WR_DATA(0x42);

  LCD_WR_REG(0xB7);             //进入模式设置(NO)
  LCD_WR_DATA(0xc6);

  LCD_WR_REG(0xBE);             //HS通道控制NO
  LCD_WR_DATA(0x00);
  LCD_WR_DATA(0x04);

  LCD_WR_REG(0xE9);             //设置图像功能
  LCD_WR_DATA(0x00);

  LCD_WR_REG(0x36);             //内存访问 0x48
  LCD_WR_DATA((1<<3)|(0<<7)|(1<<6)|(1<<5));

  LCD_WR_REG(0x3A);             //界面像素格式
  LCD_WR_DATA(0x66);

  LCD_WR_REG(0xE0);             //PGAMCTRL(正伽马对照)
  LCD_WR_DATA(0x00);
  LCD_WR_DATA(0x07);
  LCD_WR_DATA(0x10);
  LCD_WR_DATA(0x09);
  LCD_WR_DATA(0x17);
  LCD_WR_DATA(0x0B);
  LCD_WR_DATA(0x41);
  LCD_WR_DATA(0x89);
  LCD_WR_DATA(0x4B);
  LCD_WR_DATA(0x0A);
  LCD_WR_DATA(0x0C);
  LCD_WR_DATA(0x0E);
  LCD_WR_DATA(0x18);
  LCD_WR_DATA(0x1B);
  LCD_WR_DATA(0x0F);

  LCD_WR_REG(0XE1);             //NGAMCTRL(负伽马对照)
  LCD_WR_DATA(0x00);
  LCD_WR_DATA(0x17);
  LCD_WR_DATA(0x1A);
  LCD_WR_DATA(0x04);
  LCD_WR_DATA(0x0E);
  LCD_WR_DATA(0x06);
  LCD_WR_DATA(0x2F);
  LCD_WR_DATA(0x45);
  LCD_WR_DATA(0x43);
  LCD_WR_DATA(0x02);
  LCD_WR_DATA(0x0A);
  LCD_WR_DATA(0x09);
  LCD_WR_DATA(0x32);
  LCD_WR_DATA(0x36);
  LCD_WR_DATA(0x0F);

  LCD_WR_REG(0x11);             //唤醒睡眠(00x10进入睡眠)
  HAL_Delay(120);
  LCD_WR_REG(0x29);             //开显示(0x28关显示)
*/  

  LCD_CS_CLR;
  LCD_DC_CLR;

  SPI_WriteByte(0xF7);             //02
  Dat[0] = 0xA9;
  Dat[1] = 0x51;
  Dat[2] = 0x2C;
  Dat[3] = 0x82;
  LCD_DC_SET;
  SPI_WriteBuff(Dat,4);

  LCD_DC_CLR;
  SPI_WriteByte(0xC0);             //功率控制
  Dat[0] = 0x11;
  Dat[1] = 0x09;
  LCD_DC_SET;
  SPI_WriteBuff(Dat,2);

  LCD_DC_CLR;
  SPI_WriteByte(0xC1);             //功率控制
  LCD_DC_SET;
  SPI_WriteByte(0x41);

  LCD_DC_CLR;
  SPI_WriteByte(0XC5);             //VCOM控制
  LCD_DC_SET;
  Dat[0] = 0x00;
  Dat[1] = 0x0A;
  Dat[2] = 0x80;
  SPI_WriteBuff(Dat,3);

  LCD_DC_CLR;
  SPI_WriteByte(0xB1);             //帧速率控制(正常模式/全色)
  LCD_DC_SET;
  Dat[0] = 0xB0;
  Dat[1] = 0x11;
  SPI_WriteBuff(Dat,2);

  LCD_DC_CLR;
  SPI_WriteByte(0xB4);             //显示反转控制

  LCD_DC_SET;
//  Reg = 0x20;
//  SPI_WriteByte(Reg);
  LCD_WR_DATA(0x02);

  LCD_CS_CLR;
  LCD_DC_CLR;
  SPI_WriteByte(0xB6);             //显示功能控制
  LCD_DC_SET;
  Dat[0] = 0x02;
  Dat[1] = 0x42;
  SPI_WriteBuff(Dat,2);

  LCD_DC_CLR;
  SPI_WriteByte(0xB7);             //进入模式设置(NO)
  LCD_DC_SET;
  SPI_WriteByte(0xc6);

  LCD_DC_CLR;
  SPI_WriteByte(0xBE);             //HS通道控制NO
  LCD_DC_SET;
  Dat[0] = 0x00;
  Dat[1] = 0x04;
  SPI_WriteBuff(Dat,2);

  LCD_DC_CLR;
  SPI_WriteByte(0xE9);             //设置图像功能
  LCD_DC_SET;
  SPI_WriteByte(0x00);

  LCD_DC_CLR;
  SPI_WriteByte(0x36);             //内存访问 0x48
  LCD_DC_SET;
  SPI_WriteByte((1<<3)|(0<<7)|(1<<6)|(1<<5));

  LCD_DC_CLR;
  SPI_WriteByte(0x3A);             //界面像素格式
  LCD_DC_SET;
  SPI_WriteByte(0x66);

  LCD_DC_CLR;
  SPI_WriteByte(0xE0);             //PGAMCTRL(正伽马对照)
  LCD_DC_SET;
  Dat[0] = 0x00;
  Dat[1] = 0x07;
  Dat[2] = 0x10;
  Dat[3] = 0x09;
  Dat[4] = 0x17;
  Dat[5] = 0x0B;
  Dat[6] = 0x41;
  Dat[7] = 0x89;
  Dat[8] = 0x4B;
  Dat[9] = 0x0A;
  Dat[10] = 0x0C;
  Dat[11] = 0x0E;
  Dat[12] = 0x18;
  Dat[13] = 0x1B;
  Dat[14] = 0x0F;
  SPI_WriteBuff(Dat,15);

  LCD_DC_CLR;
  SPI_WriteByte(0XE1);             //NGAMCTRL(负伽马对照)
  LCD_DC_SET;
  Dat[0] = 0x00;
  Dat[1] = 0x17;
  Dat[2] = 0x1A;
  Dat[3] = 0x04;
  Dat[4] = 0x0E;
  Dat[5] = 0x06;
  Dat[6] = 0x2F;
  Dat[7] = 0x45;
  Dat[8] = 0x43;
  Dat[9] = 0x02;
  Dat[10] = 0x0A;
  Dat[11] = 0x09;
  Dat[12] = 0x32;
  Dat[13] = 0x36;
  Dat[14] = 0x0F;
  SPI_WriteBuff(Dat,15);

  LCD_DC_CLR;
  SPI_WriteByte(0x11);             //唤醒睡眠(00x10进入睡眠)
  LCD_CS_SET;
  HAL_Delay(120);
  LCD_CS_CLR;
  LCD_DC_CLR;
  SPI_WriteByte(0x29);             //开显示(0x28关显示)
  LCD_CS_SET;

  LcdDirection(3);                 //设置LCD显示方向为270度(横屏)
//  LCD_BL_ON;                       //点亮背光  
  LcdClear(WHITE);                 //清全屏白色
}

/*****************************************************************************
 * 函数名:    void LCD_SetWindows(uint16_t xStar, uint16_t yStar, uint16_t xEnd, uint16_t yEnd)
 * 编制日期:  2025-03-10 
 * 作用:      设置LCD的显示窗口
 * 参数:      xStar  列开始坐标点
 *            yStar  行开始坐标点
 *            xEnd   列结束坐标点
 *            yEnd   行结束坐标点
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LCD_SetWindows(uint16_t xStar, uint16_t yStar, uint16_t xEnd, uint16_t yEnd)
{
  uint8_t Reg,Dat[4];
  Dat[0] = xStar>>8;
  Dat[1] = 0x00FF&xStar;
  Dat[2] = xEnd>>8;
  Dat[3] = 0x00FF&xEnd;
  LCD_CS_CLR;
  LCD_DC_CLR;
  SPI_WriteByte(lcddev.setxcmd);
  LCD_DC_SET;
  SPI_WriteBuff(Dat,4);

  Dat[0] = yStar>>8;
  Dat[1] = 0x00FF&yStar;
  Dat[2] = yEnd>>8;
  Dat[3] = 0x00FF&yEnd;
  LCD_DC_CLR;
  SPI_WriteByte(lcddev.setycmd);
  LCD_DC_SET;
  SPI_WriteBuff(Dat,4);

  LCD_DC_CLR;
    SPI_WriteByte(lcddev.wramcmd);  //开始写入GRAM
  LCD_CS_SET;
}   

/*****************************************************************************
 * 函数名:    void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
 * 编制日期:  2025-03-05 
 * 作用:      设置LCD光标位置
 * 参数:      Xpos   列坐标点
 *            Ypos   行坐标点
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LCD_SetCursor(uint16_t Xpos, uint16_t Ypos)
{                   
  LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);
} 

/*****************************************************************************
 * 函数名:    LcdDirection(uint8_t direction)
 * 编制日期:  2025-03-10 
 * 作用:      设置LCD方向
 * 参数:      0       0度
 *            1      90度
 *            2     180度
 *            3     270度
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdDirection(uint8_t direction)
{
  uint8_t Reg,Dat;
  lcddev.setxcmd=0x2A;
  lcddev.setycmd=0x2B;
  lcddev.wramcmd=0x2C;

  switch(direction){          
    case 0:
      Dat = 0x08;                              //0000 1000 = 0x08   反向0100 1000 = 0x48
      lcddev.width = LCD_W;
      lcddev.height = LCD_H;
      break;
    case 1:
      Dat = 0x40 | 0x20 | 0x08;                //0110 1000 = 0x68   反向0010 1000 = 0x28
      lcddev.width = LCD_H;
      lcddev.height = LCD_W;
      break;
    case 2:
      Dat = 0x80 | 0x40 | 0x08;                //1100 1000  = 0xc8  反向1000 1000 = 0x88
      lcddev.width = LCD_W;
      lcddev.height = LCD_H;
      break;
    case 3:
      Dat = 0x80 | 0x20 | 0x08;                //1010 1000 = 0xa8   反向1110 1000 = 0xe8
      lcddev.width = LCD_H;
      lcddev.height = LCD_W;
      break;
    default:
      break;
  }
  LCD_CS_CLR;
  LCD_DC_CLR;
  SPI_WriteByte(0x36);
  LCD_DC_SET;
  SPI_WriteByte(Dat);
  LCD_CS_SET;
}    

/*****************************************************************************
 * 函数名:    void LcdDrawHline(uint16_t x,uint16_t y,uint16_t l,uint16_t c)
 * 编制日期:  2024-01-28 
 * 作用:      画垂直线(由上往下画)
 * 参数:      x  起点坐标
 *            y
 *            l  线长(点)
 *            c  16位RBG颜色
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdDrawHline(uint16_t x,uint16_t y,uint16_t l,uint16_t c)
{
  uint16_t i;
  POINT_COLOR=c;
  LCD_CS_CLR;
  for (i=0; i<l; i++){
    LCD_DrawPoint(x,y+i);
  }
  LCD_CS_SET;
}

/*****************************************************************************
 * 函数名:    void LcdDrawVline(uint16_t x,uint16_t y,uint16_t l,uint16_t c)
 * 编制日期:  2024-01-28 
 * 作用:      画水平线(由左往右画)
 * 参数:      x  起点坐标
 *            y
 *            l  线长(点)
 *            c  16位RBG颜色
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdDrawVline(uint16_t x,uint16_t y,uint16_t l,uint16_t c)
{
  uint16_t i;
  LCD_CS_CLR;
//  LCD_SetCursor(x,y);             //设置光标位置 
  POINT_COLOR=c;
  for (i=0; i<l; i++){
//    Lcd_WriteData_16Bit(c);
    LCD_DrawPoint(x+i,y);
  }
  LCD_CS_SET;
}

/*****************************************************************************
 * 函数名:    void LcdDrawLine(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t c)
 * 编制日期:  2024-01-29
 * 作用:      两点之间画线
 * 参数:      x0  起点坐标
 *            y0
 *            x1  终点坐标
 *            y1
 *            c  16位RBG颜色
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdDrawLine(uint16_t x0,uint16_t y0,uint16_t x1,uint16_t y1,uint16_t c)
{
  int dx,dy,dx2,dy2,x_inc,y_inc,er,id;

  LCD_CS_CLR;
  dx = x1 - x0;
  dy = y1 - y0;

  if(dx >= 0){
    x_inc = 1;
  }else{
    x_inc = -1;
    dx = -dx;
  } 

  if(dy >= 0){
    y_inc = 1;
  }else{
    y_inc = -1;
    dy = -dy; 
  } 

  dx2 = dx << 1;
  dy2 = dy << 1;
  POINT_COLOR=c;
  if(dx > dy){
    /* initialize error */
    er = dy2 - dx;
    /* draw the line */
    for(id = 0;id <= dx;id++){
      LCD_DrawPoint(x0,y0);
      /* test if error has overflowed */
      if(0 <= er){
        er -= dx2;
        /* move to next line */
        y0 += y_inc;
      }
      /* adjust the error term */
      er += dy2;
      /* move to the next pixel */
      x0 += x_inc;
    }
  }else{
    /* initialize error term */
    er = dx2 - dy;
    /* draw the linedraw the line*/
    for(id= 0;id <= dy;id++){
      /* set the pixel */
      LCD_DrawPoint(x0,y0);

      /* test if error overflowed */
      if(0 <= er){
        er -= dy2;
        /* move to next line */
        x0 += x_inc;
      }
      /* adjust the error term */
      er += dx2;
      /* move to the next pixel */
      y0 += y_inc;
    }
  }
  LCD_CS_SET;
}

/*****************************************************************************
 * 函数名:    void LcdDrawCircle(uint16_t x,uint16_t y,uint16_t r,uint16_t c)
 * 编制日期:  2024-01-27
 * 作用:      画对称圆算法
 * 参数:      xc  圆形中心的x坐标
 *            yc  圆形中心的y坐标
 *            x   相对于圆形中心的x坐标
 *            y   相对于圆形中心的y坐标
 *            c  16位RBG颜色
 * 返回值:    无
 * 备注:     无
******************************************************************************/ 
/*void LCD_DrawCircle(uint16_t x,uint16_t y,uint16_t r,uint16_t c)
{
  POINT_COLOR=c;
  LCD_DrawPoint(xc + x, yc + y);
  LCD_DrawPoint(xc - x, yc + y);
  LCD_DrawPoint(xc + x, yc - y);
  LCD_DrawPoint(xc - x, yc - y);
  LCD_DrawPoint(xc + y, yc + x);
  LCD_DrawPoint(xc - y, yc + x);
  LCD_DrawPoint(xc + y, yc - x);
  LCD_DrawPoint(xc - y, yc - x);
}
*/
/*****************************************************************************
 * 函数名:    void LcdDrawCircle(uint16_t x,uint16_t y,uint16_t r,uint16_t c)
 * 编制日期:  2024-01-27
 * 作用:      画圆
 * 参数:      x  圆心坐标
 *            y
 *            c  16位RBG颜色
 * 返回值:    无
 * 备注:     无
******************************************************************************/ 
void LcdDrawCircle(uint16_t x,uint16_t y,uint16_t r,uint16_t c)
{
  unsigned short a,b;
  int n;
  a=0;
  b=r;
  n=3-2*r;
  POINT_COLOR=c;
  while(a < b){
    // draw points on the lcd 
    LCD_DrawPoint(x+a, y+b);
    LCD_DrawPoint(x-a, y+b);
    LCD_DrawPoint(x+a, y-b);
    LCD_DrawPoint(x-a, y-b);
    LCD_DrawPoint(x+b, y+a);
    LCD_DrawPoint(x-b, y+a);
    LCD_DrawPoint(x+b, y-a);
    LCD_DrawPoint(x-b, y-a);
    if(n<0)
      n=n+4*a+6;
    else{ 
      n=n+4*(a-b)+10;
      b-=1; 
    } 
    a+=1;
  } 
  if(a==b){
    // draw points on the lcd 
    LCD_DrawPoint(x+a, y+b);
    LCD_DrawPoint(x+a, y+b);
    LCD_DrawPoint(x+a, y-b);
    LCD_DrawPoint(x-a, y-b);
    LCD_DrawPoint(x+b, y+a);
    LCD_DrawPoint(x-b, y+a);
    LCD_DrawPoint(x+b, y-a);
    LCD_DrawPoint(x-b, y-a);
  } 
}

/*****************************************************************************
 * 函数名:    void LcdDrawRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t c)
 * 编制日期:  2025-03-05
 * 作用:      画矩形
 * 参数:      x   起点坐标
 *            y
 *            w   宽度
 *            h
 *            c  16位RBG颜色
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdDrawRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t c)
{
  LcdDrawVline(x,y,w,c);
  LcdDrawHline(x,y,h,c);
  LcdDrawVline(x,y+h,w,c);
  LcdDrawHline(x+w,y,h,c);
}

/*****************************************************************************
 * 函数名:    LcdGuiRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t c)
 * 编制日期:  2025-03-05
 * 作用:      填充矩形
 * 参数:      x   起点坐标
 *            y
 *            w   宽度
 *            h
 *            c  16位RBG颜色
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdGuiRectangle(uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint16_t c)
{
  uint16_t i,j;
  LCD_SetWindows(x,y,x+w,y+h);         //设置显示窗口
  for(i=0; i<h; i++)
  {
    for(j=0; j<w; j++)
    Lcd_WriteData_16Bit(c);            //写入数据    
  }
  LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复窗口设置为全屏
}

 /*****************************************************************************
 * 函数名:    void (uint16_t x,uint16_t y,uint16_t fc,uint16_t bc,char *str,uint8_t size)
 * 编制日期:  2024-07-03
 * 作用:      显示多种字号的字符串
 * 参数:      x     起点坐标
 *            y
 *            fc    16位RBG前景色
 *            bc    16位RBG背景色(背景色与前景色相同则为透明显示,即不改变背景色)
 *            *str  字符串指针
 *            size  字体的高度(行数)16,24,40
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdDrawFont(uint16_t x,uint16_t y,uint16_t fc,uint16_t bc,char *str,uint8_t size)
{
  uint8_t temp,i,j,k,h,s;
  uint16_t x0=x;

  while(*str){                            //开始字符循环
    if(((uint8_t)(*str))<128){            //ASCII字符
      k=*str;
      //处理换行符及其它控制符
      if(13==k){                          //换行符
        x=x0;
        y+=size;
      }else{
        if(k>32)                          //字符码减32,等于字符序号
          k-=32;
        else
          k=0;                            //其他不可显示字符用空格替代
      }
      //确定字符占用的块(宽8b)
      if(size<24)
        s=1;                              //计算重复次数(16*8点阵1块,24*12点阵2块,40*20点阵3块,
      else if(size<40)
        s=2;
      else
        s=3;
      //开始写点阵
      for(h=0; h<s; h++){                 //逐块写
        for(i=0; i<size; i++){            //逐行写
          if(s==1)
            temp=asc_16[k][i];            //调用16*8点阵字体数据
          else if(s==2)
            temp=asc_24[k][i*2+h];        //调用24*12点阵字体数据
          else
            temp=asc_40[k][i*3+h];        //调用24*12点阵字体数据
          for(j=0; j<8; j++){
            if(temp & 0x80){              //写一点
              POINT_COLOR=fc;
              LCD_DrawPoint(x+j+h*8, y+i);
            }else{
              if(bc!=fc){                 //写背景色
                POINT_COLOR=bc;
                LCD_DrawPoint(x+j+h*8, y+i);
              }                           //写背景色结束
            }
            temp<<=1;
          }                               //写一行结束
        }
      }                                   //单个字符写结束
      x+=size/2;                          //移到下一字符位置
      str++;                              //移动字符串指针
    }
    else{                                 //汉字字符
      if(size==16){
        for(k=0; k<hz16_num; k++){        //查找汉字序号(k=数组下标)
          if((font16[k].ID[0]==*(str)) && (font16[k].ID[1]==*(str+1))){
            break;
          }
        }
      }else{
        for(k=0; k<hz24_num; k++){
          if((font24[k].ID[0]==*(str)) && (font24[k].ID[1]==*(str+1))){
            break;
          }                             
        }
      }
      for(h=0; h<(size/8); h++){          //16点阵字库h=2块,24点阵字库h=3块
        for(i=0; i<size; i++){            //开始循环写一列(8位)
          if(size==16)
            temp=font16[k].Msk[i*2+h];    //取16点阵字模
          else
            temp=font24[k].Msk[i*3+h];    //取24点阵字模
          for(j=0; j<8; j++){
            if(temp & 0x80){              //写一点
              POINT_COLOR=fc;
              LCD_DrawPoint(x+j+h*8, y+i);
            }else{
              if(bc!=fc){                 //写背景色
                POINT_COLOR=bc;
                LCD_DrawPoint(x+j+h*8, y+i);
              }                           //写背景色结束
            }                             //写一点结束
            temp<<=1;
          }                               //写一行结束
        }
      }                                   //写n块结束
      x+=size;                            //移到下一字符位置
      str+=2;                             //移动字符串指针
    }
  }
}

 /*****************************************************************************
 * 函数名:    void LcdDrawASCII(uint16_t x,uint16_t y,uint16_t fc,uint16_t bc,char code,uint8_t size)
 * 编制日期:  2024-07-03
 * 作用:      显示多种字号的单个ASCII字符
 * 参数:      x     起点坐标
 *            y
 *            fc    16位RBG前景色
 *            bc    16位RBG背景色(背景色与前景色相同则为透明显示,即不改变背景色)
 *            code  ASCII字符码
 *            size  字体的高度(行数)16,24,40
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdDrawASCII(uint16_t x,uint16_t y,uint16_t fc,uint16_t bc,char code,uint8_t size)
{
  uint8_t h,i,j,temp,s;
  if(code<32)                           //非可显示字符
    return;
  if(size<24)
    s=1;                                //计算重复次数(16*8点阵1块,24*12点阵2块,40*20点阵3块,
  else if(size<40)
    s=2;
  else
    s=3;
  //开始写点阵
  for(h=0; h<s; h++){                           //逐块写
    for(i=0; i<size; i++){              //逐行写
      if(size==16)
        temp=asc_16[code-32][i];        //调用16*8点阵字体数据
      else if(size==24)
        temp=asc_24[code-32][i*2+h];    //调用24*12点阵字体数据
      else if(size==40)
        temp=asc_40[code-32][i*3+h];    //调用24*12点阵字体数据
      else
        temp=asc_48[code-32][i*3+h];    //调用24*12点阵字体数据

      for(j=0; j<8; j++){
        if(temp & 0x80){                //写一点
          POINT_COLOR=fc;
          LCD_DrawPoint(x+j+h*8, y+i);
        }else{
          if(bc!=fc){                   //写背景色
            POINT_COLOR=bc;
            LCD_DrawPoint(x+j+h*8, y+i);
          }                             //写背景色结束
        }
        temp<<=1;
      }                                 //写一行结束
    }
  }                                     //单个字符写结束
}

 /*****************************************************************************
 * 函数名:    void LcdDrawValue(uint16_t x,uint16_t y,uint16_t v,uint8_t l,uint8_t d,uint8_t z,uint8_t t,uint16_t fc,uint16_t bc)
 * 编制日期:  2024-07-03
 * 作用:      显示多种字号的变量值
 * 参数:      x     起点坐标
 *            y
 *            v     变量
 *            l     显示的字符数(含小数点)
 *            d     小数位数
 *            z     0=显示前导零 1=空格替换前导零
 *            t     字体的高度(行数)16,24,40
 *            fc    16位RBG前景色
 *            bc    16位RBG背景色(背景色与前景色相同则为透明显示,即不改变背景色)
 * 返回值:    无
 * 备注:     无
******************************************************************************/
void LcdDrawValue(uint16_t x,uint16_t y,uint16_t v,uint8_t l,uint8_t d,uint8_t z,uint8_t t,uint16_t fc,uint16_t bc)
{
  uint8_t i,c,f=0,x1;                       //字循环、位循环、当前数字,前导零参数,字符宽度
  uint16_t n,x0;                            //当前余数、当前x坐标
  uint32_t m;                               //当前倍数
  if(z>0)                                   //前导零用空格替换
    f=16;
  x0=x;
  n=v;
  m=1;
  if(48==t)
    x1=24;
  else if(16==t)
    x1=7;
  else
    x1=t/2;
  for(i=0; i<l; i++)                        //计算最高位的倍数
    m=m*10;
  for(i=l; i>0; i--)                        //开始循环处理
  {
    m=i<2 ? 1: m/10;                        //计算当前位的倍数
    c=n/m;                                  //当前位数字
    n%=m;                                   //求余数
    if(f>0){
      if((c>0)|(i==(d+1)))                  //有有效数字或是个位,显示零
        f=0;
    }
    if((d>0) & (d==i)){                     //写小数点
      LcdDrawASCII(x0,y,fc,bc,'.',t);
      x0+=x1;                               //移到下一位
    }                                       //写小数点结束
    LcdDrawASCII(x0,y,fc,bc,48+c-f,t);      //写数字
    x0+=x1;                                 //移到下一位
  }
}

 /*****************************************************************************
 * 函数名:    void LcdDrawBmp16(uint16_t x,uint16_t y,uint16_t w,uint16_t h,const unsigned char *p)
 * 编制日期:  2025-03-07
 * 作用:      显示bmp图片
 * 参数:      x     起点坐标
 *            y
 *            w     图片宽度
 *            h     图片高度
 *            *p    图片数据指针
 * 返回值:    无
 * 备注:     无
******************************************************************************/
/*void LcdDrawBmp16(uint16_t x,uint16_t y,uint16_t w,uint16_t h,const unsigned char *p)
{
  int i; 
  uint8_t picH,picL; 
  LCD_SetWindows(x,y,x+w-1,y+h-1);                   //窗口设置
  for(i=0; i<w*h; i++)
  {
    picL=*(p+i*2);                                   //数据低位在前
    picH=*(p+i*2+1);            
    Lcd_WriteData_16Bit(picH<<8|picL);                      
  }
  LCD_SetWindows(0,0,lcddev.width-1,lcddev.height-1);//恢复显示窗口为全屏
}
*/

下面是模拟SPI的配置:

TFT_2.png

因为代码是通用的,不需要作其它修改,直接编译就成。

这是硬件SPI驱动TFT彩屏的动画:

TFT_hard.gif

这是模拟SPI驱动TFT彩屏的动画,可以看出明显比硬件SPI驱动时的刷新快很多:

TFT_soft.gif

TFT_1.png
收藏 评论0 发布时间:2025-5-8 10:48

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版