51单片机学习7

IIC协议

5.1.1 IIC协议概述

IIC全称Inter-Integrated Circuit (集成电路总线)

是由PHILIPS公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备。IIC属于半双工(同一时间只能发送或接受,只能一个方向)同步通信方式

5.1.2 特点

简单性和有效性。

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

多主控(multimastering)

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

5.1.2 构成

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

5.2.1 IIC协议

IIC总线在传输数据的过程中一共有三种类型信号,分别为:开始信号、结束信号和应答信号。

//起始位,停止位,数据位,速度

这些信号中,起始信号是必需的,结束信号和应答信号

  • 起始信号

         

     a——b点:SCL和SDA同处于高电平,且延时时间大于4.7us

     b——c点:SDA由高电平变为低电平

     c——d点:SCL处于高电平,SDA处于低电平且延时时间大于4us

        

  • 终止信号

     

     a——b点:SCL处于高电平,SDA处于低电平且延时时间大于4us

     b——c点:SDA由低电平变为高电平

     c——d点:SCL和SDA同处于高电平,且延时时间大于4.7us

  • 应答信号

发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号。

应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字 节;

应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。 

  • 数据发送的时序

a点:注意!注意!注意!信号的转换(0和1的转换)只能发生在SCL为低电平(0)的时候发生。如果SCL为高电平,SDA的转换即信号的转换会被误认为是终止或起始信号

b——c点:这两点之间,SCL为高电平,此时发生数据的传输

代码
#include "reg52.h"
#include "intrins.h"
sbit SCL=P0^1;
sbit SDA=P0^3;
void IIC_START()
{
	SCL=1;
	SDA=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;
}
char IIC_NACK()
{
	char flag;
	SDA=0;//在时钟脉冲9期间释放数据线
	_nop_();
	SCL=1;
	_nop_();
	flag=SDA;
	
	return flag;
}
void IIC_Send_byte()
{
	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 main()
{
	int a=10;
	
	IIC_START();
	IIC_STOP();
	
	
	
}

5.3.1 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)
5.1.4 OLED的寻址模式
如何显示一个点?
有三种,分别位页地址模式,水平地址模式和垂直地址模式,可以通过一下表格进行配置
内存管理
{
// 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)
{
// 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(dataData);
//7. ACK
IIC_ACK();
//8. STOP
IIC_Stop();
}

5.3.2 OLED的寻址模式

如何显示一个点?

有三种,分别位页地址模式,水平地址模式和垂直地址模式,可以通过一下表格进行配置

内存管理

 页地址模式
水平地址模式

垂直地址模式

列地址选择

 例子:页寻址模式

1.找到page,从page0,开始0xb0,

2.发送cmd:0x20;Set Memory

2.发送cmd:0x02;默认页寻址模式Addressing Mode

代码

#include "reg52.h"
#include "intrins.h"
#include "IIC.h"
sbit SCL=P0^1;
sbit SDA=P0^3;

void main()
{
	int a=10;
	//1.oled 初始化
	Oled_Init();
	//2.选择一个位置,确认寻址模式,选择对应的page,显示一个点
	OLED_write_cmd(0x20);
	OLED_write_cmd(0x02);
	

	
	OLED_write_cmd(0xB0);
	
	
	OLED_write_data(0x08);

	
	
	while(1);
	
}
#include "reg52.h"
#include "intrins.h"


sbit SCL=P0^1;
sbit SDA=P0^3;


void IIC_START()
{
	SCL=1;
	SDA=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;//拉低转换信号
	SDA=datasend & 0x80;//获得datasend的最高位
	_nop_();//发送数据建立时间
	SCL=1;//拉高开始传输
	_nop_();//数据发送时间
	SCL=0;//发送完毕,拉低
	_nop_();
	datasend=datasend<<1;
	}
}
void OLED_write_cmd(char datacmd)
{
	/*
1. start()
2. 写入地址 b0111 1000 0x78
3. ACK
4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
5. ACK
6. 写入指令/数据
7. ACK
8. STOP
*/
	IIC_START();
	IIC_Send_byte(0x78);
	IIC_ACK();
	IIC_Send_byte(0x00);
	IIC_ACK();
	IIC_Send_byte(datacmd);
	IIC_ACK();
	IIC_STOP();
}

void OLED_write_data(char datadata)
{
	/*
1. start()
2. 写入地址 b0111 1000 0x78
3. ACK
4. cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
5. ACK
6. 写入指令/数据
7. ACK
8. STOP
*/
	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(void){
	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		
}

此代码会出现满屏雪花,但由于本人技术问题还未能解决,往后学习看看能不能解决

列地址选择

2的7次=128

lower column控制低64列——0x0...

high  column控制高64列——0x1...

做左边0x00,0x10;最右边0x0f,0x17;

最终代码

需要加入清屏函数

#include "reg52.h"
#include "intrins.h"
#include "IIC.h"
sbit SCL=P0^1;
sbit SDA=P0^3;

void main()
{
	int a=10;
	//1.oled 初始化
	Oled_Init();
	//2.选择一个位置,确认寻址模式,选择对应的page,显示一个点
	OLED_write_cmd(0x20);
	OLED_write_cmd(0x02);
	OLED_clear();
	
	OLED_write_cmd(0xB0);
	OLED_write_cmd(0x0f);
	OLED_write_cmd(0x17);
	
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	
	
	OLED_write_cmd(0xB5);
	OLED_write_cmd(0x00);
	OLED_write_cmd(0x10);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	OLED_write_data(0x08);
	
	
	
	OLED_write_cmd(0xB8);
	OLED_write_cmd(0x0f);
	OLED_write_data(0x17);
	OLED_write_data(0x08);
	
	while(1);
	
}

5.4.1 OLED显示图片

  • 21
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值