|
SHOW---LCD12864之模拟指针式时钟
[复制链接]
LCD12864是个好东西,之前介绍了用LCD12864显示一个简易的动画,以及用LCD12864做一个俄罗斯方块游戏,今天再介绍一点其他的好玩的东西-----用LCD12864做一个模拟指针式时钟。用LCD12864做一个模拟指针式时钟,其实主要用的是LCD12864(ST7920)的绘图功能: 1.利用圆心坐标和半径画一个圆作为表盘 2.利用两点间画线功能画出时分秒指针。 让我们一起来做一个LCD12864模拟指针式时钟,Let's GO!! LCD12864的底层驱动很简单,利用时序图可以轻松解决,这部分就跳过了。所以,我们首先要解决的是如何画圆。我在查找资料时,发现有好几种方法,我使用的是这种:/**************************************** 对称法画圆的8个镜像点 *****************************************/ void CircleDot(unsigned char x,unsigned char y,char xx,char yy,unsigned char Color)//内部函数,对称法画圆的8个镜像点 { Lcd_PutPixel((x+yy),(y+xx),Color);//第 1 个 8 分圆 Lcd_PutPixel((x+xx),(y+yy),Color);//第 2 个 8 分圆 Lcd_PutPixel((x-xx),(y+yy),Color);//第 3 个 8 分圆 Lcd_PutPixel((x-yy),(y+xx),Color);//第 4 个 8 分圆 Lcd_PutPixel((x-yy),(y-xx),Color);//第 5 个 8 分圆 Lcd_PutPixel((x-xx),(y-yy),Color);//第 6 个 8 分圆 Lcd_PutPixel((x+xx),(y-yy),Color);//第 7 个 8 分圆 Lcd_PutPixel((x+yy),(y-xx),Color);//第 8 个 8 分圆 }
/****************************************** 向LCD指定圆心坐标画一个半径为r的指定颜色的圆 *******************************************/ void Lcd_Circle(unsigned char x,unsigned char y,unsigned char r,unsigned char Color)//中点法画圆 {//中点法画圆 unsigned char xx,yy; char deltax,deltay,d; xx=0; yy=r; deltax=3; deltay=2-r-r; d=1-r; CircleDot(x,y,xx,yy,Color);//对称法画圆的8个镜像点 while (xx { if (d<0) { d+=deltax; deltax+=2; xx++; } else { d+=deltax+deltay; deltax+=2; deltay+=2; xx++; yy--; } CircleDot(x,y,xx,yy,Color);//对称法画圆的8个镜像点 } }
利用画圆函数可以先画出时钟的表盘,下一步,我们得再画出时分秒的指针。画时分秒的指针其实用到的是任意两点间画一条线这个功能,如何实现呢?答案是:布兰森汉姆(Bresenham)算法画线!在画线、画圆中经常会用到Bresenham算法,Bresenham算法是什么?如果你感兴趣的话,可以先搜一下,网上关于这个的介绍很多很多,我就不介绍了,上代码:/******************************************* 向LCD指定起始坐标和结束坐标之间画一条指定颜色的直线 ********************************************/ void Lcd_Line(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char Color) { unsigned int x,y; unsigned int d_x,d_y;//d_x=x2-x1;d_y=y2-y1; int err=0; unsigned char temp=0; if(y2 { x=x1; y=y1; x1=x2; y1=y2; x2=x; y2=y; } d_y=y2-y1; if (d_y==0) { if (x1>x2) { x=x1; x1=x2; x2=x; } for (x=x1;x<=x2;x++) Lcd_PutPixel(x,y1,Color); } else { if(x2>=x1) { temp=1; d_x=x2-x1; } else d_x=x1-x2; x=x1; y=y1; Lcd_PutPixel(x,y,Color); if(temp&&(d_y<=d_x)) while(x!=x2) { if(err<0) { x=x+1; err=err+(y2-y); } else { x=x+1; y=y+1; err=err+(y2-y)-(x2-x); } Lcd_PutPixel(x,y,Color); } else if(temp&&(d_y>d_x)) while(y!=y2) { d_x=x2-x; d_y=y2-y; if(err<0) { x=x+1; y=y+1; err=err+d_y-d_x; } else { y=y+1; err=err-d_x; } Lcd_PutPixel(x,y,Color); } else if(!temp&&(d_y<=d_x)) while(x!=x2) { d_x=x-x2; d_y=y2-y; if(err<0) { x=x-1; err=err+d_y; } else { x=x-1; y=y+1; err=err+d_y-d_x; } Lcd_PutPixel(x,y,Color); } else if(!temp &&(d_y>d_x)) { while(y!=y2) { d_x=x-x2; d_y=y2-y; if(err<0) { x=x-1; y=y+1; err=err+d_y-d_x; } else { y=y+1; err=err-d_x; } Lcd_PutPixel(x,y,Color); } } } }
有了画线的方法,我们还不能画出时分秒指针,因为画线需要起点坐标和末点坐标。指针是从圆心这一点指向这一刻时间的一条线,起点坐标有了,就是圆盘的圆心坐标,但是末点坐标不知道。比如1秒,秒针由圆心坐标指向1秒的位置,这个1秒的位置在哪??我们可以由圆心坐标和半径,以及时间的角度算出:/*************************************************** 函数名称:LcdTimeX(uint8 Length,uint8 Angle) 函数功能:计算指针的X坐标 输入参数:circle_x:圆心横坐标 Length :半径长度 Angle :角度 输出参数: x坐标 ****************************************************/ unsigned char Lcd_TimeX(unsigned char circle_x,unsigned char Length,unsigned char Angle) { unsigned char x; if((Angle>0) && (Angle<=15)) { x = circle_x + Length * (sin(PI * Angle / 30)); } else if(Angle > 15 && Angle <= 30) { x = circle_x + Length * cos((PI * Angle) / 30 - (PI / 2 )); } else if(Angle > 30 && Angle <= 45) { x = circle_x - Length * sin((PI * Angle) / 30- PI); } else { x = circle_x-Length * cos((PI * Angle) / 30 - ((3 * PI) / 2)); } return x; }
/*************************************************** 函数名称:LcdTimeY(uint8 Length,uint8 Angle) 函数功能:计算指针的Y坐标 输入参数:circle_y:圆心纵坐标 Length :半径长度 Angle :角度 输出参数: Y坐标 ****************************************************/ unsigned char Lcd_TimeY(unsigned char circle_y,unsigned char Length,unsigned char Angle) { unsigned char y; if((Angle>0) && (Angle<=15)) { y = circle_y - Length * (cos(PI * Angle / 30)); } else if(Angle > 15 && Angle <= 30) { y = circle_y + Length * sin((PI * Angle) / 30 - (PI / 2 )); } else if(Angle > 30 && Angle <= 45) { y = circle_y + Length * cos((PI * Angle) / 30- PI); } else { y = circle_y - Length * sin((PI * Angle) / 30 - ((3 * PI) / 2)); } return y; }
好了,所有的东西都准备齐全了,开工!! 先画表盘:void init_Point_Clock() //初始化表盘 { unsigned char i; Lcd_Circle(32,32,31,1);//画圆 圆心坐标(32,32) 半径31 for(i=0;i<60;i++) { if((i%5)==0) //画刻度 { Lcd_Line(Lcd_TimeX(32,30,i),Lcd_TimeY(32,30,i),Lcd_TimeX(32,27,i),Lcd_TimeY(32,27,i),1); } } } 我用的是定时器做的,这一时刻的时间与上一时刻不一样时,把上一时刻的指针消除掉,显示这一时刻的指针
//【0】:上一时刻时间 //【1】:这一时刻时间 struct POINT_CLOCK { unsigned char hour; unsigned char minute; unsigned char second;
}Point_Time[2];
/*======================================================================== *name:Display_Pointer(struct POINT_CLOCK AA,unsigned char color) *function:显示时、分、秒指针 *参 数:结构体: 时分秒 * color: 0不显示 1:显示 *注:秒针长24 分针长17 秒针长12 =========================================================================*/ void Display_Pointer(struct POINT_CLOCK AA,unsigned char color) //指针显示 { Lcd_Line(Lcd_TimeX(32,24,AA.second),Lcd_TimeY(32,24,AA.second),32,32,color); Lcd_Line(Lcd_TimeX(32,17,AA.minute),Lcd_TimeY(32,17,AA.minute),32,32,color); Lcd_Line(Lcd_TimeX(32,12,AA.minute/10+5*(AA.hour%12)),Lcd_TimeY(32,12,AA.minute/10+5*(AA.hour%12)),32,32,color); }
/*======================================================================== *name:Display_PointClock(struct POINT_CLOCK AA,unsigned char color) *function:显示时、分、秒指针 *参 数:结构体0:存放上一个时分秒 》》》两者不同时,刷新显示 结构体1:存放这一个时分秒 》》》 * * color:0不显示 1:显示 =========================================================================*/ void Display_PointClock() //指针式时钟显示 { if(Point_Time[0].second!=Point_Time[1].second) //秒刷新 { Lcd_Line(Lcd_TimeX(32,24,Point_Time[0].second),Lcd_TimeY(32,24,Point_Time[0].second),32,32,0); } if(Point_Time[0].minute!=Point_Time[1].minute) //分刷新 { Lcd_Line(Lcd_TimeX(32,17,Point_Time[0].minute),Lcd_TimeY(32,17,Point_Time[0].minute),32,32,0); } if((Point_Time[0].minute/10+5*(Point_Time[0].hour%12))!=(Point_Time[1].minute/10+5*(Point_Time[1].hour%12))) //时刷新显示 { Lcd_Line(Lcd_TimeX(32,12,Point_Time[0].minute/10+5*(Point_Time[0].hour%12)),Lcd_TimeY(32,12,Point_Time[0].minute/10+5(Point_Time[0].hour%12)),32,32,0); } Display_Pointer(Point_Time[1],1); //现在的指针式时钟显示 Point_Time[0]=Point_Time[1]; }
效果图如下所示:
注:没怎么发过帖子,所以不知道怎么跟大家讲这些东西,能用代码的直接粘代码了。因为自己感觉这些东西很好玩,所以想跟大家分享一下,如果有什么不懂,可以留言一些资料:
12864液晶屏上画圆算法函数(源代码).pdf
(74.9 KB, 下载次数: 533)
12864画圆资料.pdf
(184.53 KB, 下载次数: 468)
[ 本帖最后由 季夏木槿 于 2013-8-21 22:05 编辑 ]
|
赞赏
-
1
查看全部赞赏
-
|