【STM32】ST7789屏幕驱动

news2025/4/15 4:33:40

目录

CubeMX配置

配置SPI

开DMA

时钟树

堆栈大小

Keil工程配置

添加两个group

添加文件包含路径

驱动编写

写单字节函数

写字函数

写多字节函数

初始化函数

设置窗口函数

情况一:正常的0度旋转

情况二:顺时针90度旋转

情况三:180度旋转

情况四:顺时针270度旋转

清屏函数

画单色水平线函数

画单色垂直线函数

区域填充函数

画彩色线函数

画图函数

附录

ST7789.c

ST7789.h


ST7789手册阅读,准备编写驱动-CSDN博客

看完手册之后就可以开始敲代码

先看看最终效果

笔者用的是淘宝买的裸屏,分辨率240*240,自己焊接外围电路。

CubeMX配置

配置晶振,调试口等等就不赘述了

配置SPI

笔者的单片机SPI时钟最大可以到50MHz,为了便于演示,这里只开到6.25MHz,后面会有不同时钟下速率的对比

开DMA

屏幕的数据量还是挺大的,用DMA可以让MCU的负荷轻一些

时钟树

堆栈大小

按默认的来也可以

至此,cubemx配置完毕,点击生成代码

Keil工程配置

添加两个group

ST7789用于存放即将编写的驱动,generate存放生成的文件

添加文件包含路径

驱动编写

写单字节函数

可以发命令或者数据,均为单字节

void ST7789_SendByte(uint8_t dat, ST7789_DCType DC)
{
   ST7789_CS_LOW();

   (DC == ST7789_DATA) ? ST7789_DC_HIGH() : ST7789_DC_LOW();

   HAL_SPI_Transmit_DMA(ST7789_SPI, &dat, 1);
   while (HAL_SPI_GetState(ST7789_SPI) == HAL_SPI_STATE_BUSY_TX);

   ST7789_CS_HIGH();
}

写字函数

用于发送一个字

void ST7789_SendHalfWord(uint16_t dat)
{
   uint8_t da[2];
   ST7789_CS_LOW();
   ST7789_DC_HIGH();

   da[0] = dat >> 8;
   da[1] = dat & 0xFF;

   HAL_SPI_Transmit_DMA(ST7789_SPI, da, 2);
   while (HAL_SPI_GetState(ST7789_SPI) == HAL_SPI_STATE_BUSY_TX);

   ST7789_CS_HIGH();
}

写多字节函数

void ST7789_SendMultiByte(uint8_t* dat, uint16_t len)
{
   ST7789_CS_LOW();
   ST7789_DC_HIGH();

   HAL_SPI_Transmit_DMA(ST7789_SPI, dat, len);
   while (HAL_SPI_GetState(ST7789_SPI) == HAL_SPI_STATE_BUSY_TX);

   ST7789_CS_HIGH();
}

初始化函数

复位低电平时间需要持续至少10us,然后拉高,接下来的最大120ms内是在reset

