新闻中心

EEPW首页 > 设计应用 > 瑞萨RA0单片机连载——面向对象编程之SHT31温度计

瑞萨RA0单片机连载——面向对象编程之SHT31温度计

作者:lulugl 时间:2025-05-22 来源:EEPW 收藏


本文引用地址:https://www.eepw.com.cn/article/202505/470718.htm

SHT3X是一款优秀的温湿度计。他采用i2c 接口,地址为0x44。它的驱动与原理的讲解非常的丰富,网上也有非多的现成的代码,我这里不做过多的阐述。本篇的主要特点是在前面OLED驱动的前提下,对sht31进行面向对象的编程方式进行讲解。

1   前提

在OLED驱动之中,我已经初始化了I2C的总线,所以有总线驱动在本篇没有做,如果是使用spi 或者其他的方式进行数据展示,那么需要加上对i2c 总线进行初始化。

2 实现步骤

2.1 创建sensor.h,在其中创建结构体

image.png

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

首先实例化

image.png

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. }

接下来编写发送、接收超时函数

image.png

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.}

image.png

为了验证读取的温度与数据是否正确,编写CRC函数如下:

image.png

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的地址,他的发送数据转换命令如下:

image.png

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转换,转换成功后放到结构体中,并更新状态:整个获取数据的代码如下:

image.png

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.}

image.png

image.png

3   数据展示

在主函数中编写测试代码如下,如果获取到温度数据则显示温湿度,如果获取出错则显示EEROR, 其代码如下:

image.png

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. }

image.png

image.png

4   实验效果

image.png

5   总结

使用面向对象对sht31的驱动进行封装,在瑞萨的FSP驱动中,可以快速实现驱动,同时只需要提供驱动的接口,可以实现低耦合的功能。

( 本文来源于《EEPW》



关键词: 202505

评论


技术专区

关闭