【专为人体测温优化的高精度数字温度传感器——GXT310,可替代CT7117,附STM32F103硬件IIC驱动代码及详细说明】
分享STM32F103硬件IIC驱动高精度数字温度传感器GXT310的调试心得
分享STM32F103硬件IIC驱动高精度数字温度传感器GXT310的调试心得
GXT310传感器概述
GXT310是一款专为人体测温优化的全集成数字式温度传感器,可用于消费电子、医疗温度计或高精度温度探头等应用中的温度测量。
GXT310无需任何外部感温单元即可实现16位温度输出,并且在30℃~45℃温度范围内具有小于±0.1℃的测温误差。每颗芯片在出厂时均已完成精密校准,用户无需对温度输出进行任何额外补偿处理。
一、基本性能
• 测温范围:-55℃ ~ +150℃
• 最大精度:±0.1℃ (+30℃ ~ +45℃)
• 高分辨率:0.0078125℃@16bits
• 电源电压:1.6V ~ 5.5V
• 转换时间:50ms
• 低功耗:平均电流3μA@1Hz,关断电流0.5μA
• 数字输出:兼容SMBus、I 2 C接口
• 专为人体测温优化
二、引脚说明及参考电路


三、温度读取
1.通信说明
GXT310 使用指针寄存器来指示当前读写流程所操作的寄存器名称。指针寄存器是主机写操作的第二个字节,对 GXT310 的每次写操作都需要写入指针寄存器。两个数据字节紧随指针字节之后,代表即将写入指定寄存器中的数据。对 GXT310 的每次读操作都需要先修改指针寄存器,以指示本次读操作即将读取的寄存器名称。具体实现方法为先通过写操作发送指针字节,再发送启动条件,并设置读写标志位为 1b,以更改数据传输方向,从而允许 GXT310 向总线发送指针所选定目标寄存器的数据。
读写操作的具体时序如图 4 和图 5 所示。

2.温度格式

四、硬件IIC调试记录
1.硬件IIC初始化
软件模拟I2C直接使用CPU内核按照 I2C协议要求控制GPIO输出高低电平,而使用硬件I2C 可以直接通过外设寄存器来控制MCU产生 I2C 协议方式的通讯,而不需要内核直接控制引脚的电平。
本次调试采用的MCU型号是STM32F103C8T6,使用PB6和PB7复用为硬件IIC功能,下面代码是硬件IIC的初始化函数,每行代码都加了详细注释。
2.使用硬件IIC执行写命令时序
下图为STM32F103参考手册上的主发送器传输序列图,EVx为I2C通信过程中的各个事件,用户需要确保每个事件完成后才能开始下一事件,否则可能会发生数据混乱。例如向DR寄存器写入一个字节数据后,MCU会自动向从机设备传输这个字节,刚传输到一半,又向DR寄存器写入下一字节数据,这时传输数据就会出错,正确做法是等到上一字节传输结束再写入下一字节。搞懂这个原理后,写程序就容易多了,只需按照下面的传输序列图写就可以。
下图是STM32标准库列出的硬件I2C的各个事件,根据这些事件编写I2C读写函数。
下图是向IIC总线上某一地址设备的某一寄存器写入两个字节的函数,可以看到整个流程都是根据STM32F103参考手册提供的主发送器传输序列图写的,实际测试也没有问题。
3.使用硬件IIC执行读命令时序
使用硬件IIC执行写命令时序看起来和软件模拟IIC的流程差不多,按照这个思想编写读命令时序,如下图,但是当用示波器查看波形时发现了问题。。。

程序里写了接收两字节数据,但是从波形中可以看到实际接收了三个字节数据,那么最后的九个时钟是从哪来的?仔细查阅手册发现这么一段描述。
这段描述说明要想在最后一个字节后产生NACK和STOP信号,需要在接收最后一个字节之前(也就是倒数第二个字节之后)进行配置,因此把代码顺序调整一下,把产生NACK信号和设置停止信号放在接收两个字节之间,如下图。

调整代码后波形正常了,接收到0x0D98,按照GXT310的温度格式可以计算得到温度为27.1875℃。
小测试:如果把产生NACK信号代码去掉,那MCU在接收完最后一个字节后也产生ACK信号,而不是NACK,如下图。

