• LCD layout and connections
• LCD test program
• BCD count program
The plain 3.5-digit parallel liquid crystal display (LCD) is driven directly from the MCU, occupying 15 of the I/O pins. The usual alternative to this arrangement is to use a serial LCD, which can be driven via the RS232 port. This occupies only one or two pins, but it is more expensive, as it contains its own microcontroller.
The parallel LCD is operated by specific combinations of inputs that enable the segments as required (Figure 4.7). The segments are designated A to G for each seven-segment digit, with digits numbered 1 to 4 from the right. The most significant half digit (4) has only segments B and C, displaying only ‘1’. Four common connections (COM1–COM4) enable groups of segments such that each has a unique address.
Note that this is a standard DMM display, so additional symbols are available that are not needed in the mechatronics board applications. The data for the display segments are stored in dedicated set of 12 registers in the PIC 16F917 (Table 4.5
Address | COM0+ | Address | COM1+ |
---|---|---|---|
00+ | -- 06 -- -- 03 -- -- -- | 24+ | -- 06 -- -- 03 -- -- -- |
LCDDATA0 | xx 2 A xx xx 3 A xx xx xx | LCDDATA3 | xx 2F xx xx 3F xx xx xx |
08+ | -- -- -- -- 11 -- -- -- | 32+ | -- -- -- -- 11 -- -- -- |
LCDDATA1 | xx xx xx xx 3B xx xx xx | LCDDATA4 | xx xx xx xx 3G xx xx xx |
016+ | 23 22 21 -- -- -- -- -- | 40+ | 23 22 21 -- -- -- -- -- |
LCDDATA2 | 1B 1 A 2B XX XX XX XX XX | LCDDATA5 | 1G 1F 2G xx xx xx xx xx |
Address | COM2+ | Address | COM3+ |
---|---|---|---|
48+ | -- 06 -- -- 03 02 -- -- | 72+ | -- 06 -- -- 03 02 -- -- |
LCDDATA6 | xx 2E xx xx 3E 4x xx xx | LCDDATA9 | xx 2D xx xx 3D P3 xx xx |
56+ | -- -- -- -- 11 -- -- -- | 80+ | -- -- -- -- 11 -- -- -- |
LCDDATA7 | xx xx xx xx 3C xx xx xx | LCDDATA10 | xx xx xx xx P2 xx xx xx |
64+ | 23 22 21 -- -- -- -- -- | 88+ | -- 22 21 -- -- -- -- -- |
LCDDATA8 | 1C 1E 2C xx xx xx xx xx | LCDDATA11 | xx 1D P1 xx xx xx xx xx |
The LCD has a total of 26 numerical segments, comprising three seven-segment digits, two segments for the MSD, and three decimal points. The MSD bits are controlled by the same bit, as they always come on together, giving only 25 bits actually required. Therefore, only some bits in the registers are used, but the spare capacity allows more complex displays to be operated by the ‘917 in other applications. We see that the bits that are used are not arranged very logically, so they will be mapped by the LCD display function to simplify the output process.
The bits in the first three registers (LCDDATA0–LCDDATA2) are associated with COM0 output, the next three with COM1, and so on to COM3 (see Table 4.5). Unfortunately, the common inputs on the LCD are identified as COM1–COM4, so COM1 is controlled from the MCU output COM0, and so on, with COM4 being connected to COM3 MCU output pin.
The 16F917 MCU can provide up to 24 segment drive outputs (SEG0–SEG23), with four common connections (COM0–COM3). These are used in defined combinations to control up to 24×4=96 segments or pixels in the display. In this way, 1 bit in the LCDDATAx registers controls one element of the display. This display needs only 25 bits and ten of the available segment outputs (SEG0, 1, 2, 3, 6, 11, 16, 21, 22, and 23). These outputs are encoded to allow individual bit control within the program.
Listing 4.3 shows a test program, LCD1, which displays the numerals 0 to 9 on each digit in turn, then flashes on the MSD and three decimal points, so that correct operation of each can be checked.
Listing 4.3. Test Program for Mechatronics Board LCD
//LCD1.C MPB 20-4-07
//Test program for mechatronics board LCD
//Displays count 0 to 9 on Digits1,2,3 and 1 on Digit4
#include “16F917.h”
#use delay(clock=8000000)
//LCD DISPLAY DATA: (3 numerals * 7 segments)+MSD * 1 segment+3 decimal points
//Bit map for numerals 0–9 and blank..................................
//Numeral: 0 1 2 3 4 5 6 7 8 9 blank
byte const DigMap[11]={0xFD,0×60,0xDB,0xF3,0×66,0xB7,0xBF,0xE0,0xFF,0xE7,0×00};
//Bit addressess in LCD RAM locations LCDDATA0 to LCDDATA11=12*8 bits
//Numbered 0-95 with offsets COM0=0, COM1=24, COM2=48, COM3=72
//Segment: A B C D E F G
#define DIG1 COM0+22,COM0+23,COM2+23,COM3+22,COM2+22,COM1+22,COM1+23
//Bit addresses
♯define DIG2 COM0+6, COM0+21,COM2+21,COM3+6, COM2+6, COM1+6, COM1+21
//Bit addresses
♯define DIG3 COM0+3, COM0+11,COM2+11,COM3+3, COM2+3, COM1+3, COM1+11
//Bit addresses
#define DIG4 COM2+2 //Both bits
#define DP1 COM3+21 //Decimal point 1
#define DP2 COM3+11 //Decimal point 2
#define DP3 COM3+2 //Decimal point 3
void main()
{
int8 n;
setup_lcd(LCD_MUX14,0); //Initialize 14-pin LCD, no clock divide
for(n=0;n<11;n++) //Display numerals 0–9 at digit 1
{lcd_symbol(DigMap[n],DIG1); //Send digit bits to segment addresses
delay_ms(300);
}
for(n=0;n<11;n++) //Display numerals 0–9 at digit 2
{lcd_symbol(DigMap[n],DIG2); //Send digit bits to segment addresses
delay_ms(300);
}
for(n=0;n<11;n++) //Display numerals 0–9 at digit 3
{lcd_symbol(DigMap[n],DIG3); //Send digit bits to segment addresses
delay_ms(300);
}
lcd_symbol(0X80,DIG4); //Switch on MSD digit 4
delay_ms(1000);
lcd_symbol(00X00,DIG4); //Switch off MSD digit 4
lcd_symbol(0XFF,DP1); //Switch on decimal point 1
delay_ms(500);
lcd_symbol(0X00,DP1); //Switch off decimal point 1
lcd_symbol(0XFF,DP2); //Switch on decimal point 2
delay_ms(500);
lcd_symbol(0X00,DP2); //Switch off decimal point 2
lcd_symbol(0XFF,DP3); //Switch on decimal point 3
delay_ms(500);
lcd_symbol(0X00,DP3); //Switch off decimal point 3
while(1){}; //Done
}
Each group of segments associated with each common connection on the LCD is operated in turn by the program. The LCD functions used are setup_lcd()and lcd_symbol(). The arguments of the setup function specify a 14-pin display module and 0 clock divide factor. The clock rate controls the display multiplexing rate, which can be modified for best visibility.
The arguments of the output function comprise an 8-bit map for the numeral to be displayed as a hex number (Table 4.6
Numeral | Segment | A | B | C | D | E | F | G | LSB | Code |
---|---|---|---|---|---|---|---|---|---|---|
Bit | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | ||
0 | 1 | 1 | 1 | 1 | 1 | 1 | 0 | 1 | 0xFD | |
1 | 0 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0x6 0 | |
2 | 1 | 1 | 0 | 1 | 1 | 0 | 1 | 0 | 0xDB | |
3 | 1 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 0xF3 | |
4 | 0 | 1 | 1 | 0 | 0 | 1 | 1 | 0 | 0x6 6 | |
5 | 1 | 0 | 1 | 0 | 0 | 1 | 1 | 1 | 0xB7 | |
6 | 1 | 0 | 1 | 0 | 1 | 1 | 1 | 1 | 0xBF | |
7 | 1 | 1 | 1 | 0 | 0 | 0 | 0 | 0 | 0xE0 | |
8 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0xFF | |
9 | 1 | 1 | 1 | 0 | 0 | 1 | 1 | 1 | 0xE7 | |
— | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | Blank |
The mapping data for each segment is provided to the output function in the form of a list of segment bit addresses, 0–95. To include information about which COM line is active for each bit, the address is supplied as the sum of the start address of each COM block and the bit number within that block. Therefore, the bit address of segment A of digit 1 (DIG1) is COM0+22. COM0 has the value 0, COM1=24, COM2=48, and COM3=72. Therefore, COM0+22=22. By the same process, the single-bit address controlling the MSD (DIG4) is COM2+2=50, and the first decimal point (DP1) is addressed at COM3+21=93.
For convenience, the lists of segment bit addresses for each digit are defined at the top of the program, using the replacement text labels DIG1, DIG2, DIG3, and DIG4plus the three decimal point addresses. The lcd_symbol() function is then supplied with the constant array element number for the numeral to be displayed and the bit address list as DIGx. A ‘for’ loop outputs each numeral at each position in turn, including the blank digit, while the MSD and decimal points are switched on and off individually.
Listing 4.4 shows a program that displays a decimal count on the LCD. The count is generated as binary coded decimal (BCDx) digits. Each digit is initialized to 0, then incremented until it reaches 10, when it is cleared back to 0 and the next most significant digit incremented. The three digits are then displayed together. The MSD (DIG4) is not used. The LCD data block is now concealed in a separate source code file lcd.inc, which is included at the top of the program.
Listing 4.4. LCD Counting Program
/////////////////////////////////////////////////////////////////////
//LCD2.C MPB 20-4-07
//LCD program to count up when SW2 on
//Hardware: Connect SW2 to RA4
/////////////////////////////////////////////////////////////////////
#include “16F917.h”
#include “lcd.inc” //Include file with LCD data
#use delay(clock=8000000)
void main() //////////////////////////////////////////////////
{
int8 BCD1=0, BCD2=0, BCD3=0; //BCD count digits
setup_lcd(LCD_MUX14,0); //Initialize 14-pin LCD
while(1)
{ //GENERATE DECIMAL COUNT
if(!input(PIN_A4)) //Test Switch 2
{
delay_ms(10); //Debounce and slow
BCD1++; //Increment ones
if(BCD1==10) //..up to 9
{
BCD1=0; //Reset ones
BCD2++; //Increment tens
if(BCD2==10) //..up to 90
{
BCD2=0; //Reset tens
BCD3++; //Increment hundreds
if(BCD3==10) //..up to 900
BCD3=0; //All reset to zero
}
}
}
//DISPLAY BCD DIGITS
lcd_symbol(DigMap[BCD1],DIG1); //Display Digit 1
lcd_symbol(DigMap[BCD2],DIG2); //Display Digit 2
lcd_symbol(DigMap[BCD3],DIG3); //Display Digit 3
} //Loop always
}/////////////////////////////////////////////////////////END
18.117.167.230