找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1511|回复: 5
收起左侧

关于单片机计时器和计数器中断程序修改问题

[复制链接]
ID:820813 发表于 2022-3-7 16:21 | 显示全部楼层 |阅读模式
我写了一个单片机程序,但是没办法满足实际应用,第一是因为计数器最大位65535并不满足我要的计数要求。第二P3.5引脚接收的方波时候在方波的上升沿有大量的小方波毛刺造成一个方波记好多数。所以想请大佬帮忙给一个解决办法,帮忙修改一下 谢谢啦。
我能想到的使用计时器设置在65534来一个计数就溢出然后对溢出计数相加,溢出再做一个跟按键相似的防抖处理。可是我不会改,如果有会改的希望可以帮忙指导一下 。 万分感谢

单片机源程序如下:
#include <reg51.h>
#include "DigDisplay.h"
#include "delay.h"


void DigDisplay_Service();  //数码管数值显示
void Timer0Init(void);       //做一个计时器声明
void Timer1Init(void);       //做一个计数器声明
void key();                      //按键声明

unsigned long NumCnt;

sbit export1 = P1^0;         //将单片机的P1^0端口设定为输出
sbit key1 = P1^7;             //定义P1^7口是按键key1

/*****************************************************
函数名: main
功  能:主函数
参  数:
返回值:
*****************************************************/
void main()
{
          Timer0Init();         //做一个调用 定时功能去刷新数码管
          Timer1Init();         //做一个调用 计数功能去做一个计数
          EA = 1;//中断中开开关
        while(1)
         {
                key();
                NumCnt = TH1*256 + TL1; //前一个是一个整型 而TH1和TL1是8个字节,所以将TH1左移8位
                DigDisplay();
   }
}

void display_service()
{
    LEDBuf[0] = NumCnt/10000000;      //千万位
                LEDBuf[1] = NumCnt/1000000%10;    //百万位
                LEDBuf[2] = NumCnt/100000%10;     //十万位
                LEDBuf[3] = NumCnt/10000%10;      //万位
                LEDBuf[4] = NumCnt/1000%10;       //千位
                LEDBuf[5] = NumCnt/100%10;        //百位
                LEDBuf[6] = NumCnt/10%10;         //十位
                LEDBuf[7] = NumCnt%10;            //个位    取余
}

void Timer1Init(void)  //1毫秒@12.00MHz
{
    TMOD &= 0xF0; //设置计数器模式
    TMOD |= 0x01; //设置计数器模式 65536
    TL1 = 0;      //设置计数器初值
          TH1 = 0;      //设置计数器初值
    TF1 = 0;      //清除TF1标志
//  ETO = 1;      //定时器0的中断开关
//  EA  = 1;       //终端总开关
          TR0 = 1;      //打开计数器 1开始计数
}
/*****************************************
1、中断服务函数一定是一个没有返回值的函数
2、中断服务函数一定是一个没有参数的函数
3、中断服务函数名称后面跟一个关键字interrupt
4、interrupt 0--4共计5个中断源  8*n +0003H
   0003H INT0
   000BH T0
   0013H INT1
   001BH T1
   0023H ES
5、中断服务函数不能被主程序或者其他程序调用
6、N后面跟using m (0--3)工作寄存器组
*****************************************/


void Timer0Init(void)                //100微秒定时器@12.000MHz
{
        TMOD &= 0xF0;                //设置定时器模式
        TMOD |= 0x01;                //设置定时器模式
        TL0 = 0x9C;                //设置定时初值
        TH0 = 0xFF;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        ET0 = 1;     //定时器0的中断开关
        EA = 1;       //中断开关
        TR0 = 1;                //定时器0开始计时
}

