[DemoCode下载] SHOW---LCD12864之模拟指针式时钟

[复制链接]
1513|14
 楼主| C洛达尔多 发表于 2015-12-17 20:23 | 显示全部楼层 |阅读模式
LCD12864是个好东西,之前介绍了用LCD12864显示一个简易的动画,以及用LCD12864做一个俄罗斯方块游戏,今天再介绍一点其他的好玩的东西-----用LCD12864做一个模拟指针式时钟。用LCD12864做一个模拟指针式时钟,其实主要用的是LCD12864(ST7920)的绘图功能:
      1.利用圆心坐标和半径画一个圆作为表盘
      2.利用两点间画线功能画出时分秒指针。
      让我们一起来做一个LCD12864模拟指针式时钟,Let's GO!!
     LCD12864的底层驱动很简单,利用时序图可以轻松解决,这部分就跳过了。所以,我们首先要解决的是如何画圆。我在查找资料时,发现有好几种方法,我使用的是这种:

 楼主| C洛达尔多 发表于 2015-12-17 20:24 | 显示全部楼层
  1.             /****************************************

  2.             对称法画圆的8个镜像点

  3.             *****************************************/

  4.             void CircleDot(unsigned char x,unsigned char y,char xx,char yy,unsigned char Color)//内部函数,对称法画圆的8个镜像点

  5.             {

  6.                     Lcd_PutPixel((x+yy),(y+xx),Color);//第 1 个 8 分圆

  7.                     Lcd_PutPixel((x+xx),(y+yy),Color);//第 2 个 8 分圆

  8.                     Lcd_PutPixel((x-xx),(y+yy),Color);//第 3 个 8 分圆

  9.                     Lcd_PutPixel((x-yy),(y+xx),Color);//第 4 个 8 分圆

  10.                     Lcd_PutPixel((x-yy),(y-xx),Color);//第 5 个 8 分圆

  11.                     Lcd_PutPixel((x-xx),(y-yy),Color);//第 6 个 8 分圆

  12.                     Lcd_PutPixel((x+xx),(y-yy),Color);//第 7 个 8 分圆

  13.                     Lcd_PutPixel((x+yy),(y-xx),Color);//第 8 个 8 分圆

  14.             }


  15.             /******************************************

  16.             向LCD指定圆心坐标画一个半径为r的指定颜色的圆

  17.             *******************************************/

  18.             void Lcd_Circle(unsigned char x,unsigned char y,unsigned char r,unsigned char Color)//中点法画圆

  19.             {//中点法画圆

  20.                     unsigned char xx,yy;

  21.                     char deltax,deltay,d;

  22.                     xx=0;

  23.                     yy=r;

  24.                     deltax=3;

  25.                     deltay=2-r-r;

  26.                     d=1-r;

  27.                     CircleDot(x,y,xx,yy,Color);//对称法画圆的8个镜像点

  28.                     while (xx

  29.                         {

  30.                                 if (d<0)

  31.                                 {

  32.                                         d+=deltax;

  33.                                         deltax+=2;

  34.                                         xx++;

  35.                                 }

  36.                                 else

  37.                                 {

  38.                                         d+=deltax+deltay;

  39.                                         deltax+=2;

  40.                                         deltay+=2;

  41.                                         xx++;

  42.                                         yy--;

  43.                                 }

  44.                                 CircleDot(x,y,xx,yy,Color);//对称法画圆的8个镜像点

  45.                         }

  46.                 }
 楼主| C洛达尔多 发表于 2015-12-17 20:24 | 显示全部楼层
利用画圆函数可以先画出时钟的表盘,下一步,我们得再画出时分秒的指针。画时分秒的指针其实用到的是任意两点间画一条线这个功能,如何实现呢?答案是:布兰森汉姆(Bresenham)算法画线!在画线、画圆中经常会用到Bresenham算法,Bresenham算法是什么?如果你感兴趣的话,可以先搜一下,网上关于这个的介绍很多很多,我就不介绍了,上代码:
 楼主| C洛达尔多 发表于 2015-12-17 20:25 | 显示全部楼层
  1.         /*******************************************

  2.         向LCD指定起始坐标和结束坐标之间画一条指定颜色的直线

  3.         ********************************************/

  4.         void Lcd_Line(unsigned char x1,unsigned char y1,unsigned char x2,unsigned char y2,unsigned char Color)

  5.         {

  6.                 unsigned int x,y;

  7.                 unsigned int d_x,d_y;//d_x=x2-x1;d_y=y2-y1;

  8.                 int err=0;

  9.                 unsigned char temp=0;

  10.                 if(y2

  11.                     {

  12.                             x=x1;

  13.                             y=y1;

  14.                             x1=x2;

  15.                             y1=y2;

  16.                             x2=x;

  17.                             y2=y;

  18.                     }

  19.                     d_y=y2-y1;

  20.                     if (d_y==0)

  21.                     {

  22.                             if (x1>x2)

  23.                             {

  24.                                     x=x1;

  25.                                     x1=x2;

  26.                                     x2=x;

  27.                             }

  28.                             for (x=x1;x<=x2;x++)

  29.                                     Lcd_PutPixel(x,y1,Color);

  30.                     }

  31.                    

  32.                     else

  33.                     {

  34.                             if(x2>=x1)

  35.                             {

  36.                                     temp=1;

  37.                                     d_x=x2-x1;

  38.                             }

  39.                             else

  40.                             d_x=x1-x2;

  41.                             x=x1;

  42.                             y=y1;

  43.                             Lcd_PutPixel(x,y,Color);

  44.                    

  45.                             if(temp&&(d_y<=d_x))

  46.                             while(x!=x2)

  47.                             {

  48.                                     if(err<0)

  49.                                     {

  50.                                             x=x+1;

  51.                                             err=err+(y2-y);

  52.                                     }

  53.                                     else

  54.                                     {

  55.                                             x=x+1;

  56.                                             y=y+1;

  57.                                             err=err+(y2-y)-(x2-x);

  58.                                     }

  59.                                     Lcd_PutPixel(x,y,Color);

  60.                             }

  61.                    

  62.                             else if(temp&&(d_y>d_x))

  63.                             while(y!=y2)

  64.                             {

  65.                                     d_x=x2-x;

  66.                                     d_y=y2-y;

  67.                                     if(err<0)

  68.                                     {

  69.                                             x=x+1;

  70.                                             y=y+1;

  71.                                             err=err+d_y-d_x;

  72.                                     }

  73.                                     else

  74.                                     {

  75.                                             y=y+1;

  76.                                             err=err-d_x;

  77.                                     }

  78.                                     Lcd_PutPixel(x,y,Color);

  79.                                    

  80.                             }

  81.                    

  82.                             else if(!temp&&(d_y<=d_x))

  83.                             while(x!=x2)

  84.                             {

  85.                                     d_x=x-x2;

  86.                                     d_y=y2-y;

  87.                                     if(err<0)

  88.                                     {

  89.                                             x=x-1;

  90.                                             err=err+d_y;

  91.                                     }

  92.                                     else

  93.                                     {

  94.                                             x=x-1;

  95.                                             y=y+1;

  96.                                             err=err+d_y-d_x;

  97.                                     }

  98.                                     Lcd_PutPixel(x,y,Color);

  99.                             }

  100.                    

  101.                             else if(!temp &&(d_y>d_x))

  102.                             {

  103.                                     while(y!=y2)

  104.                                     {

  105.                                             d_x=x-x2;

  106.                                             d_y=y2-y;

  107.                                             if(err<0)

  108.                                             {

  109.                                                     x=x-1;

  110.                                                     y=y+1;

  111.                                                     err=err+d_y-d_x;

  112.                                             }

  113.                                             else

  114.                                             {

  115.                                                     y=y+1;

  116.                                                     err=err-d_x;

  117.                                             }

  118.                                             Lcd_PutPixel(x,y,Color);

  119.                                     }

  120.                             }

  121.                     }

  122.             }
 楼主| C洛达尔多 发表于 2015-12-17 20:26 | 显示全部楼层
有了画线的方法,我们还不能画出时分秒指针,因为画线需要起点坐标和末点坐标。指针是从圆心这一点指向这一刻时间的一条线,起点坐标有了,就是圆盘的圆心坐标,但是末点坐标不知道。比如1秒,秒针由圆心坐标指向1秒的位置,这个1秒的位置在哪??我们可以由圆心坐标和半径,以及时间的角度算出:
 楼主| C洛达尔多 发表于 2015-12-17 20:26 | 显示全部楼层
  1.     /***************************************************

  2.     函数名称:LcdTimeX(uint8 Length,uint8 Angle)

  3.     函数功能:计算指针的X坐标

  4.     输入参数:circle_x:圆心横坐标

  5.               Length  :半径长度

  6.                      Angle   :角度

  7.     输出参数: x坐标

  8.     ****************************************************/

  9.     unsigned char Lcd_TimeX(unsigned char circle_x,unsigned char Length,unsigned char Angle)

  10.     {

  11.        unsigned char x;

  12.        if((Angle>0) && (Angle<=15))

  13.        {  

  14.          x = circle_x + Length * (sin(PI * Angle / 30));   

  15.        }

  16.        else if(Angle > 15 && Angle <= 30)   

  17.        {  

  18.           x = circle_x + Length * cos((PI * Angle) / 30 - (PI / 2 ));

  19.        }

  20.        else if(Angle > 30 && Angle <= 45)

  21.        {

  22.            x = circle_x - Length * sin((PI * Angle) / 30- PI);

  23.        }

  24.        else

  25.        {

  26.            x = circle_x-Length * cos((PI * Angle) / 30 - ((3 * PI) / 2));

  27.        }  

  28.             return x;                       

  29.     }
 楼主| C洛达尔多 发表于 2015-12-17 20:27 | 显示全部楼层
  1.     /***************************************************

  2.     函数名称:LcdTimeY(uint8 Length,uint8 Angle)

  3.     函数功能:计算指针的Y坐标

  4.     输入参数:circle_y:圆心纵坐标

  5.               Length  :半径长度

  6.                      Angle   :角度

  7.     输出参数: Y坐标

  8.     ****************************************************/

  9.     unsigned char Lcd_TimeY(unsigned char circle_y,unsigned char Length,unsigned char Angle)

  10.     {

  11.        unsigned char y;

  12.        if((Angle>0) && (Angle<=15))

  13.        {  

  14.           y = circle_y - Length * (cos(PI * Angle / 30));   

  15.        }

  16.        else if(Angle > 15 && Angle <= 30)   

  17.        {  

  18.           y = circle_y + Length * sin((PI * Angle) / 30 - (PI / 2 ));

  19.        }

  20.        else if(Angle > 30 && Angle <= 45)

  21.        {

  22.            y = circle_y + Length * cos((PI * Angle) / 30- PI);

  23.        }

  24.        else

  25.        {

  26.            y = circle_y - Length * sin((PI * Angle) / 30 - ((3 * PI) / 2));

  27.        }

  28.        return y;                       

  29.     }
 楼主| C洛达尔多 发表于 2015-12-17 20:28 | 显示全部楼层
好了,所有的东西都准备齐全了,开工!!
   
先画表盘:
  1. void init_Point_Clock() //初始化表盘
  2. {
  3.       unsigned char i;
  4.       Lcd_Circle(32,32,31,1);//画圆  圆心坐标(32,32) 半径31
  5.       for(i=0;i<60;i++)
  6.      {
  7.         if((i%5)==0)      //画刻度
  8.        {
  9.            Lcd_Line(Lcd_TimeX(32,30,i),Lcd_TimeY(32,30,i),Lcd_TimeX(32,27,i),Lcd_TimeY(32,27,i),1);                                       
  10.        }
  11.     }
  12. }
 楼主| C洛达尔多 发表于 2015-12-17 20:28 | 显示全部楼层
我用的是定时器做的,这一时刻的时间与上一时刻不一样时,把上一时刻的指针消除掉,显示这一时刻的指针
//【0】:上一时刻时间
//【1】:这一时刻时间
  1. struct POINT_CLOCK
  2. {
  3.         unsigned char hour;
  4.         unsigned char minute;
  5.         unsigned char second;

  6. }Point_Time[2];


  7. /*========================================================================
  8. *name:Display_Pointer(struct POINT_CLOCK AA,unsigned char color)
  9. *function:显示时、分、秒指针
  10. *参    数:结构体: 时分秒   
  11. *                   color: 0不显示  1:显示
  12. *注:秒针长24
  13.         分针长17
  14.          秒针长12
  15. =========================================================================*/
  16. void Display_Pointer(struct POINT_CLOCK AA,unsigned char color)        //指针显示
  17. {
  18.         Lcd_Line(Lcd_TimeX(32,24,AA.second),Lcd_TimeY(32,24,AA.second),32,32,color);         
  19.         Lcd_Line(Lcd_TimeX(32,17,AA.minute),Lcd_TimeY(32,17,AA.minute),32,32,color);        
  20.         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);                                                         
  21. }

 楼主| C洛达尔多 发表于 2015-12-17 20:29 | 显示全部楼层
  1. /*========================================================================
  2. *name:Display_PointClock(struct POINT_CLOCK AA,unsigned char color)
  3. *function:显示时、分、秒指针
  4. *参    数:结构体0:存放上一个时分秒   》》》两者不同时,刷新显示
  5.            结构体1:存放这一个时分秒   》》》
  6. *
  7. *                   color:0不显示  1:显示
  8. =========================================================================*/
  9. void Display_PointClock()        //指针式时钟显示
  10. {
  11.         if(Point_Time[0].second!=Point_Time[1].second)      //秒刷新
  12.         {
  13.                 Lcd_Line(Lcd_TimeX(32,24,Point_Time[0].second),Lcd_TimeY(32,24,Point_Time[0].second),32,32,0);
  14.         }
  15.         if(Point_Time[0].minute!=Point_Time[1].minute)    //分刷新
  16.         {
  17.                  Lcd_Line(Lcd_TimeX(32,17,Point_Time[0].minute),Lcd_TimeY(32,17,Point_Time[0].minute),32,32,0);        
  18.         }
  19.         if((Point_Time[0].minute/10+5*(Point_Time[0].hour%12))!=(Point_Time[1].minute/10+5*(Point_Time[1].hour%12)))   //时刷新显示
  20.         {
  21.         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);        
  22.         }
  23.         Display_Pointer(Point_Time[1],1);        //现在的指针式时钟显示
  24.         Point_Time[0]=Point_Time[1];
  25. }
落叶行健ywm 发表于 2015-12-21 16:39 | 显示全部楼层
不错,没事的时候测试下!
jy6715 发表于 2015-12-22 09:28 | 显示全部楼层
谢谢分享
bkn1860 发表于 2015-12-22 09:43 | 显示全部楼层
刚好用手上的12864玩玩,谢谢分享
捉虫天师 发表于 2016-1-31 14:29 | 显示全部楼层

谢谢分享
quray1985 发表于 2016-2-1 16:21 | 显示全部楼层
12864的屏有没有彩屏啊,做个俄罗斯方块挺好玩的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

28

主题

236

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部