6104|3

205

帖子

0

TA的资源

纯净的硅(初级)

楼主
 

【国民技术低功耗系列N32L43x测评】04.结构体设计让LCD显示不拘泥于底层操作 [复制链接]

 

官方的LCD例程可能功能比较丰富,所以在阅读和理解起来都需要一定时间;所以按照自己的逻辑方式实现了一个看上去相对简易一些,容易理解一些的实现方式,主要是通过定义结构体和查表的方式来实现的,供大伙借鉴参考。

 

首先我们定义一个显示字符映射段位编码的结构体:

typedef struct
{
    char    ch;
    uint8_t Data;
} LCD_CODING_TypeDef;

然后将常规显示字符及对应的段位编码编入一个数组,这样我们在显示一个字符的时候,就可以通过查表的方式来获取对应字符的段位编码了,实现代码如下:

const LCD_CODING_TypeDef LCD_CODE[38] = 
{
    {' ', 0x00},
    {'0', 0x3F},
    {'1', 0x06},
    {'2', 0x5B},
    {'3', 0x4F},
    {'4', 0x66},
    {'5', 0x6D},
    {'6', 0x7D},
    {'7', 0x07},
    {'8', 0x7F},
    {'9', 0x6F},
    {'A', 0x77},
    {'b', 0x7C},
    {'c', 0x58},
    {'C', 0x39},
    {'d', 0x5E},
    {'E', 0x79},
    {'F', 0x71},
    {'g', 0x6F},
    {'H', 0x76},
    {'h', 0x74},
    {'i', 0x04},
    {'I', 0x30},
    {'J', 0x1E},
    {'l', 0x30},
    {'L', 0x38},
    {'n', 0x54},
    {'o', 0x5C},
    {'O', 0x3F},
    {'P', 0x73},
    {'q', 0x67},
    {'r', 0x50},
    {'S', 0x6D},
    {'t', 0x78},
    {'u', 0x1C},
    {'U', 0x3E},
    {'y', 0x6E},
    {'-', 0x40},
};

uint8_t LCD_SearchCode(char ch)
{
    for(uint8_t i = 0; i < 38; i++)
    {
        if(ch == LCD_CODE[i].ch)
        {
            return LCD_CODE[i].Data;
        }
    }

    return 0xFF;
}

接下来我们定义一个LCD液晶屏显示段位与硬件连接的对照关系表,结构体定义如下:

typedef struct
{
    char    *Name;
    uint32_t RAMRegisterIndex;
    uint32_t RAMData;
} LCD_MAP_TypeDef;

那我们如何赋值这个结构体中的数据呢?我们用到了LCD的真值表,还用到我们MCU实际与LCD连接的引脚对应关系,如下所示:

LCD真值表

PIN

1

2

3

4

5

6

7

8

9

10

11

12

COM1

COM1

 

 

 

1F

1A

2F

2A

3F

3A

4F

4A

COM2

 

COM2

 

 

1G

1B

2G

2B

3G

3B

4G

4B

COM3

 

 

COM3

 

1E

1C

2E

2C

3E

3C

4E

4C

COM4

 

 

 

COM4

P1

1D

P2

2D

P3

3C

P4

4D

MCU与LCD连接的引脚

LCD

1

2

3

4

5

6

7

8

9

10

11

12

MCU

COM4

COM5

COM6

COM7

SEG5

SGE6

SEG10

SEG11

SEG12

SEG13

SEG14

SEG15

 

PC10

PC11

PC12

PD2

PB0

PB1

PB10

PB11

PB12

PB13

PB14

PB15

通过如上这两个表格,我们将LCD真值表中的段位号作为关键字,定义如下的映射关系,我们就可以通过LCD真值表的段位号通过查表的方式,轻松获取到MCU所对应的LCD操作段和位了,实现代码如下:

