項目開源鏈接
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
文件開頭的宏定義。需要用戶提供延時微秒的函數,以及使能和失能單片機中斷的函數。
#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以及初始化了,所以這部分就不用管了,但是如果使用標準庫的話,也要添加引腳初始化。
/*************** 用戶處理區域 ****************/#define max31850_delay_ms DWT_Delay_msstatic 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中的步驟,先要定義一個初始化的函數,然后開始地址掃描、校驗、復位、選地址、轉換、讀取數據等一系列操作。
/*** @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 chipswitch (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 endmax31850_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 Scratchpadfor ( i = 0; i < 9; i++) { // we need 9 bytesone_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 defaultif (data[7] == 0x10) {// "count remain" gives full 12 bit resolutionraw = (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 themif (cfg == 0x00) raw = raw & ~7; // 9 bit resolution, 93.75 mselse if (cfg == 0x20) raw = raw & ~3; // 10 bit res, 187.5 mselse 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。
/*** @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 endmax31850_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 Scratchpadfor ( i = 0; i < 9; i++) { // we need 9 bytesone_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;
}