上次实验了点灯,对CW32饭盒派的操作有了初步的了解,基本上也是按照给的实验案例跑通并下载看下效果,没有改动代码,但也借此熟悉了一下开发方法,和stm32很类似。因此也能够更好的移植相关代码。还剩下4个例程,准备自己改一下代码,将温湿度测试案例与tft屏幕案例进行结合。
拟实现功能是:每2秒采集一次dht11温湿度传感器数据,再在tft_LCD上显示,同时判断是否是舒适环境,是的话显示笑脸,不是的话,显示怒脸,哈哈。
这里基本都是将原有代码模块进行整合,所不同的是为了画脸,需要修改增加一下画半圆的代码,为此研究了一下lcd_driver.c中相关代码,可以看到,画直线和画圆圈,都采用了bresenham算法。这里简要介绍一下。
Bresenham算法是计算机图形学领域使用最广泛的直线扫描转换方法。bresenham算法是计算机图形学中为了"显示器(屏幕或打印机)系由像素构成"的这个特性而设计出来的算法,使得在求直线各点的过程中全部以整数来运算,因而大幅度提升计算速度。其原理是过各行、各列像素中心构造一组虚拟网格线,按直线从起点到终点的顺序计算直线各垂直网格线的交点,然后确定该列像素中与此交点最近的像素。优点在于该算法的优点在于可以采用增量计算,使得对于每一列,只要检查一个误差项的符号,就可以确定该列所求的像素。具体可以看下网上或b站介绍。
在实验例程“TFT 彩屏实验”进行修改设计,主要添加了温湿度传感器读取的驱动部分,RTC时钟显示部分,同时为了测试画图效果,对温湿度进行判断,当温湿度达到适宜值时,显示笑脸,否则显示哭脸。查看了下lcd画线代码,发现只有画线Gui_DrawLine()和画圆圈Gui_Circle()的代码,采用的都是Bresenham法,为了画出半圆,自己修改了LCD_calculate.c/.h,添加了2个函数
void Gui_Up_SemiCircle(unsigned int X,unsigned int Y,unsigned int R,unsigned int fc)
{
//Bresenham
unsigned short a,b;
int c;
a=0;
b=R;
c=3-2*R;
while (a<b)
{
Gui_DrawPoint(X+a,Y-b,fc); // 2
Gui_DrawPoint(X-a,Y-b,fc); // 3
Gui_DrawPoint(X+b,Y-a,fc); // 1
Gui_DrawPoint(X-b,Y-a,fc); // 4
if(c<0) c=c+4*a+6;
else
{
c=c+4*(a-b)+10;
b-=1;
}
a+=1;
}
if (a==b)
{
Gui_DrawPoint(X+a,Y-b,fc);
Gui_DrawPoint(X-a,Y-b,fc);
Gui_DrawPoint(X+b,Y-a,fc);
Gui_DrawPoint(X-b,Y-a,fc);
}
}
void Gui_Down_SemiCircle(unsigned int X,unsigned int Y,unsigned int R,unsigned int fc)
{
//Bresenham
unsigned short a,b;
int c;
a=0;
b=R;
c=3-2*R;
while (a<b)
{
Gui_DrawPoint(X+a,Y+b,fc); // 7
Gui_DrawPoint(X-a,Y+b,fc); // 6
Gui_DrawPoint(X+b,Y+a,fc); // 8
Gui_DrawPoint(X-b,Y+a,fc); // 5
if(c<0) c=c+4*a+6;
else
{
c=c+4*(a-b)+10;
b-=1;
}
a+=1;
}
if (a==b)
{
Gui_DrawPoint(X+a,Y+b,fc);
Gui_DrawPoint(X+a,Y+b,fc);
Gui_DrawPoint(X+b,Y+a,fc);
Gui_DrawPoint(X-b,Y+a,fc);
}
}
再在main函数中添加笑脸和哭脸的代码
static void Gui_Draw_Happyface(unsigned int x, unsigned int y,unsigned int fc)
{
unsigned int R = 20;
Lcd_Clear_1(GRAY0);
Gui_Circle(x, y, R, fc);
Gui_Up_SemiCircle((x - (R>>1)), (y - (R>>1)), R>>2, fc);
Gui_Up_SemiCircle((x + (R>>1)), (y - (R>>1)), R>>2, fc);
Gui_DrawPoint(x, y, fc);
Gui_Down_SemiCircle(x, y, R>>1, fc);
}
static void Gui_Draw_Sadface(unsigned int x, unsigned int y,unsigned int fc)
{
unsigned int R = 20;
Lcd_Clear_1(GRAY0);
Gui_Circle(x, y, R, fc);
Gui_Down_SemiCircle((x - (R>>1)), (y - (R>>1)), R>>2, fc);
Gui_Down_SemiCircle((x + (R>>1)), (y - (R>>1)), R>>2, fc);
Gui_DrawPoint(x, y, fc);
Gui_Up_SemiCircle(x, (y + (R>>1)), R>>1, fc);
}
在main()的while循环中,每秒中读出温湿度并保存在float型变量后,再判断是否满足适宜度要求,这里适宜度要求根据经验值设置,但是为了显示效果,能够在视频中显示变化,修改了下范围
if((temperature < 31) && (temperature > 23.9) && (humidity < 40) && (humidity > 30))
{
Gui_Draw_Happyface(64, 80, RED);
}
else
{
Gui_Draw_Sadface(64, 100, BLACK);
}
基本实现功能。