历史上的今天
返回首页

历史上的今天

今天是:2024年09月11日(星期三)

正在发生

2018年09月11日 | STM32的IIC应用详解2

2018-09-11 来源:eefocus

IIC简单介绍


小编能力有限,写的不对处还望诸位大侠指正哈!


      平时所说的IIC通信指的是用单片机的两个I/O端口模拟出来的IIC,正真的IIC实际上是一块硬件电路,那是飞利浦公司的专利,要想用那就拿钱来买。有大牛既想用又不想花钱,就用两个端口模拟出了IIC通信协议,因为方便(51上的IIC改一下端口配置就可以在STM32F103上使用)所以被广泛使用。啰嗦了这么多,下面进入正题,嘿嘿。


      首先IIC通信由两根线组成: 

                时钟线SCL:在通信过程起到控制作用。 

                数据线SDA:用来一位一位的传送数据。 

      其次IIC通信过程由开始、结束、发送、接收四个函数构成,接下来小编通过介绍这四个函数来介绍IIC通信协议。


      先记住两个概念,很重要: 

                1、(在发送、接收数据的时候)当SCL为高电平时,SDA线不允许变化;当SCL线为低电平时,SDA线可以任意0、1变化。 

                2、(在任意时候)只有当SCL为高电平时,IIC电路才对SDA线上的电平(0或者1)进行记录(这个记录小编把它叫做采样),当SCL线为低电平时,无论SDA是高还是低,IIC电路都不对SDA进行采样。


(假设我现在有一个单片机和外设进行IIC通信,两根线初始状态均为高电平)

 

开始信号


      IIC协议规定:当SCL为高电平时,SDA由高电平变成低电平,认为这是IIC通信的开始信号。具体代码实现如下:


void MPU_IIC_Start(void)

{

    MPU_SDA_OUT();     //sda线输出

    MPU_IIC_SDA=1;        

    MPU_IIC_SCL=1;

    MPU_IIC_Delay();

    MPU_IIC_SDA=0;//SDA线由高变低

    MPU_IIC_Delay();

    MPU_IIC_SCL=0;

}     

      如上述代码所示,起始状态SCL和SDA均为高点平,延时下(一般4.7us左右),之后拉低SDA,这样起始信号就产生了,外设的IIC接口一收到这种电平变化就认为 哦哦,要开始IIC通信了。最后一句拉低SCL的操作小编认为是一是为了允许SDA线0、1变化;二是为了防止外设的IIC对SDA线进行采样。


结束信号


      IIC协议规定:当SCL为高电平时,SDA由低电平变成高电平,认为这是IIC通信的结束信号。具体代码实现如下:


void IIC_Stop(void)

{

    SDA_OUT();//sda线输出

    IIC_SCL=0;

    IIC_SDA=0;

    delay_us(4); 

    IIC_SCL=1;

    delay_us(4); 

    IIC_SDA=1;//发送I2C总线结束信号                             

}

      如上述代码所示,先把SCL拉低允许SDA变化,再把SDA拉低(为拉高做准备,哈哈)延时,再把SCL拉高,(让外设的IIC电路采集SDA线上的电平0)再延时(外设采样需要花时间)之后拉高SDA(因为SCL已经为高了,所以外设直接就采样了)。这样结束信号就产生了,外设IIC接收到这种电平变换意识到 哦哦 IIC通信结束了。


应答信号


      IIC协议规定,当接受到一个字节(8bit)后,数据接收方必须向数据发送方返回一个低电平信号,此信号称作应答信号(表示上一个数据成功接受可以继续接受)。若未返回应答信号,则认为数据接收方出现故障。由于单片的这端是IIC程序,而外设那端是IIC电路,所以当单片机发送数据时,外设的IIC电路会自动返回应答信号(前提外设没故障,嘿嘿)。当单片机接收数据的时候,应答信号就得我们自己写了。 

      //应答信号具体实现如下:


void IIC_Ack(void)

{

    IIC_SCL=0;

    SDA_OUT();

    IIC_SDA=0;

    delay_us(2);

    IIC_SCL=1;

    delay_us(2);

    IIC_SCL=0;

}

      如上代码所示,先把时钟线拉低,再把数据线拉低,最后把始终先拉高,这样就告诉外设赶紧把数据线上的低电平才进去,应答信号就这样反回了,是不是很简单呢。非应答信号的代码如下,也很近单,小编就不啰嗦了。


void IIC_NAck(void)

{

    IIC_SCL=0;

    SDA_OUT();

    IIC_SDA=1;

    delay_us(2);

    IIC_SCL=1;

    delay_us(2);

    IIC_SCL=0;

}           

