amobbs.com 阿莫电子技术论坛

标题: ATmega16的TWI(I2C)读取MMA7455角加速度仪死活调不出来,求助 [打印本页]

作者: wlkobe    时间: 2012-6-15 13:06
标题: ATmega16的TWI(I2C)读取MMA7455角加速度仪死活调不出来,求助
我用ATmega16的TWI模块读取角加速度仪传感器MMA7455的数据,总是在开始信号发送等待应答位的时候工作就不正常了,不知道是什么原因。
原来用51单片机模拟I2C一点问题也没有,但是在AVR上用TWI模块就是不行(已经设置上拉电阻),求哪位大神帮我看下我的程序

这是I2C的头文件I2C.h

#ifndef _PMU_TEMPERATURE_H
#define _PMU_TEMPERATURE_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

//常用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        WriteByte(x)        {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);}        //写数据到TWDR
       
#define TWI_ACT ((1<<TWINT)|(1<<TWEN)|(1<<TWIE)|(1<<TWEA))
       
unsigned char f_I2cWrite(unsigned char Wdata,unsigned char RegAddress);                //I2C写

signed int f_I2cRead(unsigned char RegAddress);

#endif


这是I2C.c文件

#include <avr/io.h>
#include "I2C.h"

#define uchar unsigned char
#define uint unsigned int

#define WD_DEVICE_ADDR        0x1D
#define RD_DEVICE_ADDR        0x1D

uchar Delay_ms(uint x)
{
        uint i,j;
        for(i=0;i<x;i++)
    for(j=0;j<800;j++);
}

uchar f_I2cWrite(uchar Wdata,uchar RegAddress)                //I2C总线写一字节  返回1:写成功  返回0:写失败
{
        Start();                                                                                //I2C启动
        Wait();
        if(TestAck()!=START)        return 12;                                //ACK
        //uint t=WD_DEVICE_ADDR<<1;
        WriteByte(WD_DEVICE_ADDR);                                        //写入I2C从器件地址和写方式
        Wait();
        if(TestAck()!=MT_SLA_ACK)        return 2;                        //ACK
        WriteByte(RegAddress);                                                        //写相应寄存器地址
        Wait();
        if(TestAck()!=MT_DATA_ACK)        return 3;
        WriteByte(Wdata);                                                                //写数据
        Wait();
        if(TestAck()!=MT_SLA_ACK)        return 4;                        //ACK
        Stop();                                                                                        //I2C停止
        Delay_ms(10);
        return 0;
}

signed int f_I2cRead(uchar RegAddress)                                //I2C总线读一个字节   返回0:失败   返回非0:成功
{
        signed int siTemp;
        Start();                                                                                //I2C启动
        Wait();       
        if(TestAck()!=START)                return 1;                        //ACK
        uint t=WD_DEVICE_ADDR;
        WriteByte(WD_DEVICE_ADDR);                                        //写入I2C从器件地址和写方式
        Wait();
        if(TestAck()!=MT_SLA_ACK)        return 2;                        //ACK
        WriteByte(RegAddress+1);                                                        //写ROM地址
        Wait();
        if(TestAck()!=MT_DATA_ACK)        return 3;
        Start();                                                                                //I2C重新启动
        Wait();
        if(TestAck()!=RE_START)                return 4;
        t=(RD_DEVICE_ADDR)+1;
        WriteByte(RD_DEVICE_ADDR);                        //写I2C从器件地址和读方式
        Wait();
        if(TestAck()!=MR_SLA_ACK)        return 5;                        //ACK
       
        if(RegAddress==0x00)
        {
                Twi();                                                                                //启动主I2C读方式
                Wait();
                if(TestAck()!=MR_DATA_NOACK)        return 0;        //ACK
                siTemp=TWDR;                                                                //读取I2C接收数据
                siTemp=siTemp<<8;
               
                Twi();                                                                                //再次启动主I2C读方式
                Wait();
                if(TestAck()!=MR_DATA_NOACK)        return 0;        //ACK
                siTemp+=TWDR;                                                                //读取I2C接收数据
               
                SetAck();
                Stop();                                                                                //I2C停止
                siTemp=siTemp>>6;
                siTemp=siTemp/4;
        }
        else
        {
                Twi();                                                                                //启动主I2C读方式
                Wait();
                if(TestAck()!=MR_DATA_NOACK)        return 0;        //ACK
                siTemp=TWDR;                                                                //读取I2C接收数据
                //siTemp=siTemp/4;
                SetAck();
                Stop();                                                                                //I2C停止
        }
        return siTemp;                                                                        //返回值
}


