这是逻辑分析仪读出的图形,我也没看明白,不知道是哪里出纰漏,导致模拟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);
}
然后再讲讲这款OLED的数据变化与保持的时序。数据SDA要保持到一个SCLK脉冲结束,Data line is stable,在脉冲期间,如果SDA发生变化,就会产生启动或者结束信号造成错误,数据是在scl拉低了之后才会去改变。
惠特的例程软件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。
一周热门 更多>