何志扬 发表于 2024-12-25 21:04:20

求助帖—如何使用擎天柱AI8051最小系统板驱动iic0.96OLED屏幕

本人已经研究2天还是不能驱动屏幕,最多只能驱动屏幕显示雪花屏,
请各位大佬指教,该如何学习i2c屏幕,看过一下开源项目都不能成功复现
,希望能看下能成功驱动屏幕的源代码

何志扬 发表于 2024-12-25 21:06:18

软键i2c和硬件i2c都尝试过,我的代码是东拼西凑来的,就不展示我的愚见了

DebugLab 发表于 2024-12-25 23:52:14

我是这样学习的
根据OLED屏的COG IC (Chip On Glass Integrated Circuit)找到原厂数据手册(Datasheet),翻译一遍,尤其是指令集部分,看懂这个芯片有哪些功能,如何工作的,寄存器每个bit都要弄懂
还有OLED需要的工作条件,电压,时钟,扫描顺序方向,对比度,反白,滚动等等
单片机也是,IO如何配置,硬件I2C如何使用,时钟速度,上升沿下降沿,指令数据是如何传输的,哪个字节哪个位代表什么,每个bit都要弄懂
然后用单片机通过I2C把OLED的寄存器都配置一遍,接个逻辑分析仪看I2C信号,有没有按照预期工作,都正确配置了就能正常工作了,随便显示什么
然后是如何让OLED按照你的想法点亮或熄灭某个像素,显示一个点,一条线,一个字符,行列排列方式,数据发送顺序,字模和图片的显示
到处抄代码东拼西凑是学不会的

DebugLab 发表于 2024-12-26 00:01:40



#include <STC8G.H>
#include "define.h"
#include <intrins.h>
#define         RXD                P30
#define         TXD                P31
#define         SCL                P32
#define         SDA                P33

bit I2C_Busy;

unsigned char code BMP[]=
{
        #include <0.h>
};

void Delay_10ms(void)
{
        unsigned char i,j;
        _nop_();
        _nop_();
        i=144;
        j=157;
        do
        {
                while(--j);
        }
        while(--i);
        WDT_CONTR=CLR_WDT;
}

void Delay_x10ms(unsigned char x)
{
        while(--x)
                Delay_10ms();
}

void I2C_Start(void)
{
        I2C_Busy=1;
        I2CMSCR=0x81;
        while(I2C_Busy);
}

void I2C_SendData(unsigned char dat)
{
        I2CTXD=dat;
        I2C_Busy=1;
        I2CMSCR=0x82;
        while(I2C_Busy);
}

void I2C_RecvACK(void)
{
        I2C_Busy=1;
        I2CMSCR=0x83;
        while(I2C_Busy);
}

//unsigned char I2C_RecvData(void)
//{
//        I2C_Busy=1;
//        I2CMSCR=0x84;
//        while(I2C_Busy);
//        return I2CRXD;
//}

//void I2C_SendACK(void)
//{
//        I2CMSST=0x00;
//        I2C_Busy=1;
//        I2CMSCR=0x85;
//        while(I2C_Busy);
//}

//void I2C_SendNAK(void)
//{
//        I2CMSST=0x01;
//        I2C_Busy=1;
//        I2CMSCR=0x85;
//        while(I2C_Busy);
//}

void I2C_Stop(void)
{
        I2C_Busy=1;
        I2CMSCR=0x86;
        while(I2C_Busy);
}

void SSD1316_Write_CMD(unsigned char cmd)
{
        I2C_Start();
        I2C_SendData(0x78);
        I2C_RecvACK();
        I2C_SendData(0x00);
        I2C_RecvACK();
        I2C_SendData(cmd);
        I2C_RecvACK();
        I2C_Stop();
}

void SSD1316_Write_DATA_A(void)
{
        I2C_Start();
        I2C_SendData(0x78);
        I2C_RecvACK();
        I2C_SendData(0x40);
        I2C_RecvACK();
}

void SSD1316_Write_DATA_B(unsigned char dat)
{
        I2C_SendData(dat);
        I2C_RecvACK();
}

void SSD1316_Write_DATA_C(void)
{
        I2C_Stop();
}

