Using the Segment LCD Controller on the Kinetis KL46

Created by Ethan Hettwer, last modified by Ben Roloff on May 13, 2016

Introduction

Multiplexed segment LCD operation isn’t necessarily straightforward or easy, even with a peripheral to help with it. The purpose of this page is to help guide you through the configuration of the Segment LCD controller on the Kinetis KL46. While the example is done using the LCD on the FRDM-KL46z board, this setup can be used as a reference to help configure the controller for other LCDs as well.

In the LCD controller each element consists of a front plane segment and a back plane phase. These 8 phases are labeled A through H. Each bit controls whether the pin is “active” on a particular phase. Each LCD_Pn Signal can be connected to multiple segments (in front plane operation) or one or more phases (in back plane operation). On the FRDM-KL46z, each front plane pin will be connected to 4 segments, while the back plane pin will be active during 2 of 8 phases. An LCD element is turned on when the associated back plane phase is active along with the front plane segment.

For reference I will be using certain fonts or styles to denote specific things, shown in the following table

Style Meaning Example
Bold Exact wording or button Click on Next to continue
Italics Filename, Path, or Variable Now open My_File.c
Monospace Register names Set the 9th bit in SIM_SCGC5

Helpful Links

Reference Information

Kinetis KL46 Reference Manual KL46P121M48SF4RM (3).pdf (10.6 MB) The section for the SLCD begins on page 863.

Lumex S401M16KR Datasheet LCD-S401M16KR-81359.pdf (54.2 KB) This is the display on the FRDM-KL46z.

Example Code

Seg_LCD.h (2.0 KB)

Seg_LCD.c (17.2 KB)

Getting Started

For basic information on registry manipulation on the KL46, please see the eewiki article here.

For this example I will be creating a new project, though it can be entirely incorporated into an existing one.

As I prefer to keep my code as modular as possible, I will be creating a c file for functions and a header file to be included in the main c file. These will be refered to as SegLCD.c and SegLCD.h for the rest of the page.

I will be using the System_MKL46Z4.c and MKL46Z4.h files included with KEIL uVision4.74.0.0. These will need to be included for the code to function properly, and information on how to select these can be found in the eewiki article listed above.

Initializing the LCD

LCD Pins on the FRDM-KL46z connect to the LUMEX LCD-S401M16KR in the following manner (from FRDM-KL46Z User Guide)

s401 Pin KL46 LCD Pin Pin Name
1 LCD_P40 (COM 0) PTD0
2 LCD_P52 (COM 1) PTE4
3 LCD_P19 (COM 2) PTB23
4 LCD_P18 (COM 3) PTB22
5 LCD_P37 PTC17
6 LCD_P17 PTB21
7 LCD_P7 PTB7
8 LCD_P8 PTB8
9 LCD_P53 PTE5
10 LCD_P38 PTC18
11 LCD_P10 PTB10
12 LCD_P11 PTB11

As such, we don’t need to enable PORTA, but all other ports are needed.

Below is my example code for initializing the LCD. It is included in SegLCD.c, or can simply be copy pasted into your code. I highly suggest reading it and at least getting a basic understanding of what the registers do so you know what options are available to you. More information on these registers can be found in the KL46 reference manual in the “helpful links” section.

SegLCD_Init

