STM32的IIC应用详解2

发布者:trendsetter10最新更新时间:2018-09-11 来源: eefocus关键字:STM32  IIC应用 手机看文章 扫描二维码
随时随地手机看文章

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通信协议,具体怎么使用得看不同外设的通信方式是怎么规定的。这些就只能见招拆招了,嘿嘿,至此,小编啰嗦完毕!


关键字:STM32  IIC应用 引用地址:STM32的IIC应用详解2

上一篇:STM32的IIC应用详解3
下一篇:STM32的IIC应用详解1

推荐阅读最新更新时间:2024-03-16 16:13

STM32库函数和寄存器的区别
库函数版和寄存器版的系统时钟设置的区别: **1.**库函数的目的是让用户应用的,而寄存器更加原始 库函数的系统时钟是默认设置的,且放在启动文件里。而寄存器版的系统时钟是Stm32_Clock_Init(336,8,2,7);. **2.**库函数的快捷的,但不是每个芯片都有的;寄存器是复杂的,但是每个芯片厂商都有提供系统的寄存器设置信息。 分别打开库函数和寄存器版的I/O口设置: 库函数: RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE);gotoh后先通过assert_param();函数检查格式是否正确同时只要是ENABLE,RCC- AHB1ENR |=
[单片机]
<font color='red'>STM32</font>库函数和寄存器的区别
stm32矩阵键盘原理图及程序介绍
STM32F0 系列产品基于超低功耗的 ARM Cortex-M0 处理器内核,整合增强的技术和功能,瞄准超低成本预算的应用。该系列微控制器缩短了采用 8 位和 16 位微控制器的设备与采用 32 位微控制器的设备之间的性能差距,能够在经济型用户终端产品上实现先进且复杂的功能。本文为大家介绍stm32矩阵键盘原理图及程序 stm32矩阵键盘原理图 stm32矩阵键盘程序介绍 主要实现:扫描矩阵键盘,将检测到的数据通过spi 通信发送到数码管显示。 主要步骤: 1:初始化时钟 void RCC_Configuration(void) { //----------使用外部RC晶振----------- RCC_DeIn
[单片机]
<font color='red'>stm32</font>矩阵键盘原理图及程序介绍
STM32为什么需要模块的DeInit()函数
简介:一直有一个疑惑,为什么Stm32的每个模块基本上都有一个DeInit()函数。这个函数是否和Init()函数在功能上重复了。查过一部分资料以后,发现有以下的说法。 在main()函数开始时,不管各模块处于什么状态,先执行该模块的DeInit()操作,然后在程序中较晚的时间或真正需要时再开启相应的模块。这样保证在刚进入调试状态时,调试器能够有充足的时间完成初始化和下载程序的操作。先执行该模块的DeInit()操作的目的是为了关闭哪些上一次操作开启的模块。
[单片机]
浅谈STM32 模数转换器 (ADC)(下)
温度传感器和VRENFINT通道框图 要使用传感器,请执行以下操作: 选择 ADC1_IN16 或 ADC1_IN18 输入通道。 选择一个采样时间,该采样时间要大于数据手册中所指定的最低采样时间。 在 ADC_CCR 寄存器中将 TSVREFE 位置 1,以便将温度传感器从掉电模式中唤醒。 通过将 SWSTART 位置 1(或通过外部触发)开始 ADC 转换 读取 ADC 数据寄存器中生成的 V SENSE 数据 使用以下公式计算温度: 温度(单位为 °C)= {(V SENSE — V 25 ) / Avg_Slope} + 25 其中: — V 25 = 25 °C 时的 V SENSE 值 — Avg
[单片机]
浅谈<font color='red'>STM32</font> 模数转换器 (ADC)(下)
STM32——MDK4与MDK5中对于数据类型的不同
首先我们来看MD4中的对于数据类型的定义: 然后我们跳转到其定义处查看对其的定义: typedef unsigned long u32; typedef unsigned short u16; typedef unsigned char u8; /*首先我们来认识typedef,这是用来为复杂的声明定义简单的别名,也就是说,我们可以用它来给我们的数据类型来进行定义。*/ /* 然后我们再来看之后的unsigned,unsigned用于限定后面的为无符号类型,如果后面不加什么的话,就默认为unsigned int。*/ /*unsigned long 无符号长数据 unsigned char 无符号字符型 u
[单片机]
STM32的GPIO输入输出模式配置
最近在看数据手册的时候,发现STM32的GPIO输入输出模式的配置种类有8种之多(输入和输入各4种): (1)GPIO_Mode_AIN模拟输入 (2)GPIO_Mode_IN_FLOATING浮空输入 (3)GPIO_Mode_IPD下拉输入 (4)GPIO_Mode_IPU上拉输入 (5)GPIO_Mode_Out_OD开漏输出 (6)GPIO_Mode_Out_PP推挽输出 (7)GPIO_Mode_AF_OD复用开漏输出 (8)GPIO_Mode_AF_PP复用推挽输出 我们平时接触的最多的也就是推挽输出、开漏输出、上拉输入这三种,但对于各种模式下IO口的内部电路和典型应用,STM32的数据手册中也未曾做过详细的说明和归纳
[单片机]
STM32高级开发(13)-Ubuntu下的串口助手minicom
在这么长时间里我们在Ubuntu上调试stm32,大家在使用串口的时候是不是一直都是在宿主机上的串口助手中查看串口信息呢?来回切换是不是很麻烦?那么在这篇中我们就来介绍一下在Ubuntu下的串口助手,或者准确点说应该叫串口终端,它就是minicom。 终端与串口助手的区别 在我们正式介绍minicom之前,我们首先来关注一个问题即:终端与串口助手有什么区别?(注意这里的终端不是指Ubuntu的shell指令终端,而是说串口软件终端) 其实如果大家接触过Linux嵌入式开发应该就很明白这其中的差别了,不过鉴于大家可能之前没有接触过Linux嵌入式开发,我们这里就为大家详细的讲解一下他们。 在Linux嵌入式开发中,很多时
[单片机]
<font color='red'>STM32</font>高级开发(13)-Ubuntu下的串口助手minicom
STM32单片机中断详解
中断,在单片机中占有非常重要的地位。代码默认地从上向下执行,遇到条件或者其他语句,会按照指定的地方跳转。而在单片机执行代码的过程中,难免会有一些突发的情况需要处理,这样就会打断当前的代码,待处理完突发情况之后,程序会回到被打断的地方继续执行。 1 EXTI控制器 外部中断/事件控制器(EXTI)管理了控制器的 23 个中断/事件线。每个中断/事件线都对应有一个边沿检测器,可以实现输入信号的上升沿检测和下降沿的检测。EXTI 可以实现对每个中断/事件线进行单独配置,可以单独配置为中断或者事件,以及触发事件的属性。 外部信号进入经过1的边沿检测电路,检测是否符合(有2和3的上升沿和下降沿选择寄存器决定),产生信号,然后和4软件
[单片机]
<font color='red'>STM32</font>单片机中断详解
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved