OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 7889|回复: 26

IIC总线学习笔记

[复制链接]

4

主题

20

帖子

0

精华

新手上路

积分
45
金钱
45
注册时间
2016-1-16
在线时间
7 小时
发表于 2016-2-25 15:01:30 | 显示全部楼层 |阅读模式
                                                 通信的桥梁-----IIC总线
人与人之间能进行交流是因为有语言这个工具。电子芯片之间的交流也需要一个工具,IIC总线就是这个工具,通过IIC总线,芯片之间能进行信息交流。但是,交流并不是那么简单的,交流的双方必须有共同语言,就像我们和外国人交流的时候就要用外语,而不能用国语,否则无法交流。芯片通过IIC总线进行交流。

    什么是IIC总线?
    IIC总线由一条SDA数据线和一条SCL时钟线组成,在这两条线上可以挂载多个IIC设备,每个IIC设备都有自己的地址,这些地址由硬件的出厂固定地址位和可编程地址位组成,只有在两条线上传输的值是IIC设备的地址时,这个IIC设备才会作出响应。就像老师上课提问学生一样,只有学生被叫到自己的名字才会站起来回答问题。
    IIC作为电子芯片之间的交流语言,它也有一些语法------IIC通讯协议。
   当SCL时钟线为高电平的时候,如果SDA线由高电平跳到低电平,说明老师准备提问学生了,即IIC主机准备寻找从机。
    这个过程转换为C语言就是
void IIC_Start(void)
{
SDA_OUT();     //sda线设置为输出模式
IIC_SDA=1;   
IIC_SCL=1;
delay_us(4);
IIC_SDA=0;  // SDA由高跳到低
delay_us(4);
IIC_SCL=0;//钳住I2C总线,准备发送或接收数据
}  
    我们把这个过程称为IIC的起始信号。
    注意:上面的delay延时函数不是固定的,要根据硬件设备的固定时序来设置。就像有些学生反应比较快,有些学生反应比较慢,老师不能要求每个学生反应时间都一样。所以主机呼叫从机要根据从机的反应速度来设定等待时间。这个延时十分重要!延时长一点和短一点都无法得到正确的数据。

    做事要有始有终,老师提问完学生当然要请学生坐下啦,IIC用完从机,当然也要把从机释放了。
    这个过程就是主机发出一个终止信号:SCL为高时,SDA由低电平跳到高电平
    void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL=0;
IIC_SDA=0;//SDA由低跳到高
delay_us(4);
IIC_SCL=1;
IIC_SDA=1;//发送I2C总线结束信号
delay_us(4);  
}
    终止信号完了之后,IIC处于闲置状态,主机可以呼叫其他设备了,(提问完一个学生,老师又可以去提问另一个学生了!)
                                 
    俗话说:一个巴掌拍不响。老师叫学生起来回答问题,如果学生不乐意当然也就不鸟老师了。当主机呼叫从机时,从机可以应答也可以不应答。即当SCL为高电平的时候,SDA为低电平表明从机应答,否则表明从机不应答。
void IIC_Ack(void)
{
IIC_SCL=0;      //首先拉低SCL,防止产生起始或结束信号
SDA_OUT();
IIC_SDA=0;      //低电平代表应答
delay_us(4);
IIC_SCL=1;
delay_us(4);
IIC_SCL=0;
}
      Ack即从机应答。
    void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1;  //高电平代表不应答
delay_us(4);
IIC_SCL=1;
delay_us(4);
IIC_SCL=0;
  }
    NAck即是No Ack ,从机不应答。


等待应答也是一个过程:
    u8IIC_Wait_Ack(void)
    {
        u8ucErrTime=0;
        SDA_IN();     //SDA设置为输入模式  
        IIC_SDA=1;
        delay_us(4);      
        IIC_SCL=1;
        delay_us(4);     
        while(READ_SDA)             //SDA为高即未应答
        {
            ucErrTime++;
            if(ucErrTime>250)           //等待一段时间还没应答则发送停止信号
            {
                IIC_Stop();
                return1;
            }
        }
        IIC_SCL=0;//时钟线输出0      
        return0;                     
    }




  有了上面的基本信号,主从机可以进行交流了。
    voidIIC_Send_Byte(u8 txd)  //发送一个字节的数据            
    {                     
        u8t;   
        SDA_OUT();         
        IIC_SCL=0;//拉低时钟线开始数据传输
        for(t=0;t<8;t++)
        {            
            
            if(txd&0x80) // 因为先发的是最高位
                IIC_SDA=1;      //如果刚刚的位是1则证明SDA为高,所以置1
            else
                IIC_SDA=0;          //你懂的
            txd <<=1;              //为读下一位作准备
            delay_us(4);  
            IIC_SCL=1;          //时钟线高的时候,数据保持稳定,保证正确读取
            delay_us(4);
            IIC_SCL=0;          //时钟线拉低,允许读下一位
            delay_us(4);
        }   
        }      
              为什么要先把SCL设置为低电平?其实上面已经有提示,因为在SCL为高电平的时候,SDA的变化代表着起始或者终止信号,所以在SCL为低的时候,才允许SDA变化(这些变化代表数据)。

   
