[FM33LG0 Series Development Board Review] 07. LCD & Segment Display Software Implementation Framework
[Copy link]
1. Introduction
FM33LG048 has an LCD display driver module for driving segment code LCD screens. It can support up to 8 COMs, 8*40, 6*42, 4*44 display segments, 16 levels of adjustable grayscale, and selectable 1/3Bias or 1/4Bias; a typical frame refresh rate of 64Hz.
J14 on the FM33LG0XX DEMO V1.1 development board brings out some LCD COM ports and SEG ports in the form of pin headers, making it easy to connect to an external segment code LCD display. The interface schematic is shown below:
But one thing to note is that COM0~COM7 and SEG0~SEG12 of J14 are consistent with the function definition of MCU port pins, and the rest are connected to other SEG port pins. The specific connection comparison table is shown in the figure below:
2. LCD screen selection
We purchased an LCD screen with a relatively large number of display segments online, with 4 COM ports and 25 SEG ports. The full display effect is as follows:
In order to display all the content, the SEG port of J14 is not enough, so we just expand the SPI1 interface to use the SEG port, which just meets the SEG port number requirement. The wiring sequence can be seen from the table in Section 1. The truth table of the LCD is shown in the figure below:
3. Implement functions
Through the built-in LCD driver module of FM33LG048, the driving and display of LCD is realized to achieve dynamic display effect; combined with the self-written segment code display software implementation framework, the application display software development can be quickly realized and the product iteration can be carried out quickly; this software framework is not only suitable for MCU with built-in LCD driver module, but also suitable for the form of using external LCD driver chip, and also suitable for driving display of digital tube.
4. Hardware connection and display effect
5. Implementation code
5.1. Define segment codes to display commonly used characters
/* Private variables ---------------------------------------------------------*/
const DIGITRON_STRUCT DIGITRON_TABLE[38] =
{
{' ', {0, 0, 0, 0, 0, 0, 0, 0}},
{'0', {1, 1, 1, 1, 1, 1, 0, 0}},
{'1', {0, 1, 1, 0, 0, 0, 0, 0}},
{'2', {1, 1, 0, 1, 1, 0, 1, 0}},
{'3', {1, 1, 1, 1, 0, 0, 1, 0}},
{'4', {0, 1, 1, 0, 0, 1, 1, 0}},
{'5', {1, 0, 1, 1, 0, 1, 1, 0}},
{'6', {1, 0, 1, 1, 1, 1, 1, 0}},
{'7', {1, 1, 1, 0, 0, 0, 0, 0}},
{'8', {1, 1, 1, 1, 1, 1, 1, 0}},
{'9', {1, 1, 1, 1, 0, 1, 1, 0}},
{'A', {1, 1, 1, 0, 1, 1, 1, 0}},
{'b', {0, 0, 1, 1, 1, 1, 1, 0}},
{'c', {0, 0, 0, 1, 1, 0, 1, 0}},
{'C', {1, 0, 0, 1, 1, 1, 0, 0}},
{'d', {0, 1, 1, 1, 1, 0, 1, 0}},
{'E', {1, 0, 0, 1, 1, 1, 1, 0}},
{'F', {1, 0, 0, 0, 1, 1, 1, 0}},
{'g', {1, 1, 1, 1, 0, 1, 1, 0}},
{'H', {0, 1, 1, 0, 1, 1, 1, 0}},
{'h', {0, 0, 1, 0, 1, 1, 1, 0}},
{'i', {0, 0, 1, 0, 0, 0, 0, 0}},
{'I', {0, 0, 0, 0, 1, 1, 0, 0}},
{'J', {0, 1, 1, 1, 1, 0, 0, 0}},
{'l', {0, 0, 0, 0, 1, 1, 0, 0}},
{'L', {0, 0, 0, 1, 1, 1, 0, 0}},
{'n', {0, 0, 1, 0, 1, 0, 1, 0}},
{'o', {0, 0, 1, 1, 1, 0, 1, 0}},
{'O', {1, 1, 1, 1, 1, 1, 0, 0}},
{'P', {1, 1, 0, 0, 1, 1, 1, 0}},
{'q', {1, 1, 1, 0, 0, 1, 1, 0}},
{'r', {0, 0, 0, 0, 1, 0, 1, 0}},
{'S', {1, 0, 1, 1, 0, 1, 1, 0}},
{'t', {0, 0, 0, 1, 1, 1, 1, 0}},
{'u', {0, 0, 1, 1, 1, 0, 0, 0}},
{'U', {0, 1, 1, 1, 1, 1, 0, 0}},
{'y', {0, 1, 1, 1, 0, 1, 1, 0}},
{'-', {0, 0, 0, 0, 0, 0, 1, 0}},
};
5.2. Define the LCD segment code lookup table based on the LCD segment code truth table and hardware wiring sequence
/* Private variables ---------------------------------------------------------*/
const char LCD_CS_TABLE[4][44][3] =
{
/*SEGX 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43*/
/*COM0*/{"1D","P1","2D","P2","3D","P3","4D","C1","C2","W5","L1","5F","5A"," "," "," "," "," "," "," "," "," "," "," ","9F","9A","AF","AA"," "," "," "," "," "," "," "," ","6F","6A","7F","7A","S4","S5","8F","8A"},
/*COM1*/{"1E","1C","2E","2C","3E","3C","4E","4C","C3","W4","L2","5G","5B"," "," "," "," "," "," "," "," "," "," "," ","9G","9B","AG","AB"," "," "," "," "," "," "," "," ","6G","6B","7G","7B","S3","S6","8G","8B"},
/*COM2*/{"1G","1B","2G","2B","3G","3B","4G","4B","T1","W3","L3","5E","5C"," "," "," "," "," "," "," "," "," "," "," ","9E","9C","AE","AC"," "," "," "," "," "," "," "," ","6E","6C","7E","7C","S2","S7","8E","8C"},
/*COM3*/{"1F","1A","2F","2A","3F","3A","4F","4A","W1","W2","L4","5D","P5"," "," "," "," "," "," "," "," "," "," "," ","9D","P9","AD","S9"," "," "," "," "," "," "," "," ","6D","P6","7D","P7","S1","S8","8D","P8"},
};
5.3. Divide and group according to display content and define the display function area array
/* Private variables ---------------------------------------------------------*/
const char DISPLAY_DIGIT_TABLE[10][7][3] =
{
{"1A", "1B", "1C", "1D", "1E", "1F", "1G"},
{"2A", "2B", "2C", "2D", "2E", "2F", "2G"},
{"3A", "3B", "3C", "3D", "3E", "3F", "3G"},
{"4A", "4B", "4C", "4D", "4E", "4F", "4G"},
{"5A", "5B", "5C", "5D", "5E", "5F", "5G"},
{"6A", "6B", "6C", "6D", "6E", "6F", "6G"},
{"7A", "7B", "7C", "7D", "7E", "7F", "7G"},
{"8A", "8B", "8C", "8D", "8E", "8F", "8G"},
{"9A", "9B", "9C", "9D", "9E", "9F", "9G"},
{"AA", "AB", "AC", "AD", "AE", "AF", "AG"},
};
const char DISPLAY_POINT_TABLE[11][3] = {"P1", "P2", "P3", "P5", "P6", "P7", "P8", "P9", "C1", "C2", "C3"};
const char DISPLAY_BAT_TABLE[5][3] = {"W1", "W2", "W3", "W4", "W5"};
const char DISPLAY_CSQ_TABLE[4][3] = {"L1", "L2", "L3", "L4"};
const char DISPLAY_UNIT_TABLE[10][3] = {"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "T1"};
5.4. Query the COM and SEG positions that need to be operated according to the truth table content
/*******************************************************************************
* @brief * @param
* @retval
* @attention *******************************************************************************/
void LCD_SearchCS(const char *str, uint8_t *com, uint8_t *seg)
{
for(uint8_t i = 0; i < 4; i++) //扫描04个COM段
{
for(uint8_t j = 0; j < 44; j++) //扫描44个SEG段
{
if(strcmp(str, LCD_CS_TABLE[j]) == 0)
{
*com = i; *seg = j; return;
}
}
}
*com = 0xFF;
*seg = 0xFF;
}
5.5. Initialize the LCD driver module according to the hardware connection
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LCD_Init(void)
{
FL_GPIO_InitTypeDef GPIO_InitStruct;
FL_LCD_InitTypeDef LCD_InitStruct;
memset(LCD_DisplayBuffer, 0, sizeof(LCD_DisplayBuffer));
FL_GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.pin = FL_GPIO_PIN_0 | FL_GPIO_PIN_1 | FL_GPIO_PIN_2 |
FL_GPIO_PIN_3 | FL_GPIO_PIN_8 | FL_GPIO_PIN_9 |
FL_GPIO_PIN_10;
GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
FL_GPIO_Init(GPIOA, &GPIO_InitStruct);
FL_GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.pin = FL_GPIO_PIN_4 | FL_GPIO_PIN_5 | FL_GPIO_PIN_6 |
FL_GPIO_PIN_7 | FL_GPIO_PIN_8 | FL_GPIO_PIN_9 |
FL_GPIO_PIN_10 | FL_GPIO_PIN_11 | FL_GPIO_PIN_13 |
FL_GPIO_PIN_14;
GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
FL_GPIO_Init(GPIOB, &GPIO_InitStruct);
FL_GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.pin = FL_GPIO_PIN_13 | FL_GPIO_PIN_14 | FL_GPIO_PIN_15;
GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
FL_GPIO_Init(GPIOC, &GPIO_InitStruct);
FL_GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.pin = FL_GPIO_PIN_2 | FL_GPIO_PIN_3 | FL_GPIO_PIN_4 |
FL_GPIO_PIN_5;
GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
FL_GPIO_Init(GPIOD, &GPIO_InitStruct);
FL_GPIO_StructInit(&GPIO_InitStruct);
GPIO_InitStruct.pin = FL_GPIO_PIN_0 | FL_GPIO_PIN_1 | FL_GPIO_PIN_2 |
FL_GPIO_PIN_3 | FL_GPIO_PIN_5;
GPIO_InitStruct.mode = FL_GPIO_MODE_ANALOG;
GPIO_InitStruct.outputType = FL_GPIO_OUTPUT_PUSHPULL;
FL_GPIO_Init(GPIOE, &GPIO_InitStruct);
FL_LCD_StructInit(&LCD_InitStruct);
LCD_InitStruct.biasCurrent = FL_LCD_BIAS_CURRENT_HIGH;
LCD_InitStruct.biasMode = FL_LCD_BIAS_MODE_3BIAS;
LCD_InitStruct.biasVoltage = FL_LCD_BIAS_VOLTAGE_LEVEL7;
LCD_InitStruct.COMxNum = FL_LCD_COM_NUM_4COM;
LCD_InitStruct.waveform = FL_LCD_WAVEFORM_TYPEA;
LCD_InitStruct.displayFreq = 64;
LCD_InitStruct.mode = FL_LCD_DRIVER_MODE_INNER_RESISTER;
FL_LCD_Init(LCD, &LCD_InitStruct);
FL_LCD_EnableCOMEN(LCD, FL_LCD_COMEN_COM0);
FL_LCD_EnableCOMEN(LCD, FL_LCD_COMEN_COM1);
FL_LCD_EnableCOMEN(LCD, FL_LCD_COMEN_COM2);
FL_LCD_EnableCOMEN(LCD, FL_LCD_COMEN_COM3);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG0);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG1);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG2);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG3);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG4);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG5);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG6);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG7);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG8);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG9);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG10);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG11);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG12);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG24);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG25);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG26);
FL_LCD_EnableSEGEN0(LCD, FL_LCD_SEGEN0_SEG27);
FL_LCD_EnableSEGEN1(LCD, FL_LCD_SEGEN1_SEG4); //SEG36
FL_LCD_EnableSEGEN1(LCD, FL_LCD_SEGEN1_SEG5); //SEG37
FL_LCD_EnableSEGEN1(LCD, FL_LCD_SEGEN1_SEG6); //SEG38
FL_LCD_EnableSEGEN1(LCD, FL_LCD_SEGEN1_SEG7); //SEG39
FL_LCD_EnableSEGEN1(LCD, FL_LCD_SEGEN1_SEG8); //SEG40
FL_LCD_EnableSEGEN1(LCD, FL_LCD_SEGEN1_SEG9); //SEG41
FL_LCD_EnableSEGEN1(LCD, FL_LCD_SEGEN1_SEG10); //SEG42
FL_LCD_EnableSEGEN1(LCD, FL_LCD_SEGEN1_SEG11); //SEG43
FL_LCD_Enable(LCD);
LCD_DisplayRefresh();
TASK_Append(TASK_ID_LCD, LCD_DisplayHandler, 100);
}
5.6. Mainly implement the source code of the function. For details, you can download the source code project in the attachment for reading
/*******************************************************************************
* @brief
* @param
* @retval
* @attention
*******************************************************************************/
void LCD_DisplayHandler(void)
{
static uint32_t DisplayTick = 0;
static uint16_t BAT_Index = 0, CSQ_Index = 0, Unit_Index = 0;
static uint16_t COL_State = 0;
LCD_DisplayCount(); //100ms
if((DisplayTick % 2) == 0) //200ms
{
switch(BAT_Index++ % 4)
{
case 0 : LCD_DisplayBAT(0x0001); break;
case 1 : LCD_DisplayBAT(0x0001 | 0x0002); break;
case 2 : LCD_DisplayBAT(0x0001 | 0x0002 | 0x0004); break;
case 3 : LCD_DisplayBAT(0x0001 | 0x0002 | 0x0004 | 0x0008); break;
default: break;
}
switch(CSQ_Index++ % 4)
{
case 0 : LCD_DisplayCSQ(0x0001); break;
case 1 : LCD_DisplayCSQ(0x0001 | 0x0002); break;
case 2 : LCD_DisplayCSQ(0x0001 | 0x0002 | 0x0004); break;
case 3 : LCD_DisplayCSQ(0x0001 | 0x0002 | 0x0004 | 0x0008); break;
default: break;
}
LCD_DisplayUnit(0x0001 << (Unit_Index++ % 10));
}
if((DisplayTick % 5) == 0) //500ms
{
if(COL_State == 0)
{
COL_State = 1; LCD_DisplayPoint(POINT_COL2 | POINT_COL3);
}
else
{
COL_State = 0; LCD_DisplayPoint(0x0000);
}
}
if((DisplayTick % 10) == 0) //1000ms
{
LCD_DisplayClock();
}
DisplayTick += 1;
DisplayTick %= 10000;
}
6. Run the demo
7. Project source code
Project_LCD.zip
(386.07 KB, downloads: 65)
GDC0689TP-11.pdf
(337.42 KB, downloads: 47)
|