void ST7789_Init(void)
{
   ST7789_BL_HIGH();
   ST7789_CS_HIGH();

   ST7789_RST_HIGH();
   ST7789_RST_LOW();
	HAL_Delay(1);
	ST7789_RST_HIGH();
	HAL_Delay(120);

   ST7789_SendByte(0x11, ST7789_CMD);	

   ST7789_SendByte(0x3A, ST7789_CMD);			
   ST7789_SendByte(0x55, ST7789_DATA);   //   5 565  6 666

   ST7789_SendByte(0xB2, ST7789_CMD);			
   ST7789_SendByte(0x0C, ST7789_DATA);
   ST7789_SendByte(0x0C, ST7789_DATA); 
   ST7789_SendByte(0x00, ST7789_DATA); 
   ST7789_SendByte(0x33, ST7789_DATA); 
   ST7789_SendByte(0x33, ST7789_DATA); 			

   ST7789_SendByte(0xB7, ST7789_CMD);			
   ST7789_SendByte(0x35, ST7789_DATA);

   ST7789_SendByte(0xBB, ST7789_CMD);			
   ST7789_SendByte(0x32, ST7789_DATA); //Vcom=1.35V
                                          
   ST7789_SendByte(0xC2, ST7789_CMD);			
   ST7789_SendByte(0x01, ST7789_DATA);

   ST7789_SendByte(0xC3, ST7789_CMD);			
   ST7789_SendByte(0x19, ST7789_DATA); //GVDD=4.8V 
                                          
   ST7789_SendByte(0xC4, ST7789_CMD);			
   ST7789_SendByte(0x20, ST7789_DATA); //VDV, 0x20:0v

   ST7789_SendByte(0xC6, ST7789_CMD);			
   ST7789_SendByte(0x0F, ST7789_DATA); //0x0F:60Hz        	

   ST7789_SendByte(0xD0, ST7789_CMD);			
   ST7789_SendByte(0xA4, ST7789_DATA);
   ST7789_SendByte(0xA1, ST7789_DATA); 											  												  																								
         
   ST7789_SendByte(0xE0, ST7789_CMD);     
   ST7789_SendByte(0xD0, ST7789_DATA);   
   ST7789_SendByte(0x08, ST7789_DATA);   
   ST7789_SendByte(0x0E, ST7789_DATA);   
   ST7789_SendByte(0x09, ST7789_DATA);   
   ST7789_SendByte(0x09, ST7789_DATA);   
   ST7789_SendByte(0x05, ST7789_DATA);   
   ST7789_SendByte(0x31, ST7789_DATA);   
   ST7789_SendByte(0x33, ST7789_DATA);   
   ST7789_SendByte(0x48, ST7789_DATA);   
   ST7789_SendByte(0x17, ST7789_DATA);   
   ST7789_SendByte(0x14, ST7789_DATA);   
   ST7789_SendByte(0x15, ST7789_DATA);   
   ST7789_SendByte(0x31, ST7789_DATA);   
   ST7789_SendByte(0x34, ST7789_DATA);   

   ST7789_SendByte(0xE1, ST7789_CMD);     
   ST7789_SendByte(0xD0, ST7789_DATA);   
   ST7789_SendByte(0x08, ST7789_DATA);   
   ST7789_SendByte(0x0E, ST7789_DATA);   
   ST7789_SendByte(0x09, ST7789_DATA);   
   ST7789_SendByte(0x09, ST7789_DATA);   
   ST7789_SendByte(0x15, ST7789_DATA);   
   ST7789_SendByte(0x31, ST7789_DATA);   
   ST7789_SendByte(0x33, ST7789_DATA);   
   ST7789_SendByte(0x48, ST7789_DATA);   
   ST7789_SendByte(0x17, ST7789_DATA);   
   ST7789_SendByte(0x14, ST7789_DATA);   
   ST7789_SendByte(0x15, ST7789_DATA);   
   ST7789_SendByte(0x31, ST7789_DATA);   
   ST7789_SendByte(0x34, ST7789_DATA);   

   ST7789_SendByte(0x21, ST7789_CMD);

   ST7789_SendByte(0x36, ST7789_CMD); //MX, MY, RGB mode 
#if (ST7789_ROTATION == 0)
   ST7789_SendByte(0x00, ST7789_DATA);
#elif (ST7789_ROTATION == 90)
   ST7789_SendByte(0x60, ST7789_DATA);//90
#elif (ST7789_ROTATION == 180)
   ST7789_SendByte(0xC0, ST7789_DATA);//180
#elif (ST7789_ROTATION == 270)
   ST7789_SendByte(0xA0, ST7789_DATA);//270
#endif

   ST7789_SendByte(0x2A, ST7789_CMD); //Column Address Set
   ST7789_SendByte(0x00, ST7789_DATA);
   ST7789_SendByte(0x00, ST7789_DATA); //0
   ST7789_SendByte(0x00, ST7789_DATA);
   ST7789_SendByte(0xEF, ST7789_DATA); //239

   ST7789_SendByte(0x2B, ST7789_CMD); //Row Address Set
   ST7789_SendByte(0x00, ST7789_DATA);
   ST7789_SendByte(0x00, ST7789_DATA); //0
   ST7789_SendByte(0x00, ST7789_DATA);
   ST7789_SendByte(0xEF, ST7789_DATA); //239

   ST7789_SendByte(0x29, ST7789_CMD);
}

设置窗口函数

void ST7789_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
	if(ST7789_ROTATION==0)
	{
		ST7789_SendByte(0x2a, ST7789_CMD);//列地址设置
		ST7789_SendHalfWord(x1);
		ST7789_SendHalfWord(x2);
		ST7789_SendByte(0x2b, ST7789_CMD);//行地址设置
		ST7789_SendHalfWord(y1);
		ST7789_SendHalfWord(y2);
		ST7789_SendByte(0x2c, ST7789_CMD);//储存器写
	}
	else if(ST7789_ROTATION == 90)
	{
      
		ST7789_SendByte(0x2a, ST7789_CMD);//列地址设置
		ST7789_SendHalfWord(x1);
		ST7789_SendHalfWord(x2);
		ST7789_SendByte(0x2b, ST7789_CMD);//行地址设置
		ST7789_SendHalfWord(y1);
		ST7789_SendHalfWord(y2);
		ST7789_SendByte(0x2c, ST7789_CMD);//储存器写
	}
	else if(ST7789_ROTATION == 180)
	{
      y1 += 80;
	   y2 += 80;
		ST7789_SendByte(0x2a, ST7789_CMD);//列地址设置
		ST7789_SendHalfWord(x1);
		ST7789_SendHalfWord(x2);
		ST7789_SendByte(0x2b, ST7789_CMD);//行地址设置
		ST7789_SendHalfWord(y1);
		ST7789_SendHalfWord(y2);
		ST7789_SendByte(0x2c, ST7789_CMD);//储存器写
	}
	else if(ST7789_ROTATION == 270)
	{
      x1 += 80;
      x2 += 80;
		ST7789_SendByte(0x2a, ST7789_CMD);//列地址设置
		ST7789_SendHalfWord(x1);
		ST7789_SendHalfWord(x2);
		ST7789_SendByte(0x2b, ST7789_CMD);//行地址设置
		ST7789_SendHalfWord(y1);
		ST7789_SendHalfWord(y2);
		ST7789_SendByte(0x2c, ST7789_CMD);//储存器写
	}
   else
   {
   }
}

编写设置窗口函数,有些角度需要加80的偏移,这里简单解释一下

因为屏幕是240*240的但是芯片本身支持240*320

