【STM32】ST7789屏幕驱动
目录
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 666ST7789_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.35VST7789_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:0vST7789_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
#endifST7789_SendByte(0x2A, ST7789_CMD); //Column Address SetST7789_SendByte(0x00, ST7789_DATA);ST7789_SendByte(0x00, ST7789_DATA); //0ST7789_SendByte(0x00, ST7789_DATA);ST7789_SendByte(0xEF, ST7789_DATA); //239ST7789_SendByte(0x2B, ST7789_CMD); //Row Address SetST7789_SendByte(0x00, ST7789_DATA);ST7789_SendByte(0x00, ST7789_DATA); //0ST7789_SendByte(0x00, ST7789_DATA);ST7789_SendByte(0xEF, ST7789_DATA); //239ST7789_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 666ST7789_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.35VST7789_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:0vST7789_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
#endifST7789_SendByte(0x2A, ST7789_CMD); //Column Address SetST7789_SendByte(0x00, ST7789_DATA);ST7789_SendByte(0x00, ST7789_DATA); //0ST7789_SendByte(0x00, ST7789_DATA);ST7789_SendByte(0xEF, ST7789_DATA); //239ST7789_SendByte(0x2B, ST7789_CMD); //Row Address SetST7789_SendByte(0x00, ST7789_DATA);ST7789_SendByte(0x00, ST7789_DATA); //0ST7789_SendByte(0x00, ST7789_DATA);ST7789_SendByte(0xEF, ST7789_DATA); //239ST7789_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 0X8430typedef 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相关文章:
【STM32】ST7789屏幕驱动
目录 CubeMX配置 配置SPI 开DMA 时钟树 堆栈大小 Keil工程配置 添加两个group 添加文件包含路径 驱动编写 写单字节函数 写字函数 写多字节函数 初始化函数 设置窗口函数 情况一:正常的0度旋转 情况二:顺时针90度旋转 情况三࿱…...
深入理解 PyTorch 的 nn.Embedding:词向量映射及变量 weight 的更新机制
文章目录 前言一、直接使用 nn.Embedding 获得变量1、典型场景2、示例代码:3、特点 二、使用 iou_token nn.Embedding(1, transformer_dim) 并访问 iou_token.weight1、典型场景2、示例代码:3、特点 三、第一种方法在模型更新中会更新其值吗?…...
10min速通Linux文件传输
实验环境 在Linux中传输文件需要借助网络以及sshd,我们可通过systemctl status sshd来查看sshd状态 若服务未开启我们可通过systemctl enable --now sshd来开启sshd服务 将/etc/ssh/sshd_config中的PermitRootLogin 状态修改为yes 传输文件 scp scp (Sec…...
dify windos,linux下载安装部署,提供百度云盘地址
dify1.0.1 windos安装包百度云盘地址 通过网盘分享的文件:dify-1.0.1.zip 链接: 百度网盘 请输入提取码 提取码: 1234 dify安装包 linux安装包百度云盘地址 通过网盘分享的文件:dify-1.0.1.tar.gz 链接: 百度网盘 请输入提取码 提取码: 1234 1.安装…...
使用 TFIDF+分类器 范式进行企业级文本分类(二)
1.开场白 上一期讲了 TF-IDF 的底层原理,简单讲了一下它可以将文本转为向量形式,并搭配相应分类器做文本分类,且即便如今的企业实践中也十分常见。详情请见我的上一篇文章 从One-Hot到TF-IDF(点我跳转) 光说不练假把…...
《车辆人机工程-汽车驾驶操纵实验》
汽车操纵装置有哪几种,各有什么特点 汽车操纵装置是驾驶员直接控制车辆行驶状态的关键部件,主要包括以下几种,其特点如下: 一、方向盘(转向操纵装置) 作用:控制车辆行驶方向,通过转…...
[ABC400F] Happy Birthday! 3 题解
考虑正难则反。问题转化为: 一个环上有 n n n 个物品,颜色分别为 c o l i col_i coli,每次操作选择两个数 i , j i, j i,j 使得 ∀ k ∈ [ i , j ] , c o l k c o l i ∨ c o l k 0 \forall k \in [i, j], col_k col_i \lor col_k …...
python高级编程一(生成器与高级编程)
@TOC 生成器 生成器使用 通过列表⽣成式,我们可以直接创建⼀个列表。但是,受到内存限制,列表容量肯定是有限的。⽽且,创建⼀个包含100万个元素的列表,不仅占⽤很⼤的存储空间,如果我们仅仅需要访问前⾯⼏个元素,那后⾯绝⼤多数元素占 ⽤的空间都⽩⽩浪费了。所以,如果…...
Go 字符串四种拼接方式的性能对比
简介 使用完整的基准测试代码文件,可以直接运行来比较四种字符串拼接方法的性能。 for 索引 的方式 for range 的方式 strings.Join 的方式 strings.Builder 的方式 写一个基准测试文件 echo_bench_test.go package mainimport ("os""stri…...
windows安装fastbev环境时,安装mmdetection3d出现的问题总结
出现的问题如下: C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v11.3\include\crt/host_config.h(160): fatal error C1189: #error: -- unsupported Microsoft Visual Studio version! Only the versions between 2017 and 2019 (inclusive) are supporte…...
单片机Day05---动态数码管显示01234567
一、原理图 数组索引段码值二进制显示内容00x3f0011 1111010x060000 0110120x5b0101 1011230x4f0100 1111340x660110 0110450x6d0110 1101560x7d0111 1101670x070000 0111780x7f0111 1111890x6f0110 11119100x770111 0111A110x7c0111 1100B120x390011 1001C130x5e0101 1110D140…...
【Python3教程】Python3基础篇之数据结构
博主介绍:✌全网粉丝22W+,CSDN博客专家、Java领域优质创作者,掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围:SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物联网、机器学习等设计与开发。 感兴趣的可…...
muduo库源码分析: One Loop Per Thread
One Loop Per Thread的含义就是,一个EventLoop和一个线程唯一绑定,和这个EventLoop有关的,被这个EventLoop管辖的一切操作都必须在这个EventLoop绑定线程中执行 1.在MainEventLoop中,负责新连接建立的操作都要在MainEventLoop线程…...
使用Python解决Logistic方程
引言 在数学和计算机科学中,Logistic 方程是描述人口增长、传播过程等现象的一种常见模型。它通常用于表示一种有限资源下的增长过程,比如动物种群、疾病传播等。本文将带领大家通过 Python 实现 Logistic 方程的求解,帮助你更好地理解这一经典数学模型。 1.什么是 Logist…...
AI Agent工程师认证-学习笔记(3)——【多Agent】MetaGPT
学习链接:【多Agent】MetaGPT学习教程 源代码链接(觉得很好,star一下):GitHub - 基于MetaGPT的多智能体入门与开发教程 MetaGPT链接:GitHub - MetaGPT 前期准备 1、获取MetaGPT (1)使用pip获取MetaGPT pip install metagpt==0.6.6#或者在国内加速安装镜像 #pip in…...
MCP结合高德地图完成配置
文章目录 1.MCP到底是什么2.cursor配置2.1配置之后的效果2.2如何进行正确的配置2.3高德地图获取key2.4选择匹配的模型 1.MCP到底是什么 作为学生,我们应该如何认识MCP?最近看到了好多跟MCP相关的文章,我觉得我们不应该盲目的追求热点的技术&…...
重读《人件》Peopleware -(5)Ⅰ管理人力资源Ⅳ-质量—若时间允许
20世纪的心理学理论认为,人类的性格主要由少数几个基本本能所主导:生存、自尊、繁衍、领地等。这些本能直接嵌入大脑的“固件”中。我们可以在没有强烈情感的情况下理智地考虑这些本能(就像你现在正在做的那样),但当我…...
文献总结:AAAI2025-UniV2X-End-to-end autonomous driving through V2X cooperation
UniV2X 一、文章基本信息二、文章背景三、UniV2X框架1. 车路协同自动驾驶问题定义2. 稀疏-密集混合形态数据3. 交叉视图数据融合(智能体融合)4. 交叉视图数据融合(车道融合)5. 交叉视图数据融合(占用融合)6…...
制造一只电子喵 (qwen2.5:0.5b 微调 LoRA 使用 llama-factory)
AI (神经网络模型) 可以认为是计算机的一种新的 “编程” 方式. 为了充分利用计算机, 只学习传统的编程 (编程语言/代码) 是不够的, 我们还要掌握 AI. 本文以 qwen2.5 和 llama-factory 举栗, 介绍语言模型 (LLM) 的微调 (LoRA SFT). 为了方便上手, 此处选择使用小模型 (qwen2…...
如何查询node inode上限是多少?
在 Linux 系统中,inode 上限由文件系统的类型和格式化时的参数决定。不同文件系统(如 ext4、XFS)有不同的查询方法。以下是详细操作步骤: 1. 确认文件系统类型 首先确定目标磁盘分区的文件系统类型(如 ext4、XFS&…...
Redis核心功能实现
前言 学习是个输入的过程,在进行输入之后再进行一些输出,比如写写文章,笔记,或者做一些技术串讲,虽然需要花费不少时间,但是好处很多,首先是能通过输出给自己的输入带来一些动力,然…...
驱动学习专栏--字符设备驱动篇--1_chrdevbase
字符设备驱动简介 字符设备是 Linux 驱动中最基本的一类设备驱动,字符设备就是一个一个字节,按照字节 流进行读写操作的设备,读写数据是分先后顺序的。比如我们最常见的点灯、按键、 IIC 、 SPI , LCD 等等都是字符设备&…...
Python及C++中的列表
一、Python中的列表(List) Python的列表是动态数组,内置于语言中,功能强大且易用,非常适合算法竞赛。 1. 基本概念 定义:列表是一个有序、可变的序列,可以存储任意类型的元素(整数…...
Oracle DROP、TRUNCATE 和 DELETE 原理
在 Oracle 11g 中,DROP、TRUNCATE 和 DELETE 是三种不同的数据清理操作,它们的底层原理和适用场景有显著差异 1. DELETE 的原理 类型:DML(数据操作语言) 功能:逐行删除表中符合条件的数据,保留…...
ida 使用记录
文章目录 伪代码-汇编hexstring快捷键 伪代码-汇编 流程图界面——F5——伪代码界面——再点Tab——流程图界面——再按空格——汇编界面流程图界面——空格——汇编界面 hex view - open subviews - hex dump string view - open subviews - string快捷键: sh…...
【连载3】基础智能体的进展与挑战综述
基础智能体的进展与挑战综述 从类脑智能到具备可进化性、协作性和安全性的系统 【翻译团队】刘军(liujunbupt.edu.cn) 钱雨欣玥 冯梓哲 李正博 李冠谕 朱宇晗 张霄天 孙大壮 黄若溪 2. 认知 人类认知是一种复杂的信息处理系统,它通过多个专门的神经回路协调运行…...
MacOs java环境配置+maven环境配置踩坑实录
oracl官网下载jdk 1.8的安装包 注意可能需要注册!!! 下载链接:下载地址点击 注意晚上就不要下载了 报错400 !!! 1.点击安装嘛 2.配置环境变量 export JAVA_HOME/Library/Java/Java…...
【Git】--- 企业级开发流程
Welcome to 9ilks Code World (๑•́ ₃ •̀๑) 个人主页: 9ilk (๑•́ ₃ •̀๑) 文章专栏: Git 本篇博客我们讲解Git在企业开发中的整体流程,理解Git在实际企业开发中的高效设计。 🏠 企业级开发流程 一个软件从零开始到最…...
SAP系统客户可回收包材库存管理
问题:客户可回收包材库存管理 现象:回收瓶无库存管理,在库数量以及在客户的库存数量没有统计,管理混乱。 解决方法: 客户可回收包装材料在SAP有标准的解决方案,在集团尚未启用该业务,首先…...
蓝桥杯嵌入式历年省赛客观题
一.第十五届客观题 第十四届省赛 十三届 十二届...
