.. index:: temperature sensor project, lmt01 temperature sensor .. _LMT01: Project: LMT01 Temperature Sensor ================================= This project displays up to three LMT01 temperature sensor readings in degrees C/F, reading one sensor at a time. The design allows for one LMT01 sensor per GPIO pin, and more can be easily added. Example Output -------------- :: testall ( only LMT01 sensors 1 and 2 are fitted ) Sensor-1: 25.5C or 77.9F Sensor-2: 25.4C or 77.7F Sensor-3: LMT01 faulty or disconnected Sensor-4: No such sensor !! ok. YouTube Video ------------- https://youtu.be/UpIYeZxftcE The LMT01 Temperature Sensor ---------------------------- The LMT01 provides a digital output in the form of a pulse count that is transmitted by a train of current pulses. After the LMT01 is powered up, it transmits a very low current of 34 µA for less than 54 ms while performing a temperature to digital conversion. When the temperature-to-digital conversion is complete, the LMT01 transmits a pulse train that toggles from the low current of 34 µA to a high current level of 125 µA. The total pulse count represents the temperature of the LMT01. LMT01 Spec ^^^^^^^^^^ The LMT01 outputs at minimum 1 pulse and a theoretical maximum of 4095 pulses. Each pulse has a weight of 0.0625°C. One pulse corresponds to a temperature less than -50°C while a pulse count of 4096 corresponds to a temperature greater than 200°C. .. warning:: The LMT01 is only ensured to operate up to 150°C. Exceeding this temperature by more than 5°C may damage the device. The accuracy of the device degrades as well when 150°C is exceeded. Software Flowchart ------------------ This is the basic design of the Forth software to read multiple LMT01 two wire temperature sensors. My next modification will be to count the pulses from the temperature sensors in a counter timer so the MCU doesn't need to do it (currently handled by interrupts), freeing up cpu cycles for more important tasks. .. image:: projects/3temp.sensors/pics/f0-lmt01-temp-sensor2-flowchart.jpg LMT01 TO-92 Package ^^^^^^^^^^^^^^^^^^^ .. image:: projects/3temp.sensors/pics/lmt01-mechanical.jpg LMT01 Waveforms ^^^^^^^^^^^^^^^ Free Running Pulse Block Timing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Taken at the Collector of Q1 .. image:: projects/3temp.sensors/pics/lmt01-free-running-pulse-block-timing.png Pulse Block Width ~~~~~~~~~~~~~~~~~ Taken at the Collector of Q1 .. image:: projects/3temp.sensors/pics/lmt01-pulse-block-width.png Individual Pulse Timing ~~~~~~~~~~~~~~~~~~~~~~~ Taken at the Collector of Q1 .. image:: projects/3temp.sensors/pics/lmt01-pulses-expanded.png The schematic ------------- .. note:: all parts inside the :ref:`STM32F0 Discovery Board` rectangle are actually built into it by ST, they aren't parts I've added for this project .. image:: projects/3temp.sensors/pics/f0-lmt01-temp-sensor-2-schematic.jpeg LMT01 Software -------------- This is actually one file :download:`f0-lmt01-temp-sensor-2.fs` but I've broken it up into three parts for clarity. If you copy and paste these files, just load part-1 first, part-2 second, and part-3 third. Part-2 ^^^^^^ This is the 'main' program which counts the temperature sensor pulses, scales and prints the results. :: : lmt01-fault? ( -- ) raw.temperature @ 0 = ; \ If a sensor has a zero count, it's faulty : pretty.print ( -- ) 0 <# # 46 hold #s #> type ; \ Insert one decimal point into final value : degrees.c ( raw -- C ) \ Print Degrees C pretty.print ." C " ; : degrees.f ( raw -- F ) \ Convert Degrees C to Degrees F (formula: °C x 9/5 + 32 = °F 90 5 / * 3200 + 10 / pretty.print ." F " ; : degrees ( -- ) lmt01-fault? if ." LMT01 faulty or disconnected " else raw.temperature @ \ fetch total number of pulses counted 10000 4096 */ 256 * 500000 - 1000 / \ Temp (C) = ((count/4096) *256) -50 scale raw temp into degrees x 10 dup degrees.c ." or " degrees.f then ; : temperature? ( sensor -- ) \ one temperature? measurement 0 lmt01-x.count ! \ lmt01-x.count increments once per lmt01-x pulse 0 raw.temperature ! \ raw.temperature is lmt01-x.count total count 0 ready.flag ! \ ready.flag is set when raw.temperature value is stable and ready to be used case \ power up selected sensor 1 OF lmt01-1.power.on ENDOF 2 OF lmt01-2.power.on ENDOF 3 OF lmt01-3.power.on ENDOF ." No such sensor !! " drop exit \ sensor not implimented fall thru warning endcase green-on \ mark start of count window tim6_cr1_cen \ start timer6 (end of timer kills the power to the lmt01) begin \ loop until raw.temperature is stable pause ready.flag @ 1 = until degrees cr ; : t temperature? ; : testall cr ( -- ) \ simple test of sensors ." Sensor-1: " 1 t ." Sensor-2: " 2 t ." Sensor-3: " 3 t ." Sensor-4: " 4 t ; Part-1 ^^^^^^ Contains all the low level routines, variables and constants :: compiletoram 0 variable lmt01-x.count 0 variable raw.temperature 0 variable ready.flag \ RCC Words : rcc_apb2enr_syscfgen-set ( -- ) %1 0 lshift rcc_apb2enr bis! ; \ rcc_apb2enr_syscfgen syscfg clock enable : rcc_apb1enr_tim6en ( -- ) %1 4 lshift rcc_apb1enr bis! ; \ rcc_apb1enr_tim6en tim6 clock enable : init.gpio ( -- ) \ One Port pull up for all sensors rcc_apb2enr_syscfgen-set \ REQUIRED!! for using GPIO's as interrupts! pull-up ( %xx -- ) 0 lshift gpioc_pupdr bis! \ gpioc_pupdr_pupdr0 PC0 ; \ LMT01 related Words : syscfg_exticr1_exti0 ( -- ) %0010 0 lshift syscfg_exticr1 bis! ; \ pc-0 is interrupt source x010: pc[0] pin : exti_imr_mr0-set ( -- ) %1 0 lshift exti_imr bis! ; \ exti_imr_mr0 set interrupt mask on line 0 : exti_pr_pr0 ( -- ) %1 0 lshift exti_pr bis! ; \ exti_pr_pr0 pending bit 0 : exti_ftsr_tr0-set ( -- ) %1 0 lshift exti_ftsr bis! ; \ exti_ftsr_tr0 falling trigger event configuration of line 0 : exti_pr_pr0-set ( -- ) %1 0 lshift exti_pr bis! ; \ exti_pr_pr0 interrupt pending flag for line 0 : nvic_iser_setena-exti0_1 ( -- ) %100000 0 lshift nvic_iser bis! ; \ nvic_iser_setena-exti0_1 : nvic_icer_clrena-exti0_1 ( -- ) %100000 0 lshift nvic_icer bis! ; \ nvic_icer_clrena-exti0_1 : lmt01-1.power.on ( -- ) output ( %xx -- ) 2 lshift gpioc_moder bis! \ gpioc_moder_moder1 PC1 %1 1 lshift gpioc_bsrr bis! \ gpioc_bsrr_bs1; output high ; : lmt01-2.power.on ( -- ) output ( %XX -- ) 4 lshift GPIOC_MODER bis! \ GPIOC_MODER_MODER2 PC2 %1 2 lshift gpioc_bsrr bis! ; \ gpioc_bsrr_bs2; output high : lmt01-3.power.on ( -- ) output ( %XX -- ) 6 lshift gpioc_moder bic! \ gpioc_moder_moder3 PC3 %1 3 lshift gpioc_bsrr bis! ; \ gpioc_bsrr_bs3; output high : lmt01-1.power.off %11 ( -- ) 2 lshift gpioc_moder bic! ; \ gpioc_moder_moder1 PC1 : lmt01-2.power.off %11 ( -- ) 4 lshift gpioc_moder bic! ; \ gpioc_moder_moder2 PC2 : lmt01-3.power.off %11 ( -- ) 6 lshift gpioc_moder bic! ; \ gpioc_moder_moder3 PC3 : lmt01-x.power.off ( -- ) \ turn off all lmt01's by switching the port from output to input mode lmt01-1.power.off lmt01-2.power.off lmt01-3.power.off ; \ Tim6 related Words 48000000 constant fCK : nvic_iser_setena-tim6 ( -- ) 1 17 lshift nvic_iser bis! ; \ nvic_iser_setena tim6 : nvic_icer_clrena-tim6 ( -- ) 1 17 lshift nvic_icer bis! ; \ nvic_icer_clrena tim6 : nvic_icpr_clrpend-tim6 ( -- ) 1 17 lshift nvic_icpr bis! ; \ nvic_icpr_clrpend tim6 : tim6_cnt@ ( -- ) tim6_cnt h@ ; \ tim6_cnt_cnt 16 bit counter value : tim6_cr1_opm ( -- ) %1 3 lshift tim6_cr1 hbis! ; \ tim6_cr1_opm one-pulse mode : tim6_cr1_cen ( -- ) %1 0 lshift tim6_cr1 hbis! ; \ tim6_cr1_cen counter enable : tim6_cr1_cdis ( -- ) %1 0 lshift tim6_cr1 hbic! ; \ tim6_cr1_cen counter disable : tim6_dier_uie ( -- ) %1 0 lshift tim6_dier hbis! ; \ tim6_dier_uie update interrupt enable : tim6_sr_uif ( -- ) %1 0 lshift tim6_sr hbic! ; \ tim6_sr_uif clear tim6 int pending flag : tim6_egr_ug ( -- ) %1 0 lshift tim6_egr hbis! ; \ tim6_egr_ug update generation : preset.psc.no.int ( -- ) \ preset Prescaler but don't cause interrupt. PSC does not get 'active' until the second update event tim6_arr h! \ preset arr tim6_egr_ug \ update generation: (causes a interrupt when run) but loads ARR into shaddow register! tim6_sr_uif \ clear tim6 int pending flag after running tim6_egr_ug tim6_dier_uie \ update interrupt enable ; : tim6.int.handler ( -- ) nvic_icpr_clrpend-tim6 \ clear pending iser for tim6 tim6_sr_uif \ clear tim6 int pending flag tim6_cr1_cdis \ counter disable nvic_icer_clrena-tim6 \ disable the tim6 interrupt or dropping power to the LMT01 will re-trigger it green-off \ mark finish of count window lmt01-x.power.off lmt01-x.count @ raw.temperature ! \ raw.temperature now contains valid lmt01 count 1 ready.flag ! \ it's safe to read raw.temperature now nvic_iser_setena-tim6 \ re-enable tim6 iser nvic_iser_setena-exti0_1 \ re enable exti0_1 iser ( won't work without this ) ; : init.tim6 ( -- ) rcc_apb1enr_tim6en \ enable tim6 in rcc tim6_cr1_opm \ one pulse mode high = Counter stops counting at the next update event (clearing the bit CEN) 47952 tim6_psc h! \ preset prescaler for 1mS (47 for 1 uS) 104 preset.psc.no.int \ preset PSC --> clear int pending flag, enable interrupt ['] tim6.int.handler irq-tim6_dac ! nvic_iser_setena-tim6 \ enable iser ; : lmt01.interrupt.handler ( -- ) exti_pr_pr0 \ clear pending bit 0 lmt01-x.count @ 1+ lmt01-x.count ! \ increment temperature count by one exti_pr_pr0-set \ clear external interrupt pending register (exti_pr) ; : init.lmt01 ( -- ) syscfg_exticr1_exti0 \ negative going pulses from lmt01 trigger pc0 interrupt exti_imr_mr0-set \ exti0 set interrupt mask on line 0 exti_ftsr_tr0-set \ falling trigger on line 0 ['] lmt01.interrupt.handler irq-exti0_1 ! \ tie the interrupt handler to the interrupt nvic_iser_setena-exti0_1 \ enable exti0_1 interrupt ; Part-3 ^^^^^^ This last part adds initialization and multitasking :: : main ( -- ) \ executed about every 5ms @48mHz pause ; : init-general ( -- ) \ executed once at boot-up f0-disco-48mhz \ switch MCU clock from 8 to 48 MHz init.gpio \ Initialisations init.tim6 init.lmt01 ; task: maintask \ essential multitasking Word : main& ( -- ) \ multitasking.fs Word maintask activate \ multitasking.fs Words begin main again \ this is the only task, and it loops forever (about every 5uS @ 48Mhz clock) unless blocked ; : init ( -- ) \ essential multitasking Word init-general \ main user application inits multitask \ multitasking.fs Word main& \ multitasking.fs Word ; init \ this init for non flash use, i.e. after uploading this program Waveforms ^^^^^^^^^ Window Start to Pulse Block Start Timing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Window and Power are the same thing displayed on CH-1 * Waveform 1: PC-1 * Waveform 2: Collector Q1 .. image:: projects/3temp.sensors/pics/lmt01-pwr-up-delay.png Pulse Block Start to Window Close Timing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * Waveform 1: PC-1 * Waveform 2: Collector Q1 .. image:: projects/3temp.sensors/pics/lmt01-pulseblock-window.close.png Testall ~~~~~~~ * Waveform 1: PC-1 * Waveform 2: Collector Q1 .. image:: projects/3temp.sensors/pics/testall.png Downloads --------- :download:`f0-lmt01-temp-sensor-2.fs ` :download:`memmap.fs ` :download:`bitfields.fs ` :download:`template.xml ` :download:`screen-f0-lmt01-temp-sens~2-cuaU0-498600-ctsrts.sh ` :download:`Kernel be337881895e64e60016a3514a0dea8e.bin ` :download:`be337881895e64e60016a3514a0dea8e.words.txt ` :download:`be337881895e64e60016a3514a0dea8e.README.txt ` :download:`lmt01.pdf ` .. note:: The Kernel binary filename is a MD5SUM of the file itself. :: md5 be337881895e64e60016a3514a0dea8e.bin MD5 (be337881895e64e60016a3514a0dea8e.bin) = be337881895e64e60016a3514a0dea8e