5.1IIC协议(基于oled模块)

文章介绍了IIC总线的基本概念、特点和构成,包括其多主控特性及信号传输过程中的起始、结束和应答信号。接着详细展示了如何使用C51单片机的IO口模拟I2C通信,以及编写OLED显示屏的写命令、写数据和初始化函数。此外,还讨论了OLED的寻址模式,包括页地址模式、水平地址模式和垂直地址模式,并提供了清屏和显示一个点的代码示例。
摘要由CSDN通过智能技术生成
  1. IIC概述

IIC全称Inter-Integrated Circuit (集成电路总线) 是由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双 工同步通信方式
  • 特点

  1. 简单性和有效性。 由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降 低了互联成本。总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件

  1. 多主控(multimastering) 其中任何能够进行发送和接收的设备都可以成为主总线。一个主控能够控制信号的传输和时钟频率。当 然,在任何时间点上只能有一个主控。

  • 构成

IIC串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL,其时钟信号是由主控 器件产生。所有接到IIC总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线 的SCL上。对于并联在一条总线上的每个IC都有唯一的地址。

2. IIC协议

IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。 //起始位,停止位,数据位,速度 这些信号中,起始信号是必需的,结束信号和应答信号

  • 起始信号

  • 终止信号

  • 应答信号

发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。 应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字 节; 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。

  • 数据发送的时序

  • 由于c51单片机没有i2c功能,我们用io口模拟i2c

3.代码-起始信号,终止信号,数据发送函数

sbit scl = P0^1;
sbit sda = P0^3;

void IIC_Start()
{
    sda = 1;
    scl = 1;
    _nop_();
    sda = 0;
    _nop_();
}
void IIC_Stop()
{
    sda = 0;
    scl = 1;
    _nop_();
    sda = 1;
    _nop_();
}

char IIC_ACK()
{
    char flag;
    sda = 1;//就在时钟脉冲9期间释放数据线
    _nop_();
    scl = 1;
    _nop_();
    flag = sda;
    _nop_();
    scl = 0;
    _nop_();
    return flag;
}

void IIC_Send_Byte(char dataSend)
{
    int i;
    for(i = 0;i<8;i++){
        scl = 0;//scl拉低,让sda做好数据准备
        sda = dataSend & 0x80;//1000 0000获得dataSend的最高位,给sda
        _nop_();//发送数据建立时间
        scl = 1;//scl拉高开始发送
        _nop_();//数据发送时间
        scl = 0;//发送完毕拉低
        _nop_();//
        dataSend = dataSend << 1;
    }
}

4.OLED写命令

/*
1. start()
2. 写入 b0111 1000 0x78
3. ACK
4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
5. ACK
6. 写入指令/数据
7. ACK
8. STOP
*/
void Oled_Write_Cmd(char dataCmd)
{
    // 1. start()
    IIC_Start();
    // 2. 写入从机地址 b0111 1000 0x78
    IIC_Send_Byte(0x78);
    // 3. ACK
    IIC_ACK();
    // 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
    IIC_Send_Byte(0x00);
    // 5. ACK
    IIC_ACK();
    //6. 写入指令/数据
    IIC_Send_Byte(dataCmd);
    //7. ACK
    IIC_ACK();
    //8. STOP
    IIC_Stop();
}

void Oled_Write_Data(char dataData){   //OLED写入数据函数
 
    IIC_Start();             //开始信号函数
    IIC_Send_Byte(0x78);     //写入从机地址
    IIC_Ack();               //应答信号函数
    IIC_Send_Byte(0x40);     //发送一个写数据的信号
    IIC_Ack();               //应答信号函数
    IIC_Send_Byte(dataData);  //开始写入数据
    IIC_Ack();
    IIC_Stop();              //终止信号函数
}

5.oled的寻址模式

如何显示一个点? 有三种,分别位页地址模式,水平地址模式和垂直地址模式,可以通过一下表格进行配置 内存管理

水平地址模式

垂直地址模式

Oled_Write_Cmd(0x20);   // 选择页寻址模式
Oled_Write_Cmd(0x02);    //第几页

主要是这里

列地址选择

Oled_Write_Cmd(0xB0);   //选择PAGE0,可以配置8次,分别是B0-B7
//上面都配置完后
Oled_Write_Data(0x08);  //显示一个点

6.代码-清屏函数

void Oled_Clear()       //清屏代码
{
    int i, j;
    for(i=0;i<8;i++)
    {
        Oled_Write_Cmd(0xB0+i);//page0--page7
        //每个page从0列
        Oled_Write_Cmd(0x00);
        Oled_Write_Cmd(0x10);
        //一共有128列,0~127
        for(j=0;j<128;j++)
        {
            Oled_Write_Data(0);
        }
    }
}

7.代码-oled初始化函数