void SegLCD_Init(void){ //Initializes all components of SLCD on the FRDM-KL46Z
  
 SIM->SCGC5 |= SIM_SCGC5_PORTB_MASK | SIM_SCGC5_PORTC_MASK | SIM_SCGC5_PORTD_MASK | SIM_SCGC5_PORTE_MASK | SIM_SCGC5_SLCD_MASK; //Enable Clock to ports B, C, D and E, and SegLCD Peripheral
 LCD->GCR |= LCD_GCR_PADSAFE_MASK; //Set PADSAFE to disable LCD while configuring
 LCD->GCR &= ~LCD_GCR_LCDEN_MASK;  //Clear LCDEN (LCD Enable) while configuring
  
 //Configure pins *From Reference manual, set pins to MUX 0 for normal LCD display operation, only use MUX 7 if using LCD fault detection
 PORTB->PCR[7]  = PORT_PCR_MUX(0u);     //Set PTB7 to LCD_P7
 PORTB->PCR[8]  = PORT_PCR_MUX(0u);     //Set PTB8 to LCD_P8
 PORTB->PCR[10] = PORT_PCR_MUX(0u);     //Set PTB10 to LCD_P10
 PORTB->PCR[11] = PORT_PCR_MUX(0u);     //Set PTB11 to LCD_P11
 PORTB->PCR[21] = PORT_PCR_MUX(0u);     //Set PTB21 to LCD_P17
 PORTB->PCR[22] = PORT_PCR_MUX(0u);     //Set PTB22 to LCD_P18
 PORTB->PCR[23] = PORT_PCR_MUX(0u);     //Set PTB23 to LCD_P19
 PORTC->PCR[17] = PORT_PCR_MUX(0u);     //Set PTC17 to LCD_P37
 PORTC->PCR[18] = PORT_PCR_MUX(0u);     //Set PTC18 to LCD_P38
 PORTD->PCR[0]  = PORT_PCR_MUX(0u);     //Set PTD0 to LCD_P40
 PORTE->PCR[4]  = PORT_PCR_MUX(0u);     //Set PTE4 to LCD_P52
 PORTE->PCR[5]  = PORT_PCR_MUX(0u);     //Set PTE5 to LCD_P53
  
 //Configure LCD Registers
 //Configure LCD_GCR - General Control Register, controls most options in LCD Peripheral
 LCD->GCR =//LCD_GCR_RVEN_MASK |       //Clear LCD_GCR_RVEN, disable voltage regulator.
       LCD_GCR_RVTRIM(0x00) |      //Set RVTRIM to 0, irrelevant as voltage regulator is disabled, but setting it to a known state.
       LCD_GCR_CPSEL_MASK |      //Set LCD_GCR_CPSEL to use capacitor charge pump.
       LCD_GCR_LADJ(0x03) |      //Set LCD_GCR_LADJ to 11, slow clock rate = lower power, but higher load capacitance on the LCD requires higher clock speed.
      //LCD_GCR_VSUPPLY |        //Clear LCD_GCR_VSUPPLY, drive VLL3 externally.
       LCD_GCR_PADSAFE_MASK |     //Set LCD_GCR_PADSAFE, leave enabled during configuration process.
      //LCD_GCR_FDCIEN_MASK |      //Clear LCD_GCR_FDCIEN, No interrupt from fault dection.
       LCD_GCR_ALTDIV(0x00) |     //Set LCD_GCR_ALTDIV to 11, divide alternate clock by 512.  This is assuming an 8MHz External Crystal is used.
      //LCD_GCR_ALTSOURCE_MASK |    //Set LCD_GCR_ALTSOURCE, Part of setting clock source to OSCERCLK, or external oscillator.
       LCD_GCR_FFR_MASK |       //Set LCD_GCR_FFR, allow an LCD Frame Frequency of 46.6Hz to 146.2Hz.  Disable to change range to 23.3Hz to 73.1Hz.
      //LCD_GCR_LCDDOZE_MASK |     //Clear LCD_GCR_LCDDOZE, allows LCD peripheral to run even in doze mode.  Set to disable LCD in doze mode.
      //LCD_GCR_LCDSTP_MASK |      //Clear LCD_GCR_LCDSTP, allows LCD peripheral to run even in stop mode.  Set to disable LCD in stop mode.
      //LCD_GCR_LCDEN_MASK |      //Clear LCD_GCR_LCDEN, Disables all front and backplane pins.  Leave disabled during configuration process.
       LCD_GCR_SOURCE_MASK |      //Set LCD_GCR_SOURCE, Part of setting clock source to OSCERCLK, or external oscillator.
       LCD_GCR_LCLK(0x04) |       //Set LCD_GCR_LCLK to 111, LCD Clock prescaler where LCD controller frame frequency = LCD clock/((DUTY  |  1) x 8 x (4 | LCLK[2:0]) x Y), where Y = 2, 2, 3, 3, 4, 5, 8, 16 chosen by module duty cycle config
       LCD_GCR_DUTY(0x03);        //Set LCD_GCR_DUTY to 011, Have 4 backplane pins, so need a 1/4 duty cycle.
  
 //Configure LCD_SEG_AR  - Auxiliary Register, controls blinking of LCD
 LCD->AR = //LCD_AR_BLINK_MASK |       //Clear LCD_SEG_AR_BLINK, Disable SLCD blinking.  Enable to make LCD Blink.
      //LCD_AR_ALT_MASK |        //Clear LCD_SEG_AR_ALT, if enabled LCD back plane sequencer changes to an alternate display.  Only functional if DUTY[2:0] is less than 100(binary).  This allows a blink screen that is not blank.
      //LCD_AR_BLANK_MASK |       //Clear LCD_SEG_AR_BLANK, asserting bit clears all segments in LCD.
      //LCD_AR_BMODE_MASK |       //Clear LCD_SEG_AR_BMODE, if enabled displays alternate display during blink period instead of blank.
      LCD_AR_BRATE(0x00);        //Set LCD_SEG_AR_BRATE to 000.  Frequency of blink is determined by LCD clock/(2^(12 + BRATE))
       
 //Configure LCD_SEG_FDCR - Fault Detect Control Register, controls use of Fault Detect features of SLCD.
 LCD->FDCR = 0x00000000;           //Clear all bits in FDCR.  As this will not be covering use of fault detect, this register is cleared.
  
 //Configure LCD_PENn - Pin Enable Register, controls which of the possible LCD pins are used
 //LCD->PEN[0] contains bits 0-31, while LCD->PEN[1] contains bits 32-63.  For pins >= 32, set in LCD->PEN[1] as LCD_PEN_PEN(Pin#-32)
 LCD->PEN[0] =  LCD_PEN_PEN(1u<<7u) |    //LCD_P7
         LCD_PEN_PEN(1u<<8u) |    //LCD_P8
         LCD_PEN_PEN(1u<<10u)|    //LCD_P10
         LCD_PEN_PEN(1u<<11u)|    //LCD_P11
         LCD_PEN_PEN(1u<<17u)|    //LCD_P17
         LCD_PEN_PEN(1u<<18u)|    //LCD_P18
         LCD_PEN_PEN(1u<<19u);    //LCD_P19
 LCD->PEN[1] =  LCD_PEN_PEN(1u<<5u) |    //LCD_P37
         LCD_PEN_PEN(1u<<6u) |    //LCD_P38
         LCD_PEN_PEN(1u<<8u) |    //LCD_P40
         LCD_PEN_PEN(1u<<20u)|    //LCD_P52
         LCD_PEN_PEN(1u<<21u);    //LCD_P53
  
 //Configure LCD_SEG_BPENn - Back Plane Enable Register, controls which pins in LCD->PEN are Back Plane (commons)
 //LCD->BPEN[0] contains bits 0-31, while LCD->BPEN[1] contains bits 32-63.  For pins >= 32, set in LCD->BPEN[1] as LCD_BPEN_BPEN(Pin#-32)
 LCD->BPEN[0] = LCD_BPEN_BPEN(1u<<18u)|   //LCD_P18  COM3
         LCD_BPEN_BPEN(1u<<19u);   //LCD_P19, COM2
 LCD->BPEN[1] = LCD_BPEN_BPEN(1u<<8u) |   //LCD_P40, COM0
         LCD_BPEN_BPEN(1u<<20u);   //LCD_P52, COM1
  
 //Configure LCD_WFyTOx - Configures 4 Waveform signals, LCD_WF[z] is defined such that x = (z*4) and y = 3 | (z*4)
 //Where x is the n index value of WFn on the least significant byte (bits 7-0) and y is the n index value of WFn on the most significant byte (bits 31-24)
 //Note that "Disabled" is used for pins that are not set as LCD pins, where "Off" is used for pins that are set as LCD, but are just inactive.
 LCD->WF[0]  = LCD_WF_WF0(0x00) |      //WF Pin 0 Disabled
         LCD_WF_WF1(0x00) |      //WF Pin 1 Disabled
         LCD_WF_WF2(0x00) |      //WF Pin 2 Disabled
         LCD_WF_WF3(0x00) ;      //WF Pin 3 Disabled
 LCD->WF[1]  = LCD_WF_WF4(0x00) |      //WF Pin 4 Disabled
         LCD_WF_WF5(0x00) |      //WF Pin 5 Disabled
         LCD_WF_WF6(0x00) |      //WF Pin 6 Disabled
         LCD_WF_WF7(0x00) ;      //WF Pin 7 Off
 LCD->WF[2]  = LCD_WF_WF8(0x00) |      //WF Pin 8 Off
         LCD_WF_WF9(0x00) |      //WF Pin 9 Disabled
         LCD_WF_WF10(0x00)|      //WF Pin 10 Off
         LCD_WF_WF11(0x00);      //WF Pin 11 Off
 LCD->WF[3]  = LCD_WF_WF12(0x00)|      //WF Pin 12 Disabled
         LCD_WF_WF13(0x00)|      //WF Pin 13 Disabled
         LCD_WF_WF14(0x00)|      //WF Pin 14 Disabled
         LCD_WF_WF15(0x00);      //WF Pin 15 Disabled
 LCD->WF[4]  = LCD_WF_WF16(0x00)|      //WF Pin 16 Disabled
         LCD_WF_WF17(0x00)|      //WF Pin 17 Off
         LCD_WF_WF18(0x88)|      //WF Pin 18 (COM3) is enabled on Phases D and H
         LCD_WF_WF19(0x44);      //WF Pin 19 (COM2) is enabled on Phases C and G
 LCD->WF[5]  = LCD_WF_WF20(0x00)|      //WF Pin 20 Disabled
         LCD_WF_WF21(0x00)|      //WF Pin 21 Disabled
         LCD_WF_WF22(0x00)|      //WF Pin 22 Disabled
         LCD_WF_WF23(0x00);      //WF Pin 23 Disabled
 LCD->WF[6]  = LCD_WF_WF24(0x00)|      //WF Pin 24 Disabled
         LCD_WF_WF25(0x00)|      //WF Pin 25 Disabled
         LCD_WF_WF26(0x00)|      //WF Pin 26 Disabled
         LCD_WF_WF27(0x00);      //WF Pin 27 Disabled
 LCD->WF[7]  = LCD_WF_WF28(0x00)|      //WF Pin 28 Disabled
         LCD_WF_WF29(0x00)|      //WF Pin 29 Disabled
         LCD_WF_WF30(0x00)|      //WF Pin 30 Disabled
         LCD_WF_WF31(0x00);      //WF Pin 31 Disabled
 LCD->WF[8]  = LCD_WF_WF32(0x00)|      //WF Pin 32 Disabled
         LCD_WF_WF33(0x00)|      //WF Pin 33 Disabled
         LCD_WF_WF34(0x00)|      //WF Pin 34 Disabled
         LCD_WF_WF35(0x00);      //WF Pin 35 Disabled
 LCD->WF[9]  = LCD_WF_WF36(0x00)|      //WF Pin 36 Disabled
         LCD_WF_WF37(0x00)|      //WF Pin 37 Off
         LCD_WF_WF38(0x00)|      //WF Pin 38 Off
         LCD_WF_WF39(0x00);      //WF Pin 39 Disabled
 LCD->WF[10] = LCD_WF_WF40(0x11)|      //WF Pin 40 (COM0) is enabled on Phases A and E
         LCD_WF_WF41(0x00)|      //WF Pin 41 Disabled
         LCD_WF_WF42(0x00)|      //WF Pin 42 Disabled
         LCD_WF_WF43(0x00);      //WF Pin 43 Disabled
 LCD->WF[11] = LCD_WF_WF44(0x00)|      //WF Pin 44 Disabled
         LCD_WF_WF45(0x00)|      //WF Pin 45 Disabled
         LCD_WF_WF46(0x00)|      //WF Pin 46 Disabled
         LCD_WF_WF47(0x00);      //WF Pin 47 Disabled
 LCD->WF[12] = LCD_WF_WF48(0x00)|      //WF Pin 48 Disabled
         LCD_WF_WF49(0x00)|      //WF Pin 49 Disabled
         LCD_WF_WF50(0x00)|      //WF Pin 50 Disabled
         LCD_WF_WF51(0x00);      //WF Pin 51 Disabled
 LCD->WF[13] = LCD_WF_WF52(0x22)|      //WF Pin 52 (COM1) is enabled on Phases B and F
         LCD_WF_WF53(0x00)|      //WF Pin 53 Off
         LCD_WF_WF54(0x00)|      //WF Pin 54 Disabled
         LCD_WF_WF55(0x00);      //WF Pin 55 Disabled
 LCD->WF[14] = LCD_WF_WF56(0x00)|      //WF Pin 56 Disabled
         LCD_WF_WF57(0x00)|      //WF Pin 57 Disabled
         LCD_WF_WF58(0x00)|      //WF Pin 58 Disabled
         LCD_WF_WF59(0x00);      //WF Pin 59 Disabled
 LCD->WF[15] = LCD_WF_WF60(0x00)|      //WF Pin 60 Disabled
         LCD_WF_WF61(0x00)|      //WF Pin 61 Disabled
         LCD_WF_WF62(0x00)|      //WF Pin 62 Disabled
         LCD_WF_WF63(0x00);      //WF Pin 63 Disabled
         
 //Disable GCR_PADSAFE and Enable GCR_LCDEN
 LCD->GCR &= ~LCD_GCR_PADSAFE_MASK;      //Clear PADSAFE to unlock LCD pins
 LCD->GCR |= LCD_GCR_LCDEN_MASK;       //Set LCDEN to enable operation of LCD
}//End SegLCD_Init 

