分享 收藏 返回

单片机/MCU论坛

nt06 关注 私信

[问答] I2C通信求助

2012-8-21 12:24

这个代码是我网上搞到的,研究了很久 结果搭建好电路 郁闷了竟然不行
大家看看代码有没有问题 个人觉得是有的首先
他没开中断 就在等中断
其次实际中它并没有得到我想要的现象
代码贴上如下:

#include <iom16v.h>
/****************************
I2C 状态定义
MT 主方式传输 MR 主方式接受
***************************/
#define START                        0x08
#define RE_START                0x10
#define MT_SLA_ACK                0x18
#define MT_SLA_NOACK         0x20
#define MT_DATA_ACK                0x28
#define MT_DATA_NOACK        0x30
#define MR_SLA_ACK                0x40
#define MR_SLA_NOACK        0x48
#define MR_DATA_ACK                0x50
#define MR_DATA_NOACK        0x58
#define RD_DEVICE_ADDR 0xA1   //前4位器件固定,后三位看连线,最后1位是读写指令
#define WD_DEVICE_ADDR 0xA0
/*常用TWI操作(主模式写和读)*/
#define Start()                 (TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN))                //启动I2C
#define Stop()                 (TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN))                //停止I2C
#define Wait()                 {while(!(TWCR&(1<<TWINT)));}                                //等待中断发生
#define TestAck()         (TWSR&0xf8)                                                                //观察返回状态
#define SetAck                 (TWCR|=(1<<TWEA))                                                        //做出ACK应答
#define SetNoAck         (TWCR&=~(1<<TWEA))                                                        //做出Not Ack应答
#define Twi()                 (TWCR=(1<<TWINT)|(1<<TWEN))                                //启动I2C
#define Write8Bit(x) {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);}                //写数据到TWDR

/*延时子程序*/
void delay_ms(int time)
{
int i;
for(;time>0;time--)
  for(i=0;i<1000;i++);
}

/*串口初始化*/
void uart_init()
{
UCSRA=0x02; //异步正常模式
UCSRB=0x18; //允许发送接受中断和使能
UCSRC=0x06; //8位数据
UBRRH=0x00;
UBRRL=12;   //波特率位9600
}

/*********************************************
I2C总线写一个字节
返回0:写成功
返回1:写失败
**********************************************/
unsigned char I2C_Write(unsigned char Wdata,unsigned char RegAddress)
{
   Start();                                                //I2C启动
   Wait();
   if(TestAck()!=START)
          return 1;                                        //ACK
          
   Write8Bit(WD_DEVICE_ADDR);        //写I2C从器件地址和写方式
   Wait();
   if(TestAck()!=MT_SLA_ACK)
          return 1;                            //ACK
                                 
   Write8Bit(RegAddress);                //写器件相应寄存器地址
   Wait();
   if(TestAck()!=MT_DATA_ACK)
         return 1;                                    //ACK
         
   Write8Bit(Wdata);                                 //写数据到器件相应寄存器
   Wait();
   if(TestAck()!=MT_DATA_ACK)
          return 1;                                    //ACK       
          
   Stop();                                                  //I2C停止
   delay_ms(100);                                //延时
   return 0;
}  

/*********************************************
I2C总线读一个字节
返回0:读成功
返回1:读失败
**********************************************/
unsigned char I2C_Read(unsigned RegAddress)
{
   unsigned char temp;
   Start();//I2C启动
   Wait();
   if (TestAck()!=START)
           return 1;                                         //ACK          
          
   Write8Bit(WD_DEVICE_ADDR);        //写I2C从器件地址和写方式
   Wait();
   if (TestAck()!=MT_SLA_ACK)
           return 1;                                    //ACK
          
   Write8Bit(RegAddress);                //写器件相应寄存器地址
   Wait();
   if (TestAck()!=MT_DATA_ACK)
           return 1;
          
   Start();                                                      //I2C重新启动
   Wait();
   if (TestAck()!=RE_START)  
           return 1;
          
   Write8Bit(RD_DEVICE_ADDR);        //写I2C从器件地址和读方式
   Wait();
   if(TestAck()!=MR_SLA_ACK)  
           return 1;                                   //ACK
          
   Twi();                                            //启动主I2C读方式
   Wait();
   if(TestAck()!=MR_DATA_NOACK)
           return 1;                                        //ACK       
          
   temp=TWDR;        //读取I2C接收数据
   Stop();          //I2C停止
   return temp;
}

void main()
{
unsigned char i;
uart_init();          /*串口初始化*/
for(i=0;i<10;i++)
   I2C_Write(i,0x80+i);
delay_ms(1000);
while(1)
{
   for(i=0;i<10;i++)
   {
     while(!(UCSRA&(1<<UDRE))); /*等待接受准备好*/
         delay_ms(10);
     UDR=I2C_Read(0x80+i);
   }
}
}


回帖(8)

张三

2012-8-21 15:30:51
最好用示波器看一下,首先地址是否匹配,其次再看数据是否传输正确。

彭春

2012-8-21 22:09:12
程序太长了,电路没连错吧?贴上来看一下

nt06

2012-8-22 08:45:30
引用: lstcspring 发表于 2012-8-21 22:09
程序太长了,电路没连错吧?贴上来看一下

这段程序就两根线一根TX 一根 RX 没有什么值得看的

nt06

2012-8-22 18:07:44
引用: lovezjf234 发表于 2012-8-21 15:30
最好用示波器看一下,首先地址是否匹配,其次再看数据是否传输正确。

感谢提醒 继续煎熬

wxzhao

2012-8-22 22:50:25
路过学习

liaolicy

2012-9-20 19:22:54
这个调成功没啊 楼方 我也想试试 菜鸟一枚啊我

haiwen001

2012-9-21 20:32:55
可能需要仔细看一下你的I2C器件,不同的器件,ACK信号的定义有点区别。
比如我们用24系列的器件,ACK可能会这样写:
void ack()
{
     SDA = 1;
     delay();
     SCLK = 1;
     delay();
     SCLK = 0;
     delay();
     while(SDA!=0);
}
又比如,我们用pixelplus的图象芯片,则ACK需要写成这样:
void ACK()
{
    SDA=1;
    delay();
    SCLK=1;
    delay();
    while(SDA!=0);
    SCLK=0;
}
另外,I2C通信时,对应的上拉电阻跟速度是有很大关系的,一般来说,速度越高,上拉电阻阻值要用小
一点的电阻。

nt06

2012-9-25 10:12:17
引用: liaolicy 发表于 2012-9-20 19:22
这个调成功没啊 楼方 我也想试试 菜鸟一枚啊我

这个程序是对的 我用示波器看了一下有个端口是坏的

更多回帖