CSDN专栏:
- 嵌入式程序开发实战
- 嵌入式双范式AI编程
- 嵌入式开发必掌握
- 嵌入式求职面试技术资料
第31讲:实战——SPI屏驱动快速试错、点亮屏幕
一、SPI屏幕驱动基础
SPI屏幕是嵌入式常见的显示设备,驱动屏幕需要正确配置SPI、理解屏幕控制命令、实现绘图功能。
1.1 常见SPI屏幕
小尺寸屏幕:
- 0.96寸 OLED(SSD1306):128x64
- 1.3寸 OLED(SH1106):128x64
- 1.8寸 TFT(ST7735):128x160
- 2.4寸 TFT(ILI9341):240x320
SPI接口:
- SCK:时钟
- MOSI:主出从入(数据)
- MISO:主入从出(可选)
- CS:片选
- DC:数据/命令选择
- RST:复位
1.2 驱动要点
SPI配置:
- 模式:主机模式
- 时钟极性/相位:根据屏幕芯片确定
- 速率:通常10-40MHz
- 数据位:8位
控制命令:
- 初始化序列:配置屏幕参数
- 写命令:发送控制命令
- 写数据:发送显示数据
- 刷新:更新显示
二、OLED屏幕驱动(SSD1306)
2.1 快速试错流程
第一步:AI生成初始驱动
Prompt:
生成STM32F103 SSD1306 OLED驱动: - SPI1:PA5(SCK)、PA7(MOSI) - CS:PA4 - DC:PA6 - RST:PB0 - 屏幕:0.96寸,128x64 - 使用HAL库AI生成:
#include"stm32f1xx_hal.h"#defineSSD1306_WIDTH128#defineSSD1306_HEIGHT64SPI_HandleTypeDef hspi1;voidSSD1306_Init(void);voidSSD1306_WriteCommand(uint8_tcmd);voidSSD1306_WriteData(uint8_t*data,uint16_tlen);voidSSD1306_Fill(uint8_tcolor);voidSSD1306_Update(void);// CS控制#defineSSD1306_CS_LOW()HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_RESET)#defineSSD1306_CS_HIGH()HAL_GPIO_WritePin(GPIOA,GPIO_PIN_4,GPIO_PIN_SET)// DC控制#defineSSD1306_DC_LOW()HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_RESET)// 命令#defineSSD1306_DC_HIGH()HAL_GPIO_WritePin(GPIOA,GPIO_PIN_6,GPIO_PIN_SET)// 数据// RST控制#defineSSD1306_RST_LOW()HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_RESET)#defineSSD1306_RST_HIGH()HAL_GPIO_WritePin(GPIOB,GPIO_PIN_0,GPIO_PIN_SET)voidSPI1_Init(void){hspi1.Instance=SPI1;hspi1.Init.Mode=SPI_MODE_MASTER;hspi1.Init.Direction=SPI_DIRECTION_2LINES;hspi1.Init.DataSize=SPI_DATASIZE_8BIT;hspi1.Init.CLKPolarity=SPI_POLARITY_LOW;hspi1.Init.CLKPhase=SPI_PHASE_1EDGE;hspi1.Init.NSS=SPI_NSS_SOFT;hspi1.Init.BaudRatePrescaler=SPI_BAUDRATEPRESCALER_4;hspi1.Init.FirstBit=SPI_FIRSTBIT_MSB;HAL_SPI_Init(&hspi1);}voidSSD1306_WriteCommand(uint8_tcmd){SSD1306_CS_LOW();SSD1306_DC_LOW();// 命令模式HAL_SPI_Transmit(&hspi1,&cmd,1,100);SSD1306_CS_HIGH();}voidSSD1306_WriteData(uint8_t*data,uint16_tlen){SSD1306_CS_LOW();SSD1306_DC_HIGH();// 数据模式HAL_SPI_Transmit(&hspi1,data,len,100);SSD1306_CS_HIGH();}voidSSD1306_Init(void){// 复位SSD1306_RST_LOW();HAL_Delay(10);SSD1306_RST_HIGH();HAL_Delay(10);// 初始化序列SSD1306_WriteCommand(0xAE);// 关闭显示SSD1306_WriteCommand(0xD5);// 设置时钟分频SSD1306_WriteCommand(0x80);SSD1306_WriteCommand(0xA8);// 设置多路复用率SSD1306_WriteCommand(0x3F);SSD1306_WriteCommand(0xD3);// 设置显示偏移SSD1306_WriteCommand(0x00);SSD1306_WriteCommand(0x40);// 设置起始行SSD1306_WriteCommand(0x8D);// 电荷泵设置SSD1306_WriteCommand(0x14);SSD1306_WriteCommand(0x20);// 内存地址模式SSD1306_WriteCommand(0x00);// 水平寻址模式SSD1306_WriteCommand(0xA1);// 段重映射SSD1306_WriteCommand(0xC8);// COM输出扫描方向SSD1306_WriteCommand(0xDA);// COM引脚配置SSD1306_WriteCommand(0x12);SSD1306_WriteCommand(0x81);// 对比度控制SSD1306_WriteCommand(0xCF);SSD1306_WriteCommand(0xD9);// 预充电周期SSD1306_WriteCommand(0xF1);SSD1306_WriteCommand(0xDB);// VCOMH电压SSD1306_WriteCommand(0x40);SSD1306_WriteCommand(0xA4);// 全屏点亮关闭SSD1306_WriteCommand(0xA6);// 正常显示SSD1306_WriteCommand(0xAF);// 开启显示}staticuint8_tSSD1306_Buffer[SSD1306_WIDTH*SSD1306_HEIGHT/8];voidSSD1306_Fill(uint8_tcolor){memset(SSD1306_Buffer,color?0xFF:0x00,sizeof(SSD1306_Buffer));}voidSSD1306_Update(void){for(uint8_tpage=0;page<8;page++){SSD1306_WriteCommand(0xB0+page);SSD1306_WriteCommand(0x00);SSD1306_WriteCommand(0x10);SSD1306_WriteData(&SSD1306_Buffer[page*SSD1306_WIDTH],SSD1306_WIDTH);}}第二步:测试验证
intmain(void){HAL_Init();SystemClock_Config();SPI1_Init();SSD1306_Init();// 清屏SSD1306_Fill(0);SSD1306_Update();// 全白SSD1306_Fill(1);SSD1306_Update();while(1);}第三步:迭代修正
如果屏幕不亮,添加调试:
voidSSD1306_Debug(void){printf("SSD1306 Debug:\r\n");printf("SPI CR1: 0x%04X\r\n",SPI1->CR1);printf("GPIOA CRL: 0x%08X\r\n",GPIOA->CRL);printf("GPIOB CRL: 0x%08X\r\n",GPIOB->CRL);}三、TFT屏幕驱动(ST7735)
3.1 ST7735驱动
Prompt:
生成STM32F103 ST7735 TFT驱动: - SPI1:PA5(SCK)、PA7(MOSI) - CS:PA4 - DC:PA6 - RST:PB0 - 屏幕:1.8寸,128x160 - 使用HAL库AI生成核心代码:
#defineST7735_WIDTH128#defineST7735_HEIGHT160voidST7735_WriteCommand(uint8_tcmd){ST7735_CS_LOW();ST7735_DC_LOW();HAL_SPI_Transmit(&hspi1,&cmd,1,100);ST7735_CS_HIGH();}voidST7735_WriteData(uint8_tdata){ST7735_CS_LOW();ST7735_DC_HIGH();HAL_SPI_Transmit(&hspi1,&data,1,100);ST7735_CS_HIGH();}voidST7735_SetWindow(uint8_tx0,uint8_ty0,uint8_tx1,uint8_ty1){ST7735_WriteCommand(0x2A);// 列地址设置ST7735_WriteData(0x00);ST7735_WriteData(x0);ST7735_WriteData(0x00);ST7735_WriteData(x1);ST7735_WriteCommand(0x2B);// 行地址设置ST7735_WriteData(0x00);ST7735_WriteData(y0);ST7735_WriteData(0x00);ST7735_WriteData(y1);ST7735_WriteCommand(0x2C);// 写内存}voidST7735_DrawPixel(uint8_tx,uint8_ty,uint16_tcolor){ST7735_SetWindow(x,y,x,y);uint8_tdata[2];data[0]=color>>8;data[1]=color&0xFF;ST7735_CS_LOW();ST7735_DC_HIGH();HAL_SPI_Transmit(&hspi1,data,2,100);ST7735_CS_HIGH();}voidST7735_FillColor(uint16_tcolor){ST7735_SetWindow(0,0,ST7735_WIDTH-1,ST7735_HEIGHT-1);uint8_tdata[2];data[0]=color>>8;data[1]=color&0xFF;ST7735_CS_LOW();ST7735_DC_HIGH();for(uint16_ti=0;i<ST7735_WIDTH*ST7735_HEIGHT;i++){HAL_SPI_Transmit(&hspi1,data,2,100);}ST7735_CS_HIGH();}四、绘图功能实现
4.1 基础绘图函数
画线:
voidSSD1306_DrawLine(uint8_tx0,uint8_ty0,uint8_tx1,uint8_ty1){int16_tdx=abs(x1-x0);int16_tdy=abs(y1-y0);int16_tsx=(x0<x1)?1:-1;int16_tsy=(y0<y1)?1:-1;int16_terr=dx-dy;while(1){SSD1306_DrawPixel(x0,y0,1);if(x0==x1&&y0==y1)break;int16_te2=2*err;if(e2>-dy){err-=dy;x0+=sx;}if(e2<dx){err+=dx;y0+=sy;}}}画矩形:
voidSSD1306_DrawRect(uint8_tx,uint8_ty,uint8_tw,uint8_th){SSD1306_DrawLine(x,y,x+w-1,y);SSD1306_DrawLine(x,y+h-1,x+w-1,y+h-1);SSD1306_DrawLine(x,y,x,y+h-1);SSD1306_DrawLine(x+w-1,y,x+w-1,y+h-1);}画圆:
voidSSD1306_DrawCircle(uint8_tx0,uint8_ty0,uint8_tr){int16_tf=1-r;int16_tddF_x=1;int16_tddF_y=-2*r;int16_tx=0;int16_ty=r;SSD1306_DrawPixel(x0,y0+r,1);SSD1306_DrawPixel(x0,y0-r,1);SSD1306_DrawPixel(x0+r,y0,1);SSD1306_DrawPixel(x0-r,y0,1);while(x<y){if(f>=0){y--;ddF_y+=2;f+=ddF_y;}x++;ddF_x+=2;f+=ddF_x;SSD1306_DrawPixel(x0+x,y0+y,1);SSD1306_DrawPixel(x0-x,y0+y,1);SSD1306_DrawPixel(x0+x,y0-y,1);SSD1306_DrawPixel(x0-x,y0-y,1);SSD1306_DrawPixel(x0+y,y0+x,1);SSD1306_DrawPixel(x0-y,y0+x,1);SSD1306_DrawPixel(x0+y,y0-x,1);SSD1306_DrawPixel(x0-y,y0-x,1);}}4.2 显示文字
ASCII字符显示:
// 5x7字体constuint8_tfont5x7[]={0x00,0x00,0x00,0x00,0x00,// 空格0x00,0x00,0x5F,0x00,0x00,// !// ... 字体数据};voidSSD1306_DrawChar(uint8_tx,uint8_ty,charc){for(uint8_ti=0;i<5;i++){uint8_tline=font5x7[(c-32)*5+i];for(uint8_tj=0;j<7;j++){if(line&(1<<j)){SSD1306_DrawPixel(x+i,y+j,1);}}}}voidSSD1306_DrawString(uint8_tx,uint8_ty,char*str){while(*str){SSD1306_DrawChar(x,y,*str);x+=6;str++;}}五、常见问题与解决
5.1 屏幕不亮
原因:
1. SPI配置错误 2. 初始化序列错误 3. 引脚配置错误 4. 复位时序错误解决:
// 验证SPI配置voidSPI_Debug(void){printf("SPI Configuration:\r\n");printf("Mode: %d\r\n",hspi1.Init.Mode);printf("BaudRate: %d\r\n",hspi1.Init.BaudRatePrescaler);printf("CLKPolarity: %d\r\n",hspi1.Init.CLKPolarity);printf("CLKPhase: %d\r\n",hspi1.Init.CLKPhase);}5.2 显示异常
原因:
1. 内存地址模式错误 2. 扫描方向错误 3. 颜色格式错误解决:
// 调整内存地址模式SSD1306_WriteCommand(0x20);// 内存地址模式SSD1306_WriteCommand(0x00);// 水平寻址模式// 调整扫描方向SSD1306_WriteCommand(0xA1);// 段重映射SSD1306_WriteCommand(0xC8);// COM输出扫描方向六、本讲核心要点
6.1 记住这三句话
SPI屏幕驱动:正确配置SPI、理解控制命令、实现绘图功能
快速试错:AI生成初始驱动→测试验证→迭代修正
常见问题:SPI配置、初始化序列、引脚配置、复位时序
6.2 实践建议
对于新手:
- 学习SPI配置
- 理解屏幕控制命令
- 实践绘图功能
对于有经验工程师:
- 建立屏幕驱动模板库
- 优化绘图性能
- 实现高级功能
6.3 下讲预告
第32讲将深入讲解:实战:I2C传感器极简驱动快速验证
I2C传感器驱动如何快速验证?下一讲将以具体传感器为例详细讲解。