1. IIC协议初识(246.92)
概述
- 全称 Inter-Integrated Circuit (集成电路总线)
- 是由 PHILIPS 公司在80年代开发的两线式串行总线,用于连接微控制器及其外围设备
- 属于半双工同步通信方式
特点(*10KB/s会在面试中问到)
- 简单性和有效性
- 由于接口直接在组件之上,因此IIC总线占用的空间非常小,减少了电路板的空间和芯片管脚的数量,降低了互联成本
- 总线的长度可高达25英尺,并且能够以10Kbps的最大传输速率支持40个组件(*10KB/s会在面试中问到)
- 多主控(multimastering)
- 其中任何能够进行发送和接收的设备都可以成为主总线
- 一个主控能够控制信号的传输和时钟频率
- 当然,在任何时间点上只能有一个主控
构成
- IIC 串行总线一般有两根信号线,一根是双向的数据线 SDA,另一根是时钟线 SCL,其时钟信号是由主控器件产生
- 所有接到 IIC 总线设备上的串行数据 SDA 都接到总线的 SDA 上,各设备的时钟线 SCL 接到总线的 SCL 上
- 对于并联在一条总线上的每个 IC 都有唯一的地址
2. IIC协议起始和终止信号(247.93)
- IIC 总线在传输数据的过程中一共有三种类型信号:开始信号、结束信号和应答信号。(多机通信要点:起始位,停止位,数据位,速度(波特率))
- 这些信号中,起始信号和结束信号是必需的,应答信号则非必需
- 起始信号、终止信号:
- 代码(19./01_IIC协议基本函数封装)
#include "reg52.h"
#include "intrins.h"
sbit scl = P0^1;
sbit sda = P0^3;
void IIC_start(){
sda = 1;
scl = 1;
_nop_();//5us
sda = 0;
_nop_();
}
void IIC_stop(){
sda = 0;
scl = 1;
_nop_();
sda = 1;
_nop_();
}
3. IIC协议ACK函数封装(248.94)
- 应答信号
- 发送器每发送一个字节(8个bit),就在时钟脉冲9期间释放数据线,由接收器反馈一个应答信号;
- 应答信号为低电平时,规定为有效应答位(ACK,简称应答位),表示接收器已经成功地接收了该字节;
- 应答信号为高电平时,规定为非应答位(NACK),一般表示接收器接收该字节没有成功。
- 代码(19./01_IIC协议基本函数封装)
char IIC_ACK(){
//Answer back
char flag;
sda = 1;//在时钟脉冲9期间释放数据线
_nop_();
scl = 1;//拉高
_nop_();
flag = sda;//读数据
_nop_();
scl = 0;//拉低
_nop_();
return flag;
}
4. IIC协议发送一个字节的函数封装(249.95)
数据发送的时序
- 代码(19./01_IIC协议基本函数封装)
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;//将要发送的数据左移一位,准备发送下一位
}
}
5. OLED写入指令和数据(250.96)
OLED 写命令/数据:
- start()
- 写入从机地址 b0111 1000 0x78
- ACK
- cotrol byte: (0)(0)000000 写入命令 (0)(1)000000写入数据
- ACK
- 写入指令/数据
- ACK
- STOP
代码(19./02_OLED写数据写命令函数封装)
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 写入命令
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)(1)000000写入数据
IIC_Send_Byte(0x40);
//5. ACK
IIC_ACK();
//6. 写入指令
IIC_Send_Byte(dataData);
//7. ACK
IIC_ACK();
//8. STOP
IIC_stop();
}
6. OLED显示一个点的思路(251.97)
- Resolution: 128 x 64 dot matrix panel
- 内存管理
- 如何显示一个点?
- 有三种寻址模式:页地址模式、水平地址模式和垂直地址模式,可通过以下表格进行配置
- 设置页寻址模式:(默认即页模式)
a. 发送 cmd:0x20
b. 发送 cmd:0x02
页地址模式
水平地址模式
垂直地址模式
-
PAGE地址选择
- 0xB0–0xB7
- 0xB0–0xB7
-
如果写入0x08(b00001000)会显示什么呢
- 一个字节负责一个Page的一列显示(1处点亮其他灭)
- 一个字节负责一个Page的一列显示(1处点亮其他灭)
7. OLED显示一个点代码实现(252.98)
- 代码(19./03_OLED显示一个点)(显示雪花,需要清屏操作:清雪花的函数)
void Oled_Init(){
Oled_Write_Cmd(0xAE)