找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1788|回复: 10
打印 上一主题 下一主题
收起左侧

单片机60s倒计时程序为什么不能显示?

[复制链接]
跳转到指定楼层
楼主
//60s倒计时
#include"stc8.h"
#include "intrins.h"

#define  uint unsigned int
#define  uchar unsigned char   

#define  SEG P1

sbit SCON1 = P3^7;            
sbit SCON2 = P3^6;   

sbit KEY = P3^2;

uchar count=0;
char num=60,ge,shi;
uchar flag;

uchar code table[]={      
        0x03,/*0*/
        0x9F,/*1*/
        0x25,/*2*/
        0x0D,/*3*/
        0x99,/*4*/
        0x49,/*5*/
        0x41,/*6*/
        0x1F,/*7*/
        0x01,/*8*/
        0x09,/*9*/};

void T0_init()                                //5毫秒@11.0592MHz
{
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TMOD |= 0x01;                        //设置定时器模式
        TL0 = 0x00;                                //设置定时初始值
        TH0 = 0xEE;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                           
        ET0 = 1;                                //使能定时器0中断
        EA = 1;
}

void IO_init()
{
    P3M0 = 0x00; P3M1 = 0x00;
    P1M0 = 0xff; P1M1 = 0x00;

}

void TM0_Isr() interrupt 1 //5毫秒
{
        TL0 = 0x00;                                //设置定时初始值
        TH0 = 0xEE;                                //设置定时初始值
        flag++;
        if (flag=20)
        {
        flag=0;
                num--;
                if (flag=0)
        {
        flag=60;
        }
}
}

void main()
{
IO_init();
T0_init() ;
        while (1)
  {
                SEG=0xff;
                shi=num/10;
                ge=num%10;
                switch (count)
    {
            case0:SCON1 = 0;SCON2=1; SEG = table[ge];
                    break;
            case1:SCON1 = 1;SCON2=0; SEG = table[shi];
                    break;
            default:
                    break;
    }
                count++;
                if (count>1)count=0;
  }

}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1109793 发表于 2024-5-19 10:19 | 只看该作者
每当flag++到20时,flag = 0然后立刻flag=60,然后flag++以后就得等他++到255再变0,重复++到20时再变60,再重复。就是大概flag计数215次num--一次,1075ms减一次,应该可以啊。为啥不显示?是不显示还是不计时?另外,SEG=0XFF是想消隐,但是你这是共阴的,因为你的SCON是设置的标准IO,那么只能共阴极了。共阴极的段码要给0x00才行消隐,你这0xff不是一直亮着吗?还有扫描切换不要放到主循环,这扫描速度得有多快啊。一个位的显示时间可能太短了。消隐也可以把两个SCON都置1。
回复

使用道具 举报

板凳
ID:619259 发表于 2024-5-19 11:23 | 只看该作者
原程序有多处错误:1.  if (flag=20),应改为 if (flag==200)
2.  动态刷新时间太快,需合理设置count++的时间间隔
3.  case0、case1应为case 0、case 1
……
程序修改如下,仅供参考:
void TM0_Isr() interrupt 1 //5毫秒
{
        TL0 = 0x00;           //设置定时初始值
        TH0 = 0xEE;           //设置定时初始值
        flag++;
        if(flag==200)
        {
                flag=0;
                num--;
                if (num==0)
                {
                    num=60;
                       }
         }

        //动态扫描刷新周期为10毫秒
        count++;
             if (count>1)
             {
                       count=0;
             }
}

void main()
{
        IO_init();
        T0_init() ;
        while(1)
          {
                shi=num/10;
                ge=num%10;
                SCON1 = 1;  SCON2 = 1;  //消隐
                switch(count)
                    {
                            case 0:  SCON1 = 1;  SCON2 = 0;  SEG = table[ge];  break;
                            case 1:  SCON1 = 0;  SCON2 = 1;  SEG = table[shi]; break;
                            default: break;
                    }
          }
}


回复

使用道具 举报

地板
ID:72649 发表于 2024-5-19 13:43 | 只看该作者
xiaobendan001 发表于 2024-5-19 10:19
每当flag++到20时,flag = 0然后立刻flag=60,然后flag++以后就得等他++到255再变0,重复++到20时再变60, ...

共阳数码管

51hei图片_20240518215731.png (53.96 KB, 下载次数: 35)

51hei图片_20240518215731.png
回复

使用道具 举报

5#
ID:72649 发表于 2024-5-19 13:44 | 只看该作者
xiaobendan001 发表于 2024-5-19 10:19
每当flag++到20时,flag = 0然后立刻flag=60,然后flag++以后就得等他++到255再变0,重复++到20时再变60, ...

void TM0_Isr() interrupt 1 //5毫秒
{
        TL0 = 0x00;                                //设置定时初始值
        TH0 = 0xEE;                                //设置定时初始值
        flag++;
        if (flag=20)
        {
        flag=0;
                num--;
                if (num=0)
        {
        num=60;
        }
}
}
回复

