打印
[AVR单片机]

关于I2C监测程序的讨论

[复制链接]
2011|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Loo_jack|  楼主 | 2007-4-14 10:59 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
众所周知,I2C主模式的模拟程序比较好写,但从模式要模拟出来却不容易
以下是我写的一个I2C总线的监测程序,能检测正在通讯的i2c总线上传送的数据
有点类似于从模式的I2C模拟程序,但很多地方没有完善,也没找到好的办法
有没有高手指点一下?
程序是测试代码,很乱,不好意思!
#define        __I2CMONITOR_DECL__

#include "global.h"

#include <avr/io.h>            // include I/O definitions (port names, pin names, etc)
//#include <avr/signal.h>        // include "signal" names (interrupt names)
#include <avr/interrupt.h>    // include interrupt support
#include <stdio.h>
#include <util/delay.h>//<avr/delay.h>
#include "uart.h"

//#define        _READ_DROP_EDGE_    //如果需要下降沿读数
//默认为上升沿读数
#define        SDA_PORT    PORTD
#define        SDA_DDR        DDRD
#define        SDA_PIN        PIND
#define        SDA_POT        PD2
 
#define        SCL_PORT    PORTD
#define        SCL_DDR        DDRD
#define        SCL_PIN        PIND
#define        SCL_POT        PD3

#define        RECEIVE_DATA_LENGTH    10
//传输一串数据的最大长度,如果小于最大数据长度,将导致接收错误

#define        RECEIVE_DATA_ANOUNT    60
//传输数据串的个数,建议超过有次发送的串数,这样程序才有时间将数据输出出来
//注意,如果是自动输出的数据(不是按PD7键输出),头尾数据有一定错误(主要是丢失)
//下降沿置数,上升沿读数


unsigned char gBitIndex=0;
unsigned char gByteIndex=0;
unsigned char gReceiveIndex=0;
unsigned char gReceiveDat[RECEIVE_DATA_ANOUNT][RECEIVE_DATA_LENGTH];
unsigned char gStartFlag=0;//是否开始

void intSDAInit(void)        //SDA
{
    MCUCR |=(1<<ISC00);        //电平有变化就中断
    GICR |=(1<<INT0);
}

void intSCLInit(void)            //SCL
{
#ifdef    _READ_DROP_EDGE_
    MCUCR |= (1<<ISC11);        //下降沿中断
#else
    MCUCR |= (1<<ISC10)|(1<<ISC11);        //上升沿中断
#endif    
    //enable_external_int(_BV(INT1));        //使能外部中断1
    GICR |=(1<<INT1);
}
void i2cMonitorInit(void)
{
    intSDAInit();
//    cbi(SDA_DDR,SDA_POT);
//    sbi(SDA_PORT,SDA_POT); 
    intSCLInit();
}
SIGNAL(SIG_INTERRUPT1)        //scl 上升沿,读取数据
{
    if (SDA_PIN&0x04/*(1<<SDA_POT)减少运算次数*/) {    //如果是高电平,收到'1'
        if (!gStartFlag) {    //如果没有开始
            return;
        }
        gReceiveDat[gReceiveIndex][gByteIndex] |= 0x80>>gBitIndex;
        //putchar('1');
    }else{//收到'0'
        if (!gStartFlag) {    //如果没有开始
            return;
        }
        //putchar('0');
    }
    gBitIndex++;
    if ((gBitIndex>8)&&(gByteIndex<RECEIVE_DATA_LENGTH-1)) {//8bit数据和1bit的ack
        gBitIndex=0;
        gByteIndex++;
    }
    
}  

SIGNAL(SIG_INTERRUPT0)        //sda 上电平有变化
{
    if (SCL_PIN&0x08/*(1<<SDA_POT)*/) {//如果SCL是高电平,说明是开始或者结束
        if (SDA_PIN&0x04/*(1<<SDA_POT)减少运算次数*/) {    //如果是上升沿,表示结束
            gStartFlag=0;//结束
            gReceiveDat[gReceiveIndex][0]=gByteIndex;
        }else{//下降沿,表示开始
            gStartFlag=1;//开始
            gBitIndex=0;
            gByteIndex=1;
            if (gReceiveIndex<RECEIVE_DATA_ANOUNT-1) {//用下一个数组存储
                gReceiveIndex++;
            }else{
                gReceiveIndex=0;
            }
            gReceiveDat[gReceiveIndex][0]=RECEIVE_DATA_LENGTH;
        }
    }
    
}
void delay_ms(unsigned int _msNumber_)
{
    unsigned int i;
    for (i=0;i<_msNumber_;i++) {
        _delay_ms(1);
    }
}
int main(void)

    cli();
    i2cMonitorInit();
    uartInit();

    DDRD &=~(1<<PIND7);
    
    printf("uart start ok!\n");

    unsigned char outIndex=0;
    unsigned char i;
    sei();


    while (1) {
        if (outIndex!=gReceiveIndex) {
            if (gReceiveDat[gReceiveIndex][0]) {
                putchar('\n');
                for (i=1;i<gReceiveDat[outIndex][0];i++) {
                    printf("%02X\t",gReceiveDat[outIndex]);
                    gReceiveDat[outIndex]=0;
                }
                gReceiveDat[outIndex][0]=0;
            }

            if (outIndex<RECEIVE_DATA_ANOUNT-1) {    
                outIndex++;
            }else{
                outIndex=0;
            }
        }

    }
    return 0;
}


相关帖子

沙发
John_Lee| | 2007-4-14 21:24 | 只看该作者

AVR有硬件的TWI,为什么不用?

使用特权

评论回复
板凳
Loo_jack|  楼主 | 2007-4-16 10:08 | 只看该作者

如果能用当然就用了

硬件的TWI有很多限制,而且我这个不是接收程序,而是监测程序,一个主机和一个从机在进行I2C通讯,我用这个东西去监测他们通讯的数据,如果用硬件的,对方一发数据你就去写ACK,甚至人家读数的时候你就给他发送数据,这样就影响了原来的通讯,我要做的是在不影响原通讯的情况下读取I2C上的数据并通过串口打印出来。

难点在于原I2C的数据很快,而且一次连续发送的数据很多,有点处理不过来的感觉

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5

主题

30

帖子

0

粉丝