为什么我的IIC从设备无法发送应答信号
发布网友
发布时间:2022-05-10 11:23
我来回答
共1个回答
热心网友
时间:2023-10-08 20:01
只要IIC接口芯片未损坏,则主要问题就是SDA、SCL的时序问题。
以AT89C51+24C04驱动数码管为例:
(图片传不上)
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define NOP4() {_nop_();_nop_();_nop_();_nop_();}
sbit SCL = P1^0; //时钟线
sbit SDA = P1^1; //数据线
sbit clear_K=P3^7;//清0键
uchar code DSY_CODE[]= //共阳数码显示编码
{
0xc0,0xf9,0xa4,0xb0,0x99, //0~4
0x92,0x82,0xf8,0x80,0x90, //5~9
0xff
};
uchar DISP_Buffer[]={0,0,0}; //显示缓存
uchar Count = 0; //全局变量:计数值
void DelayMS(uint x) //ms延时子函数
{
uchar t; //循环变量
while(x--) //循环x次
{
for(t=120;t>0;t--); //嵌套循环120次
}
}
void Start() //开启总线子程序
{
SDA=1;//拉高数据线电平
SCL=1;//拉高时钟线电平
NOP4(); //延时4个机器周期
SDA=0;//拉低数据线电平
NOP4();//延时4个机器周期
SCL=0; //拉低时钟线电平
}
void Stop() //释放总线子程序
{
SDA=0;//拉低数据线电平
SCL=0;//拉低时钟线电平
NOP4(); //延时4个机器周期
SCL=1;//拉高时钟线电平
NOP4();//延时4个机器周期
SDA=1; //拉高数据线电平
}
void RACK() //应答
{
SDA=1;//拉高数据线电平
NOP4();//延时4个机器周期
SCL=1;//拉高时钟线电平
NOP4(); //延时4个机器周期
SCL=0;//拉低时钟线电平
}
void NO_ACK() //无应答
{
SDA=1;//拉高数据线电平
SCL=1;//拉高时钟线电平
NOP4();//延时4个机器周期
SCL=0;//拉低时钟线电平
SDA=0;//拉低数据线电平
}
void Write_A_Byte(uchar b) //写入一个字节数据
{
uchar i; //循环变量
for(i=0;i<8;i++) //循环8次
{
b<<=1; //数据左移1位,最高位移入进位位
SDA=CY;_nop_();//将进位位数送总线数据线
SCL=1;NOP4();//拉高时钟线电平,将数据写入
SCL=0;//拉低时钟线
}
RACK();//应答
}
uchar Receive_A_Byte()//接收一个字节数据
{
uchar i,d;//定义循环变量,读数变量
for(i=0;i<8;i++)//循环8次
{
SCL=1;//拉高时钟线电平
d<<=1;//读数左移1位
d|=SDA;//并入串行数据(从高位到低位逐位加入)
SCL=0;//拉低时钟线
}
return d;//返回数据d(8位并行数据)
}
void Write_Random_Address_Byte(uchar add,uchar dat) //写随机地址字节
{
Start();//初始化总线
Write_A_Byte(0xa0);//发送命令控制字:写入地址数据
Write_A_Byte(add);//写入地址码
Write_A_Byte(dat);//写入数据码
Stop();//传送结束,释放总线
DelayMS(10);//延时10ms
}
uchar Read_Current_Address_Data()//读数据流
{
uchar d;//定义数据变量
Start();//初始化总线
Write_A_Byte(0xa1);//发送命令控制字:读取数据
d=Receive_A_Byte();//8位数据接收
NO_ACK();//无应答
Stop();//读取数据结束
return d;//返回d值
}
uchar Random_Read(uchar addr)//随机读取数据
{
Start();//初始化总线
Write_A_Byte(0xa0);//写入读取控制字
Write_A_Byte(addr);//写入字节地址
Stop();//释放总线
return Read_Current_Address_Data();//返回数据流数值
}
void Convert_And_Display()//转换并显示
{
DISP_Buffer[2]=Count/100;//显示缓存百位数
DISP_Buffer[1]=Count%100/10;//显示缓存十位数
DISP_Buffer[0]=Count%100%10;//显示缓存个位数
if(DISP_Buffer[2]==0)//如果百位数为0
{
DISP_Buffer[2]=10;//不显示百位数
if(DISP_Buffer[1]==0)//如果十位数也为0
{
DISP_Buffer[1]=10;//十位数也不显示
}
}
P2 = 0x80;//送显示位码:第8位数码管
P0 = DSY_CODE[DISP_Buffer[0]];//送显示段码:显示数个位
DelayMS(5);//延时5ms
P2=0x00;//消影
P2 = 0x40;//送显示位码:第7位数码管
P0 = DSY_CODE[DISP_Buffer[1]];//送显示段码:显示数十位
DelayMS(5);//延时5ms
P2=0x00;//消影
P2 = 0x20;//送显示位码:第6位数码管
P0 = DSY_CODE[DISP_Buffer[2]];//送显示段码:显示数百位
DelayMS(5);//延时5ms
P2=0x00; //消影
}
void main()//主程序
{
Count = Random_Read(0x00);//读取存储数值(上电或复位)
Count++;//计数值自加1
Write_Random_Address_Byte(0x00,Count);//计数值写入存储器
while(1)//无限循环
{
if(clear_K==0)//如果清0键被按下
{
DelayMS(10);//延时10ms,消抖动
if(clear_K==0)//确认清0键被按下
{
Count=0;//计数值归0,
//Count=100;//计数值调整为5
}
while(clear_K==0);//等待键松开
Write_Random_Address_Byte(0x00,Count); //重写存储器
}
else//否则
Convert_And_Display();//调用转换与显示程序
}
}