使用道具 举报

6#
ID:72649 发表于 2024-5-19 13:48 | 只看该作者
xiaobendan001 发表于 2024-5-19 10:19
每当flag++到20时,flag = 0然后立刻flag=60,然后flag++以后就得等他++到255再变0,重复++到20时再变60, ...

//倒计时
#include"stc8.h"
#include "intrins.h"

#define  uint unsigned int
#define  uchar unsigned char   

#define  SEG P1

sbit SCON1 = P3^7;            
sbit SCON2 = P3^6;   
  
sbit KEY = P3^2;

uchar count=0;
char num=60,ge,shi;
uchar flag;

uchar code table[]={      
        0x03,/*0*/
        0x9F,/*1*/
        0x25,/*2*/
        0x0D,/*3*/
        0x99,/*4*/
        0x49,/*5*/
        0x41,/*6*/
        0x1F,/*7*/
        0x01,/*8*/
        0x09,/*9*/};

void T0_init()                                //5毫秒@11.0592MHz
{
        AUXR &= 0x7F;                        //定时器时钟12T模式
        TMOD &= 0xF0;                        //设置定时器模式
        TMOD |= 0x01;                        //设置定时器模式
        TL0 = 0x00;                                //设置定时初始值
        TH0 = 0xEE;                                //设置定时初始值
        TF0 = 0;                                //清除TF0标志
        TR0 = 1;                           
        ET0 = 1;                                //使能定时器0中断
        EA = 1;
}

void IO_init()
{
    P3M0 = 0x00; P3M1 = 0x00;
    P1M0 = 0xff; P1M1 = 0x00;

}

void TM0_Isr() interrupt 1 //5毫秒
{
        TL0 = 0x00;                                //设置定时初始值
        TH0 = 0xEE;                                //设置定时初始值
        flag++;
        if (flag=20)
        {
        flag=0;
                num--;
                if (num=0)
        {
        num=60;
        }
}
}

void main()
{
IO_init();
T0_init() ;
        while (1)
  {
                SEG=0;
                shi=num/10;
                ge=num%10;
                switch (count)
    {
            case0:SCON1 = 0;SCON2=1; SEG = table[ge];
                    break;
            case1:SCON1 = 1;SCON2=0; SEG = table[shi];
                    break;
            default:
                    break;
    }
                count++;
                if (count>1)count=0;
  }

}



















回复

使用道具 举报

