使用51单片机与oled配合进行IIC通讯显示汉字或字符

先看代码,会的你可以直接用,不会的我会在代码后面有详细的解释

#include "reg52.h"
#include "intrins.h"
sbit scl = P0^1;
sbit sda = P0^3;
void IIC_Start()//启动IIC
{
    scl=0;
 sda=1;
 scl=1;
 _nop_();
 sda=0;
 _nop_();
}

void IIC_End()//终止IIC
{
    scl=0;
sda=0;
scl=1;
_nop_();
sda=1;
_nop_();
}

char IIC_Ack()//IIC应答
{
    char flag;
    sda=1;//释放数据线
    _nop_();
    scl=1;
    _nop_();
    flag=sda;
    _nop_();
    scl=0;
    _nop_();
    return flag;
}
void send_Byte(char dataSend)//发送一个字节
{
    int i;
    for(i=0;i<8;i++)
    {
   scl=0;//scl拉低,sda可以数据变换
    sda=dataSend & 0x80;//获得sda最高位
    _nop_();//发送数据,建立时间
    scl=1;//scl拉高,开始发送
    _nop_();//数据发送时间
    scl=0;//发送完毕,拉低
    _nop_();
  dataSend=dataSend << 1;//高位开始发送,左移一位,高位不断变换
    }
}

void Oled_Write_Cmd(char dataCmd)
{
    IIC_Start();//1.IICstart
    send_Byte(0x78);//发送从机地址
    IIC_Ack();//应答
    send_Byte(0x00);//开启写入命令0x00或写入数据0x40
    IIC_Ack();//应答
    send_Byte(dataCmd);//写入具体的命令或者数据
    IIC_Ack();
    IIC_End();//IIC结束
}

void Oled_Write_Data(char dataData)
{
// 1. start()
IIC_Start();
//
// 2. 写入从机地址 b0111 1000 0x78
send_Byte(0x78);
// 3. ACK
IIC_Ack();
// 4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
send_Byte(0x40);
// 5. ACK
IIC_Ack();
///6. 写入指令/数据
send_Byte(dataData);
//7. ACK
IIC_Ack();
//8. STOP
IIC_End();
}
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()
{
unsigned char i,j; //char的范围-128 --- 127,使用unsign char
for(i=0;i<8;i++){
Oled_Write_Cmd(0xB0 + i);//page0--page7
//每个page从0列
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
//0到127列,依次写入0,每写入数据,列地址自动偏移
for(j = 0;j<128;j++){
Oled_Write_Data(0);
}
}
}
/*-- 文字: A --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=8x16 但是一页的高只有8,因此需要两页,因此需要两个数组--*/
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 y1[16] =
{0x10,0x10,0xD0,0xFF,0x90,0x10,0x00,0x42,0xE2,0x52,0x4A,0xC6,0x42,0x40,0xC0,0x00
};
char y2[16] =
{0x04,0x03,0x00,0xFF,0x00,0x23,0x10,0x8C,0x43,0x20,0x18,0x47,0x80,0x40,0x3F,0x00
};
/*-- 文字: 栋 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char d1[16] =
{0x10,0x10,0xD0,0xFF,0x90,0x08,0x88,0x68,0x18,0x0F,0xE8,0x08,0x08,0x08,0x08,0x00
};
code char d2[16] =
{0x04,0x03,0x00,0xFF,0x00,0x21,0x11,0x0D,0x41,0x81,0x7F,0x01,0x05,0x09,0x30,0x00
};
/*-- 文字: 很 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char h1[16] =
{0x00,0x10,0x88,0xC4,0x33,0x00,0xFE,0x92,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00
};
code char h2[16] =
{0x02,0x01,0x00,0xFF,0x00,0x00,0xFF,0x40,0x20,0x03,0x0C,0x14,0x22,0x41,0x40,0x00
};
/*-- 文字: 帅 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char s1[16] =
{0x00,0xFC,0x00,0x00,0xFF,0x00,0x00,0xF0,0x10,0x10,0xFF,0x10,0x10,0xF0,0x00,0x00
};
code char s2[16] =
{0x00,0x87,0x40,0x30,0x0F,0x00,0x00,0x1F,0x00,0x00,0xFF,0x08,0x10,0x0F,0x00,0x00
};
/*-- 文字: 哦 --*/
/*-- 宋体12; 此字体下对应的点阵为:宽x高=16x16 --*/
code char o1[16] =
{0xFC,0x04,0x04,0xFC,0x20,0x24,0x24,0xFE,0x22,0x20,0xFF,0x20,0x21,0xA6,0x20,0x00
};
code char o2[16] =
{0x0F,0x04,0x04,0x0F,0x04,0x44,0x82,0x7F,0x81,0x40,0x27,0x18,0x26,0x41,0xF0,0x00
};