发送函数


      发送数据就是把字节一位一位的发送出去,具体实现如下:


void IIC_Send_Byte(u8 txd)

{                        

    u8 t;   

    SDA_OUT();      

    IIC_SCL=0;

    for(t=0;t<8;t++)

    {              

        IIC_SDA=(txd&0x80)>>7;//把要发送的数据的最高位放到数据线上

        txd<<=1;//次高位变最高位(为下次发送做准备)       

        delay_us(2);   //必须延时

        IIC_SCL=1;//拉高时钟线,告诉外设可以采样了

        delay_us(2); 

        IIC_SCL=0;//拉低时钟线,允许数据线发生变化

        delay_us(2);

    }    

}   

      对了单片机发送完一个字节后面必须跟一个等外应答函数,万一外设挂了呢,单片机还在傻傻的发送,好可怜呢?具体实现如下:


u8 IIC_Wait_Ack(void)

{

    u8 Time=0;

    SDA_IN();        

    IIC_SDA=1;

    delay_us(1);       

    IIC_SCL=1;

    delay_us(1);     

    while(IIC_SDA)

    {

        Time++;

        if(Time>250)

        {

            IIC_Stop();

            return 1;

        }

    }

    IIC_SCL=0;     

    return 0;  

      这段代码很简单,就是先让SDA=1,再判断在一定时间内SDA是否变为0,从而识别出外设有没有发送应答信号。这里就不赘述了。


接受函数


      跟发送一样,只是把数据一位一位接受进来,记得要返回应答信号哟。具体实现如下:


u8 IIC_Read_Byte(unsigned char ack)

{

    unsigned char i,receive=0;

    SDA_IN();

    for(i=0;i<8;i++ )

    {

        IIC_SCL=0; 

        delay_us(2);

        IIC_SCL=1;

        receive<<=1;

        if(IIC_SDA)receive++;   

        delay_us(1); 

    }                    

    if (!ack)

        IIC_NAck();//非应答

    else

        IIC_Ack(); //应答   

    return receive;

}

 

      首先我们要确定这个字节接收完毕后还需不需要继续接受字节,继续ACK=1,不继续ACK=0。循环中,时钟线拉低,先允许外设把数据线0、1变换,在时钟线拉高,禁止数据线变化(把外设送到数据线上的电平固定住)。 当i=0时,receive<<=1;不起任何作用,但是以后就有用了,有大用处。再判断下数据线上电平是高还是低,假设IIC_SDA=1,则receive++就是把外设输出的1方到receive的最低位上去,这样一位数据就接受进来了。循环第二次,此时i=1,仍旧数据线拉低,再拉高,先允许变化再固定,receive<<=1起作用了,把刚才接受到的1移到次低位上去,给即将要接收的电平腾个地,之后的在判断什么什么的就都一样了哈,读者自己分析。八次循环以后,一个字节就接受到了。别忘了应答信号哟。最后把接受到了的数据返回,则一个字节就真正接收到了。是不是很简单呢? 

      上述几个函数是IIC通信协议,具体怎么使用得看不同外设的通信方式是怎么规定的。这些就只能见招拆招了,嘿嘿,至此,小编啰嗦完毕!


推荐阅读

史海拾趣

Collins Electronics Corp公司的发展小趣事

Collins Electronics Corp的创始人在电子领域拥有深厚的背景和丰富的经验。在公司创立初期,他们发现市场上的电子设备在性能和稳定性上存在巨大的提升空间。于是,他们决定创立一家公司,专注于研发和生产高品质的电子设备。经过多次试验和改进,Collins Electronics Corp推出了他们的首款产品,一款高性能的信号放大器。这款产品凭借其卓越的性能和稳定性,在市场上获得了极大的成功,也为公司的后续发展奠定了坚实的基础。

岑科(CENKER)公司的发展小趣事

岑科公司成立于2001年,初期主要从事电子元器件的贸易业务。在创始人蔡旌章的带领下,岑科以优质的服务和灵活的运营策略,在国内外市场上赢得了良好的口碑。这一时期,岑科的服务对象主要是海内外的电子元器件需求商,通过精准把握市场需求和优质的产品供应,逐渐在电子元器件贸易领域站稳了脚跟。随着业务的不断拓展,岑科开始思考如何进一步提升自身的竞争力,以实现更长远的发展。

Corning Cable Systems公司的发展小趣事

在深海光缆领域,Corning Cable Systems公司也展现出了强大的实力。公司成功研发出适用于深海环境的光缆产品,并在多个国际项目中得到了广泛应用。这些深海光缆不仅具有优异的传输性能,还能够在极端恶劣的海底环境下保持长期稳定运行,为跨洋通信提供了可靠的保障。

Electro-Films Inc Semi-Films Div公司的发展小趣事

随着市场的扩大和竞争的加剧,Semi-Films Division 意识到品质是品牌的核心。因此,公司加大了对产品质量控制的投入,引入了先进的生产设备和检测手段,确保每一批产品都符合客户的要求。同时,公司还建立了完善的质量管理体系,对生产过程进行全程监控,确保产品质量的稳定性和可靠性。这些努力使得 Semi-Films 的产品在市场上赢得了良好的口碑。

电连(ECT)公司的发展小趣事

ECT在射频连接器领域取得了显著的技术突破。从2006年到2008年,公司开始研发射频同轴连接器,并在2009年实现精密射频同轴连接器的量产,并成功获得专利。这一技术突破为ECT在射频连接器市场赢得了重要地位,也为公司后续的发展奠定了坚实的基础。

AC Photonics Inc公司的发展小趣事

随着技术的成熟,AC Photonics Inc开始积极拓展市场。公司不仅在国内建立了完善的销售网络,还积极开拓海外市场。同时,AC Photonics Inc还与其他知名电子企业建立了战略合作关系,共同推动光电技术在各个领域的应用。这些合作不仅提升了公司的知名度和影响力,还为公司的长远发展提供了有力支持。

问答坊 | AI 解惑

后级是用IGBT管子的电鱼器

后级是用IGBT管子的电鱼器…

查看全部问答>

频谱仪与矢量信号分析仪的区别

矢量网络分析仪  对于频谱分析和电磁干扰测量来说,频谱分析仪是通信测量仪器中常用的设备,由于具有大于1∞dB的动态范围、低于-110dBc/Hz的噪声、1Hz-100Hz的带宽、50GHz以上的频率范围,能够接收到极微弱的信号和分辨出两个幅度相差很大的信号。频 ...…

查看全部问答>

DM642外部两个中断不同时发生,怎么得到两个中断之间的时间呢?

我现在使用的是DM642,ext_int5,ext_int6分别用作两个外部中断信号 相信大家也遇到过这样的问题,比如一个车轮压在前后两个磁钢上,这两个磁钢分别产生中断信号送给CPU,请问这两次中断之间的时间应该怎么计算呢? 我现在想的是:第一个中断发生 ...…

查看全部问答>

运放经典

本帖最后由 paulhyde 于 2014-9-15 04:26 编辑 运放经典 运放经典  …

查看全部问答>

9G-LINUX嵌入式开发书籍推荐(附WINCE部分)

来源:我的博客:http://blog.163.com/yuan_xihua/blog/static/3074054420087135650488/ 一,编程语言部分1,C语言 《C语言大全(第四版)》  市场价 :¥48.00 【原 书 名】 The Complete Referene,Fourth Edition   【 ...…

查看全部问答>

s3c2410 Nand flash 驱动问题

在看2.4.18内核的关于三星的nand flash 驱动时遇到一个地方没有看明白,请指教 使用的nand flash 为 k9f1208 其中有个函数:作用是向flash发送一个地址 static void s3c2410_command (struct mtd_info *mtd, unsigned command, int column, int ...…

查看全部问答>

招聘 兼职嵌入式Linux讲师 (上海)

招聘嵌入式Linux讲师,工作地点上海,要求如下: 1、具有3年或以上相关领域工作经验 2、熟悉嵌入式Bootloadr 3、熟悉Linux 内核及实时系统 4、熟悉Linux驱动 5、熟悉Linux设备驱动 6、熟悉嵌入式文件系统 工作时间可在周末,一经录用 ...…

查看全部问答>

NI 在线研讨会(明天)

与时俱进的LabVIEW 2010   Friday, September 17, 2010 2:00 PM - 4:00 PM CST   Webinar Registration       作为图形化系统设计的平台, NI LabVIEW帮助世界上的工程师与科学家们实现了一个又 ...…

查看全部问答>

【白皮书分享】为无线扩容铺平道路

作者:Ralf Bendlin,德州仪器系统工程师Tony Ekpenyong,德州仪器系统工程师Debbie Greenstreet,德州仪器战略市场营销   摘要       智能手机与其它手持设备的发展以及其上数据消费应用的大量繁衍生息,不 ...…

查看全部问答>

INOUT引脚:在FPGA中使用方法

INOUT引脚: 1.FPGA IO在做输入时,可以用作高阻态,这就是所说的高阻输入; 2.FPGA IO在做输出时,则可以直接用来输入输出。 芯片外部引脚很多都使用inout类型的,为的是节省管腿。就是一个端口同时做输入和输出。 inout在具体实现上一般用 ...…

查看全部问答>