; TempAlarm - Basic Atom code to sense temperatures from up to 4 sensors and power down ; a device if any of the sensors detect a temperature greater than a ; set point. Also provides LCD status display and user interface and ; command interface to extract sensor and status data using a ; serially-connected computer. ; ; Created May, 2006 by Tim Sharpe ; ; Hardware: ; Basic Atom microcontroller, 40-pin package. ; Temperature sensors. I used type K thermocouples and Maxim MAX6675 chips, which directly ; interface with Type K thermocouples, sense open connections, and provide a direct ; digital readout using an SPI interface. ; Set point config. I used 2 BCD thumbwheel switches. They were interfaced through a ; 74HC165 8-bit Parallel-In/Serial Out Shift Register to reduce the I/O pin requirement ; on the Basic Atom from 8 to 3 pins, by trating the 74HC165 as an SPI interface. ; Serial Ports: I used the Hardware serial port on P14-P15 to provide the command interface ; and a "Soft" serial port on P12-P13 to drive a remote serial display. A TI Max232 ; converts between TTL and RS-232 signal levels for both ports. ; Output. ; C/F setting. ; Alarm Indicator. ; LCD Display. I used a standard Hitachi Hd44780-compatible 2x16 Alphanumeric LCD display, ; with data leads on P8-P11, RegSel on P12, and Clock on P13. ; Remote Serial Display. 2 Velleman K8063 Serial LED kits provide a remote 4-digit 7-segment ; interfacing via RS-232 (send only to digits). ; ; ; TODO: ; -After some number of passes through the EventLoop while in states 1 or 2, should revert ; back to state 0. The system should clear these by itself, but better to be safe. ; ; Revision Log ; Date Ver Remarks ;====================================================================================== ;05/24/2006 0.35 Reflagging of first truly functional sensor/LCD display code. No changes ; from previous test code. ;05/24/2006 0.36 Fixed the Temp/Open/Fail conditional in Display_Temp so that it works ; correctly for both Fahrenheit and Celsius. ; Minor cleanup of comments and deletion of some declared but unused variables. ;05/27/2006 0.37 Added code to read the temperature set point from BCD thumbwheel switches and ; to require the same value to be read several times before using it as the ; alarm set point. ;05/28/2006 0.38 Added requirement in GetTemp that the system not be in alarm state before ; looking for a new max temperature value, so that the max temp will be ; retained when the system alarms. ; Added code to determine whether the system should alarm out and modified ; GetTemp not to change the max temperature information if the system is ; in alarm state. ;06/02/2006 0.39 Mod to quit reading the set point after the system alarms out. New set ; point will be read after a system reset. ;06/03/2006 0.40 Added code to read Temprature Scale from a jumper connected to P11. ; Added code to set the Boiler Interrupt Output (P9) low at startup and ; added code in AlarmCheck to raise the output when the system alarms out. ;06/04/2006 0.50 Implemented to serial port and command interface. Required mods to the ; GetSetPoint subroutine due to problems with an "if" statement with ; an inequality. For some reason, it caused the command interface code ; (Handle_Cmd) to fail reading the hardware serial port except when in ; Debug mode. A simple logic reversal in the "if" statement cured the ; problem (at least for now). Command set conforms to the Command/ ; Reponse Spec v1.1. Due to the additional changes, skipped version ; numbers out to v0.50. ;06/04/2004 0.51 Mod to have Handle_Cmd provide the correct number of digits for Sys_Uptime. ; It's a 32-bit number and displays using 8 hex digits rather than the ; 4 hex digits previously specified. This was because of an error in the ; command spec which was found while updating the spec. ;06/06/2006 0.52 Minor mod to adjust the EventLoop "pause". An external program querying ; the "System State" via the Command Interface showed that the event ; loop was running about 4% slow. There will surely be more adjustments ; after the remote display is operational and it's running duty cycle ; is determined. ;06/08/2006 0.53 Mod to Handle_Cmd to fix the length of hex strings in "@S" and "@D" ; responses. Had fixed the minimum length but not the maximum, so that ; an open thermocouple changed the length of the output response which ; is fixed according to the specification. ;06/13/2006 0.54 Added very rudimentary code to update the Remote LED Display. At this, ; point, it only displayed the max temp reading on every EventLoop pass. ; No handling for different display when system is alarmed out or to ; blank display when max temp is below a certain point. ;06/14/2006 0.55 Added code to only update the display every so many EventLoop passes ; Added leading zero suppression for normal temperature display. ; Added sending of different information depending on the system state. ; Added code to supress display if the max temp is below a ; predetermined value. ;06/15/2005 0.56 Minor mod to adjust EventLoop pause after implementing code for Remote ; LED display. Was 6.3% slow. ;07/01/2006 0.57 Reworked RemoteLEDDisplay to alternate "HELP" and the max temperature, ; which holds when the system alarms out. "HELP" displays at max brightness ; and the max temperature displays at normal brightness. ;10/09/2006 0.58 Last version before system installation. Changed LEDDigMinTemp to turn ; on the Remote LED Display when MaxTemp>=120 degrees from the 80 used ; during development. ;10/09/2006 0.59 Changed LEDDigMinTemp from a constant to a variable and added code to ; convert the hard-coded value (in Fahrenheit) to Celsius when the ; system is running in Celsius ; ; ; TODOs ; -Reintroduce leading zero suppression on the tens digit in RemoteLEDDisplay for both "normal" ; and "alarm" modes. May as well. ; -Test with scheduled task and eventloop delay with both remote display and "per minute" ; network polling enabled. Should be 1 second per event loop ; -Just before installation, adjust LEDDigMinTemp to a more reasonable value. It's a constant ; set in the declarations. ; Declarations ; ; System Variables ; SysState holds the Armed/Alarm state of the system. Armed=0, Alarm=1. SysState var bit ; This holds the system uptime. Used to detect reboots. Sys_Uptime var long ; ; Command-set input validation variables ; Cmd_State holds the state of current command input. States are: ; $00-Waiting to see @ character (@ is hex 40) ; $01-Received @ character, waiting for Command character ; $02-Received @ and valid Command character. All actions happen here. ; $0F-Invalid Command. This reset Cmd_State back to 0. Cmd_State var nib ; Cmd_Dummy is a holder for incoming characters. We'll check it flr @ after receiving ; each character to catch the start of commands. Cmd_Dummy var byte ; Cmd_Command holds the Command Character so we can validate it. Cmd_Command var byte ; Cmd_Command_Valid holds all the legal commamd characters for validation Cmd_Command_Valid var byte(4) ; Cmd_Command_Valid_LastIndex holds the index of the last value in Cmd_Command_Valid Cmd_Command_Valid_LastIndex var nib ; Cmd_Ack holds the character "ACKed" for the response. Cmd_ACK var byte ; These are dummy bytes for use in processing commands Cmd_Dummy1 var byte ; ; Set Point Variables-for reading the set point from the BCD Thumbwheel Switches ; This holds the current set point SetPoint var word ; This holds the bytes from each BCD thumbwheel switch SetPointTemp var word ; This hold the candidate value for the set point while we wait a number of samples ; to assure a stable value before committing the value to the set point. SetPointCand var word ; This counts how many times we've seen the same new value. SetPointCandCount var byte ; How many times we must see a new value before it's committed as the new set point SetPointCheck con 5 ; ; Alarm check variables AlarmCount var byte ; This holds the number of times the set point has been violated so that ; we can require several violations before alarming. ; How many times can the set point be violated before we alarm out? AlarmLimit con 5 ; ; ; Temperature variables ; This holds whether we're using the Fahrenheit or Celsius scale. Celsius=0, Fahrenheit=1. TempScale var bit ; These are the temperatures, in degrees Fahrenheit, of the 4 sensors. Added an extra ; word to each array to avoid having to dick up the display code. Burned 2 bytes of ; RAM so the data positions in the arrays match the sensor numbers. Temp var word(5) ; These are the sensor open/closed states of the 4 sensors. 0 is closed, 1 is open. Open var bit(5) ; These hold the maximum current reading from the sensors and which sensor is the max TempMax var word TempMaxSensor var byte ; ; --Temporary variables for use with temperature computations and display Dummy_RawTemp var word Dummy_Temp var word Dummy_Open var bit ; ; ; Set Variables to load into LCD Running Display ; Line 1 LCD_Line1 var byte(16) ; LCD_Status is a 7-byte field starting at Position 0 LCD_Status var LCD_Line1(0) ; LCD_Maxtemp is an 9-byte field starting at Position 7 LCD_MaxTemp var LCD_Line1(7) ; Line 2 LCD_Line2 var byte(16) ; LCD_Label is a 9-byte field starting at Position 0 LCD_Label var LCD_Line2(0) ; LCD_Temp is a 6-byte field starting at Position 9 LCD_Temp var LCD_Line2(9); ; LCD_Spinner is a 1-byte field starting at Position 15 LCD_Spinner var LCD_Line2(15) ; ; Set up some general counters Counter1 var byte ; CounterSpin controls the LCD Display Spinner CounterSpin var byte ; CounterLCD is a counter specifically for updating the LCD display CounterLCD var byte ; CounterLCDTemp determines which temperature is displayed on the LCD CounterLCDTemp var byte ; Need a digits string to map integer digits to their ASCII representations Digits var byte(16) ; ; Variables for Remote LED Display ; This one holds the temp delow which no display occurs LEDDigMinTemp var byte ; This one holds the digit address LEDDigAddr var byte ; This one holds the command to send to the digit LEDDigCmd1 var byte ; This one holds the optional command argument (must be present, even if command ; doesn't care about it) LEDDigCmd2 var byte ; This one holds the command checksum LEDDigChk var byte ; This is a dummy digit for skipping the LED update every so many EventLoop cycles LEDDigDummy var nib ; This is a dummy bit for alternating the alarm display LEDDigAlt var bit ; Main ; Initalize the LCD ; Wait a second for the LCD to power up and stabilize pause 1000 ; Initalize the module lcdwrite p4\p5,outa,[INITLCD1,INITLCD2,twoline,clear,home,scr] ; Load in the user-defined characters for the spinner lcdwrite p4\p5,outa,[cgram+$00,$00,$00,$00,$1F,$00,$00,$00,$00] lcdwrite p4\p5,outa,[cgram+$08,$00,$10,$08,$04,$02,$01,$00,$00] lcdwrite p4\p5,outa,[cgram+$10,$00,$04,$04,$04,$04,$04,$00,$00] lcdwrite p4\p5,outa,[cgram+$18,$00,$01,$02,$04,$08,$10,$00,$00] ; Load in the user-defined character for the degree symbol lcdwrite p4\p5,outa,[cgram+$20,$0C,$12,$12,$0C,$00,$00,$00,$00] ; ; Load the initial display(s) LCD_Line1="TempAlarm v0.59 " LCD_Line2="Initializing... " ; Write out data to the LCD display gosub Write_LCD pause 2000 ; ; Initialize the spinner's counter CounterSpin = $0 ; Initialize the Digits string Digits="0123456789ABCDEF" ; Initialize the counter that controls what's displayed on Line 2 of the ; LCD Dislay CounterLCDTemp = 0 ; ; Initialize the System State to Armed. Output Pin P6 is low. SysState = 0 low P9 ; Initialize the system uptime Sys_Uptime = 0 ; ; Initial requirements for command handling Cmd_Command_Valid = "RASD" Cmd_Command_Valid_LastIndex = 3 ; Set up the hardware serial port and clear all buffers. sethserial h9600 hserstat 2 ; ; Read the temerature scale jumper on I/O Pin 11 (1=Fahrenheit, 0=Celsius) Input P11 debug ["C/F ", bin in11,13] Tempscale = in11 ; ; Set the minimum temperature below which the Remote LED Display will be blank ; The value is set in Fahrenheit and converted to Celsius when needed LEDDigMinTemp = 120 if TempScale = 0 then ; We're running in Celsius. Convert LEDDigMinTemp. LEDDigMinTemp=(5 * (LEDDigMinTemp-32)) / 9 endif ; ; Initialize the temperature set point ; Do the dirty gosub ReadBCDSwitches SetPoint = SetPointTemp ; Rig the system so that GetSetPoint doesn't think it's a new reading SetPointCandCount = SetPointCheck + 1 ; ; Initialize alarm checking AlarmCount = 0 ; ; Read the Temperature to get an initial reading going before the first display gosub GetTemp pause 500 ; ; Main event loop. After Initialization, everything branches from here! EventLoop ; Handle the command interface gosub HandleCmd ; ; Check the Set Point (every X passes). gosub GetSetPoint ; ; Read the sensors, store readings and determine the maximum reading found. gosub GetTemp ; ; Check the highest Temperature against the set point and alarm as needed. Alarm after ; seeing X consecutive readings above the set point. gosub AlarmCheck ; ; Update the LCD Temperature Display gosub Display_Temp ; ; Update the remote display every 4th pass ;SEE MODULO (a//b) section in Basic ATOM manual for info on using modulo to skip some passes LEDDigDummy = Sys_Uptime // 2 if LEDDigDummy = 0 then gosub RemoteLEDDisplay endif ; ; Pause for a while to freese the display and let the sensors process ; We're targeting a 1 second event loop so that the Sys_Uptime counter ; roughly reflects seconds of uptime. pause 891 ; Update the system uptime counter Sys_Uptime = Sys_Uptime + 1 if Sys_Uptime < 0 then Sys_Uptime = 0 endif ; ; Restart the loop goto EventLoop ; Handle waiting command HandleCmd ; If there is no data waiting, continue on with business. Otherwise, command processing ; will begin debug ["Handle_Cmd",13] hserstat 4, HandleCmd_NoData ; Grab a character fron the buffer. hserin [Cmd_Dummy] ; Now, start checking... ; If the character is an "@", immediately change Cmd_State to 1 and start looking for ; a command. debug ["Handle_Cmd Data",Cmd_Dummy,13] if Cmd_Dummy = $40 then Cmd_State = 1 goto HandleCmd ; If Cmd_State=1, look for a valid Command character elseif Cmd_State = 1 ; Store the received character and test is to see if it's a valid command. Cmd_Command = Cmd_Dummy ; Set Cmd_State to $0F, which will be the case unless we find a valid Command ; character. Cmd_State = $0F ; Check Cmd_Command against the list of valid Command characters. for Counter1 = 0 to Cmd_Command_Valid_LastIndex ; If Cmd_Command is in Cmd_Command_Valid, change Cmd_State to 2, store the ; Command character and continue. if Cmd_Dummy = Cmd_Command_Valid(Counter1) then ; Update the command state so to overwrite the default error state. Cmd_State = 2 ; From here, we go to the start of command parsing. endif next ; Should never get here, but set Cmd_State to zero go back to InputLoop just in case else Cmd_State = 0 goto HandleCmd endif ; ; If Cmd_State was $0F, send a Negative Acknowledgement if Cmd_State = $0F then Cmd_ACK = $3F hserout [Cmd_ACK,Cmd_Command] ; Otherwise, Cmd_State must be 3 (valid command) else ; All commands from here will get Positive Acknowledgements Cmd_ACK = $21 ; R - System Reset (Restart code from top) if Cmd_Command = "R" then ; Have to acknowledge this one here, as we're going down... hserout [Cmd_ACK,Cmd_Command] goto Main ; A - Attention (Just respond) elseif Cmd_Command = "A" hserout [Cmd_ACK,Cmd_Command] ; S - Query System State. elseif Cmd_Command = "S" ; Store the System Status in Cmd_dummy as we need to send a byte. Cmd_Dummy ; is no longer required now that command state detection is complete. Cmd_Dummy = SysState ; Store the letter we'll send for the Temperature Scale if TempScale = 1 then ; Fahrenheit Cmd_Dummy1 = "F" else ; Celsius Cmd_Dummy1 = "C" endif ; Send the response, fixing hex field lengths hserout [Cmd_ACK,Cmd_Command,dec Cmd_Dummy,Cmd_Dummy1,hex4 SetPoint\4,hex8 Sys_Uptime\8] ; D - Query thermocouple readings elseif Cmd_Command = "D" ; Store the Open Status the four thermocouples in Cmd_Dummy. Cmd_Dummy is no ; longer required now that command state detection is complete. Cmd_Dummy = 0 ; Set the lower 4 bits to match the open states of the thermocouples in the same ; order as the thermosouple data is provided Cmd_Dummy = Cmd_Dummy + (Open(1) * 8) Cmd_Dummy = Cmd_Dummy + (Open(2) * 4) Cmd_Dummy = Cmd_Dummy + (Open(3) * 2) Cmd_Dummy = Cmd_Dummy + Open(4) ; Send the response, fixing hex field lengths hserout [Cmd_ACK,Cmd_Command,hex4 Temp(1)\4,hex4 Temp(2)\4,hex4 Temp(3)\4,hex4 Temp(4)\4,hex1 Cmd_Dummy\1] ; Default command - Nothing else ; Does nothing, which is what this command does endif endif ; After dealing with commands, reset Cmd_State Cmd_State=0 ; HandleCmd_NoData return ; Subroutine to set the temperature set point when it changes GetSetPoint ; Don't accept set point changes if we''ve alarmed out. if SysState = 1 then ; Do nothing. We're in alarm state. goto NoSetPointChange endif ; Not in alarm state...Continuing ; ; Read the BCD thumbwheel switches gosub ReadBCDSwitches ; ; Is the current reading the same as the current set point? if SetPointTemp = SetPoint then ; No change. Do nothing. goto NoSetPointChange endif ; ; The BCD Switches have been changed...Continuing ; ; The BCD thumbwheel switches have changed. Must figure out ; where we are in the cycle. ; Is this the first change we've seen? If so, SetPointCand will ; equal SetPoint. if SetPointCand = SetPoint then ; This is the first time we've seen any new value. Reset the ; counter to zero and hold the value. SetPointCandCount = 0 SetPointCand = SetPointTemp else ; We're somewhere in the cycle. Is this the same value we saw ; last time? ; NOTE: This "if" statement was revesed. It used to check for ; SetPointCand not equal to SetPointTemp, but for some reason, ; it caused Handle_CMD not be to able to read the hardware serial ; port except when debugging. Narrowed if down to the "if" ; statement, reversed the lodig order to make it an equality, and ; the problem was fixed. if SetPointCand = SetPointTemp then ; We've seen this value before. Increment the counter and see ; if it's time to commit. SetPointCandCount = SetPointCandCount + 1 ; Are we over the limit to commit? Is it time to believe the new value? if SetPointCandCount > SetPointCheck then ; The new value passed the test of time. Commit it. SetPoint = SetPointCand else ; Do nothing. It will come around later to check again. endif else ; New value. Reset the start the cycle over. SetPointCandCount = 0 SetPointCand = SetPointTemp endif endif ;debug ["ReadSetPoint. Set Point: ",dec SetPoint," Cand: ",dec SetPointCand, " Count: ",dec SetPointCandCount,13] ; NoSetPointChange return ; Obtain the value from the BCD thumbwheel switches (via a 74HC165 Shift Register) ReadBCDSwitches ; Lower then raise the 74HC165 Shift/Load pin to make it read the BCD thumbwheel switches low P6 high P6 ; Read the value from the 74HC165 shiftin P8,P7,msbpre,[SetPointTemp\8] ; Clear the upper 8 bits, convert the 2 packed BCD digits to binary and multiply by 10 ; so that the 2 BCD switches provide the 100's and 10's digits of the set point. The ; 1's digit will always be zero SetPointTemp=(bcd2bin (SetPointTemp & $FF))*10 ;debug ["Read Set Point Switches: ",dec SetPointTemp," ",bin SetPointTemp,13] return ; Temperature Measurement Subroutine GetTemp ; If the system isn't alarmed out, reset the variables that hold the max temperature ; for the next calculation if SysState = 0 then TempMax = 0 TempMaxSensor = 0 endif ; Loop through 1-4 and sample temperatures for Counter1 = 1 to 4 ; Set Dummy_Temp to zero as a default in case we get no value Dummy_RawTemp=0 ; For each value of Counter1 ; Drop CS to stop converting and present reading ; Read the 16 bits from the chip. ; Raise CS to resume converting if Counter1 = 1 then low P16 shiftin P18,P17,msbpre,[Dummy_RawTemp] high P16 elseif Counter1 = 2 low P19 shiftin P21,P20,msbpre,[Dummy_RawTemp] high P19 elseif Counter1 = 3 low P22 shiftin P24,P23,msbpre,[Dummy_RawTemp] high P22 elseif Counter1 = 4 low P25 shiftin P27,P26,msbpre,[Dummy_RawTemp] high P25 else ; Nothing. Just had to have a real comparison for all values, so need this to pass syntax check. endif ;debug[dec Counter1,"--",bin Dummy_RawTemp,13] ; ; Extract the data we're interested in. ; Bits 14-5 are the integer part of the Celsius temperature and bit 2 is the ; thermocouple open indicator. The rest are garbage. ; ; Get the open bit first. Mask out bit 2 and shift be a 1 or 0 Open(Counter1)=(Dummy_RawTemp & %100)>>2 ; ; Get the Temperature Reading ; Mask off bit 15 to get rid of it ; Right-shift 5 bits to get get rid of fractional and "other" bits Dummy_Temp=(Dummy_RawTemp & $7fff) >> 5 ;debug[dec Counter1,"--","Pre-Convert: ",dec Dummy_Temp,13] ; ; The MAX6675 reads in Celsius. If TempScale is set for Fahrenheit, ; convert the resulting value. if TempScale = 1 then gosub CtoF endif ; ; Store the converted value Temp(Counter1)=Dummy_Temp ;debug[dec Counter1,"--","Converted: ",dec Temp(Counter1)," Open: ",dec Open(Counter1),13] ; ; If the system isn't in alarm state, the current sensor isn't open, ; and it reads higher than the others, use it as the max. if SysState = 0 and Temp(Counter1) > TempMax and Open(Counter1) = 0 then TempMax = Temp(Counter1) TempMaxSensor = Counter1 endif next ; return ; Celsius to Fahrenheit Conversion CtoF Dummy_Temp=((9 * Dummy_Temp) / 5) + 32 return ; Subroutine to determine whether to alarm out the system. AlarmCheck ; Before we even bother with this, ; Are we above the set point? Also,make sure that we're in the cycle of testing ; for a new set point. We should only alarm when the set point is stable. ; (Note: Verify this assumption from the standpoint of safety!) if TempMax > SetPoint and SetPointCandCount > SetPointCheck then ; Is it time to alarm? if AlarmCount > AlarmLimit then ; We've reached the limit. Alarm out and raise P9! SysState = 1 High P9 else ; We haven't seen enough violations to alarm out. Increment the counter. AlarmCount = AlarmCount + 1 endif else: ; Temperatures are within limits. Reset the alarm counter. AlarmCount = 0 endif debug ["AlarmCheck. Count: ",dec AlarmCount," State: ",dec SysState,13] return ; LCD Temperature Display Update Subroutine Display_Temp ; Note: We write the status line and setpoint or 1 sensor reading per pass ; ; ***Prepare LCD Line 1 ; Write data for the System State if SysState = 0 then LCD_Status(0)="A" LCD_Status(1)="r" LCD_Status(2)="m" LCD_Status(3)="e" LCD_Status(4)="d" LCD_Status(5)="!" LCD_Status(6)=" " else LCD_Status(0)="A" LCD_Status(1)="L" LCD_Status(2)="A" LCD_Status(3)="R" LCD_Status(4)="M" LCD_Status(5)="!" LCD_Status(6)=" " endif ; Write Data for the Max temperature LCD_MaxTemp(0)="M" LCD_MaxTemp(1)="a" LCD_MaxTemp(2)="x" LCD_MaxTemp(3)=Digits(TempMaxSensor) LCD_MaxTemp(4)=":" LCD_MaxTemp(5)=Digits(TempMax dig 2) LCD_MaxTemp(6)=Digits(TempMax dig 1) LCD_MaxTemp(7)=Digits(TempMax dig 0) LCD_MaxTemp(8)=4 ; ; ***End of LCD Line 1 Preparation ; ; ***Prepare LCD Line 2 ; Write the label for sensor or set point ; Determine which temprature we'll dislay this time ; CounterLCDTemp = 0 will display the set point if CounterLCDTemp = 0 then Dummy_Temp = 0 LCD_Label(0)="S" LCD_Label(1)="e" LCD_Label(2)="t" LCD_Label(3)="P " LCD_Label(4)="o" LCD_Label(5)="i" LCD_Label(6)="n" LCD_Label(7)="t" LCD_Label(8)=":" LCD_Temp(0)=Digits(SetPoint dig 2) LCD_Temp(1)=Digits(SetPoint dig 1) LCD_Temp(2)=Digits(SetPoint dig 0) LCD_Temp(3)=4 if TempScale=1 then LCD_Temp(4)="F" else LCD_Temp(4)="C" endif ; CounterLCDTemp between 1 and 4 inclusive will display sensor readings else Dummy_Temp = Temp(CounterLCDTemp) Dummy_Open = Open(CounterLCDTemp) LCD_Label(0)="S" LCD_Label(1)="e" LCD_Label(2)="n" LCD_Label(3)="s" LCD_Label(4)="o" LCD_Label(5)="r" LCD_Label(6)="_" LCD_Label(7)=Digits(CounterLCDTemp) LCD_Label(8)=":" ; ; If the Thermocouple isn't open, write the temprature to the LCD if Dummy_Open = 0 then ; The MAX6675 output ranges from 0C to 1023C and F temps will be larger. ; The lowest F temp will be 32 and the highest set point will be 990 ; (absolute). If we have atemperature reading above 1000, it's a ; leftover value from reconnection of an open thermocouple and is invalid. A value this ; A value this high would have tripped out the set point checker. The ; check for values greter than 32 is an attempt to detect nonresponding ; MAX6675 chips. If the chip is disconnected, it should fail at one extreme ; or the other. ; Note: Modified to make this work for either Celsius for Fahrenheit by ANDing temp and scales. ;if Dummy_Temp < 1000 and Dummy_Temp > 32 then if Dummy_Temp < 1000 and ((Dummy_Temp > 32 and TempScale = 1) or (Dummy_Temp > 0 and TempScale = 0)) then ; Send each digit of the temperature to LCD_SensorA ;debug[dec Temp4 dig 2,dec Temp4 dig 1,dec Temp4 dig 0,13] LCD_Temp(0)=Digits(Dummy_Temp dig 2) LCD_Temp(1)=Digits(Dummy_Temp dig 1) LCD_Temp(2)=Digits(Dummy_Temp dig 0) LCD_Temp(3)=4 if TempScale=1 then LCD_Temp(4)="F" else LCD_Temp(4)="C" endif ; If the reading is freezing, the we didn't read the chip else LCD_Temp(0)="F" LCD_Temp(1)="a" LCD_Temp(2)="i" LCD_Temp(3)="l" LCD_Temp(4)="!" endif ; If the thermocouple is open, say so... else LCD_Temp(0)="O" LCD_Temp(1)="p" LCD_Temp(2)="e" LCD_Temp(3)="n" LCD_Temp(4)="!" endif endif ; ; Clear the space after the temperature LCD_Temp(5)=" " ; ; Update the spinner gosub RunSpinner ; ; ***End of LCD Line 2 Preparation ; ; Update the LCD display gosub Write_LCD ; ; Increment the counter CounterLCDTemp = CounterLCDTemp + 1 if CounterLCDTemp > 4 then CounterLCDTemp = 0 endif return ; Remote LED Display subroutine RemoteLEDDisplay ; Send the max temp value or alarm indication to the Remote LED display ; We'll create the display depending on SysState and use common code ; to strobe it out to the display ; ; Send the max temp is we're not alarmed out. Don't display if max temp ; is below LEDDigMinTemp if SysState = 0 then ; Set the display intensity LEDDigAddr = 0 LEDDigCmd1 = "I" LEDDigCmd2 = 255 gosub SendLEDDigit ; ; Set the degree sign LEDDigAddr = 1 LEDDigCmd1 = "B" ; Display only if the max temp is high enough if TempMax > LEDDigMinTemp then LEDDigCmd2 = 39 else LEDDigCmd2 = 0 endif gosub SendLEDDigit ; ; Set the ones digit LEDDigAddr = 2 ; Display only if the max temp is high enough if TempMax > LEDDigMinTemp then LEDDigCmd1 = "A" LEDDigCmd2 = Digits(TempMax dig 0) else LEDDigCmd1 = "B" LEDDigCmd2 = 0 endif gosub SendLEDDigit ; ; Set the tens digit ; May want to suppress leading zeroes on this, but it would only apply ; to Celsius temps below 10 (less than 50F) and would never apply to ; Fahrenheit temps. LEDDigAddr = 3 ; Display only if the max temp is high enough if TempMax > LEDDigMinTemp then LEDDigCmd1 = "A" LEDDigCmd2 = Digits(TempMax dig 1) else LEDDigCmd1 = "B" LEDDigCmd2 = 0 endif gosub SendLEDDigit ; ; Set the hundreds digit LEDDigAddr = 4 ; Suppress hundreds digit if it's zero (leading zero as the hundreds ; digit will be zero most of the time) or if the max temp isn't high enough. if (TempMax dig 2)=0 or (TempMax < LEDDigMinTemp) then LEDDigCmd1 = "B" LEDDigCmd2 = 0 else LEDDigCmd1 = "A" LEDDigCmd2 = Digits(TempMax dig 2) endif gosub SendLEDDigit ; ; If we're alarmed out, alternate between an alarm indication and a blank display else ; Set the rightmost digit if LEDDigAlt = 0 then ; Alarm display ; Set the letter "P" LEDDigAddr = 1 LEDDigCmd1 = "B" LEDDigCmd2 = 103 else ; Max Temp Display ; Set the degree sign LEDDigAddr = 1 LEDDigCmd1 = "B" LEDDigCmd2 = 39 endif gosub SendLEDDigit ; ; Set the 2nd rightmost digit if LEDDigAlt = 0 then ; Alarm display ; Set the letter "L" LEDDigAddr = 2 LEDDigCmd1 = "B" LEDDigCmd2 = 193 else ; Max Temp Display ; Set the ones digit LEDDigAddr = 2 LEDDigCmd1 = "A" LEDDigCmd2 = Digits(TempMax dig 0) endif gosub SendLEDDigit ; ; Set the 2nd leftmost digit if LEDDigAlt = 0 then ; Alarm display ; Set the letter "E" LEDDigAddr = 3 LEDDigCmd1 = "B" LEDDigCmd2 = 227 else ; Max Temp Display ; Set the tens digit LEDDigAddr = 3 LEDDigCmd1 = "A" LEDDigCmd2 = Digits(TempMax dig 1) endif gosub SendLEDDigit ; ; Set the leftmost digit if LEDDigAlt = 0 then ; Alarm display ; Set the letter "H" LEDDigAddr = 4 LEDDigCmd1 = "B" LEDDigCmd2 = 79 else ; Max Temp Display ; Set the hundreds digit LEDDigAddr = 4 ; Suppress hundreds digit if it's zero (leading zero as the hundreds ; digit will be zero most of the time) or if the max temp isn't high enough. if (TempMax dig 2)=0 then LEDDigCmd1 = "B" LEDDigCmd2 = 0 else LEDDigCmd1 = "A" LEDDigCmd2 = Digits(TempMax dig 2) endif endif gosub SendLEDDigit ; ; Set the display intensity if LEDDigAlt = 0 then ; Alarm display LEDDigAddr = 0 LEDDigCmd1 = "I" LEDDigCmd2 = 0 gosub SendLEDDigit else ; Max Temp Display LEDDigAddr = 0 LEDDigCmd1 = "I" LEDDigCmd2 = 255 gosub SendLEDDigit endif gosub SendLEDDigit endif ; ; Update the alternation bit LEDDigAlt = LEDDigAlt + 1 ; Strobe sent data to the display LEDDigAddr = 0 LEDDigCmd1 = "S" LEDDigCmd2 = 0 gosub SendLEDDigit ; return ; Spinner Subroutne RunSpinner ;debug [CounterSpin] ;lcdwrite p4\p5,outa,[scrram+$0F,CounterSpin] LCD_Spinner(0)=CounterSpin CounterSpin=CounterSpin + 1 if CounterSpin > 3 then CounterSpin = 0 endif return ; Overwrite entire LCD display Write_LCD lcdwrite p4\p5,outa,[clear,home] for CounterLCD = 0 to 15 lcdwrite p4\p5,outa,[scrram+CounterLCD,LCD_Line1(CounterLCD)] lcdwrite p4\p5,outa,[scrram+CounterLCD+$40,LCD_Line2(CounterLCD)] next return ; Send a digit command to the remote LED display ; Transmit Data to the Display on on Pin 12 and runs 2400/8/N/1 and ; inverted data (i.e., the same inversion sent by the hardware serial ; port so that the MAX232 convers them the same way. SendLEDDigit LEDDigChk = 256 - ((13 + LEDDigAddr + LEDDigCmd1 + LEDDigCmd2) | 256) serout P12,I2400,[13,LEDDigAddr,LEDDigCmd1,LEDDigCmd2,LEDDigChk] return End