找回密码
 立即注册
查看: 262|回复: 12

为什么SPI OLED 右边有两列乱码啊?

[复制链接]
已绑定手机

35

主题

91

回帖

249

积分

中级会员

积分
249
发表于 2026-10-3 17:01:10 | 显示全部楼层 |阅读模式
我已崩溃
#include <STC8051U.H>
#include "SPI.h"
#include "OLED_WORD.h"
extern unsigned char xdata OLED_GRAM[1024];
unsigned char code oled_init_table[19]={
0xaf,0xa8,0x3f,0xd3,0x00,0x40,0xa1,0xc8,0xda,
0x12,0x81,0xff,0xa4,0xa6,0xd5,0xf0,0x8d,0x14,};
void OLED_Write(bit dat1,unsigned char dat2){
        DC=dat1;
        SPI_Send(1,dat2);
}
void OLED_Reflesh(){
        unsigned char i,j;
        for(i=0;i<8;i++){
                OLED_Write(0,0xb0+i);
                OLED_Write(0,0x10);
                OLED_Write(0,0x02);//这里不是加过2了吗?
                for(j=0;j<128;j++){
                        OLED_Write(1,OLED_GRAM[(i<<7)|j]);
                }
        }
}
void OLED_Init(){
        unsigned char i,j;
        SPI_Init();
        for(i=0;i<((sizeof(oled_init_table))/(sizeof(oled_init_table[0])));i++){
                OLED_Write(0,oled_init_table[i]);
        }
        for(i=0;i<8;i++){
                for(j=0;j<128;j++){
                        OLED_GRAM[(i<<7)|j]=0x00;
                }
        }
        OLED_Reflesh();
}


回复

使用道具 举报 送花

已绑定手机

35

主题

91

回帖

249

积分

中级会员

积分
249
 楼主| 发表于 2026-10-3 17:01:47 | 显示全部楼层
之前IIC都没问题的,
回复

使用道具 举报 送花

已绑定手机

123

主题

5133

回帖

1万

积分

超级版主

无情的代码机器

积分
11463
发表于 2026-10-3 20:55:45 | 显示全部楼层

哪个型号?论坛应该都能找到例程吧,或者找屏幕卖家要下例程,对比下差异。
截图202610032054549651.jpg

点评

拼夕夕卖家不负责任的  发表于 2026-10-4 10:38
三天不学习,赶不上刘少奇~
回复

使用道具 举报 送花

已绑定手机

35

主题

91

回帖

249

积分

中级会员

积分
249
 楼主| 发表于 2026-10-4 10:37:39 | 显示全部楼层
erci*** 发表于 2026-10-3 20:55
哪个型号?论坛应该都能找到例程吧,或者找屏幕卖家要下例程,对比下差异。

...

SH1106,除此之外还有一个问题,ShowASC函数在IIC上好好的,在SPI上,下半部分第一列直接跳过,比如'0',下半的'u'形直接全部往左移一列,第一列消失。在IIC上明明好好的呀

点评

IIC的屏幕是什么型号的?如果IIC的显示正常,估计用的是0.96吋的屏幕,型号是SSD1306或者SSD1315。 如果是这样的话,右边两列乱码就说得通了。 因为SH1106的屏幕多数是1.3吋的,和SSD1306不同,x地址需要+2。所以你  详情 回复 发表于 2026-10-4 10:51
回复

使用道具 举报 送花

49

主题

611

回帖

5448

积分

荣誉版主

积分
5448
发表于 2026-10-4 10:51:27 | 显示全部楼层
光头*** 发表于 2026-10-4 10:37
SH1106,除此之外还有一个问题,ShowASC函数在IIC上好好的,在SPI上,下半部分第一列直接跳过,比如'0', ...

IIC的屏幕是什么型号的?如果IIC的显示正常,估计用的是0.96吋的屏幕,型号是SSD1306或者SSD1315。
如果是这样的话,右边两列乱码就说得通了。
因为SH1106的屏幕多数是1.3吋的,和SSD1306不同,x地址需要+2。所以你把0.96吋屏幕的程序直接用在1.3吋屏幕上,右边两列地址刷不到,所以显示的是上电初始化时的乱码,而左边有两列在屏幕外。
这个跟IIC或者SPI没关系,是OLED的主控芯片原因。

关于这个问题,论坛的OLED版块有专门的帖子解释