这是主函数

int main()
{
        InitPort();    //DDRC=0x02;PORTC=0x03;
        InitI2C();
        float n;
        f_I2cWrite(0x16,0x05);       
        TurnOff();
        while(1)
        {
               
                n=f_I2cRead(0x07);
                Display(n);
        }
}

程序结果:显示的值一直都是1(在f_I2cRead()函数中设置第一个应答位如果没有接受到return 1;)
作者: BBC    时间: 2012-6-17 02:44
估计你只是设置了IO口的内部上拉电阻吧?用AVR的TWI一定要外接上拉电阻!!我以前曾在这上面浪费了一个星期时间呐~~
作者: wlkobe    时间: 2012-6-17 22:09
BBC 发表于 2012-6-17 02:44
估计你只是设置了IO口的内部上拉电阻吧?用AVR的TWI一定要外接上拉电阻!!我以前曾在这上面浪费了 ...

可是我后来是接了外部上拉电阻的啊……而且当时我用51调的时候没有设置上拉电阻照样可以用。AVR的时候不管是模拟还是模块I2C都没用。
你那儿有这个芯片能用的程序么?能让我借鉴一下么?谢了哦!!!
作者: BBC    时间: 2012-6-18 12:42
wlkobe 发表于 2012-6-17 22:09
可是我后来是接了外部上拉电阻的啊……而且当时我用51调的时候没有设置上拉电阻照样可以用。AVR的时候不 ...
  1. //Atmega8 @ 8MHz
  2. //ICCAVR v7

  3. #include "iom8v.h"
  4. #include <macros.h>

  5. #define Start() ( TWCR = (1<<TWINT) | (1<<TWSTA) | (1<<TWEN) )        //产生START信号
  6. #define Stop()  ( TWCR = (1<<TWINT) | (1<<TWSTO) | (1<<TWEN) )        //产生STOP信号  
  7. #define tea5767_add_w 0xC0
  8. #define tea5767_add_r 0xC1

  9. unsigned int freq = 10800;
  10. unsigned char rx[5];

  11. unsigned int cal_pll( unsigned long temp )
  12. {  
  13.   unsigned int ans;
  14.   ans = (unsigned int)(((temp*10-225)*4000)/32768);
  15.   return ans;
  16. }

  17. void TWI_write( unsigned char twi_d )
  18. {
  19.   TWDR = ( twi_d );
  20.   TWCR = ( 1<<TWINT ) | ( 1<<TWEN );
  21. }

  22. void TWI_init( void )
  23. {
  24.   TWCR=0X00; //关闭TWI总线
  25.   TWBR=0x12; //设置传输比特率  
  26.   TWSR=0x03; //设置TWI总线的速度,频率不能大于400K,否则5767不工作
  27.   TWCR=0x04; //使能TWI总线
  28. }

  29. unsigned char TWI_read( void )
  30. {
  31.   unsigned char temp;
  32.   TWCR |= 0x04;
  33.   while(!(TWCR&(1<<TWINT)));
  34.   temp = TWDR;
  35.   return temp;
  36. }

  37. void read_5767( void )
  38. {
  39.   unsigned char k;
  40.   Start();
  41.   while(!(TWCR&(1<<TWINT)));
  42.   TWI_write(tea5767_add_r);
  43.   while(!(TWCR&(1<<TWINT)));
  44.   for(k=0;k<5;k++)
  45.   {
  46.     rx[k] = TWI_read();
  47.   }
  48. }

  49. void write_5767( unsigned char tx0, unsigned char tx1, unsigned char tx2, unsigned char tx3, unsigned char tx4 )
  50. {
  51.   Start();
  52.   while(!(TWCR&(1<<TWINT)));
  53.   TWI_write( tea5767_add_w );
  54.   while(!(TWCR&(1<<TWINT)));
  55.   TWI_write(tx0);
  56.   while(!(TWCR&(1<<TWINT)));
  57.   TWI_write(tx1);
  58.   while(!(TWCR&(1<<TWINT)));
  59.   TWI_write(tx2);
  60.   while(!(TWCR&(1<<TWINT)));
  61.   TWI_write(tx3);
  62.   while(!(TWCR&(1<<TWINT)));
  63.   TWI_write(tx4);
  64.   while(!(TWCR&(1<<TWINT)));
  65.   Stop();
  66. }  

  67. void init_5767( void )
  68. {
  69.   unsigned int pll;
  70.   pll = cal_pll( freq );
  71.   write_5767( pll/256|0x80, pll%256, 0x09, 0x90, 0x01 );       //mute
  72.   //write_5767( pll/256&(~0x80), pll%256, 0x09, 0x90, 0x01 );  //unmute
  73. }
