返回介绍

实验十 I2C 串行日历时钟与 TMS320LF2407 的接口应用

发布于 2023-05-14 20:35:30 字数 21652 浏览 0 评论 0 收藏 0

一.实验说明

I2C总线是由PHILIPS公司发明的一种高性能芯片间串行同步传输总线。与SPI接口不同,它仅仅需要两根信号线(串行数据线SDA和串行时钟线SCL),就实现了完善的双工同步数据传送,能够极其方便地构成多机系统和外围器件扩展系统。I2C总线采用了器件地址的硬件设置方法,通过软件寻址完全避免了器件的片选线寻址的弊端,从而使硬件系统具有更简单、更灵活的扩展方法。

I2C总线的串行通信过程与SPI或SCI相比,无论是从硬件结构、组网方式、软件编制方法,都有很大的不同。为了便于学习和应用I2C总线技术,现将它的特点介绍如下:

•二线制(SDA和SCL):I2C总线上的所有节点,包含主器件节点和外围器件节点,其同名端都分别挂接到两条信号SDA和SCL线上。

•I2C总线上的所有节点,其SDA和SCL引脚的输出驱动级电路,都是一只集电极开路的三极管或漏极开路的场效应管,以便通过接有上拉电阻的SDA和SCL线,链接成“线与逻辑关系”。

•采用的是互控通信方式且控制信号种类多。在一次通信过程中,通信双方频繁交换控制信息和状态信息。这些信息种类繁多,不仅包括常规的时钟、数据、地址,还包括启动信号、停止信号、重启动信号、方向信号、应答信号等。

•I2C总线具备时钟同步机制:通过这一机制,很容易对挂接到同一I2C总线上的、工作速度不同的各个器件进行同步控制。

•系统中所挂接的所有外围控制器件,一般均拥有一个专用的7位从器件地址码,以供主控器来寻址识别。

•系统中主控制器对于其它任何节点的寻址,不再像SPI那样需要链接专用片选线的方法,而是采用纯软件的寻址方法,从而减少了连线数目,并且固定为2条。

•所有具备I2C总线接口的外围器件,都具有自动应答功能,即产生应答信号的能力。

•所有具备I2C总线接口的外围器件,在片内有多个单元地址(例如串行EEPROM存储器),在对于若干个相邻单元的数据(亦称为数据串或数据块)进行连续访问时,具有地址自动加1逻辑。这样在通过I2C总线对于某一个器件读/写多个字节时,很容易实现自动操作。

•在I2C总线系统中,由于采用了时钟同步和总线仲裁机制,可以方便地构成多主机系统。各个主机之间没有优先次序之分,也无中心主机,任何一个主器件节点都可以作为整个系统的主控制器。多机竞争总线时,时钟同步和总线仲裁都由硬件自动完成。

•挂接到I2C总线上的各个节点,可以使用各自独立的、电压值不同的电源供电,但是必须共地。I2C总线上的各个节点可以热插拔,即可以在系统带电的状况下自由接入和拆除。

•兼容7位寻址和10位寻址两种寻址模式。

•具有广播式寻址能力:利用一个通用地址码同时呼叫挂接到I2C总线上的所有被控器件。

•I2C总线上允许同时挂接不同工作速率的具有I2C总线接口的器件。

•I2C总线系统中除了可以挂接带I2C总线硬件接口的单片机、外围器件外,还可以通过I2C总线并行扩展器、I2C总线/并行总线协议转换器或者软件模拟方式,挂接不带I2C总线接口的单片机、微处理器或数字信号处理器。

•I2C总线不仅可以广泛地用作电路板总线,还可以通过I2C总线双向驱动,进行不同系统之间的远程通信。

鉴于I2C总线的众多优越性,本实验用不带I2C总线接口的TMS320LF2407芯片,通过I2C总线/日历时钟PCF8583挂接,以实现串行通信功能。

二.实验目的

1. 理解PCF8583与TMS320LF2407硬件电路设计。