另外因为一个字节(8位)的数据是按照一位一位来传送的,协议规定先传送最高位,所以txd与上0x80,判断最高位什么电平,然后txd自身左移一位,即第6位变第7...以此类推,循环8次,则0~7号位上的数据完成了传送。

        
老师可以提问学生,学生也可以提问老师。同样,主机可以向从机发数据,从机也可以向主机发数据(或主机读取从机数据)
u8 IIC_Read_Byte()          //因为接收从最高位开始,所以下面进行左移操作的。
       {
              u8i,receive=0;
              SDA_IN();                //SDA设置为输入
              for(i= 0;i < 8;i++ )                            //一个字节需要一位一位地读出来,所以要循环8次
              {
                     IIC_SCL= 0;
                     delay_us(4);
                     IIC_SCL= 1;
                     receive<<= 1;      //左移一位
                     if(READ_SDA)   //当SDA是1的时候读入1否则直接补零
                            receive|= 0x01;  
                     delay_us(1);
              }                                   
                     IIC_Ack();//发送ACK   ,表示读完数据且应答了
              returnreceive;
       }
    这里的READ_SDA是SDA线的引脚状态号。


以上就是IIC的基本“语法”了。
再来一个实际应用:
/************************************************/
/*                   向从机写数据                    */
/************************************************/
//“1”代表主机读取数据,“0”代表主机发送数据
void Single_Write(u8 SlaveAddress,u8 REG_Address,u8REG_Data)
{
       IIC_Start();                                //开始信号
       IIC_Send_Byte(SlaveAddress);   //发送设备地址+写信号
       IIC_Wait_Ack();                         //等待应答
       IIC_Send_Byte(REG_Address);             //发送设备寄存器地址
       IIC_Wait_Ack();                         //等待应答
       IIC_Send_Byte(REG_Data);            //写数据
       IIC_Wait_Ack();                         //等待应答
       IIC_Stop();                                       //停止信号
       delay_ms(5);
}
/************************************************/
/*                   读取从机的数据   */
/************************************************/
u8 Single_Read(u8 SlaveAddress,u8 REG_Address)
{
       u8 REG_Data;
       IIC_Start();                                //开始信号
       IIC_Send_Byte(SlaveAddress);   //发送设备地址+写信号
       IIC_Wait_Ack();                         //等待应答
       IIC_Send_Byte(REG_Address);   //发送设备寄存器地址
       IIC_Wait_Ack();                         //等待应答
       IIC_Start();                                //再次开始信号
       IIC_Send_Byte(SlaveAddress+ 1);    //发送设备地址+读信号
       IIC_Wait_Ack();                         //等待应答
       REG_Data =IIC_Read_Byte();        //获取数据
       IIC_NAck();                                      //不再应答
       IIC_Stop();                                       //停止信号
       delay_ms(5);        
       returnREG_Data;                           
}




注意:在同一IIC总线上可以挂载的同一IIC设备最大数量是2^(可编程位数),如果可编程位数是3,那么可以挂载这种IIC设备的最大数量就是8个。

小小心得,希望能帮助新人~~~  同时也欢迎大神指点

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

72

主题

2711

帖子

2

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
3505
金钱
3505
注册时间
2014-8-4
在线时间
696 小时
发表于 2016-2-25 17:21:48 | 显示全部楼层
很详细,楼主很用心.....
以我资质之鲁钝,当尽平心静气、循序渐进、稳扎稳打之力。
回复 支持 反对

使用道具 举报

4

主题

18

帖子

0

精华

新手上路

积分
38
金钱
38
注册时间
2016-2-25
在线时间
6 小时
发表于 2016-2-25 17:46:01 | 显示全部楼层
楼主用过AD7991这块ADC吗?
回复 支持 反对

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2016-2-25 22:02:46 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

