4823 views|8 replies

205

Posts

0

Resources
The OP
 

[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)

This post is from Domestic Chip Exchange

Latest reply

Fudan Micro Agent   Details Published on 2024-7-19 15:31

赞赏

1

查看全部赞赏

Personal signatureWe are a team and we work as a team !
 
 

6841

Posts

11

Resources
2
 

Very attentive, serious evaluation!

This post is from Domestic Chip Exchange

Comments

Thanks  Details Published on 2021-12-25 08:24
 
 
 

205

Posts

0

Resources
3
 
lugl4313820 posted on 2021-12-25 08:11 I put a lot of effort into the evaluation!

Thank you

This post is from Domestic Chip Exchange
 
 
 

2

Posts

0

Resources
4
 

May I ask why the LCD_DisplayBuffer cache buff is set to 10? I don’t quite understand it. I hope you can help me solve my doubts. Thank you!

image.png (135.29 KB, downloads: 0)

image.png
This post is from Domestic Chip Exchange

Comments

[attachimg]666730[/attachimg]   Details Published on 2022-12-23 17:15
 
 
 

205

Posts

0

Resources
5
 
fiee posted on 2022-12-16 17:10 May I ask why the LCD_DisplayBuffer cache buff is set to 10? I don’t quite understand it. I hope the big guys can solve my doubts. Thank you!

This post is from Domestic Chip Exchange
Personal signatureWe are a team and we work as a team !
 
 
 

2

Posts

0

Resources
6
 

Excuse me, why is the array dimension defined as 3? Thank you!

This post is from Domestic Chip Exchange

Comments

You can think of it as a two-dimensional array, but each element in the array is a string, so a three-dimensional array is needed to represent it...  Details Published on 2023-4-19 14:05
 
 
 

205

Posts

0

Resources
7
 
The invincible little lion posted on 2023-4-19 08:59 Excuse me, why is the array dimension defined as 3-dimensional? Thank you!

You can think of it as a two-dimensional array, but each element in the array is a string, so a three-dimensional array is needed to represent it...

This post is from Domestic Chip Exchange
Personal signatureWe are a team and we work as a team !
 
 
 

2

Posts

0

Resources
8
 
xld0932 posted on 2023-4-19 14:05 You can think of it as a two-dimensional array, but each element in the array is a string, so a three-dimensional array is needed to represent it...&he ...

Thanks!

This post is from Domestic Chip Exchange
 
 
 

11

Posts

0

Resources
9
 

Fudan Micro Agent

This post is from Domestic Chip Exchange
 
 
 

Just looking around
Find a datasheet?

EEWorld Datasheet Technical Support

Related articles more>>
Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号
快速回复 返回顶部 Return list