const LCD_MAP_TypeDef LCD_MAP[32] =
{
    {"1F", LCD_RAM1_COM4, (0x00000001 <<  5)},  /* LCD_COM4   LCD_SEG5  */
    {"1A", LCD_RAM1_COM4, (0x00000001 <<  6)},  /* LCD_COM4   LCD_SEG6  */
    {"2F", LCD_RAM1_COM4, (0x00000001 << 10)},  /* LCD_COM4   LCD_SEG10 */
    {"2A", LCD_RAM1_COM4, (0x00000001 << 11)},  /* LCD_COM4   LCD_SEG11 */
    {"3F", LCD_RAM1_COM4, (0x00000001 << 12)},  /* LCD_COM4   LCD_SEG12 */
    {"3A", LCD_RAM1_COM4, (0x00000001 << 13)},  /* LCD_COM4   LCD_SEG13 */
    {"4F", LCD_RAM1_COM4, (0x00000001 << 14)},  /* LCD_COM4   LCD_SEG14 */
    {"4A", LCD_RAM1_COM4, (0x00000001 << 15)},  /* LCD_COM4   LCD_SEG15 */

    {"1G", LCD_RAM1_COM5, (0x00000001 <<  5)},  /* LCD_COM5   LCD_SEG5  */
    {"1B", LCD_RAM1_COM5, (0x00000001 <<  6)},  /* LCD_COM5   LCD_SEG6  */
    {"2G", LCD_RAM1_COM5, (0x00000001 << 10)},  /* LCD_COM5   LCD_SEG10 */
    {"2B", LCD_RAM1_COM5, (0x00000001 << 11)},  /* LCD_COM5   LCD_SEG11 */
    {"3G", LCD_RAM1_COM5, (0x00000001 << 12)},  /* LCD_COM5   LCD_SEG12 */
    {"3B", LCD_RAM1_COM5, (0x00000001 << 13)},  /* LCD_COM5   LCD_SEG13 */
    {"4G", LCD_RAM1_COM5, (0x00000001 << 14)},  /* LCD_COM5   LCD_SEG14 */
    {"4B", LCD_RAM1_COM5, (0x00000001 << 15)},  /* LCD_COM5   LCD_SEG15 */

    {"1E", LCD_RAM1_COM6, (0x00000001 <<  5)},  /* LCD_COM6   LCD_SEG5  */
    {"1C", LCD_RAM1_COM6, (0x00000001 <<  6)},  /* LCD_COM6   LCD_SEG6  */
    {"2E", LCD_RAM1_COM6, (0x00000001 << 10)},  /* LCD_COM6   LCD_SEG10 */
    {"2C", LCD_RAM1_COM6, (0x00000001 << 11)},  /* LCD_COM6   LCD_SEG11 */
    {"3E", LCD_RAM1_COM6, (0x00000001 << 12)},  /* LCD_COM6   LCD_SEG12 */
    {"3C", LCD_RAM1_COM6, (0x00000001 << 13)},  /* LCD_COM6   LCD_SEG13 */
    {"4E", LCD_RAM1_COM6, (0x00000001 << 14)},  /* LCD_COM6   LCD_SEG14 */
    {"4C", LCD_RAM1_COM6, (0x00000001 << 15)},  /* LCD_COM6   LCD_SEG15 */

    {"P1", LCD_RAM1_COM7, (0x00000001 <<  5)},  /* LCD_COM7   LCD_SEG5  */
    {"1D", LCD_RAM1_COM7, (0x00000001 <<  6)},  /* LCD_COM7   LCD_SEG6  */
    {"P2", LCD_RAM1_COM7, (0x00000001 << 10)},  /* LCD_COM7   LCD_SEG10 */
    {"2D", LCD_RAM1_COM7, (0x00000001 << 11)},  /* LCD_COM7   LCD_SEG11 */
    {"P3", LCD_RAM1_COM7, (0x00000001 << 12)},  /* LCD_COM7   LCD_SEG12 */
    {"3D", LCD_RAM1_COM7, (0x00000001 << 13)},  /* LCD_COM7   LCD_SEG13 */
    {"P4", LCD_RAM1_COM7, (0x00000001 << 14)},  /* LCD_COM7   LCD_SEG14 */
    {"4D", LCD_RAM1_COM7, (0x00000001 << 15)},  /* LCD_COM7   LCD_SEG15 */
};

uint8_t LCD_SearchMapIndex(char *str)
{
    for(uint8_t i = 0; i < 32; i++)
    {
        if(strcmp(str, LCD_MAP[i].Name) == 0)
        {
            return i;
        }
    }

    return 0xFF;
}

接下来我们就来实现如果显示一个字符或者是特殊段位,我们用到库函数中3个基本功能函数:

LCD_ErrorTypeDef LCD_SetBit(uint32_t RAMRegisterIndex,uint32_t RAMData);
LCD_ErrorTypeDef LCD_ClearBit(uint32_t RAMRegisterIndex,uint32_t RAMData);
LCD_ErrorTypeDef LCD_UpdateDisplayRequest(void);