void SSD1316_Clear(void)
{
        unsigned char i,n;                  
        for(i=0;i<4;i++)
        {
                SSD1316_Write_CMD(0xb0+i);        //设置页地址(0~3)
                SSD1316_Write_CMD(0x00);        //设置显示位置—列低地址
                SSD1316_Write_CMD(0x10);        //设置显示位置—列高地址
                SSD1316_Write_DATA_A();               
                for(n=0;n<128;n++)
                {
                        SSD1316_Write_DATA_B(0x00);
                }
                SSD1316_Write_DATA_C();
        }
}

void SSD1316_Display_128x32(void)
{
        unsigned int i;
        SSD1316_Write_CMD(0x20);        //Set Memory Addressing Mode(设置内存寻址模式)
        SSD1316_Write_CMD(0x01);        //0x01(垂直寻址模式)
        SSD1316_Write_CMD(0x21);        //Set Column Address(设置列地址)
        SSD1316_Write_CMD(0);                //(列开始地址)
        SSD1316_Write_CMD(127);                //(列结束地址)
        SSD1316_Write_CMD(0x22);        //Set Page Address(设置页地址)
        SSD1316_Write_CMD(0x00);        //0
        SSD1316_Write_CMD(0x03);        //3
        SSD1316_Write_DATA_A();
        for(i=0;i<512;i++)
        {
                SSD1316_Write_DATA_B(BMP);
        }
        SSD1316_Write_DATA_C();
        SSD1316_Write_CMD(0x20);        //Set Memory Addressing Mode(设置内存寻址模式)
        SSD1316_Write_CMD(0x02);        //0x02(页寻址模式)
}

void SSD1316_Init(void)
{
        SSD1316_Write_CMD(0xAE);        //Set Display OFF(设置显示关)
        SSD1316_Write_CMD(0xA1);        //Set Segment Remap(设置列重映射)
        SSD1316_Write_CMD(0xA8);        //Set Multiplex Ratio(设置行通道数)
        SSD1316_Write_CMD(0x1F);        //31
//        SSD1316_Write_CMD(0xC8);        //Set COM Output Scan Direction(设置行重映射)
        SSD1316_Write_CMD(0xD3);        //Set Display Offset(设置垂直偏移量)
        SSD1316_Write_CMD(0x00);        //0
        SSD1316_Write_CMD(0xD5);        //Set Display Clock Divide Ratio/Oscillator Frequency(设置显示时钟分频器、振荡器频率)
        SSD1316_Write_CMD(0xF0);        //0xF0
        SSD1316_Write_CMD(0x8D);        //Charge Pump Setting(设置电荷泵)
        SSD1316_Write_CMD(0x14);        //0x14
        SSD1316_Write_CMD(0xAF);        //Set Display ON(设置显示开)
        SSD1316_Clear();
//        SSD1316_Write_CMD(0x81);        //Set Contrast Control(设置对比度)
//        SSD1316_Write_CMD(0x7F);        //127
//        SSD1316_Write_CMD(0xA7);        //Set Normal/Inverse Display(设置反相显示)
}

void Init(void)
{
        P_SW2|=EAXFR;
        P3M0=0x00;
        P3M1=0x00;
        P5M0=0x00;
        P5M1=0x00;
        P3PU=0x0c;
        I2CCFG=0xC1;        //921.6K@11.0592M
        I2CMSCR=EMSI;
        I2CMSST=0x00;
        EA=1;
        Delay_x10ms(10);
        SSD1316_Init();
}

void main(void)
{
        Init();
        SSD1316_Display_128x32();
        while(1)
        {
                SSD1316_Write_CMD(0xA6);
                Delay_x10ms(50);
                SSD1316_Write_CMD(0xA7);
                Delay_x10ms(50);
        }
}

void I2C_Isr(void) interrupt 24
{
        _push_(P_SW2);
        P_SW2|=EAXFR;
        if(I2CMSST&MSIF)
        {
                I2CMSST&=~MSIF;
                I2C_Busy=0;
        }
        _pop_(P_SW2);
}

DebugLab 发表于 2024-12-26 00:05:27




