📄 i2c.c
字号:
//I2C串行日历时钟与TMS320LF2407的接口及应用
// 源程序代码:
// 该程序实现对I2C总线日历时钟芯片PCF8583的读写操作
#include "register.h"
int wr_data[6],rd_time[4],set_time[4],year_base=0x2003,rd_data[5];
// 系统初始化子程序
void sysinit()
{
asm( " setc INTM "); // 关闭总中断
asm( " clrc SXM ") ; // 抑制符号扩展
asm( " clrc OVM ") ; // 累加器结果正常溢出
asm( " clrc CNF ") ; // B0被配置为数据空间
SCSR1=0X81FE; // CLKIN=6M,CLKOUT=40M
WDCR=0X0E8 ; // 不使能看门狗
IMR=0X00; // 禁止所有中断
IFR=0X0FFFF; // 清除所有的中断标志
WSGR=0x0FFFF; // 不使能所有的等待状态
}
// 输入输出口初始化子程序
void IOINIT()
{
MCRC=MCRC&0X0F3FF; // 配置IOPF2和IOPF3为一般的I/O口方式
PFDATDIR=PFDATDIR|0X0C0C; // 配置IOPF2和IOPF3为输出方式,且SCL=SDA=1
}
// 软件延时子程序
void delay(unsigned int x)
{
int i;
for(i=0;i<x;i++) {i=i;}
}
// 启动I2C总线子程序
void START()
{
PFDATDIR=PFDATDIR|0X000C; // SDA=SCL=1
delay(72); // 软件延时,以使时序匹配
PFDATDIR=PFDATDIR&0X0FFF7; // SDA=0
delay(72); // 软件延时,以使时序匹配
PFDATDIR=PFDATDIR&0X0FFFB; // SCL=0
delay(24); // 软件延时,以使时序匹配
}
// 发送字节子程序
void TRANSMIT(TRAN)
int TRAN;
{
int flag,sz; // 定义需要的局部变量
PFDATDIR=PFDATDIR&0X0FFFB; // SCL=0
delay(72); // 软件延时,以使时序匹配
for(flag=0x0080;flag!=0x00;flag=flag>>1)
{
sz=TRAN&flag; // 屏蔽掉不需要的位
if(sz==0) PFDATDIR=PFDATDIR&0X0FFF7;// 如果相应的位为0,则SDA=0
else PFDATDIR=PFDATDIR|0X0008; // 如果相应的位为1,则SDA=1
delay(72); // 软件延时,以使时序匹配
PFDATDIR=PFDATDIR|0X0004; // SCL=1
delay(72); // 软件延时,以使时序匹配
PFDATDIR=PFDATDIR&0X0FFFB; // SCL=0
delay(24); // 软件延时,以使时序匹配
}
}
// 从机(即PCF8583芯片)应答子程序。返回值为0时,代表操作成功;返回值为1时,代表操
// 作失败
int SLAVE_ACK()
{
int sz,k=0; // 定义所需要的局部变量
PFDATDIR=PFDATDIR|0X0008; // SDA=1
delay(24); // 软件延时,以使时序匹配
PFDATDIR=PFDATDIR&0X0F7FF; // 设置IOPF3(SDA)为输入
delay(24); // 软件延时,以使时序匹配
PFDATDIR=PFDATDIR|0X0004; // SCL=1
delay(24); // 软件延时,以使时序匹配
sz=PFDATDIR&0X0008; // 检测数据位
if(sz==0X0008) k=1; // 如果数据位为1,则证明失败,则令k=1
else k=0; // 如果数据位为0,则证明成功,则保持k=0不变
PFDATDIR=PFDATDIR|0X0800; // 设置IOPF3(SDA)为输出
PFDATDIR=PFDATDIR&0X0FF03; // SCL=SDA=0
return(k);
}
// I2C停止子程序
void STOP()
{
PFDATDIR=PFDATDIR&0X0FFF7; // SDA=0
delay(24);
PFDATDIR=PFDATDIR|0X0004; // SCL=1
delay(24); // 软件延时,以使时序匹配
PFDATDIR=PFDATDIR|0X0008; // SDA=1
delay(24);
}
// 字节写子程序,即向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); // 送出地址
k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答
if(k==0) TRANSMIT(T_DATA); // 送出需要保存的数据
k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答
if(k==0) STOP(); // 设置停止状态
return(k);
}
// 接收一个字节子程序,出口为接收到的数据R_DATA
int RECEIVE()
{
int R_DATA=0,sz,i;
PFDATDIR=PFDATDIR&0X0F7FF; // 设置IOPF3(SDA)为输入
PFDATDIR=PFDATDIR&0X0FFFB; // SCL=0
delay(72); // 软件延时,以使时序匹配
for(i=0;i<8;i++) {
R_DATA=R_DATA<<1; // R_DATA左移一位
PFDATDIR=PFDATDIR|0X0004; // SCL=1
delay(72); // 软件延时,以使时序匹配
sz=PFDATDIR&0X0008; // 取得相应的数据位
if(sz==0) R_DATA=R_DATA&0XFFFE; // 如果数据位为0,则R_DATA最低位清0
else R_DATA=R_DATA|0x0001; // 如果数据位为1,则R_DATA最低位置1
PFDATDIR=PFDATDIR&0X0FFFB; // SCL=0
delay(24); // 软件延时,以使时序匹配
}
PFDATDIR=PFDATDIR|0X0800; // 设置IOPF3(SDA)为输出
return(R_DATA); // 返回接收的字节
}
// 主机无应答信号子程序
void NO_ACK()
{
PFDATDIR=PFDATDIR|0X0004; // SCL=1
delay(24); // 软件延时,以使时序匹配
PFDATDIR=PFDATDIR&0X0FFFB; // SCL=0
}
// 主机应答子程序
void MASTER_ACK()
{
PFDATDIR=PFDATDIR&0X0FFFB; // SCL=0
PFDATDIR=PFDATDIR&0X0FFF7; // SDA=0
PFDATDIR=PFDATDIR|0X0004; // SCL=1
delay(24); // 软件延时,以使时序匹配
PFDATDIR=PFDATDIR&0X0FFFB; // 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); // 送出要写数据的起始地址
k=SLAVE_ACK(); // 从机(即PCF8583芯片)应答
if(k==0)
{
for(;N>0;N--,ARRAY++)
{
TRANSMIT(*ARRAY&0x00FF); // 送出需要保存的数据的低八位,保存在数组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&0x00FF; // 读出的数据存入数组
MASTER_ACK(); // 主机应答,地址自动加1
}
R_DATA=RECEIVE(); // 接收PCF8583发出的数据
*ARRAY=R_DATA&0x00FF; // 读出的数据存入数组
NO_ACK(); // 主机不作应答
STOP(); // 设置停止状态
}
return(k); // k=0时表示操作成功,k=1时表示操作失败
}
//
void time_WR()
{
wr_data[0]=0x0; //ms
wr_data[1]=set_time[3]&0x00ff; //second
wr_data[2]=(set_time[3]&0xff00)>>8; //minute
wr_data[3]=set_time[2]&0x00ff; //hour;
wr_data[4]=((set_time[0]&0x03)<<6)|(set_time[1]&0x003f); //year/date
wr_data[5]=((set_time[2]&0x0700)>>3)|((set_time[1]&0x1f00)>>8); //week/month
CON_WR(0x01,wr_data,6);
}
//**********从8583中读时间子程序------------------**********/
void time_rd()
{
CON_RD(0x02,rd_data,5);
rd_time[0]=year_base+((rd_data[3]&0x00C0)>>6);//year
rd_time[1]=((rd_data[4]&0x001f)<<8)|(rd_data[3]&0x003f); //month,date
rd_time[2]=((rd_data[4]&0x00e0)<<3)|rd_data[2]; //week.hour
rd_time[3]=(rd_data[1]<<8)|rd_data[0]; //minute,second
}
// 主程序
main()
{
int k;
int R_DATA;
sysinit(); // 系统初始化
IOINIT(); // 输入输出口初始化
set_time[0]=0x2003;/*2003年*/
set_time[1]=0x1231;/*12月31日*/
set_time[2]=0x0523;/*星期五23时*/
set_time[3]=0x5930;/*59分30秒*/
time_WR();
// k=BYTE_WR(0x00,0x00); /* 设置PCF8583的控制状态寄存器,其地址为0x00,值0x00
//代表的意义请参考相关资料,若k==0,则证明写入成功;若 k==1,则证明写入失败 */
// R_DATA=BYTE_RD(0x00); /*读出地址单元0X00的值,如果读出值为0X0FFFF,则表示
// 读出值有误,其地址为0x05,值0xD8代表的意义请参考相关资料,若k==0,则证明写入成功;,若k==1则证明写入失败
// 读出地址单元0X05的值,如果读出值为0X0FFFF,则表示
// 读出值有误*/
while(1)
{
time_rd();
asm(" nop");
}
}
// 直接返回中断服务子程序
void interrupt nothing()
{
return;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -