15377|36

577

帖子

9

TA的资源

纯净的硅(中级)

楼主
 

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 编辑 ]
查看本帖全部内容,请登录或者注册
此帖出自51单片机论坛

最新回复

好东西!谢谢分享.   详情 回复 发表于 2021-6-21 14:26

赞赏

1

查看全部赞赏

点赞(3) 关注(5)
 

回复
举报

34

帖子

0

TA的资源

一粒金砂(初级)

推荐
 
求仿真图及代码,942647200@qq。com可能的话发我邮箱
此帖出自51单片机论坛

点评

源代码在我的下载资源里  详情 回复 发表于 2013-11-25 19:43
 
 
 

回复

178

帖子

2

TA的资源

一粒金砂(中级)

板凳
 
好东西啊!求完整的代码!
此帖出自51单片机论坛

点评

源代码在我的下载资源里  详情 回复 发表于 2013-11-25 10:33
 
 
 

回复

553

帖子

0

TA的资源

纯净的硅(中级)

4
 
此帖出自51单片机论坛

点评

建议你用彩屏做,那个效果好:) :)  详情 回复 发表于 2013-8-23 16:07
 
 
 

回复

360

帖子

0

TA的资源

纯净的硅(初级)

5
 
很好的專題
此帖出自51单片机论坛
 
 
 

回复

4996

帖子

19

TA的资源

裸片初长成(初级)

6
 
分辨率问题,实际效果还是不怎么样,如果用彩屏就很不错。
此帖出自51单片机论坛

点评

你说的很对,效果确实不能和彩屏相比,画出来的时候,有的线是不太直的:lol :lol  详情 回复 发表于 2013-8-23 16:05
 
个人签名我的博客
 
 

回复

577

帖子

9

TA的资源

纯净的硅(中级)

7
 

回复 5楼zhaojun_xf 的帖子

你说的很对,效果确实不能和彩屏相比,画出来的时候,有的线是不太直的
此帖出自51单片机论坛

点评

楼主,为什么算出横坐标的,那个sin里面的是那样子算,按数学方法来算的话不对呀。。求告解  详情 回复 发表于 2015-12-11 22:44
 
 
 

回复

577

帖子

9

TA的资源

纯净的硅(中级)

8
 

回复 板凳在路上的旁观者 的帖子

建议你用彩屏做,那个效果好
此帖出自51单片机论坛
 
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

9
 
while (xx
   if(y2
都是缺失的,程序少了些,能发完整的就好了
此帖出自51单片机论坛
 
 
 

回复

577

帖子

9

TA的资源

纯净的硅(中级)

10
 

回复 沙发shaoye7031 的帖子

源代码在我的下载资源里
此帖出自51单片机论坛
 
个人签名哈喽,我是卡索KaSuo~~
 
 

回复

577

帖子

9

TA的资源

纯净的硅(中级)

11
 

回复 8楼daidong110 的帖子

源代码在我的下载资源里
此帖出自51单片机论坛
 
个人签名哈喽,我是卡索KaSuo~~
 
 

回复

34

帖子

0

TA的资源

一粒金砂(中级)

12
 
程序调试出来了,在display函数显示字符串下面有下划线是,开始关上绘图就没有了,谢谢楼主分享
此帖出自51单片机论坛

点评

恭喜了:)  详情 回复 发表于 2013-11-26 21:25
 
 
 

回复

577

帖子

9

TA的资源

纯净的硅(中级)

13
 

回复 12楼lsm123 的帖子

恭喜了
此帖出自51单片机论坛
 
个人签名哈喽,我是卡索KaSuo~~
 
 

回复

8

帖子

0

TA的资源

一粒金砂(初级)

14
 
好东西,要是仿真图和程序一起上就好了
此帖出自51单片机论坛
 
 
 

回复

6

帖子

0

TA的资源

一粒金砂(初级)

15
 
很完整的專題介紹,很棒!
此帖出自51单片机论坛
 
 
 

回复

846

帖子

0

TA的资源

纯净的硅(中级)

16
 
不错!!
此帖出自51单片机论坛
 
 
 

回复

29

帖子

0

TA的资源

一粒金砂(中级)

17
 
好东西!谢谢分享!
此帖出自51单片机论坛
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

18
 
很好
此帖出自51单片机论坛
 
 
 

回复

19

帖子

0

TA的资源

一粒金砂(初级)

19
 
下载资源在哪里啊!!!!!!!!!!!!!
此帖出自51单片机论坛
 
 
 

回复

20

帖子

0

TA的资源

一粒金砂(初级)

20
 
学学
此帖出自51单片机论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
有奖直播:当AI遇见仿真,会有什么样的电子行业革新之路?
首场直播:Simcenter AI 赋能电子行业研发创新
直播时间:04月15日14:00-14:50

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网 1

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表