stm32之DS18B20温度传感器+OLED显示+RTOS多任务执行(cubemx配置,使用hal库)

这次做了个小东西,主要分为三个部分,一部分是正确接收DS18B20传感器的数据,另一部分是将接收到的数据显示到OLED上,最后一部分是使用RTOS来多任务执行,一个任务是从DS18B20传感器接收到数据后传到消息队列中,另一个任务是从消息队列中读取数据然后显示到OLED上。我们将分别讲述三个部分
代码链接,包含DS18B20的数据手册

提取码:bMGx

DS18B20传感器

cubemx配置

我们选择的是PA0引脚当作我们的数据线,所以我们先配置PA0
GPIO output level:配置为Low(表示默认输出低电平)
GPIO mode:Output Push Pull(推挽输出)
GPIO Pull-up/Pull-down:Pull-up(表示为上拉,其实在推挽输出选什么影响不大,这个选项仅在引脚处于输入态或开漏输出时起主要作用)
Maximum output speed:Low(这个选项配置最大输出速度,就是信号输出的频率)

时序配置图如下

因为DS18B20只使用一个数据线,所以我们还要自己写一个将PA0置为输入或输出的函数


RCC使用的是外部晶振时钟源

c 复制代码
void DS18B20GPIO_Out(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;//推挽输出
  GPIO_InitStruct.Pull = GPIO_PULLUP;//上拉电阻
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;//低速
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}
c 复制代码
void DS18B20GPIO_Input(void)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};

  /* GPIO Ports Clock Enable */
  __HAL_RCC_GPIOD_CLK_ENABLE();
  __HAL_RCC_GPIOA_CLK_ENABLE();

  /*Configure GPIO pin Output Level */

  /*Configure GPIO pin : PA0 */
  GPIO_InitStruct.Pin = GPIO_PIN_0;
  GPIO_InitStruct.Mode = GPIO_MODE_INPUT;//输入模式
  GPIO_InitStruct.Pull = GPIO_PULLUP;//上拉电阻,在没有输入时为高电平
  GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;//低速
  HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

配置完GPIO口之后,我们就来看数据手册的事件序列

初始化

c 复制代码
uint8_t DS18B20_Init(){
	volatile uint8_t i=0;
	DS18B20GPIO_Out();//切换为输出
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);//拉低总线
	my_delay_us(550);//延迟至少480us
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);//释放总线,拉高
	DS18B20GPIO_Input();//切换为输入模式
	my_delay_us(30);//等待传感器拉低总线
	while(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_RESET&&i<240)//等待传感器拉低总线60-240us
	{
		i++;
		my_delay_us(1);
	}
	if(i>=240) return 1;//如果一直是低电平代表没有应答成功,返回1表示连接失败
	
	return 0;//返回0表示建立连接成功
}

ROM命令

当总线上的主设备检测到了存在脉冲后,就可以执行ROM命令。这些命令是对每个设备独一无二的64位ROM编码进行操作的,当总线上连接有多个设备时,可以通过这些命令识别各个设备。所以ROM命令查找到我们具体的设备,由于我们这里只有DS18B20,所以使用下面的命令

为了写我们的命令,也需要写一个函数遵循传感器的时序将命令写入传感器,这是传感器规定的写时段

c 复制代码
void DS18B20_Write_Byte(uint8_t data)
{
	uint8_t i,testb;
	DS18B20GPIO_Out();//切换为输入模式
	for(i=0;i<8;i++)
	{
		testb=data&0x01;//取出每一个八位里的每一位bit
		data=data>>1;//数据右移准备下一次取bit,如果不想修改原始数据,可以多使用一个局部变量
		if(testb)
		{
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);//拉低总线
			my_delay_us(8);//在15us内释放总线
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);//释放总线
			my_delay_us(58);//每个写时段必须要有60us的持续时间,58+8>60
		}
		else
		{
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);//拉低总线
			my_delay_us(70);//至少拉低60us
			HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);//释放总线
			my_delay_us(2);//每个写时段至少有1us的恢复时间
		}
	}
}

DS18B20功能命令

当总线上的主设备通过ROM命令确定了哪个DS18B20能够进行通信时,主设备可以向其中一个DS18B20发送功能命令。这些命令使得主设备可以向DS18B20的暂存寄存器写入或者读出数据,初始化温度转换及定义供电模式。这里我们只列举读取温度的指令

在我们写入这个指令后,需要从传感器接数据,所以我们需要写关于读取的函数

c 复制代码
uint8_t DS18B20_Read_Bit(void)
{
	uint8_t data;
	DS18B20GPIO_Out();//切换为输出模式操作总线
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);//拉低总线
	my_delay_us(10);//至少拉低1us
	DS18B20GPIO_Input();//切换为输入模式
	if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==GPIO_PIN_SET)//判断输入的是1还是0
		data=1;
	else
		data=0;
	my_delay_us(55);//每个读时段最小必须有60us的持续时间且至少有1us的恢复时间,10+55>61
	return data;
}
uint8_t DS18B20_Read_Byte(void)
{
	uint8_t i,j,data=0;
	for(i=0;i<8;i++)
	{
		j=DS18B20_Read_Bit();//每次接收一位bit
		data=(data)|(j<<i);//将数据放入data中
	}
	return data;
}

