51单片机OLED12864 I2C接口使用教程

发布者:清新自然最新更新时间:2020-08-06 来源: 51hei关键字:51单片机  OLED  I2C接口 手机看文章 扫描二维码
随时随地手机看文章

    现在能买到的OLED12864显示屏大多为SPI和I2C接口的,I2C通信协议只需要两条总线就可以进行通信,下面介绍一下如何用51单片机使用I2C接口的OLED12864。


       首先介绍一下I2C通信协议,I2C(Inter-Integrated Circuit)字面上的意思是集成电路之间,它其实是I2CBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。I2C的正确读法为“I平方C”("I-squared-C")。

       I2C只使用两条双向漏极开路(Open Drain)(串行数据(SDA)及串行时钟频率(SCL))总线,且利用上拉电阻将两条总线的电位上拉。I2C允许相当大的工作电压范围,但典型的电压准位为+3.3V或+5V。

       I2C的参考设计使用一个7比特长度的地址空间但保留了16个地址,所以在一组总线最多可和112个节点通信[a]。常见的I2C总线依传输速率的不同而有不同的模式:标准模式(100 Kbit/s)、低速模式(10 Kbit/s),但时钟频率可被允许下降至零,这代表可以暂停通信。而新一代的I2C总线可以和更多的节点(支持10比特长度的地址空间)以更快的速率通信:快速模式(400 Kbit/s)、高速模式(3.4 Mbit/s)。

       我们在51单片机中使用I2C通信协议的时候,需要编写程序去模拟I2C总线的通信,详细的I2C通信协议的介绍可以参考:http://www.51hei.com/bbs/dpj-110328-1.html

       对于I2C通信协议,需要补充的一点是:在实际通信传输数据时,SCL总线拉高的时间只要大于1.5μs都能够正常传输数据。

       OLED12864的裸屏是由SSD1306驱动的,I2C接口的OLED12864模块对外一共有4个接口,从左到右分别是GND(接地)、VCC(电源正极,可加3.3V,也可加5V)、SCL(时钟总线)、SDA(数据总线):



       模块背面的IIC ADRESSSELECT表示该模块在I2C通信作为从机时的地址,当中间的脚用电阻和左边接起来时,地址为0x78,当和右边接起来时,地址为0x7A。



       SSD1306的I2C总线数据格式,可以看出,往OLED12864写数据时,先发送一个起始信号,接着发送从机地址,从机地址带有读写位(低电平为写),之后就可以发送指令或数据。在发送指令或数据之前,一般都需要发送一个控制字节,如图,控制字节的最高位为连续位(如果连续位为0,接下来发送的信息只能包含数据字节),次高位为数据/指令选择位(该位声明接下来发送的是数据还是指令,0为指令,1为数据),控制字节的低六位为0。可以在一个声明连续发送数据的控制字节后面跟上多个数据字节。


注释详细的51单片机源程序如下(IIC.c):

#include "IIC.h"


void delay5us()               

{


}


void I2C_init()                                   //初始化

{

        SDA = 1;

        _nop_();

        SCL = 1;

        _nop_();                //空闲时,两条线均为高电平         

}


/*I2C通信起始信号*/

void I2C_start()

{

        SCL = 1;   //此时主机有总线控制权,先把SCL线拉高

        _nop_();   //稳定一下

        SDA = 1;   //把SDA线拉高,以便发出起始信号(不确定是否为高)

        delay5us();//通信协议规定延时大于4.7us

        SDA = 0;   //拉低SDA线,制造下降沿的起始信号

        delay5us();//通信协议规定延时大于4us

}

                                 

/*I2C通信终止信号*/

void I2C_stop()

{

        SDA = 0;   //拉低SDA线,以便发出终止信号

        _nop_();   //稳定一下

        SCL = 1;   //拉高SCL线

        delay5us();//通信协议规定延时大于4us

        SDA = 1;   //拉高SDA线

        delay5us();//通信协议规定延时大于4.7us

}


