【开源】STM32HAL库移植Arduino OneWire库驱动DS18B20和MAX31850

项目开源链接

github主页 https://github.com/snqx-lqh
本项目github地址 https://github.com/snqx-lqh/STM32F103C8T6HalDemo
作者 VX Qinghua-Li7

📖 欢迎交流 如果开源的代码对你有帮助,希望可以帮我点个赞👍和收藏

项目说明

最近在做一个项目的时候,需要用到Max31850去读取PT100的温度值,使用的模块如下

由于店家给的资料只有Arduino的,然后我就把Arduino库中的OneWire库修改成了STM32可移植的C语言代码,使用函数指针面向对象设计,使得代码移植性更强。具体的操作以及演示我也有在B站进行讲解,DS18B20和MAX31850一样使用的单总线协议,所以可以共同使用这个代码。

【开源】STM32F103读取DS18B20温度(移植Arduino的OneWire库)

移植讲解

如果想要使用我移植好的OneWire库,首先需要修改u_one_wire.c文件开头的宏定义。需要用户提供延时微秒的函数,以及使能和失能单片机中断的函数。

c 复制代码
#include "u_one_wire.h"

/**************用户处理的区域*****************/
#include "delay.h"

#define noInterrupts()         __disable_irq();  //失能单片机中断
#define interrupts()           __enable_irq();   //使能单片机中断
#define one_wire_delay_us      DWT_Delay_us
/********************************************/

然后在max_31850.c,也就是传感器处理文件中,建立一个one_wire的对象,并且实现对象中的方法。主要是设置引脚方向,引脚电平和读取引脚的电平,我这里由于是使用的HAL库,CubeMX将我的GPIO以及初始化了,所以这部分就不用管了,但是如果使用标准库的话,也要添加引脚初始化。

c 复制代码
/***************    用户处理区域    ****************/

#define max31850_delay_ms DWT_Delay_ms

static uint8_t gpio_init(void)
{
	return 0;
}

static uint8_t set_pin_dir(one_wire_dir_t one_wire_dir)
{
	if(one_wire_dir == ONE_WIRE_DIR_IN)
	{
		GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=8<<(4*0);
	}else if(one_wire_dir == ONE_WIRE_DIR_OUT)
	{
		GPIOA->CRL&=0XFFFFFFF0;GPIOA->CRL|=3<<(4*0);
	}
	return 0;
}

static  uint8_t set_pin_level(uint8_t level)
{
	if(0 == level)
	{
		GPIOA->BRR  = GPIO_PIN_0;
	}else if(1 == level)
	{
		GPIOA->BSRR = GPIO_PIN_0;
	}
	return 0;
}

static uint8_t read_pin_level(void)
{
	uint8_t read_pin ;
	read_pin = HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0);
	return read_pin;
}

one_wire_dev_t max31850={
	.init = gpio_init,
	.set_pin_dir = set_pin_dir,
	.set_pin_level= set_pin_level,
	.read_pin_level= read_pin_level,
};

/**********************************************************/

最后在使用的时候,就可以参考Arduino中的步骤,先要定义一个初始化的函数,然后开始地址扫描、校验、复位、选地址、转换、读取数据等一系列操作。

c 复制代码
/**
  * @brief   初始化max31850,包含引脚初始化
  * @param   
  * @retval   
 **/
void max31850_init()
{
	 one_wire_begin(&max31850);
}
/**
  * @brief   读取max31850的温度,带扫描地址
  * @param   celsius:摄氏度 fahrenheit:华氏温度
  * @retval  
 **/
