单片机的I/O口模拟I2C数据总线传输方式

需要做的工作小结如下:
1、MCU的I2C采用IO口模拟实现;
2、MCU作为I2C主设备与定时芯片RX-8025SA建立通信;
3、实现定时闹钟、定时唤醒及睡眠的功能;
【单片机的I/O口模拟I2C数据总线传输方式】调试过程:
1、IO口模拟I2C的代码在网上是可以找得到的 。但是在具体的项目中 , 由于时钟的的不同在时序的控制上有区别 , 需要再调试 。
在具体项目中调试I2C时 , 需要注意一下几点:
1)I 2C设备的地址 , 有的描述方法是7位 , 有的描述方法是8位 。
注意只要代码和实际的设备地址相一致就好的 。关于7位地址的使用方法无非描述的是8位地址的高7位 , 因为最后一位是固定的 。(读的时候是1 , 写的时候是0) 。
2)I2C通信协议本身并没有规定在通信过程中 , 传输的字节数 。但是 , 有的设备可能只允许传输1个字节 , 或者两个字节 , 或者固定位数以内的字节 。具体的规则要看从设备的规格书 。
3)有的I2C设备只能写 , 不能读 , 这点也需要注意 。
4)2C从设备的通信速率 , 即数据传输速度 , 不同设备之间会有所不同 , 所以 , 要考虑兼容性的问题 。
5)有的设备可能是10位地址 , 写地址的时候 , 需要送两次设备地址 。
6)设备的程序编写尽量规范 。总线要释放的时候 , 最好把I/O设置为输入口 。有的程序编写的做法是 , 释放总线即把I/O设置为高 , 这样不好 。
7)时序的控制上 , 要符合设备的规格书的要求:
 
手头有示波器的话 , 这里介绍一个比较适用且效率较高的调试方法 。用示波器两路的探头直接接到I2C的数据线SDA和时钟线SCL上 , 上电后获取两路波形 , 再根据I2C通信协议读取通信数据 , 这样就可以看出是哪里的时序出的问题 。
2、I2C通信OK就需要根据RX-8025SA的规格书来实现项目所需要的定时功能啦 。
以实现闹钟功能为例说明:(请查看RX-8025SA的规格书)
1、8025芯片中有一个警报D功能:
警报D 功能指可从/INTA 引脚获得对[时+分]中断信号的功能 。
即当当前时间(星期+时+分)与Alarm_D 设定时间一致时 , /INTA 置L , 
DALE 位置1 。
2、将该/INTA连到MCU的RA5引脚上 , MCU通过判断RA5引脚的L or H , 
以及当前设备是否处于关机状态 , 当同时满足 RA5 = L 且 开机状态时 , 
MCU通知设备 , 设备再根据相关设置判断是否出闹钟提示 。
3、设定警报D时间的方法如下:
1)将本DALE bit 设置为0 使Alarm_D 无效;
注:这是为了避免警报设定中现行时刻与警报时刻恰巧一致时 , 输出/INTA=L 。
2)其次设定星期时分DAFG bit;
3)最后将DALE 设定为1 使警报D 功能有效;
4、开机初始化:将DAFG和WAFG 置0; 使警报W/警报D在开机瞬间当次无效 。
3、附上模拟I2C通信的代码(网上搜索一下):
void IIC_str ( void )
{
IIC_SCL=0;
IIC_SDA=1;
_nop_();
_nop_();
IIC_SCL=1;
nops();
IIC_SDA=0; // 开始
nops();
IIC_SCL=0;
return;
}
void IIC_stop ( void )
{
IIC_SCL=0;
IIC_SDA=0;
_nop_();
_nop_();
IIC_SCL=1;
nops();
IIC_SDA=1; // 结束
nops();
return;
}
void IIC_ack ( bit ack )
{
IIC_SCL=0;
_nop_();
_nop_();
if ( ack )
IIC_SDA=0; //应答
else
IIC_SDA=1; //非应答
nops();
IIC_SCL=1;
nops();
IIC_SCL=0;
}
bit IIC_send_byte ( uchar c )
{
uchar outtime;
uchar bitnum;
outtime=0;
for ( bitnum=0; bitnum<8; bitnum++ )
{
IIC_SCL=0;
if ( ( c
IIC_SDA=1;
else
IIC_SDA=0;
_nop_();
IIC_SCL=1;
nops();
nops();
IIC_SCL=0;
}
IIC_SDA=0;
IIC_SDA=1; // 准备接收应答信号
_nop_(); _nop_(); _nop_(); _nop_();
IIC_SCL=1; // 开始接受应答信号
while ( IIC_SDA ) // 超时判断
{
if ( ( outtime++ )>250 ) // 不能接收到应答信号 , 停止IIC通讯 , 返回0值报错
{
outtime=0;
IIC_stop();
return ( 0 ) ;
}
}
outtime=0;
IIC_SCL=0;
return ( 1 ); // 发送完毕 , 返回1值 , 通讯成功
}
uchar IIC_read_byte ( bit ack )
{
uchar retc;
uchar bitnum;
retc=0; //接收存储清0
IIC_SCL=0;
nops();
IIC_SDA=1;
for ( bitnum=0; bitnum<8; bitnum++ )
{
_nop_();
IIC_SCL=0;
IIC_SDA=1; //准备接受
nops();
IIC_SCL=1; //接收
nops();
retc<<=1;
if ( IIC_SDA ) //接收数据位判断
retc+=1;
}
IIC_SCL=0;
_nop_();
_nop_();
_nop_();
IIC_SDA=1;
IIC_ack( ack ); //应答信号
return retc;
}
void IIC_send_noadder ( uchar adder, uchar ddata )
{
bit ack;
IIC_str ();
ack=IIC_send_byte ( adder ); //发送地址
if ( !ack )
{ alarm=0;
return ; }
nops();
ack=IIC_send_byte ( ddata ); //发送数据
if ( !ack )
{ alarm=0;
return ; }
IIC_stop ();
return ;
}
void IIC_read_noadder ( uchar adder, uchar *buf, uchar num )
{
bit ack;
uchar i;
IIC_str ();
ack=IIC_send_byte ( adder ); //发送地址
if ( !ack )
{ alarm=0;
return ; }
nops();
for ( i=0; i
{
*( buf++ )=IIC_read_byte ( 1 ); //接收数据 存储倒*buf
}
IIC_stop ();
return ;
}
void IIC_send_adder ( uchar adder , uchar sub , uchar ddata )
{
bit ack;
IIC_str();
ack=IIC_send_byte ( adder ); //发送从机地址
if ( !ack )
{
alarm=0;
return ; }
ack=IIC_send_byte ( sub ); //发送从机子地址
if ( !ack )
{ alarm=0;
return ; }
ack=IIC_send_byte ( ddata ); //发送数据
if ( !ack )
{ alarm=0;
return ; }
IIC_stop ();
return ;
}
void IIC_read_adder ( uchar adder, uchar sub, uchar *buf, uchar num )
{
bit ack;
uchar i;
IIC_str ();
ack=IIC_send_byte ( adder ); //发送从机地址
if ( !ack )
{ alarm=0;
return ; }
ack=IIC_send_byte ( sub ); //发送从机子地址
if ( !ack )
{ alarm=0;
return ; }
for ( i=0; i
{
*( buf++ )=IIC_read_byte ( 1 ); //接收数据 存储倒*buf
}
IIC_stop ();
return ;
}

    推荐阅读