2. 理解TMS320LF2407与一片具有I2C总线接口的芯片之间建立通信的过程。

三.实验内容

1. 设计用软件模拟I2C总线时序,实现I2C串行日历时钟芯片PCF8583与TMS320LF2407的接口电路及其应用。

2. 在液晶显示器上显示出日历时钟。

四.实验硬件电路

五.实验参考程序清单

C语言

//I2C串行日历时钟与TMS320LF2407的接口及应用

// 源程序代码:

// 该程序实现对I2C总线日历时钟芯片PCF8583的读写操作

#include "register.h"

// 系统初始化子程序

void sysinit()

{

asm( " setc INTM "); // 关闭总中断

asm( " clrc SXM ") ; // 抑制符号扩展

asm( " clrc OVM ") ; // 累加器结果正常溢出

asm( " clrc CNF ") ; // B0被配置为数据空间

*SCSR1=0X81FE; // CLKIN=6M,CLKOUT=24M

*WDCR=0X0E8 ; // 不使能看门狗

*IMR=0X00; // 禁止所有中断

*IFR=0X0FFFF; // 清除所有的中断标志

WSGR=0x0FFFF; // 不使能所有的等待状态

}

// 输入输出口初始化子程序

void IOINIT()

{

*MCRB=*MCRB&0X0FFD7; // 配置IOPC3和IOPC5为一般的I/O口方式

*PCDATDIR=*PCDATDIR|0X02828; // 配置IOPC3和IOPC5为输出方式,且SCL=SDA=1

}

// 软件延时子程序

void delay()

{

int i;

for(i=0X07D;i--;) { i=i;}

}

// 启动I2C总线子程序

void START()

{

*PCDATDIR=*PCDATDIR|0X028; // SDA=SCL=1

delay( ); // 软件延时,以使时序匹配

*PCDATDIR=*PCDATDIR&0X0FFDF; // SDA=0

delay(); // 软件延时,以使时序匹配

*PCDATDIR=*PCDATDIR&0X0FFF7; // SCL=0

delay(); // 软件延时,以使时序匹配

}

// 发送字节子程序

void TRANSMIT(TRAN)

int TRAN;

{

int flag,sz; // 定义需要的局部变量

*PCDATDIR=*PCDATDIR&0X0FFF7; // SCL=0

delay(); // 软件延时,以使时序匹配

for(flag=0x0080;flag!=0x00;flag=flag/2) {

sz=TRAN&flag; // 屏蔽掉不需要的位

if(sz==0) *PCDATDIR=*PCDATDIR&0X0FFDF;// 如果相应的位为0,则SDA=0

else *PCDATDIR=*PCDATDIR|0X020; // 如果相应的位为1,则SDA=1

delay(); // 软件延时,以使时序匹配

*PCDATDIR=*PCDATDIR|0X08; // SCL=1

delay(); // 软件延时,以使时序匹配

*PCDATDIR=*PCDATDIR&0X0FFF7; // SCL=0

delay(); // 软件延时,以使时序匹配

}

}

// 从机(即PCF8583芯片)应答子程序。返回值为0时,代表操作成功;返回值为1时,代表操

// 作失败

int SLAVE_ACK()

{

int sz,k=0; // 定义所需要的局部变量

*PCDATDIR=*PCDATDIR|0X0020; // SDA=1

delay(); // 软件延时,以使时序匹配

*PCDATDIR=*PCDATDIR&0X0DFFF; // 设置IOPC5(SDA)为输入

delay(); // 软件延时,以使时序匹配

*PCDATDIR=*PCDATDIR|0X08; // SCL=1

delay(); // 软件延时,以使时序匹配

sz=*PCDATDIR&0X0020; // 检测数据位

if(sz==0X0020) k=1; // 如果数据位为1,则证明失败,则令k=1

else k=0; // 如果数据位为0,则证明成功,则保持k=0不变

*PCDATDIR=*PCDATDIR|0X2000; // 设置IOPC5(SDA)为输出

*PCDATDIR=*PCDATDIR&0X0FFD7; // SCL=SDA=0

return(k);

}