Writing the Control Library

Now that we have an initialization function, we still need functions to use the LCD. A bit of the operation was discussed in the introduction, and more information can be found in the reference manual pages 918-919.

As our backplanes are already set from the initialization function, we know that COM0 is on phase A, COM1 on phase B, COM2 on phase C, and COM3 on phase D. On the FRDM-KL46z, each character is controlled by two pins, so we can determine what segments will be on from the following table. For each character, Pin 1 is (Digit2 - 1) and Pin 2 is Digit2.

Pin 1 Pin 2
A (COM0) D Decimal/Colon
B (COM1) E C
C (COM2) G B
D (COM3) F A

So if we wanted segments A, B, D, E and G (the number 2) lit on the third digit, we would have to set WF8B[53] and WF8B[37], the 5th and 6th frontplane pins, to 0x77 and 0xCC respectively. This will make pin 5 active on phases A, B and C (segments D E and G) and pin 6 on phases C and D (segments A and B).

In the helpful links and downloads section I have included a SegLCD.c and SegLCD.h, which have some basic functions included. I have them listed below and will briefly describe the functionality and dependencies of each.

Variable Definitions and Macros
These macros define how many pins are on the LCD, how each segment needs to be manipulated, a mapping from LCD pins to Microcontroller pins and inline functions for turning decimals and the colon on and off. These should be placed in the header file for the LCD functions.
Macros

