瑞萨RA0单片机连载——面向对象编程之SHT31温度计
SHT3X是一款优秀的温湿度计。他采用i2c 接口,地址为0x44。它的驱动与原理的讲解非常的丰富,网上也有非多的现成的代码,我这里不做过多的阐述。本篇的主要特点是在前面OLED驱动的前提下,对sht31进行面向对象的编程方式进行讲解。
1 前提
在OLED驱动之中,我已经初始化了I2C的总线,所以有总线驱动在本篇没有做,如果是使用spi 或者其他的方式进行数据展示,那么需要加上对i2c 总线进行初始化。
2 实现步骤
2.1 创建sensor.h,在其中创建结构体
view plaincopy to clipboardprint?
1.typedef struct SensorDevice{
2.char *name;
3.uint8_t slaveAddr; //从机地址
4.
5.float Temp;
6.float Hum;
7.unsigned short read_status;
8.int(*Init)(void); /*硬件初始化*/
9.void (*Read)(struct SensorDevice *ptDev); //读取温湿度
10.}SensorDevice, *PSensorDevice;
2.2 创建drv_sensor.c
首先实例化
view plaincopy to clipboardprint?
1.static SensorDevice gSht31Dev ={
2. name=“SHT31”,
3. .slaveAddr = 0x44,
4. //.Init = Sht3xDrvGpioInit,
5. Temp = 0,
6. Hum = 0,
7. read_status = 0,
8. Read = sht3x_read,
9. };
10.
11. struct SensorDevice *SHT31GetDevice(void)
12. {
13. return &gSht31Dev;
14. }
接下来编写发送、接收超时函数
view plaincopy to clipboardprint?
1.static void I2C2WaitTxCplt(void)
2.{
3.uint16_t wTimeOut = 1;
4.while(!gI2CsxCplt && wTimeOut)
5.{
6.HAL_Delay(1);
7.wTimeOut--;
8.}
9.gI2C2TxCplt=false;
10.}
11.
12.static void I2C2WaitRxCplt(void)
13.{
14.uint16_t wTimeOut = 10;
15.while(!gI2C2RxCplt && wTimeOut)
16.{
17.HAL_Delay(1);
18.wTimeOut--;
19.}
20.gI2C2RxCplt = false;
21.}
为了验证读取的温度与数据是否正确,编写CRC函数如下:
view plaincopy to clipboardprint?
1./*
2.*@name CRC_8
3.*@brief CRC-8 校验
4.*@param Crc_ptr -> 校验数据首地址
5.LEN->校验数据长度
6.*@retval CRC_Value->校验值
7. =*/
8.static uint8_t CRC_8(uint8_t *Crc_ptr,uint8_t LEN)
9.{
10.uint8_t CRC_Value = 0xFF;
11.uint8_t i = 0,j = 0;
12.
13.for(i=0;i<LEN;i++)
14.{
15.CRC_Value ^= *(Crc_ptr+i);
16.for(j=0;j<8;j++)
17.{
18.if(CRC_Value & 0x80)
19.CRC_Value = (CRC_Value << 1) ^ 0x31;
20.else
21.CRC_Value = (CRC_Value << 1);
22.}
23.}
24.return CRC_Value;
25.}
在读取温度的函数中首先向sht31发送开始转换命令0x2400, 我将他封装在一个数据中,使用R_SAU_I2C_Write进行一次性发送。当然由于总线上有SSD1306 操作时他的g_sau_i2c_master_ctrl 的从机地址是SSD1306的0x3c所以,需要先配置sht31的地址,他的发送数据转换命令如下:
view plaincopy to clipboardprint?
1. g_sau_i2c_master_ctrl.slave = ptDev->slaveAddr;
2. err = R_SAU_I2C_Write(&g_sau_i2c_master_
ctrl,cmd, 2, true);
3. I2C2WaitTxCplt();
4. if(FSP_SUCCESS != err )
5. {
6. ptDev->read_status = 0;
7. printf(“Error when open i2c1 device!rn”);
8. return ;
9. }
由于转换需要一段时间,需要延时。
延时之后,我一次读取6位数据,如果获取数据成功,则进行CRC并进行float转换,转换成功后放到结构体中,并更新状态:整个获取数据的代码如下:
view plaincopy to clipboardprint?
1. static void sht3x_read(struct SensorDevice *ptDev)
2. {
3. if(NULL == ptDev) return;
4. fsp_err_t err;
5. uint32_t temp_uint;
6. // 写入开始转换的命令
7. //0xE000 是向SHT30 取数据的指令,主机发送该指令后开始读取SHT30 的温湿度数据
8. uint8_t temp_array[6] = {0};
9. uint8_t cmd[] = {
10. 0x24,0x00
11. };
12. g_sau_i2c_master_ctrl.slave = ptDev->slaveAddr;
13. err = R_SAU_I2C_Write(&g_sau_i2c_master_ctrl,cmd, 2, true);
14. I2C2WaitTxCplt();
15. if(FSP_SUCCESS != err )
16. {
17. ptDev->read_status = 0;
18. printf(“Error when open i2c1 device!rn”);
19. return ;
20. }
21. HAL_Delay(2);
22.
23. err = R_SAU_I2C_Read(&g_sau_i2c_master_ctrl, temp_array, 6, true);
24. I2C2WaitRxCplt();
25. if(FSP_SUCCESS != err )
26. {
27. ptDev->read_status = 0;
28. printf(“Error when open i2c1 device!rn”);
29. return ;
30. }
31. else
32. {
33. // 计算温度
34. if(CRC_8(temp_array,2) == temp_array[2]) // 进行CRC-8 校验
35. {
36. temp_uint = temp_array[0]*256+temp_array[1]; //取出16位的温度值
37. ptDev->Temp = ((float)temp_uint)*0.267032-4500; //根据手册公式计算,为了精度,计算数值先*100
38. ptDev->Temp = ptDev->Temp*0.01;//再除以100,得到正常温度值
39.}
40.
41.//计算湿度
42.if(CRC_8(&temp_array[3],2) == temp_array[5]) // 进行CRC-8校验
43.{
44.temp_uint = temp_array[3]*256+temp_array[4]; // 取出16位的湿度值
45.ptDev->Hum = ((float)temp_uint)*0.152590; // 根据手册公式计算
46.ptDev->Hum = (uint8_t)(ptDev->Hum*0.01); // 除以100,得到正常湿度值
47.ptDev->read_status = 1;
48.}
49.
50.
51.}
52.}
3 数据展示
在主函数中编写测试代码如下,如果获取到温度数据则显示温湿度,如果获取出错则显示EEROR, 其代码如下:
view plaincopy to clipboardprint?
1. void led_blink(void)
2. {
3.
4. UartDevicesRegister();
5.
6. DisplayDevice *ptDispDev = OLEDGetDevice();
7. if(NULL == ptDispDev )
8. {
9. printf(“Failed to get OLED Display Device!
rn”);
10. return;
11. }
12. uint8_t cnt;
13. ptDispDev->Init(ptDispDev);
14. ptDispDev->GUI_Set_Horizontal_Mode
(ptDispDev,0,128,0,64);
15. SensorDevice *ptSHT31Dev = SHT31GetDevice();
16. if(NULL == ptSHT31Dev)
17. {
18. printf(“Failed to get Sht31 Device!rn”);
19. return;
20. }
21. while(1)
22. {
23. ptSHT31Dev->Read(ptSHT31Dev);
24.
25. if(cnt>96) cnt = 0;
26. ptDispDev->GUI_clear(ptDispDev,0);
27. if(1 == ptSHT31Dev->read_status)
28. {
29. ptDispDev->GUI_ShowString(ptDisp
Dev,10,16, (uint8_t *)”TEMP:”,16,1);
30. ptDispDev->GUI_ShowNum
(ptDispDev,64,16,(int)ptSHT31Dev->Temp,2,16,1);
31. ptDispDev->GUI_ShowString(ptDisp
Dev,16,32, (uint8_t *)”HUM:”,16,1);
32. ptDispDev->GUI_ShowNum(ptDispDev,
64,32,(int)ptSHT31Dev->Hum,2,16,1);
33. }
34. else
35. {
36. ptDispDev->GUI_ShowString(ptDisp
Dev,10,16, (uint8_t *)”TEMP:ERROR”,16,1);
37. }
38. ptDispDev->GUI_DrawLine(ptDispDe
v,0,0,cnt,0,1);
39. ptDispDev->GUI_Display(ptDispDev);
40.
41. //HAL_Delay(1);
42. cnt ++;
43. }
44. }
4 实验效果
5 总结
使用面向对象对sht31的驱动进行封装,在瑞萨的FSP驱动中,可以快速实现驱动,同时只需要提供驱动的接口,可以实现低耦合的功能。
( 本文来源于《EEPW》202505)
评论