打印

还是时钟问题,把时钟程序分开成3个文件了

[复制链接]
楼主: 雷影少年
手机看帖
扫描二维码
随时随地手机跟帖
21
雷影少年|  楼主 | 2012-7-5 12:19 | 只看该作者 回帖奖励 |倒序浏览
再次感谢版主

使用特权

评论回复
22
雷影少年|  楼主 | 2012-7-5 12:20 | 只看该作者
void get_clock(u8 sec,min,hour)
在这里只转换一次点阵即可
另外你这个写法也...
void get_clock(u8 sec, u8  min, u8  hour)
sedatefire 发表于 2012-7-5 12:03

这里不错代码运行效率又有提高了

使用特权

评论回复
23
sedatefire| | 2012-7-5 17:44 | 只看该作者
本帖最后由 sedatefire 于 2012-7-6 09:46 编辑

void get_clock(u8 sec, u8  min, u8  hour)
{
     u8  buf[8+1];
     u8 i;
     sprintf(buf, "%02u\x0A%02u\x0A%02u",  \
                            (uint)hour,  (uint)min, (uint)sec);
     for (i=0; i<8; i++)
     {
          dot = seg[ buf & 0x0F ];
     }
}

使用特权

评论回复
24
sedatefire| | 2012-7-5 17:44 | 只看该作者
本帖最后由 sedatefire 于 2012-7-5 17:46 编辑

void display_polling5ms(void)
{
       static  u8 i = 0;
       P0 =0xff;
       P2 =  wei;
       P0 =  dot; /* 存放的直接是点阵 */
       i = (i+1)&0x07;
}
结合上面的get_clock,这样就比较符合自然的思想

没有冗余的动作,点阵该转换时就只转一次
显示就专门只管显示即可

使用特权

