/* ********************************************************************** ** Program: lcd51e.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 allows to manage an alphanumeric LCD featuring a number rows and columns definible by the User. The display must be connected to CN5 following the connections shown in the diagram of K51-AVR page 4 of 4. 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 #define FALSE 0x00 // Boolean values #define TRUE 0xFF #define LF 0x0A #define CRET 0x0D /***************** 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) /********* 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 } void demo_init(void) { unsigned char i; // 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); } // 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 specified time, in milliseconds void buzzer(unsigned int t) { BUZ=0; ritardo(t); BUZ=1; } // 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=1 and y=1 (top left corner) // from x=2 and y=20 (bottom right corner) void locate_lcd(unsigned char x, unsigned char y) { unsigned char p; p=(x==1 ? 0x80 : 0xc0) + y - 1; p|=0x80; // Position setting command wr_nibble(p & 0xf0, 0); wr_nibble(p << 4, 0); rit_45usec(1); } void set_cursor(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); } } void main(void) { unsigned char i; 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(); // Clears display set_usr_chr(0, pattern_r); // Mathces to character 0 pattern of (r) puts_lcd("Grifo"); // Prints a string putc_lcd(0); // Prints user character (r) puts_lcd(" www.grifo.com"); locate_lcd(2, 3); // Puts cursor in row 2 column 3 puts_lcd("Tel.+39051892052"); ritardo(1000); // Delay one second for(i=0; i<10; i++) // Shift ten times display to the right { shift_display_right(1); // Shift one character to the right ritardo(250); } for(i=0; i<10; i++) // Shift ten times display to the left { shift_display_left(1); // Shift one character to the left ritardo(250); } while(1) // Loop forever { } }