// I2C停止子程序

void STOP()

{

*PCDATDIR=*PCDATDIR&0X0FFDF; // SDA=0

delay();

*PCDATDIR=*PCDATDIR|0X0008; // SCL=1

delay( ); // 软件延时,以使时序匹配

*PCDATDIR=*PCDATDIR|0X0020; // SDA=1

}

// 字节写子程序,即向I2C器件写1个字节的数据,入口为地址BYTE_ADDR和需要写入的

// 字节

// 内容T_DATA。返回值为0时,代表操作成功;返回值为1时,代表操作失败

int BYTE_WR(BYTE_ADDR,T_DATA)

int BYTE_ADDR,T_DATA;

{

int k;

START(); // 启动I2C总线

TRANSMIT(0X0A0); // 送写控制字

k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) TRANSMIT(BYTE_ADDR); // 送出地址

if(k==0) k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) TRANSMIT(T_DATA); // 送出需要保存的数据

if(k==0) k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) STOP(); // 设置停止状态

return(k);

}

// 接收一个字节子程序,出口为接收到的数据R_DATA

int RECEIVE()

{

int R_DATA=0,sz,i;

*PCDATDIR=*PCDATDIR&0X0DFFF; // 设置IOPC5(SDA)为输入

*PCDATDIR=*PCDATDIR&0X0FFF7; // SCL=0

delay(); // 软件延时,以使时序匹配

for(i=0;i<8;i++) {

R_DATA=R_DATA<<1; // R_DATA左移一位

*PCDATDIR=*PCDATDIR|0X0008; // SCL=1

delay(); // 软件延时,以使时序匹配

sz=*PCDATDIR&0X0020; // 取得相应的数据位

if(sz==0) R_DATA=R_DATA&0XFFFE; // 如果数据位为0,则R_DATA最低位清0

else R_DATA=R_DATA|0x0001; // 如果数据位为1,则R_DATA最低位置1

*PCDATDIR=*PCDATDIR&0X0FFF7; // SCL=0

delay(); // 软件延时,以使时序匹配

}

*PCDATDIR=*PCDATDIR|0X2000; // 设置IOPC5(SDA)为输出

return(R_DATA); // 返回接收的字节

}

// 主机无应答信号子程序

void NO_ACK()

{

*PCDATDIR=*PCDATDIR|0X0008; // SCL=1

delay(); // 软件延时,以使时序匹配

*PCDATDIR=*PCDATDIR&0X0FFF7; // SCL=0

}

// 主机应答子程序

void MASTER_ACK()

{

*PCDATDIR=*PCDATDIR&0X0FFF7; // SCL=0

*PCDATDIR=*PCDATDIR&0X0FFDF; // SDA=0

*PCDATDIR=*PCDATDIR|0X0008; // SCL=1

delay(); // 软件延时,以使时序匹配

*PCDATDIR=*PCDATDIR&0X0FFF7; // SCL=0

}

// 字节读子程序,即从I2C器件读出1个字节的数据,入口为需要读出的地址BYTE_ADDR,

// 出口为读出的数据R_DATA,通过C语言的参数传递功能实现。返回值为0X0FFFF时,

// 表示操作失败;

// 否则操作成功

int BYTE_RD(int BYTE_ADDR)

{

int k,R_DATA;

START(); // 启动I2C总线

TRANSMIT(0XA0); // 送出写控制字,以写入地址字节

k=SLAVE_ACK( ); // 从机(即PCF8583芯片)应答

if(k==0) TRANSMIT(BYTE_ADDR);// 送出需要读出数据的地址

k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) {

START( ); // 启动I2C总线

TRANSMIT(0XA1);

} // 送出读控制字