[视频]1.3吋OLED屏画面偏移和花边问题的成因和解决办法
https://www.stcaimcu.com/thread-8637-1-1.html
(出处: 国芯人工智能技术交流网站)




能体会到发现一个不理解的现象然后找原因然后要么解决掉问题要么被问题解决掉的那种快乐是我的幸运
回复

使用道具 举报 送花

49

主题

611

回帖

5448

积分

荣誉版主

积分
5448
发表于 2026-10-4 11:03:24 | 显示全部楼层
另外,刷新屏幕是OLED_Refresh,“flash”是“肉”,“fresh”才是刷新。

在你的刷新屏幕的函数里,在定位起始地址的地方,给列地址加了2,但是不知道你的显示字符的函数是什么样的,显示字符的函数里如果也用到定位指令,看下有没有也加了2。
最好是把定位的三行指令单独封装成一个OLED_Set_Pos函数,然后在用到的地方直接调用,就不用每次都修改了

点评

啊?我函数名没写错吧?等我找下原函数  发表于 2026-10-4 11:20
能体会到发现一个不理解的现象然后找原因然后要么解决掉问题要么被问题解决掉的那种快乐是我的幸运
回复

使用道具 举报 送花

已绑定手机

35

主题

91

回帖

249

积分

中级会员

积分
249
 楼主| 发表于 2026-10-4 11:18:18 | 显示全部楼层
大*** 发表于 2026-10-4 10:51
IIC的屏幕是什么型号的?如果IIC的显示正常,估计用的是0.96吋的屏幕,型号是SSD1306或者SSD1315。
如果是 ...

IIC是淘宝的SH1106,此时已加二,一切顺利;昨天中午兼容时出了问题;下午去掉加二,反而正常;傍晚又出了问题。我整天都在研究您的OLED相关视频。
回复

使用道具 举报 送花

已绑定手机

35

主题

91

回帖

249

积分

中级会员

积分
249
 楼主| 发表于 2026-10-4 11:23:20 | 显示全部楼层
大*** 发表于 2026-10-4 10:51
IIC的屏幕是什么型号的?如果IIC的显示正常,估计用的是0.96吋的屏幕,型号是SSD1306或者SSD1315。
如果是 ...

void OLED_ShowASC(unsigned char x,unsigned char y,unsigned char word,bit color){
        unsigned char i,j;
        word-=' ';
        if(color){
                for(i=0;i<8;i++){
                        for(j=0;j<8;j++){
                                OLED_Point(x+i,y+j,ASC16x8[(word<<4)|i]&(0x01<<j));
                        }
                }
                for(i=0;i<8;i++){
                        for(j=0;j<8;j++){
                                OLED_Point(x+i,y+j+8,ASC16x8[(word<<4)|i|0x08]&(0x01<<j));
                        }
                }
        }else{
                for(i=0;i<8;i++){
                        for(j=0;j<8;j++){
                                OLED_Point(x+i,y+j,!(ASC16x8[(word<<4)|i]&(0x01<<j)));
                        }
                }
                for(i=0;i<8;i++){
                        for(j=0;j<8;j++){
                                OLED_Point(x+i,y+j+8,!(ASC16x8[(word<<4)|i|0x08]&(0x01<<j)));
                        }
                }
        }
}
依此逻辑的Chinese16x16没有问题;
void OLED_ShowASC(unsigned char x,unsigned char y,unsigned char word,bit color){
        unsigned char i,j;
        word-=' ';
        if(color){
                for(i=0;i<8;i++){
                        for(j=0;j<8;j++){
                                OLED_Point(x+i,y+j,ASC16x8[(word<<4)|i]&(0x01<<j));
                        }
                }
                for(i=0;i<8;i++){
                        for(j=0;j<8;j++){
                                OLED_Point(x+i+1,y+j+8,ASC16x8[(word<<4)|i|0x08]&(0x01<<j));//
                        }
                }
        }else{
                for(i=0;i<8;i++){
                        for(j=0;j<8;j++){
                                OLED_Point(x+i,y+j,!(ASC16x8[(word<<4)|i]&(0x01<<j)));
                        }
                }
                for(i=0;i<8;i++){
                        for(j=0;j<8;j++){
                                OLED_Point(x+i+1,y+j+8,!(ASC16x8[(word<<4)|i|0x08]&(0x01<<j)));//
                        }
                }
        }
}
反而正常;
还是8h8k64u+IIC_OLED爽
回复