//Define Number of Front and Back plane pins
#define LCD_NUM_FRONTPLANE_PINS 8
#define LCD_NUM_BACKPLANE_PINS 4
//Create macros for segments
#define LCD_SEG_D 0x11
#define LCD_SEG_E 0x22
#define LCD_SEG_G 0x44
#define LCD_SEG_F 0x88
#define LCD_SEG_DECIMAL 0x11
#define LCD_SEG_C 0x22
#define LCD_SEG_B 0x44
#define LCD_SEG_A 0x88
#define LCD_CLEAR 0x00
//Create Macros for each pin
#define LCD_FRONTPLANE0 37u
#define LCD_FRONTPLANE1 17u
#define LCD_FRONTPLANE2 7u
#define LCD_FRONTPLANE3 8u
#define LCD_FRONTPLANE4 53u
#define LCD_FRONTPLANE5 38u
#define LCD_FRONTPLANE6 10u
#define LCD_FRONTPLANE7 11u
#define LCD_BACKPLANE0 40u
#define LCD_BACKPLANE1 52u
#define LCD_BACKPLANE2 19u
#define LCD_BACKPLANE3 18u
//Macros for turning decimal points and colon on and off
#define SegLCD_DP1_On() LCD->WF8B[LCD_FRONTPLANE1]  |= LCD_SEG_DECIMAL;
#define SegLCD_DP1_Off() LCD->WF8B[LCD_FRONTPLANE1] &= ~LCD_SEG_DECIMAL;
#define SegLCD_DP2_On() LCD->WF8B[LCD_FRONTPLANE3]  |= LCD_SEG_DECIMAL;
#define SegLCD_DP2_Off() LCD->WF8B[LCD_FRONTPLANE3] &= ~LCD_SEG_DECIMAL;
#define SegLCD_DP3_On() LCD->WF8B[LCD_FRONTPLANE5]  |= LCD_SEG_DECIMAL;
#define SegLCD_DP3_Off() LCD->WF8B[LCD_FRONTPLANE5] &= ~LCD_SEG_DECIMAL;
#define SegLCD_Col_On() LCD->WF8B[LCD_FRONTPLANE7]  |= LCD_SEG_DECIMAL;
#define SegLCD_Col_Off() LCD->WF8B[LCD_FRONTPLANE7] &= ~LCD_SEG_DECIMAL;

