这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 企业专区 » Renesas » 瑞萨RA0单片机连载之七——面向对象编程之SHT31温度计

共5条 1/1 1 跳转至

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

助工
2024-06-02 09:08:16     打赏

SHT3X是一款优秀的温湿度计。他采用i2c接口,地址为0x44。

他的驱动与原理的讲解非常的丰富,网上也有非多的现成的代码,我这里不做过多的阐述。

本篇的主要特点是在前面OLED驱动的前提下,对sht31进行面向对象的编程方式进行讲解。

【前提】

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

【实现步骤】

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

typedef struct SensorDevice {
    char *name;
	  uint8_t        slaveAddr; //从机地址
	  
	  float          Temp;
	  float          Hum;
	  unsigned short read_status;
	  int            (*Init)(void);   /* 硬件初始化 */
	  void            (*Read)(struct SensorDevice *ptDev);  //读取温湿度
} SensorDevice, *PSensorDevice;

2、创建drv_sensor.c

首先实例化

static SensorDevice gSht31Dev = {
                             .name = "SHT31",
	                           .slaveAddr = 0x44,
	                           //.Init = Sht3xDrvGpioInit,
	                           .Temp = 0,
	                           .Hum  = 0,
	                           .read_status = 0,
	                           .Read = sht3x_read,
};

struct SensorDevice *SHT31GetDevice(void)
{
    return &gSht31Dev;
}

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

static void I2C2WaitTxCplt(void)
{
    uint16_t wTimeOut = 1;
    while(!gI2C2TxCplt && wTimeOut)
    {
        HAL_Delay(1);
        wTimeOut--;
    }
    gI2C2TxCplt = false;
}

static void I2C2WaitRxCplt(void)
{
    uint16_t wTimeOut = 10;
    while(!gI2C2RxCplt && wTimeOut)
    {
        HAL_Delay(1);
        wTimeOut--;
    }
    gI2C2RxCplt = false;
}

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

/*
* @name   CRC_8
* @brief  CRC-8校验
* @param  Crc_ptr -> 校验数据首地址
		LEN     -> 校验数据长度
* @retval CRC_Value -> 校验值      
*/
static uint8_t CRC_8(uint8_t *Crc_ptr,uint8_t LEN)
{
	uint8_t CRC_Value = 0xFF;
	uint8_t i = 0,j = 0;

	for(i=0;i<LEN;i++)
	{
		CRC_Value ^= *(Crc_ptr+i);
		for(j=0;j<8;j++)
		{
			if(CRC_Value & 0x80)
				CRC_Value = (CRC_Value << 1) ^ 0x31;
			else
				CRC_Value = (CRC_Value << 1);
		}
	}
	return CRC_Value;
}

在读取温度的函数中首先向sht31发送开始转换命令0x2400,我将他封装在一个数据中,使用R_SAU_I2C_Write进行一次性发送。当然由于总线上有SSD1306操作时他的g_sau_i2c_master_ctrl的从机地址是SSD1306的0x3c所以,需要先配置sht31的地址,他的发送数据转换命令如下:

	g_sau_i2c_master_ctrl.slave = ptDev->slaveAddr;
	err = R_SAU_I2C_Write(&g_sau_i2c_master_ctrl,cmd, 2, true);
	I2C2WaitTxCplt();
	if(FSP_SUCCESS != err )
	{
			ptDev->read_status = 0;
			printf("Error when open i2c1 device!\r\n");
			return ;
	}

由于转换需要一段时间,需要延时。

延时之后,我一次读取6位数据,如果获取数据成功,则进行CRC并进行float转换,转换成功后放到结构体中,并更新状态:整个获取数据的代码如下:

static void sht3x_read(struct SensorDevice *ptDev)
{
	if(NULL == ptDev)  return;
	fsp_err_t err;
	uint32_t temp_uint;
	//写入开始转换的命令
	//0xE000是向SHT30取数据的指令,主机发送该指令后开始读取SHT30的温湿度数据
	uint8_t temp_array[6] = {0};
	uint8_t cmd[] = {
		0x24,0x00
	};
	g_sau_i2c_master_ctrl.slave = ptDev->slaveAddr;
	err = R_SAU_I2C_Write(&g_sau_i2c_master_ctrl,cmd, 2, true);
	I2C2WaitTxCplt();
	if(FSP_SUCCESS != err )
	{
			ptDev->read_status = 0;
			printf("Error when open i2c1 device!\r\n");
			return ;
	}
	HAL_Delay(2);
	
	err = R_SAU_I2C_Read(&g_sau_i2c_master_ctrl, temp_array, 6, true);
	I2C2WaitRxCplt();
	if(FSP_SUCCESS != err )
    {
			  ptDev->read_status = 0;
        printf("Error when open i2c1 device!\r\n");
        return ;
    }
	else
	{
		        //计算温度
        if(CRC_8(temp_array,2) == temp_array[2])                //进行CRC-8校验
        {
            temp_uint = temp_array[0]*256+temp_array[1];        //取出16位的温度值
            ptDev->Temp = ((float)temp_uint)*0.267032-4500;    //根据手册公式计算,为了精度,计算数值先*100
            ptDev->Temp = ptDev->Temp*0.01;             //再除以100,得到正常温度值
        }

        //计算湿度
        if(CRC_8(&temp_array[3],2) == temp_array[5])            //进行CRC-8校验
        {
            temp_uint = temp_array[3]*256+temp_array[4];        //取出16位的湿度值
            ptDev->Hum = ((float)temp_uint)*0.152590;           //根据手册公式计算
            ptDev->Hum = (uint8_t)(ptDev->Hum*0.01);      //除以100,得到正常湿度值
					ptDev->read_status = 1;
        }
				
				
	}
}

【数据展示】

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

void led_blink(void)
{
	
	UartDevicesRegister();

	DisplayDevice *ptDispDev = OLEDGetDevice();
    if(NULL == ptDispDev )
    {
        printf("Failed to get OLED Display Device!\r\n");
        return;
    }
		uint8_t cnt;
    ptDispDev->Init(ptDispDev);
		ptDispDev->GUI_Set_Horizontal_Mode(ptDispDev,0,128,0,64);
	SensorDevice *ptSHT31Dev = SHT31GetDevice();
	if(NULL == ptSHT31Dev)
	{
		printf("Failed to get Sht31 Device!\r\n");
		return;
	}
	while(1)
	{
		ptSHT31Dev->Read(ptSHT31Dev);
		
		if(cnt>96) cnt = 0;
        ptDispDev->GUI_clear(ptDispDev,0);
		    if(1 == ptSHT31Dev->read_status)
				{
					ptDispDev->GUI_ShowString(ptDispDev,10,16, (uint8_t *)"TEMP:",16,1);
					ptDispDev->GUI_ShowNum(ptDispDev,64,16,(int)ptSHT31Dev->Temp,2,16,1);
					ptDispDev->GUI_ShowString(ptDispDev,16,32, (uint8_t *)"HUM:",16,1);
					ptDispDev->GUI_ShowNum(ptDispDev,64,32,(int)ptSHT31Dev->Hum,2,16,1);
				}
				else
				{
					ptDispDev->GUI_ShowString(ptDispDev,10,16, (uint8_t *)"TEMP:ERROR",16,1);
				}
				ptDispDev->GUI_DrawLine(ptDispDev,0,0,cnt,0,1);
				ptDispDev->GUI_Display(ptDispDev);
		    
				//HAL_Delay(1);
		cnt ++;
	}
}

【实验效果】

image.png

【总结】

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






关键词: 刘工爱评测之瑞萨RA0单片机     SHT31     面向对    

助工
2024-06-02 09:11:46     打赏
2楼

FSP_SHT31.zip附工程源码


高工
2024-06-02 11:04:02     打赏
3楼

谢谢分享


专家
2024-06-02 11:10:04     打赏
4楼

感谢楼主分享


专家
2024-06-02 16:32:05     打赏
5楼

感谢楼主分享


共5条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]