void Oled_Init()
{
    Oled_Write_Cmd(0xAE);//--display off
    Oled_Write_Cmd(0x00);//---set low column address
    Oled_Write_Cmd(0x10);//---set high column address
    Oled_Write_Cmd(0x40);//--set start line address
    Oled_Write_Cmd(0xB0);//--set page address
    Oled_Write_Cmd(0x81); // contract control
    Oled_Write_Cmd(0xFF);//--128
    Oled_Write_Cmd(0xA1);//set segment remap
    Oled_Write_Cmd(0xA6);//--normal / reverse
    Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
    Oled_Write_Cmd(0x3F);//--1/32 duty
    Oled_Write_Cmd(0xC8);//Com scan direction
    Oled_Write_Cmd(0xD3);//-set display offset
    Oled_Write_Cmd(0x00);//
    Oled_Write_Cmd(0xD5);//set osc division
    Oled_Write_Cmd(0x80);//
    Oled_Write_Cmd(0xD8);//set area color mode off
    Oled_Write_Cmd(0x05);//
    Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
    Oled_Write_Cmd(0xF1);//
    Oled_Write_Cmd(0xDA);//set com pin configuartion
    Oled_Write_Cmd(0x12);//
    Oled_Write_Cmd(0xDB);//set Vcomh
    Oled_Write_Cmd(0x30);//
    Oled_Write_Cmd(0x8D);//set charge pump enable
    Oled_Write_Cmd(0x14);//
    Oled_Write_Cmd(0xAF);//--turn on oled panel
}

8.代码-显示一个点

#include "reg52.h"
#include "intrins.h"

sbit scl = P2^0;
sbit sda = P2^1;

void IIC_Start()
{
    scl = 0;//消除雪花
    sda = 1;
    scl = 1;
    _nop_();//一个nop的时间大概5us
    sda = 0;
    _nop_();

}

void IIC_Stop()
{
    scl = 0;    //防止雪花
    scl = 1;
    sda = 0;
    
    _nop_();
    sda = 1;
    _nop_();
}

char IIC_Ack()
{
    char flag;
       sda = 1;
    _nop_();
    scl = 1;
    _nop_();
    flag = sda;
    _nop_();
    scl = 0;
    _nop_();
    
    return flag;
}

void IIC_Send_Byte(char dataSend)
{
    int i;
    for(i=0;i<8;i++){
           scl = 0;
        sda = dataSend & 0x80;//dataSend的最高位
        _nop_();
        scl = 1;
        _nop_();
        scl = 0;
        _nop_();
        dataSend = dataSend << 1;
    }
}
void Oled_Write_Cmd(char dataCmd)
{
//    1. start()
    IIC_Start();
//    2. 写入 b0111 1000 0x78
    IIC_Send_Byte(0x78);
//    3. ACK
    IIC_Ack();
//    4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
    IIC_Send_Byte(0x00);
//    5. ACK
    IIC_Ack();
//    6. 写入指令/数据
    IIC_Send_Byte(dataCmd);
//    7. ACK
    IIC_Ack();
//    8. STOP
    IIC_Stop();

}

void Oled_Write_Data(char dataData){   //OLED写入数据函数
 
    IIC_Start();             //开始信号函数
    IIC_Send_Byte(0x78);     //写入从机地址
    IIC_Ack();               //应答信号函数
    IIC_Send_Byte(0x40);     //发送一个写数据的信号
    IIC_Ack();               //应答信号函数
    IIC_Send_Byte(dataData);  //开始写入数据
    IIC_Ack();
    IIC_Stop();              //终止信号函数
}

void Oled_Init()
{
    Oled_Write_Cmd(0xAE);//--display off
    Oled_Write_Cmd(0x00);//---set low column address
    Oled_Write_Cmd(0x10);//---set high column address
    Oled_Write_Cmd(0x40);//--set start line address
    Oled_Write_Cmd(0xB0);//--set page address
    Oled_Write_Cmd(0x81); // contract control
    Oled_Write_Cmd(0xFF);//--128
    Oled_Write_Cmd(0xA1);//set segment remap
    Oled_Write_Cmd(0xA6);//--normal / reverse
    Oled_Write_Cmd(0xA8);//--set multiplex ratio(1 to 64)
    Oled_Write_Cmd(0x3F);//--1/32 duty
    Oled_Write_Cmd(0xC8);//Com scan direction
    Oled_Write_Cmd(0xD3);//-set display offset
    Oled_Write_Cmd(0x00);//
    Oled_Write_Cmd(0xD5);//set osc division
    Oled_Write_Cmd(0x80);//
    Oled_Write_Cmd(0xD8);//set area color mode off
    Oled_Write_Cmd(0x05);//
    Oled_Write_Cmd(0xD9);//Set Pre-Charge Period
    Oled_Write_Cmd(0xF1);//
    Oled_Write_Cmd(0xDA);//set com pin configuartion
    Oled_Write_Cmd(0x12);//
    Oled_Write_Cmd(0xDB);//set Vcomh
    Oled_Write_Cmd(0x30);//
    Oled_Write_Cmd(0x8D);//set charge pump enable
    Oled_Write_Cmd(0x14);//
    Oled_Write_Cmd(0xAF);//--turn on oled panel
}

