之前的帖子可以参考:
【GD32L233C-START评测】3.移植FreeRTOS到GD32L233
【GD32L233C-START评测】4. 移植RT-Thread到GD32L233
【GD32L233C-START评测】5. IIC驱动OLED
【GD32L233C-START评测】6. 获取RTC时间并通过OLED显示
【GD32L233C-START评测】7. PWM驱动LED
【GD32L233C-START评测】8. TRNG真随机数生成
【GD32L233C-START评测】10. ADC读取芯片内部温度
【GD32L233C-START评测】11.DAC输出电压值_ADC读取外部电压值
【GD32L233C-START评测】12. 硬件IIC驱动OLED
【GD32L233C-START评测】13. CAU加密算法之DES/TDES
【GD32L233C-START评测】14. CAU加密算法之AES
【GD32L233C-START评测】15. flash擦写操作,将FLASH当做EEPROM使用
一、前言
本帖将讲解使用GD32L233C的硬件IIC来驱动x-nucleo-iks01a3传感器板子中的温度传感器STTS751,湿度传感器HTS221以及气压传感器LPS22HH。
硬件接线:
PB10 - SCL
PB11 - SDA
本帖的代码是在RT-Thread的基础上开发的,单独创建了一个线程用来1s中打印一次温湿度以及气压值。
二、传感器手册
1. STTS751
STTS751是一个温度传感器,其原理很简单,直接从温度寄存器中取出温度值就可以了,寄存器中存储的温度值就是实际温度,不需要进行转换,使用起来很方便,这里不在赘述。
STTS751的主要信息如下:
IIC地址:0x94
温度寄存器地址:温度整数部分:0x00,温度小数部分:0x02
2. LPS22HH
LPS22HH是一个大气压强传感器,可以获取大气压强的值,有三个寄存器来获取大气压强的高位,中位和低位,然后除以40960的大气压强单位就是kPA。
LPS22HH中也提供了温度传感器,但是我们已经使用了STTS751,这里就不需要在使用了,但是可以读取出来对大气压强做校准。
IIC地址:0xBA
其中有几个比较重要级的寄存器分别如下:
(1)0x0E:
这个寄存器用于设置传输方式,我们使用的是I2C传输,所以将该寄存器设置为0x0A
(2)0x10:这个寄存器用来设置采样频率以及方式,我们使用连续采样,采样频率为1Hz,所以该值设置为0x18。
(3)0x28,0x29,0x2A: 这三个寄存器是大气压强寄存器,读取这三个寄存器的值后就可以直接计算出大气压强的值。
0x2A是存取的气压值的最高位,0x29存取的是气压值的中位,0x28存取的是寄存器的低位。
获取了这三个值之后在处于4096就是气压值,其单位为hPa, 我们一般转为kPa只用,在除以10就行了。
计算公式的说明见下图:
3. HTS221
HTS221是一个温湿度传感器,可以检测出温湿度等信息,但是该寄存器操作起来计较复杂,其校准信息也存储在特定的寄存器中。校准数值由两个采样值和两个湿度值存在4个寄存器中,根据这四个值计算出一个线性方程公式,再将我们实际采集到的湿度值带入方程中计算出真实的湿度百分比值,其温度值和湿度值一样,也需要根据校准公式推导,方式一样,本贴中没有进行使用,温度值使用的是STTS751的值。
该传感器使用之前必须要初始化,不然不会工作。
IIC地址:0xBE
关键寄存器信息如下:
(1)0x10:配置温湿度平均采样寄存器,本帖配置为0x09
(2)0x20:配置采样率以及电源开启关闭等信息,设置为0x81,激活传感器以及采样率设置为1Hz
(3)0x28,0x29:读取的未转换的湿度值,该数值需要转换之后才是真是的湿度值。
0x29为高位,0x28为低位。
(4)0x30,0x31,(0x36,0x37),(0x3A,0x3B):校准值,这些值在传感器初始化完成之后读取一次就行了,这是固定在寄存器中的值。
寄存器描述以及计算方式如下:
从上面的寄存器介绍中可以看到,寄存器符号以及作用,其实是一个线性方程,公式为: y=k*x+b
其中,y就是湿度的百分比的2倍,计算出来之后还要除以2
x就是独取出来的寄存器0x28, 0x29的值。
我们在初始化的时候还需要做的一件事就是计算出k和b的值,方式如下:
1. 读取校准寄存器的值, x1 = 寄存器0x36,0x37的值,即H0_T0_OUT
2. 读取校准寄存器的值, x2 = 寄存器0x3A,0x3B的值,即H1_T0_OUT
3. 读取校准寄存器的值, y1 = 寄存器0x30的值,即H0_rH_x2
4. 读取校准寄存器的值, y2 = 寄存器0x31的值,即H1_rH_x2
可以计算出k = (y2-y1)/ (x2-x1), b = y1 - k*x1 = y1 - x1*(y2-y1)/(x2-x1)
之后将我们读取的寄存器0x28,0x29的值带入进去就可以算出来真实的湿度值了,注意要除以2才是真实值。
三、代码实现
代码实现才考附件。
其中关于I2C硬件初始化以及串口初始化的代码都放在了RT-Thread的board.c这个文件中的rt_hw_board_init()函数里面,因为RT-Thread中main函数也是一个线程,所以最好不要将硬件初始化的代码放在main里面,而是放在RT-Thread提供的硬件初始化接口函数rt_hw_board_init()里面。
传感器的数字通过串口打印,1s中打印一次,见文件iks01a3.c中,如下:
void BEEP_Thread_Init(void)
{
iks01a3_thr = rt_thread_create(IKS01A3_THREAD_LABEL,
IKS01A3_ThreadEntry, /*线程入口函数*/
RT_NULL, /*线程入口函数参数*/
IKS01A3_THREAD_SIZE,
IKS01A3_THREAD_PRIO,
IKS01A3_THREAD_TIME_SLICE);
if (RT_NULL != iks01a3_thr)
rt_thread_startup (iks01a3_thr);
else
rt_kprintf("\r\n ERROR: iks01a3_thr thread initializd failed! \r\n");
}
static void IKS01A3_ThreadEntry(void *parameter)
{
/* Initialize HTS221 */
HTS221_Init();
/* Initialize LPS22HH */
LPS22HH_Init();
while (1)
{
printf("Temperature:%d.%dC\r\n", STTS751_GetTempH(), STTS751_GetTempL());
printf("Humidity:%f%%\r\n", HTS221_GetHumidity());
printf("Pressure:%fkPa\r\n", LPS22HH_GetPressure());
printf("------------------------\r\n");
rt_thread_mdelay(1000);
}
}
IIC接口代码,写IIC数据以及读IIC数据同样在iks01a3.c中
void IKS01A3_IicWrite(uint8_t addr, uint8_t IIC_Reg, uint8_t IIC_Data)
{
rt_enter_critical();
#if (IIC_TYPE == IIC_TYPE_HW)
uint8_t i2c_transmitter[2]={IIC_Reg, IIC_Data};
uint8_t i;
I2C_SetSlaveConfig(addr, I2C_MASTER_TRANSMIT, 2);
i2c_transmitter[0] = IIC_Reg;
i2c_transmitter[1] = IIC_Data;
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY)){};
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until the transmit data buffer is empty */
I2C_STAT(I2C1) |= I2C_STAT_TBE;
while(!i2c_flag_get(I2C1, I2C_FLAG_TBE)){};
for(i = 0; i < 2; i++)
{
/* data transmission */
i2c_data_transmit(I2C1, i2c_transmitter[i]);
/* wait until the TI bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_TI));
}
/* wait for transfer complete flag */
while(!i2c_flag_get(I2C1, I2C_FLAG_TC)){};
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C1);
/* wait until stop condition generate */
while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET)){};
/* clear the STPDET bit */
i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
#elif (IIC_TYPE == IIC_TYPE_SW)
IIC_Start();
IIC_Send_Byte(addr);
IIC_Wait_Ack();
IIC_Send_Byte(IIC_Reg); //write data
IIC_Wait_Ack();
IIC_Send_Byte(IIC_Data);
IIC_Wait_Ack();
IIC_Stop();
#endif
rt_exit_critical();
}
uint8_t IKS01A3_IicRead(uint8_t addr, uint8_t IIC_Reg)
{
char ret = 0;
uint8_t ret_suc = 1;
rt_enter_critical();
#if (IIC_TYPE == IIC_TYPE_HW)
uint8_t i2c_receiver = 0;
uint8_t i;
uint8_t i2c_transmitter = IIC_Reg;
I2C_SetSlaveConfig(addr, I2C_MASTER_TRANSMIT, 1);
i2c_transmitter = IIC_Reg;
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY)){};
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until the transmit data buffer is empty */
I2C_STAT(I2C1) |= I2C_STAT_TBE;
while(!i2c_flag_get(I2C1, I2C_FLAG_TBE)){};
/* data transmission */
i2c_data_transmit(I2C1, i2c_transmitter);
/* wait until the TI bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_TI)){};
/* wait for transfer complete flag */
while(!i2c_flag_get(I2C1, I2C_FLAG_TC)){};
I2C_SetSlaveConfig(addr, I2C_MASTER_RECEIVE, 1);
/* wait until I2C bus is idle */
while(i2c_flag_get(I2C1, I2C_FLAG_I2CBSY)){};
/* send a start condition to I2C bus */
i2c_start_on_bus(I2C1);
/* wait until the RBNE bit is set */
while(!i2c_flag_get(I2C1, I2C_FLAG_RBNE)){};
/* read a data from I2C_DATA */
i2c_receiver = i2c_data_receive(I2C1);
/* wait for transfer complete flag */
while(!i2c_flag_get(I2C1, I2C_FLAG_TC)){};
/* send a stop condition to I2C bus */
i2c_stop_on_bus(I2C1);
/* wait until stop condition generate */
while(!i2c_flag_get(I2C1, I2C_FLAG_STPDET)){};
/* clear the STPDET bit */
i2c_flag_clear(I2C1, I2C_FLAG_STPDET);
ret = i2c_receiver;
#elif (IIC_TYPE == IIC_TYPE_SW)
IIC_Start();
IIC_Send_Byte(addr & 0xfe);
ret_suc = IIC_Wait_Ack();
if(ret_suc == 1)
return 1; //失败
IIC_Send_Byte(IIC_Reg);
ret_suc = IIC_Wait_Ack();
if(ret_suc == 1)
return 1; //失败
IIC_Start();
IIC_Send_Byte(addr | 0x01);
ret_suc = IIC_Wait_Ack();
ret=IIC_Read_Byte(1);
IIC_Stop();
#endif
rt_exit_critical();
return (uint8_t)ret;
}
四、结果验证
如下图:
可以看到温湿度信息以及气压信息都可以成功打印出来
五、附件
代码仅供参考。