Bootstrap

基于Stm32f103硬件iic驱动LM75A温度传感器

这是LM75A温度传感器的概述,本文主要介绍基于Stm32f103的硬件iic驱动LM75A温度传感器。

这是我所使用的硬件电路,很简单。

对于该传感器的使用,主要是读取温度值,查看数据手册我们知道需要利用iic通讯读取。

首先我们要知道什么是iic?简单来说它是一种常用的板级通讯协议,对于详细iic的学习,可以参考iic协议规范,我也不会,暂时只是学会最初步的使用,遇到问题再查看解决吧。

下面来说说,如何使用stm32f103标准库的硬件iic。

首先我们需要初始化iic

void I2C1_Init(void)
{
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
    
    GPIO_InitTypeDef GPIOB_InitStrcture;
    GPIOB_InitStrcture.GPIO_Mode=GPIO_Mode_AF_OD;
    GPIOB_InitStrcture.GPIO_Pin=GPIO_Pin_6 | GPIO_Pin_7;
    GPIOB_InitStrcture.GPIO_Speed=GPIO_Speed_50MHz;
    
    GPIO_Init(GPIOB,&GPIOB_InitStrcture);
    
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);
    
    I2C_InitTypeDef I2C1_Initstrcture;
    I2C1_Initstrcture.I2C_Ack=I2C_Ack_Enable;
    I2C1_Initstrcture.I2C_AcknowledgedAddress=I2C_AcknowledgedAddress_7bit;
    I2C1_Initstrcture.I2C_ClockSpeed=200000;
    I2C1_Initstrcture.I2C_DutyCycle=I2C_DutyCycle_2;
    I2C1_Initstrcture.I2C_Mode=I2C_Mode_I2C;
    I2C1_Initstrcture.I2C_OwnAddress1=HostAddress;
    
    I2C_Init(I2C1,&I2C1_Initstrcture);
    I2C_Cmd(I2C1,ENABLE);
}

Stm32f103的iic1的SDA,SCL与PB6、PB7是复用的,所以要如上初始io口和iic1。(其中有几点说明:一、GPIO.Mode需要设置成复用开漏输出。二、HostAddress为主机地址可自行设置(我使用的0xcc)。三、I2C_ClockSpeed一般不能超过400000。

参照前面数据手册图10(读包含指针字节的temp寄存器)建议查阅一下数据手册,你会明白这些寄存器的作用,这里暂时只会用到temp这个寄存器。由于我们需要读取MS、LS两个字节(实际只有11位见后文),所以我们需要编写一个读取多字节的关于iic的函数。

/I2C读取数据串(器件地址,寄存器,内部地址,数量)
void I2C1_Read_Buffer(uint8_t SlaveAddr,uint8_t ReadAddr,uint8_t* ReadBuffer,uint8_t Num)
{ 
    while(I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY));
    I2C_GenerateSTART(I2C1,ENABLE);//开启信号
    while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT));    //清除 EV5
    I2C_Send7bitAddress(I2C1,SlaveAddr, I2C_Direction_Transmitter); //写入器件地址
    while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED));//清除 EV6
    I2C_SendData(I2C1,ReadAddr); //发送读的地址
    while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED)); //清除 EV8
    I2C_GenerateSTART(I2C1,ENABLE); //开启信号
    while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT)); //清除 EV5
    I2C_Send7bitAddress(I2C1,SlaveAddr,I2C_Direction_Receiver); //将器件地址传出,主机为读
    while(!I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)); //清除EV6
    while(Num)
    {
        if(Num == 1)//只剩下最后一个数据时进入 if 语句
        { 
             I2C_AcknowledgeConfig(I2C1,DISABLE); //最后有一个数据时关闭应答位
             I2C_GenerateSTOP(I2C1,ENABLE);    //最后一个数据时使能停止位
        }
        if(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED))//读取数据
        { 
             *ReadBuffer = I2C_ReceiveData(I2C1);//调用库函数将数据取出到 Buffer
             ReadBuffer++; //指针移位
             Num--; //字节数减 1 
        }
    }
    I2C_AcknowledgeConfig(I2C1,ENABLE);
}
    

慢慢对照上面图10看,都是一一对应的!!!!(

唯一注意的是:你可能会有疑问为什么最后的while会这样写呢?那是因为应答的原因,仔细看图10最后一次接受数据后,需要关闭应答。对于其中清除EV,在参照下图的情况下打开标准库函数看看,每个事件代表的含义。

有了iic读取函数后就好办了,那就只需要把读取的数据进行处理了。

结合这两张图你就可以清楚明白它的数据是如何处理的了,特别注意,如果是负温度,需要将读取的数据转化成二进制补码后再进行温度值转化。简而言之,就是把后面10位二进制转化为十进制再乘以精度0.125得到的就是实际的温度值,下面是代码。

//读出LM75A的温度值(-55~125摄氏度)
//温度正负号(0正1负),温度整数,温度小数(点后2位)依次放入*Tempbuffer(十进制)
void LM75A_GetTemp(uint8_t *Tempbuffer)
{   
  uint8_t buf[2]; //温度值储存
  uint8_t t=0,a=0;   
    
  I2C1_Read_Buffer(LM75A_ADD,0x00,buf,2); //读出温度值(器件地址,子地址,数据储存器,字节数)
    t = buf[0]; //处理温度整数部分,0~125度
    *Tempbuffer = 0; //温度值为正值
    if(t & 0x80)//判断温度是否是负(MSB表示温度符号)
    { 
        *Tempbuffer = 1; //温度值为负值
        t = ~t;
        t++; //计算补码(原码取反后加1)
    }
    if(t & 0x01){ a=a+1; } //从高到低按位加入温度积加值(0~125)
    if(t & 0x02){ a=a+2; }
    if(t & 0x04){ a=a+4; }
    if(t & 0x08){ a=a+8; }
    if(t & 0x10){ a=a+16; }
    if(t & 0x20){ a=a+32; }
    if(t & 0x40){ a=a+64; }
    Tempbuffer++;
    *Tempbuffer = a;
    a = 0;
    t = buf[1]; //处理小数部分,取0.125精度的前2位(12、25、37、50、62、75、87)
    if(t & 0x20){ a=a+12; }
    if(t & 0x40){ a=a+25; }
    if(t & 0x80){ a=a+50; }
    Tempbuffer++;
    *Tempbuffer = a;   
}

对于温度处理的代码,你可能会有这些疑问:一、第一个if语句是再干嘛,那是在对如果D10为1(即负温度情况下的数据去补码)二、为什么a的值是这样加的,这里特别注意,我这里是将小数部分,整数部分分开处理的,并且a所加的值,已经是对应数据*0.125以后的实际温度值!!!这里可以参照上图我自己注明的数据转化过程。

最后贴上我的主函数,你就会更加明白数据的整数、小数转化过程

#include "headfile.h"

uint8_t buffer[3]={0};
int main()
{
    RCC_Init();
    TM1640_Init();
    I2C1_Init();
    
    while(1)
    {
        LM75A_GetTemp(buffer); //读取LM75A的温度数据
        
        TM1640_Show(1,buffer[1]/10); //显示数值
        TM1640_Show(2,buffer[1]%10+10);
        TM1640_Show(3,buffer[2]/10);
        TM1640_Show(4,buffer[2]%10);

  }


}

我的整数、小数也是分开显示的,相当于只看数,不管大小。

如有错误,敬请指出,在错误中进步。

;