初始化的时候可以设置屏幕镜像旋转等参数,如下图所示

0度对应MV=0,MX=0,MY=0

90度对应MV=1,MX=1,MY=0

180度对应MV=0,MX=1,MY=1

270度对应MV=1,MX=0,MY=1

情况一:正常的0度旋转

黑色代表屏幕可见区域(240*240),红色是芯片RAM(240*320),蓝色是起始坐标,此时不需要偏移

情况二:顺时针90度旋转

黑色代表屏幕可见区域(240*240),红色是芯片RAM(240*320),蓝色是起始坐标,此时不需要偏移

情况三:180度旋转

黑色代表屏幕可见区域(240*240),红色是芯片RAM(240*320),蓝色是我们想要的起始坐标(0,0),紫色的是芯片的(0,0)坐标

此时如果setwindow(0,0),那么实际上是从紫色的地方开始的,这部分已经在屏幕外面,因此Y需要增加80

情况四:顺时针270度旋转

黑色代表屏幕可见区域(240*240),红色是芯片RAM(240*320),蓝色是我们想要的起始坐标(0,0),紫色的是芯片的(0,0)坐标

此时如果setwindow(0,0),那么实际上是从紫色的地方开始的,这部分已经在屏幕外面,因此X需要增加80

手册里镜像的操作读者可以自行编写,明白原理后都是相通的

清屏函数

void ST7789_Clear(uint16_t color)
{
   uint16_t i,j;
   ST7789_Address_Set(0,0,240-1,240-1);

   for ( i = 0; i < ST7789_BUF_SIZE; i += 2)
   {
      ST7789_Buf[i] = color >> 8;
      ST7789_Buf[i + 1] = color & 0xFF;
   }
   for ( i = 0; i < 240 * 240 * 2 / ST7789_BUF_SIZE; i++)
   {
      ST7789_SendMultiByte(ST7789_Buf, ST7789_BUF_SIZE);
   }
}

效果

ST7789_Clear(BLUE);

逻辑分析仪测试波形如下,清屏耗费150ms和21ms

void ST7789_DrawPixel(uint16_t x,uint16_t y,uint16_t color)
{
   ST7789_Address_Set(x,y,x,y);//设置光标位置 
   ST7789_SendHalfWord(color);
}

效果

   ST7789_Clear(BLACK);    
   ST7789_DrawPixel(0, 100, WHITE);
   ST7789_DrawPixel(239, 100, WHITE);

画单色水平线函数

void ST7789_DrawHLine(uint16_t xs, uint16_t xe,uint16_t y,uint16_t color)
{
   uint16_t i,j;
   ST7789_Address_Set(xs,y,xe,y);//设置光标位置 


   for ( i = 0; i < (xe - xs + 1) * 2; i += 2)
   {
      ST7789_Buf[i] = color >> 8;
      ST7789_Buf[i + 1] = color & 0xFF;
   }
   ST7789_SendMultiByte(ST7789_Buf, (xe - xs + 1) * 2);
}

效果

   ST7789_Clear(BLACK);    
   ST7789_DrawPixel(0, 100, WHITE);
   ST7789_DrawPixel(239, 100, WHITE);
   ST7789_DrawHLine(1,238,100,RED);

画单色垂直线函数

void ST7789_DrawVLine(uint16_t ys, uint16_t ye, uint16_t x, uint16_t color)
{
   uint16_t i,j;
   ST7789_Address_Set(x,ys,x,ye);//设置光标位置 

   for ( i = 0; i < (ye - ys + 1) * 2; i += 2)
   {
      ST7789_Buf[i] = color >> 8;
      ST7789_Buf[i + 1] = color & 0xFF;
   }
   ST7789_SendMultiByte(ST7789_Buf, (ye - ys + 1) * 2);
}

效果

   ST7789_Clear(BLACK);    
   ST7789_DrawPixel(0, 100, WHITE);
   ST7789_DrawPixel(239, 100, WHITE);
   ST7789_DrawHLine(1,238,100,RED);
   ST7789_DrawVLine(0,199,100,BLUE);

区域填充函数

void ST7789_FillRect(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye, uint16_t color)
{
   uint16_t i,j;
   uint32_t depth;
   depth = (ye - ys + 1) * (xe - xs + 1) * 2;
   ST7789_Address_Set(xs, ys, xe, ye);//设置光标位置 

   if (depth < ST7789_BUF_SIZE)
   {
      for ( i = 0; i < depth; i += 2)
      {
         ST7789_Buf[i] = color >> 8;
         ST7789_Buf[i + 1] = color & 0xFF;
      }
      ST7789_SendMultiByte(ST7789_Buf, depth);
   }
   else
   {
      for ( i = 0; i < ST7789_BUF_SIZE; i += 2)
      {
         ST7789_Buf[i] = color >> 8;
         ST7789_Buf[i + 1] = color & 0xFF;
      }

      for ( i = 0; i < depth / ST7789_BUF_SIZE; i++)
      {
         ST7789_SendMultiByte(ST7789_Buf, ST7789_BUF_SIZE);
      }
      
      if (depth % ST7789_BUF_SIZE != 0)
      {
         ST7789_SendMultiByte(ST7789_Buf, (depth % ST7789_BUF_SIZE));
      }
      else
      {
         
      }
   }
}