SegLCD_Set
:warning:Dependencies
This function is dependent on the variable “LCD_Frontplane_Pin” which is defined in SegLCD.c. This variable holds which LCD pins map to which Microcontroller pins. This is not removable without a serious rework.
:warning:Dependency
This function is dependent on the SegLCD_DisplayError function! This is removable by removing or commenting out the “If(Digit > 4)” if statement, but will cause an input of Digit > 4 to create undefined behavior.

SegLCD_Set takes Value and places it in the Digit slot of the LCD, with 1 being the leftmost, 4 being the rightmost. This does not alter any of the other digits, though it will clear decimals and colons on that digit.

It will display “Err” if Digit is greater than 4. If Value is greater than 15 it will NOT display an error and will not change the display.
SegLCD_Set

void SegLCD_Set(uint8_t Value,uint8_t Digit){//Sets a value from 0-F to a specified Digit, with 1 being the leftmost, 4 being the rightmost. Will not display error is Value is outside of 0-F, but display will not update
 if(Digit > 4){
 SegLCD_DisplayError(0x01);
 } //Display "Err" if trying to access a digit that does not exist
 else{
 if(Value==0x00) {LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_E |LCD_SEG_F); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_A | LCD_SEG_B | LCD_SEG_C);}
 else if(Value==0x01){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_CLEAR); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_B | LCD_SEG_C);}
 else if(Value==0x02){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_E | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_A | LCD_SEG_B);}
 else if(Value==0x03){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_A | LCD_SEG_B | LCD_SEG_C);}
 else if(Value==0x04){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_F | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_B | LCD_SEG_C);}
 else if(Value==0x05){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_F | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_A | LCD_SEG_C);}
 else if(Value==0x06){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_E | LCD_SEG_F | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_A | LCD_SEG_C);}
 else if(Value==0x07){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_CLEAR); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_A | LCD_SEG_B | LCD_SEG_C);}
 else if(Value==0x08){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_E | LCD_SEG_F | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_A | LCD_SEG_B | LCD_SEG_C);}
 else if(Value==0x09){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_F | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_A | LCD_SEG_B | LCD_SEG_C);}
 else if(Value==0x0A){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_E | LCD_SEG_F | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = (LCD_SEG_A | LCD_SEG_B | LCD_SEG_C);}
 else if(Value==0x0B){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_E | LCD_SEG_F | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = LCD_SEG_C;}
 else if(Value==0x0C){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_E | LCD_SEG_F); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = LCD_SEG_A;}
 else if(Value==0x0D){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_E | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = LCD_SEG_B | LCD_SEG_C;}
 else if(Value==0x0E){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_D | LCD_SEG_E | LCD_SEG_F | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = LCD_SEG_A;}
 else if(Value==0x0F){LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-2)]] = (LCD_SEG_E | LCD_SEG_F | LCD_SEG_G); LCD->WF8B[LCD_Frontplane_Pin[((2*Digit)-1)]] = LCD_SEG_A;}
 }
}//End SegLCD_Set

