' ********************************************************************** ' ** Program: DEMOLCD51U.BAS - Version : 1.1 - 09 January 2001 ** ' ** Compiler: BASCOM 8051 DEMO, (IDE V.2.0.4.0, LIB V.2.04) ** ' ** Board: K51-AVR ** ' ** Firm: grifo(r) ITALIAN TECHNOLOGY ** ' ** Via Dell' Artigiano 8/6 40016 San Giorgio di Piano (BO) ** ' ** Tel.+39 051 892 052 Fax +39 051 893 661 ** ' ** http://www.grifo.com http://www.grifo.it ** ' ** sales@grifo.it tech@grifo.it grifo@grifo.it ** ' ** ** ' ** Written by: Graziano GAIBA ** ' ********************************************************************** ' ' This program is a terminal emulator completely configurable both for ' the protocol keymap and for the procedures associated to each key. ' The procedure charged with filtering the characters and deciding ' whether to print them or to execute them as commands is called ' Filterlcd. ' There are three different kinds of commands: ' ' 1) Control characters ' 2) Immediate commands ' 3) Commands with at least one parameter ' ' Control characters are not visualized but, as soon as they are received, ' trigger the execution of a specific portion of code. For example the ASCII ' character called BEL (code 7) normally produces a sound but is not printed ' to the screen. ' Immediate commands are sequences like , that is a ' character that acts as prefix to precede a command code (often as prefix the ' ASCII ESC key is used (code 27)) and a chatacter that identifies the command ' to execute. As soon as is recognized the instructions matched ' to it are executed. ' Commands with at least one parameter are variable length sequences like: ' ' <1st parameter><2nd parameter> ... ' ' each command is preceded by the prefix and identified by its code, then follow ' one or more characters that are stored as parameters. As soon as the last ' parameter of the command has been received its instructions are executed, ' every command can have an independent number of parameters limited only by the ' memory available. ' The procedures Conin and Conout (Console input and Console output) make a ' comfortable interface to the procedure Filterlcd. Their behaviour depends on ' which device (serial port or K51 board) is being used as input and as output. ' To select the devices to use as input and as output it is enough to give the ' opportune value to the variables Indev and Outdev. For example, to read from ' the serial port and write to the LCD display of K51-AVR, type: ' ' Indev = Ser ' Outdev = K51 ' Call Constatus ' If Kbhit <> 0 Then ' Call Conin ' P = In ' Call Conout(p) ' End If ' ' The procedure Constatus checks whether the device selected for output has one ' or more characters ready to be read. If at least one character is ready the ' procedure, after being called, sets to 1 the value of the variable kbhit, ' otherwise the procedure resets it to 0. To read the next pending character ' it is enough to call the procedure Conin and read the value of the variable ' In. Conin always returns 0 if called with no characters pending, but it also ' returns 0 if the character pending was just 0. To avoid ambiguity just call ' Constatus before Conin and examine the value of kbhit. ' To send a character to the output device selected by Outdev it is enough to ' call the procedure Conout giving it as parameter the character to print. ' ' NOTE ' To be able to store in opportune buffers the characters coming from the input ' sources an interrupt must scan them periodically, this means also that the ' K51-AVR keys must be debounced. This interrupt is generated through timer 0. ' ' To use the LCD display it is essential to remove the integrated circuit in ' IC12 and to disconnect jumper J4, losing the possibility to use key T3. It ' must be done to aviod conflicts between these devices and the LCD display ' lines. ' ' The periodic output of Real Time Clock PCF8583 is connected to the same I/O ' line used by key T4, so it generates false key pressing. To be able to use key ' T4 the RTC (IC7) must be removed or it must be reprogrammed to make it stop ' the periodic signal. ' '*********************************************************************** ' '*********************** Compiler directives *************************** ' $regfile = "REG51.DAT" ' 8xc51 registers list $romstart = &H0 ' code start address $crystal = 11059200 ' micro clock frequence Config Lcd = 20 * 2 ' Lcd with 20 columns and 4 rows ' LCD signals connections (see on line help for more information) Config Lcdpin = Pin , Db4 = P1.5 , Db5 = P1.6 , Db6 = P1.7 , Db7 = P1.2 , E = P1.4 , Rs = P1.3 ' Character (R) registered, created using the LCD designer of menu Edit. Deflcdchar 0 , 32 , 14 , 10 , 12 , 10 , 32 , 32 , 32 ' Bit indicating when the SIO input buffer is full Ri Alias Scon.0 ' Line where the key T1 is connected T1 Alias P1.0 ' Line where the key T2 is connected T2 Alias P1.1 ' Line where the key T3 is connected T3 Alias P1.2 ' Line where the key T4 is connected T4 Alias P3.2 ' Line where the auto-oscillating buzzer is connected Buz Alias P3.5 ' Sets label Scan as response procedure to interrupt generated by timer 0 On Timer0 Scan ' '********************** Procedures declaration ************************* ' Declare Sub Init ' Initializes display Declare Sub Conin ' Reads byte from console Declare Sub Conout(ch As Byte) ' Filters a character ' Checks whether a character is available Declare Sub Constatus ' Recognizes and filters the characters in output Declare Sub Filterlcd(ch As Byte) ' Corrects the values of the variables Row and Column Declare Sub Adjustxy ' '*********************** Constants declaration ************************** ' ' Value to load into timer0 to have a 20 msec periodical interrupt Const Loadtimer = &HB7FF ' Number of iterations of debouncing before considering a key as pressed Const Debiter = 10 ' Maximum number of characters in the serial reception buffer Const Maxchar = 5 ' Maximum number of characters in the K51 keys reception buffer Const Maxkeys = 2 ' Highest number of parameters for a parametric command Const Maxpar = 3 ' Prefix for terminal emulation commands Const Prefix = &H1B ' Character Esc ' Used to indcate the serial port as input or output Const Ser = 1 ' Used to indcate the K51 as input or output Const K51 = 2 ' '*********************** Variables declaration ************************** ' Dim In As Byte ' Value read in input Dim Kbhit As Bit ' Is 1 if key pressed Dim Command As Byte ' Commands management Dim Code As Byte ' Code of command Dim Indev As Byte ' Select input device Dim Outdev As Byte ' Select output device Dim Par(maxpar) As Byte ' Parameters of commands Dim Row As Byte , Column As Byte ' Cursor coordinates Dim Bufferk51(maxkeys) As Byte ' Buffer for K51 keys Dim Bufferser(maxchar) As Byte ' Buffer for serial port Dim Idxser As Byte , Idxk51 As Byte ' Buffer indexes Dim Idxcarser As Byte , Idxcark51 As Byte ' Index for next ' character to be read Dim Debcnt As Byte ' Debouncing counter Dim Debcod As Byte ' Code of key pressed Dim Debchar As Byte ' Key under debouncing Dim Buzcnt As Byte ' Buzzer counter Dim P As Byte , Ch As Byte ' General purpose ' '***************************** Main Program ***************************** ' Main: ' ' Initializes the LCD display, the timer for the input scansion and the ' program variables. ' Call Init Do Indev = Ser ' Serial port as input Outdev = K51 ' LCD display as output Call Constatus ' Charcter available? If Kbhit <> 0 Then ' If available, read the Call Conin ' character and store it P = In ' in variable p Call Conout(p) ' Send it to the output End If ' device Indev = K51 ' K51 keys as input Outdev = Ser ' Serial port as output Call Constatus ' Charcter available? If Kbhit <> 0 Then ' If available, read the Call Conin ' character and store it P = In ' in variable p Call Conout(p) ' Send it to the output End If ' device Loop ' ' Timer 0 interrupt response procedure. ' It is charged with timing the buzzer sound, updating the serial port buffer if ' a character is ready and updating the K51 keys buffer if a key is pressed. ' Scan: ' Whenever a timed interrupt is triggered, the first thing to do is to ' reinitialize the timer. Stop Timer0 ' Stops the timer Counter0 = Loadtimer ' Restores the timer Start Timer0 ' Restarts the timer ' Buzzer sound timing. If variable Buzcnt is 0 the buzzer is silented, otherwise ' the variable is decremented. If Buzcnt <> 0 Then ' If Buzcnt is not 0 Decr Buzcnt ' decrement it Else ' otherwise Buz = 1 ' stops the buzzer End If ' Read the serial port. If bit Ri is 1 then the SIO input buffer is full and ' the pending character is stored in the buffer Bufferser which is managed as a ' circular buffer, that is when the buffer is full it continues to store bytes ' overwriting the bytes not yet read. If Ri = 1 Then ' Character available? Bufferser(idxser) = Inkey ' Read it and store it Incr Idxser ' Increment index If Idxser > Maxchar Then ' If index overflows Idxser = 1 ' Reset it to the End If ' starting value End If ' K51 keys acquisition. If the I/O pin of the microcontroller is at logical 0 ' then the key is pressed. Debcod = 0 ' If key 1 is pressed If T1 = 0 Then ' store the code Debcod = "1" End If If T2 = 0 Then ' If key 2 is pressed Debcod = "2" ' store the code End If ' Here keys 3 and 4 are not acquired. See note on top of the source code. ' If T3 = 0 Then ' Debcod = "3" ' End If ' If T4 = 0 Then ' Debcod = "4" ' End If ' Debouncing. The keycode possibly read becomes the new key under debouncing ' unless it is already under debouncing. In this latter case the debouncing ' counter is incremented. When the counter reaches the limit value the key ' under debouncing is considered as pressed and its code is stored in the K51 ' keys buffer. If Debcod <> 0 Then ' If there is a key code If Debcod = Debchar Then ' and it is debounced Incr Debcnt ' increment counter Else ' otherwise Debchar = Debcod ' new key debounced Debcnt = 0 ' resets the counter End If End If If Debcnt > Debiter Then ' If counter overflows Debcnt = 0 ' resets the counter Bufferk51(idxk51) = Debchar ' Store the keycode Incr Idxk51 ' Increment index If Idxk51 > Maxkeys Then ' If index overflows Idxk51 = 1 ' Restore it to the End If ' starting value Call Bip ' Buzzer makes a bip End If Return End ' '************************* End of Main Program ************************** ' ' ' Initialization of variables, I/O devices and interrupt. ' Sub Init ' Initialization of global variables Kbhit = 0 ' No key pressed Command = 0 ' No commands of Code = 0 ' terminal emulation Idxser = 1 ' Starting value of Idxcarser = 1 ' indexes for buffer Idxk51 = 1 ' filling and reading Idxcark51 = 1 Debcod = 0 ' Resets key code and Debchar = 0 ' key under debouncing Debcnt = 0 ' Resets debouncing and Buzcnt = 0 ' buzzer counters Cls ' Initializes and clears ' the display Column = 1 : Row = 1 ' Initializes cursor Cursor Blink ' Cursor blinking Config Timer0 = Timer , Gate = Internal , Mode = 1 Counter0 = Loadtimer ' One interrupt every Enable Timer0 ' 20 msec Enable Interrupts ' All interrupts enabled Start Timer0 ' Starts Timer 0 End Sub ' ' Reads a byte from the selected input device. ' ' Input parameters ' None ' ' Output value ' In byte read ' Sub Conin In = 0 ' Return 0 if no ' character is read. Select Case Indev ' According to device Case Ser: ' Serial port If Idxcarser <> Idxser Then ' Character available? ' Reads one character In = Bufferser(idxcarser) ' from reception buffer Incr Idxcarser ' Points next character If Idxcarser > Maxchar Then ' If out of the buffer Idxcarser = 1 ' Return to buffer start End If End If Case K51: ' K51 keys If Idxcark51 <> Idxk51 Then ' Character available? ' Reads one character In = Bufferk51(idxcark51) ' from reception buffer Incr Idxcark51 ' Points next character If Idxcark51 > Maxkeys Then ' If out of the buffer Idxcark51 = 1 ' Return to buffer start End If End If End Select End Sub ' ' Writes a byte to the selected output device ' ' Input parameters ' Ch Byte to send to the selected output device ' ' Output value ' None ' Sub Conout(ch) Select Case Outdev ' According to device Case Ser: ' Serial port Print Chr(ch); ' Send the character Case K51: ' LCD display Call Filterlcd(ch) ' Filter the character End Select End Sub ' ' Checks whether characters not yet read are present in the buffer of the ' device selected as input. ' ' Input parameters ' None ' ' Output value ' Kbhit set to 1 if there is at least one character not yet read,0 otherwise ' Sub Constatus Select Case Indev ' According to device Case Ser: ' Serial port If Idxcarser = Idxser Then ' If indexes are equal Kbhit = 0 ' No character left Else ' Otherwise Kbhit = 1 ' At least one char End If Case K51: ' LCD display If Idxcark51 = Idxk51 Then ' If indexes are equal Kbhit = 0 ' No character left Else ' Otherwise Kbhit = 1 ' At least one char End If End Select End Sub ' ' ' Sub Filterlcd(ch As Byte) If Ch = Prefix Then ' If it is the prefix If Command = 0 Then ' and no command is run Command = &H80 ' enter in command mode End If ' Otherwise if it is not Else ' the prefix Select Case Command Case 0: ' no command is run ' IMMEDIATE COMMANDS Select Case Ch ' Immeditate commands ' also known as control ' characters Case &H07: ' ASCII BEL character Call Bell ' Makes buzzer sound Case &H0A: ' ASCII LF (line feed) Incr Row ' Move to next row If Row > 2 Then ' If over last row Row = 1 ' back to first row End If Locate Row , Column ' Move the cursor Case Else: ' Printable characters Lcd Chr(ch) ' Write character to LCD Column = Column + 1 Call Adjustxy ' adjust variables End Select Case &H80: ' Recognizes a command Select Case Ch ' Start recognition ' COMMAND WITHOUT PARAMETERS Case "1": ' Zero parameters Cls ' Immediate execution Row = 1 ' Update variables of Column = 1 ' cursor position Command = 0 ' Command End ' COMMANDS WITH PARAMETERS Case "2": ' One parameter Command = 1 ' Parameters number Code = Ch ' Store command code Case "3": ' Two parameters Command = 2 ' Parameter number Code = Ch ' Store command code Case Else: ' Command not recognized Command = 0 ' Exit command mode Code = 0 End Select ' If a command with one ' or more parameters is ' run, gathers its ' parameter. Number of ' parameters is value of ' variable command ' GATHER PARAMETERS Case 1 To Maxpar: Par(command) = Ch ' Store parameter Command = Command - 1 ' Update parameters left ' EXECUTION COMMANDS WITH PARAMETERS If Command = 0 Then ' All parameters stored Select Case Code ' According to code Case "2": ' One parameter If Par(1) = "b" Then ' If parameter is "b" Cursor Blink ' Set cursor to blink Else ' Otherwise If Par(1) = "n" Then ' If parameter is "n" Cursor Noblink ' Cursor doesn't blink End If End If Case "3": ' Two parameters ' parameters are stored ' in reversed order If Par(2) = "1" Then ' If first parameter "1" Lcd Chr(par(1)) ' Print second parameter Column = Column + 1 ' Advance to next column Else ' Otherwise Lcdhex Par(1) ' Print second parameter ' in hex format Column = Column + 2 ' Advance two columns End If Call Adjustxy ' Update the variables End Select End If End Select End If End Sub ' ' Corrects the value of variables Row and Column to prevent them from ' overflowing the limits of the LCD display. ' Sub Adjustxy If Column > 20 Then ' If over last column Column = 1 ' Back to first column Row = Row + 1 ' Next row If Row > 2 Then ' If over last row Row = 1 ' Back to first row End If Locate Row , Column ' Move the cursor End If End Sub ' ' Activates the buzzer and sets the buzzer interrupt counter to disable it ' after 25 interrupt cycles, that is half of a second. ' Sub Bell Buzcnt = 25 ' Sets 25 cycles Buz = 0 ' Activates the buzzer End Sub ' ' Activates the buzzer and sets the buzzer interrupt counter to disable it ' after 5 interrupt cycles, that is one tenth of a second. ' Sub Bip Buzcnt = 5 ' Sets 5 cycles Buz = 0 ' Activates the buzzer End Sub