void Oled_Clear()       //清屏代码
{
    int i, j;
    for(i=0;i<8;i++)
    {
        Oled_Write_Cmd(0xB0+i);//page0--page7
        //每个page从0列
        Oled_Write_Cmd(0x00);
        Oled_Write_Cmd(0x10);
        //一共有128列,0~127
        for(j=0;j<128;j++)
        {
            Oled_Write_Data(0);
        }
    }
}
void main()
{
    Oled_Clear();
    Oled_Init();            //初始化OLED
    Oled_Write_Cmd(0x20);   //选择一个位置,确认页寻址地址
    Oled_Write_Cmd(0x02);
    Oled_Write_Cmd(0xB0);   //选择PAGE0,可以配置8次,分别是B0-B7
    Oled_Write_Data(0x08);  //显示一个点
 
    while(1);              //防止程序退出
}

来个没有经过分文件的代码

9.代码oled-显示“上官可编程”

/*-- 文字: A --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 --*/
char A1[8] = {0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00};
char A2[8] = {0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20};
/*-- 文字: 上 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
char s1[16] =
{0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,0x00
};
char s2[16] =
{0x40,0x40,0x40,0x40,0x40,0x40,0x7F,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00
};
/*-- 文字: 官 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char g1[16] =
{0x10,0x0C,0x04,0xE4,0x24,0x24,0x25,0x26,0x24,0x24,0x24,0xE4,0x04,0x14,0x0C,0x00
};
code char g2[16] =
{0x00,0x00,0x00,0xFF,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0x49,0xF8,0x00,0x00,0x00
};
/*-- 文字: 可 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char k1[16] =
{0x00,0x02,0x02,0xF2,0x12,0x12,0x12,0xF2,0x02,0x02,0x02,0xFE,0x02,0x02,0x02,0x00
};
code char k2[16] =
{0x00,0x00,0x00,0x0F,0x04,0x04,0x04,0x0F,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00
};
/*-- 文字: 编 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char b1[16] =
{0x20,0x30,0xAC,0x63,0x30,0x00,0xFC,0x24,0x25,0x26,0x24,0x24,0x24,0x3C,0x00,0x00
};
code char b2[16] =
{0x22,0x67,0x22,0x12,0x52,0x38,0x07,0xFF,0x09,0x7F,0x09,0x3F,0x89,0xFF,0x00,0x00
};
/*-- 文字: 程 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char c1[16] =
{0x24,0x24,0xA4,0xFE,0x23,0x22,0x00,0x3E,0x22,0x22,0x22,0x22,0x22,0x3E,0x00,0x00
};
code char c2[16] =
{0x08,0x06,0x01,0xFF,0x01,0x06,0x40,0x49,0x49,0x49,0x7F,0x49,0x49,0x49,0x41,0x00
};
void main()
{
unsigned char i;
//1. OLED初始化
Oled_Init();
//2. 选择一个位置
//2.1 确认页寻址模式
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear();
//2.2 选择PAGE0 1011 0000
// 0xB0
Oled_Write_Cmd(0xB0);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<16;i++){
Oled_Write_Data(s1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(g1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(k1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(b1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(c1[i]);
}
Oled_Write_Cmd(0xB1);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<16;i++){
Oled_Write_Data(s2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(g2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(k2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(b2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(c2[i]);
}
while(1);
}
51单片机iic协议oled代码可以通过以下步骤实现: 1. 首先,我们需要包含51单片机的头文件和对应的引脚定义,以便于程序中使用。 ```c #include <reg52.h> sbit SCL=P2^1; // 定义SCL引脚 sbit SDA=P2^0; // 定义SDA引脚 ``` 2. 然后,我们需要定义iic协议中的起始条件、停止条件和数据传输函数。 ```c void iic_start() // IIC起始条件 { SDA=1; SCL=1; Delay5us(); SDA=0; Delay5us(); SCL=0; } void iic_stop() // IIC停止条件 { SDA=0; Delay5us(); SCL=1; Delay5us(); SDA=1; } void iic_writebyte(unsigned char dat) // 写一个字节 { unsigned char i; for(i=0;i<8;i++) { SDA=(bit)(dat&0x80); dat<<=1; SCL=1; Delay5us(); // 调整延时时间,保证IIC操作正常 SCL=0; } SDA=1; SCL=1; Delay5us(); SCL=0; } ``` 3. 最后,我们可以示范如何使用iic协议oled屏幕进行通信,并将需要显示的内容写入oled屏幕的数据寄存器。 ```c void oled_write_cmd(unsigned char cmd) // 向OLED写控制命令 { iic_start(); iic_writebyte(0x78); // OLED I2C Write address iic_writebyte(0x00); // Control byte: Co = 0, D/C# (bit0 write command) iic_writebyte(cmd); // Write command iic_stop(); } void oled_write_data(unsigned char dat) // 向OLED写数据 { iic_start(); iic_writebyte(0x78); // OLED I2C Write address iic_writebyte(0x40); // Control byte: Co = 0, D/C# (bit0 write data) iic_writebyte(dat); // Write data iic_stop(); } ``` 通过以上代码,我们可以实现51单片机基于iic协议控制oled屏幕的显示,从而实现各种图形和文本的显示效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值