SegLCD_DisplayDecimal
:warning:Dependency
This function is dependent on the SegLCD_Set function! This is not removable without a serious rework.

:warning:Dependency
This function is dependent on the SegLCD_DisplayError function! This is removable by removing or commenting out the “If(Value > 9999)” if statement and making the else statement the main block of code, but will cause inputs greater than 4 digits to display undefined behavior.
SegLCD_DisplayDecimal takes Value and displays it to the screen in decimal. If the number is greater than 4 digits it will display “Err”. If Value is less than 4 digits there will be leading zeros.
SegLCD_DisplayDecimal

void SegLCD_DisplayDecimal(uint16_t Value){//Displays a 4 Digit number in decimal
 if(Value > 9999){
  SegLCD_DisplayError(0x10); //Display "Err" if value is greater than 4 digits
 }
 else{
  SegLCD_Set(Value/1000,1);
  SegLCD_Set((Value - (Value/1000)*1000)/100,2);
  SegLCD_Set((Value - (Value/100)*100)/10,3);
  SegLCD_Set(Value - (Value/10)*10,4);
 }
}//End SegLCD_Display4Digit

SegLCD_DisplayHex
SegLCD_DisplayHex takes Value and displays it in hexadecimal on the LCD. If Value is less than 0x1000 it will display leading zeros.
SegLCD_DisplayHex