int get_max31850_temp(float *celsius,float *fahrenheit)
{
    uint8_t i;
	uint8_t present = 0;
	uint8_t temptype;
	uint8_t data[12];
	uint8_t addr[8];
	
    if(celsius == NULL || fahrenheit == NULL)
        return -1;

    if ( !one_wire_search(&max31850,addr,true)) 
	{
        one_wire_reset_search(&max31850);
        max31850_delay_ms(250);
        return -2;
    }

    if (crc8(addr, 7) != addr[7]) {
        return -3;
    }

    // the first ROM byte indicates which chip
    switch (addr[0]) {
    case 0x10:
        temptype = TYPE_DS18S20;
        break;
    case 0x28:
        temptype = TYPE_DS18B20;
        break;
    case 0x22:
        temptype = TYPE_DS18S22;
        break;
    // ADDED SUPPORT FOR MAX31850!
    case 0x3B:
        temptype = TYPE_MAX31850;
        break;
    default:
        return -4;
    }

    one_wire_reset(&max31850);
    one_wire_select(&max31850,addr);
    one_wire_write(&max31850,0x44, 1);        // start conversion, with parasite power on at the end

    max31850_delay_ms(1000);     // maybe 750ms is enough, maybe not
    // we might do a ds.depower() here, but the reset will take care of it.

    present = one_wire_reset(&max31850);
    one_wire_select(&max31850,addr);
    one_wire_write(&max31850,0xBE,0);         // Read Scratchpad

    for ( i = 0; i < 9; i++) {           // we need 9 bytes
        one_wire_read(&max31850,&data[i]);
    }

    // Convert the data to actual temperature
    // because the result is a 16 bit signed integer, it should
    // be stored to an "int16_t" type, which is always 16 bits
    // even when compiled on a 32 bit processor.
    int16_t raw = (data[1] << 8) | data[0];
    if (temptype == TYPE_DS18S20) {
        raw = raw << 3; // 9 bit resolution default
        if (data[7] == 0x10) {
            // "count remain" gives full 12 bit resolution
            raw = (raw & 0xFFF0) + 12 - data[6];
        }
    } else if (temptype == TYPE_MAX31850) {
        printf("--------------------------------\r\n");
        if (raw & 0x01) {
            return -4;
        }
    } else {
        uint8_t cfg = (data[4] & 0x60);
        // at lower res, the low bits are undefined, so let's zero them
        if (cfg == 0x00) raw = raw & ~7;  // 9 bit resolution, 93.75 ms
        else if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 ms
        else if (cfg == 0x40) raw = raw & ~1; // 11 bit res, 375 ms
         default is 12 bit resolution, 750 ms conversion time
    }
    *celsius = (float)raw / 16.0;
    *fahrenheit = *celsius * 1.8 + 32.0;
	return 0;
}

还可以跳过扫描阶段,直接获取数据,这种方式比较适合单节点的获取。就是电路上只连接了一个DS18B20或者MAX31850。

c 复制代码
/**
  * @brief   读取max31850的温度,跳过地址扫描
  * @param   celsius:摄氏度 fahrenheit:华氏温度
  * @retval  
 **/
int get_max31850_temp_skiprom(float *celsius,float *fahrenheit)
{
    uint8_t i;
	uint8_t present = 0;
	uint8_t temptype;
	uint8_t data[12];
	uint8_t addr[8];
	
    if(celsius == NULL || fahrenheit == NULL)
        return -1;
	
    one_wire_reset(&max31850);
    one_wire_skip(&max31850);
    one_wire_write(&max31850,0x44, 1);        // start conversion, with parasite power on at the end

    max31850_delay_ms(1000);     // maybe 750ms is enough, maybe not
    // we might do a ds.depower() here, but the reset will take care of it.

    present = one_wire_reset(&max31850);
    one_wire_skip(&max31850);
    one_wire_write(&max31850,0xBE,0);         // Read Scratchpad
    for ( i = 0; i < 9; i++) {                // we need 9 bytes
        one_wire_read(&max31850,&data[i]);
    }
    int16_t raw = (data[1] << 8) | data[0];
	if (raw & 0x01) {
		return -4;
	}
    *celsius = (float)raw / 16.0;
    *fahrenheit = *celsius * 1.8 + 32.0;
	return 0;
}
相关推荐
happygrilclh5 分钟前
STM32的ADC模块中,**采样时机(Sampling Time)**和**转换时机(Conversion Time),获取数据的时机详解
stm32·单片机·嵌入式硬件
真的想上岸啊33 分钟前
学习51单片机02
嵌入式硬件·学习·51单片机
sword devil9001 小时前
STM32F407VET6实战:CRC校验
stm32·单片机·嵌入式硬件
小智学长 | 嵌入式2 小时前
单片机-STM32部分:18、WiFi模组
stm32·单片机·嵌入式硬件
zkmall4 小时前
Java + 鸿蒙双引擎:ZKmall开源商城如何定义下一代B2C商城技术标准?
java·开源·harmonyos
说私域4 小时前
基于开源链动2+1模式AI智能名片S2B2C商城小程序的低集中度市场运营策略研究
人工智能·小程序·开源·零售
charles_vaez5 小时前
开源模型应用落地-模型上下文协议(MCP)-Resources-资源的使用逻辑
深度学习·语言模型·自然语言处理·开源
亿道电子Emdoor5 小时前
【ARM】MDK如何将变量存储到指定内存地址
arm开发·stm32·单片机
搬砖的小码农_Sky5 小时前
FPGA:Lattice的FPGA产品线以及器件选型建议
嵌入式硬件·fpga开发·硬件架构·硬件工程
一个没有感情的程序猿5 小时前
当 PyIceberg 和 DuckDB 遇见 AWS S3 Tables:打造 Serverless 数据湖“开源梦幻组合”
开源·serverless·aws