- 前言
- 实验须知
- 概述
- 实验一 TMS320LF2407 DSP 实验开发系统及CC软件应用
- 实验二 常用指令操作实验
- 实验三 追灯式电路控制
- 实验四 按键计数器
- 实验五 键盘和 LED 发光二极管显示电路
- 实验六 模/数转换器 ADC 应用
- 实验七 串行外围接口 SPI 的应用
- 实验八 串行通信接口模块(SCI)
- 实验九 TMS320LF2407 与图形液晶显示模块接口及应用
- 实验十 I2C 串行日历时钟与 TMS320LF2407 的接口应用
- 附录一 DSP 器件仿真开发技术基础
- 附录二 TMS320LF2407 DSP 实验开发系统
- 附录三 TMS320LF2407 DSP 器件简介
- 附录四 XDS510 仿真开发系统的基本操作技术
- 附录五 程序开发平台 Code Composer
- 参考文献
实验十 I2C 串行日历时钟与 TMS320LF2407 的接口应用
一.实验说明
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论