attach://76714.mp4
#include <STC8.H>
#include <intrins.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#define                A0                        P30
#define                CS_O                P31
#define                CLK                        P32
#define                MISO                P33
#define                MOSI                P54
#define                CS_F                P55
#define                FOSC                11059200UL
#define                Command                0
#define                Data                1
#define                Enable                0
#define                Disable                1

unsigned char FPS;
unsigned int Temp,Frame,Video;
unsigned char xdata Buffer;
unsigned char code String=
{
      /*----------------------------数字----------------------------*/
      0x7E,0x81,0x81,0x81,0x7E,
      0x00,0x82,0xFF,0x80,0x00,
      0xC2,0xA1,0x91,0x89,0x86,
      0x42,0x81,0x89,0x89,0x76,
      0x18,0x14,0x12,0xFF,0x10,
      0x4F,0x89,0x89,0x89,0x71,
      0x7C,0x8A,0x89,0x89,0x70,
      0x01,0xC1,0x31,0x0D,0x03,
      0x76,0x89,0x89,0x89,0x76,
      0x0E,0x91,0x91,0x51,0x3E,
};

/*----------------------------延时10us@STC-Y6@11.0592MHz----------------------------*/
//void Delay_10us(void)
//{
//      unsigned char i;
//      i=35;
//      while(--i);
//}

/*----------------------------延时x10us----------------------------*/
//void Delay_x10us(unsigned char x)
//{
//      while(x--)
//                Delay_10us();
//}

/*----------------------------延时10ms@STC-Y6@11.0592MHz----------------------------*/
void Delay_10ms(void)
{
      unsigned char i,j;
      _nop_();
      _nop_();
      i=144;
      j=157;
      do
      {
                while(--j);
      }while(--i);
}

/*----------------------------延时x10ms----------------------------*/
//void Delay_x10ms(unsigned char x)
//{
//      while(x--)
//                Delay_10ms();
//}

void SPI_Write(unsigned char temp)
{
      unsigned char i;
      for(i=0;i<8;i++)
      {
                CLK=0;
                temp<<=1;
                MOSI=CY;
                CLK=1;
      }
}

unsigned char SPI_Read(void)
{
      unsigned char i,temp;
      for(i=0;i<8;i++)
      {
                temp<<=1;
                CLK=0;
                CLK=1;
                if(MISO)
                        temp|=0x01;
      }
      return temp;
}

void SH1106_Init(void)
{
      A0=Command;
      SPI_Write(0xae);      //关闭显示
      SPI_Write(0xa8);      //设置驱动路数为32路
      SPI_Write(0x1f);      //设置驱动路数为32路
      SPI_Write(0xc8);      //设置Common输出扫描方向
      SPI_Write(0xa1);      //设置镜像
//      SPI_Write(0xa7);      //设置反白
      SPI_Write(0xaf);      //打开显示
}

void SH1106_Set_Posi(unsigned char page,unsigned char column)
{
      A0=Command;
      SPI_Write(0xb0+(page&0x0f));
      SPI_Write(0x00+(column&0x0f));
      SPI_Write(0x12+((column&0xf0)>>4));
}

void SH1106_Clear_Screen(void)
{
      unsigned char i,j;
      for(i=0;i<4;i++)
      {
                A0=Command;
                SPI_Write(0xb0+i);
                SPI_Write(0x00);
                SPI_Write(0x12);
                A0=Data;
                for(j=0;j<64;j++)
                {
                        SPI_Write(0x00);
                }
      }
}

void Display_String(unsigned char page,unsigned char column,unsigned char temp)
{
      unsigned char i;
      SH1106_Set_Posi(page,column);
      A0=Data;
      for(i=0;i<5;i++)
      {
                SPI_Write(String);
      }
}

void Display_Buffer(void)
{
      unsigned char i,j;
      CS_O=Enable;
      for(i=0;i<4;i++)
      {
                SH1106_Set_Posi(i,0);
                A0=Data;
                for(j=0;j<64;j++)
                {
                        SPI_Write(Buffer);
                }
      }
      CS_O=Disable;
}