有了这些单独的功能封装后,我们可以将其组装成一个函数,读取温度的函数,只需要调用就可以返回温度值,但是在此之前我们需要讲一下DS18B20传感器返回的数据是什么样的,精度是什么样的

我们看到上电后默认的精度就是12位精度,我们的程序并没有修改这个精度

在DS18B20中,转换的温度值以16位二进制补码形式存放在暂存寄存器的第0字节和第1字节,其中低字节存储温度的小数部分和整数低八位,高字节存储整数高八位和符号位,所以我们的程序中分别读取了这两个字节,最后拼接出16位温度数据

c 复制代码
void DS18B20_Start(void){
	DS18B20_Init();//初始化
	DS18B20_Write_Byte(0XCC);//跳过ROM
	DS18B20_Write_Byte(0X44);//温度转换
}
float DS18B20_Get_Temp(void)
{
	uint8_t tpmsb,tplsb;//tpmsb表示高八位字节,tplsb表示低八位字节
	volatile short s_tem;
	volatile float f_tem;
	DS18B20_Init();
	DS18B20_Write_Byte(0XCC);//跳过ROM命令
	DS18B20_Write_Byte(0X44);//传感器转换温度
	DS18B20_Init();//重新初始化
	DS18B20_Write_Byte(0XCC);//跳过ROM命令
	DS18B20_Write_Byte(0XBE);//读取温度数据
	tplsb=DS18B20_Read_Byte();//读取低八位
	tpmsb=DS18B20_Read_Byte();//读取高八位
	s_tem=tpmsb<<8;
	s_tem=s_tem|tplsb;//将高八位和低八位拼成16位数据
	if(s_tem<0)
		f_tem=-(~s_tem + 1)*0.0625;
  else
		f_tem=(s_tem*0.0625);//上电后默认温度为12位转换精度,0.0625分辨率		
	return f_tem;//返回处理好的温度
}

OLED显示

这个部分我是直接移植了江协科技的OLED代码,不多讲解

多任务执行

要想让我们多任务执行,就要首先配置RTOS,在这里我们创建了两个任务(实际代码中我创建了三个,有一个加了个超过阈值LED亮灯的功能)

这里我们添加任务时不需要修改,使用默认的就行了

创建队列数据类型我使用了float类型,因为我返回数据就是float类型的,然后生成代码后我们打开项目里的freertos.c文件,然后在我们创建的任务函数里写上我们的功能

c 复制代码
void StartTask02(void *argument)	//OLED显示任务
{
  /* USER CODE BEGIN StartTask02 */
  float data;
  for(;;)
  {
		taskENTER_CRITICAL();//进入临界区
		OLED_ShowString(0, 0, "temperature", OLED_8X16);
		OLED_Update();
		osMessageQueueGet(myQueue01Handle,&data,0,0);//从队列中读取数据
		OLED_ShowNum(0, 28, data, 5, OLED_8X16);//显示数据
		OLED_Update();
		taskEXIT_CRITICAL();//退出临界区
		osDelay(1);
  }
  /* USER CODE END StartTask02 */
}
c 复制代码
void StartTask03(void *argument) //读取温度任务
{
  /* USER CODE BEGIN StartTask03 */
	osThreadId_t self_task=osThreadGetId();//获得任务句柄
	float temp;
  /* Infinite loop */
  for(;;)
  {
		osThreadSetPriority(self_task,osPriorityHigh);//设置高优先级
		taskENTER_CRITICAL();//进入临界区
		temp=DS18B20_Get_Temp();//读取温度
		osMessageQueuePut(myQueue01Handle,&temp,0,0);//将数据放置到队列中
		osThreadSetPriority(self_task,osPriorityLow);//恢复默认优先级
		taskEXIT_CRITICAL();//退出临界区
    osDelay(100);
  }
  /* USER CODE END StartTask03 */
}
相关推荐
别了,李亚普诺夫31 分钟前
PCB设计大师篇笔记
笔记·嵌入式硬件·学习
点灯小铭1 小时前
双积分AD转换电路
单片机·毕业设计·课程设计·期末大作业
Zeku1 小时前
20260110 - Linux驱动学习笔记:环形缓冲区与按键防丢失
stm32·freertos·linux驱动开发·linux应用开发
youcans_1 小时前
【动手学STM32G4】(8)STM32G431之 DAC进阶
stm32·单片机·嵌入式硬件·dma·定时器
hqwest1 小时前
码上通QT实战14--监控页面06-串口设备数据初始化-
单片机·rs232·serialport·波特率·串口设备·虚拟串口设备软件·qt项目配置文件
Zeku1 小时前
20260111 - Linux驱动学习笔记:异步通知
笔记·stm32·freertos·linux驱动开发·linux应用开发
qq_397562311 小时前
BMI088 , 传感器的使用经验 . ( SPI 模式 )
单片机
点灯小铭2 小时前
基于单片机的智能收银机模拟系统设计
单片机·嵌入式硬件·mongodb·毕业设计·课程设计·期末大作业
TEC_INO2 小时前
STM32_9:I2C_DHT11_OLED项目
stm32·单片机·嵌入式硬件
__万波__2 小时前
STM32基于HAL 库开发包创建新的工程-编译-烧录
stm32·单片机·嵌入式硬件