本帖最后由 Alden 于 2023-3-22 11:39 编辑
#技术资源#
APM32F072的硬件IIC例程中只有双板通讯和EEPROM的例程.
但无法直接用来用来跟其他IIC设备通讯,因此参考极海Eval板的硬件IIC例程和网上资料,改写了一个读写温湿度传感器HTU21D的例程。首先是IIC的初始化部分,与EEPROM的相同
#define HTU_I2C I2C2
#define HTU_I2C_CLK RCM_APB1_PERIPH_I2C2
#define HTU_I2C_SCL_PIN GPIO_PIN_10
#define HTU_I2C_SCL_GPIO_PORT GPIOB
#define HTU_I2C_SCL_GPIO_CLK RCM_AHB_PERIPH_GPIOB
#define HTU_I2C_SCL_SOURCE GPIO_PIN_SOURCE_10
#define HTU_I2C_SCL_AF GPIO_AF_PIN1
#define HTU_I2C_SDA_PIN GPIO_PIN_11
#define HTU_I2C_SDA_GPIO_PORT GPIOB
#define HTU_I2C_SDA_GPIO_CLK RCM_AHB_PERIPH_GPIOB
#define HTU_I2C_SDA_SOURCE GPIO_PIN_SOURCE_11
#define HTU_I2C_SDA_AF GPIO_AF_PIN1
void APM_I2C_Init(void)
{
GPIO_Config_T gpioConfigStruct;
I2C_Config_T i2cConfigStruct;
/* Enable I2C related Clock */
RCM_EnableAHBPeriphClock(HTU_I2C_SCL_GPIO_CLK | HTU_I2C_SDA_GPIO_CLK);
RCM_EnableAPB1PeriphClock(HTU_I2C_CLK);
RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
/* Connect I2C to SCL */
GPIO_ConfigPinAF(HTU_I2C_SCL_GPIO_PORT, HTU_I2C_SCL_SOURCE, HTU_I2C_SCL_AF);
/* Connect I2C to SDA */
GPIO_ConfigPinAF(HTU_I2C_SDA_GPIO_PORT, HTU_I2C_SDA_SOURCE, HTU_I2C_SDA_AF);
/* Config I2C GPIO */
gpioConfigStruct.mode = GPIO_MODE_AF;
gpioConfigStruct.speed = GPIO_SPEED_50MHz;
gpioConfigStruct.outtype = GPIO_OUT_TYPE_OD;
gpioConfigStruct.pupd = GPIO_PUPD_NO;
gpioConfigStruct.pin = HTU_I2C_SCL_PIN;
GPIO_Config(HTU_I2C_SCL_GPIO_PORT, &gpioConfigStruct);
gpioConfigStruct.pin = HTU_I2C_SDA_PIN;
GPIO_Config(HTU_I2C_SDA_GPIO_PORT, &gpioConfigStruct);
/* Config I2C2 */
I2C_Reset(HTU_I2C);
i2cConfigStruct.ack = I2C_ACK_ENABLE;
i2cConfigStruct.ackaddress = I2C_ACK_ADDRESS_7BIT;
i2cConfigStruct.address1 = 0x00;
i2cConfigStruct.analogfilter = I2C_ANALOG_FILTER_ENABLE;
i2cConfigStruct.digitalfilter = I2C_DIGITAL_FILTER_0;
i2cConfigStruct.mode = I2C_MODE_I2C;
i2cConfigStruct.timing = 0xB0420F13;
I2C_Config(HTU_I2C,&i2cConfigStruct);
/* Enable I2Cx */
I2C_Enable(HTU_I2C);
I2CInfo.address = HTU_ADDR_WR;
I2CInfo.addrNum = 1;
}
由HTU21D的手册可以看到设备地址和温湿度数据对应的寄存器地址。
进行宏定义
#define HTU_ADDR 0x80
#define HTU_ADDR_WR (HTU_ADDR & 0xFE)
#define HTU_ADDR_RD (HTU_ADDR | 0x01)
//非主机模式
#define HTU_TEMP 0xE3
#define HTU_HUMI 0XE5
然后编写对应的读写函数,根据HTU21D的手册,读数据需要有一个等待转换的时间,最大需要50ms,这个等待需要加入读函数中。
I2C_ERROR_T I2C_HTU_Read(uint8_t* buffer, uint16_t writeAddr, uint8_t number)
{
I2C_ERROR_T errSta = I2C_OK;
uint32_t temp = number;
uint8_t read_Num;
I2C_HandlingTransfer(HTU_I2C, I2CInfo.address, I2CInfo.addrNum, I2C_RELOAD_MODE_SOFTEND, I2C_GENERATE_START_WRITE);
I2CInfo.timeout = I2C_LONG_TIMEOUT;
while(I2C_ReadStatusFlag(HTU_I2C, I2C_FLAG_TXINT) == RESET)
{
if((I2CInfo.timeout--) == 0)
{
errSta = I2C_TIMEOUT;
return I2C_Callback(10);
}
}
I2C_TxData(HTU_I2C, (uint8_t)(writeAddr & 0x00FF));
I2CInfo.timeout = I2C_LONG_TIMEOUT;
while(I2C_ReadStatusFlag(HTU_I2C, I2C_FLAG_TXCF) == RESET)
{
if((I2CInfo.timeout--) == 0)
{
errSta = I2C_TIMEOUT;
return I2C_Callback(13);
}
}
APM_EVAL_DelayMs(50);//等待转化完成
/* I2Cx send the number of byte to write to eeprom */
I2C_HandlingTransfer(HTU_I2C, I2CInfo.address, (uint8_t)(number), I2C_RELOAD_MODE_AUTOEND, I2C_GENERATE_START_READ);
for(read_Num = 0; read_Num < temp; read_Num++)
{
I2CInfo.timeout = I2C_LONG_TIMEOUT;
while(I2C_ReadStatusFlag(HTU_I2C, I2C_FLAG_RXBNE) == RESET)
{
if((I2CInfo.timeout--) == 0)
{
errSta = I2C_TIMEOUT;
return I2C_Callback(14);
}
}
buffer[read_Num] = I2C_RxData(HTU_I2C);
}
I2CInfo.timeout = I2C_LONG_TIMEOUT;
while(I2C_ReadStatusFlag(HTU_I2C, I2C_FLAG_STOP) == RESET)
{
if((I2CInfo.timeout--) == 0)
{
errSta = I2C_TIMEOUT;
return I2C_Callback(15);
}
}
I2C_ClearStatusFlag(HTU_I2C, I2C_FLAG_STOP);
return errSta;
}
然后配置对应的读数据函数和数据转换函数。
float Htu_Measure(uint8_t _ucOrder)
{
uint8_t ucaRecvBuf[2] = {0};
uint8_t ucTmpVal = _ucOrder;
volatile float fTemp = 0.0;
volatile float fHumi = 0.0;
volatile float fRetVal = 0.0;
I2C_HTU_Read(ucaRecvBuf,ucTmpVal,2);
ucaRecvBuf[1] &= 0xFC; //设置分辨率,最低两位为0,温度:14位;湿度:12位
fRetVal = (ucaRecvBuf[0] << 8) | ucaRecvBuf[1]; // MSB=(MSB<<=8)+LSB;即将MSB移位到高8位
if(_ucOrder == HTU_TEMP)
{
fTemp = (175.72) * fRetVal / 65536 - 46.85;//温度:T= -46.85 + 175.72 * ST/2^16
return fTemp;
}
else if(_ucOrder == HTU_HUMI)
{
fHumi = (fRetVal * 125) / 65536 - 6.00;//湿度: RH%= -6 + 125 * SRH/2^16
return fHumi;
}
else
{
return 0;
}
}
用串口输出,就得到了当前的温湿度值
HTU21D数据手册.pdf
(983.58 KB)
APM32F072_EVAL_SDK_v1.0 .zip
(1.46 MB)
|
学习一下