void Flash_Read(unsigned int temp)
{
      unsigned char i,j;
      CS_F=Enable;
      SPI_Write(0x03);
      SPI_Write(temp/256);
      SPI_Write(temp%256);
      SPI_Write(0x00);
      for(i=0;i<4;i++)
      {
                CS_F=Enable;
                for(j=0;j<64;j++)
                {
                        Buffer=SPI_Read();
                }
      }
      CS_F=Disable;
}

void Config_Read(void)
{
      CS_F=Enable;
      SPI_Write(0x03);
      SPI_Write(0);
      SPI_Write(0);
      SPI_Write(0x00);
      FPS=SPI_Read();
      Video=SPI_Read();
      Video<<=8;
      Video|=SPI_Read();
      CS_F=Disable;
}

void Init_OLED(void)
{
      CS_O=Enable;
      SH1106_Init();
      SH1106_Set_Posi(0,0);
      SH1106_Clear_Screen();
      CS_O=Disable;
}

void Init(void)
{
      P3M0=0x04;
      P3M1=0x08;
      P5M0=0x30;
      P5M1=0x00;
      P3PU=0x03;
      P5PU=0x00;
      Config_Read();
      Temp=0x10000-FOSC/12/FPS;
      TH0=Temp>>8;      //设置定时初始值
      TL0=Temp;                //设置定时初始值
      TF0=0;                        //清除TF0标志
      ET0=1;                        //打开定时器0中断
      EA=1;                        //打开总中断
}

void main(void)
{
      Init();
      if(P30)
      {
                Init_OLED();
                TR0=1;                //打开定时器0
                while(1);
      }
      else
      {
                while(!P30);
                Delay_10ms();
                Init_OLED();
                Delay_10ms();
                CS_O=Enable;
                Display_String(0,0,FPS/100);
                Display_String(0,6,FPS%100/10);
                Display_String(0,12,FPS%10);
                Display_String(1,0,Video/10000);
                Display_String(1,6,Video%10000/1000);
                Display_String(1,12,Video%1000/100);
                Display_String(1,18,Video%100/10);
                Display_String(1,24,Video%10);
                CS_O=Disable;
                P3M0=0x00;
                P3M1=0x0C;
                P5M0=0x00;
                P5M1=0x30;
                P3PU=0x03;
                P5PU=0x00;
                while(1);
      }
}

void Timer0(void) interrupt 1
{
      unsigned char i;
      Flash_Read(Frame);
      if(Frame==0)
      {
                for(i=0;i<3;i++)
                {
                        Buffer=0x00;
                }
      }
      Display_Buffer();
      Frame++;
      if(Frame==Video)
                Frame=0;
}

DebugLab 发表于 2024-12-26 00:14:05

你的应该是SSD1306的,自己研究吧,显示雪花屏已经成功一半了

何志扬 发表于 2024-12-26 08:46:54

DebugLab 发表于 2024-12-25 23:52
我是这样学习的
根据OLED屏的COG IC (Chip On Glass Integrated Circuit)找到原厂数据手册(Datasheet), ...

好的谢谢佬

何志扬 发表于 2024-12-26 08:47:12

wnagming 发表于 2024-12-26 07:11
贡献我自己翻译的1306文件

谢谢佬

大明狐 发表于 2024-12-26 09:19:42

何志扬 发表于 2024-12-25 21:06
软键i2c和硬件i2c都尝试过,我的代码是东拼西凑来的,就不展示我的愚见了

能显示雪花点,说明驱动部分没有问题,正常驱动屏幕了。问题必然就是出在显示函数的使用上。正确顺序是在初始化屏幕之后,先调用清屏函数,熄灭屏幕上所有的点,然后再用显示字符或者图片的函数。

wlhet 发表于 2024-12-26 23:49:35

大明狐 发表于 2024-12-26 09:19
能显示雪花点,说明驱动部分没有问题,正常驱动屏幕了。问题必然就是出在显示函数的使用上。正确顺序是在 ...

他的是SSD1306的iic屏。我也有一块,最左边是VCC的
页: [1] 2
查看完整版本: 求助帖—如何使用擎天柱AI8051最小系统板驱动iic0.96OLED屏幕