Freescale Semiconductor Application Note
AN1950 Rev 4, 11/2006
Water Level Monitoring
by: Michelle Clifford, Applications Engineer Sensor Products, Tempe, AZ
INTRODUCTION
Many washing machines currently in production use a mechanical sensor for water level detection. Mechanical sensors work with discrete trip points enabling water level detection only at those points. The purpose for this reference design is to allow the user to evaluate a pressure sensor for not only water level sensing to replace a mechanical switch, but also for water flow measurement, leak detection, and other solutions for smart appliances. This system continuously monitors water level and water flow using the temperature compensated MPXM2010GS pressure sensor in the low cost MPAK package, a dual op-amp, and the MC68HC908QT4, eight-pin microcontroller.
measuring is between 0–40 cm. This corresponds to a pressure range of 0–4 kPa. Therefore, the MPXM2010GS was selected for this system. The sensor sensitivity is 2.5 mV/kPa, with a full-scale span of 25 mV at the supply voltage of 10 VDC. The full-scale output of the sensor changes linearly with supply voltage, so a supply voltage of 5 V will return a full-scale span of 12.5 mV. (VS actual / VS spec) * VOUT full-scale spec = VOUT full-scale (5.0 V/ 10 V) x 25 mV = 12.5 mV Since this application will only be utilizing 40 percent of the pressure range, 0–4kPa, our maximum output voltage will be 40 percent of the full-scale span. VOUT FS * (Percent FS Range) = VOUT max 12.5 mV * 40% = 5.0 mV The package of the pressure sensor is a ported MPAK package. This allows a tube to be connected to the sensor and the tube is connected to the bottom of the tub. This isolates the sensor from direct contact with the water. The small size and low cost are additional features making this package a perfect fit for this application.
SYSTEM DESIGN Pressure Sensor
The pressure sensor family has three levels of integration — Uncompensated, Compensated and Integrated. For this design, the MPXM2010GS compensated pressure sensor was selected because it has both temperature compensation and calibration circuitry on the silicon, allowing a simpler, yet more robust, system circuit design. An integrated pressure sensor, such as the MPXV5004G, is also a good choice for the design eliminating the need for the amplification circuitry.
Figure 2. A Ported Pressure Sensor
Figure 1. Water Level Reference Design Featuring a Pressure Sensor The height of most washing machine tubs is 40 cm, therefore the water height range that this system will be
© Freescale Semiconductor, Inc., 2006. All rights reserved.
Table 1. MPXM2010D OPERATING CHARACTERISTICS (VS = 10 VDC, TA = 25°C unless otherwise noted, P1 > P2)
Characteristic Pressure Range Supply Voltage Supply Current Full Scale Span Offset Sensitivity Linearity Symbol POP VS IO VFSS Voff DV/DP — Min 0 — — 24 -1.0 — -1.0 Typ — 10 6.0 25 — 2.5 — Max 10 16 – 26 1.0 — 1.0 Unit kPa Vdc mAdc mV mV mV/kPa %VFSS
Amplifier Induced Errors
The sensor output needs to be amplified before being inputted directly to the microcontroller through an eight-bit A/D input pin. To determine the amplification requirements, the pressure sensor output characteristics and the 0-5 V input range for the A/D converter had to be considered. The amplification circuit uses three op-amps to add an offset and convert the differential output of the MPXM2010GS sensor to a ground-referenced, single-ended voltage in the range of 0–5.0 V. The pressure sensor has a possible offset of ±1 mV at the minimum rated pressure. To avoid a nonlinear response when a pressure sensor chosen for the system has a negative offset (VOFF), we added a 5.0 mV offset to the positive sensor output signal. This offset will remain the same regardless of the sensor output. Any additional offset the sensor or op-amp introduces is compensated for by software routines invoked when the initial system calibration is done. To determine the gain required for the system, the maximum output voltage from the sensor for this application had to be determined. The maximum output voltage from the sensor is approximately 12.5 mV with a 5.0 V supply since the full-scale output of the sensor changes linearly with supply voltage. This system will have a maximum pressure of 4 kPa at 40 cm of water. At a 5.0 V supply, we will have a maximum sensor output of 5 mV at 4 kPa of pressure. To amplify the maximum sensor output to 5.0 V, the following gain is needed: Gain = (Max Output needed) / (Max Sensor Output and Initial Offset) = 5.0 V / (0.005 V + 0.005) = 500 The gain for the system was set for 500 to avoid railing from possible offsets from the pressure sensor or the op-amp. The Voltage Outputs from the sensor are each connected to a non-inverting input of an op-amp. Each op-amp circuit has the same resistor ratio. The amplified voltage signal from the negative sensor lead is VA. The resulting voltage is calculated as follows: VA = (1+R8/R6) * V4 = (1+10/1000) * V4 = (1.001) * V4
The amplified voltage signal from the positive sensor lead is VB. This amplification adds a small gain to ensure that the positive lead, V2, is always greater than the voltage output from the negative sensor lead, V4. This ensures the linearity of the differential voltage signal. VB = (1+R7/R5) * V2 – (R7/R5) * VCC = (1+10/1000) * V2 + (10/1000)*(5.0 V) = (1.001) * V2 + 0.005 V The difference between the positive sensor voltage, VB, and the negative sensor voltage, VA is calculated and amplified with a resulting gain of 500. VC = (R12/R11) * (VB – VA) = (500 K/1K) * (VB – VA) = 500 * (VB – VA) The output voltage, VC, is connected to a voltage follower. Therefore, the resulting voltage, VC, is passed to an A/D pin of the microcontroller. The range of the A/D converter is 0 to 255 counts. However, the A/D Values that the system can achieve are dependent on the maximum and minimum system output values: Count = (VOUT – VRL) / ( VRH – VRL) x 255 where VXdcr = Transducer Output Voltage VRH = Maximum A/D voltage VLH = Minimum A/D voltage Count (0 mm H20) = (2.5 – 0) / (5.0 – 0) * 255 = 127 Count (40 mm H20) = (5.0 – 0) / (5.0 – 0) * 255 = 255 Total # counts = 255 – 127 = 127 counts. The resolution of the system is determined by the mm of water represented by each A/D count. As calculated above, the system has a span of 226 counts to represent water level up to and including 40 cm. Therefore, the resolution is: Resolution = mm of water / Total # counts = 400mm/127 counts = 3.1 mm per A/D count
AN1950 2 Sensors Freescale Semiconductor
R6 10K
R8 10Ω 6 5
+
7
VA
V4sensor
R12 500K VCC R11 1K 13 12 R9 1K R10 500K
+
4
VCC
R7 10Ω
C5 0.1µF VC 14
9 10
+
8
VOUT
11
R5 10K
2 3
+
1
VB
V2sensor
Figure 3. Amplification Scheme
Microprocessor
To provide the signal processing for pressure values, a microprocessor is needed. The MCU chosen for this application is the MC68HC908QT4. This MCU is perfect for appliance applications due to its low cost, small eight-pin package, and other on-chip resources. The MC68HC908QT4 provides: a four-channel, eight-bit A/D, a 16-bit timer, a trimmable internal timer, and in-system FLASH programming. The central processing unit is based on the high performance M68HC08 CPU core and it can address 64 Kbytes of memory space. The MC68HC908QT4 provides 4096 bytes of user FLASH and 128 bytes of random access memory (RAM) for ease of software development and maintenance. There are five bi-directional input/output lines and one input line shared with other pin features. The MCU is available in eight-pin as well as 16-pin packages in both PDIP and SOIC. For this application, the eight-pin PDIP was selected. The eight-pin PDIP was chosen for a small package, eventually to be designed into applications as the eight-pin SOIC. The PDIP enables the customer to reprogram the software on a programming board and retest.
PTA3 PTA4 PTA5 HC908QT4 R2 1K EN RS RW LCD
DB0 DB1 DB2 DB3 DB4 DB5 DB6 DB7
A B CLK HC164 R3 1K
Figure 4. Multiplexed LCD Circuit Multiplexing of the microcontroller output pins allows communication of the LCD to be accomplished with three pins instead of eight or 11 pins of I/O lines usually needed. With an eight-bit shift register, we are able to manually clock in eight bits of data. The enable line (EN) is manually accepted when eight bytes have been shifted in, telling the LCD the data on the data bus is available to execute. The LEDs are used to show pressure output data by displaying binary values corresponding to a pressure range. Leak detection, or water-flow speed, is displayed by blinking a green LED at a speed relating to the speed of water flow. The red LED displays the direction of water flow. Turning the red LED off signifies water flowing into the tub. Turning the red LED on signifies water flowing out of the tub, or alternatively, there is a leak. Digital values for water height, rate of water flow, and calibration values are displayed if an LCD is connected to the board AN1950
Display
Depending on the quality of the display required, water level and water flow can be shown with two LEDs. If a higher quality, digital output is needed, an optional LCD interface is provided on the reference board. Using a shift register to hold display data, the LCD is driven with only three lines outputted from the microcontroller: an enable line, a data line, and a clock signal. The two LEDs are multiplexed with the data line and clock signal
Sensors Freescale Semiconductor
3
OTHER
This system is designed to run on a 9.0 V battery. It contains a 5.0 V regulator to provide 5.0 V to the pressure
sensor, microcontroller, and LCD. The battery is mounted on the back of the board using a space saving spring battery clip.
Table 2. Parts List
Ref. U2 C1 C2 C3 D1 D2 S2, S3 U1 U3 U4 R1 R2 R3, R6 R4, R5 R7, R8 R9, R10 U6 U5 Qty 1 1 1 1 1 1 2 1 1 1 1 1 2 2 2 2 1 1 Description Pressure Sensor Vcc Cap Op-Amp Cap Shift Register Cap Red LED Green LED Pushbuttons Quad Op-Amp Voltage Regulator Microcontroller ¼ W Resistor ¼ W Resistor ¼ W Resistor ¼ W Resistor ¼ W Resistor ¼ W Resistor LCD (Optional) Shift Registor Value 1 0.1µf 0.1µf 0.1µf Vendor Freescale Generic Generic Generic Generic Generic Generic ADI Fairchild Freescale Generic Generic Generic Generic Generic Generic Seiko Texas Instruments Part No. MPXM2010GS
— — — — — —
AD8544 LM78L05ACH MC68HC908QT4
— — — —
5.0 V 8-pin 22 K 2.4 K 1.2 M 1.5 K 10 K 1.0 K 16 x 2
— — — — — —
L168200J000 74HC164
—
Smart Washer Software
This application note describes the first software version available. However, updated software versions may be available with further functionality and menu selections.
Software User Instructions
When the system is turned on or reset, the microcontroller will flash the selected LED and display the program title on the LCD for five seconds, or until the select (SEL) button is pushed. Then the menu screen is displayed. Using the select (SEL) pushbutton, it is easy to scroll through the menu options for a software program. To run the water level program, use the select button to highlight the Water Level option, then press the enter (ENT) pushbutton. The Water Level program will display current water level, the rate of flow, a message if the container is Filling, Emptying, Full, or Empty, and a scrolling graphical history displaying data points representing the past forty level readings. The Water Level is displayed by retrieving the digital voltage from the internal A/D Converter. This voltage is converted to pressure in millimeters of water and then displayed on the LCD.
buttons on system power-up enters the calibration mode. At this point, the calibration menu is displayed with the previously sampled offset voltage. To recalibrate the system, expose the sensor to atmospheric pressure and press the SEL button (PB1). At this point, the zero offset voltage will be sampled and saved to a location in the microcontroller memory. To obtain the second calibration point, place the end of the plastic tube from the pressure sensor to the bottom of a container holding 40 mm of water. Then press the ENT button (PB2). The voltage output will be sampled, averaged and saved to a location in memory. To exit the calibration mode, press the SEL (PB1) button.
Calibration and Calibration Software
To calibrate the system, a two-point calibration is performed. The sensor will take a calibration point at 0 mm and at 40 mm of water. Depressing both the SEL and ENT Figure 5. Water Level System Set-Up for Demonstration
AN1950 4 Sensors Freescale Semiconductor
Converting Pressure to Water Level
Hydrostatic pressure being measured is the pressure at the bottom of a column of fluid caused by the weight of the fluid and the pressure of the air above the fluid. Therefore, the hydrostatic pressure depends on the air pressure, the fluid density and the height of the column of fluid. P= Pa + ρ g ∆h where P = pressure Pa = pressure ρ = mass density of fluid g = 9.8066 m/s^2 h = height of fluid column To calculate the water height, we can use the measured pressure with the following equation, assuming the atmospheric pressure is already compensated for by the selection of the pressure sensor being gauge: ∆h = P \ ρ g
The function first clears the 40 pressure readings it updates for the Graphical History. The history then enters the loop first displaying eight special characters, each containing five data points of water level history. The function adcbyta is called to obtain the current averaged A/D value. The function LfNx is called to convert the A/D value to a water level. It is then compared to the calibration points, the maximum and minimum points, to determine if the container is full or empty. If true, then it displays the corresponding message. The current water level is compared to the previous read and displays the message filling if it has increased, emptying if it has decreased, and steady if it has not changed. The water level calculation has to be converted to decimal in order to display it in the LCD. To convert the water level calculation to decimal, the value is continually divided with the remainder displayed to the screen for each decimal place. To display the Rate of Water Flow, the sign of the value is first determined. If the value is negative, the one's complement is taken, a negative sign is displayed, and then the value is continually divided to display each decimal place. If the number is positive, a plus sign. Level Function The Level function initializes the graphics characters. Once this is complete, it continues looping to obtain an average A/D reading, displaying the Water Level, the Water Flow, and a Graphical History until simultaneously depressing both PB1 and PB2 to return to the main function. The function first clears the 40 pressure readings it updates for the Graphical History. The history then enters the loop first displaying eight special characters, each containing five data points of water level history. The function adcbyta is called to obtain the current averaged A/D value. The function LfNx is called to convert the A/D value to a water level. It is then compared to the calibration points, the maximum and minimum points, to determine if the container is full or empty. If true, then it displays the corresponding message. The current water level is compared to the previous read and displays the message filling if it has increased, emptying if it has decreased, and steady if it has not changed. The water level calculation has to be converted to decimal in order to display it in the LCD. To convert the water level calculation to decimal, the value is continually divided with the remainder displayed to the screen for each decimal place. To display the Rate of Water Flow, the sign of the value is first determined. If the value is negative, the one's complement is taken, a negative sign is displayed, and then the value is continually divided to display each decimal place. If the number is positive, a plus sign is displayed to maintain the display alignment and the value is continually divided to display each decimal place. The most complicated part of this function is updating the graphics history display. The characters for the 16x2 LCD chosen for this reference design are 8x5 pixels by default. Therefore, each special character that is created will be able to display five water level readings. Since the height of the special character is eight pixels, each vertical pixel position will represent a water level in increments of 20 mm. Resolution = (H1 – H0) / D
Software Function Descriptions
Main Function The main function calls an initialization function Allinit calls a warm-up function, Warmup, to allow extra time for the LCD to initialize, then checks if buttons PB1 and PB2 are depressed. If they are depressed concurrently, it calls a calibration function Calib. If they are not both pressed, it enters the main function loop. The main loop displays the menu, moves the cursor when the PB1 is pressed and enters the function corresponding to the highlighted menu option when PB2 is depressed. Calibration Function The calibration function is used to obtain two calibration points. The first calibration point is taken when the head tube is not placed in water to obtain the pressure for 0 mm of water. The second calibration point is obtained when the head tube is placed at the bottom of a container with a height of 160 mm. When the calibration function starts, a message appears displaying the A/D values for the corresponding calibration points currently stored in the flash. To program new calibration points, press PB1 to take 256 A/D readings at 0 mm of water. The average is calculated and stored in a page of flash. Then the user has the option to press PB1 to exit the calibration function or obtain the second calibration point. To obtain the second calibration point, the head tube should be placed in 160 mm of water, before depressing PB2 to take 256 A/D readings. The average is taken and stored in a page of flash. Once the two readings are taken, averaged, and stored in the flash, a message displays the two A/D values stored. Level Function The Level function initializes the graphics characters. Once this is complete, it continues looping to obtain an average A/D reading, displaying the Water Level, the Water Flow, and a Graphical History until simultaneously depressing both PB1 and PB2 to return to the main function.
AN1950 Sensors Freescale Semiconductor 5
where H1 and H2 are the maximum and minimum water levels respectively and D is the possible datapoints available per character. Resolution = (160mm– 0mm) / 8.0 = 20 mm / data point. The graphical history is displayed using the eight special characters. To update the graphics, all the characters have to be updated. The characters are updated by first positioning a pixel for the most recent water level reading in the first column of the first character. Then the four right columns of the first character are shifted to the right. The pixel in the last column of that character is carried to the first column of the next character. This column shifting is continued until all 40 data points have been updated in the eight special characters. LfNx Function The LfNx function calculates the water level from the current A/D pressure reading. The A/D Pressure value is stored in Register A before this function is called. Using the A/D value and the calibration values stored in the flash, the water level is calculated from the following function: RBRA: = (NX –N1) * 160 / (N2 – N1), where NX is the current A/D Value N1 is the A/D Value at 0 mm H20 N2 is the A/D Value at 160 mm H20 To simplify the calculation, the multiplication is done first. Then the function NdivD is called to divide the values. NdivD Function The NdivD function performs a division by counting successive subtractions of the denominator from the numerator to determine the quotient. The denominator is subtracted from the numerator until the result is zero. If there is an overflow, the remainder from the last subtraction is the remainder of the division. wrflash and ersflsh Functions The wrflash and ersflsh functions are used to write to and erase values from the flash. For more information regarding flash functionality, refer to Section Four, Flash Memory from the MC68HC908QY4/D Databook. ALLINIT Function The Allinit function disables the COP for this version of software, sets the data direction bits, and disables the data to the LCD and turns off the LCD enable line. It also sets up the microcontroller's internal clock to half the speed of the bus clock. See Section 15, Computer Operating Properly, of the MC68908QT4 datasheet for information on utilizing the COP module to help software recover from runaway code. WARMUP Function The Warmup function alternates the blinking of the two LEDs ten times. This gives the LCD some time to warm up. Then the function warmup calls the LCD initialization function, lcdinit.
bintasc Function The binasc function converts a binary value to its ascii representation. A/D Functions The A/D functions are used to input the amplified voltage from the pressure sensor from channel 0 of the A/D converter. The function adcbyti will set the A/D control register, wait for the A/D reading and load the data from the A/D data register into the accumulator. The function adcbyta is used to obtain an averaged A/D reading by calling adcbyti 256 times and returning the resulting average in the accumulator. LCD Functions The LCD hardware is set up for multiplexing three pins from the microcontroller using an eight-bit shift register. Channels three, four, and five are used on port A for the LCD enable (E), the LCD reset (RS), and the shift register clock bit, respectively. The clock bit is used to manually clock data from channel four into the eight-bit shift register. This is the same line as the LCD RS bit because the MSB of the data is low for a command and high for data. The RS bit prepares the LCD for instructions or data with the same bit convention. When the eight bits of data are available on the output pins of the shift register, the LCD enable (E) is toggled to receive the data. The LCD functions consist of an initialization function lcdinit which is used once when the system is started and five output functions. The functions lcdcmdo and lcdchro both send a byte of data. The function shiftA is called by both lcdcmdo and lcdchro to manually shift eight bits of data into the shift register. The function lcdnibo converts the data to binary before displaying. The lcdnibo displays a byte of data by calling lcdnibo for each nibble of data. The function lcdnibo enables strings to be easily added to the software for display. The function accepts a comma- delimited string of data consisting of 1–2 commands for clearing the screen and positioning the cursor. It then continues to output characters from the string until the @ symbol is found, signally the end of the string.
CONCLUSION
The water level reference design uses a MPXM2010GS pressure sensor in the low cost MPAK package, the low cost, eight-pin microcontroller, and a quad op-amp to amplify the sensor output voltage. This system uses very few components, reducing the overall system cost. This allows for a solution to compete with a mechanical switch for water level detection but also offer additional applications such as monitoring water flow for leak detection, and the other applications for smart washing machines.
AN1950 6 Sensors Freescale Semiconductor
SOFTWARE LISTING
;NitroWater 2.0 24Jan03 ;-------------; ;Water Level Reference Design ;**************************** ; - uses 908QT4 (MC68HC908QT4) and MPAK (MPXM2010GS) ; CALIB: 2-point pressure calibration (0mm and 160mm) ; LEVEL: displays water level, flow, and graphics ; UNITS: allows user to select between cm and inches ; ;__________________________________________________________ ram equ $0080 ;memory pointers rom equ $EE00 vectors equ $FFDE ;__________________________________________________________ porta equ $00 ;registers ddra equ $04 config2 equ $1E config1 equ $1F tsc equ $20 tmodh equ $23 icgcr equ $36 adscr equ $3C adr equ $3E adiclk equ $3F flcr equ $FE08 flbpr equ $FFBE ;__________________________________________________________ org $FD00 ;flash variables N1 db $96 ;1st calibration pt. = 0mm org $FD40 N2 db $F6 ;2nd calibration pt. = 160mm org $FD80 ;__________________________________________________________ org vectors dw cold ;ADC dw cold ;Keyboard dw cold ;not used dw cold ;not used dw cold ;not used dw cold ;not used dw cold ;not used dw cold ;not used dw cold ;not used dw cold ;not used dw cold ;TIM Overflow dw cold ;TIM Channel 1 dw cold ;TIM Channel 0 dw cold ;not used dw cold ;IRQ dw cold ;SWI dw cold ;RESET ($FFFE) ;__________________________________________________________ org ram BB ds 1 ;variables flshadr ds 2 flshbyt ds 1 memSP ds 2 mem03 ds 2
AN1950 Sensors Freescale Semiconductor 7
CNT ds 1 Lgfx ds 1 weath ds 1 UnitType ds 1 UnitDiv ds 1 UnitEmpt ds 1 UnitFull ds 1 ram0 ds 1 NC ds 1 NB ds 1 NA ds 1 DC ds 1 DB ds 1 DA ds 1 MB ds 1 MA ds 1 OB ds 1 OA ds 1 RB ds 1 RA ds 1 P0C ds 1 P0B ds 1 P0A ds 1 NPTR ds 1 ramfree ds 80 ;used both for running RAM version of wrflash & storing 40 readings ;__________________________________________________________ ;__________________________________________________________ ;__________________________________________________________ org rom cold: rsp ;reset SP if any issues (all interrupt vectors point here) jsr ALLINIT ;general initialization jsr WARMUP ;give LCD extra time to initialize brset 1,porta,nocalib brset 2,porta,nocalib jmp CALIB ;only do calibration if SEL & ENT at reset nocalib: ldhx #msg01 ;otherwise skip and show welcome messages jsr lcdstro ;"Reference Design" msg jsr del1s ;wait 1s ldhx #msg01a ;"Water Level" msg jsr lcdstro jsr del1s ;wait 1s initCM: ldhx #$A014 sthx UnitType ldhx #$039E sthx UnitEmpt MENU: jsr clr lda jsr luke: ;initialize default units to cm ($A0=cm, $3F=in) ;UnitType set to $A0; UnitDiv set to $14 ;UnitEmpt set to $03; UnitFull set to $9E
ldhx #msg01b lcdstro ;Menu msg RA ;menu choice=0 to begin with #$0D lcdcmdo ;blink cursor on menu choice
ldx RA ;get current menu choice clrh lda menupos,x ;and look up corresponding LCD address jsr lcdcmdo ;reposition cursor
AN1950 8 Sensors Freescale Semiconductor
warm:
brclr 1,porta,PB1 ;check for SEL brclr 2,porta,PB2 ;or for ENT bclr 4,porta ;otherwise bset 5,porta ;turn on "SEL" LED jsr del100ms ;delay bset 4,porta ;toggle LEDs bclr 5,porta ;"ENT" now on: means choice is SEL ***or*** ENT jsr del100ms ;delay and repeat until SEL or ENT bra warm
PB1:
inc RA ;***SEL*** toggles menu choices lda RA cmp #$02 ;menu choices are $00 and $01 bne PB1ok clr RA ;back to $00 when all others have been offered PB1ok: bclr 4,porta bclr 5,porta ;LEDs off jsr del100ms ;wait a little bit brclr 1,porta,PB1ok ;make sure they let go of SEL bra luke PB2: bclr 4,porta ;***ENT*** confirms menu choice bclr 5,porta ;LEDs off lda RA ;get menu choice bne skip00 jmp LEVEL ;do ===LEVEL=== if choice=$01 skip00: jmp UNITS ;do ===UNITS=== if choice=$00 ;__________________________________________________________ ;__________________________________________________________ CALIB: lda #$01 jsr lcdcmdo clr ram0 ldhx #msg05 ;===CALIB=== 2-point calibration jsr lcdstro ;Calibration current values lda N1 ;0mm jsr lcdbyto lda #'/' jsr lcdchro lda N2 ;160mm jsr lcdbyto bset 4,porta bset 5,porta ;LEDs on lego1: brclr 1,porta,lego1 lego2: brclr 2,porta,lego2 bclr 4,porta bclr 5,porta ;LEDs off when both SEL & ENT are released jsr del1s jsr del1s ;wait 2s ldhx #msg05a jsr lcdstro ;show instructions waitPB1: brset 2,porta,no2 ;if ENT is not pressed, skip jmp nocalib ;if ENT is pressed then cancel calibration no2: brclr 1,porta,do1st ;if SEL is pressed then do 1st point cal bra waitPB1 ;otherwise wait for SEL or ENT do1st: ldhx #msg05b ;1st point cal: show values jsr lcdstro clr CNT ;CNT will count 256 A/D readings clr RB clr RA ;RB:RA will contain 16-bit add-up of those 256 values
AN1950 Sensors Freescale Semiconductor 9
do256: lda #$C9 jsr lcdcmdo ;position LCD cursor at the right spot lda CNT deca jsr lcdbyto ;display current iteration $FF downto $00 lda #':' jsr lcdchro jsr adcbyti ;get reading add RA sta RA lda RB adc #$00 sta RB ;add into RB:RA (16 bit add) jsr lcdbyto ;show RB lda RA jsr lcdbyto ;then RA dbnz CNT,do256 ;and do 256x lsl RA ;get bit7 into carry bcc nochg ;if C=0 then no need to round up inc RB ;otherwise round up nochg: lda RB ;we can discard RA: average value is in RB ldhx #N1 ;point to flash location jsr wrflash ;burn it in! ldhx #msg05c ;ask for 160mm jsr lcdstro waitPB2: brset 2,porta,waitPB2 ;wait for ENT ldhx #msg05d ;2nd point cal: show values jsr lcdstro clr CNT ;ditto as 1st point cal clr RB clr RA do256b: lda #$C9 jsr lcdcmdo lda CNT deca jsr lcdbyto lda #':' jsr lcdchro jsr adcbyti add RA sta RA lda RB adc #$00 sta RB jsr lcdbyto lda RA jsr lcdbyto dbnz CNT,do256b lsl RA bcc nochg2 inc RB nochg2: lda RB cmp N1 ;compare N2 to N1 bne validcal ;if different, we are OK ldhx #msg05e ;otherwise warn of INVALID CAL! jsr lcdstro jsr del1s jsr del1s jsr del1s ;wait 2s jmp CALIB ;try cal again
AN1950 10 Sensors Freescale Semiconductor
validcal: ldhx #N2 jsr wrflash ;burn N2 into flash ldhx #msg05 ;and display new current cal values from flash jsr lcdstro lda N1 ;0mm value jsr lcdbyto lda #'/' jsr lcdchro lda N2 ;160mm value jsr lcdbyto jsr del1s jsr del1s jmp nocalib ;done! ;__________________________________________________________ ;__________________________________________________________ LEVEL: lda #$01 ;===LEVEL=== main routine: displays level, flow & graphics jsr lcdcmdo ;clear screen lda #$0C jsr lcdcmdo ;cursor off lda #$88 ;position cursor at LCD graphics portion jsr lcdcmdo ;(2nd half of first line) clra ;and write ascii $00 through $07 fillgfx: jsr lcdchro ;which contain the graphics related to inca ;40 different readings cmp #$08 ;do all 8 bne fillgfx LVL: ldhx #ramfree ;point to 40 pressure readings lda #$28 ;count down from 40 purge: clr 0,x ;clear all those locations incx ;next (H cannot change: we are in page0 RAM) dbnza purge jsr adcbyta ;get averaged A/D reading (i.e. NX) jsr LfNx ;convert to level and sta Lgfx ;store in "Level graphics" LVLwarm: bset 4,porta bset 5,porta ;LEDs on during this cycle ldhx #ramfree ;point to 40 pressure readings mov #$27,RA ;count down from 39 shiftgfx: lda 1,x ;take location+1 sta 0,x ;and move to location+0, i.e. shift graphics left incx ;next X (once again: we are in page 0, no need to worry about H) dbnz RA,shiftgfx ;do this 39x jsr adcbyta jsr LfNx mov RA,OA ;get averaged A/D reading (i.e. NX) ;LX:=(NX-N1)*ConversionValue/(N2-N1) ;store result in OA
clr RB ;RB will contain graphic pixels (default=$00) cmp UnitEmpt ;if =UnitFull (preset value = full or almost) bcc Lsat ;then "full" (pixel $80=bit 7) clrh ;otherwise determine one of 8 graphic values ldx UnitDiv ;UnitDiv is roughly full range/8 div ;in order to give 8 values mov #$01,RB ;but now value has to be converted to pixel
AN1950 Sensors Freescale Semiconductor 11
cmp #$01 ;if result is $01 beq Lzero ;then display it directly makeRB lsl RB ;otherwise shift 1 pixel bit to the right place dbnza makeRB ;by counting down result of division bra Lzero Lsat: mov #$80,RB ;if full then position highest pixel Lzero: lda RB ldhx #ramfree+$27 ;last of the 40 sta 0,x ;put it at then end of the 40 bytes (new value), all others were shifted left clr weath ;weath will contain dynamic change based also on value of RB lda RB beq donew ;if RB=$00 then weath=$00: "empty" cmp #$80 bne notfull ; mov #$01,weath ;if $80 then weath=$01: "full" bra donew notfull mov #$02,weath ;prepare for "steady" if L(i)=L(i-1) lda OA ;get current level value L(i) cmp Lgfx ;compare to previous level value L(i-1) beq donew mov #$03,weath ;"filling" if L(i)>L(i-1) bcc donew mov #$04,weath ;"emptying" otherwise donew: lda OA ;current level L(i) sub Lgfx ;minus previous level L(i-1) sta MA ;establishes rate: L(i)-L(i-1) mov RA,Lgfx ;update L(i-1) ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - golevel: lda #$80 ;******** now let's display the level in decimal ******** jsr lcdcmdo ;start on 1st character of 1st line lda OA ;get current level value clrh ldx #$64 ;and divide by 100 div bne over100 ;if result is >0 then handle "hundreds" lda #$20 ;otherwise display space (remove leading 0) jsr lcdchro bra lnext over100: jsr lcdnibo ;display "hundreds" digit lnext: pshh pula ;move remainder into A clrh ldx #$0A ;divide by 10 div jsr lcdnibo ;display "tens" digit lda #'.' jsr lcdchro ;display decimal point pshh pula jsr lcdnibo ;and first decimal lda UnitType ;check for cm ($A0) vs. in (#3F) cmp #$3F beq dsplIN dsplCM: lda #'c' jsr lcdchro lda #'m'
AN1950 12 Sensors Freescale Semiconductor
jsr lcdchro bra goflow
;display "cm" for centimeters
dsplIN: lda #'i' jsr lcdchro lda #'n' jsr lcdchro ;display "in" for inches ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - goflow: lda #$C0 ;******** now let's display the flow in decimal ******** jsr lcdcmdo ;position cursor on 1st character 2nd line lda MA ;get flow lsla ;test sign of rate (in MA) bcc positiv ;if positive, then it's easy lda MA coma inca sta MA cmp #$64 bcs not2lo lda #'' jsr lcdchro lda #$63 sta MA bra goconv not2hi: lda #'+' jsr lcdchro goconv: lda MA clrh ldx #$0A div jsr lcdnibo lda #'.' jsr lcdchro pshh pula jsr lcdnibo lda UnitType cmp #$3F beq dsplINf dsplCMf: lda #'c' jsr lcdchro lda #'m' bra reusef ;otherwise 1's complement of MB
;check to see if >100 ;if not we are OK ;otherwise display that we exceeded min rate ;that LCD can display (100 ;if not we are OK ;otherwise display that we exceeded max rate ;that LCD can display (>9.9) ;force value to 99
;display the plus sign (to keep alignment) ;get flow ;and divide by 10 ;display "tens" digit ;display decimal point
;and first decimal ;check for cm ($A0) vs. in (#3F)
AN1950 Sensors Freescale Semiconductor 13
dsplINf: lda #'i' jsr lcdchro lda #'n' reusef: jsr lcdchro lda #'/' jsr lcdchro lda #'s' jsr lcdchro ;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - gfxupdt: lda #$40 ;======== Graphics Update: tough stuff =========== jsr lcdcmdo ;prepare to write 8 bytes into CGRAM starting at @ $40 ldhx#ramfree;point to 40 pressure readings (this reuses wrflash RAM) mov #$08,DA ;DA will count those 8 CGRAM addresses cg8: lda 0,x sta NC lda 1,x sta NB lda 2,x sta NA lda 3,x sta DC lda 4,x staDB;readings 0-4 go into NC,NB,NA,DC,DB and will form 1 LCD special character mov #$08,RA ;RA will count the 8 bits fill:clrRB;start with RB=0, this will eventually contain the data for CGRAM rol NC rolRB rol NB rolRB rol NA rolRB rol DC rolRB rol DB rolRB;rotate left those 5 values and use carry bits to form RB (tough part) lda RB jsrlcdchro;and put it into CGRAM dec RA ;do this 8 times to cover all 8 bits bne fill incx incx incx incx incx ;now point to next 5 values for next CGRAM address (5 values per character) dec DA ;do this for all 8 CGRAM characters bne cg8 ldaweath;get weather variable and decide which message to display cmp #$04 bne try3210 ldhx #msg02e ;if $04 bra showit try3210: cmp #$03 bne try210 ldhx #msg02d ;if $03 bra showit try210: cmp #$02
AN1950 14 Sensors Freescale Semiconductor
bne try10 ldhx #msg02c ;if $02 bra showit try10: cmp #$01 bne try0 ldhx #msg02b ;if $01 bra showit try0: ldhx #msg02a ;otherwise this one showit: jsr lcdstro jsr del1s ;1s between pressure/altitude readings brset 1,porta,contin ;exit only if SEL brset 2,porta,contin ;and ENT pressed together jmp MENU contin: jmp LVLwarm ;__________________________________________________________ LfNx: sub N1 ;*** PX=f(NX,N2,N1) *** ldx UnitType ;$A0=160 for cm, $3F=63 for in mul sta NA stx NB clr NC ;NCNBNA:=(NX-N1)* (conversion value: 160 or 63) lda sub sta clr clr jsr N2 N1 DA DB DC NdivD
;RBRA:=(NX-N1)*(conversion value)/(N2-N1)
lda RA cmp #$C8 ;check to see if result is negative bcs noovflw ;if