ADT7410是一款基于SOIC封装的高精度数字温度传感器。它内部具有带隙温度参考源以及13位ADC,可以提高0.0625摄氏度的温度精度。 他的通信接口是IIC总线。I2C总线是由Philips公司开发的一种简单、双向二线制同步串行总线。它只需要两根线即可在连接于总线上的器件之间传送信息。两根线是SDA(串行数据线)和SCL(串行时钟线) 根据数据手册,iic通信时序如下
按照他的通信时序,实现iic通信如下
#include "stm32f10x_gpio.h" #define GPIO_PORT_I2C GPIOC/* GPIO端口 / #define RCC_I2C_PORT RCC_APB2Periph_GPIOC/ GPIO端口时钟 / #define I2C_SCL_PIN GPIO_Pin_0 / 连接到SCL时钟线的GPIO / #define I2C_SDA_PIN GPIO_Pin_13 / 连接到SDA数据线的GPIO */
#define I2C_SCL_1() GPIO_SetBits(GPIO_PORT_I2C, I2C_SCL_PIN)/* SCL = 1 / #define I2C_SCL_0() GPIO_ResetBits(GPIO_PORT_I2C, I2C_SCL_PIN)/ SCL = 0 */
#define I2C_SDA_1() GPIO_SetBits(GPIO_PORT_I2C, I2C_SDA_PIN)/* SDA = 1 / #define I2C_SDA_0() GPIO_ResetBits(GPIO_PORT_I2C, I2C_SDA_PIN)/ SDA = 0 */
#define I2C_SDA_READ() GPIO_ReadInputDataBit(GPIO_PORT_I2C, I2C_SDA_PIN)/* 读SDA口线状态 */
extern void delay(unsigned int num);
typedef struct { char (*init) (void); float (*read_temperature)(void);
}IIC_SIMULATION_T;
extern IIC_SIMULATION_T *IIC_Simulation;
#include "DeviceSimulationIICDriver.h"
/*
- 函 数 名: i2c_Delay
- 功能说明: I2C总线位延迟,最快400KHz
- 形 参:无
- 返 回 值: 无
*/ static void i2c_Delay(void) { uint8_t i;
/* 下面的时间是通过安富莱AX-Pro逻辑分析仪测试得到的。 CPU主频72MHz时,在内部Flash运行, MDK工程不优化 循环次数为10时,SCL频率 = 205KHz 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us
IAR工程编译效率高,不能设置为7 */ for (i = 0; i < 10; i++); }
/*
- 函 数 名: i2c_Start
- 功能说明: CPU发起I2C总线启动信号
- 形 参:无
- 返 回 值: 无
/ void i2c_Start(void) { / 当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号 */ I2C_SCL_1(); I2C_SDA_1(); i2c_Delay(); I2C_SDA_0(); // i2c_Delay(); // I2C_SCL_0(); // i2c_Delay(); }
/*
- 函 数 名: i2c_Start
- 功能说明: CPU发起I2C总线停止信号
- 形 参:无
- 返 回 值: 无
/ void i2c_Stop(void) { / 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */ I2C_SCL_1(); I2C_SDA_0(); i2c_Delay(); I2C_SDA_1(); }
/*
- 函 数 名: i2c_SendByte
- 功能说明: CPU向I2C总线设备发送8bit数据
- 形 参:_ucByte : 等待发送的字节
- 返 回 值: 无
*/ void i2c_SendByte(uint8_t _ucByte) { uint8_t i;
/* 先发送字节的高位bit7 / for (i = 0; i < 8; i++) { I2C_SCL_0(); i2c_Delay(); if (_ucByte & 0x80) { I2C_SDA_1(); } else { I2C_SDA_0(); } i2c_Delay(); I2C_SCL_1(); i2c_Delay(); I2C_SCL_0(); if (i == 7) { I2C_SDA_1(); // 释放总线 } _ucByte <<= 1; / 左移一个bit */ i2c_Delay(); } }
/*
- 函 数 名: i2c_ReadByte
- 功能说明: CPU从I2C总线设备读取8bit数据
- 形 参:无
- 返 回 值: 读到的数据
*/ uint8_t i2c_ReadByte(void) { uint8_t i; uint8_t value;
/* 读到第1个bit为数据的bit7 */ value = 0; I2C_SCL_1(); i2c_Delay(); for (i = 0; i < 8; i++) { value <<= 1; I2C_SCL_1(); i2c_Delay(); if (I2C_SDA_READ()) { value++; } I2C_SCL_0(); i2c_Delay(); } return value; }
/*
- 函 数 名: i2c_WaitAck
- 功能说明: CPU产生一个时钟,并读取器件的ACK应答信号
- 形 参:无
- 返 回 值: 返回0表示正确应答,1表示无器件响应
*/ uint8_t i2c_WaitAck(void) { uint8_t re;
I2C_SDA_1(); /* CPU释放SDA总线 / i2c_Delay(); I2C_SCL_1(); / CPU驱动SCL = 1, 此时器件会返回ACK应答 / i2c_Delay(); if (I2C_SDA_READ()) / CPU读取SDA口线状态 */ { re = 1; } else { re = 0; } I2C_SCL_0(); i2c_Delay(); return re; }
/*
- 函 数 名: i2c_Ack
- 功能说明: CPU产生一个ACK信号
- 形 参:无
- 返 回 值: 无
/ void i2c_Ack(void) { I2C_SDA_0(); / CPU驱动SDA = 0 / i2c_Delay(); I2C_SCL_1(); / CPU产生1个时钟 / i2c_Delay(); I2C_SCL_0(); i2c_Delay(); I2C_SDA_1(); / CPU释放SDA总线 */ }
/*
- 函 数 名: i2c_NAck
- 功能说明: CPU产生1个NACK信号
- 形 参:无
- 返 回 值: 无
/ void i2c_NAck(void) { I2C_SDA_1(); / CPU驱动SDA = 1 / i2c_Delay(); I2C_SCL_1(); / CPU产生1个时钟 */ i2c_Delay(); I2C_SCL_0(); i2c_Delay(); }
/*
- 函 数 名: i2c_CfgGpio
- 功能说明: 配置I2C总线的GPIO,采用模拟IO的方式实现
- 形 参:无
- 返 回 值: 无
*/ void iic_init(void) { GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE); /* 打开GPIO时钟 */
GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 开漏输出 */ GPIO_Init(GPIO_PORT_I2C, &GPIO_InitStructure);
/* 给一个停止信号, 复位I2C总线上的所有设备到待机模式 */ i2c_Stop(); }
/*
- 函 数 名: i2c_CheckDevice
- 功能说明: 检测I2C总线设备,CPU向发送设备地址,然后读取设备应答来判断该设备是否存在
- 形 参:_Address:设备的I2C总线地址
- 返 回 值: 返回值 0 表示正确, 返回1表示未探测到
*/ uint8_t i2c_CheckDevice(uint8_t _Address) { uint8_t ucAck;
// i2c_CfgGpio();/* 配置GPIO */
i2c_Start(); /* 发送启动信号 */
/* 发送设备地址+读写控制bit(0 = w, 1 = r) bit7 先传 / i2c_SendByte(_Address | 0); ucAck = i2c_WaitAck(); / 检测设备的ACK应答 */
i2c_Stop(); /* 发送停止信号 */
return ucAck; }
static float read_temperature() { float num,read_h,read_l; i2c_Start(); i2c_SendByte((0x48<<1)); if (i2c_WaitAck() != 0) { return 0; } i2c_SendByte(0x00); if (i2c_WaitAck() != 0) { return 0; } // i2c_Stop(); i2c_Start(); i2c_SendByte((0x48<<1)|1); if (i2c_WaitAck() != 0) { return 0; } read_h=i2c_ReadByte(); i2c_Stop(); // if (i2c_WaitAck() != 0) // { // return 0; // } i2c_Start(); i2c_SendByte((0x48<<1)); if (i2c_WaitAck() != 0) { return 0; } i2c_SendByte(0x01); if (i2c_WaitAck() != 0) { return 0; }
// i2c_Stop(); i2c_Start(); i2c_SendByte((0x48<<1)|1); if (i2c_WaitAck() != 0) { return 0; } read_l=i2c_ReadByte(); i2c_Stop(); num=read_h*256+read_l; if(num<32768) {
num=num/128; } else {
num=(num-65536)/128;
} delay_ms(10); // delay(999); // delay(999); return num;
}
static char adt7410_init() {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE);
GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIO_PORT_I2C, &GPIO_InitStructure);
// GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN; // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
// GPIO_Init(GPIO_PORT_I2C, &GPIO_InitStructure); // // GPIO_InitStructure.GPIO_Pin = I2C_SDA_PIN; // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
// GPIO_Init(GPIO_PORT_I2C, &GPIO_InitStructure);
i2c_Stop();
i2c_Start(); i2c_SendByte(0x48<<1); if (i2c_WaitAck() != 0) { return 1; }
i2c_SendByte(0x03); if (i2c_WaitAck() != 0) { return 1; } i2c_SendByte(0xc0); if (i2c_WaitAck() != 0) { return 1; } i2c_Stop(); return 0;
}
IIC_SIMULATION_T IIC_init = { .init = adt7410_init, .read_temperature = read_temperature, };
IIC_SIMULATION_T *IIC_Simulation=&IIC_init;