/*******************************************
1、中断服务函数一定是一个没有返回值的一个函数
2、中断服务函数是一个没有参数的函数
3、中断服务函数函数名称后面跟一个关键字interrupt
4、interrupt 0——4 共计5各中断源  8*n + 0003H
   0003H INT0  
   000BH T0
   0013H INT1
   001BH T1
   0023H ES
5、中断服务函数不能被主程序或者其他程序调用
6、n后面跟using m (0——3)工作寄存器组
*******************************************/
void time0_ISR(void) interrupt 1 //终端定时器0标号1
{
        TR0 = 0;       //关闭定时器0开始计时
        DigDisplay();
        TL0 = 0x9C;                //设置定时初值
        TH0 = 0xFF;                //设置定时初值
  TR0 = 1;      //打开定时器0开始计时
}

        
void key()        //按键  按一下开始 按一下暂停
{
    if(key1 == 0)          //检测按键K1是否按下
{
    DelayXms(1);           //消除按键抖动
          if(key1 == 0)          //再次判断按键是否按下
  {
          export1 = 0;
                DelayXms(415);          //延迟1秒 使继电器吸合一秒
                export1 = ~export1;
                DelayXms(415);          //延迟1秒 使继电器断开一秒
  }
}
}


回复

使用道具 举报

ID:213173 发表于 2022-3-7 22:42 | 显示全部楼层
输入波形有毛刺需要加低通滤波器,外部计数大于65535要开中断。程序中毛病较多,给你改了。 无标题.jpg
  1. #include <reg51.h>

  2. sbit export1 = P1^0;         //将单片机的P1^0端口设定为输出
  3. sbit key1 = P1^7;             //定义P1^7口是按键key1

  4. unsigned char code table[]={//共阴数码管段码"0~f-."
  5.                 0x3f,0x06,0x5b,0x4f,
  6.                 0x66,0x6d,0x7d,0x07,
  7.                 0x7f,0x6f,0x77,0x7c,
  8.                 0x39,0x5e,0x79,0x71,0x40,0x80};
  9. unsigned char data LEDBuf[8];
  10. unsigned long NumCnt=0;
  11. unsigned int  num,num1;

  12. void Timer0Init(void);       //做一个计时器声明
  13. void Timer1Init(void);       //做一个计数器声明
  14. void key();                      //按键声明
  15. void display_service();
  16. void DigDisplay_Service();  //数码管数值显示
  17. /*****************************************************
  18. 函数名: main
  19. 功  能:主函数
  20. 参  数:
  21. 返回值:
  22. *****************************************************/
  23. void main()
  24. {
  25.         Timer0Init();         //做一个调用 定时功能去刷新数码管
  26.         Timer1Init();         //做一个调用 计数功能去做一个计数
  27.         EA = 1;//中断中开开关
  28.         while(1)
  29.         {
  30.                 key();
  31.                 NumCnt=((unsigned long)num<<16)|((TH1<<8)|TL1);
  32.                 display_service();
  33.         }
  34. }

  35. void key()        //按一下输出只维持1s
  36. {
  37.         static unsigned char count;       
  38.         static bit sign=0;       
  39.         if(!key1)          //检测按键K1是否按下
  40.         {
  41.                 if(++count>=5 && sign==0 && export1==1)
  42.                 {
  43.                         sign=1;
  44.                         export1=0;
  45.                 }
  46.         }
  47.         else
  48.         {
  49.                 count=0;
  50.                 sign=0;
  51.         }
  52. }

  53. void display_service()
  54. {
  55.         static unsigned char i;       
  56.         switch(i)
  57.         {
  58.                 case 0: LEDBuf[0] = table[NumCnt/10000000%10]; break;  //千万位
  59.                 case 1: LEDBuf[1] = table[NumCnt/1000000%10]; break;//百万位
  60.                 case 2: LEDBuf[2] = table[NumCnt/100000%10]; break;//十万位
  61.                 case 3: LEDBuf[3] = table[NumCnt/10000%10]; break;//万位
  62.                 case 4: LEDBuf[4] = table[NumCnt/1000%10]; break;//千位
  63.                 case 5: LEDBuf[5] = table[NumCnt/100%10]; break;//百位
  64.                 case 6: LEDBuf[6] = table[NumCnt/10%10]; break;//十位
  65.                 case 7: LEDBuf[7] = table[NumCnt%10]; break;//个位
  66.         }
  67.         i=++i%8;
  68. }

  69. void DigDisplay_Service()
  70. {
  71.         static unsigned char i;       
  72.         P0=0x00;
  73.         P2=~(0x01<<i);
  74.         P0=LEDBuf[i];
  75.         i=++i%8;
  76. }
  77. /*****************************************
  78. 1、中断服务函数一定是一个没有返回值的函数
  79. 2、中断服务函数一定是一个没有参数的函数
  80. 3、中断服务函数名称后面跟一个关键字interrupt
  81. 4、interrupt 0--4共计5个中断源  8*n +0003H
  82.    0003H INT0
  83.    000BH T0
  84.    0013H INT1
  85.    001BH T1
  86.    0023H ES
  87. 5、中断服务函数不能被主程序或者其他程序调用
  88. 6、N后面跟using m (0--3)工作寄存器组
  89. *****************************************/
  90. void Timer0Init(void)//1毫秒@12.000MHz
  91. {
  92.         TMOD &= 0xF0;    //设置定时器模式
  93.         TMOD |= 0x01;    //设置定时器模式
  94.         TL0 = 0x18;                //设置定时初始值
  95.         TH0 = 0xFC;                //设置定时初始值
  96.         TF0 = 0;         //清除TF0标志
  97.         ET0 = 1;              //定时器0的中断开关
  98.         EA = 1;          //中断开关
  99.         TR0 = 1;         //定时器0开始计时
  100. }

  101. void Timer1Init(void)  //1毫秒@12.00MHz
  102. {
  103.         TMOD &= 0x0F; //设置计数器模式
  104.         TMOD |= 0x50; //设置计数器模式
  105.         TL1 = 0;      //设置计数器初值
  106.         TH1 = 0;      //设置计数器初值
  107.         TF1 = 0;      //清除TF1标志
  108.         ET1 = 1;      //定时器1的中断开关
  109.         TR1 = 1;      //打开计数器1开始计数
  110. }

  111. /*******************************************
  112. 1、中断服务函数一定是一个没有返回值的一个函数
  113. 2、中断服务函数是一个没有参数的函数
  114. 3、中断服务函数函数名称后面跟一个关键字interrupt
  115. 4、interrupt 0——4 共计5各中断源  8*n + 0003H
  116.    0003H INT0  
  117.    000BH T0
  118.    0013H INT1
  119.    001BH T1
  120.    0023H ES
  121. 5、中断服务函数不能被主程序或者其他程序调用
  122. 6、n后面跟using m (0——3)工作寄存器组
  123. *******************************************/
  124. void time0_ISR(void) interrupt 1 //终端定时器0标号1
  125. {
  126.         TL0 = 0x18;                //设置定时初始值
  127.         TH0 = 0xFC;                //设置定时初始值
  128.         if(!export1)
  129.         {
  130.                 num1++;
  131.                 if(num1>=1000)
  132.                 {
  133.                         num1=0;
  134.                         export1=1;
  135.                 }
  136.         }
  137.         DigDisplay_Service();
  138. }
  139. void time1_ISR(void) interrupt 3
  140. {
  141.         num++;
  142. }
