├── .gitignore ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── components └── esp32-thermistor │ ├── CMakeLists.txt │ ├── LICENSE │ ├── README.md │ ├── component.mk │ ├── include │ └── thermistor.h │ └── thermistor.c ├── dependencies.lock ├── images ├── NXRT15WF104FA1B.png ├── Schematic.png ├── TEK_930mv.png ├── TEK_noise.png ├── adc-noise-graph.png ├── monitor_935mv.png ├── pcb_proto_1.png ├── temp_test.gif ├── temp_test.mp4 └── visual_code_temp.gif ├── main ├── CMakeLists.txt ├── Kconfig.projbuild ├── app_main.c └── component.mk └── sdkconfig.defaults /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | sdkconfig 3 | sdkconfig.old 4 | managed_components 5 | 6 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "ESP-IDF", 5 | "compilerPath": "${default}", 6 | "cStandard": "c11", 7 | "cppStandard": "c++17", 8 | "includePath": [ 9 | "${config:idf.espIdfPath}/components/**", 10 | "${config:idf.espIdfPathWin}/components/**", 11 | "${workspaceFolder}/**" 12 | ], 13 | "browse": { 14 | "path": [ 15 | "${config:idf.espIdfPath}/components", 16 | "${config:idf.espIdfPathWin}/components", 17 | "${workspaceFolder}" 18 | ], 19 | "limitSymbolsToIncludedHeaders": false 20 | }, 21 | "compileCommands": "${workspaceFolder}/build/compile_commands.json", 22 | "configurationProvider": "ms-vscode.cmake-tools" 23 | } 24 | ], 25 | "version": 4 26 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "type": "espidf", 9 | "name": "Launch", 10 | "request": "launch", 11 | } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.clang_format_style": "Visual Studio", 3 | "editor.formatOnSave": false, 4 | "[cpp]": { 5 | "editor.quickSuggestions": { 6 | "comments": "on", 7 | "strings": "on", 8 | "other": "on" 9 | } 10 | }, 11 | "[c]": { 12 | "editor.quickSuggestions": { 13 | "comments": "on", 14 | "strings": "on", 15 | "other": "on" 16 | } 17 | }, 18 | "C_Cpp.intelliSenseEngine": "Tag Parser", 19 | "C_Cpp.default.compilerPath": "/home/jjsch/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/xtensa-esp32-elf-gdb", 20 | "idf.espIdfPath": "/home/jjsch/esp/esp-idf", 21 | "idf.toolsPath": " /home/jjsch/.espressif/tools/xtensa-esp32-elf/esp-2020r3-8.4.0/xtensa-esp32-elf/bin/", 22 | "idf.flashType": "UART", 23 | "idf.port": "/dev/ttyUSB0", 24 | "files.associations": { 25 | "atomic": "c", 26 | "ets_sys.h": "c", 27 | "ws2812_led.h": "c" 28 | }, 29 | "cmake.configureOnOpen": true, 30 | "idf.adapterTargetName": "esp32c3", 31 | "idf.openOcdConfigs": [ 32 | "board/esp32c3-ftdi.cfg" 33 | ] 34 | } 35 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Build - Build project", 6 | "type": "shell", 7 | "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py build", 8 | "windows": { 9 | "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py build", 10 | "options": { 11 | "env": { 12 | "PATH": "${env:PATH};${config:idf.customExtraPaths}" 13 | } 14 | } 15 | }, 16 | "options": { 17 | "env": { 18 | "PATH": "${env:PATH}:${config:idf.customExtraPaths}" 19 | } 20 | }, 21 | "problemMatcher": [ 22 | { 23 | "owner": "cpp", 24 | "fileLocation": [ 25 | "relative", 26 | "${workspaceFolder}" 27 | ], 28 | "pattern": { 29 | "regexp": "^\\.\\.(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 30 | "file": 1, 31 | "line": 2, 32 | "column": 3, 33 | "severity": 4, 34 | "message": 5 35 | } 36 | }, 37 | { 38 | "owner": "cpp", 39 | "fileLocation": "absolute", 40 | "pattern": { 41 | "regexp": "^[^\\.](.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 42 | "file": 1, 43 | "line": 2, 44 | "column": 3, 45 | "severity": 4, 46 | "message": 5 47 | } 48 | } 49 | ], 50 | "group": { 51 | "kind": "build", 52 | "isDefault": true 53 | } 54 | }, 55 | { 56 | "label": "Set ESP-IDF Target", 57 | "type": "shell", 58 | "command": "${command:espIdf.setTarget}", 59 | "problemMatcher": { 60 | "owner": "cpp", 61 | "fileLocation": "absolute", 62 | "pattern": { 63 | "regexp": "^(.*):(//d+):(//d+)://s+(warning|error)://s+(.*)$", 64 | "file": 1, 65 | "line": 2, 66 | "column": 3, 67 | "severity": 4, 68 | "message": 5 69 | } 70 | } 71 | }, 72 | { 73 | "label": "Clean - Clean the project", 74 | "type": "shell", 75 | "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py fullclean", 76 | "windows": { 77 | "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py fullclean", 78 | "options": { 79 | "env": { 80 | "PATH": "${env:PATH};${config:idf.customExtraPaths}" 81 | } 82 | } 83 | }, 84 | "options": { 85 | "env": { 86 | "PATH": "${env:PATH}:${config:idf.customExtraPaths}" 87 | } 88 | }, 89 | "problemMatcher": [ 90 | { 91 | "owner": "cpp", 92 | "fileLocation": [ 93 | "relative", 94 | "${workspaceFolder}" 95 | ], 96 | "pattern": { 97 | "regexp": "^\\.\\.(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 98 | "file": 1, 99 | "line": 2, 100 | "column": 3, 101 | "severity": 4, 102 | "message": 5 103 | } 104 | }, 105 | { 106 | "owner": "cpp", 107 | "fileLocation": "absolute", 108 | "pattern": { 109 | "regexp": "^[^\\.](.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 110 | "file": 1, 111 | "line": 2, 112 | "column": 3, 113 | "severity": 4, 114 | "message": 5 115 | } 116 | } 117 | ] 118 | }, 119 | { 120 | "label": "Flash - Flash the device", 121 | "type": "shell", 122 | "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} -b ${config:idf.flashBaudRate} flash", 123 | "windows": { 124 | "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py flash -p ${config:idf.portWin} -b ${config:idf.flashBaudRate}", 125 | "options": { 126 | "env": { 127 | "PATH": "${env:PATH};${config:idf.customExtraPaths}" 128 | } 129 | } 130 | }, 131 | "options": { 132 | "env": { 133 | "PATH": "${env:PATH}:${config:idf.customExtraPaths}" 134 | } 135 | }, 136 | "problemMatcher": [ 137 | { 138 | "owner": "cpp", 139 | "fileLocation": [ 140 | "relative", 141 | "${workspaceFolder}" 142 | ], 143 | "pattern": { 144 | "regexp": "^\\.\\.(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 145 | "file": 1, 146 | "line": 2, 147 | "column": 3, 148 | "severity": 4, 149 | "message": 5 150 | } 151 | }, 152 | { 153 | "owner": "cpp", 154 | "fileLocation": "absolute", 155 | "pattern": { 156 | "regexp": "^[^\\.](.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 157 | "file": 1, 158 | "line": 2, 159 | "column": 3, 160 | "severity": 4, 161 | "message": 5 162 | } 163 | } 164 | ] 165 | }, 166 | { 167 | "label": "Monitor: Start the monitor", 168 | "type": "shell", 169 | "command": "${config:idf.pythonBinPath} ${config:idf.espIdfPath}/tools/idf.py -p ${config:idf.port} monitor", 170 | "windows": { 171 | "command": "${config:idf.pythonBinPathWin} ${config:idf.espIdfPathWin}\\tools\\idf.py -p ${config:idf.portWin} monitor", 172 | "options": { 173 | "env": { 174 | "PATH": "${env:PATH};${config:idf.customExtraPaths}" 175 | } 176 | } 177 | }, 178 | "options": { 179 | "env": { 180 | "PATH": "${env:PATH}:${config:idf.customExtraPaths}" 181 | } 182 | }, 183 | "problemMatcher": [ 184 | { 185 | "owner": "cpp", 186 | "fileLocation": [ 187 | "relative", 188 | "${workspaceFolder}" 189 | ], 190 | "pattern": { 191 | "regexp": "^\\.\\.(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 192 | "file": 1, 193 | "line": 2, 194 | "column": 3, 195 | "severity": 4, 196 | "message": 5 197 | } 198 | }, 199 | { 200 | "owner": "cpp", 201 | "fileLocation": "absolute", 202 | "pattern": { 203 | "regexp": "^[^\\.](.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 204 | "file": 1, 205 | "line": 2, 206 | "column": 3, 207 | "severity": 4, 208 | "message": 5 209 | } 210 | } 211 | ], 212 | "dependsOn": "Flash - Flash the device" 213 | }, 214 | { 215 | "label": "OpenOCD: Start openOCD", 216 | "type": "shell", 217 | "presentation": { 218 | "echo": true, 219 | "reveal": "never", 220 | "focus": false, 221 | "panel": "new" 222 | }, 223 | "command": "openocd -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}", 224 | "windows": { 225 | "command": "openocd.exe -s ${command:espIdf.getOpenOcdScriptValue} ${command:espIdf.getOpenOcdConfigs}", 226 | "options": { 227 | "env": { 228 | "PATH": "${env:PATH};${config:idf.customExtraPaths}" 229 | } 230 | } 231 | }, 232 | "options": { 233 | "env": { 234 | "PATH": "${env:PATH}:${config:idf.customExtraPaths}" 235 | } 236 | }, 237 | "problemMatcher": { 238 | "owner": "cpp", 239 | "fileLocation": "absolute", 240 | "pattern": { 241 | "regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$", 242 | "file": 1, 243 | "line": 2, 244 | "column": 3, 245 | "severity": 4, 246 | "message": 5 247 | } 248 | } 249 | }, 250 | { 251 | "label": "adapter", 252 | "type": "shell", 253 | "command": "${config:idf.pythonBinPath}", 254 | "isBackground": true, 255 | "options": { 256 | "env": { 257 | "PATH": "${env:PATH}:${config:idf.customExtraPaths}", 258 | "PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter" 259 | } 260 | }, 261 | "problemMatcher": { 262 | "background": { 263 | "beginsPattern": "\bDEBUG_ADAPTER_STARTED\b", 264 | "endsPattern": "DEBUG_ADAPTER_READY2CONNECT", 265 | "activeOnStart": true 266 | }, 267 | "pattern": { 268 | "regexp": "(\\d+)-(\\d+)-(\\d+)\\s(\\d+):(\\d+):(\\d+),(\\d+)\\s-(.+)\\s(ERROR)", 269 | "file": 8, 270 | "line": 2, 271 | "column": 3, 272 | "severity": 4, 273 | "message": 9 274 | } 275 | }, 276 | "args": [ 277 | "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter_main.py", 278 | "-e", 279 | "${workspaceFolder}/build/${command:espIdf.getProjectName}.elf", 280 | "-s", 281 | "${command:espIdf.getOpenOcdScriptValue}", 282 | "-ip", 283 | "localhost", 284 | "-dn", 285 | "${config:idf.adapterTargetName}", 286 | "-om", 287 | "connect_to_instance" 288 | ], 289 | "windows": { 290 | "command": "${config:idf.pythonBinPathWin}", 291 | "options": { 292 | "env": { 293 | "PATH": "${env:PATH};${config:idf.customExtraPaths}", 294 | "PYTHONPATH": "${command:espIdf.getExtensionPath}/esp_debug_adapter/debug_adapter" 295 | } 296 | } 297 | } 298 | } 299 | ] 300 | } -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # The following five lines of boilerplate have to be in your project's 2 | # CMakeLists in this exact order for cmake to work correctly 3 | cmake_minimum_required(VERSION 3.5) 4 | 5 | set(EXTRA_COMPONENT_DIRS $ENV{RUNMAKER_PATH}/components $ENV{RUNMAKER_PATH}/examples/common) 6 | 7 | include($ENV{IDF_PATH}/tools/cmake/project.cmake) 8 | project(thermistor) 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Juan Schiavoni 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # This is a project Makefile. It is assumed the directory this Makefile resides in is a 3 | # project subdirectory. 4 | # 5 | 6 | PROJECT_NAME := thermistor 7 | 8 | include $(IDF_PATH)/make/project.mk 9 | 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ESP32 Thermistor Example 2 | 3 | This is an example of using the component [esp32-thermistor](https://github.com/jjsch-dev/esp32-thermistor/tree/master/components/esp32-thermistor) to measure the temperature using a [thermistor](https://www.murata.com/~/media/Webrenewal/Support/library/catalog/products/thermistor/ntc/r44e.ashx?la=en-us) connected to an ADC channel of ESP32-C3. 4 | 5 | ![alt text](images/NXRT15WF104FA1B.png) 6 | 7 | Although the implementation has been demonstrated with the Murata NXRT15WF104FA1B, knowing the beta coefficient published by the manufacturer, any other available on the market can be used, an example could be those that use [3D printers](https://reprap.org/wiki/Thermistor) for the bed or the hot-end. 8 | 9 | ## Circuit 10 | 11 | The thermistor is part of a resistive divider, where one of its ends is connected to GND and the other to the digital analog channel of ESP32-C3 plus the series resistor whose end is connected to 3.3 V. 12 | 13 | ![alt text](images/Schematic.png) 14 | 15 | It is important to note that the series resistance has to have a tolerance of 1% or better, and if the footprint allows the dissipated power to be better than an order of magnitude than the maximum current through it, then the stability improves. 16 | 17 | Espressif [recomend](https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/adc.html) a 0.1uF capacitor to the ADC input to minimize noise. 18 | 19 | ![alt text](images/adc-noise-graph.png) 20 | 21 | ## Prototype 22 | 23 | This component is the thermostat of an IOT project of the ceiling fan, so I started testing it on the next development board. 24 | 25 | ![alt text](images/pcb_proto_1.png) 26 | 27 | ## Behavior analysis 28 | 29 | To evaluate the performance of a thermistor that is connected to an analog digital converter, (in addition to the quality and precision of the same), many things can alter the result, for example, the stability of the power supply, the Ripple of VDD 3.3 V. , the precision of the series resistor, but especially the linearity of the ADC converter that Espressif has implemented in ESP32. 30 | I must say that the quality of the ESP32-C3 has surprised me, after using the characterization function of the ADC, the mV measurement is extremely accurate for a processor of this price. 31 | 32 | In the following images you can compare the measurement made with the oscilloscope at the analog channel input of the ESP32-C3 and the monitor output where the measured thermistor temperature is logged, as you can see the difference is a few mV. 33 | 34 | ![alt text](images/TEK_930mv.png) 35 | ![alt text](images/monitor_935mv.png) 36 | 37 | AC noise with wifi / bluetooth off is better than 15mV. 38 | 39 | ![alt text](images/TEK_noise.png) 40 | 41 | ## Brief description of the API 42 | To use the component, you need to get the handle of the instance `thermistor_handle_t` with the function `thermistor_init`, which takes as parameters the series resistance, the nominal resistance of the thermistor, the adc channel, the voltage of the source and the nominal temperature of thermistor. 43 | 44 | To get the temperature in degrees Celsius, you must call the `thermistor_get_celsius` function that returns a float, and to convert it to Fahrenheit you can use the `thermistor_celsius_to_fahrenheit` function that also returns a float. 45 | 46 | Note: With the sample application, it is possible to configure these parameters with `idf.py menuconfig`. 47 | 48 | Usage Example 49 | ---------------- 50 | ```c 51 | 52 | thermistor_handle_t th = {0}; 53 | ESP_ERROR_CHECK(thermistor_init(&th, ADC_CHANNEL_2, 54 | CONFIG_SERIE_RESISTANCE, 55 | CONFIG_NOMINAL_RESISTANCE, 56 | CONFIG_NOMINAL_TEMPERATURE, 57 | CONFIG_BETA_VALUE, 58 | CONFIG_VOLTAGE_SOURCE)); 59 | while (1) { 60 | float celsius = thermistor_get_celsius(&th); 61 | float fahrenheit = thermistor_celsius_to_fahrenheit(celsius); 62 | 63 | ESP_LOGI(TAG,"Voltage: %d mV\tTemperature: %2.1f C / %2.1f F:\tResistance: %.0f ohm", 64 | th.vout, celsius, fahrenheit, th.t_resistance); 65 | 66 | vTaskDelay(200 / portTICK_PERIOD_MS); 67 | } 68 | ``` 69 | ## Operation video 70 | The following section shows the operation of the App thermistor. The video shows the temperature logged on the monitor in degrees Celsius and Fahrenheith along with the divider voltage and the calculated resistance of the thermistor. It also displays the voltage read on an oscilloscope and tester for comparison. 71 | 72 | ![](images/temp_test.gif) 73 | 74 | The video shows the temperature recorded on the monitor in degrees Celsius and Fahrenheith when the thermistor is heated by hand. 75 | 76 | 77 | ![](images/visual_code_temp.gif) 78 | 79 | -------------------------------------------------------------------------------- /components/esp32-thermistor/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #set(COMPONENT_ADD_INCLUDEDIRS include) 2 | #set(COMPONENT_SRCS "thermistor.c") 3 | #set(COMPONENT_REQUIRES esp_adc_cal) 4 | #register_component() 5 | idf_component_register(SRCS "thermistor.c" 6 | INCLUDE_DIRS "include" 7 | REQUIRES esp_adc) 8 | -------------------------------------------------------------------------------- /components/esp32-thermistor/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Juan Schiavoni 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /components/esp32-thermistor/README.md: -------------------------------------------------------------------------------- 1 | # esp32-thermistor 2 | 3 | In construction. 4 | -------------------------------------------------------------------------------- /components/esp32-thermistor/component.mk: -------------------------------------------------------------------------------- 1 | # Use defaults 2 | -------------------------------------------------------------------------------- /components/esp32-thermistor/include/thermistor.h: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2021 Juan Schiavoni 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file thermistor.h 27 | * @brief API definitions for adc thermistor driver for ESP32. 28 | * 29 | * This component provides a means to interface with a thermistor connected 30 | * to an analog digital channel of an esp32 processor using the Espressif IDF. 31 | * 32 | * The thermistor is part of a resistive divider, where one of its ends is 33 | * connected to GND and the other to the digital analog channel plus the series 34 | * resistor whose end is connected to 3.3 V. 35 | * 36 | * The ADC initialization is carried out with the esp_adc_cal module which, 37 | * with a series of functions, uses the ADC calibration values recorded in eFuse 38 | * to linearize the response. 39 | * 40 | * The raw reading of the resistive divisor voltage becomes mV with the 41 | * esp_adc_cal_raw_to_voltage function, and since the supply voltage of the 42 | * resistive divider (3.3v) is known, with simple mathematics, the value of 43 | * the resistance of the thermistor is obtained. 44 | * 45 | * To obtain the temperature, the simplified Steniarth's equation is applied, 46 | * which uses a logarithm of the coefficient provided by the manufacturer of 47 | * the thermistor to linerize it. 48 | */ 49 | 50 | #ifndef __THERMISTOR_H__ 51 | #define __THERMISTOR_H__ 52 | 53 | #ifdef __cplusplus 54 | extern "C" { 55 | #endif 56 | 57 | #include "esp_adc/adc_cali.h" 58 | #include "esp_adc/adc_cali_scheme.h" 59 | #include "esp_adc/adc_oneshot.h" 60 | 61 | /** 62 | * @brief Structure to storing the thermistor instance. 63 | * 64 | * @note Call thermistor_init() to initialize the structure 65 | */ 66 | typedef struct 67 | { 68 | adc_oneshot_unit_handle_t adc_h;/**< ADC handle. */ 69 | adc_channel_t channel; /**< ADC channel pin where the thermistor is connected. */ 70 | float serial_resistance; /**< Value of the serial resistor connected to +3V. */ 71 | float nominal_resistance; /**< Nominal resistance at 25 degrees Celsius of thermistor. */ 72 | float nominal_temperature; /**< Nominal temperature of the thermistor, usually 25 degress Celsius. */ 73 | float beta_val; /**< Beta coefficient of the thermistor. */ 74 | float vsource; /**< Voltage to which the serial resistance is connected in mV, usually 3300.0. */ 75 | float t_resistance; /**< Calculated thermistor resistance. */ 76 | uint32_t vout; /**< Voltage in mV of thermistor channel. */ 77 | bool calibrated; /**< The calibration ADC was succesfull. */ 78 | adc_cali_handle_t adc_cali_h; /**< Calibration information handle. */ 79 | } thermistor_handle_t; 80 | 81 | /** 82 | * @brief Initialice the thermistor driver. 83 | * 84 | * This function configure the ADC, and calibrate the reference voltage 85 | * to read the vout from resitance divider. 86 | * 87 | * @param th Pointer to store the driver information. 88 | * @param channel ADC channel pin where the thermistor is connected. 89 | * @param serial_resistante Value of the serial resistor connected to +3V. 90 | * @param nominal_resistance Nominal resistance at 25 degrees Celsius of thermistor. 91 | * @param nominal_temperature Nominal temperature of the thermistor, usually 25 degress Celsius. 92 | * @param beta_val Beta coefficient of the thermistor. 93 | * @param vsource Voltage to which the series resistance is connected in mV, typically 3300.0. 94 | * 95 | * @return 96 | * - ESP_OK: Initialization OK. 97 | */ 98 | esp_err_t thermistor_init(thermistor_handle_t* th, 99 | adc_channel_t channel, float serie_resistance, 100 | float nominal_resistance, float nominal_temperature, 101 | float beta_val, float vsource); 102 | 103 | /** 104 | * @brief Read the vout of the resistance divider in mV. 105 | * 106 | * This function reads the value from the ADC and converts it to voltage in mV, 107 | * using the calibration information from the reference. 108 | * 109 | * @param th Pointer of the driver information. 110 | * 111 | * @return 112 | * - Vout in mV. 113 | */ 114 | uint32_t thermistor_read_vout(thermistor_handle_t* th); 115 | 116 | /** 117 | * @brief Converts the output voltage of the divider to degrees Celsius. 118 | * 119 | * To linearize the thermistor output use the simplified Steniarth equation. 120 | * 121 | * @param th Pointer of the driver information. 122 | * @param vout Output voltage of the resistive divider in mV. 123 | * 124 | * @return 125 | * - Temperature in degrees Celsius. 126 | */ 127 | float thermistor_vout_to_celsius(thermistor_handle_t* th, uint32_t vout); 128 | 129 | /** 130 | * @brief Get temperature in degrees Celsius from the thermistor. 131 | * 132 | * This function calls thermistor_read_vout to read the voltage from the resistive 133 | * divider and thermistor_vout_to_celsius to convert it to degrees Celsius. 134 | * 135 | * @param th Pointer of the driver information. 136 | * 137 | * @return 138 | * - Temperature in degrees Celsius. 139 | */ 140 | float thermistor_get_celsius(thermistor_handle_t* th); 141 | 142 | /** 143 | * @brief Convert temperature of degrees Celsius to Fahrenheit. 144 | * 145 | * @param temp Temperature in degrees Celsius. 146 | * 147 | * @return 148 | * - Temperature in degrees Fahrenheit. 149 | */ 150 | float thermistor_celsius_to_fahrenheit(float temp); 151 | 152 | #ifdef __cplusplus 153 | } 154 | #endif 155 | 156 | #endif /* __THERMISTOR_H__ */ 157 | -------------------------------------------------------------------------------- /components/esp32-thermistor/thermistor.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2021 Juan Schiavoni 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file thermistor.c 27 | * @brief Driver implementation of thermistor component for ESP32. 28 | */ 29 | 30 | #include "thermistor.h" 31 | 32 | #include "math.h" 33 | 34 | #include "esp_log.h" 35 | static const char* TAG = "drv_thr"; 36 | 37 | #define DEFAULT_VREF 1100 // Use adc2_vref_to_gpio() to obtain a better estimate 38 | #define NO_OF_SAMPLES 64 // Amount suggested by espresif for multiple samples. 39 | 40 | static bool adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle); 41 | 42 | esp_err_t thermistor_init(thermistor_handle_t* th, 43 | adc_channel_t channel, float serial_resistance, 44 | float nominal_resistance, float nominal_temperature, 45 | float beta_val, float vsource) 46 | { 47 | adc_oneshot_unit_handle_t adc_handle; 48 | adc_oneshot_unit_init_cfg_t init_config = { 49 | .unit_id = ADC_UNIT_1, 50 | }; 51 | 52 | esp_err_t err = adc_oneshot_new_unit(&init_config, &adc_handle); 53 | 54 | if (err == ESP_OK) { 55 | adc_oneshot_chan_cfg_t config = { 56 | .bitwidth = ADC_BITWIDTH_12, 57 | .atten = ADC_ATTEN_DB_12, 58 | }; 59 | 60 | err = adc_oneshot_config_channel(adc_handle, channel, &config); 61 | 62 | adc_cali_handle_t adc_cali_handle = NULL; 63 | th->calibrated = adc_calibration_init(ADC_UNIT_1, ADC_ATTEN_DB_12, &adc_cali_handle); 64 | th->channel = channel; 65 | th->adc_h = adc_handle; 66 | th->adc_cali_h = adc_cali_handle; 67 | th->serial_resistance = serial_resistance; 68 | th->nominal_resistance = nominal_resistance; 69 | th->nominal_temperature = nominal_temperature; 70 | th->beta_val = beta_val; 71 | th->vsource = vsource; 72 | th->t_resistance = 0; 73 | } 74 | 75 | return err; 76 | } 77 | 78 | float thermistor_vout_to_celsius(thermistor_handle_t* th, uint32_t vout) 79 | { 80 | float steinhart; 81 | 82 | // Rt = R1 * Vout / (Vs - Vout); 83 | th->t_resistance = (th->serial_resistance * vout) / (th->vsource - vout); 84 | 85 | steinhart = th->t_resistance / th->nominal_resistance; // (R/Ro) 86 | steinhart = log(steinhart); // ln(R/Ro) 87 | steinhart /= th->beta_val; // 1/B * ln(R/Ro) 88 | steinhart += 1.0 / (th->nominal_temperature + 273.15); // + (1/To) 89 | steinhart = 1.0 / steinhart; // Invert 90 | steinhart -= 273.15; // convert to C 91 | 92 | return steinhart; 93 | } 94 | 95 | uint32_t thermistor_read_vout(thermistor_handle_t* th) 96 | { 97 | int adc_raw; 98 | int voltage = 0; 99 | esp_err_t err; 100 | 101 | double sum = 0.0f; 102 | double c = 0.0f; // Variable to store the error 103 | double y; 104 | double t; 105 | int i; 106 | 107 | // Use multiple samples to stabilize the measured value, and 108 | // implement the Kahan summation algorithm to reduce the int error. 109 | for (i = 0; i < NO_OF_SAMPLES; i++) { 110 | err = adc_oneshot_read(th->adc_h, th->channel, &adc_raw); 111 | 112 | if(err != ESP_OK) { 113 | break; 114 | } 115 | 116 | y = adc_raw - c; 117 | t = sum + y; 118 | 119 | // Algebraically, c is always 0 120 | // when t is replaced by its 121 | // value from the above expression. 122 | // But, when there is a loss, 123 | // the higher-order y is cancelled 124 | // out by subtracting y from c and 125 | // all that remains is the 126 | // lower-order error in c 127 | c = (t - sum) - y; 128 | sum = t; 129 | } 130 | 131 | adc_raw = (int)(sum/i); 132 | 133 | if ((err== ESP_OK) && (th->calibrated)) { 134 | adc_cali_raw_to_voltage(th->adc_cali_h, adc_raw, &voltage); 135 | } 136 | 137 | return voltage; 138 | } 139 | 140 | float thermistor_get_celsius(thermistor_handle_t* th) 141 | { 142 | th->vout = thermistor_read_vout(th); 143 | 144 | return thermistor_vout_to_celsius(th, th->vout); 145 | } 146 | 147 | float thermistor_celsius_to_fahrenheit(float temp) 148 | { 149 | return (temp * 1.8) + 32; 150 | } 151 | 152 | static bool adc_calibration_init(adc_unit_t unit, adc_atten_t atten, adc_cali_handle_t *out_handle) 153 | { 154 | adc_cali_handle_t handle = NULL; 155 | esp_err_t ret = ESP_FAIL; 156 | bool calibrated = false; 157 | 158 | #if ADC_CALI_SCHEME_CURVE_FITTING_SUPPORTED 159 | if (!calibrated) { 160 | ESP_LOGI(TAG, "calibration scheme version is %s", "Curve Fitting"); 161 | adc_cali_curve_fitting_config_t cali_config = { 162 | .unit_id = unit, 163 | .atten = atten, 164 | .bitwidth = ADC_BITWIDTH_DEFAULT, 165 | }; 166 | ret = adc_cali_create_scheme_curve_fitting(&cali_config, &handle); 167 | if (ret == ESP_OK) { 168 | calibrated = true; 169 | } 170 | } 171 | #endif 172 | 173 | #if ADC_CALI_SCHEME_LINE_FITTING_SUPPORTED 174 | if (!calibrated) { 175 | ESP_LOGI(TAG, "calibration scheme version is %s", "Line Fitting"); 176 | adc_cali_line_fitting_config_t cali_config = { 177 | .unit_id = unit, 178 | .atten = atten, 179 | .bitwidth = ADC_BITWIDTH_DEFAULT, 180 | }; 181 | ret = adc_cali_create_scheme_line_fitting(&cali_config, &handle); 182 | if (ret == ESP_OK) { 183 | calibrated = true; 184 | } 185 | } 186 | #endif 187 | 188 | *out_handle = handle; 189 | if (ret == ESP_OK) { 190 | ESP_LOGI(TAG, "Calibration Success"); 191 | } else if (ret == ESP_ERR_NOT_SUPPORTED || !calibrated) { 192 | ESP_LOGW(TAG, "eFuse not burnt, skip software calibration"); 193 | } else { 194 | ESP_LOGE(TAG, "Invalid arg or no memory"); 195 | } 196 | 197 | return calibrated; 198 | } 199 | -------------------------------------------------------------------------------- /dependencies.lock: -------------------------------------------------------------------------------- 1 | dependencies: 2 | espressif/cbor: 3 | component_hash: 440f4ee4504841cc9b4f3a8ef755776a612ac9dace355514c68b999868f990ff 4 | source: 5 | service_url: https://api.components.espressif.com/ 6 | type: service 7 | version: 0.6.0~1 8 | espressif/esp_diag_data_store: 9 | component_hash: null 10 | source: 11 | path: /home/jjsch/esp/esp-rainmaker/components/esp-insights/components/esp_diag_data_store 12 | type: local 13 | version: 1.0.1 14 | espressif/esp_diagnostics: 15 | component_hash: null 16 | source: 17 | path: /home/jjsch/esp/esp-rainmaker/components/esp-insights/components/esp_diagnostics 18 | type: local 19 | version: 1.0.1 20 | espressif/esp_insights: 21 | component_hash: null 22 | source: 23 | path: /home/jjsch/esp/esp-rainmaker/components/esp-insights/components/esp_insights 24 | type: local 25 | version: 1.0.1 26 | espressif/esp_rainmaker: 27 | component_hash: null 28 | source: 29 | path: /home/jjsch/esp/esp-rainmaker/components/esp_rainmaker 30 | type: local 31 | version: 1.3.0 32 | espressif/esp_schedule: 33 | component_hash: null 34 | source: 35 | path: /home/jjsch/esp/esp-rainmaker/components/esp_schedule 36 | type: local 37 | version: 1.2.0 38 | espressif/esp_secure_cert_mgr: 39 | component_hash: a20007d67e65a000670ab77e45d7554c943eb8dcb0abeada0a57dd9adac3a703 40 | source: 41 | service_url: https://api.components.espressif.com/ 42 | type: service 43 | version: 2.4.1 44 | espressif/json_generator: 45 | component_hash: null 46 | source: 47 | path: /home/jjsch/esp/esp-rainmaker/components/json_generator 48 | type: local 49 | version: 1.1.1 50 | espressif/json_parser: 51 | component_hash: null 52 | source: 53 | path: /home/jjsch/esp/esp-rainmaker/components/json_parser 54 | type: local 55 | version: 1.0.3 56 | espressif/mdns: 57 | component_hash: 31117d76cae83a6d83ffd7f035f6fdae5bd05b914fc30b641afeb208b84de19a 58 | source: 59 | service_url: https://api.components.espressif.com/ 60 | type: service 61 | version: 1.3.2 62 | espressif/rmaker_common: 63 | component_hash: null 64 | source: 65 | path: /home/jjsch/esp/esp-rainmaker/components/rmaker_common 66 | type: local 67 | version: 1.4.6 68 | idf: 69 | component_hash: null 70 | source: 71 | type: idf 72 | version: 5.4.0 73 | jsmn: 74 | component_hash: null 75 | source: 76 | path: /home/jjsch/esp/esp-rainmaker/components/jsmn 77 | type: local 78 | version: 1.1.0 79 | manifest_hash: 8b86cce2941dbf67e235b917b2f146308ded47eed5d5f7b058a77f89efdf0e6d 80 | target: esp32c3 81 | version: 1.0.0 82 | -------------------------------------------------------------------------------- /images/NXRT15WF104FA1B.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/NXRT15WF104FA1B.png -------------------------------------------------------------------------------- /images/Schematic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/Schematic.png -------------------------------------------------------------------------------- /images/TEK_930mv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/TEK_930mv.png -------------------------------------------------------------------------------- /images/TEK_noise.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/TEK_noise.png -------------------------------------------------------------------------------- /images/adc-noise-graph.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/adc-noise-graph.png -------------------------------------------------------------------------------- /images/monitor_935mv.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/monitor_935mv.png -------------------------------------------------------------------------------- /images/pcb_proto_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/pcb_proto_1.png -------------------------------------------------------------------------------- /images/temp_test.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/temp_test.gif -------------------------------------------------------------------------------- /images/temp_test.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/temp_test.mp4 -------------------------------------------------------------------------------- /images/visual_code_temp.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jjsch-dev/esp32-thermistor/626772b334d042ca1cff1156c7994cf1b47058ae/images/visual_code_temp.gif -------------------------------------------------------------------------------- /main/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(COMPONENT_SRCDIRS ".") 2 | set(COMPONENT_ADD_INCLUDEDIRS ".") 3 | 4 | register_component() -------------------------------------------------------------------------------- /main/Kconfig.projbuild: -------------------------------------------------------------------------------- 1 | menu "ESP32 Thermistor Configuration" 2 | 3 | config SERIE_RESISTANCE 4 | int "Serial resistor in ohm" 5 | range 0 200000 6 | default 164000 7 | help 8 | Value of the serial resistor connected to +3V. 9 | 10 | config NOMINAL_RESISTANCE 11 | int "Th nominal resistor in ohm" 12 | range 0 200000 13 | default 100000 14 | help 15 | Nominal resistance at 25 degrees Celsius of thermistor. 16 | 17 | config NOMINAL_TEMPERATURE 18 | int "Th nominal temperature in celcius" 19 | range 0 50 20 | default 25 21 | help 22 | Nominal temperature of the thermistor, usually 25 degress Celsius. 23 | 24 | config BETA_VALUE 25 | int "Betha coefficient from thermistor manufacturer" 26 | range 0 100000 27 | default 4250 28 | help 29 | Beta coefficient of the thermistor. 30 | 31 | config VOLTAGE_SOURCE 32 | int "Voltage source CPU in mV" 33 | range 0 5000 34 | default 3330 35 | help 36 | Voltage to which the serial resistance is connected in mV, usually 3300. 37 | 38 | config BLINK_GPIO 39 | int "Blink GPIO number" 40 | range 0 34 41 | default 5 42 | help 43 | GPIO number (IOxx) to blink on and off. 44 | 45 | Some GPIOs are used for other purposes (flash connections, etc.) and cannot be used to blink. 46 | 47 | GPIOs 35-39 are input-only so cannot be used as outputs. 48 | 49 | endmenu 50 | -------------------------------------------------------------------------------- /main/app_main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * MIT License 3 | * 4 | * Copyright (c) 2021 Juan Schiavoni 5 | * 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy 7 | * of this software and associated documentation files (the "Software"), to deal 8 | * in the Software without restriction, including without limitation the rights 9 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | * copies of the Software, and to permit persons to whom the Software is 11 | * furnished to do so, subject to the following conditions: 12 | * 13 | * The above copyright notice and this permission notice shall be included in all 14 | * copies or substantial portions of the Software. 15 | * 16 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | * SOFTWARE. 23 | */ 24 | 25 | /** 26 | * @file app_main.c 27 | * @brief Example of use of the thermistor component that is connected to an 28 | * analog channel of ESP32. 29 | * With menuconfig, you can configure the parameters used by the initialization 30 | * function to obtain the instance handle. 31 | * Each 200 ms is invoked the function that reads the voltage of the resistive 32 | * divider and converts it to degrees Celsius using the simplified equation 33 | * of Steniarth. 34 | * The temperature is shown on the monitor in degrees Celsius and Fahrenheit. 35 | */ 36 | #include "freertos/FreeRTOS.h" 37 | #include "freertos/task.h" 38 | #include "driver/gpio.h" 39 | #include "thermistor.h" 40 | 41 | #include "sdkconfig.h" 42 | 43 | #include "esp_log.h" 44 | static const char* TAG = "app"; 45 | 46 | #ifdef CONFIG_IDF_TARGET_ESP32C3 47 | #include 48 | #define DEFAULT_SATURATION 100 49 | #define DEFAULT_BRIGHTNESS 50 50 | #endif 51 | 52 | /** 53 | * @brief Initialize the LED driver, with the ESP32-C3-Devkitm a neopixel 54 | * is used, for ESP32 based boards a standard LED. 55 | */ 56 | static esp_err_t init_led(void) 57 | { 58 | esp_err_t err = ESP_OK; 59 | 60 | #ifdef CONFIG_IDF_TARGET_ESP32C3 61 | err = ws2812_led_init(); 62 | ESP_LOGI(TAG, "ws2812_led_init: %d", err); 63 | #else 64 | gpio_reset_pin(CONFIG_BLINK_GPIO); 65 | gpio_set_direction(CONFIG_BLINK_GPIO, GPIO_MODE_INPUT_OUTPUT); 66 | #endif 67 | return err; 68 | } 69 | 70 | /** 71 | * @brief With Neopixel, the saturation of color changes with the value of the 72 | * temperature, and with the standard LED toggle each time. 73 | * @param celius Temperature in degrees Celsius. 74 | */ 75 | static void temperature_to_light(float celsius) 76 | { 77 | #ifdef CONFIG_IDF_TARGET_ESP32C3 78 | uint16_t g_hue = (35-(uint16_t)celsius) * 10; 79 | ws2812_led_set_hsv(g_hue, DEFAULT_SATURATION, DEFAULT_BRIGHTNESS); 80 | #else 81 | /* Toggle output */ 82 | gpio_set_level(CONFIG_BLINK_GPIO, !gpio_get_level(CONFIG_BLINK_GPIO)); 83 | #endif 84 | } 85 | 86 | void app_main(void) 87 | { 88 | thermistor_handle_t th = {0}; 89 | ESP_ERROR_CHECK(thermistor_init(&th, ADC_CHANNEL_2, 90 | CONFIG_SERIE_RESISTANCE, 91 | CONFIG_NOMINAL_RESISTANCE, 92 | CONFIG_NOMINAL_TEMPERATURE, 93 | CONFIG_BETA_VALUE, 94 | CONFIG_VOLTAGE_SOURCE)); 95 | 96 | init_led(); 97 | 98 | while(1) { 99 | float celsius = thermistor_get_celsius(&th); 100 | float fahrenheit = thermistor_celsius_to_fahrenheit(celsius); 101 | 102 | ESP_LOGI(TAG,"Voltage: %d mV\tTemperature: %2.1f C / %2.1f F:\tResistance: %.0f ohm", 103 | (int)th.vout, celsius, fahrenheit, th.t_resistance); 104 | 105 | temperature_to_light(celsius); 106 | vTaskDelay(200 / portTICK_PERIOD_MS); 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /main/component.mk: -------------------------------------------------------------------------------- 1 | # 2 | # "main" pseudo-component makefile. 3 | # 4 | # (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.) 5 | -------------------------------------------------------------------------------- /sdkconfig.defaults: -------------------------------------------------------------------------------- 1 | 2 | 3 | --------------------------------------------------------------------------------