wlkobe 发表于 2012-6-15 13:06:40

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:15

{:lol:} 估计你只是设置了IO口的内部上拉电阻吧?用AVR的TWI一定要外接上拉电阻!!我以前曾在这上面浪费了一个星期时间呐~~

wlkobe 发表于 2012-6-17 22:09:57

BBC 发表于 2012-6-17 02:44 static/image/common/back.gif
估计你只是设置了IO口的内部上拉电阻吧?用AVR的TWI一定要外接上拉电阻!!我以前曾在这上面浪费了 ...

可是我后来是接了外部上拉电阻的啊……而且当时我用51调的时候没有设置上拉电阻照样可以用。AVR的时候不管是模拟还是模块I2C都没用。
你那儿有这个芯片能用的程序么?能让我借鉴一下么?谢了哦!!!

BBC 发表于 2012-6-18 12:42:59

wlkobe 发表于 2012-6-17 22:09 static/image/common/back.gif
可是我后来是接了外部上拉电阻的啊……而且当时我用51调的时候没有设置上拉电阻照样可以用。AVR的时候不 ...

//Atmega8 @ 8MHz
//ICCAVR v7

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

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

unsigned int freq = 10800;
unsigned char rx;

unsigned int cal_pll( unsigned long temp )
{
unsigned int ans;
ans = (unsigned int)(((temp*10-225)*4000)/32768);
return ans;
}

void TWI_write( unsigned char twi_d )
{
TWDR = ( twi_d );
TWCR = ( 1<<TWINT ) | ( 1<<TWEN );
}

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

unsigned char TWI_read( void )
{
unsigned char temp;
TWCR |= 0x04;
while(!(TWCR&(1<<TWINT)));
temp = TWDR;
return temp;
}

void read_5767( void )
{
unsigned char k;
Start();
while(!(TWCR&(1<<TWINT)));
TWI_write(tea5767_add_r);
while(!(TWCR&(1<<TWINT)));
for(k=0;k<5;k++)
{
    rx = TWI_read();
}
}

void write_5767( unsigned char tx0, unsigned char tx1, unsigned char tx2, unsigned char tx3, unsigned char tx4 )
{
Start();
while(!(TWCR&(1<<TWINT)));
TWI_write( tea5767_add_w );
while(!(TWCR&(1<<TWINT)));
TWI_write(tx0);
while(!(TWCR&(1<<TWINT)));
TWI_write(tx1);
while(!(TWCR&(1<<TWINT)));
TWI_write(tx2);
while(!(TWCR&(1<<TWINT)));
TWI_write(tx3);
while(!(TWCR&(1<<TWINT)));
TWI_write(tx4);
while(!(TWCR&(1<<TWINT)));
Stop();
}

void init_5767( void )
{
unsigned int pll;
pll = cal_pll( freq );
write_5767( pll/256|0x80, pll%256, 0x09, 0x90, 0x01 );       //mute
//write_5767( pll/256&(~0x80), pll%256, 0x09, 0x90, 0x01 );//unmute
}{:lol:} 这里有个TEA5767的IIC,希望有用......

wlkobe 发表于 2012-6-18 22:18:52

BBC 发表于 2012-6-18 12:42 static/image/common/back.gif
这里有个TEA5767的IIC,希望有用......

后天考试,考完试好好研究研究,谢啦哈!!!{:biggrin:}

wlkobe 发表于 2012-6-18 22:24:52

BBC 发表于 2012-6-18 12:42 static/image/common/back.gif
这里有个TEA5767的IIC,希望有用......

你好,我还想问下你读取数据的时候调用了中断么?

rei1984 发表于 2012-6-18 22:27:32

lz 给你个提示,利用icc 产生一个 twi程序在试试,一般都是可以的

BBC 发表于 2012-6-19 00:21:47

wlkobe 发表于 2012-6-18 22:24 static/image/common/back.gif
你好,我还想问下你读取数据的时候调用了中断么?

{:lol:} 没有用中断...不过在等待的时候不断查询中断标志:while(!(TWCR&(1<<TWINT)));

wlkobe 发表于 2012-6-21 21:55:46