复制代码
这里有个TEA5767的IIC,希望有用......
作者: wlkobe    时间: 2012-6-18 22:18
BBC 发表于 2012-6-18 12:42
这里有个TEA5767的IIC,希望有用......

后天考试,考完试好好研究研究,谢啦哈!!!
作者: wlkobe    时间: 2012-6-18 22:24
BBC 发表于 2012-6-18 12:42
这里有个TEA5767的IIC,希望有用......

你好,我还想问下你读取数据的时候调用了中断么?
作者: rei1984    时间: 2012-6-18 22:27
lz 给你个提示,  利用icc 产生一个 twi程序在试试,一般都是可以的

作者: BBC    时间: 2012-6-19 00:21
wlkobe 发表于 2012-6-18 22:24
你好,我还想问下你读取数据的时候调用了中断么?

没有用中断...不过在等待的时候不断查询中断标志:while(!(TWCR&(1<<TWINT)));
作者: wlkobe    时间: 2012-6-21 21:55
BBC 发表于 2012-6-19 00:21
没有用中断...不过在等待的时候不断查询中断标志:while(!(TWCR&(1

哎?我用了下你的程序,发现我程序里像这种if(TestAck()!=START)判断应答位的语句只要有了,就有问题,无语哎……
现在写数据没什么问题了,可是读数据的时候貌似还是不行额……你平时用的时候功能一切正常的么?
作者: wlkobe    时间: 2012-6-21 21:56
rei1984 发表于 2012-6-18 22:27
lz 给你个提示,  利用icc 产生一个 twi程序在试试,一般都是可以的

这个可以自动生成的么?
作者: BBC    时间: 2012-6-21 22:27
本帖最后由 BBC 于 2012-6-21 22:33 编辑
wlkobe 发表于 2012-6-21 21:55
哎?我用了下你的程序,发现我程序里像这种if(TestAck()!=START)判断应答位的语句只要有了,就有问题,无 ...


我估计是IIC操作顺序问题......

哈哈,不好意思,刚才看你程序的注释,搞错了......操作顺序如下:

1. 发送start指令
2. 查询start命令是否发送成功(非必要)
3. 写从机地址
4. 等待从机ACK
......

希望有用......

附上截图:

[attach]26793[/attach]

上图图例:
[attach]26794[/attach]
作者: wlkobe    时间: 2012-6-21 22:49
BBC 发表于 2012-6-21 22:27
我估计是IIC操作顺序问题......

哈哈,不好意思,刚才看你程序的注释,搞错了......操作顺序如下:

其实我的等待Wait()是{while(!(TWCR&(1<<TWINT)));}和你的程序是一样的额……
啊哦,我们要关门了,明天再调,谢了哈!明天再讨论
作者: BBC    时间: 2012-6-21 22:56
wlkobe 发表于 2012-6-21 22:49
其实我的等待Wait()是{while(!(TWCR&(1

哈哈,是啊,但是你后一句的注释是ACK,刚刚被这个给骗了,还以为你的操作顺序有问题......
wait()是等待IIC操作完成,if(TestAck()!=START)是查询start命令是否发出......这些都是芯片内部的查询操作啊,怎么会卡住呢......
作者: wlkobe    时间: 2012-6-22 12:58
BBC 发表于 2012-6-21 22:56
哈哈,是啊,但是你后一句的注释是ACK,刚刚被这个给骗了,还以为你的操作顺序有问题......
wait ...

所以很奇怪啊,我后来发IF语句全都去了,然后在示波器里看波形,start,ack,stop这些都没有问题
作者: wlkobe    时间: 2012-6-22 15:39
BBC 发表于 2012-6-21 22:56
哈哈,是啊,但是你后一句的注释是ACK,刚刚被这个给骗了,还以为你的操作顺序有问题......
wait ...

你好,我想问下TWI是TWINT为1时工作还是为0时工作啊,我看的有点糊涂了……
作者: wlkobe    时间: 2012-6-22 17:19
BBC 发表于 2012-6-21 22:56
哈哈,是啊,但是你后一句的注释是ACK,刚刚被这个给骗了,还以为你的操作顺序有问题......
wait ...

你好,我想问下你当时IO口是怎么设置的啊?
作者: BBC    时间: 2012-6-22 18:07
wlkobe 发表于 2012-6-22 17:19
你好,我想问下你当时IO口是怎么设置的啊?

当TWINT为0的时候,表示IIC正在工作。

当IIC完成当前工作后(或者收到数据等等),TWINT变为1(置位)。

其实怪就怪在下面这里 :

在TWINT变为1(置位)之后,程序处理完当前数据,并且需要IIC做下一步工作的时候,要对TWINT位写“1”来对其清零......


IO设置的话,我的SCL设为输出,SDA设为输入。
作者: wlkobe    时间: 2012-6-22 18:47
怪就怪在这啊,如果TWINT在工作完成后置为while(!(TWCR&(1<<TWINT)));的结果不久成了继续循环了么,这样的话和程序的本意不是相反了么?
话说我的TWI快调出来了,嘿嘿,不过还是接收不到数据……
作者: wlkobe    时间: 2012-6-22 18:47
BBC 发表于 2012-6-22 18:07
当TWINT为0的时候,表示IIC正在工作。

当IIC完成当前工作后(或者收到数据等等),TWINT变为1(置位)。 ...


怪就怪在这啊,如果TWINT在工作完成后置为while(!(TWCR&(1<<TWINT)));的结果不久成了继续循环了么,这样的话和程序的本意不是相反了么?
话说我的TWI快调出来了,嘿嘿,不过还是接收不到数据………
作者: BBC    时间: 2012-6-22 19:52
wlkobe 发表于 2012-6-22 18:47
怪就怪在这啊,如果TWINT在工作完成后置为while(!(TWCR&(1

  也不是啊,如果IIC工作完成了,TWINT就为1,直到下一次对IIC的操作。

所以,如果IIC工作未完成,( TWCR&(1<<TWINT) ) 就为0,!(TWCR&(1<<TWINT)) 为真,while(!(TWCR&(1<<TWINT))) ; 会一直循环直到IIC工作完成后。

如果工作完成了,( TWCR&(1<<TWINT) )为1,!(TWCR&(1<<TWINT)) 为假,while(!(TWCR&(1<<TWINT))) ; 这句判断一下之后直接跳过,不会循环啵...
作者: xlwq    时间: 2012-6-22 20:44
前段时间调过ATmega16的IIC,中断方式,具体内容已经忘了,悲剧,不过挺好用的!!
作者: wlkobe    时间: 2012-6-22 20:47
xlwq 发表于 2012-6-22 20:44
前段时间调过ATmega16的IIC,中断方式,具体内容已经忘了,悲剧,不过挺好用的!! ...

想问一下中断内部写的大概是什么方面的程序呢?
作者: xlwq    时间: 2012-6-22 20:58
wlkobe 发表于 2012-6-22 20:47
想问一下中断内部写的大概是什么方面的程序呢?

每个应答信号后,对应的状态是不一样的,并会触发一次中断,可以读取当前状态寄存器来确定,中断里面用状态机的方式来进行状态判断,然后处理数据!
作者: wlkobe    时间: 2012-6-22 22:23
xlwq 发表于 2012-6-22 20:58
每个应答信号后,对应的状态是不一样的,并会触发一次中断,可以读取当前状态寄存器来确定,中断里面用状 ...

哦,我貌似今天下午见过类似的程序,试试看,谢了哈!
作者: xlwq    时间: 2012-6-22 22:47
wlkobe 发表于 2012-6-22 22:23
哦,我貌似今天下午见过类似的程序,试试看,谢了哈!

嗯!!这个方式还是很稳定的!比较好用。
作者: wlkobe    时间: 2012-7-15 21:00
xlwq 发表于 2012-6-22 22:47
嗯!!这个方式还是很稳定的!比较好用。

你好,我这里有个问题想让你帮我看一下
我是用的是AVR Stdio 5 ,在使用定时中断时总是出现这个错误:ignoring #pragma interrupt_handler PWM
不知道到底是什么原因呢?应该如何解决,谢谢
作者: xlwq    时间: 2012-7-15 21:27
AVR studio5 用的是GCC编译器!你的中断函数是
SIGNAL(SIG_INTERRUPT0) //外部中断0
{

}
这种格式吗?
作者: wlkobe    时间: 2012-7-15 21:33
我用了那种格式可是错误更多了

警告        1        statement with no effect        E:\AVR\Programs\ROBOTS\ROBOTS\ROBOTS\ROBOTS.c        11        2        ROBOTS

警告        2        large integer implicitly truncated to unsigned type        E:\AVR\Programs\ROBOTS\ROBOTS\ROBOTS\ROBOTS.c        26        2        ROBOTS

错误        3        expected identifier or '(' before numeric constant        E:\AVR\Programs\ROBOTS\ROBOTS\ROBOTS\ROBOTS.c        32        1        ROBOTS

错误        4        expected identifier or '(' before numeric constant        E:\AVR\Programs\ROBOTS\ROBOTS\ROBOTS\ROBOTS.c        32        1        ROBOTS

作者: wlkobe    时间: 2012-7-15 21:51
BBC 发表于 2012-6-22 18:07
当TWINT为0的时候,表示IIC正在工作。

当IIC完成当前工作后(或者收到数据等等),TWINT变为1(置位)。 ...

你好,我这里有个问题想让你帮我看一下
我是用的是AVR Stdio 5 ,在使用定时中断时总是出现这个错误:ignoring #pragma interrupt_handler PWM
不知道到底是什么原因呢?应该如何解决,谢谢
作者: BBC    时间: 2012-7-19 20:43
wlkobe 发表于 2012-7-15 21:51
你好,我这里有个问题想让你帮我看一下
我是用的是AVR Stdio 5 ,在使用定时中断时总是出现这个错误:ign ...

请把代码贴出来吧...估计是程序里的中断向量名和头文件里宏定义的有出入
作者: wlkobe    时间: 2012-7-20 17:08
BBC 发表于 2012-7-19 20:43
请把代码贴出来吧...估计是程序里的中断向量名和头文件里宏定义的有出入 ...

问题已经解决了,嘿嘿。是因为Studio是GCC的,而program这种语句是ICC才有的,所以自然就编译不了了

对了,你原来用AVR的定时中断模拟过PWM么?模拟出来的频率跟预设的误差有多少啊?我的误差貌似特别大的说不知道是原本就这样还是其他原因

这是我的程序:
void InitTimer()
{
        CLI();
        TCCR1A=0x00;
        TCCR1B=0x01;
        TCNT1H=0xFF;
        TCNT1L=0xFF;
        TIMSK|=(1<<TOIE1);
        SEI();
}

SIGNAL(TIMER1_OVF_vect)       
{
        TCNT1H=0xFF;
        TCNT1L=0xFF;
        PORTA=~PORTA;
}

所用的是8M的晶振,但是出来的频率是108KHz……
作者: BBC    时间: 2012-7-21 00:29
wlkobe 发表于 2012-7-20 17:08
问题已经解决了,嘿嘿。是因为Studio是GCC的,而program这种语句是ICC才有的,所以自然就编译不了了

对 ...

呵呵,这个问题我也遇到过,原因是IO口也有它自己的工作时钟,所以这样模拟的频率并不一定就是定时器的频率~
作者: 新月弯刀    时间: 2012-9-10 10:37
谁有计算8451角度的公式啊
作者: seewolf    时间: 2012-9-10 10:57
这是我写的I2C通信的头文件,你可以先检查下I2C是不是有问题。我用它调过ADXL345,所以这个头文件保证没错。
  1. #ifndef __I2C_h
  2. #define __I2C_h
  3. #include"Delay.h"
  4. #define uint unsigned int
  5. #define uchar unsigned char
  6. #define Baud_set   25   //TWI波特率设置
  7. #define P_value    0X00  //预分频值
  8. //TWI读写操作公共步骤
  9. #define ST_FAIL    0 //出错状态
  10. #define ST_START   1 //START状态检查
  11. #define ST_SLAW    2 //SLAW状态检查
  12. #define ST_WADDR   3 //ADDR状态检查
  13. //TWI读操作步骤
  14. #define ST_RESTART   4 //RESTART状态检查
  15. #define ST_SLAR    5 //SLAR状态检查
  16. #define ST_RDATA   6 //读取数据状态检查,循环n字节
  17. //TWI写操作步骤
  18. #define ST_WDATA   7 //写数据状态检查,循环n字节

  19. #define FAIL_MAX   20 //重试次数最大值
  20. /**********************I2C状态定义*************************/
  21. /************************主机发送状态码********************/
  22. #define TW_START    0x08 //START已发送
  23. #define TW_REP_START   0x10 //重复START已发送
  24. #define TW_MT_SLA_ACK   0x18 //SLA+W 已发送收到ACK
  25. #define TW_MT_SLA_NACK   0x20 //SLA+W 已发送接收到NOT ACK
  26. #define TW_MT_DATA_ACK   0x28 //数据已发送接收到ACK
  27. #define TW_MT_DATA_NACK   0x30 //数据已发送接收到NOT ACK
  28. #define TW_MT_ARB_LOST   0x38 //SLA+W 或数据的仲裁失败
  29. /*************************主机接收状态码*****************/
  30. #define TW_START    0x08 //START已发送
  31. #define TW_REP_START   0x10 //重复START已发送
  32. #define TW_MR_ARB_LOST   0x38 //SLA+R 或NOT ACK 的仲裁失败
  33. #define TW_MR_SLA_ACK   0x40 //SLA+R 已发送接收到ACK
  34. #define TW_MR_SLA_NACK   0x48 //SLA+R 已发送接收到NOT ACK
  35. #define TW_MR_DATA_ACK   0x50 //接收到数据ACK 已返回
  36. #define TW_MR_DATA_NACK   0x58 //接收到数据NOT ACK已返回
  37. /************************常用TWI操作***************************/
  38. #define Start()                        (TWCR=(1<<TWINT)|(1<<TWSTA)|(1<<TWEN))                //启动I2C
  39. #define Stop()                        (TWCR=(1<<TWINT)|(1<<TWSTO)|(1<<TWEN))                //停止I2C
  40. #define Wait()                        {while(!(TWCR&(1<<TWINT)));}                                //等待中断发生
  41. #define TestAck()                (TWSR&0xf8)                                                                        //观察返回状态
  42. #define SetAck                        (TWCR|=(1<<TWEA))                                                        //做出ACK应答
  43. #define SetNoAck                (TWCR&=~(1<<TWEA))                                                        //做出Not Ack应答
  44. #define Twi()                        (TWCR=(1<<TWINT)|(1<<TWEN))                                    //启动I2C
  45. #define Write8Bit(x)        {TWDR=(x);TWCR=(1<<TWINT)|(1<<TWEN);}                //写数据到TWDR
  46. /************************从机接收状态码******************
  47. #define TW_SR_SLA_ACK   0x60 //自己的SLA+W 已经被接收ACK已返回
  48. #define TW_SR_ARB_LOST_SLA_ACK 0x68 //SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收ACK 已返回
  49. #define TW_SR_GCALL_ACK   0x70 //接收到广播地址ACK 已返回
  50. #define TW_SR_ARB_LOST_GCALL_ACK 0x78 //SLA+R/W 作为主机的仲裁失败;接收到广播地址ACK已返回
  51. #define TW_SR_DATA_ACK   0x80 //以前以自己的SLA+W被寻址;数据已经被接收ACK已返回
  52. #define TW_SR_DATA_NACK   0x88 //以前以自己的SLA+W被寻址;数据已经被接收NOT ACK已返回
  53. #define TW_SR_GCALL_DATA_ACK 0x90 //以前以广播方式被寻址;数据已经被接收ACK已返回
  54. #define TW_SR_GCALL_DATA_NACK 0x98 //以前以广播方式被寻址;数据已经被接收NOT ACK已返回
  55. #define TW_SR_STOP    0xA0 //在以从机工作时接收到STOP或重复START
  56. /*************************从发送状态码*******************
  57. #define TW_ST_SLA_ACK   0xA8 //自己的SLA+R 已经被接收ACK 已返回
  58. #define TW_ST_ARB_LOST_SLA_ACK 0xB0 //SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收ACK 已返回
  59. #define TW_ST_DATA_ACK   0xB8 //TWDR 里数据已经发送接收到ACK
  60. #define TW_ST_DATA_NACK   0xC0 //TWDR 里数据已经发送接收到NOT ACK
  61. #define TW_ST_LAST_DATA   0xC8 //TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK
  62. /****************************其它状态码*****************
  63. #define TW_NO_INFO    0xF8 //没有相关的状态信息;TWINT = “0”
  64. #define TW_BUS_ERROR   0x00 //由于非法的START 或STOP 引起的总线错误

  65. /******************************************************/

  66. /****************************************************
  67. 函数名:TWI_init
  68. 作  用:TWI接口的初始化
  69. *****************************************************/
  70. void TWI_init(void)
  71. {
  72.      TWCR = 0x00;         //关闭TWI模块
  73.          TWAR = 0x00;         //主机模式,该地址无效
  74.      TWBR = Baud_set;     //25
  75.      TWSR = P_value;      //1分频
  76.          TWCR= 0x04;          //使能TWI,禁止中断
  77. }
  78. /****************************************************/
  79. //函数名:I2C_write
  80. //作用:I2C通信中的写操作
  81. uchar I2C_write(uchar SLA_WR_address,uchar wr_address,uchar wr_data)
  82. {         
  83.   Start();             //发送开始信号
  84.   Wait();              //0x08,等待信号发出
  85.   if(TestAck()!=TW_START)
  86.   return 1;
  87.   Write8Bit(SLA_WR_address);      //从机地址,主机写操作,0x3c
  88.   Twi();
  89.   Wait();                //0x18,等待发送
  90.   if(TestAck()!=TW_MT_SLA_ACK)
  91.   return 1;
  92.   Write8Bit(wr_address); //发送地址
  93.   Twi();
  94.   Wait();               //0x28
  95.   if(TestAck()!=TW_MT_DATA_ACK)
  96.   return 1;
  97.   Write8Bit(wr_data);   //写数据
  98.   Twi();
  99.   Wait();              //0x28
  100.   if(TestAck()!=TW_MT_DATA_ACK)
  101.   return 1;
  102.   Stop();            //发送结束信号
  103.   delayms(15);
  104.   return 0;
  105. }
  106. /**************************************************/
  107. //函数名:I2C_read
  108. //作用:I2C通信中的读操作
  109. uchar I2C_read(uchar SLA_WR_address,uchar SLA_RE_address,uchar re_address)
  110. {         
  111.   uchar temp;
  112.   Start();                          //发送开始信号
  113.   Wait();                           //0x08
  114.   if(TestAck()!=TW_START)
  115.   return 1;
  116.   Write8Bit(SLA_WR_address);               //从机地址,主机写操作,0x3c
  117.   Twi();
  118.   Wait();                       //0x18
  119.   if(TestAck()!=TW_MT_SLA_ACK)
  120.   return 1;
  121.   Write8Bit(re_address);        //发送地址
  122.   Twi();
  123.   Wait();                        //0x28
  124.   if(TestAck()!=TW_MT_DATA_ACK)
  125.   return 1;
  126.   
  127.   Start();                    //发送开始信号,
  128.   Wait();                     //0x10
  129.   if(TestAck()!=TW_REP_START)
  130.   return 1;
  131.   Write8Bit(SLA_RE_address);            //从机地址,主机读操作,0x3d
  132.   Twi();
  133.   Wait();                      //0x40
  134.   if(TestAck()!=TW_MR_SLA_ACK)
  135.   return 1;
  136.   Twi();
  137.   Wait();                       //0x58
  138.   if(TestAck()!=TW_MR_DATA_NACK)
  139.   return 1;
  140.   temp = TWDR;                 //读取数据
  141.   Stop();  //发送结束信号
  142.   delayms(1);
  143.   TWCR=0X80;////清除TWINT和禁止TWI(不加上这句程序只能读一次)
  144.   return temp;
  145. }
  146.   #endif
复制代码

作者: fanice    时间: 2012-9-21 11:12
能不能把GCC环境下的代码共享下啊。
作者: cooleaf    时间: 2012-9-21 15:40
帮楼主项一下,有助温习。
作者: fanice    时间: 2012-9-22 22:52
楼主能不能共享下你的代码啊。
作者: wlkobe    时间: 2012-9-25 22:05
seewolf 发表于 2012-9-10 10:57
这是我写的I2C通信的头文件,你可以先检查下I2C是不是有问题。我用它调过ADXL345,所以这个头文件保证没错 ...

哈哈!就是接受的一个标志位判断错误了!终于调出来咯!太谢谢你啦!!!!要不然还不知道要花多少时间才能弄出这个来呢…………
作者: wlkobe    时间: 2012-9-25 22:05
fanice 发表于 2012-9-22 22:52
楼主能不能共享下你的代码啊。

你是要I2C的还是中断的啊?
作者: fanice    时间: 2012-9-26 12:49
你是要I2C的还是中断的啊?


我想要I2C的。不使用中断模式。
多谢了!我的邮箱是fanice1979@yahoo.COM.CN
作者: seewolf    时间: 2012-9-27 21:15
wlkobe 发表于 2012-9-25 22:05
哈哈!就是接受的一个标志位判断错误了!终于调出来咯!太谢谢你啦!!!!要不然还不知道要花多少时间才 ...

呵呵~没事,能帮上忙就好~
作者: wlkobe    时间: 2012-9-27 22:35
fanice 发表于 2012-9-26 12:49
我想要I2C的。不使用中断模式。
多谢了!我的邮箱是

35楼的那个程序就是可以用的,你把那个拷过去就可以了
作者: fanice    时间: 2012-10-20 11:46
多谢了。
作者: lt3100232    时间: 2012-10-22 10:40
   能不能把你的ATmega16的TWI(I2C)读取MMA7455角加速度的程序发给我啊,十分感谢啊,我的邮箱是lt8603@163.com

作者: hzwl2007    时间: 2012-10-22 11:29
学习过了。。。。
作者: fanice    时间: 2012-10-23 16:41
已经顺利读出MMA7455的数据,多谢指教。
作者: xihudelei    时间: 2012-11-16 12:29
我也在调MMA7455,能不能加Q指导一下啊,或者发程序到我邮箱QQ615213015,谢谢啊,拜托了
作者: wlkobe    时间: 2012-11-17 20:28
xihudelei 发表于 2012-11-16 12:29
我也在调MMA7455,能不能加Q指导一下啊,或者发程序到我邮箱QQ615213015,谢谢啊,拜托了 ...

楼上有相应的程序,是可以用的,你可以试试,如果还不行的话加我Q吧:405519134
作者: ludlu521@163.co    时间: 2013-2-19 14:49
atmega16的电压是5V,MMA7455加速计电压最高是3.3,这怎么可以用?是外加电路了么,还有一个问题,外接上拉电阻怎么建立?
作者: plychoz    时间: 2013-2-19 15:08
wlkobe 发表于 2012-9-25 22:05
哈哈!就是接受的一个标志位判断错误了!终于调出来咯!太谢谢你啦!!!!要不然还不知道要花多少时间才 ...

能告诉我你是哪个标志位出错了吗?我的也是和你相同的问题
作者: wlkobe    时间: 2013-2-19 21:35
plychoz 发表于 2013-2-19 15:08
能告诉我你是哪个标志位出错了吗?我的也是和你相同的问题

我是
uchar f_I2cWrite(uchar Wdata,uchar RegAddress)                //I2C总线写一字节  返回1:写成功  返回0:写失败
{
        Start();                                                                                //I2C启动
        Wait();
        if(TestAck()!=START)        return 12;                                //ACK
        //uint t=WD_DEVICE_ADDR<<1;
        WriteByte(WD_DEVICE_ADDR);                                        //写入I2C从器件地址和写方式
        Wait();
        if(TestAck()!=MT_SLA_ACK)        return 2;                        //ACK
        WriteByte(RegAddress);                                                        //写相应寄存器地址
        Wait();
        if(TestAck()!=MT_DATA_ACK)        return 3;
        WriteByte(Wdata);                                                                //写数据
        Wait();
        if(TestAck()!=MT_SLA_ACK)        return 4;                        //ACK
        Stop();                                                                                        //I2C停止
        Delay_ms(10);
        return 0;
}

里面的 RETURN 4 的那个标志位错了,改成MT_DATA_ACK
作者: plychoz    时间: 2013-2-22 21:23
我的芯片外漏接了电容,加上之后,可以读写了。谢谢哈~

你有没有遇到过读XOUT寄存器的值,一直不变的情况呀?我读XOUT寄存器的值时,读数一直是255,也就是说XOUT中的值是原来的默认值0,可以这么理解吗?不知道原因出在哪
作者: as280711261    时间: 2013-4-13 21:16
楼主,不知道你在16上成功的程序,有没有在mega64上试过,我现在遇到一个情况,就是同样的TWI读写程序,在16上可行,但是在64上调试不成功,好像是发从机地址和写方式的时候反馈不成功~不知道楼主有什么看法?
作者: wlkobe    时间: 2013-4-19 16:30
as280711261 发表于 2013-4-13 21:16
楼主,不知道你在16上成功的程序,有没有在mega64上试过,我现在遇到一个情况,就是同样的TWI读写程序,在1 ...

MEGA64没有用过,这个问题确实没有遇到过,实在不好意思哦……
按理说这两个单片机模块应该是可以通用的吧?
作者: as280711261    时间: 2013-4-20 22:00
16和64的TWI接口是通用的,我的问题已经找到了,是硬件上的问题~~
作者: Simon41    时间: 2013-6-11 14:45
wlkobe 发表于 2012-9-25 22:05
你是要I2C的还是中断的啊?

楼主最后是怎么解决的啊,我也是读的时候


   Start();                                                                                                                               //I2C启动
   Wait();
   if(TestAck()!=START)
          return 1;                                                                                        //ACK

返回1.
作者: Simon41    时间: 2013-6-11 21:54
Simon41 发表于 2013-6-11 14:45
楼主最后是怎么解决的啊,我也是读的时候

已解决,上拉电阻的问题




欢迎光临 amobbs.com 阿莫电子技术论坛 (https://www.amobbs.com/) Powered by Discuz! X3.4