搜索
bottom↓
回复: 3

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

[复制链接]

出0入0汤圆

发表于 2008-1-30 20:29:17 | 显示全部楼层 |阅读模式
#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中

}

阿莫论坛20周年了!感谢大家的支持与爱护!!

知道什么是神吗?其实神本来也是人,只不过神做了人做不到的事情 所以才成了神。 (头文字D, 杜汶泽)

出0入0汤圆

 楼主| 发表于 2008-1-30 20:31:10 | 显示全部楼层
程序隔开的中间部分为问题



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

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

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

出0入0汤圆

发表于 2008-2-1 01:09:07 | 显示全部楼层
建议你先仔细学习I2C的规程,彻底弄清楚基本的概念.另外你的许多基础也不牢固,如C语言,AVR的基本特点等.

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

出0入0汤圆

发表于 2008-6-6 00:54:19 | 显示全部楼层
代码太多重复
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-7-23 04:17

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表