k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) {

R_DATA=RECEIVE(); // 接收PCF8583发出的数据

NO_ACK(); // 主机不作应答

STOP(); // 设置停止状态

}

if(k==0) return(R_DATA); // 返回一个读出的数据

else return(0X0FFFF); // 如果整个读过程有误,则返回0X0FFFF

}

// 连续写子程序,入口为需要写的起始地址ADDR,存储需要写入数据的数组的首地址

// ARRY,需要写入的数据的个数N

int CON_WR(ADDR,ARRAY,N)

int ADDR,*ARRAY,N;

{

int k;

START(); // 启动I2C总线

TRANSMIT(0X0A0); // 送写控制字

k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) TRANSMIT(ADDR); // 送出要写数据的起始地址

if(k==0) k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) {

for(;N>0;N--,ARRAY++) {

TRANSMIT(*ARRAY); // 送出需要保存的数据,保存在数组ARRAY中

k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答,地址自动加1

if(k==1) break;

}

}

STOP(); // 设置停止状态

return(k);

}

// 连续读子程序,入口为需要读的起始地址ADDR,存储读出数据的数组首地址ARRY,需

// 要读出的数据的个数N

int CON_RD(ADDR,ARRAY,N)

int ADDR,*ARRAY,N;

{

int k,R_DATA;

START(); // 启动I2C总线

TRANSMIT(0XA0); // 送出写控制字,以写入地址字节

k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) TRANSMIT(ADDR); // 送出需要读出数据的地址

k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) {

START(); // 启动I2C总线

TRANSMIT(0XA1);

} // 送出读控制字

k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答

if(k==0) {

for(;N>1;N--,ARRAY++) {

R_DATA=RECEIVE(); // 接收PCF8583发出的数据

*ARRAY=R_DATA; // 读出的数据存入数组

MASTER_ACK(); // 主机应答,地址自动加1

}

R_DATA=RECEIVE(); // 接收PCF8583发出的数据

*ARRAY=R_DATA; // 读出的数据存入数组

NO_ACK(); // 主机不作应答

STOP(); // 设置停止状态

}

return(k); // k=0时表示操作成功,k=1时表示操作失败

}

// 主程序

main()