复制代码






回复

使用道具 举报

ID:123289 发表于 2022-3-8 15:28 | 显示全部楼层
【第一是因为计数器最大位65535并不满足我要的计数要求】
回:太呆板,随意扩展一下即可。如每次中断后,给MM+1,当MM达到某值时,做你希望做的事,并将MM清0。
【第二P3.5引脚接收的方波时候在方波的上升沿有大量的小方波毛刺造成一个方波记好多数】
回:硬件上滤下波。
或者软件上,效仿按键防弹动的做法,不要让P3.5直接起效,而是防弹动后起效。
回复

使用道具 举报

ID:139866 发表于 2022-3-8 16:25 | 显示全部楼层
你这问题就相当于表钟只有60个格子,是怎么表示24小时呢?
回复

使用道具 举报

ID:820813 发表于 2022-3-8 16:42 | 显示全部楼层
wulin 发表于 2022-3-7 22:42
输入波形有毛刺需要加低通滤波器,外部计数大于65535要开中断。程序中毛病较多,给你改了。

感谢大佬,我这就试一下
回复

使用道具 举报

ID:820813 发表于 2022-3-11 11:55 | 显示全部楼层
wulin 发表于 2022-3-7 22:42
输入波形有毛刺需要加低通滤波器,外部计数大于65535要开中断。程序中毛病较多,给你改了。

很感谢你的回复,我并没有调通这个程序。我排查一下原因。
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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