至此调试结束。
五、硬件IIC驱动GXT310完整代码
在 I2C 通信中,如果从机不存在或未响应,上述代码中的while循环会因为无法满足事件条件而导致 STM32 卡死(死循环),因此需要通过添加超时机制来解决。完整代码如下。
5.1 iic.c
#include "iic.h"
static __IO uint32_t IICTimeout = 10000;
//初始化I2C接口为I2C主机模式
void IIC_INIT()
{
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //初始化GPIO的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); //初始化I2C的时钟
/*初始化GPIO*/
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //SDA和SCL的IO
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; //复用开漏输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO输出速率最大50mhz
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIO
/*初始化I2C接口*/
I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; //I2C主机模式
I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; //占空比
I2C_InitStructure.I2C_OwnAddress1 = 0x5F; //STM32 IIC自身设备地址,只要是总线上唯一即可
I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; //是否开启ACK
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; //使用7位地址模式
I2C_InitStructure.I2C_ClockSpeed = 100000; //I2C通信速率
I2C_Init(I2C1, &I2C_InitStructure); //初始化I2C接口
I2C_Cmd(I2C1, ENABLE); //开启I2C接口
}
//向IIC总线上的w_addr地址器件的point_reg寄存器写入两字节数据
void IIC_Write_TwoByte(u8 w_addr,u8 point_reg,u8 data1,u8 data2)
{
uint32_t timeout;
/*等待总线空闲*/
timeout = IICTimeout;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)) { if((timeout--) == 0) break;}
/*产生起始信号*/
I2C_GenerateSTART(I2C1, ENABLE);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) { if((timeout--) == 0) break;} //Test on EV5 and clear it
/*发送设备/从机地址 + 写标志*/
I2C_Send7bitAddress(I2C1, w_addr, I2C_Direction_Transmitter);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) { if((timeout--) == 0) break;}//Test on EV6 and clear it
/*发送写入的寄存器地址*/
I2C_SendData(I2C1, point_reg);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if((timeout--) == 0) break;} //Test on EV8 and clear it
/*写入一字节数据*/
I2C_SendData(I2C1, data1);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if((timeout--) == 0) break;}//Test on EV8 and clear it
/*写入一字节数据*/
I2C_SendData(I2C1, data2);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if((timeout--) == 0) break;}//Test on EV8 and clear it
/*发送停止信号*/
I2C_GenerateSTOP(I2C1, ENABLE);
}
//从IIC总线上的w_addr地址器件的point_reg寄存器读两个字节数据
u16 IIC_Read_TwoByte(u8 w_addr,u8 point_reg)
{
u16 data=0,data1=0,data2=0;
uint32_t timeout;
/*等待总线空闲*/
timeout = IICTimeout;
while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)) { if((timeout--) == 0) break;}
/*产生起始信号*/
I2C_GenerateSTART(I2C1, ENABLE);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) { if((timeout--) == 0) break;} //Test on EV5 and clear it
/*发送设备/从机地址 + 写标志*/
I2C_Send7bitAddress(I2C1, w_addr, I2C_Direction_Transmitter);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED)) { if((timeout--) == 0) break;} //Test on EV6 and clear it
/*发送写入的寄存器地址*/
I2C_SendData(I2C1, point_reg);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)) { if((timeout--) == 0) break;} //Test on EV8 and clear it
/*再次产生起始信号*/
I2C_GenerateSTART(I2C1, ENABLE);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT)) { if((timeout--) == 0) break;} //Test on EV5 and clear it
/*发送设备/从机地址 + 读标志*/
I2C_Send7bitAddress(I2C1, w_addr, I2C_Direction_Receiver);
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED)) { if((timeout--) == 0) break;} //Test on EV6 and clear it
I2C_AcknowledgeConfig(I2C1, ENABLE);
/*读取两字节数据*/
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) { if((timeout--) == 0) break;} //等待接收完成
data1 = I2C_ReceiveData(I2C1); //读取数据
I2C_AcknowledgeConfig(I2C1, DISABLE); //产生NACK信号
I2C_GenerateSTOP(I2C1, ENABLE); //设置停止信号
timeout = IICTimeout;
while(!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED)) { if((timeout--) == 0) break;} //等待接收完成
data2 = I2C_ReceiveData(I2C1); //读取数据
data=data1;
data=(data<<8)|data2;
return data;
}
void GET_GXT310_TEMP(void)
{
int16_t temp;
temp = (int16_t) IIC_Read_TwoByte(0x90,0x00);
printf("\r\nTEMP_LOCAL = %#X\r\n",temp); //温度原码
printf("\r\nTEMP_LOCAL = %f\r\n", temp*0.0078125);
}
5.2 iic.h
#ifndef _iic_H
#define _iic_H
#include "stm32f10x.h"
void IIC_INIT();
void IIC_Write_TwoByte(u8 w_addr,u8 point_reg,u8 data1,u8 data2);
u16 IIC_Read_TwoByte(u8 w_addr,u8 point_reg);
void GET_GXT310_TEMP(void);
#endif
欢迎各位伙伴咨询、测试GXT310,有任何问题可随时沟通交流。
更多推荐



所有评论(0)