├── 1.jpg ├── 2.jpg ├── MAX31865Conf.h ├── .github └── FUNDING.yml ├── README.md ├── MAX31865.h ├── LICENSE.TXT └── MAX31865.c /1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimaltd/max31865/HEAD/1.jpg -------------------------------------------------------------------------------- /2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nimaltd/max31865/HEAD/2.jpg -------------------------------------------------------------------------------- /MAX31865Conf.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAX31865CONF_H 2 | #define _MAX31865CONF_H 3 | 4 | #define _MAX31865_USE_FREERTOS 1 5 | 6 | #define _MAX31865_RREF 430.0f 7 | #define _MAX31865_RNOMINAL 100.0f 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [nimaltd] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: nimaltd 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: #nimaltd 10 | issuehunt: #nimaltd 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MAX31865 Library 2 | 3 | * http://www.github.com/NimaLTD 4 | * https://www.instagram.com/github.nimaltd/ 5 | * https://www.youtube.com/@nimaltd 6 | 7 | This is the MAX31865 STM32 HAL Library 8 | Based on https://github.com/adafruit/Adafruit_MAX31865 9 | 10 | How to use this Library: 11 | * Select "General peripheral Initalizion as a pair of '.c/.h' file per peripheral" on project settings. 12 | * Enable SPI and set clock below 2MHz,MSB,CPOL LOW,CPHA 2 Edge. 13 | * Enable a gpio as Output for CS Pin. 14 | * Include Header and source into your project. 15 | * Config "Max31865Conf.h". 16 | * Call Max31865_Init( .. .. .. ). 17 | ``` c 18 | #include "Max31865.h" 19 | Max31865_t pt100; 20 | bool pt100isOK; 21 | float pt100Temp; 22 | int main() 23 | { 24 | Max31865_init(&pt100,&hspi3,SENSOR_CS1_GPIO_Port,SENSOR_CS1_Pin,4,50); 25 | while(1) 26 | { 27 | float t; 28 | pt100isOK = Max31865_readTempC(&pt100,&t); 29 | pt100Temp = Max31865_Filter(t,pt100Temp,0.1); // << For Smoothing data 30 | HAL_Delay(1000); 31 | } 32 | } 33 | ``` 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /MAX31865.h: -------------------------------------------------------------------------------- 1 | #ifndef _MAX31865_H 2 | #define _MAX31865_H 3 | 4 | /* 5 | Author: Nima Askari 6 | WebSite: http://www.github.com/NimaLTD 7 | Instagram: http://instagram.com/github.NimaLTD 8 | Youtube: https://www.youtube.com/channel/UCUhY7qY1klJm1d2kulr9ckw 9 | 10 | Version: 1.0.0 11 | 12 | 13 | Reversion History: 14 | 15 | (1.0.0) 16 | First Release. 17 | 18 | */ 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #include "gpio.h" 25 | #include "spi.h" 26 | #include 27 | //######################################################################################################################### 28 | typedef struct 29 | { 30 | GPIO_TypeDef *cs_gpio; 31 | uint16_t cs_pin; 32 | SPI_HandleTypeDef *spi; 33 | uint8_t lock; 34 | 35 | }Max31865_t; 36 | //######################################################################################################################### 37 | void Max31865_init(Max31865_t *max31865,SPI_HandleTypeDef *spi,GPIO_TypeDef *cs_gpio,uint16_t cs_pin,uint8_t numwires, uint8_t filterHz); 38 | bool Max31865_readTempC(Max31865_t *max31865,float *readTemp); 39 | bool Max31865_readTempF(Max31865_t *max31865,float *readTemp); 40 | float Max31865_Filter(float newInput, float lastOutput, float efectiveFactor); 41 | //######################################################################################################################### 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | 47 | 48 | #endif 49 | -------------------------------------------------------------------------------- /LICENSE.TXT: -------------------------------------------------------------------------------- 1 | Software License Terms 2 | 3 | This software is dual-licensed: 4 | 5 | 1. GNU General Public License v2 (GPLv2): 6 | - You may redistribute and/or modify this software under the terms of GPLv2 as published by the Free Software Foundation. 7 | - This license does not provide any warranty of any kind, including but not limited to MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 8 | - See for details. 9 | 10 | 2. Commercial License: 11 | - The commercial license removes all GPLv2 restrictions and allows you to redistribute your closed-source products with the Library embedded. 12 | - This license includes access to software maintenance, such as updates and upgrades. Customers who purchase this license are eligible to receive updates whenever 13 | they are released. However, the software provider is not obligated to release updates on a specific schedule. 14 | - The commercial license is available in two models: 15 | - Single-Product License: Allows usage in one specific product. 16 | - Company-Wide License: Allows usage across all products of the company. 17 | - No Warranty: The software is provided "AS IS" without any warranties, express or implied, including but not limited to the implied warranties of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, or NON-INFRINGEMENT. 18 | - Liability Disclaimer: In no event shall the copyright holder or contributors be liable for any claim, damages, or other liability, whether in an action of contract, tort, or otherwise, arising from, out of, or in connection with the software or the use or other dealings in the software. 19 | 20 | By using this software under the commercial license, you agree to these terms and acknowledge that no additional guarantees or obligations are provided beyond what is explicitly stated in this document. 21 | 22 | --- 23 | 24 | Copyright © Nima Askari, 2025. All rights reserved. 25 | For inquiries, contact: nima.askari@gmail.com All rights reserved 26 | -------------------------------------------------------------------------------- /MAX31865.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "max31865.h" 4 | #include "max31865Conf.h" 5 | #if (_MAX31865_USE_FREERTOS == 1) 6 | #include "cmsis_os.h" 7 | #endif 8 | //######################################################################################################################### 9 | #define MAX31856_CONFIG_REG 0x00 10 | #define MAX31856_CONFIG_BIAS 0x80 11 | #define MAX31856_CONFIG_MODEAUTO 0x40 12 | #define MAX31856_CONFIG_MODEOFF 0x00 13 | #define MAX31856_CONFIG_1SHOT 0x20 14 | #define MAX31856_CONFIG_3WIRE 0x10 15 | #define MAX31856_CONFIG_24WIRE 0x00 16 | #define MAX31856_CONFIG_FAULTSTAT 0x02 17 | #define MAX31856_CONFIG_FILT50HZ 0x01 18 | #define MAX31856_CONFIG_FILT60HZ 0x00 19 | 20 | #define MAX31856_RTDMSB_REG 0x01 21 | #define MAX31856_RTDLSB_REG 0x02 22 | #define MAX31856_HFAULTMSB_REG 0x03 23 | #define MAX31856_HFAULTLSB_REG 0x04 24 | #define MAX31856_LFAULTMSB_REG 0x05 25 | #define MAX31856_LFAULTLSB_REG 0x06 26 | #define MAX31856_FAULTSTAT_REG 0x07 27 | 28 | 29 | #define MAX31865_FAULT_HIGHTHRESH 0x80 30 | #define MAX31865_FAULT_LOWTHRESH 0x40 31 | #define MAX31865_FAULT_REFINLOW 0x20 32 | #define MAX31865_FAULT_REFINHIGH 0x10 33 | #define MAX31865_FAULT_RTDINLOW 0x08 34 | #define MAX31865_FAULT_OVUV 0x04 35 | 36 | 37 | #define RTD_A 3.9083e-3 38 | #define RTD_B -5.775e-7 39 | //######################################################################################################################### 40 | void Max31865_delay(uint32_t delay_ms) 41 | { 42 | #if (_MAX31865_USE_FREERTOS == 1) 43 | osDelay(delay_ms); 44 | #else 45 | HAL_Delay(delay_ms); 46 | #endif 47 | } 48 | //######################################################################################################################### 49 | void Max31865_readRegisterN(Max31865_t *max31865,uint8_t addr, uint8_t *buffer, uint8_t n) 50 | { 51 | uint8_t tmp = 0xFF; 52 | addr &= 0x7F; 53 | HAL_GPIO_WritePin(max31865->cs_gpio, max31865->cs_pin, GPIO_PIN_RESET); 54 | HAL_SPI_Transmit(max31865->spi,&addr, 1, 100); 55 | while (n--) 56 | { 57 | HAL_SPI_TransmitReceive(max31865->spi, &tmp, buffer, 1, 100); 58 | buffer++; 59 | } 60 | HAL_GPIO_WritePin(max31865->cs_gpio, max31865->cs_pin, GPIO_PIN_SET); 61 | } 62 | //######################################################################################################################### 63 | uint8_t Max31865_readRegister8(Max31865_t *max31865,uint8_t addr) 64 | { 65 | uint8_t ret = 0; 66 | Max31865_readRegisterN(max31865, addr, &ret, 1); 67 | return ret; 68 | } 69 | //######################################################################################################################### 70 | uint16_t Max31865_readRegister16(Max31865_t *max31865,uint8_t addr) 71 | { 72 | uint8_t buffer[2] = {0, 0}; 73 | Max31865_readRegisterN(max31865, addr, buffer, 2); 74 | uint16_t ret = buffer[0]; 75 | ret <<= 8; 76 | ret |= buffer[1]; 77 | return ret; 78 | } 79 | //######################################################################################################################### 80 | void Max31865_writeRegister8(Max31865_t *max31865,uint8_t addr, uint8_t data) 81 | { 82 | HAL_GPIO_WritePin(max31865->cs_gpio, max31865->cs_pin, GPIO_PIN_RESET); 83 | addr |= 0x80; 84 | HAL_SPI_Transmit(max31865->spi,&addr, 1, 100); 85 | HAL_SPI_Transmit(max31865->spi,&data, 1, 100); 86 | HAL_GPIO_WritePin(max31865->cs_gpio, max31865->cs_pin, GPIO_PIN_SET); 87 | } 88 | //######################################################################################################################### 89 | uint8_t Max31865_readFault(Max31865_t *max31865) 90 | { 91 | return Max31865_readRegister8(max31865, MAX31856_FAULTSTAT_REG); 92 | } 93 | //######################################################################################################################### 94 | void Max31865_clearFault(Max31865_t *max31865) 95 | { 96 | uint8_t t = Max31865_readRegister8(max31865, MAX31856_CONFIG_REG); 97 | t &= ~0x2C; 98 | t |= MAX31856_CONFIG_FAULTSTAT; 99 | Max31865_writeRegister8(max31865, MAX31856_CONFIG_REG, t); 100 | } 101 | //######################################################################################################################### 102 | void Max31865_enableBias(Max31865_t *max31865, uint8_t enable) 103 | { 104 | uint8_t t = Max31865_readRegister8(max31865, MAX31856_CONFIG_REG); 105 | if (enable) 106 | t |= MAX31856_CONFIG_BIAS; 107 | else 108 | t &= ~MAX31856_CONFIG_BIAS; 109 | Max31865_writeRegister8(max31865, MAX31856_CONFIG_REG, t); 110 | } 111 | //######################################################################################################################### 112 | void Max31865_autoConvert(Max31865_t *max31865, uint8_t enable) 113 | { 114 | uint8_t t = Max31865_readRegister8(max31865, MAX31856_CONFIG_REG); 115 | if (enable) 116 | t |= MAX31856_CONFIG_MODEAUTO; 117 | else 118 | t &= ~MAX31856_CONFIG_MODEAUTO; 119 | Max31865_writeRegister8(max31865, MAX31856_CONFIG_REG, t); 120 | } 121 | //######################################################################################################################### 122 | void Max31865_setWires(Max31865_t *max31865, uint8_t numWires) 123 | { 124 | uint8_t t = Max31865_readRegister8(max31865, MAX31856_CONFIG_REG); 125 | if (numWires == 3) 126 | t |= MAX31856_CONFIG_3WIRE; 127 | else 128 | t &= ~MAX31856_CONFIG_3WIRE; 129 | Max31865_writeRegister8(max31865, MAX31856_CONFIG_REG, t); 130 | } 131 | //######################################################################################################################### 132 | void Max31865_setFilter(Max31865_t *max31865, uint8_t filterHz) 133 | { 134 | uint8_t t = Max31865_readRegister8(max31865, MAX31856_CONFIG_REG); 135 | if (filterHz == 50) 136 | t |= MAX31856_CONFIG_FILT50HZ; 137 | else 138 | t &= ~MAX31856_CONFIG_FILT50HZ; 139 | Max31865_writeRegister8(max31865, MAX31856_CONFIG_REG, t); 140 | } 141 | //######################################################################################################################### 142 | uint16_t Max31865_readRTD (Max31865_t *max31865) 143 | { 144 | Max31865_clearFault(max31865); 145 | Max31865_enableBias(max31865, 1); 146 | Max31865_delay(10); 147 | uint8_t t = Max31865_readRegister8(max31865, MAX31856_CONFIG_REG); 148 | t |= MAX31856_CONFIG_1SHOT; 149 | Max31865_writeRegister8(max31865, MAX31856_CONFIG_REG, t); 150 | Max31865_delay(65); 151 | uint16_t rtd = Max31865_readRegister16(max31865, MAX31856_RTDMSB_REG); 152 | rtd >>= 1; 153 | return rtd; 154 | } 155 | //######################################################################################################################### 156 | //######################################################################################################################### 157 | //######################################################################################################################### 158 | void Max31865_init(Max31865_t *max31865,SPI_HandleTypeDef *spi,GPIO_TypeDef *cs_gpio,uint16_t cs_pin,uint8_t numwires, uint8_t filterHz) 159 | { 160 | if(max31865->lock == 1) 161 | Max31865_delay(1); 162 | max31865->lock = 1; 163 | max31865->spi = spi; 164 | max31865->cs_gpio = cs_gpio; 165 | max31865->cs_pin = cs_pin; 166 | HAL_GPIO_WritePin(max31865->cs_gpio,max31865->cs_pin,GPIO_PIN_SET); 167 | Max31865_delay(100); 168 | Max31865_setWires(max31865, numwires); 169 | Max31865_enableBias(max31865, 0); 170 | Max31865_autoConvert(max31865, 0); 171 | Max31865_clearFault(max31865); 172 | Max31865_setFilter(max31865, filterHz); 173 | } 174 | //######################################################################################################################### 175 | bool Max31865_readTempC(Max31865_t *max31865,float *readTemp) 176 | { 177 | if(max31865->lock == 1) 178 | Max31865_delay(1); 179 | max31865->lock = 1; 180 | bool isOk = false; 181 | float Z1, Z2, Z3, Z4, Rt, temp; 182 | Rt = Max31865_readRTD(max31865); 183 | Rt /= 32768; 184 | Rt *= _MAX31865_RREF; 185 | Z1 = -RTD_A; 186 | Z2 = RTD_A * RTD_A - (4 * RTD_B); 187 | Z3 = (4 * RTD_B) / _MAX31865_RNOMINAL; 188 | Z4 = 2 * RTD_B; 189 | temp = Z2 + (Z3 * Rt); 190 | temp = (sqrtf(temp) + Z1) / Z4; 191 | 192 | if (temp >= 0) 193 | { 194 | *readTemp = temp; 195 | if(Max31865_readFault(max31865) == 0) 196 | isOk = true; 197 | max31865->lock = 0; 198 | return isOk; 199 | } 200 | Rt /= _MAX31865_RNOMINAL; 201 | Rt *= 100; 202 | float rpoly = Rt; 203 | temp = -242.02; 204 | temp += 2.2228 * rpoly; 205 | rpoly *= Rt; // square 206 | temp += 2.5859e-3 * rpoly; 207 | rpoly *= Rt; // ^3 208 | temp -= 4.8260e-6 * rpoly; 209 | rpoly *= Rt; // ^4 210 | temp -= 2.8183e-8 * rpoly; 211 | rpoly *= Rt; // ^5 212 | temp += 1.5243e-10 * rpoly; 213 | 214 | *readTemp = temp; 215 | if(Max31865_readFault(max31865) == 0) 216 | isOk = true; 217 | max31865->lock = 0; 218 | return isOk; 219 | } 220 | //######################################################################################################################### 221 | bool Max31865_readTempF(Max31865_t *max31865,float *readTemp) 222 | { 223 | bool isOk = Max31865_readTempC(max31865,readTemp); 224 | *readTemp = (*readTemp * 9.0f / 5.0f) + 32.0f; 225 | return isOk; 226 | } 227 | //######################################################################################################################### 228 | float Max31865_Filter(float newInput, float lastOutput, float efectiveFactor) 229 | { 230 | return ((float)lastOutput*(1.0f-efectiveFactor)) + ((float)newInput*efectiveFactor) ; 231 | } 232 | //######################################################################################################################### 233 | 234 | --------------------------------------------------------------------------------