/* ********************************************************************** ** Program: demolcde.c - Version : 1.4 - 02 October 2003 ** ** Compiler: uC/51 Ver. 1.10.10 ** ** Board: K51-AVR and 89c51 or compatible ** ** 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: setIndev(SER); setOutdev(K51); if(conStatus()) { conOut(conIn()) } 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. 05.06.2000 by Adriano Pedrielli (for K51 alone) (Original version in BASCOM 8051) 02.10.2003 by Graziano Gaiba Translation in uC/51. */ #include #include #include #include #define FALSE 0x00 // Boolean values #define TRUE 0xFF #define LF 0x0A #define CRET 0x0D // Debouncing #define DEBITER 10 // Cursor management #define BLINK 0x10 #define STEADY 0x00 // Input and output devices codes #define SER 0x01 #define K51 0x02 // Reload value for Timer 0 to scan the keys of K51 every 20 msec #define LoadtimerH 0xB7 #define LoadtimerL 0xFF // Number of debouncing iterations before a key is considered pressed #define Debiter 10 // Maximum size of serial reception buffer #define Maxchar 5 // Maximum size of K51-AVR keys reception buffer #define Maxtasti 2 // Maximum number of parameters for a command of terminal emulation #define Maxpar 3 // Prefix of commands of terminal emulation (Character Esc) #define Prefix 0x1B // Duration (in interrupt cycles) of the several sounds #define BIP 5 #define BELL 25 /***************** Addresses list for Saa1064 ***********************/ #define Saa1064 0x38 // Slave address SAA1064 #define Wsaa1064 0x70 // Slave address SAA1064 in Write #define Rsaa1064 0x71 // Slave address SAA1064 in Read #define Ctb 0x00 // Ind. Control byte #define Dig1 0x01 // Ind. Digit 1 #define Dig2 0x02 // Ind. Digit 2 #define Dig3 0x03 // Ind. Digit 3 #define Dig4 0x04 // Ind. Digit 4 /************************************************************************/ #define Wee 0xA0 // Slave address 24cXX in Write #define Ree 0xA1 // Slave address 24cXX in Read // Inizialization od SAA1064 #define saa1064_init_length 0x06 // Inizialization sequence length const unsigned char saa1064_init[]={ Ctb, // Points control register 0x27, // = 0b00100111 // bit0 =1 dynamic mode // bit1 =1 digit 1+3 not blanked // bit2 =1 digit 2+4 not blanked // bit3 =0 no test segment // bit4 =0 no 3mA segment current // bit5 =1 6mA segment current // bit6 =0 no 12mA segment current // bit7 =0 indifferent 0, // writes DY1 off 0, // writes DY2 off 0, // writes DY3 off 0 // writes DY4 off }; // Codes to convert a figure from 0 to F in 7 segments coding const unsigned char cifra_7seg[]={0x3F,0x06,0x5B,0x4F,0x66, 0x6D,0x7D,0x07,0x7F,0x6F, 0x77,0x7C,0x39,0x5E,0x79,0x71}; // Pattern to generate the new character (r) const unsigned char pattern_r[]={253, 245, 249, 245, 245, 225, 226, 252}; // I2C BUS management globals bit unsigned char SDA @ 0xB6; // Pin SDA=P3.6 bit unsigned char SCL @ 0xB7; // Pin SCL=P3.7 // Management of keys and buzzer bit unsigned char T1 @ 0x90; // P1.0 bit unsigned char T2 @ 0x91; // P1.1 bit unsigned char BUZ @ 0xB5; // P3.5 // Management of display LCD bit unsigned char E @ 0x94; // Address pin enable (P1.4) bit unsigned char RS @ 0x93; // Address pin RS (P1.3) bit unsigned char db4 @ 0x95; // Address DB4 (P1.5) bit unsigned char db5 @ 0x96; // Address DB5 (P1.6) bit unsigned char db6 @ 0x97; // Address DB6 (P1.7) bit unsigned char db7 @ 0x92; // Address DB7 (P1.2) // Global variables to store input and output devices inear unsigned char indev, outdev; // Global variables for command management inear unsigned char codice, comando; inear unsigned char par[Maxpar]; // Command parameters // Global variable to store cursor position inear unsigned char riga, colonna; // Global variables to manage buffered I/O inear unsigned char bufferK51[Maxtasti]; // Buffer keys read from K51 inear unsigned char bufferSER[Maxchar]; // Buffer for serial port near unsigned char idxSER, idxK51; // Indexes for buffer near unsigned char idxCarSER, idxCarK51; // Next character to read near unsigned char debCnt; // Debouncing counter near unsigned char debCod; // Code of key pressed near unsigned char debChar; // Key debounced inear unsigned char buzCnt; // Buzzer timer /********* General utilities and hardware section management ***********/ void iniser(unsigned long baud) /* Initialize serial line with: Bit x chr = 8 Stop bit = 1 Parity = None Baud rate = baud using timer 1 as baud rate generator. */ { SCON=0x052; // Mode 1, enable receiver TMOD&=0x00F; // Timer 1 in auto-reload TMOD|=0x020; TR1=0; // Stop TIMER 1 TH1=256-((2*11059200)/(384*baud)); // baud 14.7456 MHz PCON=PCON|0x080; // SetSMOD=1 for higher baud rates TR1=1; // Start TIMER 1 } void clrscr(void) /* Clear the screen of a generic console */ { unsigned char r; putc(CRET); for (r = 0 ; r < 25 ; r++) { putc(LF); // Sends 25 Line Feed } //endfor } void waitkey(void) { printf("Press a key to continue.."); getc(); puts(""); } void ritardo(unsigned int rit) /* Performs a software delay of rit milliseconds, calibrated on a CPU Clock 11 MHz. */ { unsigned int r,rit1ms; rit1ms=100; // Sperimental value for delay of 1 msec. with 80c32 do { for (r=0 ; r0); } void rit_45usec(unsigned int n) /* Performs software delay of n times 46.40 microseconds, calibrated on a clock 14.7456 MHz. */ { unsigned int r; do { for (r=0 ; r<20 ; r++) ; n--; } while(n>0); } void riti2c(void) /* Delay for I2CBUS synchronous communication. */ { #asm nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop #endasm } void starti2c(void) /* Start sequence for I2C BUS */ { SCL = 0; // Start sequence SDA = 1; riti2c(); SCL = 1; SDA = 0; riti2c(); SCL = 0; } void stopi2c(void) /* Stop sequence for I2C BUS */ { SCL = 0; // Stop sequence SDA = 0; riti2c(); SCL = 1; SDA = 1; riti2c(); SCL = 0; } void wri2c_bit(unsigned char i2cbit) /* Serializes bit D0 of i2cbit on I2C BUS */ { SCL = 0; // Set SDA and generates positive impulse on SCL SDA = i2cbit; riti2c(); SCL = 1; riti2c(); SCL = 0; } unsigned char rdi2c_bit(void) /* Deserializes a bit from I2C BUS and stores it in D0 of returned value*/ { unsigned char biti2c; SDA = 1; // Prevents conflicts on SDA acquisition SCL = 0; // Assures status of SCL riti2c(); SCL = 1; // Generates positive impulse on SCL and reads SDA biti2c = SDA; riti2c(); SCL = 0; return biti2c; } void wri2c_byte(unsigned char i2cbyte) /* Serializes byte i2cbyte to I2C BUS */ { unsigned char b; for (b = 1; b <= 8; b++) { if ((i2cbyte & 0x80) == 0) // Test and set bit b wri2c_bit(0); else wri2c_bit(1); i2cbyte = i2cbyte << 1; } } unsigned char rdi2c_byte(void) /* Deserializes byte from I2C BUS and stores it in returned value */ { unsigned char b,tmp; tmp = 0; for (b = 1; b <= 8; b++) { tmp = tmp << 1; tmp = tmp | rdi2c_bit(); // Reads and stores bit b } return tmp; } unsigned char wr_i2c(unsigned char i2csla,unsigned char i2cadd,unsigned char i2cdat) /* Writes byte i2cdat to address i2caddr of I2C BUS device with slave address in i2csla. Returns boolean flag indicating result of operation: 0=OK,1=error. */ { unsigned char i2cris; i2cris = 0; // Set OK as result starti2c(); // Start sequence wri2c_byte(i2csla); // Slave address+W i2cris = i2cris | rdi2c_bit(); // Check ACK on slave address+W wri2c_byte(i2cadd); // Address i2cris = i2cris | rdi2c_bit(); // Check ACK on address wri2c_byte(i2cdat); // Data i2cris = i2cris | rdi2c_bit(); // Check ACK on data stopi2c(); // Stop sequence return i2cris; // Result of operation } unsigned char rd_i2c(unsigned char i2csla,unsigned char i2cadd,unsigned char *i2cdat) /* Reads byte and returns it as result from address i2caddr of I2C BUS device with slave address in i2csla. Returns boolean flag indicating result of operation: 0=OK,1=error. */ { unsigned char i2cris; i2cris = 0; // Set OK as result starti2c(); // Start sequence wri2c_byte(i2csla); // Slave address+W i2cris = i2cris | rdi2c_bit(); // Check ACK on slave address+W wri2c_byte(i2cadd); // Address i2cris = i2cris | rdi2c_bit(); // Check ACK on address starti2c(); // Start sequence wri2c_byte(i2csla | 0x01); // Slave address+R i2cris = i2cris | rdi2c_bit(); // Check ACK on slave address+R *i2cdat = rdi2c_byte(); // Reads data stopi2c(); // Stop sequence return i2cris; // Result of operation } // Send to indicated slave address (as first parameter) number of bytes indicated // (as third parameter) stored from address indicated (as second parameter). // If number of bytes is 0, it does nothing. // Returns boolean flag indicating result of operation: // 0=OK,1=error. unsigned char i2c_invia(unsigned char slave, unsigned char *dati, unsigned char ndati) { unsigned char i2cris, i; if(! ndati) // If ndati is zero, exits return 0; i2cris=0; starti2c(); // Start sequence wri2c_byte(slave); // Slave address+W i2cris|=rdi2c_bit(); // Check ACK on slave address+W i=0; while(ndati--) // Send ndati bytes { wri2c_byte(dati[i++]); i2cris|=rdi2c_bit(); // Check ACK } stopi2c(); // Stop sequence return i2cris; // Return result } // Send to indicated slave address (as first parameter) number of bytes indicated // (as third parameter) stored from address indicated (as second parameter),then // expects to receive as answer indicated number of bytes (fourth parameter) and // stores them starting from address previously specified in second parameter. // Returns boolean flag indicating result of operation: // 0=OK,1=error. unsigned char i2c_ricevi(unsigned char slave, unsigned char *dati, unsigned char ndati_out, unsigned char ndati_in) { unsigned char i2cris, i; if((! ndati_in) && (! ndati_out)) // Se ndati_in e ndati_out sono zero,esce return 0; i2cris=0; // Invia i dati starti2c(); // Start sequencet wri2c_byte(slave); // Slave address+W i2cris|=rdi2c_bit(); // Check ACK on slave address+W i=0; while(ndati_out--) // Send ndati_out bytes { wri2c_byte(dati[i++]); // Send data i2cris|=rdi2c_bit(); // Check ACK } // Riceve i dati starti2c(); wri2c_byte(slave | 0x01); // Slave address+W i2cris|=rdi2c_bit(); // Check ACK on slave address+R i=0; while(ndati_in--) // Reads ndati_in bytes { dati[i++]=rdi2c_byte(); // Get data if(ndati_in) { wri2c_bit(0); // Send ACK } else { wri2c_bit(1); // Last data read, send NACK } } stopi2c(); // Stop sequence return i2cris; // Return the result } // Converts a value from 0 to 255 in two 4 bit hexadecimal figures void cifre(unsigned char v, unsigned char *c1, unsigned char *c2) { *c1=(v & 0xf0) >> 4; *c2=v & 0x0f; } /******** Converts a figure in range from 0 to F in 7 segments ******** This procedure converts a figure in range from 0 to F in 7 segments format, if value is greater than F the display is off. Parameters: Input : value in the range from 0 to F Outout : value in 7 segments format. ************************************************************************/ unsigned char digit(unsigned char n) { if(n < 16) { return cifra_7seg[n]; // reads value from table } else { return 0; // If value greater than 15 turn off display } } /************************* Visualizes a byte in HEX *********************** This procedure visualizes hexadecimal value of a byte in the two rightmost displays. E.g.: 255= FFH, 32= 20H etc. Parameters: Input: number to show in hexadecimal Output: nothing **************************************************************************/ void vis_byte(unsigned char t) { unsigned char h, l; cifre(t, &h, &l); // decomposition of value of t in 2 nibbles starti2c(); // Start sequence wri2c_byte(Wsaa1064); // Slave address rdi2c_bit(); // Check ACK on slave address+R wri2c_byte(Dig1); // First digit rdi2c_bit(); wri2c_byte(0); // Turn OFF DY1 rdi2c_bit(); wri2c_byte(0); // Turn OFF DY2 rdi2c_bit(); wri2c_byte(digit(h)); // Transforms in "7 segments" and send to DY3 rdi2c_bit(); wri2c_byte(digit(l)); // Transforms in "7 segments" and send to DY4 rdi2c_bit(); stopi2c(); // Stop sequence } /************************ Visualizes a word in HEX ************************ This procedure visualizes hexadecimal value of a word. The first two displays show (DY1 e DY2) high byte, while last two (DY3 e DY4) show low byte. E.g.s: 65535= FFFFH, 257= 101H etc. Parameters: Input: number to show in hexadecimal Output: nothing **************************************************************************/ void vis_word(unsigned int t) { unsigned char h, l; // decomposition of high byte of t in 2 nibbles cifre(t>>8, &h, &l); starti2c(); // Start sequence wri2c_byte(Wsaa1064); // Slave address rdi2c_bit(); // Check ACK on slave address+R wri2c_byte(Dig1); // First digit rdi2c_bit(); wri2c_byte(digit(h)); // Write in DY1 most significant nibble rdi2c_bit(); wri2c_byte(digit(l)); // Write in DY2 next nibble rdi2c_bit(); // decomposition of low byte of t in 2 nibbles cifre(t & 0xff, &h, &l); wri2c_byte(digit(h)); // Write in DY3 most significant nibble rdi2c_bit(); wri2c_byte(digit(l)); // Write in DY4 next nibble rdi2c_bit(); stopi2c(); // Stop sequence } // Activate buzzer for 5 interrupt cycles (about one tenth of a second) void bip(void) { buzCnt=BIP; BUZ=0; } // Activate buzzer for 25 interrupt cycles (about half of a second) void bell(void) { buzCnt=BELL; BUZ=0; } // Performs debouncing on T1 and returns its status: // 1 if pressed // 0 if not pressed unsigned char debounceT1(void) { unsigned char status; unsigned int steps; if(T1) // If T1 not pressed... { return 0; // ...return it is not pressed } else { status=1; // Indicates that it is pressed steps=20; // Check for 20 times while(status) { if(T1) // If T1 not pressed... { status=0; // ...exit loop } if(! steps--) // If steps controls made... { break; // ...exit } ritardo(5); // Delay between controls } return status; // Returns status of T1 } } // Performs debouncing on T2 and returns its status: // 1 if pressed // 0 if not pressed unsigned char debounceT2(void) { unsigned char status; unsigned int steps; if(T2) // If T2 not pressed... { return 0; // ...return it is not pressed } else { status=1; // Indicates that it is pressed steps=20; // Check for 20 times while(status) { if(T2) // If T2 not pressed... { status=0; // ...exit loop } if(! steps--) // If steps controls made... { break; // ...exit } ritardo(5); // Delay between controls } return status; // Restituisce lo stato di T2 } } // modo==0 -> Writes a command // modo!=0 -> Writes a data void wr_nibble(unsigned char d, unsigned char modo) { if(modo) // Commands or data { RS=1; } else { RS=0; } // Write data // Display is managed at nibbles, nibble to send is in the high // nibble of byte parameter d. // When a byte is sent, high nibble must be sent first. // Send bit DB7 if(d & 0x80) { db7=1; } else { db7=0; } // Send bit DB6 if(d & 0x40) { db6=1; } else { db6=0; } // Send bit DB5 if(d & 0x20) { db5=1; } else { db5=0; } // Send bit DB4 if(d & 0x10) { db4=1; } else { db4=0; } E=1; // Enable display modo=modo; // Delay E=0; // Disable display } void putc_lcd(unsigned char c) { wr_nibble(c & 0xF0, 1); // Display is managed at nibbles, wr_nibble(c << 4, 1); // first high nibble is sent, rit_45usec(1); // then low nibble } void puts_lcd(unsigned char *s) { while(*s) putc_lcd(*s++); } //************************************************************************** // For further information, please refer to electric diagram of K51-AVR //************************************************************************** // Initialization of display for two rows, characters 5x7, cursor ON void init_lcd(void) { wr_nibble(0x30, 0); ritardo(5); // Delay 5 msec wr_nibble(0x30, 0); // Repeats the same command for 3 times with different delays rit_45usec(3); // Delay 100 usec wr_nibble(0x30, 0); rit_45usec(1); wr_nibble(0x20, 0); rit_45usec(1); wr_nibble(0x20, 0); wr_nibble(0x80, 0); rit_45usec(1); wr_nibble(0x00, 0); wr_nibble(0xd0, 0); rit_45usec(1); wr_nibble(0x00, 0); wr_nibble(0x60, 0); rit_45usec(1); wr_nibble(0x00, 0); wr_nibble(0x10, 0); ritardo(3); wr_nibble(0x80, 0); wr_nibble(0x00, 0); rit_45usec(1); } // Coordinates range from x=0 and y=0 (top left corner) // from x=1 and y=19 (bottom right corner) void locate_lcd(unsigned char x, unsigned char y) { unsigned char p; p=(x ? 0xc0 : 0x80) + y; p|=0x80; // Set cursor position command wr_nibble(p & 0xf0, 0); wr_nibble(p << 4, 0); rit_45usec(1); } void set_cursor_lcd(unsigned char status) { status|=0xE0; // Display and cursor ON wr_nibble(0x00, 0); wr_nibble(status, 0); rit_45usec(1); } // Procedure that overwrites the character pattern with the one // specified by the user. void set_usr_chr(unsigned char ch, unsigned char *pattern) { unsigned char i; wr_nibble(0x00, 0); // Display on, cursor off, blink off wr_nibble(0xc0, 0); i=0x40 | (ch<<3); // Determinates command Set CG RAM address for wr_nibble(i & 0xF0, 0); // user character and wr_nibble(i << 4, 0); // send it to display for(i=0; i<8; i++) // Send pattern: high nibble first { wr_nibble(pattern[i] & 0xF0, 1); wr_nibble(pattern[i] << 4, 1); } wr_nibble(0x00, 0); // Display on, cursor off, blink on wr_nibble(0xd0, 0); wr_nibble(0x00, 0); // Cursor home wr_nibble(0x20, 0); ritardo(1); } // Shift display n columns to the right void shift_display_right(unsigned char n) { while(n--) { wr_nibble(0x10, 0); wr_nibble(0xC0, 0); } } // Shift display n columns to the left void shift_display_left(unsigned char n) { while(n--) { wr_nibble(0x10, 0); wr_nibble(0x80, 0); } } // Internal cursor position management void aggiustaXY(void) { if(colonna==20) // If beyond last column { colonna=0; // Go back to first column riga++; // Of next line if(riga==2) // If beyond last row { riga=0; // Go back to first row } } locate_lcd(riga, colonna); // Put cursor at specified coordinates } // Command interpreter display LCD void elaboraLCD(unsigned char c) { unsigned char val[4]; // Used by some commands if(c==Prefix) // If command prefix { if(! comando) // And no command is executed { comando=0x80; // Enter commmand mode } } else { switch(comando) { case 0: // No command is executed // IMMEDIATE EXECUTION COMMANDS switch(c) // Immediat commands, AKA // control characters { case 0x07: // Character BEL bell(); // Activated buzzer break; case 0x0A: // Character LF line feed riga++; // Go to next line if(riga==2) // Or go back to the first line { riga = 0; } locate_lcd(riga, colonna); // Place the cursor break; default: // Printable characters putc_lcd(c); // Write character to LCD colonna++; aggiustaXY(); // Adjust cursor position break; } break; case 0x80: // A command must be read switch(c) // Activate command recognizer { // COMMANDS WITH ZERO PARAMETERS case '1': init_lcd(); // Clear display riga = 0; // Update variables of colonna = 0; // Cursor position comando = 0; // Command completed break; // COMMANDS WITH PARAMETRERS case '2': // Command with one parameter comando = 1; // Indicate number of parameters codice = c; // Store command code break; case '3': // Command with two parameter comando = 2; // Indicate number of parameters codice = c; // Store command code break; default: // Command not recognized comando = 0; // Exit command mode codice = 0; break; } break; // Acqures parameters of a command, number of parameter currently acquired // is value of variable comando itself // GATHER PARAMETERS default: par[--comando] = c; // Store parameter,update number of parameters // EXECUTION OF COMMANDS WITH PARAMETERS if(! comando) // All parameters gathered { switch(codice) // Execute command { case '2': // Command with one parameter if(par[0] == 'b') // If parameter is character "b" { set_cursor_lcd(BLINK); // Cursor must blink } else // Otherwise { if(par[0] == 'n') // If parameter is character "n" { set_cursor_lcd(STEADY); // Cursor must not blink } } break; case '3': // Command with two parameter // parameters are stored in reverse orders if(par[1]=='1') // If first parameter is character "1" { putc_lcd(par[0]); // Print second parameter colonna++; } else // Otherwise { sprintf(val, "%X", par[0]); // Write hexadecimal value putc_lcd(val[0]); colonna++; aggiustaXY(); putc_lcd(val[1]); colonna++; } aggiustaXY(); // Adjust cursor coordinates break; } //End switch(codice) codice=0; } //End if(!comando) } //End switch(comando) } //End if(prefix) } // Response to interrupt of Timer 0. // Makes timimg of buzzer, updates buffer of serial port and of K51 keys // if there are characters to store. void scan(void) interrupt { TR0=0; // Stop Timer 0 TH0=LoadtimerH; TL0=LoadtimerL; TR0=1; // Restart Timer 0 if(buzCnt) { buzCnt--; } else { BUZ=1; // Deactivate buzzer } /* Read from serial port. Character is stored in array bufferSER, managed as a loop buffer, that is when it is filled next character overwrites first position. */ if(kbhit()) // If one character is present { bufferSER[idxSER++] = getc(); // Read it, store it and increment index if(idxSER==Maxchar) // If index beyond its maximum { idxSER = 0; // Bring it back to the beginning } } // Acquisittion of K51 keys. IF corresponding pin of micro is 0, // key is pressed debCod = 0; // If key 1 is pressed if(! T1) // store its code { debCod = '1'; } if(! T2) // If key 2 is pressed, store its code { debCod = '2'; } // Keys 3 and 4 are not acquired. See notes on top of source. /* if(! T3) // If key 3 is pressed, store its code { debCod = '3'; } if(! T4) // If key 4 is pressed, store its code { debCod = '4'; } */ /* Debouncing. Key eventually read becomes the new debounced key, unless it was already debounced, in this case debouncing counter is incremented. When counter reaches its limit, key is considere acquired and put into K51 buffer. */ if(debCod) // If a key is pressed { if(debCod==debChar) // and key is debounced { debCnt++; // increment counter } else { // Otherwise debChar = debCod; // New key debounced debCnt = 0; // Reset counter } } if(debCnt==Debiter) // If counter exceeds { debCnt = 0; // Reset counter bufferK51[idxK51++] = debChar; // Store key code and increment index if(idxK51==Maxtasti) // If index exceeds { idxK51 = 0; // Bring it back to starting value } buzCnt=BIP; // Make a bip BUZ=0; } } IRQ_VECTOR(scan, TIMER0); // Set input device void setIndev(unsigned char d) { indev=d; } // Set output device void setOutdev(unsigned char d) { outdev=d; } // Read from input device (non blocking) unsigned char conIn(void) { unsigned char in; in=0; // No character read switch(indev) { // Read from serial line case SER: if(idxCarSER!=idxSER) // If a character is present { in=bufferSER[idxCarSER]; // Read from buffer if(++idxCarSER==Maxchar) // If end of buffer { idxCarSER=0; // Back to buffer beginning } } break; // Read from keyboard of K51 case K51: if(idxCarK51!=idxK51) // If a key is pressed { in=bufferK51[idxCarK51]; // Read it from buffer if(++idxCarK51==Maxtasti) // If end of buffer { idxCarK51=0; // Back to buffer beginning } } break; } // End switch(indev) return in; } // Writes to output device void conOut(unsigned char out) { switch(outdev) { case SER: putc(out); // Send to serial line break; case K51: elaboraLCD(out); // Interprete a LCD command break; } // End switch(outdev) } // Detects bytes still to read in device buffer unsigned char conStatus(void) { unsigned char r; switch(indev) { case SER: if(idxCarSER==idxSER) // If indexes are equal { r=0; // Return no character present } else { r=1; // Viceversa } break; case K51: if(idxCarK51==idxK51) // If indexes are equal { r=0; // Return no character present } else { r=1; // Viceversa } break; } // End switch(indev) return r; // Rertun response } void demo_init(void) { unsigned char i; // Initializtion of global variables comando = 0; // Cancel evantual new commands codice = 0; // riga=0; // Cursore home colonna=0; idxSER = 0; // Starting values of idxCarSER = 0; // buffer indexes idxK51 = 0; idxCarK51 = 0; debCod = 0; // Reset key code and counters debChar = 0; // of debouncing debCnt = 0; buzCnt = 0; // Wait SAA1064 to turn on do { starti2c(); wri2c_byte(Rsaa1064); rdi2c_bit(); i = rdi2c_byte(); wri2c_byte(1); // Not Acknowledge stopi2c(); } while(i); // Send SAA1064 initialization sequence i2c_invia(Wsaa1064, saa1064_init, saa1064_init_length); TMOD=(TMOD & 0xF1) | 0x01; // Timer0 = timer, gate internal, mode 1 TR0=0; // Stop Timer 0 TH0=LoadtimerH; TL0=LoadtimerL; TR0=1; // Start Timer 0 ET0=1; // Enable Timer 0 interrupt } void main(void) { ritardo(2); iniser(19200); TI=0; RI=0; // Comment next lines if using serial line in polling (SIOTYPE=p or k) ES=1; // Enable interrupt serial port EA=1; // Enable all interrupts clrscr(); demo_init(); // Peripherals initialization init_lcd(); // Clear display locate_lcd(0, 0); set_usr_chr(0, pattern_r); // Mathces to character 0 pattern of (r) bip(); while(1) { setIndev(SER); // Select serial line for input setOutdev(K51); // Select display of K51 for output if(conStatus()) // If one character is present... { conOut(conIn()); //...get it and send it to display } setIndev(K51); // Select keys of K51 for input setOutdev(SER); // Select serial line for output if(conStatus()) // If a key is pressed... { conOut(conIn()); //...acquire it and send it to serial line } } // Loop forever }