9

主题

167

帖子

0

精华

高级会员

Rank: 4

积分
552
金钱
552
注册时间
2013-12-15
在线时间
29 小时
发表于 2016-2-25 23:06:36 | 显示全部楼层
不错 !
我是初学者
专注显示科技 - - - 让每一DOT诠释生命的精彩
TFT显示屏:   https://boy-display.taobao.com
回复 支持 反对

使用道具 举报

16

主题

55

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
301
金钱
301
注册时间
2015-12-15
在线时间
72 小时
发表于 2016-2-26 08:26:58 | 显示全部楼层
谢谢分享
回复 支持 反对

使用道具 举报

4

主题

20

帖子

0

精华

新手上路

积分
45
金钱
45
注册时间
2016-1-16
在线时间
7 小时
 楼主| 发表于 2016-2-27 13:07:13 | 显示全部楼层
_bin 发表于 2016-2-25 17:46
楼主用过AD7991这块ADC吗?

没有哦
回复 支持 反对

使用道具 举报

1

主题

14

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2016-3-22
在线时间
8 小时
发表于 2016-3-25 10:30:22 | 显示全部楼层
谢谢楼主分享   很详细的代码及注解   
回复 支持 反对

使用道具 举报

24

主题

192

帖子

0

精华

高级会员

Rank: 4

积分
504
金钱
504
注册时间
2016-3-16
在线时间
205 小时
发表于 2016-3-26 13:18:06 | 显示全部楼层
    不错! 受教了,, 人与人交流是用语言,假如哪天你用编程可以像说话那么流利地表达你的思想,那就学成了。
路漫漫其修远兮,戒骄戒躁。
回复 支持 反对

使用道具 举报

1

主题

14

帖子

0

精华

新手上路

积分
48
金钱
48
注册时间
2016-3-22
在线时间
8 小时
发表于 2016-3-29 10:42:48 | 显示全部楼层
请问楼主,不同EEPROM 的延时时间长短如何确定,另外怎么判断哪句后面加延时  哪句不加   ?    新手入门 求指教
回复 支持 反对

使用道具 举报

9

主题