void SegLCD_DisplayHex(uint16_t Value){ //Displays a 16 bit number in Hex Format
 SegLCD_Set((Value & 0xF000)>>12, 1);
 SegLCD_Set((Value & 0x0F00)>>8 , 2);
 SegLCD_Set((Value & 0x00F0)>>4 , 3);
 SegLCD_Set((Value & 0x000F)>>0 , 4);
}//End SegLCD_DisplayHex

SegLCD_DisplayTime
:warning:Dependency
This function is dependent on the SegLCD_Set function! This is not removable without a serious rework.

:warning:Dependency
This function is dependent on the SegLCD_DisplayError function! This is removable by removing or commenting out the “If((Value1 > 99) | (Value2 > 99))” if statement and making the else statement the main block of code, but will cause inputs greater than 2 digits to display undefined behavior.

:warning:Dependency
This function is dependent on the SegLCD_Col_On() macro! This is removable by removing or commenting out the line “SegLCD_Col_On();” and replacing it with an equivalent way of turning the colon on.

SegLCD_DisplayTime displays Value1 , then Value2 to the screen separated by a colon. This was originally intended to display time (as seen by the name) but can be used for other purposes. If Value1 or Value2 are greater than 2 digits it will display “Err”.
SegLCD_DisplayTime

void SegLCD_DisplayTime(uint8_t Value1, uint8_t Value2){//Displays 2 values separated by a colon
 if((Value1 > 99) | (Value2 > 99)){
  SegLCD_DisplayError(0x10); //Display "Err" if either value is greater than 2 digits
 }
 else{
  SegLCD_Set(Value1/10, 1);
  SegLCD_Set(Value1 % 10, 2);
  SegLCD_Set(Value2/10, 3);
  SegLCD_Set(Value2 % 10, 4);
  SegLCD_Col_On();
 }
}//End SegLCD_DisplayTime

SegLCD_DisplayError
:warning:Dependency
This function is dependent on the SegLCD_Set function! This is removable by removing or commenting out the “If(ErrorNum < 0x10)” if statement, moving the else statement to the main code, and changing the input from “uint8_t ErrorNum” to “void”. This will cause the function to only display “Err” without a number.

The SegLCD_DisplayError function displays “Err#” to the LCD, where # is ErrorNum . If ErrorNum is greater than 0x0F, it will simply display Err.
SegLCD_DisplayError

void SegLCD_DisplayError(uint8_t ErrorNum){//Displays Err# on screen, where # is a value 0-F.  If ErrorNum is outside of that range, just displays Err
 LCD->WF8B[LCD_FRONTPLANE0] = (LCD_SEG_D | LCD_SEG_E | LCD_SEG_F | LCD_SEG_G);
 LCD->WF8B[LCD_FRONTPLANE1] = (LCD_SEG_A);
 LCD->WF8B[LCD_FRONTPLANE2] = (LCD_SEG_E | LCD_SEG_G);
 LCD->WF8B[LCD_FRONTPLANE3] = (LCD_CLEAR);
 LCD->WF8B[LCD_FRONTPLANE4] = (LCD_SEG_E | LCD_SEG_G);
 LCD->WF8B[LCD_FRONTPLANE5] = (LCD_CLEAR);
 if(ErrorNum < 0x10){
  SegLCD_Set(ErrorNum,4); //Display ErrorNum in digit 4 if within valid range.  If not, leave blank.
 }
 else{
  LCD->WF8B[LCD_FRONTPLANE6] = (LCD_CLEAR);
  LCD->WF8B[LCD_FRONTPLANE7] = (LCD_CLEAR);
 }
}//End SegLCD_DisplayError

Questions/Comments

I hope you found this article helpful and insightful. Any questions or comments please go to the Digi-Key TechForum