评论回复
25
雷影少年|  楼主 | 2012-7-5 21:40 | 只看该作者
void get_clock(u8 sec, u8  min, u8  hour)
{
     u8  buf[8+1];
     u8 i;
     sprintf(buf, "%02u\x0A%02u\x0A%02u",  \
                            (uint)hour,  (uint)min, (uint)sec);
     for (i=0; i ...
sedatefire 发表于 2012-7-5 17:44

为什么要用整型,用字符型不是更好些吗?这里有什么说法?

使用特权

评论回复
26
sedatefire| | 2012-7-6 09:45 | 只看该作者
为什么要用整型,用字符型不是更好些吗?这里有什么说法?
雷影少年 发表于 2012-7-5 21:40

c51的%u要求必须强制转换成整型的,否则就是乱码

使用特权

评论回复
27
sedatefire| | 2012-7-6 09:46 | 只看该作者
当然%c应该就不需要这样搞了
不过我貌似没用过,没经验

使用特权

评论回复
28
sedatefire| | 2012-7-6 09:47 | 只看该作者
奇怪,我发现如果编辑旧的帖子
[i]这个老是显示不出来,好奇怪
   for (i=0; i<8; i++)
     {
          dot[i] = seg[ buf & 0x0F ];
     }

使用特权

评论回复
29
sedatefire| | 2012-7-6 09:52 | 只看该作者
综上所诉,主函数的写法,思路就很清晰了,而且显示效果刚刚的
/**/
int  main(void)
{
      system_init();
      while (1)
      {
              if (read_and_clear_5ms_flag())
              {
                     clock_update();    /* 详见上一个帖子 */
                     display_polling5ms();
              }
      }
      return 0;
}

使用特权

评论回复
30
sedatefire| | 2012-7-6 09:58 | 只看该作者
另外有一疑问
#inclued"time.c"与#include"time.h"有什么区别?
选用的规则是什么?
雷影少年 发表于 2012-7-4 22:24

这个我都不知道如何回答你
前者仅仅是简单的文件划分而已,后者实现模块真正的独立
将来,你可以把timer.c  timer.h单独拿来重复使用。

使用后者,
1.你可以任意修改timer.c里面的代码,变量名,函数算法等等,而不会影响到main.c档
2.你可以单独查看timer.c的编译汇编档,而不是得到一个杂糅在一起的乱七八糟的main汇编档。
3.使用后者,编译速度会变快,编译器可以只编译被修改过的.c档
你这种写法,任意.c档的修改,都会造成全部重新编译。
4.你这样写,无所谓变量作用域,main.c同样可以访问timer.c的static全局变量。
起不到封装的效果。
5.......

使用特权

评论回复
31
雷影少年|  楼主 | 2012-7-6 10:43 | 只看该作者
当然%c应该就不需要这样搞了
不过我貌似没用过,没经验
sedatefire 发表于 2012-7-6 09:46

哦~
我写下感受感受

使用特权

评论回复
32
雷影少年|  楼主 | 2012-7-6 10:46 | 只看该作者
综上所诉,主函数的写法,思路就很清晰了,而且显示效果刚刚的
/**/
int  main(void)
{
      system_init();
      while (1)
      {
              if (read_and_clear_5ms_flag())
              {
             ...
sedatefire 发表于 2012-7-6 09:52

“return 0;”是做什么用的,主函数进入大循环后一个是无限循环下去的啊,怎么运行到“ return 0;”这一行?
如果运行不到为什么还要返回值?直接定义void类型不可以吗?

使用特权

评论回复
33
雷影少年|  楼主 | 2012-7-6 10:48 | 只看该作者
这个我都不知道如何回答你
前者仅仅是简单的文件划分而已,后者实现模块真正的独立
将来,你可以把timer.c  timer.h单独拿来重复使用。

使用后者,
1.你可以任意修改timer.c里面的代码,变量名,函数算法等等,而 ...
sedatefire 发表于 2012-7-6 09:58

好吧~
我也看的有点晕~
估计以后程序写多了,有直接的体会后才能明白这些~

使用特权

评论回复
34
雷影少年|  楼主 | 2012-7-6 14:07 | 只看该作者
本帖最后由 雷影少年 于 2012-7-6 14:13 编辑

我又修改了下程序
源程序如下:
main.c文件
/*数字时钟程序*/
#include<reg51.h>
#include"display.c" //显示子程序
#include"time.c" //时钟更新子程序
#define count 3686
u8 flag_5ms=0;

void main(void)
{
EA =1; //开中断
ET0 =1;
TMOD =0x01;
TH0 =-(count/256);
TL0 =-(count%256);
TR0 =1;
time();
while (1)
{
static u8 flag_1s=0;
if (flag_5ms)
{
flag_5ms=0;
display(); //每4ms调用一次显示子程序
if(++flag_1s==250) //每秒更新一次时间
{
flag_1s=0;
time();
}
}
}
}
void time50() interrupt 1 //每4ms中断一次
{
TH0=-(count/256);
TL0=-(count%256);
flag_4ms=1;
}

display.c文件
/*时钟显示子模块*/
typedef unsigned char u8 ;
/*初始化数组 时间显示
选择数码管位(从左至右)
数码管显示缓冲*/
u8 code seg[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf};
u8 code wei[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
u8 seg1[]={0,1,2,3,4,5,6,7};


/*将当前时间放入缓冲区*/
void get_clock(u8 sec,min,hour)
{
seg1[7] =sec%10;
seg1[6] =sec/10;
seg1[5]=10;
seg1[4] =min%10;
seg1[3] =min/10;
seg1[2]=10;
seg1[1] =hour%10;
seg1[0] =hour/10;
}
/*显示子程序*/

void display() // 动态显示
{
static u8 i=0;
P0 =0xff;
P2 =wei;
P0 =seg[seg1];
i=(i+1)&0x07;
// delay(10);
}


time.c文件
/*时间更新模块*/
static u8 sec =50; //装载时钟秒初始值
static u8 min =59; //装载分初始值
static u8 hour =23; //装载时初始值
void time(void)
{

if ( ++sec>=60) //秒更新
{
sec=0;
if (++min>=60) //分更新
{
min =0;
if (++hour>=23) //时更新
hour =0;
}
}
get_clock(sec,min,hour); //更新缓冲区数据
}
因为是8位数码管,5ms的中断延时闪烁的很厉害,改成了4ms虽然还是有点闪,但是还能用
关于get_clock函数我没有更改,因为如果调用sprintf函数的话要加头文件stdio.h,程序会不会变得更麻烦了?

使用特权

评论回复
35
雷影少年|  楼主 | 2012-7-6 14:15 | 只看该作者
哈哈~
我也会插入代码啦~

使用特权

评论回复
36
sedatefire| | 2012-7-13 14:59 | 只看该作者
其实,还有许多可以抠的细节之处
比如,计数器的精度
你在中断中这样写,是会有精度误差的,你自己先想看看,原因何在?
void time50() interrupt 1 //每4ms中断一次
{

TH0=-(count/256);

TL0=-(count%256);

flag_4ms=1;

}

使用特权

评论回复
37
sedatefire| | 2012-7-13 15:07 | 只看该作者
再比如,
if (++hour>=23) //时更新
hour =0;

1.你这个逻辑上写错了,要用>号
2. 我以前之所以写成下面这样,是为了程序的可读性
if (++hour>=24)
或者
if (++min>=60)
3.之所以要求哪怕是只有一句指令也要{}包起来,
是因为以后的代码维护,当你要添加代码do_something_2 时,你会随意添加而忘了加{},如下
if (xxx)
    do_something_1
    do_something_2 /* 此处将造成隐性bug*/
do_otherthing
所以要养成良好的习惯
写成
if (xxx)
{
    do_something_1
}
else
{
     do_otherthing
}

使用特权

评论回复
38
sedatefire| | 2012-7-13 15:10 | 只看该作者
实际上,我在工作中,哪怕没有do_otherthing的需要
我也会写成这样
if (xxx)
{
    do_something_1
}
else
{
}
或者这样
if (xxx)
{
    do_something_1
}
/* else{} */
一来自己在程序编写过程中强迫自己充分考虑各种情况。
二来告诉程序的阅读者,else的情况我已经充分考虑过了,不必怀疑我漏掉了

使用特权

评论回复
39
sedatefire| | 2012-7-13 15:10 | 只看该作者
再比如,
if (++hour>=23) //时更新
hour =0;

1.你这个逻辑上写错了,要用>号
2. 我以前之所以写成下面这样,是为了程序的可读性,写59,23对于阅读者来讲,会愣几秒钟才反应过来你的意图。
if (++hour>=24)
或者
if (++min>=60)
3.之所以要求哪怕是只有一句指令也要{}包起 ...
sedatefire 发表于 2012-7-13 15:07

使用特权

评论回复
40
sedatefire| | 2012-7-13 15:11 | 只看该作者
2. 我以前之所以写成下面这样,是为了程序的可读性,写59,23对于阅读者来讲,会愣几秒钟才反应过来你的意图。
if (++hour>=24)
或者
if (++min>=60)

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则