原子哥,求助,用模拟I2C驱动OLED不成功

2019-07-21 01:32发布


这是逻辑分析仪读出的图形,我也没看明白,不知道是哪里出纰漏,导致模拟I2C驱动不亮OLED屏幕。感觉模拟I2C的时序延时好难把握啊!求原子哥和大神指教,源程序在附件中。调了好就没调出所以然啊
#include "myi2c.h"
#include "delay.h"
//////////////////////////////////////////////////////////////////////////////////  
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//Mini STM32开发板
//IIC 驱动函数   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2010/6/10 
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 正点原子 2009-2019
//All rights reserved
//////////////////////////////////////////////////////////////////////////////////  

//初始化IIC
void IIC_Init(void)
{     
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
  
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ;   //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
 
IIC_SCL=1;
IIC_SDA=1;

}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT();     //sda线输出
IIC_SDA=1;    
IIC_SCL=1;
delay_us(4);
  IIC_SDA=0;//START:when CLK is high,DATA change form high to low 
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据 
}  
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//STOP:when CLK is high DATA change form low to high
  delay_us(4);
IIC_SCL=1; 
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);  
}

//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答  
void IIC_Send_Byte(u8 txd)
{                        
    u8 t;   
SDA_OUT();    
    IIC_SCL=0;//拉低时钟开始数据传输
    for(t=0;t<8;t++)
    {              
        IIC_SDA=(txd&0x80)>>7;
        txd<<=1;  
delay_us(2);   //对TEA5767这三个延时都是必须的
IIC_SCL=1;
delay_us(2); 
IIC_SCL=0;
delay_us(2);
    }  
}     

OLED.C
#include "oled.h"
#include "oledfont.h"    
#include "delay.h"
#include "myi2c.h"


/*********************OLED写数据************************************/
void OLED_WrDat(u8 IIC_Data)
{
IIC_Start();
IIC_Send_Byte(OLED_ADDRESS);
IIC_Send_Byte(IIC_Data);
IIC_Stop();
}


/*********************OLED写命令************************************/
void OLED_WrCmd(u8 IIC_Command)
{
IIC_Start();
IIC_Send_Byte(OLED_ADDRESS);
IIC_Send_Byte(IIC_Command);
IIC_Stop();
}


/*********************OLED 设置坐标************************************/
void OLED_Set_Pos(u8 x, u8 y)
{
OLED_WrCmd(0xb0+y);
OLED_WrCmd(((x&0xf0)>>4)|0x10);
OLED_WrCmd((x&0x0f)|0x01);
}


/*********************OLED全屏************************************/
void OLED_Fill(u8 bmp_dat)
{
u8 y,x;
for(y=0;y<8;y++)
{
OLED_WrCmd(0xb0+y);
OLED_WrCmd(0x01);
OLED_WrCmd(0x10);
for(x=0;x<X_WIDTH;x++)
OLED_WrDat(bmp_dat);
}
}

/*********************OLED复位************************************/
void OLED_CLS(void)
{
u8 y,x;
for(y=0;y<8;y++)
{
OLED_WrCmd(0xb0+y);
OLED_WrCmd(0x01);
OLED_WrCmd(0x10);
for(x=0;x<X_WIDTH;x++)
OLED_WrDat(0);
}
}

/*********************OLED初始化************************************/
void OLED_Init(void)
{
delay_init();
delay_ms(200); //这里的延时很重要

OLED_WrCmd(0xae);//--turn off oled panel
OLED_WrCmd(0x00);//---set low column address
OLED_WrCmd(0x10);//---set high column address
OLED_WrCmd(0x40);//--set start line address  Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WrCmd(0x81);//--set contrast control register
OLED_WrCmd(Brightness); // Set SEG Output Current Brightness
OLED_WrCmd(0xa1);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
OLED_WrCmd(0xc8);//Set COM/Row Scan Direction   0xc0上下反置 0xc8正常
OLED_WrCmd(0xa6);//--set normal display
OLED_WrCmd(0xa8);//--set multiplex ratio(1 to 64)
OLED_WrCmd(0x3f);//--1/64 duty
OLED_WrCmd(0xd3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WrCmd(0x00);//-not offset
OLED_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequency
OLED_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WrCmd(0xd9);//--set pre-charge period
OLED_WrCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WrCmd(0xda);//--set com pins hardware configuration
OLED_WrCmd(0x12);
OLED_WrCmd(0xdb);//--set vcomh
OLED_WrCmd(0x40);//Set VCOM Deselect Level
OLED_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WrCmd(0x02);//
OLED_WrCmd(0x8d);//--set Charge Pump enable/disable
OLED_WrCmd(0x14);//--set(0x10) disable
OLED_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)
OLED_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7)
OLED_WrCmd(0xaf);//--turn on oled panel
OLED_Fill(0x00); //初始清屏
OLED_Set_Pos(0,0);
}


友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
17条回答
gentalk
2019-07-22 13:33
用的惠特的OLED I2C的接口,看了很多程序,然后还是看文档解决了,既然路过了这里,就针对楼主的代码提提意见,希望能够帮助到大家,在对OLED屏写字节的时候,根据官方的文档,应该要给9个SCLK,前八个给字节数据从高到低,最后一个SCLK为等待oled的ACK信号,在最后一个SCLK上不要主机不要给任何的SDA,可以不读取,加入读取可以用来调试。 捕获.JPG
然后再讲讲这款OLED的数据变化与保持的时序。数据SDA要保持到一个SCLK脉冲结束,Data line is stable,在脉冲期间,如果SDA发生变化,就会产生启动或者结束信号造成错误,数据是在scl拉低了之后才会去改变。
捕获.JPG
惠特的例程软件IIC,C51中,有一个错误,就是在一个字节传输完毕之后,不能在第九个scl脉冲之前去改变SDA的值,不然会导致阻塞了ACK,而导致ACK延后发生,干扰到下一个字节的数据。
更改后的写字节如下,
[mw_shl_code=applescript,true]void Write_IIC_Byte(unsigned char IIC_Byte)
{
        unsigned char i;
        for(i=0;i<8;i++)
        {
                if(IIC_Byte & 0x80)
                        SDA_1;
                else
                        SDA_0;
                SCL_1;
                DELAY_US(1);
                SCL_0;
                IIC_Byte<<=1;
        }

        SCL_1;
        DELAY_US(1);
        SCL_0;
}[/mw_shl_code]
这款OLED的驱动器为SSD1306,经常看到很多人在写IIC程序时喜欢逐行加入delay,在这款驱动器中,除了SCL高电平保持的那个延时不可除去以外,其他的delay均可去掉。包括起始信号和结束信号。我用的是dsp28335,主频是150M,去掉delay没有任何影响,而且我的项目需要一定的实时性。但由于没有更小的延时函数,所以没有去测试,高脉冲需保持多久。另外附上惠特的给的原例程,如果要往其他平台移植软件IIC,看C51的代码就行了。在附带一个惠特的新款SPI的OLED。

一周热门 更多>