使用道具 举报 送花

已绑定手机

35

主题

91

回帖

249

积分

中级会员

积分
249
 楼主| 发表于 2026-10-4 14:38:12 | 显示全部楼层
模拟SPI没问题,硬件的有问题,为啥?

//0xaf,0xa8,0x3f,0xd3,0x00,0x40,0xa1,0xc8,0xda,
//0x12,0x81,0xff,0xa4,0xa6,0xd5,0xf0,0x8d,0x14,
#include <STC8051U.H>
sbit DC=P3^6;
sbit CS1=P3^7;
bit SPI_busy;
void SPI_Isr() interrupt 9{
        SPSTAT = 0xc0;                              //清中断标志
        CS1 = 1;                                     //拉高从机的SS管脚
        SPI_busy = 0;
}
void OLED_Write(bit dc,unsigned char byte){
        DC=dc;
        while(SPI_busy);
        SPI_busy=1;
        CS1=0;                                //拉低从机SS管脚
        SPDAT=byte;
}
void main(){
        unsigned char p,c;
        EAXFR=1;WTST=0x00;CKCON=0x00;
        P3M0=0x00;P3M1=0x00;
        CS1=1;
  SPI_busy = 0;
        P_SW1 |= 0x0c;
        SPCTL = 0xd0;                               //使能SPI主机模式
        SPSTAT = 0xc0;                              //清中断标志
        IE2|=0x02;                                 //使能SPI中断
        EA = 1;
        OLED_Write(0,0xaf);
        OLED_Write(0,0xa8);
        OLED_Write(0,0x3f);
        OLED_Write(0,0xd3);
        OLED_Write(0,0x00);
        OLED_Write(0,0x40);
        OLED_Write(0,0xa1);
        OLED_Write(0,0xc8);
        OLED_Write(0,0xda);
        OLED_Write(0,0x12);
        OLED_Write(0,0x81);
        OLED_Write(0,0xff);
        OLED_Write(0,0xa4);
        OLED_Write(0,0xa6);
        OLED_Write(0,0xd5);
        OLED_Write(0,0xf0);
        OLED_Write(0,0x8d);
        OLED_Write(0,0x14);
        for(p=0;p<8;p++){
                OLED_Write(0,0xb0+p);
                OLED_Write(0,0x10);
                OLED_Write(0,0x02);
                for(c=0;c<128;c++){
                        OLED_Write(1,0xFF);
                }
        }
        while(1);
}

回复

使用道具 举报 送花

49

主题

611

回帖

5448

积分

荣誉版主

积分
5448
发表于 2026-10-4 14:49:57 | 显示全部楼层
在STC8H8K64U单片机上,用SPI的 SH1106的OLED驱动,试了下你的  OLED_ShowASC 函数,显示正常。
所以你说的花边和下半个字符错位的问题不在这个函数上,应该是其他地方的问提,不知道完整程序没法判断。

SPI出花还有个可能,就是SPI的速度问题,也有可能导致定位和内容之类的数据发送异常。


另外 OLED_ShowASC  里的移位运算 (word<<4) 有溢出隐患,因为参数 word 的类型是 unsigned char,只有8位。
如果是C51的Keil,会自动提升成16位再进行移位,碰巧没问题;
但是如果是其他编译器,这个八位数右移4位之后,则有可能溢出。
比如字符“0”,在字库里的序号是 16,二进制是 00010000,右移4位置后 就变成了 1 00000000,截取八位之后就成 0 了。

所以移位之前最好先强制转换一下 word 的数据类型  ( (unsigned int)word<<4 )

同理,OLED_Reflesh函数里的(i<<7)也有同样的隐患,因为 i 的类型也是 undigned char。

还有就是 加法运算用与运算符 也有可能出问题,因为与运算只是按位运算,不涉及进位。
如果是 1|2 ,结果是 00000001 | 00000010 = 00000011 = 3,看似是加法运算,
但是比如 1 和 7
1:00000001
7:00000111
1+7 = 00001000 = 8
1|7 = 00000111 = 7

所以显示16x8字符只是碰巧没问题,如果是其他尺寸的字模,结果就不好说了。

能体会到发现一个不理解的现象然后找原因然后要么解决掉问题要么被问题解决掉的那种快乐是我的幸运
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-11-7 11:51 , Processed in 0.077966 second(s), 86 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表