小智 发表于 2015-7-4 11:30:35

IIC通信心得

本帖最后由 小智 于 2015-7-4 14:23 编辑

//本程序是在看郭天祥老师视频后编制的,程序在郭老师的基础上做了细微的变动
//并在部分语句后添加了自己的理解,如果有不妥欢迎大家指正出来,谢谢!!!
//程序包含的内容很简单,只是向AT24c02中写入一个字节的数据,然后输出这个数据,并赋给P1口输出
//虽然是51程序,但愿对刚接触IIC通信的朋友有所帮助。
//邮箱:[email protected]
#include <reg52.h>
#define uchar unsigned char
sbit scl=P2^1;//定义时钟线
sbit sda=P2^0;//定义数据线
void delay()//
{;;}
void delay_(uchar x)
{
uchar a,b;
for(a=x;a>0;a--)
   for(b=100;b>0;b--);       
}
void start()//开始,开始的信号为时钟信号高的状态下,数据线一个下降沿    不用应答
{
                sda=1;
                delay();
                scl=1;
                delay();
                sda=0;
          delay();               
}
void stop()//终止,终止信号为时钟信号搞得状态下,数据线一个上升沿   不用应答
{
   sda=0;
   delay();
   scl=1;
   delay();
   sda=1;
   delay();       
}
/***********************************************************************************************************************************/
//每次上位机要向下位机读、写数据时都要等待下位机回应(即下位机将数据线sda置低),但是下位机要是一直不回应低上位机就不管了,毕竟有主动权嘛
/***************************************************************************************************************************************/
void respons()//应答      
{
        uchar i;
        scl=1;
        delay();
        while((sda==1)&&(i<250))i++;//如果下位机应答了会将数据线拉低
        scl=0;
        delay();
}
void init()//初始化时将数据线和时钟线都拉高
{
        sda=1;
        delay();
        scl=1;
        delay();
}
void write_byte(uchar date)//写一个字节      需要应答
{
        uchar i,temp;
        temp=date;
        for(i=0;i<8;i++)
        {
          scl=0;         //一个时钟完成一位数据sda的传输,一位数据sda在一个时钟scl内是不允许变化的               
          delay();                        
                temp=temp<<1;//左移时,左边溢出的那一位数据会自动保存在PSW的CY位,右边自动补0            
                sda=CY;//赋给数据线,将要传出到下位机了   
                delay();      
                scl=1;
                delay();
}
scl=0;//这个语句是为了满足最后一位数据sda传送时时钟信号scl信号跳变的完整性 低-高-低
delay();
sda=1;//置1是为了接收应答信号,应答信号sda的引脚会识别低信号
delay();
}
/***********************************************************************/
//每个字节共有8位数据,要循环8次才能将一个字节的数据读走。
//数据的写入和读走都要保证数据的稳定,
/***********************************************************************/
uchar read_byte()//读一个字节
{
        uchar i,k;
        scl=0;
        delay();
        sda=1;//数据线释放,这个引脚在读数据线时要释放掉(51中默认为高),它的高低要有下位机决定,这样才能读出下位机的数据
        for(i=0;i<8;i++)
        {
                scl=1;//高线平时才允许读数据       
                delay();
                //j=sda;       
                k=(k<<1)|sda;//每执行这个语句,都会将刚读取的那位(sda)放在k的低位上
                scl=0;
                delay();
        }
       return k;
}
void write_add(uchar address,uchar date_)
{   
          start();//起始信号                                                                         此时主机想向众多从机说话。。。
                write_byte(0xa0);//写器件地址,高四位是1010,接着三位是000;因为是写,所以最后一位也是0    上位机问众多下位机:你们有谁叫0xa0的吗?我要向你发送点数据!   
                respons();//发完地址和写请求后等待应答                                                   0xa0回答道:真的啊,那快点发过来
                write_byte(address);//写该器件存储取地址                                                   主机向从机说道:我要向你的address位发东西了哈!are you ok??
                respons();//等待回应                                                                     从机回答道:准备好啦!(内心一阵窃喜)
                write_byte(date_);//写数据喽                                                               主机开始写数据了。。。
          respons();              //                                                                      从机向主机说道:谢谢你,我都收到啦,嘻嘻。。。
                stop();         //                                                                     此时主机停止发送数据了。。。。                  
}
/*****************************************************/
//主机要向从机读数据
//对比发送和接收数据两个过程不难发现,貌似接收更难一些,是不是索取比给予都要难一些,单片机通信也是????
/*****************************************************/
uchar read_add(uchar address_)
{
          uchar a;
                start();         //                     此时主机准备向众多下位机说话。。。   
                write_byte(0xa0);//器件地址             上位机问众多下位机:你们有谁叫0xa0的吗?
                respons();       //                     下位机向上位机回答道:我是0xa0,你找我有什么事吗?
                write_byte(address_);//储存区地址       上位机向0xa0说道:我打算看看你第address_位数据(以000数据为起点啊)。
                respons();         //               下位机0xa0回答道:好的,随时恭候。
               
                start();             //               此时上位机在开始准备了。。。            
                write_byte(0xa1);//写器件地址,要读数据上位机准备好了,然后对下位机说:你可以接收数据了,你把数据发过来吧!
                respons();       //                     下位机回答道:好的,已发送,请注意查收
                a=read_byte();//都会来的值赋给P1引脚    此时主机开始接收了。。。
                stop();      //                     接收完了一个字节的数据,就停下来通信了                  
                return a;      //                     接着返回到主程序中对接收到的数据进一步处理
               
}

void main()
{
          init();//数据线,时钟线拉高
    write_add(23,0x00);//物理地址的第23个地址存入数据0x02
                delay_(100);//该延迟是为了给写入过程、读出过程留足一定的时间,也就是给硬件喘口气
          P1=read_add(23);//将读出的数据输出到引脚
          while(1);//此程序就让它运行一次
}
   

得了白学症 发表于 2015-7-5 20:43:32

:D:D:D:D:D

wing 发表于 2015-7-6 08:28:56

看得不是太懂,51没学过....{:soso_e127:}

小智 发表于 2015-7-8 02:07:17

wing 发表于 2015-7-6 08:28 static/image/common/back.gif
看得不是太懂,51没学过....

IIC通信在哪种平台协议都一样的,开始、停止、应答、写一个字节、读一个字节、写数据、读数据,好像就这几个函数,51我用的也不多:D

小智 发表于 2015-7-8 02:09:10

wing 发表于 2015-7-6 08:28 static/image/common/back.gif
看得不是太懂,51没学过....

除了写数据和读数据放在外边,其他基本都是封装在库里的
页: [1]
查看完整版本: IIC通信心得