效果

   ST7789_Clear(BLACK);    
   ST7789_DrawPixel(0, 100, WHITE);
   ST7789_DrawPixel(239, 100, WHITE);
   ST7789_DrawHLine(1,238,100,RED);
   ST7789_DrawVLine(0,199,100,BLUE);
  ST7789_FillRect(101, 0, 200, 199, RED);

画彩色线函数

/**
 * xsize is in [0,239]
 */
void ST7789_DrawBitLine16BPP(uint16_t xs, uint16_t y, uint8_t const * p, uint16_t xsize)
{
   uint16_t i,j;
   ST7789_Address_Set(xs, y, xs + xsize - 1, y);//设置光标位置 
   for ( i = 0; i < xsize * 2; i+=2)
   {
      // ST7789_Buf[i] = *(p + i) >> 8;
      // ST7789_Buf[i + 1] = *(p + i + 1) & 0xFF;
      ST7789_Buf[i + 1] = *(p + i);
      ST7789_Buf[i] = *(p + i + 1);
   }

   ST7789_SendMultiByte(ST7789_Buf, xsize * 2);
}

画图函数

void ST7789_DrawBitmap(uint16_t xs, uint16_t ys, uint16_t xsize, uint16_t ysize, uint8_t *p)
{
   uint16_t i,j;
   for ( i = 0; i < ysize; i++)
   {
      ST7789_DrawBitLine16BPP(xs, ys + i, p + i * xsize  * 2, xsize);
   }
}

效果

ST7789_DrawBitmap(0, 0, bmphonk.XSize, bmphonk.YSize, bmphonk.pData);

逻辑分析仪测试波形如下,画一张240*240的图耗费195ms和67ms

附录

ST7789.c

#include "ST7789.h"


/* at least 240*2 and can be divided wholely by 240*240*2 */
#define ST7789_BUF_SIZE (240 * 2)
uint8_t ST7789_Buf[ST7789_BUF_SIZE];


void ST7789_SendByte(uint8_t dat, ST7789_DCType DC)
{
   ST7789_CS_LOW();

   (DC == ST7789_DATA) ? ST7789_DC_HIGH() : ST7789_DC_LOW();

   HAL_SPI_Transmit_DMA(ST7789_SPI, &dat, 1);
   while (HAL_SPI_GetState(ST7789_SPI) == HAL_SPI_STATE_BUSY_TX);

   ST7789_CS_HIGH();
}

void ST7789_SendHalfWord(uint16_t dat)
{
   uint8_t da[2];
   ST7789_CS_LOW();
   ST7789_DC_HIGH();

   da[0] = dat >> 8;
   da[1] = dat & 0xFF;

   HAL_SPI_Transmit_DMA(ST7789_SPI, da, 2);
   while (HAL_SPI_GetState(ST7789_SPI) == HAL_SPI_STATE_BUSY_TX);

   ST7789_CS_HIGH();
}

void ST7789_SendMultiByte(uint8_t* dat, uint16_t len)
{
   ST7789_CS_LOW();
   ST7789_DC_HIGH();

   HAL_SPI_Transmit_DMA(ST7789_SPI, dat, len);
   while (HAL_SPI_GetState(ST7789_SPI) == HAL_SPI_STATE_BUSY_TX);

   ST7789_CS_HIGH();
}


