solank 发表于 2008-1-30 20:29:17

请教马老师IIC通讯程序问题

#include "I2C.h"

/* 延时约5微秒,对于12M时钟 */
void delay5us()
{
        uint i;
        for (i=0;i<5;i++)
                _nop_();       
}

/* 起始条件子函数 */
void start(void)
{
        SDA = 1;                        // 启动I2C总线
        SCL = 1;
        delay5us();
        SDA = 0;
        delay5us();
        SCL = 0;
}

/* 停止条件子函数 */
void stop(void)
{
        SDA = 0;                        // 停止I2C总线数据传送
        SCL = 1;
        delay5us();
        SDA = 1;
        delay5us();
        SCL = 0;
}

/* 发送应答子函数 */
void ack(void)
{
        SDA = 0;                        // 发送应答位
        SCL = 1;
        delay5us();
        SDA = 1;
        SCL = 0;
}

/* 发送非应答子函数 */
void n_ack(void)
{
        SDA = 1;                        // 发送非应答位
        SCL = 1;
        delay5us();
        SDA = 0;
        SCL = 0;
}

/* 应答位检查子函数 */
void checkack(void)
{
        SDA = 1;                    // 应答位检查(将p1.0设置成输入,必须先向端口写1)
        SCL = 1;
        nackFlag = 0;
        if(SDA == 1)            // 若SDA=1表明非应答,置位非应答标志F0
                nackFlag = 1;
        SCL = 0;
}

/* 发送一个字节数据子函数 */
void sendbyte(uchar idata *ch)
{
        uchar idata n = 8;
        uchar idata temp;
        temp = *ch;
        while(n--)
        {
                if((temp&0x80) == 0x80)    // 若要发送的数据最高位为1则发送位1
                {
                        SDA = 1;    // 传送位1
                        SCL = 1;
                        delay5us();
                        SDA = 0;
                        SCL = 0;   
                }
                else
                {
                        SDA = 0;    // 否则传送位0
                        SCL = 1;
                        delay5us();
                        SCL = 0;
                }
                temp = temp<<1;    // 数据左移一位
        }
}


/* 接收一字节子程序 */
void recbyte(uchar idata *ch)
{
        uchar idata n=8;    // 从SDA线上读取一位数据字节,共8位
        uchar idata temp = 0;
        while(n--)
        {
                SDA = 1;
                SCL = 1;
                temp = temp<<1;    // 左移一位
                if(SDA == 1)
                        temp = temp|0x01;    // 若接收到的位为1,则数据的最后一位置1
                else
                        temp = temp&0xfe;    // 否则数据的最后一位置0
                SCL=0;
        }
        *ch = temp;
}














/* 发送n字节数据子程序 */
void sendnbyte(uchar idata *sla, uchar n)
{         
        uchar idata *p;
        start();                               
        sendbyte(sla);                   
        checkack();                           
    if(F0 == 1)                                                            //这个F0是哪里来的?为什么这里是F0而不是nackFlag ?
        {
                NACK = 1;
                return;                   
                                                         //NACK置位有什么用,在哪里控制MCU說应答有问题?Return被返回哪里去了? 程序下部执行哪个?
        }



















        p = sbuf;
        while(n--)
        {
                sendbyte(p);
                checkack();            // 检查应答位
                if (nackFlag == 1)
                {
                        NACK=1;
                        return;            // 若非应答表明器件错误或已坏,置错误标志位NACK
                }
                p++;
        }
        stop();                            // 全部发完则停止
}

/* 接收n字节数据子程序 */
void recnbyte(uchar idata *sla, uchar n)
{
        uchar idata *p;
        start();                        // 发送启动信号
        sendbyte(sla);                // 发送从器件地址字节
        checkack();                        // 检查应答位
        if(nackFlag == 1)
        {
                NACK = 1;
                return;
        }
        p = rbuf;                        // 接收字节存放在rbuf中
        while(n--)
        {
                recbyte (p);
                ack();                    // 收到一个字节后发送一个应答位
                p++;
        }
        n_ack();                    // 收到最后一个字节后发送一个非应答位
        stop();
}

/* 主函数,模拟实现I2C总线的数据收发 */
void main(void)
{
        uchar i,numbyte;

        numbyte = 8;

        /* 需发送的8字节数据 */
        for (i=0;i<numbyte;i++)
                sbuf = i+0x11;

        SLAdd = 0x58;                // 从器件地址
       
           sendnbyte(&SLAdd,numbyte);        // 向从器件发送存放在sbuf中的8字节数据

        for (i=0;i<10000;i++)
                delay5us();

        recnbyte(&SLAdd,numbyte);        // 由从器件接收8字节数据,存放在rbuf中

}

solank 发表于 2008-1-30 20:31:10

程序隔开的中间部分为问题



另外程序中
定义的
bit bdata NACK 可否改为bit NACK ?
uchar idata sbuf 可否改为 uchar sbuf ?

SLAdd=0x58 是从器件地址? 如何解读? 查阅器件一般为0xa为固定然后是地址3位和一位读写, 还是說这个不是EEPROM器件,仅仅是一个IIC的通讯器件?

sendnbyte(&SLAdd,Numbyte) / & 在此有何意义?

machao 发表于 2008-2-1 01:09:07

建议你先仔细学习I2C的规程,彻底弄清楚基本的概念.另外你的许多基础也不牢固,如C语言,AVR的基本特点等.

如果你真要学习使用AVR,建议你买本我写的书《AVR单片机嵌入式系统原理与应用实践》,肯定回对你有帮助的.

yuanhuaize 发表于 2008-6-6 00:54:19

代码太多重复
页: [1]
查看完整版本: 请教马老师IIC通讯程序问题