前言
前面介绍了IIC通信原理(专栏 -> 串行通讯原理 -> 串行通讯 -- IIC通讯原理),TMP112是一款IIC通信的数字温度传感器,本篇通过TMP112数字温度传感器讲解IIC通信的应用方法。
一、TMP112介绍
1、器件地址和读写
IIC通信可以接多个从机,从机识别是7bit器件地址。TMP112器件地址和硬件连接有关,通过不同的连接,一条IIC总线可以连接几个TMP112。
器件地址 |
A0连接 |
1001000(0x48) |
GND |
1001001(0x49)
扫描二维码关注公众号,回复:
14727241 查看本文章
|
V+ |
1001010(0x4A) |
SDA |
1001011(0x4B) |
SCL |
IIC主机发送给从机的第一个字节格式是器件地址(7bit)+ 写/读(1bit)。所以A0接GND实际地址0x90是写,0x91是读。其他地址类似。
2、寄存器
TMP112寄存器地址如下:
寄存器地址 |
寄存器 |
0 |
温度寄存器 |
1 |
配置寄存器 |
2 |
下限寄存器 |
3 |
上限寄存器 |
IIC主机发送给从机的第二个字节是寄存器地址,表示需要写/读的是哪个单元或功能。对于TMP112,一般是读地址0的温度寄存器。
二、通信时序
下图是技术规格书的写时序,格式是:开始+器件地址(写)+寄存器地址+数据1+数据2+结束。
下图是技术规格书的读时序,格式是:
开始+器件地址(写)+寄存器地址(写)+结束
开始+器件地址(读)+数据1+数据2+停止。
三、例程
/***************************************
*I2C IO口定义 SCL SDA
***************************************/
#define SDA_HI GPIO_Init_Input(I2C_SDA) //SDA高,配置输入,通过上拉电阻拉高
#define SDA_LO GPIO_Output_Off(I2C_SDA) //SDA低
#define SCL_HI GPIO_Init_Input(I2C_SCL) //SCL高
#define SCL_LO GPIO_Output_Off(I2C_SCL) //SCL低
/***************************************
*I2C 地址定义
***************************************/
#define I2C_ADDR_TMP112 0x90
/***************************************
*I2C 延时定义
*延时2US,时钟频率250KHz,降低频率延时增加。频率最高400KHz
*250K = 1000000/(2+2)
*此延时单片机16M,单周期指令1/16M=62.5ns
***************************************/
void DELAY_2US(void)
{
int delay_time = 100000;
while(delay_time--);
}
/***************************************
*I2C start
***************************************/
void I2CStart(void)
{
SCL_HI;
DELAY_2US();
SDA_LO; //SDA高->低(start)
DELAY_2US();
SCL_LO;
DELAY_2US();
}
/***************************************
*I2C stop
***************************************/
void I2CStop(void)
{
SDA_LO;
DELAY_2US();
SCL_HI; //SCL置高,SCL高电平时,SDA低->高(stop)
DELAY_2US();
SDA_HI;
DELAY_2US();
}
/***************************************
*I2C 向从设备发送一个字节
*_dat 写入的值
***************************************/
void I2C_SendByte(unsigned char _dat)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCL_LO;
if(_dat & 0x80)
{
SDA_HI; //输出高
}
else
{
SDA_LO; //输出低
}
DELAY_2US();
SCL_HI;
DELAY_2US();
_dat <<= 1; //下个BIT,
}
SCL_LO;
SDA_HI;
DELAY_2US();
SCL_HI; //第9个应答BIT时钟,注:主机不判断从机ACK信号
DELAY_2US();
SCL_LO;
}
/***************************************
*I2C 读一个字节
*返回读取值
***************************************/
unsigned char I2C_ReadByte(unsigned char _ack)
{
unsigned char i,Dat;
Dat = 0;
SDA_HI;
for(i=0; i<8; i++)
{
DELAY_2US();
SCL_HI;
Dat <<= 1;
if(GPIO_Input_Read(I2C_SDA)) //判断SDA高低
{
Dat |= 0x01;
}
DELAY_2US();
SCL_LO;
}
if(_ack)
{
SDA_LO; //输出低
}
else
{
SDA_HI; //输出高
}
DELAY_2US();
SCL_HI;
DELAY_2US();
SCL_LO;
SDA_HI;
return(Dat);
}
/**********************************************************
*写N字节到TMP112对应地址
* dev_addr器件地址,是固定的。
*_addr从设备寄存器地址,_dat写入值
***********************************************************/
void I2C_WriteTMP112(unsigned char dev_addr, unsigned char _addr, unsigned char *_dat , unsigned char num)
{
I2CStart();
I2C_SendByte(dev_addr);
I2C_SendByte(_addr);
while(num--)
{
I2C_SendByte(*_dat--);
}
I2CStop();
}
/**********************************************************
*读TMP112对应地址N字节
*_addr 读地址
*返回读取值
***********************************************************/
unsigned char ReadByte24C02(unsigned char dev_addr, unsigned char _addr, unsigned char *_dat , unsigned char num)
{
unsigned char Dat;
I2CStart();
I2C_SendByte(dev_addr);
I2C_SendByte(_addr);
DELAY_2US();
I2CStart();
I2C_SendByte(dev_addr + 1);
while(num--)
{
if(num)
{
*_Dat++ = I2C_ReadByte(1);
}
else
{
*_Dat++ = I2C_ReadByte(0);
}
}
I2CStop();
return(Dat);
}
/**********************************************************
*读TMP112温度
*返回读取值
***********************************************************/
unsigned char read_temp(void)
{
unsigned char temp[2];
int temphi,templo;
ReadByte24C02(I2C_ADDR_TMP112,0,temp,2);
temphi = temp[0];
temphi <<= 4;
templo = temp[1];
templo >>= 4;
temphi += templo;
temphi /= 16;
return (unsigned char)temphi;
}