{

int k;

int R_DATA;

static int source[6]={0x0F,0x0E,0x0D,0x0C,0x0B,0x0A};

int result[6];

sysinit(); // 系统初始化

IOINIT(); // 输入输出口初始化

k=BYTE_WR(0x00,0x00); // 设置PCF8583的控制状态寄存器,其地址为0x00,值0x00

//代表的意义请参考相关资料,若k==0,则证明写入成功;若

// k==1,则证明写入失败

R_DATA=BYTE_RD(0x00); // 读出地址单元0X00的值,如果读出值为0X0FFFF,则表示

// 读出值有误

// 以下为日历时钟

k=BYTE_WR(0x02,0x48); //0100 1000 48 秒

// 设置PCF8583的控制状态寄存器,其地址为0x04,值0x48

//代表的意义请参考相关资料,若k==0,则证明写入成功;若

// k==1,则证明写入失败

R_DATA=BYTE_RD(0x02);

// 读出地址单元0X04的值,如果读出值为0X0FFFF,则表示

// 读出值有误

R_DATA=BYTE_RD(0x02); // 读出秒,要变

R_DATA=BYTE_RD(0x02);

R_DATA=BYTE_RD(0x02);

R_DATA=BYTE_RD(0x02);

R_DATA=BYTE_RD(0x02);

k=BYTE_WR(0x03,0x46); //0100 0110 46 分

// 设置PCF8583的控制状态寄存器,其地址为0x03,值0x46

//代表的意义请参考相关资料,若k==0,则证明写入成功;若,

// k==1则证明写入失败

R_DATA=BYTE_RD(0x03); //1101 1000 03 年18日

// 读出地址单元0X04的值,如果读出值为0X0FFFF,则表示

// 读出值有误

R_DATA=BYTE_RD(0x03); // 读出分 (可能变)

R_DATA=BYTE_RD(0x03);

k=BYTE_WR(0x04,0x15); //0001 0101 15 点

// 设置PCF8583的控制状态寄存器,其地址为0x04,值0x15

//代表的意义请参考相关资料,若k==0,则证明写入成功;若

// k==1,则证明写入失败

R_DATA=BYTE_RD(0x04); //1101 1000 03 年18日

// 读出地址单元0X04的值,如果读出值为0X0FFFF,则表示

// 读出值有误

R_DATA=BYTE_RD(0x04); // 读出小时

R_DATA=BYTE_RD(0x04);

k=BYTE_WR(0x05,0xD8); //1000 1001 周四9月

// 设置PCF8583的控制状态寄存器,其地址为0x05,值0x

// D8代表的意义请参考相关资料,若k==0,则证明写入成

//功;,若k==1则证明写入失败

R_DATA=BYTE_RD(0x05);

// 读出地址单元0X05的值,如果读出值为0X0FFFF,则表示

// 读出值有误

R_DATA=BYTE_RD(0x05); // 读出年,日期

R_DATA=BYTE_RD(0x05);

k=BYTE_WR(0x06,0x89);

// 设置PCF8583的控制状态寄存器,其地址为0x06,值0x89

//代表的意义请参考相关资料,若k==0,则证明写入成功;若

// k==1,则证明写入失败

R_DATA=BYTE_RD(0x06);

// 读出地址单元0X06的值,如果读出值为0X0FFFF,则表示

// 读出值有误

R_DATA=BYTE_RD(0x06); // 读出 周几,月份

R_DATA=BYTE_RD(0x06);

//以上日历时钟

k=CON_WR(0x30,source,6); // 从0x30地址开始连续写入6个数据

k=CON_RD(0x30,result,6); // 把写入的数据连续读出

}

// 直接返回中断服务子程序

void interrupt nothing()

{

return;

}

汇编语言

;12.2 I2C串行日历时钟与TMS320LF2407的接口及应用

TMP_DATA .usect ".data0",1 ;I2C临时数据寄存器

BYTE_ADDR .usect ".data0",1 ;存放字节地址

T_DATA .usect ".data0",1 ;发送数据缓冲器

R_DATA .usect ".data0",1 ;接收数据缓冲器

DP_USER equ 5 ;DP指向0280h~0300h

;~~~~~~~~~~~~~~~~~~~~~~~~~~~~ I2C 宏定义~~~~~~~~~~~~~~~~~~~~~~~~~~~~

DEVSELWR equ 0A0H ;I2C器件写操作命令

DEVSELRD equ 0A1H ;I2C器件读操作命令

DATAH equ 00020H ;数据线SDA=1 (IOPC5)

DATAL equ 0FFDFH ;SDA=0

CLOCKH equ 00008H ;时钟线SCL=1 (IOPC3)

CLOCKL equ 0FFF7H ;SCL=0

DATACLOCKH equ 00028H ;SDA=SCL=1

DATACLOCKL equ 0FFD7H ;SDA=SCL=0

DATAINPUT equ 0DFFFH ;PCDATDIR.13=0,即IOPC5引脚作为输入

DATAOUTPUT equ 02000H ;PCDATDIR.13=1,即IOPC5引脚作为输出

.include "F2407REGS.H"

.def _c_int0

;(1)主程序

.text

_c_int0

CALL SYSINIT ;系统初始化子程序

LDP #225

LACL MCRB

AND #0FFD7H

SACL MCRB ;配置IOPC3和IOPC5为一般的I/O口方式

LACL PCDATDIR

OR #02828H ;IOPC3和IOPC5为输出方式

SACL PCDATDIR ;SCL=SDA=1

LDP #DP_USER

LACL #00H,BYTE_ADDR

LACL #00H,T_DATA

CALL BYTE_WR ;设置PCF 8583的控制状态寄存器

