大明狐 发表于 2025-6-19 11:58:36

看到楼上的I/O口配置部分,突然想起一个问题,补充在这里就不另开帖子了。
之前论坛上有些朋友提过,使用论坛上的老刘示波器等等例程的时候,
屏幕会花屏或者内容错乱。
大家一直在程序方面寻找原因。

前段时间发现,可能是市面上的OLED屏幕模块质量问题,
如果IO口启用了内部上拉电阻(PxPU),有些屏幕模块可以正常显示,
而有些屏幕模块就会显示混乱,关掉上拉电阻就又能正常显示。
不知道具体原因,但并不是程序本身的问题。




神农鼎 发表于 2025-6-19 13:21:31

大明狐 发表于 2025-6-19 11:58
看到楼上的IO口配置部分,突然想起一个问题,补充在这里就不另开帖子了。
之前论坛上有些朋友提过,使用论 ...
SPI-OLED12864, 抗干扰 强:
#SS, SCLK, MOSI, 都设置成强推挽,抗干扰肯定强 !!!

I2C-OLED12864, 抗干扰 弱:
SCL, SDA, 都设置成【准双向口/弱上拉 + 上拉电阻】,抗干扰一般,容易【高 被拉 低】
===准双向口/弱上拉 的输出 低的能力 和强推挽输出低的能力一样强,外界干扰打不过这个低

SCL, SDA, 都设置成【开漏 + 上拉电阻】,抗干扰一般,容易【高 被拉 低】
===开漏 输出 低的能力 和强推挽输出低的能力一样强,外界干扰打不过这个低

所以 I2C 的问题是 高 容易被干扰到 低,解决方案:
===1,卓教授,外加 500欧到 1K的强上拉,这样不容易被干扰到低
            卓老师后来重新布线,干扰小了,I2C 加 3K ~ 10K 上拉电阻即可

===2,直接改用 SPI 接口,
            #SS, SCLK, MOSI, 都设置成强推挽,抗干扰肯定强 !!!














神农鼎 发表于 2025-6-19 20:42:40



https://www.bilibili.com/video/BV1P67nztEYj?t=2.2



https://www.bilibili.com/video/BV1XdN4ztEvp?t=107.4



https://www.bilibili.com/video/BV1tXNCzeEUx?t=5.4


https://www.bilibili.com/video/BV169K8zJE1t?t=273.4

laohu_zhou 发表于 7 天前

非常实用的内容。感谢分享!

大明狐 发表于 7 天前

试了一下SSD1306芯片的OLED12864屏幕专有的显示方式{:huaixiao:}


把43张 76×64像素的图片取模成一个大数组 DANCER;

屏幕的寻址模式设置成 【水平地址模式】

用OLED的设置显示范围的指令 0x21和 0x22 把屏幕控制范围缩小到图片的大小
void DMA_OLED_Set_Area( u8 x, u8 y, u8 width, u8 height )
{
    u8 CMD;
   
    u8 page = ( height % 8 ) ? ( height/8+1 ) : ( height/8 );
   
    if( x<0 || (x+width-1)>127 ) return;    //坐标范围不可以超出屏幕范围
    if( y<0 || (y+ page-1)>7 ) return;
   
    CMD= 0x21;                //设置列范围
    CMD= x;                     //设置起始列
    CMD= x+width-1;          //设置结束列
   
    CMD= 0x22;                //设置行范围
    CMD= y;                     //设置起始行
    CMD= y+page-1;         //设置结束行

    DMA_SendCommand( CMD, 6 );
}

然后直接发送图片里的所有数据

    DMA_OLED_Set_Area ( 26, 0, 76, 64 );      // 设置显示区域
            
    DMA_SendData ( DANCER, 76*8*43 );      // 发送所有数据
            
    DMA_OLED_Set_Area( 0, 0, 128, 64 );      // 恢复全屏区域

显示完一组内容之后,就可以重新设置其他显示区域

显示效果:
814



===============================================

还可以直接创建一个显示图片的函数

void DMA_OLED_ShowImage( u8 x, u8 y, u8 *pic, u8 width, u8 height )
{
      u16 bytes = ( height % 8 ) ? ( (height/8+1)*width ) : ( height/8*width );      //计算图片总字节数
      DMA_OLED_Set_Area( x, y, width, height );      //设置将控制区域为图片大小
      DMA_SendData ( pic, bytes );                           //发送图片所有数据
      DMA_OLED_Set_Area( 0, 0, 128, 64 );               //恢复控制区域为全屏
}


不过这两个指令并不是通用指令
SSD1036、SSD1315、SSD1309等等支持,
SH1306等等不支持,还是要老老实实一行一行发送

定位函数

void DMA_OLED_Set_Pos( u8 x, u8 y )
{
      u8 CMD;
      x += 0;
      CMD = ( 0xB0 + y );                                        // 设置起始列地址
      CMD = ( x & 0x0F );                                        // 设置起始行地址低八位
      CMD = ( 0x10 + ( x >> 4 ) );      // 设置起始行地址高八位
      DMA_SendCommand( CMD, 3 );
}



两种清屏函数

void DMA_OLED_Clear() // 通用
{
      u8 DAT={0};
      u8 i;
      for(i=0;i<8;i++)
      {
                DMA_OLED_Set_Pos( 0, i );
                DMA_SendData( DAT, 128 );
      }
}

void DMA_OLED_Clear() // 适合SSD1306等,不适合SH1106
{
      u8 DAT={0};
      DMA_OLED_Set_Pos( 0, 0 );
      DMA_SendData( DAT, 1024 );
}



通用的显示图片函数

void DMA_OLED_ShowImage( u8 x, u8 y, u8 *pic, u8 width, u8 height )
{
      u8 i;
      u8 pages = ( height % 8 ) ? ( height/8+1 ) : ( height/8 );
      
      for( i=0; i<pages; i++ )
      {
                        DMA_OLED_Set_Pos( x, y+i );
                        DMA_SendData ( pic + width*i, width );
      }
}


815





Mr.Yan 发表于 6 天前

大明狐 发表于 2025-6-17 15:33
I2C的发送和接收数据共用一条线(SDA),SPI是分成发送(MOSI)和接收(MISO)两条线。
因为控制OLED只需 ...

您解释的准确,精炼,易懂,非常感谢,又学到新知识了。

Mr.Yan 发表于 6 天前

神农鼎 发表于 2025-6-19 09:56
进行了 MOSI / MISO 切换



加油,我对 www.STCAI.com 充满期待,这两年确实发展的很快,
STCAI 是目前我认为单片机圈内生态做的最好的,
有问必答,真的是贴心。

etlqmyry 发表于 5 天前

学习了,真的好

410445549 发表于 昨天 17:35

为什么不转向vscode开发?

神农鼎 发表于 昨天 21:54

410445549 发表于 2025-6-28 17:35
为什么不转向vscode开发?

那只是一个 编辑器,我们论坛有这个版块,很多坛友在用
页: 1 [2]
查看完整版本: AiCube自动生成【SPI,SPI-DMA,I2C,I2C-DMA】代码,驱动OLED-12864, @Ai8051U