# 嵌入式_I2C总线温度传感器驱动(以CT75为例)

嵌入式_I2C总线温度传感器驱动(以CT75为例)

最近使用GD32做控制核时使用到几种I2C总线类型的温度传感器,国产的有CT75和SD5075两种类型,驱动虽然比较简单,但这里做个简单总结,记录一下注意事项和坑。



前言

注:本项目基于GD32F03RET6硬件平台, 使用标准库GD32F10x_Firmware_Library_V1.0.0(提示:此库坑多、慎用!)


一、什么是I2C总线类型的温度传感器

个人理解就是支持I2C总线传输数据的一种传感器,一般是作为从机。
MCU可以通过I2C总线对温度传感器进行读写配置或读取温度数据等。

二、写驱动步骤

1.芯片手册

读懂和使用的传感器芯片手册是非常重要的一步。一般芯片手册前几页都是介绍电器特性和封装方式的,软件工程师一般可以跳过,直接看
.芯片手册寄存器和时序图,

1.写操作时序图,

(MCU为主机,温度芯片为从机)
以7位地址写数据为例,下图是一个向寄存器写数据的时序图,常用作写芯片配置寄存器
1.为芯片作为从机的I2C地址,第0位为0,表示写操作,主机把地址发到总线上等待ACK,匹配到的从机从机会回复一个ACK
2.主机收到ACK后,再发送一个寄存器地址(手册标注寄存器读写权限),表示即将操作该寄存器,然后从机回复一个ACK
3.主机收到ACK后,发送第一个字节数据,然后从机回复一个ACK
4.主机收到ACK后,再发送第二个字节数据,然后从机不再回复ACK,结束
芯片手册会标注1、2字节哪一个是高字节哪一个是低字节
在这里插入图片描述

2.读操作时序图,

常用作读芯片温度寄存器
1.为芯片作为从机的I2C地址,第0位为0,表示写操作,主机把地址发到总线上等待ACK,匹配到的从机从机会回复一个ACK
2.主机收到ACK后,再发送一个寄存器地址(手册标注寄存器读写权限),表示即将操作该寄存器,然后从机回复一个ACK
3.主机收到ACK后,再重新发送起始信号和从机地址,第0位为1,表示读操作,然后等待从机回复一个ACK
4.从机发送一个8位数据帧,主机给回复ACK,
5.从机收到回复后再发送一个8位数据帧,主机不发送ACK,然后发送STOP信号,至此传输结束。
在这里插入图片描述

获取数据代码如下:

uint16_t CT75_GetTemperature(uint8_t vTempId)
{
	uint16_t Temp = 0x0000;
	
	/*local temperature*/
	sw_i2c_start();
	sw_i2c_write_byte(CT75_I2C_ADDR_WRITE);
	sw_i2c_wait_ack();
	sw_i2c_write_byte(CT75_REG_DATA_ADDR);
	sw_i2c_wait_ack();
	sw_i2c_stop();
	i2c_delay_us(2);
	sw_i2c_start();        
	sw_i2c_write_byte(CT75_I2C_ADDR_READ);
	sw_i2c_wait_ack();
	Temp = (Temp | sw_i2c_read_byte()<<8);
	sw_i2c_send_ack();
	Temp = Temp | sw_i2c_read_byte();
	sw_i2c_send_nack();
	sw_i2c_stop();
	
	return Temp;

3.温度计算

手册如图:
在这里插入图片描述
翻译一下大致意思就是,温度数据存储在只读温度寄存器中,将EM位设置为’0’或’1’表示12位二进制格式或13位二进制格式。这个2字节的温度数据必须在每个读取周期中同时读取,第一个字节是MSB,第二个字节是LSB,怎么来计算呢?
一般在计算机中,正负数据都是依照其补码的形式存在的(最高位1表示负数),目的是为了方便将符号 ‘-’ 纳入计算(此处不赘述),因为正数补码是其本身,负数补码是其符号位不变取反+1所得,所以你看到的上述表格二进制都是数字的补码,现在就是要先判断正符号的情况下求源码,两种方法:
(1)如果补码的符号位为“1”,表示是一个负数,那么求给定的这个补码的补码就是要求的原码。
如:-1的补码是(11111111b)→按符号位保持不变其余各位取反,得到(10000000b)→加1后得到(10000001b)
所以-1的”补码的补码”就是原码(1000001b)。
(2)如果补码的符号位为“1”,表示是一个负数,那么补码减1,再将符号位保持不变其余各位取反
-1的补码是(11111111b)→减1(11111110b)将符号位保持不变其余各位取反(10000001b)

例如,得到的12位二进制为:1111 0000 1100
取反:0000 1111 0011
加 1:0000 1111 0100(244)
分辨率:(0000 0000 0001) = 0.0625,
所以最终温度T为:-(244 * 0.0625) = - 15.25℃

一般情况下普遍认为这种计算方法没有问题,但是有人提出另外一种不一样的理解方式,就是高低字节分开存储,看到过有人争论结果不一样,个人认为可能是补码计算方式没搞清,这里举TMP42芯片的手册简单说一下。
在这里插入图片描述
将高字节数据和低字节数据分开列表的,而且给出以下说明:
在这里插入图片描述
翻译以下就是:注意,最终的数值结果是高字节和低字节的和。在负温度下,unsigned low字节与负high字节相加得到的值小于high字节(例如,-15 + 0.75 = -14.25,而不是-15.75)。
同例:得到的12位二进制为:1111 0000(高位) + 1100(低位)
高位取反:0000 1111
高位加 1:0001 0000(16)
低位得到:1100 (0.75)
所以最终温度T为:-16 + 0.75 = - 15.25℃
结果也是一样的,所以没什么可争论的。

计算代码如下:

static float CT75_GetTemperature() 
{

  uint16_t Temp;
  uint8_t temp_high, temp_low;
  float vTempFloat = 1.0f;
  
  Temp = CT75_GetTemperature();
  temp_high = (Temp & 0xFF00) >> 8;
  temp_low  = Temp & 0x00FF);
  
  if (temp_high & 0x80)
  {
    vTempFloat = -1.0f;
    temp_high = ~temp_high + 1;   
  }
    vTempFloat *= temp_high;
    vTempFloat = vTempFloat  + (temp_low >> 4)*0.0625;
  
  return vTempFloat;
}

2.I2C驱动

一般使用软件I2C进行模拟,此处不再赘述,
可以参见我的另一篇博客:https://blog.csdn.net/Yin_w/article/details/129454353?spm=1001.2014.3001.5501
根据时序图,温度数据寄存器地址为 0x00,所以读取温度函数实现如下,不同芯片支持的IIC时序延时稍有不同,注意根据手册修改,

在这里插入图片描述
在这里插入图片描述


总结

几乎所有总线类的温度芯片操作方式几乎都一样,只需要根据手册知道其地址序列、寄存器地址、读写步骤和计算方式即可。
值得注意的是:无论使用软件IIC还是硬件IIC,都需要外部上拉,使用之前记得先测一下上拉和通断,以免硬件挖坑

  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值