/*从机应答检测*/

bit Test_ack()

{

        SCL = 1;        

        //拉高SCL线,以便主机读取从机发出的应答或非应答信号

        delay5us();//通信协议规定延时大于4us

        if(SDA)           

        //主机读取的SDA线为高,说明从机发送了一个非应答信号

        {

                SCL = 0;/*接下来准备发送停止信号,所以让时钟总线SCL拉低,

                                让I2C_stop();函数中的SDA可变为0*/

                _nop_();//稳定总线

                I2C_stop();

                return 0;//结束检测从机应答函数

        }        

        else

        //主机读取的SDA线为低,说明从机发送了一个应答信号

        {

                SCL = 0;/*将时钟总线SCL拉低,此时SDA上数据的变化才有效,

                                因为接下来会继续发数据*/

                _nop_();//稳定总线

                return 1;

        }

}


/*I2C通信:发送一个字节*/

void I2C_send_byte(uint8_t byte)

{

        uint8_t i;//声明一个计数变量i

        for(i = 0; i < 8; i++)//一个字节有8位,发8次

        {

                SCL = 0;//拉低SCL,让数据总线SDA变化有效

                _nop_();//稳定总线

                if(byte & 0x80)//1000 0000 & byte

/*如果(要发送数据的当前传输位)byte的最高位为1,执行该if语句,

  如果(要发送数据的当前传输位)byte的最高位为0,不执行该if语句*/

                {

                        SDA = 1;   

                        //(当前传输位)byte的最高位为1,即把1放到SDA线上

                        _nop_();//稳定总线

                }        

                else

                //如果(当前发送位)byte的最高位为0(不为1),给SDA送0

                {

                        SDA = 0;

                        _nop_();//稳定总线

                }

                SCL = 1;//拉高SCL线,使从机能够从SDA线上读取到当前的数据

                _nop_();//稳定总线

                byte <<= 1;

/*使byte左移一位,即原来已被发送到SDA线上的最高位被移除,

第七位(还未发送的数据位)变成最高位变为下一次循环的当前发送位*/

        }

        SCL = 0;

        //发送完数据之后,将SCL拉低,以便从机改变SDA线,发出应答信号

        _nop_();//稳定总线

        SDA = 1;//释放总线控制权

        _nop_();//稳定总线

}



OLED_12864.c

#include "OLED_12864.h"



void Delay300ms()

{


}



/*写指令函数,第一个参数为指令,第二、三个参数选择是否需要通信开始和结束函数,=1有,=0没有*/

bit OLED12864_Write_Commmand(uint8_t cmd, bit start, bit stop)

{

        if(start)

        {

                I2C_start();

                I2C_send_byte(OLED_12864_Address+0);//写从机地址,并且加上读写标志位(最后一位)

                if(!Test_ack())

                {

                        return 0;

                }

                /*执行从机应答检测函数,如果从机发送了非应答信号,那么就退出数据发送函数*/

        }

        I2C_send_byte(0x80 | 0x00 | 0x00);  //Co位为1(接下来要传指令),DC为0(接下来是指令)

        if(!Test_ack())

        {

                return 0;

        }

        /*执行从机应答检测函数,如果从机发送了非应答信号,那么就退出数据发送函数*/


        I2C_send_byte(cmd);

        if(!Test_ack())

        {

                return 0;

        }

        /*执行从机应答检测函数,如果从机发送了非应答信号,那么就退出数据发送函数*/


        if(stop)

                I2C_stop();


        return 1;

}


/*写连续数据函数,第一个参数为数据,第二个参数为发送连多少位连续的数据,第三、四个参数选择是否需要通信开始和结束函数,=1有,=0没有*/

bit OLED12864_Write_Continuous_Data(uint8_t* dat, uint8_t count, bit start, bit stop)

