蓝桥杯嵌入式开发指南 04-LCD 液晶显示器配置

实例

通过配置 LCD 液晶显示器,在屏幕上显示指定内容。

电路分析



对于 LCD,由于官方在赛点资源包中提供了 LCD 整个模块的驱动示例代码,故不在此处对其电路进行详细分析,直接调用其对应程序即可。其主要需要注意的地方在于 LCD 和 LED 共用了 PC8-PC15 引脚,在对 LCD 进行写操作时,会导致 LED 状态改变,具体解决方案请见后文。

驱动代码分析

在比赛中,常用的 LCD 函数主要有以下几个:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//初始化LCD模块
void STM3210B_LCD_Init(void);

//LCD清屏并设置背景色
void LCD_Clear(u16 Color);

//设置文本背景色
void LCD_SetBackColor(vu16 Color);

//设置文本颜色
void LCD_SetTextColor(vu16 Color);

//清空行
void LCD_ClearLine(u8 Line);

//在某行显示字符串
void LCD_DisplayStringLine(u8 Line, u8 *ptr);

实例分析

通过程序实现如下功能:

  • 初始化 LCD 屏幕为黑色
  • 在第一行显示白色的 “Welcome!”
  • 在第二行用蓝色字体显示 LED 灯的 I/O 口状态”LED1-I/O:1/0”

将 L1_Status 由局部变量改为全局变量,并添加 stdio.h 头文件,定义一个长度为 20 的数组用于保存显示用的字符串:

1
2
3
#include <stdio.h>
u8 L1_Status=0;
u8 Display_String[20];

然后修改主程序:

1
2
3
4
5
6
7
8
9
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
int main(void)
{
SysTick_Config(SystemCoreClock/1000);
Delay_Ms(200);

//初始化LCD
STM3210B_LCD_Init();

//清屏并设置LCD背景为黑色
LCD_Clear(Black);

//设置字体背景颜色为黑色
LCD_SetBackColor(Black);

//调用定时器1初始化程序
Timer1_Init();

//调用LED初始化程序
LED_Init();

//调用按键初始化程序
Key_Init();

//设置字体颜色为白色
LCD_SetTextColor(White);

//在第一行输出指定的字符串
LCD_DisplayStringLine(Line1,(u8*)" Welcome!");

while(1)
{
//获取L1的IO状态并送到指定字符串中
sprintf((char*)Display_String,"LED1-I/O:%d",L1_Status);

//设置字体颜色为蓝色
LCD_SetTextColor(Blue);

//在第二行输出指定的字符串
LCD_DisplayStringLine(Line2,Display_String);
}
}

特别提醒


如何调用程序显示会变更的变量?
本处通过 sprintf 函数和 LCD 字符串输出函数实现了对有变更的数字进行显示,需要 include 标准的 C 语言程序库 “stdio.h”

函数 sprintf 的基本介绍

sprintf 指的是字符串格式化命令,函数声明:int sprintf (char *string, char *format [,argument,…]);

  • string:这是指向一个字符数组的指针,该数组存储了 C 字符串。
  • format:这是字符串,包含了要被写入到字符串 str 的文本。它可以包含嵌入的 format 标签,format 标签可被随后的附加参数中指定的值替换,并按需求进行格式化。format 标签属性是 %[flags][width][.precision][length] specifier
  • [argument]…:根据不同的 format 字符串,函数可能需要一系列的附加参数,每个参数包含了一个要被插入的值,替换了 format 参数中指定的每个 % 标签。参数的个数应与 % 标签的个数相同。

功能说明:sprintf 把格式化的数据写入某个字符串缓冲区。

示例:将 “AD=value 值” 存入字符串 Display_string 中并在 LCD 第三行显示,对主程序做如下修改:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
int main(void)
{
u8 Display_string[20];
u8 value=10;
......
while(1)
{
......
//使用sprintf函数将指定内容存入字符串Display_string中
sprintf((char*)Display_string,"AD=%d",value);
LCD_DisplayStringLine(Line3,Display_string);
}
}

则会在 LCD 显示器的第三行输出:AD=10。

如何解决 LCD 和 LED 共用 I/O 口冲突问题?

我们将上面的程序下载到开发板中不难发现,当我们对按键进行操作以后,LCD 程序刷新了显示内容,导致所有的 LED 灯均被点亮,解决方法为:在操作 LCD 前,我们先保存 GPIOC->ODR 寄存器的值,在对 LCD 操作完毕后,恢复 GPIOC->ODR 原来的值即可。

可以在 lcd.c 中找到需要修改的三个 LCD_Write 相关函数:

1
2
3
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue);
void LCD_WriteRAM_Prepare(void);
void LCD_WriteRAM(u16 RGB_Code);

在每个函数的首行加上:

1
u16 PC_Out = GPIOC->ODR

每个函数的末行加上:

1
GPIOC->ODR = PC_Out

以 LCD_WriteReg 修改为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{
u16 PC_Out = GPIOC->ODR; //首行添加内容
/* 原有程序代码起始 */
GPIOB->BRR = 0x0200;
GPIOB->BRR = 0x0100;
GPIOB->BSRR = 0x0020;

GPIOC->ODR = LCD_Reg;
GPIOB->BRR = 0x0020;
GPIOB->BSRR = 0x0020;
GPIOB->BSRR = 0x0100;

GPIOC->ODR = LCD_RegValue;
GPIOB->BRR = 0x0020;
GPIOB->BSRR = 0x0020;
GPIOB->BSRR = 0x0100;
/* 原有程序代码结束 */
GPIOC->ODR = PC_Out; //末行添加内容
}

下载调试

将程序修改好并编译下载到开发板上,此时可以看到屏幕能够正常显示欢迎提示语和 LED1 的 I/O 电平状态。