void main()
{
    int i;
  Oled_Init();
    Oled_Clear();
    Oled_Write_Cmd(0x20);//选择页模式
    Oled_Write_Cmd(0x02);
    Oled_Write_Cmd(0xB0);//显示第一页
  Oled_Write_Cmd(0x00);
  Oled_Write_Cmd(0x10);
    //第一页显示“杨栋很帅哦”的上半部分,再同一页里,每一列输入完之后会自动跑到下一列
for(i=0;i<16;i++){
Oled_Write_Data(y1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(d1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(h1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(s1[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(o1[i]);
}
//第二页显示“杨栋很帅哦”的下半部分
Oled_Write_Cmd(0xB1);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<16;i++){
Oled_Write_Data(y2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(d2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(h2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(s2[i]);
}
for(i=0;i<16;i++){
Oled_Write_Data(o2[i]);
}
//第三页显示A的上半部分,第四页显示A的下半部分
Oled_Write_Cmd(0xB3);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<8;i++){
Oled_Write_Data(A1[i]);
}

Oled_Write_Cmd(0xB4);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i=0;i<8;i++){
Oled_Write_Data(A2[i]);
}
while(1);
}

首先来说IIC通讯

IIc通讯的起始条件图

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第1张图片

从图上我们可以看出,scl高电平期间,sda变为低电平触发

void IIC_Start()//启动IIC
{
    scl=0;//这里之所以要让scl=0,是为了防止出现“雪花”,同时scl低电平期sda可以跳变
 sda=1;
 scl=1;,
 _nop_();//图上告诉我们sda和scl至少要共同处于高电平至少4.7us, _nop_()函数的时间足够了
 sda=0;//sda由高电平变为低电平,并且时间大于4us,即可触发IIC的起始条件
 _nop_();
}

IIc通讯的终止条件图

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第2张图片

从图上我们可以看出,scl高电平期间,sda变为低电平触发

void IIC_End()//启动IIC
{
    scl=0;//这里之所以要让scl=0,是为了防止出现“雪花”,同时scl低电平期sda可以跳变
 sda=0;
 scl=1;,
 _nop_();//图上告诉我们sda处于低电平和scl处于高电平至少4us, _nop_()函数的时间足够了
 sda=0;//sda由低电平变为高电平,并且时间大于4.7us,即可触发IIC的终止条件
 _nop_();
}

IIc通讯的应答条件图

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第3张图片

char IIC_Ack()//IIC应答
{
    char flag;
    sda=1;//释放数据线,就是相当于把sda拉高
    _nop_();
    scl=1;
    _nop_();//图上告诉我们scl高电平期间持续至少4us,sda变为低电平则表示从机应答,高电平代表从机不应答,这是由硬件触发的,因此我们没有手写sda的值
    flag=sda;
    _nop_();
    scl=0;//图上告诉我们scl拉低
    _nop_();
    return flag;
}

IIc通讯的发送数据或者命令条件图

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第4张图片

图上我们可以看出来,在发送数据的时候,sda发生翻转的时候,scl必须都是低电平。这很正常,因为scl高电平期间sda发生翻转,则不是发送数据或指令,而是触发起始或终止条件,因此数据或者命令的传输必须要发生在scl低电平期间,当scl高电平期间数据或指令要进行传输,同时从高位开始发送,每发送一位,我们要位移一位。

但是scl的跳变是需要实践的,虽然图上没有明确指出要延迟多久,但是我们在发生跳变时延时一个_nop_()函数

oled与单片机进行IIC通讯

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第5张图片

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第6张图片

        当主机IIC(单片机)启动之后,紧接着就要发送从机(oled)的地址,其中A0的存在可以让我们相同的模块同时存在,比如有两个oled,理论上来说它们的从机地址的前六位一样,但是这样就无法区分了,因此我们将两个oled的A0(即第七位)一个设置为0,一个设置为1。如果只有一个,我们输入从机地址(0x78),事实上七位的从机地址,我们写入0x78的时候写了八位,而第八位就是R/W,它的功能是决定主机读还是写,当R/W=0时,主机进入写模式。如果Co等于0,则传输以下信息将包含仅限数据字节。D/ c#位决定下一个数据字节作为命令或数据。如果D/ c#位是如果设置为逻辑“0”,则将以下数据字节定义为命令。如果D/ c#位设置为逻辑“1”,它将以下数据字节定义为将存储在GDDRAM中的数据。GDDRAM的列地址指针每增加一个就自动增加一个写数据。

         这也就是为什么Oled_Write_Cmd()函数里面是send_Byte(0x00),Oled_Write_Data()函数里面是send_Byte(0x40),就是因为D/ c的差异,Oled_Write_Cmd()函数里面D/ c是0,Oled_Write_Cmd()函数里面D/ c是1。

oled的初始化

调用Oled_Write_Cmd()函数,单片机对oled写入对应的命令即可

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第7张图片

oled的3种寻址模式

oled共有128列*64行,其中每8行为一页,共8页,每一页有128列8行。

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第8张图片

页地址模式

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第9张图片这种模式下,对于特定的一页写完一列之后,oled会自动转移到这一页的下一列,当写到col127的时候,不会自动转到下一页,需要我们手动设定下一页。我们这里用oled的页地址只模式,其余两种模式大家想要了解可以自己查资料,我就不细说了

水平地址模式

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第10张图片

垂直地址模式

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第11张图片

我们选择页地址模式就需要输入相应的指令

说明书告诉我们

Oled_Write_Cmd(0x20);//输入0x20进入选择页模式
Oled_Write_Cmd(0x02);//输入0x02进入页地址模式

接着我们选择页

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第12张图片

Oled_Write_Cmd(0xB0);//说明书告诉我们要输入10110X2X1X0

注意我的数据写入数据函数和写入指令函数,他们是一样的

Oled_Write_Data(0x11);单单这一个数据函数意味着要点亮某列某页的第0行和第4行(0x11=00010001)

高四位对应1011为B,X2X1X0刚好对应0~7,共八页,低四位我们选择输入0000,则进去第一页,即page0.      Oled_Write_Cmd(0xB0);//进入第一页

接着我们选择列

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第13张图片

列有128列,从0~127,需要7位进行表示(表中高位有4位,高位的第四位我们不需要,直接用0表示),这刚好对应了上面的两组X3X2X1X0

说明书告诉我们这里存在低四位和高四位之分,低死位所在的位置前面是000,0,高四位前面对应的前面是0001。

Oled_Write_Cmd(0x00);//低四位为0
 Oled_Write_Cmd(0x10);//高四位为0

输入这两条指令就意味着低四位和高四位均为0,也就说数据要从低0列进入。

字模提取

点击参数设置,点击文字输入区字体选择,将字体大小改为12,其余不变,点击确定.

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第14张图片

在文字输入区输入你想输入的汉字

我输入的是“杨栋很帅哦”,然后按住ctrl+回车会生成点阵。

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第15张图片点击取模方式,选择c51格式,点阵生成区会生成相应的位置代码

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第16张图片

我们看到一个汉字对应的宽x高=16x16,但是我们一页的高只有8,因此我们需要两页,一页储存汉字的上半部分,一页储存汉字的下半部分。因此我们对每一个汉字都设置了两个字符数组,对应两页,分别储存汉字的上下两部分,并将每一个为汉字都在第一第二页存放,具体操作看上面的代码。

同一样A也是一样的道理,我们在这里把A放到了第三第四页

使用51单片机与oled配合进行IIC通讯显示汉字或字符_第17张图片

你可能感兴趣的:(51单片机,嵌入式硬件,单片机)