;;;;;;;;;;以下增加读秒单元的值;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LDP #DP_USER

LACL #02H,BYTE_ADDR

LACL #48H,T_DATA

CALL BYTE_WR

LDP #DP_USER

LACL #02H,BYTE_ADDR

CALL BYTE_RD ;读取秒单元的值

LDP #DP_USER

LACL #02H,BYTE_ADDR

CALL BYTE_RD ;读取秒单元的值

;;;;;;;;;;以上增加读秒单元的值;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

LDP #DP_USER

LACL #03H,BYTE_ADDR

CALL BYTE_RD ;读取分单元的值

WAIT: NOP

B WAIT

;系统初始化程序

SYSINIT: SETC INTM

CLRC SXM

CLRC OVM

CLRC CNF ;B0 被配置为数据存储空间

LDP #0E0H

SPLK #81FEH,SCSR1 ;CLKIN=6 M,CLKOUT=24 M

SPLK #0E8H,WDCR ;Disable WDT

LDP #0

SPLK #0000H,IMR ;不使能中断

SPLK #0FFFFH,IFR ;清全部中断标志

RET

;(2)字节读写程序

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:字节写子程序,即向I2C器件写1个字节的数据

; 人口:BYTE_ADDR, T_DATA

; 调用到的子程序:START,TRANSMIT,SLAVE_ACK,STOP

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

BYTE_WR: CALL START ;启动I2C

LDP #DP_USER

LACL #DEVSELWR ;送写控制字 0A0H

CALL TRANSMIT

CALL SLAVE_ACK

LDP #DP_USER

LACL BYTE_ADDR ;送地址

CALL TRANSMIT

CALL SLAVE_ACK

LDP #DP_USER

LACL T_DATA ;要保存的数据

CALL TRANSMIT

CALL SLAVE_ACK

CALL STOP

RET

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:字节读子程序,即从I2C器件读出1个字节的数据

; 人口:BYTE_ADDR

; 出口:R_DATA

; 调用到的子程序:START,TRANSMIT,RECEIVE ,SLAVE_ACK,NO_ACK ,STOP

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

BYTE_RD: CALL START

LDP #DP_USER

LACL #DEVSELWR ;0A0H

CALL TRANSMIT

CALL SLAVE_ACK

LDP #DP_USER

LACL BYTE_ADDR

CALL TRANSMIT

CALL SLAVE_ACK

CALL START

LDP #DP_USER

LACL #DEVSELRD ;送读控制字 0A1H

CALL TRANSMIT

CALL SLAVE_ACK

CALL RECEIVE

LDP #DP_USER

SACL R_DATA

CALL NO_ACK

CALL STOP

RET

;(3)以下是模拟I2C时序子程序

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:发送字节子程序

; 人口:ACC

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

TRANSMIT: LDP #DP_USER

SACL TMP_DATA

LAR AR0,#08H

MAR *,AR3

LAR AR3,#0H

LDP #225

LACL PCDATDIR

AND #CLOCKL ;SCL=0 ;FFF7H

SACL PCDATDIR

CALL IIC_DLY

T_NEXT: LDP #DP_USER

BIT TMP_DATA,8

BCND T_NEXT1,TC

LDP #225

LACL PCDATDIR

AND #DATAL ;SDA=0 ;FFDFH

SACL PCDATDIR

B T_NEXT2

T_NEXT1: LDP #225

LACL PCDATDIR

OR #DATAH ;SDA=1 ,0020H

SACL PCDATDIR

T_NEXT2: CALL IIC_DLY

LACL PCDATDIR

OR #CLOCKH ;SCL=1 ;0008H

SACL PCDATDIR

CALL IIC_DLY

LACL PCDATDIR

AND #CLOCKL ;SCL=0 ;FFF7H

SACL PCDATDIR

LDP #DP_USER

LACL TMP_DATA

SFL

SACL TMP_DATA

ADRK #1

CMPR 00

BCND T_NEXT, NTC

