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_();
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(){
char flag;
sda = 1;
_nop_();
scl = 1;
_nop_();
flag = sda;
_nop_();
scl = 0;
_nop_();
return flag;
}
4. IIC协议发送一个字节的函数封装(249.95)
数据发送的时序
void IIC_Send_Byte(char dataSend){
int i;
for(i = 0;i < 8;i++){
scl = 0;
sda = dataSend & 0x80;
_nop_();
scl = 1;
_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){
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){
IIC_start();
IIC_Send_Byte(0x78);
IIC_ACK();
IIC_Send_Byte(0x40);
IIC_ACK();
IIC_Send_Byte(dataData);
IIC_ACK();
IIC_stop();
}
6. OLED显示一个点的思路(251.97)
- Resolution: 128 x 64 dot matrix panel
- 内存管理
- 如何显示一个点?
- 有三种寻址模式:页地址模式、水平地址模式和垂直地址模式,可通过以下表格进行配置
- 设置页寻址模式:(默认即页模式)
a. 发送 cmd:0x20
b. 发送 cmd:0x02
页地址模式
水平地址模式
垂直地址模式
7. OLED显示一个点代码实现(252.98)
- 代码(19./03_OLED显示一个点)(显示雪花,需要清屏操作:清雪花的函数)
void Oled_Init(){
Oled_Write_Cmd(0xAE);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
Oled_Write_Cmd(0x40);
Oled_Write_Cmd(0xB0);
Oled_Write_Cmd(0x81);
Oled_Write_Cmd(0xFF);
Oled_Write_Cmd(0xA1);
Oled_Write_Cmd(0xA6);
Oled_Write_Cmd(0xA8);
Oled_Write_Cmd(0x3F);
Oled_Write_Cmd(0xC8);
Oled_Write_Cmd(0xD3);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0xD5);
Oled_Write_Cmd(0x80);
Oled_Write_Cmd(0xD8);
Oled_Write_Cmd(0x05);
Oled_Write_Cmd(0xD9);
Oled_Write_Cmd(0xF1);
Oled_Write_Cmd(0xDA);
Oled_Write_Cmd(0x12);
Oled_Write_Cmd(0xDB);
Oled_Write_Cmd(0x30);
Oled_Write_Cmd(0x8D);
Oled_Write_Cmd(0x14);
Oled_Write_Cmd(0xAF);
}
void main(){
int a = 10;
Oled_Init();
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Write_Cmd(0xB0);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
Oled_Write_Data(0x80);
while(1);
}
8. OLED列地址和雪花BUG解决(253.99)
- 列地址选择
- 代码(19./04_OLED选择列地址显示)
void main(){
int a = 10;
Oled_Init();
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Write_Cmd(0xB0);
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_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_Cmd(0xB6);
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_Cmd(0x0f);
Oled_Write_Cmd(0x17);
Oled_Write_Data(0x08);
while(1);
}
9. OLED清屏添加清屏函数(254.100)
10. OLED显示字母A(255.101)
- 打开“字模提取”app,点击“文字输入区字体选择”
- 做字体设置
- 其他选项
- 输入“A”,Ctrl+Enter
- 点击“取模方式”,选择“C51 格式”,即可复制生成的点阵数据
char A1[8] = {0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00};
char A2[8] = {0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20};
void main(){
int i = 0;
Oled_Init();
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear();
Oled_Write_Cmd(0xB0);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i = 0;i < 8;i++){
Oled_Write_Data(A1[i]);
}
Oled_Write_Cmd(0xB1);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i = 0;i < 8;i++){
Oled_Write_Data(A2[i]);
}
while(1);
}
11. OLED显示上官可编程(256.102)
- 代码(19./07_OLED显示上官可编程 - 我记得–赵雷)
code char w1[16] = {0x20,0x24,0x24,0x24,0xFE,0x23,0x22,0x20,0x20,0xFF,0x20,0x22,0x2C,0xA0,0x20,0x00};
code char w2[16] = {0x00,0x08,0x48,0x84,0x7F,0x02,0x41,0x40,0x20,0x13,0x0C,0x14,0x22,0x41,0xF8,0x00};
code char j1[16] = {0x40,0x40,0x42,0xCC,0x00,0x00,0x00,0x84,0x84,0x84,0x84,0x84,0xFC,0x00,0x00,0x00};
code char j2[16] = {0x00,0x00,0x00,0x7F,0x20,0x10,0x00,0x3F,0x40,0x40,0x40,0x40,0x41,0x40,0x70,0x00};
code char d1[16] = {0x00,0x10,0x88,0xC4,0x33,0x00,0xBE,0xAA,0xAA,0xAA,0xAA,0xAA,0xBE,0x80,0x00,0x00};
code char d2[16] = {0x02,0x01,0x00,0xFF,0x00,0x02,0x0A,0x12,0x02,0x42,0x82,0x7F,0x02,0x02,0x02,0x00};
code char h1[16] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
code char h2[16] = {0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
code char z1[16] = {0x40,0x48,0x48,0x48,0xFF,0x48,0x48,0x00,0x04,0x08,0x30,0xC0,0x30,0x0E,0x00,0x00};
code char z2[16] = {0x80,0x60,0x1F,0x20,0x7F,0x44,0x44,0x40,0x48,0x44,0x43,0x40,0x43,0x4C,0x40,0x00};
code char l1[16] = {0x20,0x18,0x0A,0xAA,0xAA,0xAA,0x0A,0xFE,0x0A,0xAA,0xAA,0xAA,0x0A,0x28,0x18,0x00};
code char l2[16] = {0x00,0x00,0xFE,0x92,0x92,0x92,0x92,0xFE,0x92,0x92,0x92,0x92,0xFE,0x00,0x00,0x00};
void main(){
int i = 0;
Oled_Init();
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear();
Oled_Write_Cmd(0xB0);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i = 0;i < 16;i++){
Oled_Write_Data(w1[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(j1[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(h1[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(z1[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(l1[i]);
}
Oled_Write_Cmd(0xB1);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(i = 0;i < 16;i++){
Oled_Write_Data(w2[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(j2[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(h2[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(z2[i]);
}
for(i = 0;i < 16;i++){
Oled_Write_Data(l2[i]);
}
while(1);
}
12. OLED显示图片(257.103)
-
打开画图app,画简单的图像
-
保存为bmp格式(未经压缩,可轻松导入取模软件而无需解压(相比于会压缩的jpg))
-
打开“字模提取”app,“基本操作”、“打开图像图标”
-
“取模方式”、“C51 格式”
code unsigned char bmpImage[] = {....128*8....
};
void Oled_Show_Image(unsigned char *image){
unsigned char i;
unsigned int j;
for(i = 0;i < 8;i++){
Oled_Write_Cmd(0xB0 + i);
Oled_Write_Cmd(0x00);
Oled_Write_Cmd(0x10);
for(j = 128 * i;j < 128 *(i+1);j++){
Oled_Write_Data(image[j]);
}
}
}
void main(){
Oled_Init();
Oled_Write_Cmd(0x20);
Oled_Write_Cmd(0x02);
Oled_Clear();
Oled_Show_Image(bmpImage);
while(1);
}