Sıcaklığa bağlı olarak direnci değişen devre elemanlarına Termistör denir. İki farklı çeşidi vardır. “Negative Thermocouple” ifadesinin kısaltması olan NTC ve “Positive Thermocouple” ifadesinin kısaltması olan PTC . İkisinin de sıcaklığa bağlı olarak direnci değişir. Farkları ise birinin direnci sıcaklık ile artar iken diğerinin azalmasıdır.
- NTC: Sıcaklık arttıkça direnci azalır.
- PTC: Sıcaklık arttıkça direnci artar.
Bu direnç değişimleri doğrusal değildir. Bu yüzden sıcaklık hesaplamaları yapılırken bazı formüllerden yararlanılır. Bu formüllerden biri Stein-Hart denklemidir.
Bu denklemde “R” değişkeni “T(kelvin)” derecede ölçülen NTC‘nin direnç değeridir. Bu formülü kod içerisinde kullanabilmemiz için A,B ve C katsayılarını bilmemiz gerekir. Bu katsayılar NTC sıcaklık-direnç tablosuna göre hesaplanır. NTC tablosundan 3 farklı derece seçip ve bu derecelerin karşılığı olan direnç değerlerini formülde yerine yazarak 3 adet 3 bilinmeyenli denklem elde edilir. Buradan A,B ve C katsayıları bulunarak formüle yazılabilir. Ben hazır hesaplanmış olan katsayıları kullandım. Ayrıca linkteki siteden NTC sıcaklık-direnç tablosundan seçeceğiniz üç farklı değer için kendiniz A,B ve C katsayıları hesaplatıp kullanabilirsiniz.
STM32 ile NTC arasındaki bağlantı yukarıdaki gibi yapılabilir. 10k‘lık NTC yine 10k bir direnç ile pull-down bağlantı yapılarak ADC pinine bağlanmıştır.
Formüle dikkat edilecek olursa sıcaklık değerini hesaplayabilmek için NTC’nin direncini bilmemiz gerekir. Yukarıdaki bağlantıda gerilim bölücü mantığından yola çıkarak NTC’nin direnci rahatlıkla hesaplanabilir. Fakat denklem sadeleştirildiği zaman sadece ADC’den okunan 12 bitlik değeri bilmemiz yeterlidir.
Yukarıdaki denklemde görüldüğü gibi gerilim bölücüden yola çıkarak NTC nin direnci hesaplanabilir. Burada görüldüğü gibi ADC referans voltajı ve NTC nin besleme voltajı birbirini götürürür. Denklem sadeleştiği zaman aşağıdaki fonksiyondaki gibi olur.
1 2 3 4 5 6 7 8 | double Thermistor(int analogValue){ double temperature; temperature = log(((40950000 / analogValue) - 10000));// 4095 ADC çözünürlüğü(12 bit) temperature = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * temperature * temperature)) * temperature); temperature = temperature - 273.15; return temperature; } |
NOT: Denklemde dikkat ettiyseniz logaritmik işlem yapılmaktadır. Bunu yapabilmek için “math.h” kütüphanesi projeye dahil edilmelidir.
ADC’ den okunan değer bu fonksiyona gönderildiğinde geriye sıcaklık bilgisini derece cinsinden döndürmektedir.
CubeMx Ayarları
STM32-NTC Kodlarının Tamamı
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 | /** ****************************************************************************** * File Name : main.c * Description : Main program body ****************************************************************************** ** This notice applies to any and all portions of this file * that are not between comment pairs USER CODE BEGIN and * USER CODE END. Other portions of this file, whether * inserted by the user or by software development tools * are owned by their respective copyright owners. * * COPYRIGHT(c) 2019 STMicroelectronics * * Redistribution and use in source and binary forms, with or without modification, * are permitted provided that the following conditions are met: * 1. Redistributions of source code must retain the above copyright notice, * this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * 3. Neither the name of STMicroelectronics nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ #include "main.h" #include "stm32f1xx_hal.h" /* USER CODE BEGIN Includes */ #include <math.h> /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ ADC_HandleTypeDef hadc1; /* USER CODE BEGIN PV */ /* Private variables ---------------------------------------------------------*/ int adc_raw,temp; /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_ADC1_Init(void); /* USER CODE BEGIN PFP */ /* Private function prototypes -----------------------------------------------*/ double Thermistor(int analogValue){ double temperature; temperature = log(((40950000 / analogValue) - 10000)); temperature = 1 / (0.001129148 + (0.000234125 + (0.0000000876741 * temperature * temperature)) * temperature); temperature = temperature - 273.15; return temperature; } /* USER CODE END PFP */ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration----------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_ADC1_Init(); /* USER CODE BEGIN 2 */ HAL_ADC_Start(&hadc1); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { adc_raw = HAL_ADC_GetValue(&hadc1); temp = Thermistor(adc_raw); HAL_Delay(200); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** System Clock Configuration */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct; RCC_ClkInitTypeDef RCC_ClkInitStruct; RCC_PeriphCLKInitTypeDef PeriphClkInit; /**Initializes the CPU, AHB and APB busses clocks */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL7; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Initializes the CPU, AHB and APB busses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV4; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure the Systick interrupt time */ HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000); /**Configure the Systick */ HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK); /* SysTick_IRQn interrupt configuration */ HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0); } /* ADC1 init function */ static void MX_ADC1_Init(void) { ADC_ChannelConfTypeDef sConfig; /**Common config */ hadc1.Instance = ADC1; hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE; hadc1.Init.ContinuousConvMode = ENABLE; hadc1.Init.DiscontinuousConvMode = DISABLE; hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START; hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion = 1; if (HAL_ADC_Init(&hadc1) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } /**Configure Regular Channel */ sConfig.Channel = ADC_CHANNEL_0; sConfig.Rank = 1; sConfig.SamplingTime = ADC_SAMPLETIME_55CYCLES_5; if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK) { _Error_Handler(__FILE__, __LINE__); } } /** Configure pins as * Analog * Input * Output * EVENT_OUT * EXTI */ static void MX_GPIO_Init(void) { /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOD_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @param None * @retval None */ void _Error_Handler(char * file, int line) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ while(1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t* file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /** * @} */ /** * @} */ /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/ |
STMStudio programı yardımı ile “temp” isimli sıcaklık değişkeninin değerini gözlemleyebilirsiniz. Eğer daha sağlıklı bir sıcaklık değeri okumak isterseniz basit bir yazılımsal filtre uygulayabilirsiniz. Örneğin; 20 defa ADC değeri okuyup bunun aritmetik ortalamasını alıp Thermistor() fonksiyonuna gönderebilirsiniz.
İyi Çalışmalar…
Hocam NTC ile 10k nın yerlerini değiştirirsek formül nasıl değişir acaba?
Kodda NTC direncinin hesaplandığı kısım şu satırdır.
temperature = log(((40950000 / analogValue) - 10000));
burada logaritmanın içerisindeki kısım, (3,3xADC)/4095=(10^4/(10^4+R))x3,3 eşitliğinin sadeleşmiş halidir.Dediğin değişikliği yapar isek bu eşitlikte gerilim bölücüyü ilgilendiren kısım olan 10^4/(10^4+R) hesaplamasını R/(10^4+R) şeklinde düzenlemek gerekir. Burayı düzenleyip denklemi tekrar sadeleştirdiğimizde logaritma fonksiyonun içine yazılacak denklem (ADCx10^4)/(4095-ADC) şeklinde olur. Yani
temperature = log(((40950000 / analogValue) - 10000));
satırınıtemperature = log((analogvalue*10000)/(4095-analogvalue));
şeklinde değiştirince sıcaklık değeri olarak yine aynı sonucu verecektir.Teşekkür ederim.
Hocam ben bunu picte yapmaya çalışıyorum.Bu formülü kullandığımda sıcaklık değeri 6 derece fazla çıkıyor?Sebebi ne olabilir?
Kullandığın PIC’in ADC çözünürlüğü 12 bit olmayabilir. Bu örnekte STM32F103 12 bit ADC ye sahip olduğu için formülde 4095 yazıldı. Hangi PIC’i kullanıyorsun bilmiyorum ama PIC16F877A da ADC çözünürlüğü 10 bittir mesala. Eğer senin kullandığında böyle ise formülde 4095 yazan yere 1023 yazman gerekir. Birde bu örnekte NTC yi 3.3 volt ile besledim senin 5 volt ile beslemen gerekir.
12 bit kullanıyorum hocam ve 5 v ile besliyorum.
Yazıda belirtmeyi unutmuşum ben NTC olarak linkteki NTC yi kullanmıştım. Ayrıca formülde 10k’lık direncin tam 10k olduğunu kabul ederek yazıyoruz. Genelde böyle ölçümler için toleransı düşük dirençler kullanılır. Kullandığın direnç renklerine göre 10k olsa bile ölçtüğünde 10k çıkmayabilir. Tam 10k olmasa bile 6 derecelik bir sapma yapacağını zannetmiyorum gerçi. Bir de direnç değerini ölçüp formüldeki 10000 yerine direnç değerini yaz. Böylece daha yakın sonuçlar alabilirsin fakat çok hassas bir ölçüm bekleme. Hassas bir ölçüm için ekstradan filtre devresi tarzı bir şey gerekebilir. Basitçe NTC ye paralel 100nF kutupsuz bir kondansatör atabilirsin. Bunun haricinde aklıma başka bir çözüm gelmiyor İlker.
Link: https://www.direnc.net/10k-su-gecirmez-kablolu-ntc-50cm
Mehmet hocam merhabalar
Stm32f103ct8 kullanıyorum . Hocam NTC sıcaklığı ölçümü gayet güzel fakat bir sorunum. Var + sıcaklık normal. Sıcaklığı eksiye düşürdüğümde ekranda
. – işaretinin gözükmesin istiyorum örnek – 12 gibi bunu Text olarak nasıl yazdırabilirim
Merhaba,
Ölçtüğünüz sıcaklık değerini aşağıdaki örnekteki gibi bir string e çevirebilirsiniz.
int value = -12;
char string[15];
sprintf(string,”Sicaklik: %d”,value);
sprintf fonksiyonunu kullanabilmek için string.h kütüphanesini dahil etmeniz gerekir. Bir de Thermistor fonksiyonu double olarak değer döndürür. Double için %d yerine %lf kullanmanız gerek. Daha sonra bu string i ekrana gönderebilirsiniz.
teşekkür ederim mehmet hocam
Rica ederim.
neden logaritma alındığını anlayamadım
math.h kütüphanesindeki log() fonksiyonu doğal logaritmanın karşılığıdır. Yani log(R) demek aslında denklemdeki ln(R) ile aynıdır. Matematikte log10 ifadesini logaritma 10 tabanında 10 diye öğrendik. Kafa karışıklığı buradan kaynaklanıyor. math.h kütüphanesinde ise log(10) fonksiyonu logaritma e tabanında 10 demektir. Onluk tabandaki logaritma için ise log10() fonksiyonu kullanılır.
Mehmet Hocam, evdeki LED aydınlatmaya ait 12VDV 150W 12.5A SMTP de girişteki NTC üzerindeki değer okunamayacak şekilde patlamış.
Takip eden Köprü diod ve kondansatörlerle beraber değiştireceğim. NTC için ne önerirsiniz?
Hocam üzerinde yazan değere eşit bir NTC’nin işinizi göreceğini düşünüyorum. Güç kaynaklarında kullanılan NTC ler akım sınırlama amacı ile kullanılıyordu galiba. NTC lerin siyah yuvarlak kutupsuz kondansatörlere benzeyenlerinden kullanabilirsiniz ama direnç değerinden emin olamıyorum hocam. Güç kaynakları için düşük değerdeki NTC ler kullanılır. Linkteki NTC gibi olanlardan deneyebilirsiniz. https://www.direnc.net/10r-ntc
Üzerindeki değer okunmuyor demişsiniz sonradan gördüm. Aynı marka model güç kaynağının üzerinden NTC değerine bakmak lazım hocam kesin bir şey diyemiyorum ama tahminimce düşük değerdedir. 50 ohm dan küçüktür. Belki 1 ohm bile olabilir.
ben ntc ile daha önce hiç çalışmadım. Projenizi birebir uyguladım fakat stmstudio da main.c içindeki temp seçeneğini seçiyorum 140 ile 170 arası değişen sürekli durmadan hareket eden sonuçlar ortaya çıkıyor. Acaba nerede yanlış yapıyorum. ölçtüğüm değerleri nerede okuyabilirim. Yardımcı olursanız sevinirim
ADC’den yanlış ölçüm yapıyor olabilirsiniz. NTC’ye verdiğiniz gerilimi ve stm’in gerilimini ölçü aleti ile kontrol edin. Stm’in gerilimi 3.3 volttan düşük ise adc ölçümü hatalı çıkar. NTC ve seri bağlı olan direnc 10k olması gerek aksi takdirde formülde değişiklik yapılması gerekir.
Merhaba, öncelikle çok teşekkürler. Ben bu ölçtüğümüz değeri LCD ekrana yazdırmak istiyordum. Bununla ilgili bir çalışmanız var mı acaba ?
Merhaba, Bu çok genel bir soru. LCD ekran ile bir çalışmam oldu ama bu ekranların farklı farklı modeli var. Kullanıcağınız ekranın haberleşme arayüzüne göre( I2C, SPI vb.) veya diğer özelliklerine göre farklılık gösterecektir. Bazı LCD ekranların kendine özel arayüz tasarım programları oluyor( Nextion). Eğer sorunuz sadece LCD ekrana sıcaklık değerini yazdırıp yazdırmamam ise evet öyle bir çalışmam oldu.
Hii
You did a great work you have explained the topic very nicely but I have an question have you ever tried to implement VRMS to accurate the ADC readings
If yes please guide me how to do it
Thanks
Hi Pankaj,
Thanks for the comment. I have never tried to implement VRMS. I can’t help you with this issue. I’m sorry.
Merhaba Lm35 ısı sensörüyle derecelere göre 4, 5 tane led yakmaya çalışıyoruz ama başaramadık yardımcı olabilir misiniz?
Merhaba, yapmak istediklerinizi açık bir şekilde ve mümkünse geldiğiniz aşamanın kodlarıyla birlikte mehmettopuz127@gmail.com adresine mail atabilirseniz elimden geldiğince yardımcı olabilirim.
Merhaba sicakligi ölçüp belli bir dereceye ulaştığında led yakan ama lcd de gostermeyen bir kod icin vermis oldugunuz kodlarda ne gibi degisiklikler yapabilirim teşekkürler
Merhaba, buradaki örnekte kulllanacağınız tek yer Thermistor fonksiyonu olacak. Aslında bu fonksiyonun adı get_temperature() gibi bir şey de olabilir. Şimdi siz bu fonksiyonu LED’i nerede kontrol etmek istiyorsanı orada çağırabilirisiniz ( main fonksiyon içinde veya başka bir fonksiyon içinde). Örneğin;
if(get_temperature() > 25.0){
…
LED_ON();
…
}
gibi bir kullanım olabilir. LCD de göstermeyen derken ne kastettiğinizi tam anlamadım. LCD ye sıcaklık değerini göndermezseniz ekranda görünmeyecektir zaten.
Hocam meraba ledi kontrol etmek icin temp degiskenini if(temp>50) seklinde aldim bus ekilde olmasi dogru mudur sizce
ADC üzerinden NTC okuma ile ilgili bulduğum en iyi kaynak, hem ingilizce hem türkçe olarak. Hem açıklayıcı hem de detaylara fazla boğulmadan verilmiş. Kariyerinizde başarılar dilerim 🙂
Teşekkürler değerli yorumunuz için☺️