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 */
}
相关推荐
BT-BOX18 小时前
普中开发板基于51单片机贪吃蛇游戏设计
单片机·游戏·51单片机
驴友花雕18 小时前
【花雕动手做】CanMV K230 AI视觉识别模块之使用CanMV IDE调试运行人脸代码
ide·人工智能·单片机·嵌入式硬件·canmv k230 ai视觉·canmv ide 人脸代码
点灯小铭21 小时前
基于单片机的酒驾报警刹车系统设计
单片机·嵌入式硬件·毕业设计·课程设计·期末大作业
boneStudent21 小时前
Day29:I2C 高级应用
stm32·单片机·嵌入式硬件
@good_good_study1 天前
STM32 I2C配置函数及实验
stm32·单片机
芯联智造1 天前
【stm32简单外设篇】- 28BYJ-48 步进电机(配 ULN2003 驱动板)
c语言·stm32·单片机·嵌入式硬件
喜喜安1 天前
CoreS3 屏幕背光
单片机·嵌入式硬件·m5stack cores3
星期天21 天前
1.4光敏传感器控制蜂鸣器
stm32·单片机·嵌入式硬件·江科大
沐欣工作室_lvyiyi1 天前
基于无线互联的电源健康监测与控制系统设计(论文+源码)
stm32·单片机·毕业设计·电源健康监测