{

        uint8_t i = 0;//定义计数变量

        if(start)

        {

                I2C_start();

                I2C_send_byte(OLED_12864_Address+0);//写从机地址,并且加上读写标志位(最后一位)

                if(!Test_ack())

                {

                        return 0;

                }

                /*执行从机应答检测函数,如果从机发送了非应答信号,那么就退出数据发送函数*/

        }

        I2C_send_byte(0x00 | 0x40 | 0x00);  //Co位为0(接下来只传数据),DC为1(接下来是数据)

        if(!Test_ack())

        {

                return 0;

        }

        /*执行从机应答检测函数,如果从机发送了非应答信号,那么就退出数据发送函数*/

        for(i = 0 ;i < count ;i++)

        {

                I2C_send_byte(*dat++);

                if(!Test_ack())

                {

                        return 0;

                }

        /*执行从机应答检测函数,如果从机发送了非应答信号,那么就退出数据发送函数*/

        }


        if(stop)

                I2C_stop();


        return 1;

}



/*写相同的连续数据函数,第一个参数为数据,第二参数为发送的次数*/

bit OLED12864_Write_Same_Continuous_Data(uint8_t dat, uint8_t count)

{

        uint8_t i = 0;//定义计数变量

        I2C_start();

        I2C_send_byte(OLED_12864_Address+0);//写从机地址,并且加上读写标志位(最后一位)

        if(!Test_ack())

        {

                return 0;

[1] [2] [3]
关键字:51单片机  OLED  I2C接口 引用地址:51单片机OLED12864 I2C接口使用教程

上一篇:基于51单片机的自行车测速测距程序
下一篇:电子密码锁设计24c01+12864

推荐阅读最新更新时间:2024-11-17 12:38

8051单片机(STC89C52)稳定显示某两位数字
#include STC89C5xRC.H void delay() { int i, j; for(i = 0; i 15; i++) for(j = 0; j 15; j++) ; } void disp_digit() { int d = 60;//要显示的数字 unsigned char code DIG_CODE = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f}; while(1) { //显示个位数 P2 = 0;// P2 = 0 - (P24, P23, P22) = (0, 0, 0) - 右数第一个数
[单片机]
80<font color='red'>51单片机</font>(STC89C52)稳定显示某两位数字
据预计因OLED显示屏产能问题 oled屏iPhone8产量可能iPhone8占总产
    大家肯定都对今年全新的 iPhone 非常期待,当然,很多人也把自己关注的焦点放到了传闻中将会拥有众多新功能的 iPhone 8 身上。传闻称,iPhone 8 将采用全新设计,它的正面无边框,并且配备 OLED 显示屏。据说这一高端机型的制作成本远远超过了现有的 iPhone 产品。大家肯定也很关心 OLED iPhone 量产的问题,外媒也提到,在 iPhone 8 量产的过程中,三星 OLED 屏的产量也将会是一个非常关键的变量。   之前,不少传闻称三星将会为苹果提供 5000 万块 OLED 屏幕,但是从现在的情况来看,摩根斯坦利方面认为也许三星最终会为苹果带来 5000万到 1 亿块 OLED 屏幕。   这意
[电源管理]
51单片机的LED的位定义
一、位定义原理 定义方法:sbit 位名=特殊功能寄存器^位置; sbit LED1 = P2^0; 符号 ^ 前面是特殊功能寄存器的名字,后面的数字定义的可寻址位在特殊功能寄存器中的位置,取值必须是0~7 p2是连接LED的IO口,p2^0到7分别对应LED1到8 二、代码实现 #include reg52.h //对八个LED分别进行位定义 sbit LED1 = P2^0; sbit LED2 = P2^1; sbit LED3 = P2^2; sbit LED4 = P2^3; sbit LED5 = P2^4; sbit LED6 = P2^5; sbit LED7 = P2^6; sbit LED8 = P2^
[单片机]
<font color='red'>51单片机</font>的LED的位定义
51单片机控制数码管动态显示程序
说明: 驱动四位一体数码管动态显示数字,可方便的移植到其它程序中。 例如:1、硬件改为三位一体或二位一体数码管,只需修改Display_Scan()函数COM个数。 2、本例中,采用了共阴数码管,如果用在共阳数码管,只需修改相应段码表。   本程序使用P0口作为段码数据发送端,P2.0-P2.3作为数码管扫描选通, 使用P0口时,因单片机内部没有上拉电阻,所以要外接上拉电阻(参考阻值470欧姆). // STC89C52RC // +---------------+ // | | // | | Digital Number // | | _______________________ // | | | __ __ __ __
[单片机]
51单片机自学笔记(一)——keil软件的使用
认识单片机 单片机:在一片集成电路芯片上集成微处理器、存储器、I/O接口电路,从而构成了单芯片微型计算机,即单片机。 单片机的发展:单片机的发展大概经过三个阶段。第一个阶段,初级单片机阶段,以Intel公司的MCS-48为代表,这个系列的单片机在片内集成了8位CPU、并行I/O口、8位定时/计数器、RAM等,无串行接口,寻址范围不大于4KB。第二阶段,高性能单片机阶段,以MCS-51为代表,这个阶段的单片机均带有串行接口,具有多级中断处理系统,定时/计数器为16位,片内RAM和ROM容量相对增大,且寻址范围可达64KB。第三阶段,8位机巩固完善,16位、32位机推出阶段,以MCS-96和MCS-960为代表,片内RAM和ROM
[单片机]
<font color='red'>51单片机</font>自学笔记(一)——keil软件的使用
基于51单片机的无线遥控小车设计
这次的院里的电子设计竞赛我们做的是遥控小车。其实两个礼拜前就做完了,工作量加起来其实也就2天的功夫,之后由于懒,所以大家就没有往里面加入东西发挥。今晚答辩被老师说了一顿,还好老师都是认识的,我们有多少实力都清楚。无所谓了,呵呵,又要开始做其他的东西了。这个课题本身就是很简单的。还是不废话了上图吧。 这是遥控器,当然焊工不错(关键是看背面,阿康的技术绝对OK)【实物图】 这个是遥控器的【原理图】,上一幅图的绿色的PCB板子就是原理图上的2262,这个模块是老师发的包括有接收的2272,因为地址码已经做好了,所以只要发数据码就可以了,联系到接收,因为接收有悬空、0、1的三种状况,为了避免误发信息所以将悬空的功能隐去,只在按键
[单片机]
基于<font color='red'>51单片机</font>的无线遥控小车设计
51单片机外扩ROM方法
51单片机外扩ROM方法 强烈建议用户尽可能不要考虑外扩程序存储器,如果非扩不可,可以仿照下图所示电路进行扩展 图中P0口输出外部ROM的低8位地址信号,P2口输出高8位地址信号;ALE端输出地址锁存信号,/PSEN输出程序存储器输出使能信号。 两个模块 P89V51RD2单片机内部有64K用户ROM区和8K BOOT ROM区两个模块 两个模块在物理上是分开的,尽管地址重合,但一般不会发生冲突。 用户程序存储区 P89V51RD2内部有64K Flash ROM,不需要用户再进行ROM扩展 地址范围:0000H~FFFFH 其内部分配和其他51系列单片机是相同的 Fl
[单片机]
<font color='red'>51单片机</font>外扩ROM方法
51单片机串口检测程序
#i nclude "reg51_STC.H" #define uchar unsigned char #define uint unsigned int //-------------------------------------------------------------------------- //函数名称: UART_Init() //函数功能: 串口初始化函数,在系统时钟为11.059MHZ时,设定串口波特率为9600bit/s //其他说明: 串口接收中断允许,发送中断禁止 //-------------------------------------------------------------
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved