基于 GD32F303ZET6 苹果派开发板
简介
按键,可以有矩形、圆形、星形等形状。机器做按键扫描时,往往更倾向于扫描矩形按键,因为矩形按键只需要通过简单的比较即可得知按键是否被按下;圆形按键扫描时,往往要通过勾股定理求得触点与按键中心的距离,速度上会慢一些,星形等其它图案则更慢了。
在实际的项目中,我们不可能像之前的实验那样,用简单的蓝色和绿色区分按键按下与否,不然太过于单调,显得不是特别高级。然而用画点画线函数很难做出想要的效果,不是太突兀,就是毛刺特别多,显示效果不好。这时候我们可以选择使用图片包装美化按键,在按键所在位置贴上一张图片即可,简单又实用。如果使用的图片是 32 位位图或 PNG 图片,还可以让按键与背景完美融合,边沿虚化、圆弧效果都可以实现。
按键控制结构体设计
因为引入了图片,原先的按键控制结构体不再适用,需要修改一些,具体就是增加了三个成员变量。pressImage 和 releaseImage,都是 void* 类型指针,用来保存按键图片首地址,这里默认按键的图片类型为位图。background 用于保存按键的背景,因为按键控件涉及到两张图片,分别是按下时和抬起时显示的图片,如果两张图片均使用位图或 PNG,那么就容易产生混叠,和绘制文字时混叠一样,此时需要将背景提前保存下来,每次刷新图片显示之前,首先填充背景,这样就能避免混叠。
//按键控件
typedef struct
{
u16 x, y, width, height; //原点、宽度、高度
char* text; //按键名字
u8 textSize; //字体大小,可以是 12、16、24
u16 textColor; //字体颜色
u8 lastState; //按键上一个状态,0-按下,1-抬起
u16 pressColor; //按键按下时的颜色
u16 releaseColor; //按键抬起时显示的颜色
void* pressImage; //按键按下时显示的图片,不用时请填入 NULL
void* releaseImage; //按键抬起时显示的图片,不用时请填入 NULL
u16* background; //按键背景
}StructButton;
按键创建函数
按键创建函数,即 ButtonCreate 需要做出修改,如果用户选用了图片包装,那么就显示按键抬起图片。
//创建按键
void ButtonCreate(StructButton* widget)
{
u16 x, y, x0, y0, x1, y1, i;
//计算按键起点和终点
x0 = widget->x;
y0 = widget->y;
x1 = x0 + widget->width - 1;
y1 = y0 + widget->height - 1;
//保存按键背景
if((NULL != widget->pressImage) || (NULL != widget->releaseImage))
{
//为背景申请动态内存
widget->background = (u16*)malloc(widget->width * widget->height * 2);
//保存按键背景
i = 0;
for(y = y0; y <= y1; y++)
{
for(x = x0; x < x1; x++)
{
widget->background[i++] = LCDReadPoint(x, y);
}
}
}
else
{
widget->background = NULL;
}
//设置按键初始状态
widget->lastState = 0;
if(NULL != widget->releaseImage)
{
DrawBMP(widget->releaseImage, x0, y0);
}
else
{
LCDFill(x0, y0, x1, y1, widget->releaseColor);
}
//刷新名字显示
ShowText(widget);
}
按键扫描函数
同样的,按键扫描函数也要做出修改,用以支持图片包装。
//按键扫描,返回:1-检测到按键按下,0-未检测到按键按下
u8 ButtonScan(StructButton* widget)
{
u16 x, y, x0, y0, x1, y1, i;
u8 currentState;
u8 ret;
//默认返回 0
ret = 0;
//计算按键起点和终点
x0 = widget->x;
y0 = widget->y;
x1 = x0 + widget->width - 1;
y1 = y0 + widget->height - 1;
//触屏扫描
currentState = 0;
if(ScanTouch(&x, &y))
{
//触点落在了目标区域
if((x >= x0) && (x <= x1) && (y >= y0) && (y <= y1))
{
currentState = 1;
}
else
{
currentState = 0;
}
}
//上一个状态是抬起而当前状态为按下,表示捕捉到了一个按下事件
if((0 == widget->lastState) && (1 == currentState))
{
//需要绘制图片
if(NULL != widget->pressImage)
{
//绘制背景
i = 0;
for(x = x0; x <= x1; x++)
{
for(y = y0; y < y1; y++)
{
LCDFastDrawPoint(x, y, widget->background[i++]);
}
}
//绘制图片
DrawBMP(widget->pressImage, x0, y0);
}
//不需要绘制图片
else
{
LCDFill(x0, y0, x1, y1, widget->pressColor);
}
ret = 1;
}
//上一个状态是按下而当前状态为抬起,表示捕捉到了一个抬起事件
else if((1 == widget->lastState) && (0 == currentState))
{
//需要绘制图片
if(NULL != widget->releaseImage)
{
//绘制背景
i = 0;
for(x = x0; x <= x1; x++)
{
for(y = y0; y < y1; y++)
{
LCDFastDrawPoint(x, y, widget->background[i++]);
}
}
//绘制图片
DrawBMP(widget->releaseImage, x0, y0);
}
//不需要绘制图片
else
{
LCDFill(x0, y0, x1, y1, widget->releaseColor);
}
ret = 0;
}
//保存当前状态
widget->lastState = currentState;
//刷新名字显示
ShowText(widget);
//返回测量结果
return ret;
}
测试
经过简单的修改,我们的按键驱动就支持了图片封装,前提是工程里要提前移植好图片显示驱动。用于包装按键的图片可以是 BMP、PNG,甚至是 JPEG 和 GIF,在这里我们限定了只能是 BMP,实际上,我们可以更改为其它任何类型的图片。在这里推荐使用博主提供的 AnythingToC 小工具,可以将任意文件转换成 C 语言数组,方便用户将图片、音频等内嵌到单片机的 Flash 中。
测试代码如下所示。
void main(void)
{
extern const unsigned char s_arrKeyPressBmpImage[20138];
extern const unsigned char s_arrKeyReleaseBmpImage[20138];
static StructButton s_structButton;
//初始化
...
//创建按键
s_structButton.x = 350;
s_structButton.y = 215;
s_structButton.width = 100;
s_structButton.height = 50;
s_structButton.text = "BUTTON";
s_structButton.textSize = 24;
s_structButton.textColor = BLACK;
s_structButton.pressColor = BLUE;
s_structButton.releaseColor = GREEN;
s_structButton.pressImage = (void*)s_arrKeyPressBmpImage;
s_structButton.releaseImage = (void*)s_arrKeyReleaseBmpImage;
ButtonCreate(&s_structButton);
//主循环
while(1)
{
//LED 闪烁
LEDFlicker(50);
//按键扫描
if(1 == ButtonScan(&s_structButton))
{
printf("Button press\r\n");
}
//延时 10 ms
DelayNms(10);
}
}
实验结果
实验结果如下所示。点击按键时,会出现闪烁的情况,主要是因为按键切换状态时,首先刷新背景,即背景重绘,然后才显示按键的背景图片。为了避免按键闪烁,我们也可以采样 JPEG 图片装饰按键。因为 JPEG 没有透明度,所以可以直接绘图,因为无需做背景重绘,所以闪烁现象自然就消失了。
-带背景图片的按键控件-实验结果-20230304-1024x768.jpg)
源码
本章节中的源码请参考《单片机 GUI 设计(零)- 大纲》