void ST7789_Init(void)
{
   ST7789_BL_HIGH();
   ST7789_CS_HIGH();

   ST7789_RST_HIGH();
   ST7789_RST_LOW();
	HAL_Delay(1);
	ST7789_RST_HIGH();
	HAL_Delay(120);

   ST7789_SendByte(0x11, ST7789_CMD);	

   ST7789_SendByte(0x3A, ST7789_CMD);			
   ST7789_SendByte(0x55, ST7789_DATA);   //   5 565  6 666

   ST7789_SendByte(0xB2, ST7789_CMD);			
   ST7789_SendByte(0x0C, ST7789_DATA);
   ST7789_SendByte(0x0C, ST7789_DATA); 
   ST7789_SendByte(0x00, ST7789_DATA); 
   ST7789_SendByte(0x33, ST7789_DATA); 
   ST7789_SendByte(0x33, ST7789_DATA); 			

   ST7789_SendByte(0xB7, ST7789_CMD);			
   ST7789_SendByte(0x35, ST7789_DATA);

   ST7789_SendByte(0xBB, ST7789_CMD);			
   ST7789_SendByte(0x32, ST7789_DATA); //Vcom=1.35V
                                          
   ST7789_SendByte(0xC2, ST7789_CMD);			
   ST7789_SendByte(0x01, ST7789_DATA);

   ST7789_SendByte(0xC3, ST7789_CMD);			
   ST7789_SendByte(0x19, ST7789_DATA); //GVDD=4.8V 
                                          
   ST7789_SendByte(0xC4, ST7789_CMD);			
   ST7789_SendByte(0x20, ST7789_DATA); //VDV, 0x20:0v

   ST7789_SendByte(0xC6, ST7789_CMD);			
   ST7789_SendByte(0x0F, ST7789_DATA); //0x0F:60Hz        	

   ST7789_SendByte(0xD0, ST7789_CMD);			
   ST7789_SendByte(0xA4, ST7789_DATA);
   ST7789_SendByte(0xA1, ST7789_DATA); 											  												  																								
         
   ST7789_SendByte(0xE0, ST7789_CMD);     
   ST7789_SendByte(0xD0, ST7789_DATA);   
   ST7789_SendByte(0x08, ST7789_DATA);   
   ST7789_SendByte(0x0E, ST7789_DATA);   
   ST7789_SendByte(0x09, ST7789_DATA);   
   ST7789_SendByte(0x09, ST7789_DATA);   
   ST7789_SendByte(0x05, ST7789_DATA);   
   ST7789_SendByte(0x31, ST7789_DATA);   
   ST7789_SendByte(0x33, ST7789_DATA);   
   ST7789_SendByte(0x48, ST7789_DATA);   
   ST7789_SendByte(0x17, ST7789_DATA);   
   ST7789_SendByte(0x14, ST7789_DATA);   
   ST7789_SendByte(0x15, ST7789_DATA);   
   ST7789_SendByte(0x31, ST7789_DATA);   
   ST7789_SendByte(0x34, ST7789_DATA);   

   ST7789_SendByte(0xE1, ST7789_CMD);     
   ST7789_SendByte(0xD0, ST7789_DATA);   
   ST7789_SendByte(0x08, ST7789_DATA);   
   ST7789_SendByte(0x0E, ST7789_DATA);   
   ST7789_SendByte(0x09, ST7789_DATA);   
   ST7789_SendByte(0x09, ST7789_DATA);   
   ST7789_SendByte(0x15, ST7789_DATA);   
   ST7789_SendByte(0x31, ST7789_DATA);   
   ST7789_SendByte(0x33, ST7789_DATA);   
   ST7789_SendByte(0x48, ST7789_DATA);   
   ST7789_SendByte(0x17, ST7789_DATA);   
   ST7789_SendByte(0x14, ST7789_DATA);   
   ST7789_SendByte(0x15, ST7789_DATA);   
   ST7789_SendByte(0x31, ST7789_DATA);   
   ST7789_SendByte(0x34, ST7789_DATA);   

   ST7789_SendByte(0x21, ST7789_CMD);

   ST7789_SendByte(0x36, ST7789_CMD); //MX, MY, RGB mode 
#if (ST7789_ROTATION == 0)
   ST7789_SendByte(0x00, ST7789_DATA);
#elif (ST7789_ROTATION == 90)
   ST7789_SendByte(0x60, ST7789_DATA);//90
#elif (ST7789_ROTATION == 180)
   ST7789_SendByte(0xC0, ST7789_DATA);//180
#elif (ST7789_ROTATION == 270)
   ST7789_SendByte(0xA0, ST7789_DATA);//270
#endif

   ST7789_SendByte(0x2A, ST7789_CMD); //Column Address Set
   ST7789_SendByte(0x00, ST7789_DATA);
   ST7789_SendByte(0x00, ST7789_DATA); //0
   ST7789_SendByte(0x00, ST7789_DATA);
   ST7789_SendByte(0xEF, ST7789_DATA); //239

   ST7789_SendByte(0x2B, ST7789_CMD); //Row Address Set
   ST7789_SendByte(0x00, ST7789_DATA);
   ST7789_SendByte(0x00, ST7789_DATA); //0
   ST7789_SendByte(0x00, ST7789_DATA);
   ST7789_SendByte(0xEF, ST7789_DATA); //239

   ST7789_SendByte(0x29, ST7789_CMD);
}