功能分别是设置一个段位为显示状态,清除一个段位的显示状态,以及更新显示功能;

我们通过LCD数据手册中对段位的排布结合真值表,我们知道一个字符是由7个段位来组成的,分别是1A~1G、2A~2G、3A~3G、4A~4G;所以我们定义一个数组:

char TAB[4][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"},
};

我们只需要操作其中一组就可以显示一个字符了,具体流程如下:

首先我们通过需要显示的字符,通过LCD_SearchCode函数获取到对应的段位编码,然后依次对A~G段位进行赋值,段位对应MCU的映射关系我们通过LCD_SearchMapIndex函数来获得,这样就可以实现一个字符的显示了,具体的代码实现如下所示:

void LCD_Display(uint8_t Index, char ch)
{
    char TAB[4][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"},
    };

    uint8_t Code = LCD_SearchCode(ch);

    if(Code != 0xFF)
    {
        for(uint8_t j = 0; j < 7; j++)
        {
            if((Code >> j) & 0x01)
            {
                uint8_t k = LCD_SearchMapIndex(TAB[Index][j]);

                if(k != 0xFF)
                {
                    LCD_SetBit(LCD_MAP[k].RAMRegisterIndex, LCD_MAP[k].RAMData);
                }
            }
            else
            {
                uint8_t k = LCD_SearchMapIndex(TAB[Index][j]);

                if(k != 0xFF)
                {
                    LCD_ClearBit(LCD_MAP[k].RAMRegisterIndex, LCD_MAP[k].RAMData);
                }
            }
        }
    }

    LCD_UpdateDisplayRequest();
}

特殊的点位或者是其它LCD屏上还带有单位的段位,可以参考如下的函数实现方式来实现:

void LCD_DisplayPoint(uint8_t Index, uint8_t Enable)
{
    char TAB[4][3] =
    {
        "P1", "P2", "P3", "P4"
    };

    uint8_t k = LCD_SearchMapIndex(TAB[Index]);

    if(k != 0xFF)
    {
        if(Enable)
        {
            LCD_SetBit(LCD_MAP[k].RAMRegisterIndex, LCD_MAP[k].RAMData);
        }
        else
        {
            LCD_ClearBit(LCD_MAP[k].RAMRegisterIndex, LCD_MAP[k].RAMData);
        }
    }

    LCD_UpdateDisplayRequest();
}

最后我们来显示一个简单的跑秒实现,实现代码和运行效果如下所示:

void LCD_Handler(void)
{
    static uint16_t i = 0;

    if(i < 10)
    {
        LCD_Display(0, ' ');
        LCD_Display(1, ' ');
        LCD_Display(2, ' ');
        LCD_Display(3, 0x30 + (i / 1) % 10);
    }
    else if(i < 100)
    {
        LCD_Display(0, ' ');
        LCD_Display(1, ' ');
        LCD_Display(2, 0x30 + (i / 10) % 10);
        LCD_Display(3, 0x30 + (i / 1 ) % 10);
    }
    else if(i < 1000)
    {
        LCD_Display(0, ' ');
        LCD_Display(1, 0x30 + (i / 100) % 10);
        LCD_Display(2, 0x30 + (i / 10 ) % 10);
        LCD_Display(3, 0x30 + (i / 1  ) % 10);
    }
    else
    {
        LCD_Display(0, 0x30 + (i / 1000) % 10);
        LCD_Display(1, 0x30 + (i / 100 ) % 10);
        LCD_Display(2, 0x30 + (i / 10  ) % 10);
        LCD_Display(3, 0x30 + (i / 1   ) % 10);
    }

    i = (i + 1) % 10000;
}

演示效果

LCD跑秒

 

附件

工程源码: Template.zip (480 KB, 下载次数: 7)

最新回复

查表,好手段。   详情 回复 发表于 2022-7-11 19:34
点赞 关注
个人签名We are a team and we work as a team !
 
 

回复
举报

6060

帖子

6

TA的资源

版主

沙发
 

楼主的LCD段码显示的编程思路非常不错,现在的段码都是高级定制的

 
 
 

回复

7452

帖子

2

TA的资源

五彩晶圆(高级)

板凳
 

查表,好手段。

个人签名

默认摸鱼,再摸鱼。2022、9、28

 
 
 

回复

205

帖子

0

TA的资源

纯净的硅(初级)

4
 

成熟的案例,不少项目中都是这样来实现的,很方便……写出来跟大家分享一下

 

个人签名We are a team and we work as a team !
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表