【国民技术低功耗系列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)
|