BBC 发表于 2012-6-19 00:21 static/image/common/back.gif
没有用中断...不过在等待的时候不断查询中断标志:while(!(TWCR&(1

哎?我用了下你的程序,发现我程序里像这种if(TestAck()!=START)判断应答位的语句只要有了,就有问题,无语哎……
现在写数据没什么问题了,可是读数据的时候貌似还是不行额……你平时用的时候功能一切正常的么?

wlkobe 发表于 2012-6-21 21:56:24

rei1984 发表于 2012-6-18 22:27 static/image/common/back.gif
lz 给你个提示,利用icc 产生一个 twi程序在试试,一般都是可以的

这个可以自动生成的么?

BBC 发表于 2012-6-21 22:27:12

本帖最后由 BBC 于 2012-6-21 22:33 编辑

wlkobe 发表于 2012-6-21 21:55 static/image/common/back.gif
哎?我用了下你的程序,发现我程序里像这种if(TestAck()!=START)判断应答位的语句只要有了,就有问题,无 ...

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

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

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

{:lol:} 希望有用......

附上截图:



上图图例:

wlkobe 发表于 2012-6-21 22:49:39

BBC 发表于 2012-6-21 22:27 static/image/common/back.gif
我估计是IIC操作顺序问题......

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


其实我的等待Wait()是{while(!(TWCR&(1<<TWINT)));}和你的程序是一样的额……
啊哦,我们要关门了,明天再调,谢了哈!明天再讨论{:biggrin:}

BBC 发表于 2012-6-21 22:56:23

wlkobe 发表于 2012-6-21 22:49 static/image/common/back.gif
其实我的等待Wait()是{while(!(TWCR&(1

{:lol:} 哈哈,是啊,但是你后一句的注释是ACK,刚刚被这个给骗了,还以为你的操作顺序有问题......
wait()是等待IIC操作完成,if(TestAck()!=START)是查询start命令是否发出......这些都是芯片内部的查询操作啊,怎么会卡住呢......

wlkobe 发表于 2012-6-22 12:58:15

BBC 发表于 2012-6-21 22:56 static/image/common/back.gif
哈哈,是啊,但是你后一句的注释是ACK,刚刚被这个给骗了,还以为你的操作顺序有问题......
wait ...

所以很奇怪啊,我后来发IF语句全都去了,然后在示波器里看波形,start,ack,stop这些都没有问题

wlkobe 发表于 2012-6-22 15:39:52

BBC 发表于 2012-6-21 22:56 static/image/common/back.gif
哈哈,是啊,但是你后一句的注释是ACK,刚刚被这个给骗了,还以为你的操作顺序有问题......
wait ...

你好,我想问下TWI是TWINT为1时工作还是为0时工作啊,我看的有点糊涂了……

wlkobe 发表于 2012-6-22 17:19:56

BBC 发表于 2012-6-21 22:56 static/image/common/back.gif
哈哈,是啊,但是你后一句的注释是ACK,刚刚被这个给骗了,还以为你的操作顺序有问题......
wait ...

你好,我想问下你当时IO口是怎么设置的啊?

BBC 发表于 2012-6-22 18:07:22

wlkobe 发表于 2012-6-22 17:19 static/image/common/back.gif
你好,我想问下你当时IO口是怎么设置的啊?

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

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

其实怪就怪在下面这里 :

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


IO设置的话,我的SCL设为输出,SDA设为输入。

wlkobe 发表于 2012-6-22 18:47:29

怪就怪在这啊,如果TWINT在工作完成后置为while(!(TWCR&(1<<TWINT)));的结果不久成了继续循环了么,这样的话和程序的本意不是相反了么?
话说我的TWI快调出来了,嘿嘿,不过还是接收不到数据……

wlkobe 发表于 2012-6-22 18:47:55

BBC 发表于 2012-6-22 18:07 static/image/common/back.gif
当TWINT为0的时候,表示IIC正在工作。

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


怪就怪在这啊,如果TWINT在工作完成后置为while(!(TWCR&(1<<TWINT)));的结果不久成了继续循环了么,这样的话和程序的本意不是相反了么?
话说我的TWI快调出来了,嘿嘿,不过还是接收不到数据………

BBC 发表于 2012-6-22 19:52:51

wlkobe 发表于 2012-6-22 18:47 static/image/common/back.gif
怪就怪在这啊,如果TWINT在工作完成后置为while(!(TWCR&(1

{:lol:}也不是啊,如果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:58

前段时间调过ATmega16的IIC,中断方式,具体内容已经忘了,悲剧,不过挺好用的!!

wlkobe 发表于 2012-6-22 20:47:25

xlwq 发表于 2012-6-22 20:44 static/image/common/back.gif
前段时间调过ATmega16的IIC,中断方式,具体内容已经忘了,悲剧,不过挺好用的!! ...

想问一下中断内部写的大概是什么方面的程序呢?

xlwq 发表于 2012-6-22 20:58:39

wlkobe 发表于 2012-6-22 20:47 static/image/common/back.gif
想问一下中断内部写的大概是什么方面的程序呢?

每个应答信号后,对应的状态是不一样的,并会触发一次中断,可以读取当前状态寄存器来确定,中断里面用状态机的方式来进行状态判断,然后处理数据!

wlkobe 发表于 2012-6-22 22:23:00

xlwq 发表于 2012-6-22 20:58 static/image/common/back.gif
每个应答信号后,对应的状态是不一样的,并会触发一次中断,可以读取当前状态寄存器来确定,中断里面用状 ...

哦,我貌似今天下午见过类似的程序,试试看,谢了哈!

xlwq 发表于 2012-6-22 22:47:52

wlkobe 发表于 2012-6-22 22:23 static/image/common/back.gif
哦,我貌似今天下午见过类似的程序,试试看,谢了哈!

嗯!!这个方式还是很稳定的!比较好用。

wlkobe 发表于 2012-7-15 21:00:55

xlwq 发表于 2012-6-22 22:47 static/image/common/back.gif
嗯!!这个方式还是很稳定的!比较好用。

你好,我这里有个问题想让你帮我看一下
我是用的是AVR Stdio 5 ,在使用定时中断时总是出现这个错误:ignoring #pragma interrupt_handler PWM
不知道到底是什么原因呢?应该如何解决,谢谢

xlwq 发表于 2012-7-15 21:27:58

AVR studio5 用的是GCC编译器!你的中断函数是
SIGNAL(SIG_INTERRUPT0) //外部中断0
{

}
这种格式吗?

wlkobe 发表于 2012-7-15 21:33:55

我用了那种格式可是错误更多了

警告        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:33

BBC 发表于 2012-6-22 18:07 static/image/common/back.gif
当TWINT为0的时候,表示IIC正在工作。

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

你好,我这里有个问题想让你帮我看一下
我是用的是AVR Stdio 5 ,在使用定时中断时总是出现这个错误:ignoring #pragma interrupt_handler PWM
不知道到底是什么原因呢?应该如何解决,谢谢

BBC 发表于 2012-7-19 20:43:23

wlkobe 发表于 2012-7-15 21:51 static/image/common/back.gif
你好,我这里有个问题想让你帮我看一下
我是用的是AVR Stdio 5 ,在使用定时中断时总是出现这个错误:ign ...

{:lol:} 请把代码贴出来吧...估计是程序里的中断向量名和头文件里宏定义的有出入

wlkobe 发表于 2012-7-20 17:08:50

BBC 发表于 2012-7-19 20:43 static/image/common/back.gif
请把代码贴出来吧...估计是程序里的中断向量名和头文件里宏定义的有出入 ...

问题已经解决了,嘿嘿。是因为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:35

wlkobe 发表于 2012-7-20 17:08 static/image/common/back.gif
问题已经解决了,嘿嘿。是因为Studio是GCC的,而program这种语句是ICC才有的,所以自然就编译不了了

对 ...

呵呵,这个问题我也遇到过,原因是IO口也有它自己的工作时钟,所以这样模拟的频率并不一定就是定时器的频率~

新月弯刀 发表于 2012-9-10 10:37:54

谁有计算8451角度的公式啊

seewolf 发表于 2012-9-10 10:57:05

这是我写的I2C通信的头文件,你可以先检查下I2C是不是有问题。我用它调过ADXL345,所以这个头文件保证没错。#ifndef __I2C_h
#define __I2C_h
#include"Delay.h"
#define uint unsigned int
#define uchar unsigned char
#define Baud_set   25   //TWI波特率设置
#define P_value    0X00//预分频值
//TWI读写操作公共步骤
#define ST_FAIL    0 //出错状态
#define ST_START   1 //START状态检查
#define ST_SLAW    2 //SLAW状态检查
#define ST_WADDR   3 //ADDR状态检查
//TWI读操作步骤
#define ST_RESTART   4 //RESTART状态检查
#define ST_SLAR    5 //SLAR状态检查
#define ST_RDATA   6 //读取数据状态检查,循环n字节
//TWI写操作步骤
#define ST_WDATA   7 //写数据状态检查,循环n字节

#define FAIL_MAX   20 //重试次数最大值
/**********************I2C状态定义*************************/
/************************主机发送状态码********************/
#define TW_START    0x08 //START已发送
#define TW_REP_START   0x10 //重复START已发送
#define TW_MT_SLA_ACK   0x18 //SLA+W 已发送收到ACK
#define TW_MT_SLA_NACK   0x20 //SLA+W 已发送接收到NOT ACK
#define TW_MT_DATA_ACK   0x28 //数据已发送接收到ACK
#define TW_MT_DATA_NACK   0x30 //数据已发送接收到NOT ACK
#define TW_MT_ARB_LOST   0x38 //SLA+W 或数据的仲裁失败
/*************************主机接收状态码*****************/
#define TW_START    0x08 //START已发送
#define TW_REP_START   0x10 //重复START已发送
#define TW_MR_ARB_LOST   0x38 //SLA+R 或NOT ACK 的仲裁失败
#define TW_MR_SLA_ACK   0x40 //SLA+R 已发送接收到ACK
#define TW_MR_SLA_NACK   0x48 //SLA+R 已发送接收到NOT ACK
#define TW_MR_DATA_ACK   0x50 //接收到数据ACK 已返回
#define TW_MR_DATA_NACK   0x58 //接收到数据NOT ACK已返回
/************************常用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
/************************从机接收状态码******************
#define TW_SR_SLA_ACK   0x60 //自己的SLA+W 已经被接收ACK已返回
#define TW_SR_ARB_LOST_SLA_ACK 0x68 //SLA+R/W 作为主机的仲裁失败;自己的SLA+W 已经被接收ACK 已返回
#define TW_SR_GCALL_ACK   0x70 //接收到广播地址ACK 已返回
#define TW_SR_ARB_LOST_GCALL_ACK 0x78 //SLA+R/W 作为主机的仲裁失败;接收到广播地址ACK已返回
#define TW_SR_DATA_ACK   0x80 //以前以自己的SLA+W被寻址;数据已经被接收ACK已返回
#define TW_SR_DATA_NACK   0x88 //以前以自己的SLA+W被寻址;数据已经被接收NOT ACK已返回
#define TW_SR_GCALL_DATA_ACK 0x90 //以前以广播方式被寻址;数据已经被接收ACK已返回
#define TW_SR_GCALL_DATA_NACK 0x98 //以前以广播方式被寻址;数据已经被接收NOT ACK已返回
#define TW_SR_STOP    0xA0 //在以从机工作时接收到STOP或重复START
/*************************从发送状态码*******************
#define TW_ST_SLA_ACK   0xA8 //自己的SLA+R 已经被接收ACK 已返回
#define TW_ST_ARB_LOST_SLA_ACK 0xB0 //SLA+R/W 作为主机的仲裁失败;自己的SLA+R 已经被接收ACK 已返回
#define TW_ST_DATA_ACK   0xB8 //TWDR 里数据已经发送接收到ACK
#define TW_ST_DATA_NACK   0xC0 //TWDR 里数据已经发送接收到NOT ACK
#define TW_ST_LAST_DATA   0xC8 //TWDR 的一字节数据已经发送(TWAE = “0”);接收到ACK
/****************************其它状态码*****************
#define TW_NO_INFO    0xF8 //没有相关的状态信息;TWINT = “0”
#define TW_BUS_ERROR   0x00 //由于非法的START 或STOP 引起的总线错误

/******************************************************/

/****************************************************
函数名:TWI_init
作用:TWI接口的初始化
*****************************************************/
void TWI_init(void)
{
   TWCR = 0x00;         //关闭TWI模块
       TWAR = 0x00;         //主机模式,该地址无效
   TWBR = Baud_set;   //25
   TWSR = P_value;      //1分频
       TWCR= 0x04;          //使能TWI,禁止中断
}
/****************************************************/
//函数名:I2C_write
//作用:I2C通信中的写操作
uchar I2C_write(uchar SLA_WR_address,uchar wr_address,uchar wr_data)
{       
Start();             //发送开始信号
Wait();            //0x08,等待信号发出
if(TestAck()!=TW_START)
return 1;
Write8Bit(SLA_WR_address);      //从机地址,主机写操作,0x3c
Twi();
Wait();                //0x18,等待发送
if(TestAck()!=TW_MT_SLA_ACK)
return 1;
Write8Bit(wr_address); //发送地址
Twi();
Wait();               //0x28
if(TestAck()!=TW_MT_DATA_ACK)
return 1;
Write8Bit(wr_data);   //写数据
Twi();
Wait();            //0x28
if(TestAck()!=TW_MT_DATA_ACK)
return 1;
Stop();            //发送结束信号
delayms(15);
return 0;
}
/**************************************************/
//函数名:I2C_read
//作用:I2C通信中的读操作
uchar I2C_read(uchar SLA_WR_address,uchar SLA_RE_address,uchar re_address)
{       
uchar temp;
Start();                        //发送开始信号
Wait();                           //0x08
if(TestAck()!=TW_START)
return 1;
Write8Bit(SLA_WR_address);               //从机地址,主机写操作,0x3c
Twi();
Wait();                     //0x18
if(TestAck()!=TW_MT_SLA_ACK)
return 1;
Write8Bit(re_address);      //发送地址
Twi();
Wait();                        //0x28
if(TestAck()!=TW_MT_DATA_ACK)
return 1;

Start();                  //发送开始信号,
Wait();                     //0x10
if(TestAck()!=TW_REP_START)
return 1;
Write8Bit(SLA_RE_address);            //从机地址,主机读操作,0x3d
Twi();
Wait();                      //0x40
if(TestAck()!=TW_MR_SLA_ACK)
return 1;
Twi();
Wait();                     //0x58
if(TestAck()!=TW_MR_DATA_NACK)
return 1;
temp = TWDR;               //读取数据
Stop();//发送结束信号
delayms(1);
TWCR=0X80;////清除TWINT和禁止TWI(不加上这句程序只能读一次)
return temp;
}
#endif

fanice 发表于 2012-9-21 11:12:40

能不能把GCC环境下的代码共享下啊。

cooleaf 发表于 2012-9-21 15:40:42

帮楼主项一下,有助温习。

fanice 发表于 2012-9-22 22:52:23

楼主能不能共享下你的代码啊。

wlkobe 发表于 2012-9-25 22:05:03

seewolf 发表于 2012-9-10 10:57 static/image/common/back.gif
这是我写的I2C通信的头文件,你可以先检查下I2C是不是有问题。我用它调过ADXL345,所以这个头文件保证没错 ...

哈哈!就是接受的一个标志位判断错误了!终于调出来咯!太谢谢你啦!!!!要不然还不知道要花多少时间才能弄出这个来呢…………

wlkobe 发表于 2012-9-25 22:05:36

fanice 发表于 2012-9-22 22:52 static/image/common/back.gif
楼主能不能共享下你的代码啊。

你是要I2C的还是中断的啊?

fanice 发表于 2012-9-26 12:49:02

你是要I2C的还是中断的啊?

我想要I2C的。不使用中断模式。
多谢了!我的邮箱是fanice1979@yahoo.COM.CN

seewolf 发表于 2012-9-27 21:15:17

wlkobe 发表于 2012-9-25 22:05 static/image/common/back.gif
哈哈!就是接受的一个标志位判断错误了!终于调出来咯!太谢谢你啦!!!!要不然还不知道要花多少时间才 ...

呵呵~没事,能帮上忙就好~

wlkobe 发表于 2012-9-27 22:35:39

fanice 发表于 2012-9-26 12:49 static/image/common/back.gif
我想要I2C的。不使用中断模式。
多谢了!我的邮箱是

35楼的那个程序就是可以用的,你把那个拷过去就可以了

fanice 发表于 2012-10-20 11:46:21

多谢了。

lt3100232 发表于 2012-10-22 10:40:11

   能不能把你的ATmega16的TWI(I2C)读取MMA7455角加速度的程序发给我啊,十分感谢啊,我的邮箱是lt8603@163.com

hzwl2007 发表于 2012-10-22 11:29:11

学习过了。。。。

fanice 发表于 2012-10-23 16:41:09

已经顺利读出MMA7455的数据,多谢指教。

xihudelei 发表于 2012-11-16 12:29:02

我也在调MMA7455,能不能加Q指导一下啊,或者发程序到我邮箱QQ615213015,谢谢啊,拜托了

wlkobe 发表于 2012-11-17 20:28:20

xihudelei 发表于 2012-11-16 12:29 static/image/common/back.gif
我也在调MMA7455,能不能加Q指导一下啊,或者发程序到我邮箱QQ615213015,谢谢啊,拜托了 ...

楼上有相应的程序,是可以用的,你可以试试,如果还不行的话加我Q吧:405519134

ludlu521@163.co 发表于 2013-2-19 14:49:45

atmega16的电压是5V,MMA7455加速计电压最高是3.3,这怎么可以用?是外加电路了么,还有一个问题,外接上拉电阻怎么建立?

plychoz 发表于 2013-2-19 15:08:16

wlkobe 发表于 2012-9-25 22:05 static/image/common/back.gif
哈哈!就是接受的一个标志位判断错误了!终于调出来咯!太谢谢你啦!!!!要不然还不知道要花多少时间才 ...

能告诉我你是哪个标志位出错了吗?我的也是和你相同的问题

wlkobe 发表于 2013-2-19 21:35:16

plychoz 发表于 2013-2-19 15:08 static/image/common/back.gif
能告诉我你是哪个标志位出错了吗?我的也是和你相同的问题

我是
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:47

我的芯片外漏接了电容,加上之后,可以读写了。谢谢哈~

你有没有遇到过读XOUT寄存器的值,一直不变的情况呀?我读XOUT寄存器的值时,读数一直是255,也就是说XOUT中的值是原来的默认值0,可以这么理解吗?不知道原因出在哪

as280711261 发表于 2013-4-13 21:16:34

楼主,不知道你在16上成功的程序,有没有在mega64上试过,我现在遇到一个情况,就是同样的TWI读写程序,在16上可行,但是在64上调试不成功,好像是发从机地址和写方式的时候反馈不成功~不知道楼主有什么看法?

wlkobe 发表于 2013-4-19 16:30:31

as280711261 发表于 2013-4-13 21:16 static/image/common/back.gif
楼主,不知道你在16上成功的程序,有没有在mega64上试过,我现在遇到一个情况,就是同样的TWI读写程序,在1 ...

MEGA64没有用过,这个问题确实没有遇到过,实在不好意思哦……
按理说这两个单片机模块应该是可以通用的吧?

as280711261 发表于 2013-4-20 22:00:58

16和64的TWI接口是通用的,我的问题已经找到了,是硬件上的问题~~

Simon41 发表于 2013-6-11 14:45:56

wlkobe 发表于 2012-9-25 22:05 static/image/common/back.gif
你是要I2C的还是中断的啊?

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


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

返回1.

Simon41 发表于 2013-6-11 21:54:56

Simon41 发表于 2013-6-11 14:45 static/image/common/back.gif
楼主最后是怎么解决的啊,我也是读的时候




已解决,上拉电阻的问题
页: [1]
查看完整版本: ATmega16的TWI(I2C)读取MMA7455角加速度仪死活调不出来,求助