Path:
Home =>
AVR overview =>
Applications =>
Thermometer ATtiny24 => Thermometer IR/RS232
Diese Seite in Deutsch:
 |
Applications of
AVR single chip controllers AT90S, ATtiny, ATmega and ATxmega
Thermometers with serial IR interfaces and ATtiny45
|
Experimental, incomplete and not tested!
Software under construction!
ATtiny45 thermometers with 2-way infrared RS232 interface
Who doesn't know that? You'd like to have an outdoor thermometer, but you
don't want to place your laptop to the outside, because you fear that he
won't withstand rain and snow for a longer time. But how to get the data
of your thermometer to the warm inside of your living room, without drilling
holes in your window frame, to get the cable through those holes?
Here is the solution for this problem: infrared passes through the glass,
without any holes in your window frame. The outdoor sensor transmits (and
receives), on the inside an infrared-to-serial converter allows to connect
to the laptop with an RS232 connection. Here you can receive the regular
transmissions of the sensor and display or collect the thermomter's
transmissions. Today you need the temperature in Kelvin, tomorrow in
°Fahrenheit and the day after tomorrow in °Celsius - no problem:
just a short command (1-TK, 1-TF or 1-TC) over the serial RS232 switches
temperature sensor number 1 to transmit its temperature in this dimension.
You need an additional temperature sensor, either outside or inside? Just
program another ATtiny45 to be number 2 and built another sensor electronic
with that. With 2-TK, 2-TF or 2-TC this sensor transmits the temperature
in another dimension. With TK, TF or TC alone all connected thermo sensors
change their dimension.
And: as long as all sensors see the IR-serial-converter and also all other
sensors, a built-in priorization mechanism controls the transmission process.
Up to ten sensors can transmit data simultanously.
You'll need to collect this data over days and monthes? No problem, each
sensor has a built-in crystal-controlled date-and-time clock and transmits
its date and time, together with the sensor number, with each temperature
report. Once initiated with D=[Date] and T=[Time] you do not have to care
about this for three monthes any more, it is as exact as your crystal is.
The drawings, such as electrical schematics and flow charts, are all in
the LibreOffice Draw file here, all
calculations are in the LibreOffice Calc file
here.
1.1 What you need
In any case you'll need:
- a computer that runs a terminal program, such as RealTerm, and
- an USB-to-serial-converter, that can be configured for 1.2 kBaud,
and
- the infrared-to-serial-converter device, equipped with a female DB9
D-Sub plug and that can receive serial signals via infrared with a
receiver module and can transmit serial signals via an Infrared-LED,
which all is controlled with an ATtiny25, a attached transformer power
supply provides the 5V for the controller and the 10V for the IR-LED,
and
- one or more temperature sensors with an ATtiny45, either for
rechargeable battery operation outdoor or transformer power supply
operation indoor.
1.2 How this works
In a temperature measurement sensor an ATtiny45 measures the temperature,
converts it to the desired dimension and to a text string and sends this
result in serial RS232 mode with 1,200 Baud over an Infrared-LED. The
indoor converter receives these IR signals and converts those to the
RS232 signal level. The RS232 signals are outputted to a female D-SUB 9 pin
connector, to be received and displayed by the terminal program on the
computer.
The ATtiny45 in each temperature sensor has a crystal-driven clock, which
starts the temperature measurement of the device in adjustable interval
periods between one and 65,535 seconds (65,535 = approx. 18 hours, 0 =
temperature measurment off). After measuring, the temperature is send in
the desired dimension, started with sensor number and the date&time stamp.
The ATtiny45 has a serial interface, which can receive serial signals over
infrared with baud rates up to 1,200 Baud. Via this interface the
following can be adjusted:
- Date and time, including selection of anglo-saxonian or german
date&number format,
- the dimension of the temperature (Kelvin, °Celsius,
°Fahrenheit),
- the three parameters, by which the temperature in Kelvin can be
calculated from the ADC's result (with applying the formula
T = a * 128ADC2 + b * 128ADC + c), therefore all sensors
can be indidually calibrated,
- and much more, see for the details below.
All relevant parameters (Temperature dimension, a, b and c) need to be
written to the device only once, because those are stored in EEPROM
and are read from there on any restart of the device (e. g. after
changing the rechargeable battery).
1.3 Details on how this works
The IR-to-serial-converter listens to incoming infrared signals. On detection
he sends those to the RXD pin on the female D-SUB plug, formatted as RS232
via a transmitter in the MAX232. Those signals are then received and displayed
by the terminal program.
The Serial-to-IR-converter takes up signals from the TXD pin of the female
DB9 plug, converts and inverts those in a MAX232 receiver and generates
active infrared signals if a binary one is detected. The active-high
input pin INT0 of the ATtiny45 starts a rectangle signal with 40 kHz
on the OC0A pin, to be converted into a constant-current for the IR LED.
The thermo sensors
- have an individual number between 0 and 9, which they start their
messages with, this number also determines the priority of any
transmissions of the device (the lower the number the higher the
priority,
- when switched on, those transmit their identification number and
some characeristic text,
- wait for incoming strings, which are analyzed like this:
- All strings end with a carriage return and a line feed. On
receiving a line feed, the collected string is analyzed.
- All blanks, minus characters and ASCII control characters
(including cariage return and line feed) are removed, all small
letters are capitalized.
- If the strings starts with a number between 0 and 9, it is checked
whether this identification is identical with its own. If not,
the string is ignored. If the identification is correct or if
no identication was given, the string is further analyzed. As the
identification is optional, it is symbolized by [n] or [n-].
- By issuing [n-]D=2/23/23 the date is set to the 23rd of
February 2023. Additionally this sets the anglosaxon formatting
of dates and numbers. [n-]D=23.2.23 fixes the german notation.
In any case the sensor answer with its identication, date, time
and temperature.
- With [n-]T=12:34:56 the time is set to 13:34:56. The sensor
answers with id, date, time and temperature.
- With [n-]TK, [n-]TC or [n-]F the dimension of the temperature
is set. Default is Kelvin.
- Issuing [n-]M=12345 activates the sensor and sets its interval
to 12345 seconds, which means he sends the temperature and its
id/date/time stamp every 12345 seconds. Depending from the
language and dimension settings those are formatted either as
"n-2/23/23-12:34:56=-15.4F" or as
"n-23.02.23-12:34:56=-15,4C". [n-]M=0 switches the
measurements off. The interval starts immediately after issuing
the command.
- With n-A=1234, n-B=1234 and n-C=1234 the three constants for
the conversion of ADC values to Kelvin-temperatures are set.
Those three costants can be calculated from three calibration
runs using the spreadsheet calculation sheet. Those are written
to EEPROM locations and the command needs only to be issued once.
Alternatively those constants can be defined in the EEP segment
during programming the device.
- With n[-]H or n[-]? or with undefined commands a help text is
issued. Always send n, otherwise you'll get the help text from
any devices in IR distance.
- With [n-] alone the current temperature issued. Any interval
settings are preserved.
The hardware consists of two different types of temperature sensors and
of the IR-to-Serial-converter (including a transformer-power-supply).
2.1 The hardware of the sensors
The hardware for Indoor- and Outdoor-sensors is slightly different,
the differences are described in the overnext subchapter.
2.1.1 The hardware of Outdoor-temperature-sensors
That is how the sensors for the outside look like. The ATtiny45 is
clocked by a crystal (either 7.68 or 4 MHz or any other, see
the spreadsheet calculation).
The supply voltage either comes from a rechargeable Lithium-Ion battery
with 3.7 Volt or from three stacked rechargeable NiMH batteries
with 1.2 Volt each. The current consumption is only elevated during
transmission of ones, so adjust the interval as long as possible
(e. g.to 60 seconds or 5 minutes) to save battery capacity. On one
page of the spreadsheet calculation you can estimate the lifetime
of the battery.
The ATtiny45 measures regularly, between 0 - no measurements - and
65.535 seconds - measurement all 18.2 hours - the temperature
of its built-in sensor, converts the ADC measurements to the temperature
in Kelvin, and from this to the desired dimension, converst this to a
string, adds id/date/time and sends this over the infrared diode as
serial signal. The converter converts this to RS232 voltage formats
and sends this to the computer.
The infrared sensor module TSOP31240 detects, if another sensor currently
transmits. If that is the case, it waits until the activity ends. For an
id-specific period the sensor then waits until its own specific wait time
is over, before it starts to transmit its own string.
If no transmission is active, the infrared sensor waits for signals, reads
those in serial mode and stores received characters in a buffer in SRAM.
If a linefeed character is received, the line is evaluated. In case the
command is valid for the sensor, it executes it.
The infrared diode LD274-3 is driven with a constant-current, if transmit
is active and a one is transmitted. Then the ATtiny45 pin OC0A (PB0)
generates a 40kHz-rectangle. This turns a red LED on, the LED's forward
voltage drives the base of the transistor, which regulates its CE current
so that the base voltage is by its B-E forward voltage smaller on its
emitter. The emitter resistor so controls the current through the LED.
If the IR-LED is not connected or is defective, the red LED remains dark,
because the transistor's base consumes a too high portion of the total
available current and the resulting base voltage is smaller than the
forward voltage of the red LED.
Here, I measured the voltages of the constant-current regulator. Voltages
are in blue, resulting currents in red and thermal-power in violet. Note
that the thermal power figures are for durable ON of the LED, the 50%
ON periods reduce the power figures to half of those listed here.
The constant-current source works from 3.3 Volt operating voltage
(and above) very stable and reliable. Only in the case if the IR-LED's
anode is driven with 10 Volt (in case of indoor sensors) and the
emitter resistor is reduced to 12Ω to use the full power range
for the IR-LED, the transistor's thermal power is slightly higher than
specified for the BC547 and a larger transistor is necessary. I used a
BD439 for that, any other NPN in a TO126 or similar casing can be used.
Why an ATtiny45 and not an ATtiny25? Now, the assembler program is rather
large, mainly because of the intensive RS232 communication and the many
possible adjustments. This did clearly not fit into the flash memory of an
ATtiny25. Of course, an ATtiny85 can also be used, just change the include
type on top of the source code.
2.1.2 The hardware of indoor temperature sensors
Generally any additional thermo-sensors can be added, but to avoid tranmission
conflicts all those sensors have to see all sensor's IR signals.
Additional indoor-temperature sensors look similar to outdoor sensors, but
the following differences have to be considered:
- Operation of indoor sensors uses the same power-supply, batteries
are not necessary. The supply of the ATtiny45 is at +5V from the
voltage regulator.
- Because the operation of the IR-LED uses the unregulated +10V
source, the supply needs three connections (+10V, 0V and +5V).
- Because the transistor has to handle up to 10V at a constant current
of max. 100mA over 50% of the time, which corresponds with 0.5 Watt,
a larger type has to be used.
- Instead of low-current-LEDs normal LEDs with 20mA can be used.
Each sensor gets his own id, which is used in transmitting and also
during reception, so that the sensors can be adjusted individually or as
a whole.
Please be aware that because of the low baudrate each sensor needs some
time for sending the long strings. So, if you select a very short interval
such as one second, and if you use baudrates of 300 Baud and lower, the
sensor number 0 blocks all other sensors from transmitting: they still
measure, but they can never transmit their result.
2.1.3 Selection of the crystal for temperature sensors
The crystal of the temperature sensor has to allow for the following
time-relevant tasks:
- The internal clock of the sensor has to be clocked with an exact
seconds signal. For this the Counter/Timer TC1 is used, which has
comprehensive prescaler variety. The prescaler is maximized for the
highest divider rate possible, which results in an as-small-as-possible
integer value. This is then divided by a CTC value, which also results
in an integer value. This is then divided by a software divider, that
leads to one second (without any fractional parts behind).
- When sending the IR-diode has to transmit with a defined frequency,
by default 40 kHz). Differences from this by +/- 0.5 kHz are
tolerable, below or above that is an increasing risk that the IR module
doesn't recognize the signal.
- When receiving serial signals the baudrate has to be exact enough, so
that the nine bits (1 start bit plus 8 data bits) are not missed. The
default are 1,200 Baud, so each bit is 833 µs long. The
receiver software doesn't use sophistic correction methods, so that
the timing error should be less than 9/2 = 4.5% of the baudrate
or +/-54 Baud or +/-37µs.
The conclusion is, that the most relevant accuracy-driver is the clock.
If you don't want to manually reset the time daily, your crystal should
provide a stable and reliable clock signal.
Because the outdoor sensor works with a 3.6 or 3.7 V battery, you can
not use crystals with 10 MHz or higher: the tiny needs 4,5 V to
work at that frequency. And we'd like to save as-much-as-possible
operating current.
The crystals in the spreadsheet "clocking_thermometer" of the
LibreOffice-Calc file here shows
all commercially available crystals in column G. Column I calculates the
resulting IR-LED frequency in Hz, column K the resulting baudrate in Bd.
As we see, many crystals can generate an exact IR frequency, those who
result in fractions are not very far away and within the acceptable tolerance.
The correct baudrate can also be reached with many crystals. All are within
the tolerable bounds.
Columns J and L calculate the squared deviations from the target values,
to get a freeling, which crystals are how near to the target. The minimum
deviations (zero) are for the 7.68 MHz crystal and for 9.6 MHz
(which is not a crystal but the default RC oscillator of an ATtiny13).
The message here is: you can use what you like, anything goes, only only
is perfect for all.
Another part of the sheet, A56 to B65, calculates the optimal divider values
for the seconds. For the selected crystal in dropdown cell B2, here 4 MHz,
and for a selected blink duration in B57, here 1 fifth of a second,
- B59 calculates the prescaler value for TC1 (here: 256), and
- B62 determines the CTC divider (here: 125), and
- B64 calculates the soft counter
for the seconds signal. 4,000,000 / 256 / 125 / 25 yields exactly 5, by which
the blink rhythm can be generated and the seconds can be derived from
(see in the software section below the flow chart of the blinking LED).
To copy all those settings to the assembler source code, the yellow area
in the sheet collects all those informations. Just select the yellow area,
copy it with Ctrl-C and paste it into the source code file with Ctrl-V.
2.2 The hardware of the IR-to-Serial-converter
The IR-to-Serial-converter receives the IR signals of the sensors and converts
those to serial signals on the RS232 voltage levels. On the other way, serial
transmissions from the RS232 transmit line are converted into IR signals and
send via IR LED to the sensors.
2.2.1 Schematic of the IR-Serial-converter
The IR-to-Serial-converter constists of
- a female DB9 plug, which serves as two-way-communication port,
- a MAX232, which converts signal levels from 5V to the RS232 level,
- the Infrared-Receiver-module TSOP31240, which receives Infrared signals,
filters those by frequency and outputs those on its sig pin,
- a crystal-driven ATtiny25, which switches an IR-LED on and off at
40 kHz, if ones come over the DB9's transmit pin, the IR-LED is
driven by a constant current supplied by a BD439 transistor and the
LED, with its anode, is tied to the unregulated +10V supply voltage,
- a 6-pin male ISP-Interface, over which the ATtiny25 can be programmed
within the system.
Within the converter only the 40-kHz-signal of the IR-diode is time-critical.
That can be achieved by nearly any crystal. I used a 4 MHz, which fits
exactly for my 40-kHz-signal. Without a crystal, only with the internal RC
oscillator of the ATtiny25, I measured 43 kHz. That is too far away from
my target frequency, so the help of the crystal is justified.
2.2.2 Transformer power supply for the IR-to-Serial-converter
This is the power supply for the converter. It provides unregulated +10V for
the IR-LED's anode as well as regulated +5V for the ATtiny25 and the MAX232.
In the ON phase of the IR-LED the power supply needs to feed 110 mA
load current. The analysis of the power supply shows that this maximum
load is permanently fine. As the LED has a duty cycle of 50%, the really
consumed load current is much smaller than this.
This reserve capacity of the power supply can be used to supply additional
indoor sensors. As their IR-LED is active only, if the converter's LED is
quiet, several additional sensors can be supplied in a row, without overloading
the power supply. Only if you supply more than five sensors, the +5V regulator
comes to his limits, due to the many blink LEDs, which are always active in
indoor sensors. In that case it makes sense to program those for the outdoor
mode, where the LED is normally off and only consumes current when blinking.
I have mounted all devices on prototyping boards and did not design any PCBs
for those. As all schematics are rather simple, it should not be a problem
to design those when needed.
3.1 Mounting the thermo sensors
That is how a sensor looks during active transmit periods.
This is the mounting of the outdoor sensor. The indoor version is similar,
the following differences between out- and indoor sensors are:
- Indoor sensors have their IR-LED-anode on separate +5V and +10V
supply pins, the re-chargeable batteries and their casing are unnecessary.
- Due to the higher thermal power of the transistor a BD439 (or eq.) is
used instead of the BC547.
- The two resistors driving the green and the red LED and the emitter
resistor that controls the constant current are slightly smaller.
- Blinking is now reversed: the green LED is permanently on and is
switched off during blinks.
The shown board is relatively large for the few components. I used a Euro
standard size for that. If you need it in smaller sizes, no problem.
If the sensor needs a weather protection, if operated on the outside, and if
you use a plastic box for that: be aware that the temperature reaches the
ATtiny45 device a little bit delayed. Even though the thermal power of the
active IR-LED and the battery is not influencing your temperature readings
to a relevant extent, you can place the IR-sensor and the IR-LED outside of
the box (by that increasing their visibility for the converter and other
sensors) and you can protect their pins with water-resistant glue from rain
and snow.
3.2 Parts list for the sensors
This is the parts list for all components of an outdoor sensor. Three quarters
of the total costs of 23€ are for the rechargeable Lithium cell and its
casing. If you are not as rich as I am, you can save a lot here. I got the
cell and the battery case for free (or as we in Southern Hesse say: for
"umme"), so do not comment on the faked 9,800 mAh capacity of my
cell: dont look a gift horse into the mouth.
3.3 Mounting the converter
This is the component placement of the converter. It includes the power supply
part. The external connections to the IR-sensor-module and the IR-LED are
made with screw terminals, so you can use whatever casing you like, and you
can place the receiver module and the IR-LED outside of the plastic case to
increase their sensitivity. If you use a plastic box with a size of
60-by-120-by-40 mm, it is not a good idea to use angled pin connectors
for the 6-pin and 10-pin connectors, because those are not accessible within
the box. The connections for the three-pin power supply to indoor sensors
are also made with screw terminals, use three 2mm plugs when installing it
into a box (not included in the parts list). The wall cable is also on a
screw terminal for easy mounting into a box.
3.4 Parts list for converter and transformer power supply
This here is the complete parts list for the converter, including the power
supply parts. Parts for placing this converter into a plastic box are not
included, so please add the box and three 2mm plugs for the power supply
of additional indoor sensors to it, if you need it.
The software for the converter and the sensors is still under construction.
I will post the source code here when it is working and has been tested.
The software of the sensors is optimized for the ATtiny45. The flash memory
of an ATtiny25 proved as too small, due to the extensive RS232 communication.
So I changed to an ATtiny45 later on.
Do not forget to burn the fuses of the ATtiny25 and ATtiny45 so their clock
comes from an external crystal. Otherwise the complete timing is confused.
The following chapters describe the internal hardware of the controller, which
is used, as well as the algorithms that the software uses. It might be used to
better understand the internals of this and it might be useful, if you want to
design alternatives.
5.1 Hardware and algorithms used in the converter
The converter works with an ATtiny25. Its task is rather simple: to detect
signals that come from the transmit pin of the female DB9 and, after inversion
in the MAX232, to transmit with 40 kHz over the IR-LED, when the
input pin is high, and to switch the LED off if low.
The scheme on the right shows the clocks when transmitting a single character.
Responsible for the detection is the INT0 interrupt. This executes on every
transition of the INT0 pin. If the ISR finds a zero on the PB2 input pin, it
switches the TC0's OC0A output pin to clear, the constant current gets zero
and the IR-LED is off (CLR). If a high input is detected, the timer TC0's
OC0A pin is set to toggle (TGL), the constant current driver and the LED are
switched on and off.
For the green LED, that is connected to the PB1 pin, I have invented a nice
mode. As the serial baudrate is 1,200 Baud, just switching it on at high
bits from the serial transmit pin is nearly invisibly short. So I decided
to blink the LED with two different frequencies: a slow blinking when
the input pin is inactive (by default: 2 Hz), and a fast blinking if
signals come in (by default: 5 Hz). The number of blinks after the last
activity on the input pin can be selected by software.
The blink mechanism uses TC1's output pin OC1A on pin PB1. This output is
set to toggle in any case, the toggle speed is adjusted with the OCR1C
comparer in TC1. In inactive times the prescaler of TC1 divides the clock
signal by 4,096 and OCR1C's compare value is set to 243. That yields a
toggle frequency of 4,000,000 / 4,096 / (243 + 1) or 4 Hz. The blink
frequency is half the toggle frequency.
If the INT0 input pin PB2 detects high signals, it changes the prescaler to
2,048 and writes 194 to OCR1C. Now the OC1A output pin toggles faster, with
4,000,000 / 2,048 / (194 + 1) or 10 Hz. A toggle counter in rTgl is
set to the number of toggles (by default: 10). It further enables the
OCIE1B interrupt, which counts the number of blinks down whenever the
counter restarts (right side of the flow diagram). This activated state
also sets the T flag, by which further incoming positive signals on the
input pin do not restart the blink mechanism any more.
If the blink counter reaches zero,
- it clears the T flag, and
- the OCIE1B interrupt is disabled, and
- the prescaler and the OCR1C value are set to slow blinking.
All those settings (the desired crystal, the IR frequency, the baud rate,
the normal and active blink frequency, the number of blinks) can be changed
using the spreadsheet
"IR-over-serial-converter" in the LibreOffice Calc file
here and fill in all desired values in the
cells with a green background. Then copy the yellow cells to the right of the
sheet and paste those to the assembler source code. This configures anything
at once.
5.2 Algoriths used in sensors
The software of the sensors is rather complex. This is demonstrated with the
active interrupt-vectors, which look like that:
;
; **********************************
; R E S E T & I N T - V E C T O R S
; **********************************
rjmp Main ; Reset vector
rjmp Int0Isr ; INT0
reti ; PCI0
rjmp Oc1aIsr ; OC1A
reti ; OVF1
reti ; OVF0
rjmp ErdyIsr ; ERDY
reti ; ACI
rjmp AdccIsr ; ADCC
reti ; OC1B
rjmp Oc0aIsr ; OC0A
reti ; OC0B
reti ; WDT
reti ; USI_START
reti ; USI_OVF
Six of the 15 vektors are in use, behind Oc0aIsr in reality are three
different sections, depending from the current sub-tasks tranmitting,
receiving and waiting for transmitting.
The single components of the sensors are described in more detail in the
following sub chapters.
5.2.1 The clock in the sensor
Each thermo sensor has a programmed crystal clock. That makes it possible
to add the date&time stamp to any temperature measurement. The date
can be initiated via the command (over the serial transmitter)
"D=2/26/23", which sets all dates in all sensors. The time can be
initiated by sending "T=12:34:56" over the transmitter. Following
that, all sensors have the same date and time.
For clocking the clock, the Timer TC1 divides the crystal-controlled
controller clock by a prescaler and, in CTC mode, by the Compare-A value
(plus one). On reaching the Compare-A value, the OC1A interrupt is triggered.
To enable the use of many different crystals, a down-counter in the ISR can
divide the clock either by one, or by an 8-bit- or by a 16-bit-value. The
type of down-counter is in the constant cTc1Bits (0, 8 or 16). Within the
respective Interrupt-Service-Routine the following, depending from the state
of the constant cTc1Bits, is executed:
- cTc1Bits = 0: The flag bSec in the flag register is set.
- cTc1Bits = 8: An 8-bit counter in SRAM, sTc1Cnt, is decreased. If that
reaches zero, the flag bSec is set and the timer is re-started with
cTc1Cnt.
- cTc1Bits > 8: A 16-bit-counter in SRAM, sTc1Cnt+1:sTc1Cnt,
is decreased by one. If both bytes reach zero, the flag bSec is set
and the counter is re-started with cTc1Cnt.
Hence, the crystal clock frequency is divided by the prescaler, by the
CTC-Compare value and the 0-/8-/16-bit counter. This all yields not a
second, but the clock frequency by which the green LED shall be toggled.
Depending from the setting of constants, this can be one second, a halve
second, a quarter second or what-so-ever, depending from the cell B57
of the spreadsheet "clocking_thermometer".
The flag bSec causes to further handle the clock info in the routine
HdlSec: outside the ISR.
The clocking of the green LED does the following. The flag bBlk indicates
if blinking is currently active. If this the case, the PINB port register
of the green LED is set, by that toggling the PORTB bit. The blink counter
is decreased, and, if zero, the bBlk flag is cleared.
One basic rule with handling the SRAM bytes within the routine is that the
Z pointer points to the beginning of that structure in SRAM. Instead of
LDS and STS, that needs two words per instruction, the routines often use
single-word LDD and STD instructions by temporarily adding displacements
to Z's address. This saves a lot of flash memory, because date and time
handling requires many different byte accesses to SRAM locations. The
displacements have defined constants, their names all start with
"d".
In the counter at Z+dBlink always an even value has to be written, so
that after the end of blinking the default state of the LED is reached
again. This state can be ON (in indoor sensors, powered by the transformer
power supply) or OFF (in outdoor sensors, powered from batteries).
The 8-bit-counter in Z+dSecCnt counts down the number of blinks
(multiplied by two), and, at the end, reaches one second.
Increasing the clock by one second starts with the test, if the measuring
interval has a value of zero. If that is not the case, the 16-bit interval
counter in sMeasCnt+1:sMeasCnt is decreased and, on zero, the next
measurement is started.
The measurement start takes 128 single ADC measurements, sums those up,
calculates the temperature in Kelvin and, if desired in °Celsius or
°Fahrenheit, forms a string from that and sends this over the serial
interface. The measurement algorithm is independant from further time
and date handling, see the three sub-chapters below for details.
Increasing the clock by one second includes increasing the date, if the
time is at 23:59:59.
This is the algorithm to add one second to time and date. To the left,
the time increases by one. At the end of the day, the date is increased
by one day, the flow on the right. The major part to the flow on the right
is the correct detection if the next month starts. A complicated algorithm,
but any complains about that go back to Pope Gregor in the 15th century,
which needed that complication due to earth's crazy circular movements
around the sun.
As the measuring has been initiated already at the beginning, it is a question
whether this measurement uses the previous or the next time stamp (which can
have a difference of up to one year). As this routine executes until all
Gregorian complications have been finally considered, and as the set bAdc
flag after 128 measurements is only seen from the controller after the next
wake-up from sleep, the next measurement uses the next date/time stamp in
any case and as a whole, so no protection has to be added to prevent from
incomplete time&date settings.
5.2.2 Measuring the temperature in the sensor
The built-in temperature sensor in the ATtiny45 is available at the multiplex
address 0b1111 in port register ADMUX. As measuring the sensor requires that
the voltage source of the internal 1.1V is used as reference, the VREF bits
in ADMUX are to be set according to this. As no other ADC channels need to be
measured, this channel can be fixed at start-up.
The handbook of the ATtiny45 gives the following relationship of the ADC value
at three temperatures:
Behind that is not a simple linear function, how the diagram to the right
demonstrates: neither the ascending slope nor the constant adder are nearly
the same below and above 25°Celsius. On such a rough basis, a temperature
calculation is rather rough, it allows resolutions of +/-1° only, a
resolution of +/-0.2 or +/-0.1 is impossible with that.
As already used in another project on this webpage (see
here) I devellopped a squared function
to better interpolate those: T = a * ADC2 + b * ADC + c. T is the
temperature in Kelvin, of course. With the original values of ATMEL, the three
parameters of this function are as follows.
The parameter a, the squared part, is negative, which means: the curve is
slightly reducing its slope with increasing ADC values. The linear parameter
b is anything else than 1.0, which is ATMEL's interpolation suggestion.
Now, the multiplication with 0.000510 or with 1.198980 does not feel good
for an assembler programmer: I hear a loud cry for the floating math
library here. And that does not fit into the flash memory of an ATtiny45.
But, in contrast to C-dependents, the assembler programmer knows better
and much faster ways to come around this. Here is how he resolves this task.
The resulting temperature shall have a resolution of 0.1°. If we multiply
the temperature T with 10, we'll get an integer. If we convert this to
decimal, we just smuggle a dot into that, right before we issue the last
digit of the decimal. That is already it to get rid from the floating number
lib.
And, of course we'll have to measure the temperature repeatedly, to get rid
of the unavoidable toggling of the last bit in the ADC. In order to get
more exact results, we can add the results from 128 measurements, without
having to fear an overflow of a 16-bit integer for the sum value. This
would only happen if the temperature exceeds 191°Celsius, by which
the ATtiny45's silicon chip would not work correct any more and is on way
towards melting.
The summing of several ADC measurements increases the resolution, not by the
128-fold but allows for at least a +/-0.2° resolution. The formula now
is:
10*T = a * 128*ADC2 + b * 128*ADC + c
In the spreadsheet "temp-scaling" of the LibreOffice-Calc file
here we'll get a, b and c
calculated. Use this sheet to calculate your own parameters from your
calibration run data.
This diagram shows the contribution of all three components in the squared
function. The linear part contributes the highest, but the other two factors
are on remarkably high values. The slopes of the a- and b-contribution are
rather low, and cannot be really seen in that diagram. Note that the opposite
function, ADC = a * T2 + b * T + c, has been used here instead
of the above formula.
How large are the differences between this squared function compared to a
linear interpolation? Now, as the differences at 25°Celsius are small,
I have calculated that for a range from 45 to 50°Celsius. The differences
are around 0.5°. We'll never had reached an accuracy of +/-0.2° with
a linear function, and we can be sure that displaying +/-0.1° has a
solid base with the square function.
5.2.3 Converting measuring results to temperatures
Another hurdle in calculating temperatures from ADC values is the
multiplication with 3.114E-07 and with 0.093670. To do that, we'll use
another trick: we'll multiply the 3,114E-7 simply with 65,536 * 65,536,
which results in 1.337, and we'll skip the lowest four bytes of the
result. The same with 0.093670: here we multiply by 65,536, which yields
rounded 6139, and skip the lower two bytes of the multiplication result.
This results in the column L in three assembler code lines:
; Parameters, export from spreadsheet to source code
.equ cParA = 1337 ; 65536*65536*a in 10*T=-a*128ADC*128ADC+b*128ADC-c
.equ cParB = 6139 ; 65536*b in 10*T=-a*128ADC*128ADC+b*128ADC-c
.equ cParC = 156 ; c in 10*T=-a*128ADC*128ADC+b*128ADC-c
With those generic values the temperature sensor converts its ADC results
to temperatures, right until the serial interface transmits other values
for a, b and c.
The ADC sum of 128 measurements as well the parameters fit well into 16 bits.
We can now
- multiply parameter b with the 128-sum and store the 4-byte result in
SRAM, and then
- multiply parameter a with the 128-sum, divide the four bytes by
65.536 (by skipping the two lower bytes) and subtract this from the
stored value, and
- subtract parameter c from bytes 3 and 4 of previous result, and
- we use the lower two bytes of the result to round the result in the
upper two bytes.
What comes out is the 10-fold of the temperature in K, which also fits
into 16 result bits.
Depending from the states of the two flags bTC and bTF we'll have to
calculate the °Celsius and °Fahrenheit from this. The Celsius
* 10 comes out, if we subtract 273.15 * 10 from the Kelvin. The Fahrenheit
comes out if we multiply the Celsius with 1.8 * 10 and add 32 * 10 to that.
In both cases the result can be negative, so we'll have to set a flag and
to calculate 65.536 minus degrees from that to get it positive. The 16-bit
value is the temperature in the desired dimension, multiplied by 10.
5.2.4 Converting the temperature to decimal in the tranmit buffer
The rest now is simple hand-crafting:
- to set the transmit pointer X to the beginning of the transmit buffer
in SRAM,
.
- add the id of the sensor (0 to 9) and a minus-character,
- to write the date in the correct format (english or german) to the
transmit buffer, followed by a minus,
- add the time, separated with ":", to the tranmsit buffer,
followed by an "=",
- if the temperature flag signals negative, add another minus,
- add the temperatur as positive integer with a dot (english) or a
komma (german) prior to the last digit,
- add carriage return, line-feed and the cursor character as well as
the final null character to it,
- point the pointer X back to the start, and
- set the wait flag to transmit the buffer, when no other transmission
is active any more.
From now on the transmitter is busy for 250 ms long, as he transmits
the result over the serial interface (see next sub-chapter).
5.2.5 Sending the transmit buffer
If the flag bTx is set, the sensor transmits. In transmit mode, TC0 is
clocked with 80 kHz (at 4 MHz: CTC = 50, Compare A = 49, time
slice = 12.5 µs) and either toggles the output pin OC0A (when
transmitting the start bit or a one-bit) or clears it (when sending stop
bits or a zero-bit).
The example to the right shows the toggling 0C0A with 40 kHz for the
duration of a start bit at 1,200 Baud.
During transmission the X pointer points to the next character, that is to be
send, in the SRAM transmit buffer. The buffer is null-terminated, when reaching
null the transmission stops.
The tranmsit algorithm is driven by the TC0-Compare-A interrupt. As this
interrupt also serves other tasks (see overnext sub-chapter), the first
check in this interrupt is if the bTx flag is set. If that is the case,
the algorithm continues in the send section. The 16-bit counter rCntH:rCntL,
which counts the number of toggles of the CTC in TC0 and controls the duration
of transmitted bits (by default at 1k2Baud: 67 toggles).
If the counter reaches zero, the 16-bit counter is reloaded with its start
value. Now the number of bits to be transmitted is decreased. If that reaches
zero, the next character is read from the X buffer, which is auto-incremented.
If the character is a null, the transmission is ending, with the following
operations:
- the transmit flag bTx is cleared, and
- the timer-interrupt enable for TC0 is cleared, (the interrupt for TC1
is kept to keep the clock active), and
- the OC0A-pin is set to clear.
If the character wasn't a null, the number of bits to be transmitted in
register rBit is set to 11 (1 start bit, 8 data bits, 2 stop bits) and OC0A
is set to toggle (which sends the start bit of the character).
If rBit was zero after decrementing it, register rimp is set to clear the
OC0A output pin. If the number of bits to be send is smaller than two, the
stop bits are send. If not, the character is shifted left and, if carry is
set, rimp is set to toggle OC0A. The value of rimp is written to the control
port register A of TC0.
For all instructions to be executed the required clock cycles are added in
red in the flow diagram. All remain below a level of 38 clock cycles, after
which, at a crystal frequency of 3 MHz and an IR frequency of 40 kHz,
the next interrupt comes in. Only in the case that the wait cycle has just
finished and transmission of the first character starts, this limit is
reached. Because the next interrupt initiation requires five clock cycles
to get active (the rjmp in the vector is executed), the limit is not exceeded.
The case of a loss of an interrupt only occurs if another such interrupt
remains untreated, the limit is twice the 38 clock cycles long. Even if
another interrupt occurs in between and has a higher priority would occur
(e.g. an INT0), this doesn't cause a loss, because such interrupts are
disabled during the transmit period.
At 4 MHz or higher the execution is even faster, so that losses of
interrupts are not possible.
This here shows the toggling of the OC0A output pin during the transmission
of a start bit and of the upper nibble of 0x5x with 1,200 Baud. The
transmit frequency of 40 kHz is exact, the LED is 50% of the time on.
All signal durations are of equal duration, that's what an IR receiver
likes.
This here is the transmitter output for the whole 0x55 byte and for the
beginning of the next start bit. The stop bits in 8N2 are twice as long.
The same for sending 0x55 twice. The double space of the two stop bits
yields - roughly - a 600 Hz signal.
5.2.6 Wait time prior to transmit
In order to avoid sensor tranmission conflicts, the controller waits for a
certain time period, during which no other sensor is transmitting. The wait
time period restarts if another sensor transmits, so that all sensors are
transmitting in a fixed row.
Each sensor has an indivual time period, which guarantees that a priority
chain gets active.
This is the flow of the wait cycles. This is added as a further part of the
OCR0A interrupt service routine and gets active if the bTx and bRx flag is
low anfd the bRq flag is active (Rq = Request TX). If all three flags are
inactive, the OCR0A interrupt is disabled.
During the wait period, the INT0 interrupt is disabled. The INT0 input
pin is checked during the wait period, if active (low) another sensor
transmits and the counter is restarted.
If not, the counter is decreased by one. If not yet zero, waiting continues.
If the counter reaches zero, transmission starts:
- the Tx-Request-flag is cleared, and
- the transmit flag is set, and
- the X-pointer is set to the text buffer start, and
- the first character in the buffer is read to register rTx, and
- the INT0-interrupt is disabled, and
- the counter for the number of IR signals is set to 1 and the number
of bits to be transmitted is set to 11, and
- the compare-A-value of TC0 is set to the IR-transmit-value, and
- the prescaler of TC0 is set to one.
Then the first start bit is transmitted. For this a jump to the respective
routine within the transmit algorithm is executed.
All further bits of the first character as well as all other characters of
the string are send with the bTx flag set.
5.2.7 Serial reception to the receive buffer
During receiving serial signals, the flag bRx in the flag register is set.
That is initated by the INT0 interrupt, when a falling edge occurs. In
receive mode the TC0 compare match A interrupt senses the IR input pin
on INT0 for the next bit. The period between the time that the start bit
started and the center of the bit 7 (one-plus-one-half bit length) is
written to the compare A port register, the prescaler is written to be 64
(in the default case).
The IR-to-serial-converter transmits the signals that are sent by over the
interface. Normally the converter's receiver module is close to the transmit
LED, and so loops back the received signal over the receive pin on the serial
interface. So, the thermosensor does not need to loop back the incoming signals,
which simplifies the sensor's program.
Prior to reception the IR-receiver module TSOP31240 waits for incoming
signals. After roughly 10 IR-pulses the module activates its output
pin by pulling it low. The output pin is attached to the PB2 = INT0 pin.
The falling edge initiates an INT0-interrupt. This switches the INT0
interrupt enable off, sets the bRx flag in the flag register, sets the bit
counter rBits to 9 and starts TC0 with the following settings:
- Compare-Match A is set to cTc0RxStrt, which is 1.5 times longer than
one bit,
- the CTC mode (WGM01 to 1) and COM0A1/0 is set to clear the OC0A pin
(no transmission during receive),
- the prescaler is set to cTc0RxCs (normally 64),
- the TC0-Compare-Match-A-interrupt is enabled.
Now the following happens:
- The counter rBit is decreased by one. If it gets zero, the recption
of one byte is finished. If not, the following happens.
- Always, when the time of the TC0 is over, the input pin is sensed. If
low, a zero is shifted into the byte in register rRx to the left. If
high, a one is shifted into rRx.
- The compare A port register is set to the cTc0Rx period, which is the
time between two bits (at 4 MHz and 1200 Baud this is 52,
because 4,000,000 / 64 / 1200 = 52, the delay of 10 signals in the
receiver module is also inserted here.
If the reception of an 8 bit character is finalized, which occurs in the
middle of the first stop bit, the following happens:
- The received character is written to the SRAM receiver buffer in sRx,
to which the Y pointer points.
- It is tested, if the pointer now points to beyond the receiver buffer
(buffer overflow). If that is the case, the Y pointer is set back to the
beginning of the buffer area. An undefined command code is written to
this location to provoke an error message.
- After that, a null-terminating byte is written to the next location.
- Further interrupts from TC0-Compare-A are disabled, only the clock
interrupts of TC1 are kept active.
- The bRx flag is cleared, the further reception is disabled. This is
enabled again, if the next start bit arrives.
- Then it is tested, if the received character is a linefeed. If that
is the case, the flag bRxL (received line) is set, initiating analysis
of the received line.
- If the character is not a linefeed, INT0 interrupts are enabled again
and the controller waits for the next start bit.
The number of clock cycles, even though part of the diagram in red, is not
very relevant here, because the serial transmission speed is low and the
prescaler of the TC0 is 64. Even with higher speeds the number of clock
cycles, where interrupts would get lost, is never reached.
5.2.8 Analysis and execution of the received line
If the controller detects, after executing interrupts, that the flag bit
bRxL is set, the received line has to be analyzed and, if the sensor is the
receiver of a message, the received command has to be executed.
First of all, the received line is re-formatted:
- All ASCII control characters, blanks and minus symbols are removed
from the line.
- All small letters are converted to upper-case.
The remaining content is analyzed:
- If only a linefeed has been received (the first character is a null
character), immediate measurement is initiated.
- If the first character is a decimal digit between 0 and 9, it is
checked whether this matches the own ID. If that isn't the case, the
command is ignored.
- This or the next character is checked for being in "D, T, M, K,
C, F, A, B, ?, H". If the character is in "D, T, M, A, B,
C", a "=" can follow. If that is the case, the following
is done:
- D: with this the date is set. If the first separator is a
slash "/" the english notation is set. If it is a dot,
the german notation is set.
- T: sets the time. The hours, minutes and seconden have to
be separated by ":". If instead of a "=" a
"K" follows, the temperature dimension is set to Kelvin.
If "C" follows, it is set to °Celsius, with
"F" to °Fahrenheit.
- M: sets the number of seconds for starting temperature
measurements (measure interval). 0 switches the sensor off.
- A: the parameter a of the temperature formula
(10T = a * 128ADC2 + b * 128ADC +c) is set, if
"=" follows, otherwise the current value of a is echoed.
- B: the parameter b of the temperature formula is set,
otherwise the value is echoed.
- C: the parameter c is set or echoed.
- ? or H: a help text is issued, with the commands.
- If an error occurs, a meaningful error message is transmitted and the
green LED of the sensor blinks once. Otherwise ID, date, time,
temperature and its dimension are send back, and the green LED blinks
three times.
Please note, that changing the settings for "TK/TC/TF, M, A, B, C"
are written to the EEPROM and read from there on the controller's start-up.
These commands do not have to be repeated when starting, only date and time
need an update.
Many success when communicating with those devices.
©2023 by http://www.avr-asm-tutorial.net