void ST7789_Address_Set(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
{
	if(ST7789_ROTATION==0)
	{
		ST7789_SendByte(0x2a, ST7789_CMD);//列地址设置
		ST7789_SendHalfWord(x1);
		ST7789_SendHalfWord(x2);
		ST7789_SendByte(0x2b, ST7789_CMD);//行地址设置
		ST7789_SendHalfWord(y1);
		ST7789_SendHalfWord(y2);
		ST7789_SendByte(0x2c, ST7789_CMD);//储存器写
	}
	else if(ST7789_ROTATION == 90)
	{
      
		ST7789_SendByte(0x2a, ST7789_CMD);//列地址设置
		ST7789_SendHalfWord(x1);
		ST7789_SendHalfWord(x2);
		ST7789_SendByte(0x2b, ST7789_CMD);//行地址设置
		ST7789_SendHalfWord(y1);
		ST7789_SendHalfWord(y2);
		ST7789_SendByte(0x2c, ST7789_CMD);//储存器写
	}
	else if(ST7789_ROTATION == 180)
	{
      y1 += 80;
	   y2 += 80;
		ST7789_SendByte(0x2a, ST7789_CMD);//列地址设置
		ST7789_SendHalfWord(x1);
		ST7789_SendHalfWord(x2);
		ST7789_SendByte(0x2b, ST7789_CMD);//行地址设置
		ST7789_SendHalfWord(y1);
		ST7789_SendHalfWord(y2);
		ST7789_SendByte(0x2c, ST7789_CMD);//储存器写
	}
	else if(ST7789_ROTATION == 270)
	{
      x1 += 80;
      x2 += 80;
		ST7789_SendByte(0x2a, ST7789_CMD);//列地址设置
		ST7789_SendHalfWord(x1);
		ST7789_SendHalfWord(x2);
		ST7789_SendByte(0x2b, ST7789_CMD);//行地址设置
		ST7789_SendHalfWord(y1);
		ST7789_SendHalfWord(y2);
		ST7789_SendByte(0x2c, ST7789_CMD);//储存器写
	}
   else
   {
   }
}

void ST7789_Clear(uint16_t color)
{
   uint16_t i,j;
   ST7789_Address_Set(0,0,ST7789_HIGHT - 1,ST7789_WIDTH - 1);

   for ( i = 0; i < ST7789_BUF_SIZE; i += 2)
   {
      ST7789_Buf[i] = color >> 8;
      ST7789_Buf[i + 1] = color & 0xFF;
   }
   for ( i = 0; i < ST7789_HIGHT * ST7789_WIDTH * 2 / ST7789_BUF_SIZE; i++)
   {
      ST7789_SendMultiByte(ST7789_Buf, ST7789_BUF_SIZE);
   }
}

void ST7789_DrawPixel(uint16_t x,uint16_t y,uint16_t color)
{
   ST7789_Address_Set(x,y,x,y);//设置光标位置 
   ST7789_SendHalfWord(color);
}

void ST7789_DrawHLine(uint16_t xs, uint16_t xe,uint16_t y,uint16_t color)
{
   uint16_t i,j;
   ST7789_Address_Set(xs,y,xe,y);//设置光标位置 


   for ( i = 0; i < (xe - xs + 1) * 2; i += 2)
   {
      ST7789_Buf[i] = color >> 8;
      ST7789_Buf[i + 1] = color & 0xFF;
   }
   ST7789_SendMultiByte(ST7789_Buf, (xe - xs + 1) * 2);
}



void ST7789_DrawVLine(uint16_t ys, uint16_t ye, uint16_t x, uint16_t color)
{
   uint16_t i,j;
   ST7789_Address_Set(x,ys,x,ye);//设置光标位置 

   for ( i = 0; i < (ye - ys + 1) * 2; i += 2)
   {
      ST7789_Buf[i] = color >> 8;
      ST7789_Buf[i + 1] = color & 0xFF;
   }
   ST7789_SendMultiByte(ST7789_Buf, (ye - ys + 1) * 2);
}

void ST7789_FillRect(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye, uint16_t color)
{
   uint16_t i,j;
   uint32_t depth;
   depth = (ye - ys + 1) * (xe - xs + 1) * 2;
   ST7789_Address_Set(xs, ys, xe, ye);//设置光标位置 

   if (depth < ST7789_BUF_SIZE)
   {
      for ( i = 0; i < depth; i += 2)
      {
         ST7789_Buf[i] = color >> 8;
         ST7789_Buf[i + 1] = color & 0xFF;
      }
      ST7789_SendMultiByte(ST7789_Buf, depth);
   }
   else
   {
      for ( i = 0; i < ST7789_BUF_SIZE; i += 2)
      {
         ST7789_Buf[i] = color >> 8;
         ST7789_Buf[i + 1] = color & 0xFF;
      }

      for ( i = 0; i < depth / ST7789_BUF_SIZE; i++)
      {
         ST7789_SendMultiByte(ST7789_Buf, ST7789_BUF_SIZE);
      }
      
      if (depth % ST7789_BUF_SIZE != 0)
      {
         ST7789_SendMultiByte(ST7789_Buf, (depth % ST7789_BUF_SIZE));
      }
      else
      {
         
      }
   }
}

/**
 * xsize is in [0,239]
 */
void ST7789_DrawBitLine16BPP(uint16_t xs, uint16_t y, uint8_t const * p, uint16_t xsize)
{
   uint16_t i,j;
   ST7789_Address_Set(xs, y, xs + xsize - 1, y);//设置光标位置 
   for ( i = 0; i < xsize * 2; i+=2)
   {
      // ST7789_Buf[i] = *(p + i) >> 8;
      // ST7789_Buf[i + 1] = *(p + i + 1) & 0xFF;
      ST7789_Buf[i + 1] = *(p + i);
      ST7789_Buf[i] = *(p + i + 1);
   }

   ST7789_SendMultiByte(ST7789_Buf, xsize * 2);
}



void ST7789_DrawBitmap(uint16_t xs, uint16_t ys, uint16_t xsize, uint16_t ysize, uint8_t *p)
{
   uint16_t i,j;
   for ( i = 0; i < ysize; i++)
   {
      ST7789_DrawBitLine16BPP(xs, ys + i, p + i * xsize  * 2, xsize);
   }
}

ST7789.h

#ifndef ST7789_H
#define ST7789_H		


#include "main.h"
#include "gpio.h"
#include "spi.h"
#include "stdint.h"


#define ST7789_ROTATION 0
#define ST7789_SPI &hspi1

#define ST7789_BUFFER


#define ST7789_HIGHT 240
#define ST7789_WIDTH 240


#define ST7789_RST_LOW()       HAL_GPIO_WritePin(RES_GPIO_Port,RES_Pin,GPIO_PIN_RESET)
#define ST7789_RST_HIGH()      HAL_GPIO_WritePin(RES_GPIO_Port,RES_Pin,GPIO_PIN_SET)

#define ST7789_CS_LOW()        HAL_GPIO_WritePin(CS_GPIO_Port,CS_Pin,GPIO_PIN_RESET)
#define ST7789_CS_HIGH()       HAL_GPIO_WritePin(CS_GPIO_Port,CS_Pin,GPIO_PIN_SET)

#define ST7789_DC_LOW()        HAL_GPIO_WritePin(DC_GPIO_Port,DC_Pin,GPIO_PIN_RESET)
#define ST7789_DC_HIGH()       HAL_GPIO_WritePin(DC_GPIO_Port,DC_Pin,GPIO_PIN_SET)

#define ST7789_BL_LOW()        HAL_GPIO_WritePin(BL_GPIO_Port,BL_Pin,GPIO_PIN_RESET)
#define ST7789_BL_HIGH()       HAL_GPIO_WritePin(BL_GPIO_Port,BL_Pin,GPIO_PIN_SET)


#define WHITE         	 0xFFFF
#define BLACK         	 0x0000	  
#define BLUE           	 0x001F  
#define BRED             0XF81F
#define GRED 			 0XFFE0
#define GBLUE			 0X07FF
#define RED           	 0xF800
#define MAGENTA       	 0xF81F
#define GREEN         	 0x07E0
#define CYAN          	 0x7FFF
#define YELLOW        	 0xFFE0
#define BROWN 			 0XBC40
#define BRRED 			 0XFC07
#define GRAY  			 0X8430



typedef enum
{
   ST7789_CMD,
   ST7789_DATA,
}ST7789_DCType;

typedef struct
{
   ST7789_DCType DC;
   uint8_t data;
}ST7789_InitSequenceType;


typedef struct {
   uint16_t XSize;
   uint16_t YSize;
   uint16_t BytesPerLine;
   uint16_t BitsPerPixel;
   const uint8_t * pData;
 } GUI_BITMAP;


void ST7789_Clear(uint16_t Color);
void ST7789_SendByte(uint8_t dat, ST7789_DCType DC);
void ST7789_SendHalfWord(uint16_t dat);
void ST7789_SendMultiByte(uint8_t* dat, uint16_t len);
void ST7789_Init(void);
void ST7789_DrawPixel(uint16_t x,uint16_t y,uint16_t color);
void ST7789_DrawHLine(uint16_t xs, uint16_t xe,uint16_t y,uint16_t color);
void ST7789_DrawVLine(uint16_t ys, uint16_t ye,uint16_t x,uint16_t color);
void ST7789_FillRect(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye, uint16_t color);
void ST7789_DrawBitmap(uint16_t xs, uint16_t ys, uint16_t xsize, uint16_t ysize, uint8_t *p);

#endif

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2333994.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

10min速通Linux文件传输

实验环境 在Linux中传输文件需要借助网络以及sshd&#xff0c;我们可通过systemctl status sshd来查看sshd状态 若服务未开启我们可通过systemctl enable --now sshd来开启sshd服务 将/etc/ssh/sshd_config中的PermitRootLogin 状态修改为yes 传输文件 scp scp &#xff08;Sec…

dify windos,linux下载安装部署,提供百度云盘地址

dify1.0.1 windos安装包百度云盘地址 通过网盘分享的文件&#xff1a;dify-1.0.1.zip 链接: 百度网盘 请输入提取码 提取码: 1234 dify安装包 linux安装包百度云盘地址 通过网盘分享的文件&#xff1a;dify-1.0.1.tar.gz 链接: 百度网盘 请输入提取码 提取码: 1234 1.安装…

使用 TFIDF+分类器 范式进行企业级文本分类(二)

1.开场白 上一期讲了 TF-IDF 的底层原理&#xff0c;简单讲了一下它可以将文本转为向量形式&#xff0c;并搭配相应分类器做文本分类&#xff0c;且即便如今的企业实践中也十分常见。详情请见我的上一篇文章 从One-Hot到TF-IDF&#xff08;点我跳转&#xff09; 光说不练假把…

《车辆人机工程-汽车驾驶操纵实验》

汽车操纵装置有哪几种&#xff0c;各有什么特点 汽车操纵装置是驾驶员直接控制车辆行驶状态的关键部件&#xff0c;主要包括以下几种&#xff0c;其特点如下&#xff1a; 一、方向盘&#xff08;转向操纵装置&#xff09; 作用&#xff1a;控制车辆行驶方向&#xff0c;通过转…

python高级编程一(生成器与高级编程)

@TOC 生成器 生成器使用 通过列表⽣成式,我们可以直接创建⼀个列表。但是,受到内存限制,列表容量肯定是有限的。⽽且,创建⼀个包含100万个元素的列表,不仅占⽤很⼤的存储空间,如果我们仅仅需要访问前⾯⼏个元素,那后⾯绝⼤多数元素占 ⽤的空间都⽩⽩浪费了。所以,如果…

单片机Day05---动态数码管显示01234567

一、原理图 数组索引段码值二进制显示内容00x3f0011 1111010x060000 0110120x5b0101 1011230x4f0100 1111340x660110 0110450x6d0110 1101560x7d0111 1101670x070000 0111780x7f0111 1111890x6f0110 11119100x770111 0111A110x7c0111 1100B120x390011 1001C130x5e0101 1110D140…

muduo库源码分析: One Loop Per Thread

One Loop Per Thread的含义就是&#xff0c;一个EventLoop和一个线程唯一绑定&#xff0c;和这个EventLoop有关的&#xff0c;被这个EventLoop管辖的一切操作都必须在这个EventLoop绑定线程中执行 1.在MainEventLoop中&#xff0c;负责新连接建立的操作都要在MainEventLoop线程…

MCP结合高德地图完成配置

文章目录 1.MCP到底是什么2.cursor配置2.1配置之后的效果2.2如何进行正确的配置2.3高德地图获取key2.4选择匹配的模型 1.MCP到底是什么 作为学生&#xff0c;我们应该如何认识MCP&#xff1f;最近看到了好多跟MCP相关的文章&#xff0c;我觉得我们不应该盲目的追求热点的技术&…

重读《人件》Peopleware -(5)Ⅰ管理人力资源Ⅳ-质量—若时间允许

20世纪的心理学理论认为&#xff0c;人类的性格主要由少数几个基本本能所主导&#xff1a;生存、自尊、繁衍、领地等。这些本能直接嵌入大脑的“固件”中。我们可以在没有强烈情感的情况下理智地考虑这些本能&#xff08;就像你现在正在做的那样&#xff09;&#xff0c;但当我…

文献总结:AAAI2025-UniV2X-End-to-end autonomous driving through V2X cooperation

UniV2X 一、文章基本信息二、文章背景三、UniV2X框架1. 车路协同自动驾驶问题定义2. 稀疏-密集混合形态数据3. 交叉视图数据融合&#xff08;智能体融合&#xff09;4. 交叉视图数据融合&#xff08;车道融合&#xff09;5. 交叉视图数据融合&#xff08;占用融合&#xff09;6…

制造一只电子喵 (qwen2.5:0.5b 微调 LoRA 使用 llama-factory)

AI (神经网络模型) 可以认为是计算机的一种新的 “编程” 方式. 为了充分利用计算机, 只学习传统的编程 (编程语言/代码) 是不够的, 我们还要掌握 AI. 本文以 qwen2.5 和 llama-factory 举栗, 介绍语言模型 (LLM) 的微调 (LoRA SFT). 为了方便上手, 此处选择使用小模型 (qwen2…

Redis核心功能实现

前言 学习是个输入的过程&#xff0c;在进行输入之后再进行一些输出&#xff0c;比如写写文章&#xff0c;笔记&#xff0c;或者做一些技术串讲&#xff0c;虽然需要花费不少时间&#xff0c;但是好处很多&#xff0c;首先是能通过输出给自己的输入带来一些动力&#xff0c;然…

【连载3】基础智能体的进展与挑战综述

基础智能体的进展与挑战综述 从类脑智能到具备可进化性、协作性和安全性的系统 【翻译团队】刘军(liujunbupt.edu.cn) 钱雨欣玥 冯梓哲 李正博 李冠谕 朱宇晗 张霄天 孙大壮 黄若溪 2. 认知 人类认知是一种复杂的信息处理系统&#xff0c;它通过多个专门的神经回路协调运行…

MacOs java环境配置+maven环境配置踩坑实录

oracl官网下载jdk 1.8的安装包 注意可能需要注册&#xff01;&#xff01;&#xff01; 下载链接&#xff1a;下载地址点击 注意晚上就不要下载了 报错400 &#xff01;&#xff01;&#xff01; 1.点击安装嘛 2.配置环境变量 export JAVA_HOME/Library/Java/Java…

【Git】--- 企业级开发流程

Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏&#xff1a; Git 本篇博客我们讲解Git在企业开发中的整体流程&#xff0c;理解Git在实际企业开发中的高效设计。 &#x1f3e0; 企业级开发流程 一个软件从零开始到最…

蓝桥杯嵌入式历年省赛客观题

一.第十五届客观题 第十四届省赛 十三届 十二届

解决2080Ti使用节点ComfyUI-PuLID-Flux-Enhanced中遇到的问题

使用蓝大的工作流《一键同时换头、换脸、发型、发色之双pulid技巧》 刚开始遇到的是不支持bf16的错误 根据《bf16 is only supported on A100 GPUs #33》中提到&#xff0c;修改pulidflux.py中的dtype 为 dtype torch.float16 后&#xff0c;出现新的错误&#xff0c;这个…

LabVIEW驱动开发的解决思路

在科研项目中&#xff0c;常面临将其他语言开发的定制采集设备驱动转换为 LabVIEW 适用形式的难题。特别是当原驱动支持匮乏、开发人员技术支持不足时&#xff0c;如何抉择解决路径成为关键。以下提供具体解决思路&#xff0c;助力高效解决问题。 ​ 一、评估现有驱动死磕的可…

七、Qt框架编写的多线程应用程序

一、大纲 学习内容&#xff1a;使用两个线程&#xff0c;分别点击两个按钮&#xff0c;触发两个不同的效果 所需控件&#xff1a;两个button、三个label 涉及知识点&#xff1a;多线程、Qt的connect机制、定时器、互斥锁 需求&#xff1a; 1&#xff0c;多线程定时计数&#x…

MATLAB求和∑怎么用?

MATLAB求和∑怎么用&#xff1f; 一&#xff1a;题目&#xff1a;求下列方程的和 二、代码如下 1.syms函数 &#xff08;方法一) 代码如下&#xff08;示例&#xff09;&#xff1a; 1. syms x 2. symsum((x.^22*x).^3,1,100) 3. 2.直接用循环 (方法二) 代码如下&am…