实验八 IIC通信协议.docx
《实验八 IIC通信协议.docx》由会员分享,可在线阅读,更多相关《实验八 IIC通信协议.docx(20页珍藏版)》请在冰豆网上搜索。
实验八IIC通信协议
实验八I2C通信协议
一、实验目的:
1、培养学生阅读资料的能力;
2、加深学生对I2C总线通信协议的理解;
3、加强学生对模块化编程的理解;
二、实验环境:
1、硬件环境:
PC机一台、单片机实验板一块、母头串口交叉线、USB电源线;
2、软件环境:
keiluVision2集成开发环境;
STC-ISP下载上位机软件;
三、实验原理:
要学会I2C通信协议的编程,关键是要看懂并掌握其时序图,理解对I2C通信协议相关子程序的实验编写。
I2C通信协议的总线时序图如下所示:
I2C总线时序图
I2C相关子程序的详细介绍
1、起始信号:
SCL为高电平时,SDA由高电平向低电平跳变,开始传送数据。
2、结束信号:
SCL为高电平时,SDA由低电平向高电平跳变,结束传送数据。
起始信号和结束信号的时序图如下所示:
起始信号和结束信号的时序图
起始信号的流程如下:
1、SCL和SDA拉高,保持时间约为0.6us-4us;
2、拉低SDA,保持时间为约为0.6us-4us;
3、拉低时钟线
结束信号的流程如下:
1、SCL置高电平,SDA置低电平,保持时间约为0.6us-4us
2、SDA拉高,保持时间约为1.2-4us;
应答信号:
接收数据的IC在接收到8bit数据后,向发送数据的IC发出特定的低电平脉冲,表示已收到数据。
CPU向受控单元发出一个信号后,等待受控单元发出一个应答信号,CPU接收到应答信号后,根据实际情况作出是否继续传递信号的判断。
若未收到应答信号,由判断为受控单元出现故障。
应答信号的时序图如下所示:
应答时序图
发送时的应答信号
;**********应答信号**********
ACK:
SETBSDA;数据线置高
SETBSCL;时钟线置高
ACALLDELAY
JBSDA,$;等待数据线变低
ACALLDELAY
CLRSCL;时钟线置低
RET
注意:
这里如果数据线一直为高将进入死循环,所以一般我们都会在这做一个容错的处理。
具体的程序如下:
ACK:
MOVR4,#00H
SETBSDA
SETBSCL
LOP0:
JNBSDA,LOP
DJNZR4,LOP0;循环255次
LOP:
ACALLDEL
CLRSCL
RET
接收时的应答信号
ACK1:
CLRSDA;数据线置低
SETBSCL;时钟线置高
NOP
NOP
CLRSCL;时钟线置低
SETBSDA;数据线置高
RET
3、字节的发送和接收
写周期时序图
一字节数据发送子程序,流程如下:
图6-22发送子程序流程图
(2)一字节数据接收子程序,流程如下:
图6-23接收子程序流程图
7、写操作
(1)字节写
图6-24字节写时序图
流程如下:
图6-25字节写的流程图
(2)页写
图6-26页写时序图
页写流程如下:
7
图6-27页写流程图
8、读操作
(1)选择读
图6-28选择读时序图
图6-29NOACK时序图
(2)连续读
图6-30连续读时序图
四、实验原理图:
I2C总线电路图
五、实验例题:
例题一编写一程序,实现I2C的指定字节读写,用24C08来记录单片机复位或者开机的次数,并将复位或者开机的次数显示在数码管上。
程序分析本程序利用单片机复位时程序总是从0000H开始执行的特性。
用24C08的一个单元来存储开机的次数,程序一开始就将次数读出来,加上本次的开机,显示在数码管上。
再将加1之后的数据存入24c08的对应单元。
程序代码
;**************************************************************************
;****程序功能:
实现对24C08的字节读写,用24C08记录开机次数,显示在数码管上
;****程序编写:
李代勇
;****编写日期:
2007/2/04
;**************************************************************************
;**************************************************************************
;初始化数据设置
;**************************************************************************
SDAEQUP1.7;定义数据线为P1.7(实验板上已固定,不可更改)
SCLEQUP1.6;定义始终线为P1.6
I2C_AddrEQU10H;定义地址缓冲区,存储要读写24C08的单元地址
I2C_DataEQU12H;用于缓冲要读写的数据
D_BUF0EQU55H;数码管显示缓冲区(个位)
D_BUF1EQU56H;数码管显示缓冲区(十位)
D_BUF2EQU57H;数码管显示缓冲区(百位)
FLAGBIT00H;定义标志位,确定百位是否等于0,不等于0置1
;**************************************************************************
;程序段:
主程序
;**************************************************************************
ORG0000H
LJMPSTART
ORG0030H
START:
MOVSP,#70H
MOVI2C_Data,#00H
MOVI2C_Addr,#0FH
ACALLI2C_READ
MOVI2C_Data,A;读出数据
INCI2C_Data
MOVI2C_Addr,#0FH;更新数据
ACALLI2C_WRITE
LCALLDATAEDIT;数据加工
WAIT:
LCALLDISPLAY;显示数据
AJMPWAIT
;**************************************************************************
;函数名称:
DATAEDIT
;输入参数:
I2C_Data
;输出参数:
D_BUF0,D_BUF1,D_BUF2
;函数功能:
处理数据,确定每一位数码管要显示的数字,
;因为01,只要求显示1,10只要求显示10(而不是显示010)
;101要求显示101
;**************************************************************************
DATAEDIT:
MOVA,I2C_Data
MOVB,#100
DIVAB
JZL1;根据百位是否等于0确定百位的显示
MOVD_BUF2,A;百位不等于0,直接显示百位的数字
SETBFLAG;百位不等于0,标志位置1
AJMPNEX
L1:
MOVD_BUF2,#25;百位等于0,对百位赋一个超过段码个数的值
NEX:
MOVA,B;对十位数的处理
MOVB,#10
DIVAB;根据十位是否等于0确定十位的显示
JZL2
L3:
MOVD_BUF1,A;十位等于0,百位不等于0,显示十位的数字
AJMPNEX1
L2:
JBFLAG,L3;十位等于0,判断百位是否也为0
MOVD_BUF1,#22;百位、十位等于0,十位赋超过段码个数的值
NEX1:
MOVD_BUF0,B;个位的赋值
RET
;**************************************************************************
;函数名称:
DISPLAY
;输入参数:
D_BUF0,D_BUF1,D_BUF2
;输出参数:
无
;占用资源:
R6,R7,R0
;函数功能:
将D_BUF0,D_BUF1,D_BUF2显示在数码管上
;**************************************************************************
DISPLAY:
MOVR6,#3
MOVR7,#0FEH
MOVDPTR,#TAB
MOVR0,#D_BUF0
LOPP1:
MOVA,@R0
MOVCA,@A+DPTR
MOVP0,A
MOVP2,R7
LCALLDELAY5MS;动态扫描延时,消除余辉效应
INCR0
MOVA,R7
RLA
MOVR7,A
DJNZR6,LOPP1
NOP
RET
;**************************************************************************
;函数名称:
DELAY5MS
;输入参数:
无
;输出参数:
无
;占用资源:
60H,61H,62H
;函数功能:
延时5MS(24MHz晶振)
;**************************************************************************
DELAY5MS:
MOV60H,#1
DDD2:
MOV61H,#20
DDD1:
MOV62H,#248
DJNZ62H,$
DJNZ61H,DDD1
DJNZ60H,DDD2
RET
;**************************************************************************
;函数名称:
I2C_WRITE
;输入参数:
I2C_Addr,I2C_data
;输出参数:
无
;函数功能:
24C08字节写,将I2Cdata写入24C08的Address地址单元
;**************************************************************************
I2C_WRITE:
I2C_WRITE_A:
ACALLI2C_START
MOVA,#10100000B
LCALLI2C_SEND8BIT
LCALLI2C_ACK
JCI2C_WRITE_A
RS_ADDR:
MOVA,I2C_Addr
LCALLI2C_SEND8BIT
LCALLI2C_ACK
JCRS_ADDR
RS_DATA:
MOVA,I2C_Data
LCALLI2C_SEND8BIT
LCALLI2C_ACK
JCRS_DATA
LCALLI2C_STOP
LCALLDELAY10MS
RET
;**************************************************************************
;函数名称:
I2C_READ
;输入参数:
I2C_Addr
;输出参数:
I2C_Data
;函数功能:
24C08指定字节读,将24C08的Address地址单元的内容读到I2Cdata
;**************************************************************************
I2C_READ:
I2C_READ_A:
LCALLI2C_START
MOVA,#10100000B
LCALLI2C_SEND8BIT
LCALLI2C_ACK
JCI2C_READ_A
RS_ADDR2:
MOVA,I2C_Addr
LCALLI2C_SEND8BIT
LCALLI2C_ACK
JCRS_ADDR2
LCALLI2C_START
READ_ADDR:
MOVA,#10100001B
LCALLI2C_SEND8BIT
LCALLI2C_ACK
JCREAD_ADDR
ACALLI2C_RECEIVE8BIT
MOVI2C_Data,A
ACALLI2C_ACK
LCALLI2C_STOP
RET
;**************************************************************************
;函数名称:
I2C_START
;输入参数:
无
;输出参数:
无
;函数功能:
实现24C08启动时序的编写
;**************************************************************************
I2C_START:
SETBSCL
SETBSDA
NOP;TSU:
STA延时时间最少0.6us,另外还有一个值为4us
NOP
CLRSDA
NOP;THD:
STA延时时间最少0.6us,另外还有一个值为4us
NOP
CLRSCL
NOP
NOP
NOP
RET
;**************************************************************************
;函数名称:
I2C_STOP
;输入参数:
无
;输出参数:
无
;函数功能:
实现24C08停止时序的编写
;**************************************************************************I2C_STOP:
CLRSDA
SETBSCL
NOP;TSU:
STO延时时间最少0.6us,另外还有一个值为4us
NOP
SETBSDA
NOP;TBUF新的发送开始前的总线空闲时间,1.2us,还有一个为4.7us
NOP
NOP
RET
;**************************************************************************
;函数名称:
I2C_ACK
;输入参数:
无
;输出参数:
C
;函数功能:
实现24C08应答时序的编写
;**************************************************************************
I2C_ACK:
SETBSDA
SETBSCL
NOP
NOP
JBSDA,I2C_ACK0
CLRC
AJMPI2C_ACK_END
I2C_ACK0:
SETBC
I2C_ACK_END:
CLRSCL
RET
;**************************************************************************
;函数名称:
I2C_SEND8BIT
;输入参数:
A
;输出参数:
无
;函数功能:
24C08发送8位数据
;**************************************************************************
I2C_SEND8BIT:
MOVB,#08H
I2C_SEND8BIT_A:
RLCA
MOVSDA,C
SETBSCL
NOP
NOP
CLRSCL
DJNZB,I2C_SEND8BIT_A
RET
;**************************************************************************
;函数名称:
I2C_RECEIVE8BIT
;输入参数:
无
;输出参数:
A
;函数功能:
24C08接收8位数据
;**************************************************************************
I2C_RECEIVE8BIT:
MOVB,#08H
CLRA
SETBSDA
I2C_RECEIVE8IT_A:
SETBSCL
NOP
NOP
MOVC,SDA
RLCA
CLRSCL
DJNZB,I2C_RECEIVE8IT_A
RET
;**************************************************************************
;函数名称:
DELAY10MS
;输入参数:
无
;输出参数:
无
;函数功能:
实现10MS延时(24MHz晶振)
;**************************************************************************
DELAY10MS:
MOV40H,#2
D2:
MOV41H,#20
D1:
MOV42H,#248
DJNZ42H,$
DJNZ41H,D1
DJNZ40H,D2
RET
;**************************************************************************
;共阴级数码管段码数据表
;**************************************************************************
TAB:
DB3FH;0
DB06H;1
DB5BH;2
DB4FH;3
DB66H;4
DB6DH;5
DB7DH;6
DB07H;7
DB7FH;8
DB6FH;9
END
六、练习题:
1、上面的例题是针对指定字节读的,每个单元所存数据为0-255,请编写一段程序,要求能存储开机次数在0-65536次。
2、用24c08来存储几句话(内容自定),用矩阵式键盘来选择读取哪一句,并将读出的句子发送到串口调试助手显示出来。