30

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
219
金钱
219
注册时间
2015-3-2
在线时间
36 小时
发表于 2016-4-10 16:52:10 | 显示全部楼层
等待应答也是一个过程:
    u8IIC_Wait_Ack(void)
    {
        u8ucErrTime=0;
        SDA_IN();     //SDA设置为输入模式  
        IIC_SDA=1;
        delay_us(4);      
        IIC_SCL=1;
        delay_us(4);     
请问楼主 sda设置为输入了, iic_sda=1是什么意思
回复 支持 反对

使用道具 举报

7

主题

30

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2016-4-9
在线时间
14 小时
发表于 2016-4-17 17:59:02 | 显示全部楼层
崇文尚武 发表于 2016-4-10 16:52
等待应答也是一个过程:
    u8IIC_Wait_Ack(void)
    {

IIC_SDA=1;  是将SDA线拉高哦
回复 支持 反对

使用道具 举报

32

主题

230

帖子

0

精华

高级会员

Rank: 4

积分
508
金钱
508
注册时间
2016-4-14
在线时间
113 小时
发表于 2016-4-26 19:08:55 | 显示全部楼层
人才!很通俗~但让我get到很多东西!牛b
回复 支持 反对

使用道具 举报

1

主题

7

帖子

0

精华

初级会员

Rank: 2

积分
109
金钱
109
注册时间
2016-3-27
在线时间
26 小时
发表于 2016-4-26 22:33:14 | 显示全部楼层
谢谢分享,很棒的分享
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
9
金钱
9
注册时间
2016-5-25
在线时间
1 小时
发表于 2016-6-11 21:28:38 | 显示全部楼层
从语言上看,已经很有深度了
回复 支持 反对

使用道具 举报

50

主题

134

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
358
金钱
358
注册时间
2014-5-21
在线时间
84 小时
发表于 2016-6-13 18:45:17 | 显示全部楼层
IIC总线由一条SDA数据线和一条SCL时钟线组成,在这两条线上可以挂载多个IIC设备,每个IIC设备都有自己的地址,这些地址由硬件的出厂固定地址位和可编程地址位组成,只有在两条线上传输的值是IIC设备的地址时,这个IIC设备才会作出响应。
挂多个设备是怎么确定地址的?可不可以详细讲讲这个地方呢?    貌似没有体现到地址呢?
回复 支持 反对

使用道具 举报

50

主题

134

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
358
金钱
358
注册时间
2014-5-21
在线时间
84 小时
发表于 2016-6-13 19:13:51 | 显示全部楼层
如果有多个IIC存在的话,是谁去识别ID。一个设备怎么知道其他设备的存在呢?


Memory Organization AT24C01A, 1K SERIAL EEPROM: Internally organized with 16 pages of 8 bytes each,
the 1K requires a 7-bit data word address for random word addressing.
AT24C02, 2K SERIAL EEPROM: Internally organized with 32 pages of 8 bytes each,
the 2K requires an 8-bit data word address for random word addressing.
AT24C04, 4K SERIAL EEPROM: Internally organized with 32 pages of 16 bytes each,
the 4K requires a 9-bit data word address for random word addressing.
AT24C08A, 8K SERIAL EEPROM: Internally organized with 64 pages of 16 bytes each,
the 8K requires a 10-bit data word address for random word addressing.
AT24C16A, 16K SERIAL EEPROM: Internally organized with 128 pages of 16 bytes
each, the 16K requires an 11-bit data word address for random word addressing.
这段话怎么理解?
回复 支持 反对

使用道具 举报

0

主题

1

帖子

0

精华

新手入门

积分
7
金钱
7
注册时间
2016-6-29
在线时间
0 小时
发表于 2016-6-29 14:14:35 | 显示全部楼层
很棒的笔记,谢谢分享
回复 支持 反对

使用道具 举报

13

主题

87

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
421
金钱
421
注册时间
2015-12-3
在线时间
46 小时
发表于 2016-8-1 18:41:21 | 显示全部楼层
请问你的是战舰V3的板子吗?你的宏定义是PB6,7还是PB10,11??
我的前者按着视频里不行,改为重映射的就行??你的是吗?
学到老,活到老
回复 支持 反对

使用道具 举报

7

主题

102

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
299
金钱
299
注册时间
2016-4-10
在线时间
48 小时
发表于 2016-8-1 23:38:54 | 显示全部楼层
楼主很细心   讲的很详细
回复 支持 反对

使用道具 举报

2

主题

12

帖子

0

精华

新手上路

积分
26
金钱
26
注册时间
2017-3-14
在线时间
9 小时
发表于 2017-3-17 21:44:47 | 显示全部楼层

原子哥,这里读字节中的receive的各个操作有点看不懂,能不能给我讲讲?
谢谢
回复 支持 反对

使用道具 举报

8

主题

145

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
462
金钱
462
注册时间
2016-12-14
在线时间
75 小时
发表于 2017-3-18 15:39:27 | 显示全部楼层
收藏了。。。。。。。
书山有路勤为径,学海无涯苦作舟!
回复 支持 反对

使用道具 举报

39

主题

174

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
450
金钱
450
注册时间
2017-1-17
在线时间
76 小时
发表于 2017-3-18 16:08:26 | 显示全部楼层
顶一个
回复 支持 反对

使用道具 举报

13

主题

314

帖子

0

精华

高级会员

Rank: 4

积分
713
金钱
713
注册时间
2012-7-20
在线时间
102 小时
发表于 2017-3-18 18:40:40 | 显示全部楼层
挺好的!
回复 支持 反对

使用道具 举报

24

主题

57

帖子

0

精华

高级会员

Rank: 4

积分
800
金钱
800
注册时间
2016-11-25
在线时间
93 小时
发表于 2017-4-1 21:11:13 | 显示全部楼层
有感触啊
回复 支持 反对

使用道具 举报

4

主题

11

帖子

0

精华

新手上路

积分
31
金钱
31
注册时间
2017-3-21
在线时间
8 小时
发表于 2017-4-6 21:00:26 | 显示全部楼层
IIC_SCL=0; IIC_SDA=0;//SDA由低跳到高 delay_us(4); IIC_SCL=1; IIC_SDA=1;//发送I2C总线结束信号
回复 支持 反对

使用道具 举报

4

主题

11

帖子

0

精华

新手上路

积分
31
金钱
31
注册时间
2017-3-21
在线时间
8 小时
发表于 2017-4-6 21:01:41 | 显示全部楼层
为什么这个函数里面信号都是低电平跳转到了高电平,不是说在时钟信号为高的时候 数据显得信号跳变的么。。有点不懂
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-8-22 08:42

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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