RET

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:接收一个字节子程序

; 出口:ACC

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

RECEIVE: LDP #DP_USER

SPLK #00H,TMP_DATA

MAR *,AR0

LAR AR0,#08H

MAR *,AR3

LAR AR3,#0H

LDP #225

LACL PCDATDIR

AND #DATAINPUT

;SDA 设为输入 ;DFFFH ;PCDATDIR.13=0,即IOPC5引脚作为输入

SACL PCDATDIR ;FFF7H

CALL IIC_DLY

R_NEXT: LACL PCDATDIR

OR #CLOCKH ;SCL=1 ;0008H

SACL PCDATDIR

CALL IIC_DLY

LACL PCDATDIR

AND #DATAH ;从SDA引脚读数据 ;0020H

RPT #4 ;因为SDA=IOPC5,则应右移5位到ACC.0

SFR ;再把接收到的位加到TMP_DATA寄存器中

LDP #DP_USER

ADD TMP_DATA,1 ;(ACC+TMP_DATA)后再左移1位,空出ACC.0

;供下一次使用

SACL TMP_DATA

CALL IIC_DLY

LDP #225

LACL PCDATDIR

AND #CLOCKL ;SCL=0 ;FFF7H

SACL PCDATDIR

ADRK #1

CMPR 00

BCND R_NEXT, NTC

LDP #225

LACL PCDATDIR

OR #DATAOUTPUT

;02000H;PCDATDIR.13=1,即IOPC5引脚作为输出

SACL PCDATDIR

LDP #DP_USER

LACL TMP_DATA

RET

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:I2C 启动子程序

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

START: LDP #225

LACL PCDATDIR

OR #DATACLOCKH ;SDA=SCL=1 ;0028H

SACL PCDATDIR

RPT #3BH

NOP ;Delay 4.7US

LACL PCDATDIR

AND #DATAL ;FFDFH

SACL PCDATDIR ;SDA=0

RPT #32H

NOP ;Delay 4.0US

LACL PCDATDIR

AND #CLOCKL ;FFF7H

SACL PCDATDIR ;SCL=0

RET

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:I2C 停止子程序

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

;IIC_STOP :LDP #225

STOP: LDP #225

LACL PCDATDIR

OR #CLOCKH ;SCL=1 ;0008H

SACL PCDATDIR

RPT #3BH

NOP ;Delay 4.7US

LACL PCDATDIR

OR #DATAH ;SDA=1 ;0020H

SACL PCDATDIR

RET

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:从机应答信号

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

SLAVE_ACK: LDP #225

LACL PCDATDIR

OR #DATAH ;0020H

SACL PCDATDIR

RPT #32H

NOP

LACL PCDATDIR

OR #CLOCKH ;0008H

SACL PCDATDIR

RPT #32H

NOP

LACL PCDATDIR

AND #DATAINPUT SDA 输入;DFFFH

SACL PCDATDIR

RPT #32H

NOP

LACL PCDATDIR

AND #0008H

SUB #08H

BCND ERROR_ACK,EQ

LACL PCDATDIR

OR #DATAOUTPUT

;02000H;PCDATDIR.13=1,即IOPC5引脚作为输出

AND #DATACLOCKL ;FFD7H

SACL PCDATDIR

ERROR_ACK:

;…… ;添加错误处理程序

RET

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:主机应答信号

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

MASTER_ACK:LDP #225

LACL PCDATDIR

AND #DATAL ;FFDFH

SACL PCDATDIR

CALL NO_ACK

RET

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:主机无应答信号

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

NO_ACK: LDP #225

LACL PCDATDIR

OR #CLOCKH ;0008H

SACL PCDATDIR

RPT #32H

NOP

LACL PCDATDIR

AND #CLOCKL ;FFF7H

SACL PCDATDIR

RET

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

; 描述:为配合时序,延时10 μs子程序

; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

IIC_DLY: RPT #7DH

NOP

RET

END

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文