7#
ID:72649 发表于 2024-5-19 13:50 | 只看该作者
hjx5548 发表于 2024-5-19 13:44
void TM0_Isr() interrupt 1 //5毫秒
{
        TL0 = 0x00;                                //设置定 ...

这样也不能显示?
回复

使用道具 举报

8#
ID:1109793 发表于 2024-5-19 17:28 | 只看该作者

共阳极的那你得吧两个SCON设置为推挽才行啊。要不然标准IO的高电平电流同时点亮8个段,即使亮也几乎看不到吧。消隐要让SCON=0,输出SEG之后再把对应的SCON=1
回复

使用道具 举报

9#
ID:619259 发表于 2024-5-19 20:08 | 只看该作者

共阳的数码管,你用共阴的代码,提问之前请先说明清楚。
回复

使用道具 举报

10#
ID:1137639 发表于 2025-11-9 17:21 | 只看该作者
你的代码有问题
中断逻辑错误:定时器 0 中断中使用if(flag=20)和if(flag=0)(赋值语句而非判断语句),导致倒计时逻辑完全错乱,无法正常递减。
倒计时边界处理缺失:未处理num减至 0 后的复位逻辑,且flag=60的赋值无意义,导致数值溢出或停滞。
动态扫描时序不合理:主函数中无延时直接切换数码管位选,扫描频率过快,肉眼无法识别,表现为 “不显示” 或 “显示模糊”。
数码管段码可能不匹配:若使用共阳极数码管,当前段码表(共阴极)会导致显示异常,需确认硬件连接类型。
  1. #include"stc8.h"
  2. #include "intrins.h"

  3. #define uint unsigned int
  4. #define uchar unsigned char   

  5. #define SEG P1  // 数码管段选引脚
  6. sbit SCON1 = P3^7;  // 个位数码管位选
  7. sbit SCON2 = P3^6;  // 十位数码管位选
  8. sbit KEY = P3^2;    // 按键(预留,可用于启动/复位)

  9. uchar count = 0;    // 数码管扫描计数
  10. char num = 60;      // 倒计时初始值(0-60)
  11. uchar ge, shi;      // 个位、十位拆分值
  12. uchar flag = 0;     // 定时器计数标志

  13. // 共阴极数码管段码表(0-9),若为共阳极需改为0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xE0,0xFE,0xF6
  14. uchar code table[] = {      
  15.     0x03,/*0*/ 0x9F,/*1*/ 0x25,/*2*/ 0x0D,/*3*/ 0x99,/*4*/
  16.     0x49,/*5*/ 0x41,/*6*/ 0x1F,/*7*/ 0x01,/*8*/ 0x09,/*9*/
  17. };

  18. // 定时器0初始化:5毫秒@11.0592MHz(12T模式)
  19. void T0_init() {
  20.     AUXR &= 0x7F;    // 定时器时钟12T模式
  21.     TMOD &= 0xF0;    // 清除定时器0模式
  22.     TMOD |= 0x01;    // 定时器0工作模式1(16位定时)
  23.     TL0 = 0x00;      // 定时5ms初始值(11.0592MHz计算得出)
  24.     TH0 = 0xEE;      // 重载值:TH0=0xEE, TL0=0x00,单次定时约5ms
  25.     TF0 = 0;         // 清除溢出标志
  26.     TR0 = 1;         // 启动定时器0
  27.     ET0 = 1;         // 使能定时器0中断
  28.     EA = 1;          // 开启总中断
  29. }

  30. // IO口初始化:P1推挽输出(段选),P3准双向(位选/按键)
  31. void IO_init() {
  32.     P3M0 = 0x00; P3M1 = 0x00;  // P3口准双向模式
  33.     P1M0 = 0xFF; P1M1 = 0x00;  // P1口推挽输出(驱动数码管)
  34.     SCON1 = 1; SCON2 = 1;     // 初始位选关闭(避免串扰)
  35. }

  36. // 毫秒级延时函数(用于数码管动态扫描,调整显示清晰度)
  37. void Delay_ms(uint ms) {
  38.     uint i, j;
  39.     for(i = ms; i > 0; i--)
  40.         for(j = 110; j > 0; j--);
  41. }

  42. // 定时器0中断服务函数:5ms触发一次,累计1秒递减num
  43. void TM0_Isr() interrupt 1 {
  44.     TL0 = 0x00;  // 重新加载定时初始值
  45.     TH0 = 0xEE;
  46.     flag++;      // 每5ms计数+1
  47.    
  48.     // 累计20次=100ms?修正:200次=1000ms(1秒),原逻辑计时过快
  49.     if (flag == 200) {  
  50.         flag = 0;       // 计数清零
  51.         num--;          // 每秒递减1
  52.         if (num < 0) {  // 倒计时结束(0→-1),复位为60
  53.             num = 60;
  54.         }
  55.     }
  56. }

  57. void main() {
  58.     IO_init();   // IO口初始化
  59.     T0_init();   // 定时器0初始化
  60.    
  61.     while (1) {
  62.         // 拆分十位和个位(num范围0-60)
  63.         shi = num / 10;  // 十位:60→6,0→0
  64.         ge = num % 10;   // 个位:60→0,9→9
  65.         
  66.         // 动态扫描显示:个位→十位,每段延时5ms,避免闪烁
  67.         switch (count) {
  68.             case 0:  // 显示个位
  69.                 SCON1 = 0;  // 开启个位数码管
  70.                 SCON2 = 1;  // 关闭十位数码管
  71.                 SEG = table[ge];  // 输出个位段码
  72.                 Delay_ms(5);      // 保持显示,确保肉眼识别
  73.                 break;
  74.             case 1:  // 显示十位
  75.                 SCON1 = 1;  // 关闭个位数码管
  76.                 SCON2 = 0;  // 开启十位数码管
  77.                 SEG = table[shi];  // 输出十位段码
  78.                 Delay_ms(5);      // 保持显示
  79.                 break;
  80.             default:
  81.                 count = 0;  // 重置扫描计数
  82.                 break;
  83.         }
  84.         count++;
  85.         if (count > 1) {
  86.             count = 0;  // 仅两位数码管,循环扫描
  87.         }
  88.     }
  89. }
复制代码

1. 修复中断逻辑错误
将中断中的if(flag=20)改为if(flag==200)(判断语句而非赋值),且修正计时逻辑:5ms×200=1000ms(1 秒),确保每秒递减 1。
增加num<0的边界处理,倒计时结束后自动复位为 60,实现循环倒计时。
2. 优化数码管动态扫描
新增Delay_ms()函数,在每位数码管显示后延时 5ms,降低扫描频率,使肉眼能清晰识别数字(原代码无延时,扫描过快导致 “不显示”)。
初始位选设置为SCON1=1、SCON2=1(关闭状态),避免初始化时数码管串扰。
3. 修正数码管段码适配
段码表标注共阴极 / 共阳极差异,若硬件使用共阳极数码管,需替换段码表(注释中已给出共阳极段码),否则会出现 “全亮” 或 “不显示”。
4. 完善 IO 口初始化
明确 P1 口为推挽输出(驱动数码管段选),P3 口为准双向模式(位选和按键输入),匹配硬件驱动需求。
回复

使用道具 举报

11#
ID:390416 发表于 2025-11-12 21:38 | 只看该作者
去找《人人学会单片机》的课程资料 和 源代码  每一份开源代码 都是经过严格测试 千锤百炼
回复

使用道具 举报

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

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表