找回密码
 立即注册

QQ登录

只需一步,快速开始

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

关于51单片机计脉冲程序问题

[复制链接]
跳转到指定楼层
#
ID:216579 发表于 2024-6-28 15:54 | 只看该作者 回帖奖励 |正序浏览 |阅读模式
#include <reg51.h>
#include <intrins.h>
#include "display.h"
sbit LED=P1^0;
void Timer0Init(void);
void EX0_Init();
void EX1_Init();
void display_Service();
unsigned int numCnt=0;                //用于存放要显示的脉冲数
unsigned char flag;
unsigned char temp0;
unsigned char temp1;
unsigned char temp2;
unsigned char temp3;
void main()
{
                Timer0Init();
                EX0_Init();
                EX1_Init();
                EA=1;   //中断总开关
        
        while(1)               
        {

   }
}
void display_Service()
{
        temp0=numCnt/1000;
        temp1=numCnt/100%10;
        temp2=numCnt/10%10;
        temp3=numCnt%10;
        if(numCnt<1000)
                LEDBuf[0]=12;
        else
                LEDBuf[0]=temp0;
        if(numCnt<100)
                LEDBuf[1]=12;
                else
                LEDBuf[1]=temp1;
                        if(numCnt<10)
                LEDBuf[2]=12;
                else
                LEDBuf[2]=temp2;
                LEDBuf[3]=temp3;
               
}
void EX0_Init()
{
        IT0=1;
        EX0=1;
}
void EX1_Init()
{
        IT1=1;
        EX1=1;
}
void Timer0Init(void)                //1毫秒@12.000MHz
{
        
        TMOD &= 0xF0;                //设置定时器模式
        TMOD |= 0x01;                //设置定时器模式
        TL0 = 0x18;                //设置定时初值
        TH0 = 0xFC;                //设置定时初值
        TF0 = 0;                //清除TF0标志
        ET0=1;   //中断定时器0的开关

        TR0 = 1;                //定时器0开始计时
}

// void Timer1Init(void)                //50毫秒@12.000MHz
// {
//         TMOD &= 0x0F;                //设置定时器模式
//         TMOD |= 0x10;                //设置定时器模式
//         TL1 = 0xB0;                //设置定时初值
//         TH1 = 0x3C;                //设置定时初值
//         ET1=1;
//         TF1 = 0;                //清除TF1标志
//         TR1 = 1;                //定时器1开始计时
// }

/*******************************************
1、中断服务函数一定是一个没有返回值函数
2、中断服务函数一定是没有参数的函数
3、中断服务函数函数名后要跟关键字 interrupt n
4、interrupt n 0-4   8*n+0003H   0003H   INT0
000BH T0 0013H INT1  001BH TI  0023H ES
5、中服务函数不能被主程序或其他程序调用
6、n 后面跟 using m(0-3)工作寄存器组
*******************************************/
void timer0_ISR(void) interrupt 1
{
        TR0=0;   //定时器0关闭
        Display();
        TL0 = 0x18;                //重新定时初值
        TH0 = 0xFC;                //设置定时初值
        TR0=1; //定时器0开始计时
}
void EX0_ISR() interrupt 0
{
        EX0=0;
        numCnt++;
        if(numCnt>=9999)
                numCnt=0;
        EX0=1;

}
void EX1_ISR() interrupt 2
{
        EX1=0;
        flag=1;
        display_Service();
        numCnt=0;                          //实现数码管清零操作
        EX1=1;
}



问题一:程序跑的频率比较低,超过5K的信号无显示
问题二:跑出来计的脉冲数不准确

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

使用道具 举报

15#
ID:216579 发表于 2024-7-2 10:45 | 只看该作者
xiaobendan001 发表于 2024-7-2 07:16
无论调用多少次显示,都只是在Z相信号到来时的瞬间才更新显示,其余时间都是在现实之前的内容,所以从视 ...

那使用脉冲计数呢
回复

使用道具 举报

14#
ID:1109793 发表于 2024-7-2 07:16 | 只看该作者
guhuawei19 发表于 2024-7-1 16:26
不加延时的话,进一次中断就显示一次速度太快了吧?会显示不清楚吧

无论调用多少次显示,都只是在Z相信号到来时的瞬间才更新显示,其余时间都是在现实之前的内容,所以从视觉上是看不到的。
比如我在研究TM1650的时候,显示在主循环,显示内容是定时器,1秒变一次,主循环在1秒里面不知道循环了多少次了,显示依旧稳定的很。
可惜1650的按键扫描太慢了,做不了编码器。
回复

使用道具 举报

13#
ID:216579 发表于 2024-7-1 16:27 | 只看该作者
xiaobendan001 发表于 2024-7-1 13:03
这意思是外中断1是接在编码器的Z相了?

是的,中断1接到Z相
回复

使用道具 举报

12#
ID:216579 发表于 2024-7-1 16:26 | 只看该作者
xiaobendan001 发表于 2024-7-1 11:41
DelayXms(100);的意图是什么啊?

不加延时的话,进一次中断就显示一次速度太快了吧?会显示不清楚吧
回复

使用道具 举报

11#
ID:1109793 发表于 2024-7-1 13:03 | 只看该作者
guhuawei19 发表于 2024-7-1 07:56
不需要一直更新显示,只需要读出最后的脉冲数,然后显示在数码管上,比如500脉冲只要显示500,不需要显示 ...

这意思是外中断1是接在编码器的Z相了?
回复

使用道具 举报

10#
ID:1109793 发表于 2024-7-1 11:41 | 只看该作者
DelayXms(100);的意图是什么啊?
回复

使用道具 举报

9#
ID:216579 发表于 2024-7-1 09:51 | 只看该作者
xiaobendan001 发表于 2024-6-29 10:35
不知道你的准确意图,看起来脉冲是接外中断0,外中断1是清零。如果不清零就一直在0-9999之间循环。显示一直 ...

while(1)               
        {
        if(flag==1)
        {
        DelayXms(100);
                 display_Service();
       
        }
改成这样能否正常显示
回复

使用道具 举报

8#
ID:216579 发表于 2024-7-1 07:56 | 只看该作者
xiaobendan001 发表于 2024-6-29 18:14
你的显示数据只在外中断1里面更新一次的,就是计数过程看不到,清零时才能看到?

不需要一直更新显示,只需要读出最后的脉冲数,然后显示在数码管上,比如500脉冲只要显示500,不需要显示增加的过程
回复

使用道具 举报

7#
ID:1109793 发表于 2024-6-30 07:37 | 只看该作者
ZCF03 发表于 2024-6-29 19:08
不知道你的准确意图,看起来脉冲是接外中断0,外中断1是清零。如果不清零就一直在0-9999之间循环。显示一直 ...

干嘛要抄啊,赚个积分不容易。删除几个字比较容易是吧
回复

使用道具 举报

6#
ID:1109793 发表于 2024-6-29 18:14 | 只看该作者
guhuawei19 发表于 2024-6-29 17:00
程序的主要原理就是测编码器转一圈测试实际的脉冲数,有个零位是起始到终止的总脉冲数,然后在显示函数里 ...

你的显示数据只在外中断1里面更新一次的,就是计数过程看不到,清零时才能看到?
回复

使用道具 举报

5#
ID:216579 发表于 2024-6-29 17:00 | 只看该作者
xiaobendan001 发表于 2024-6-29 10:35
不知道你的准确意图,看起来脉冲是接外中断0,外中断1是清零。如果不清零就一直在0-9999之间循环。显示一直 ...

程序的主要原理就是测编码器转一圈测试实际的脉冲数,有个零位是起始到终止的总脉冲数,然后在显示函数里显示,可能显示函数放到中断了造成显示过快,是不是要把显示函数放到MAIN函数下面?
回复

使用道具 举报

地板
ID:161164 发表于 2024-6-29 14:51 | 只看该作者
一:不要用外部中断,用定时器的计数模式
二: 同上
回复

使用道具 举报

板凳
ID:1109793 发表于 2024-6-29 10:35 | 只看该作者
不知道你的准确意图,看起来脉冲是接外中断0,外中断1是清零。如果不清零就一直在0-9999之间循环。显示一直在更新,是啥意思,如果脉冲速度很快,可能都看不清了。超过5K的信号无显示是说的频率,还是计数值达到5000以后就不显示了?脉冲的频率是多少?外中断采集脉冲比较容易受到干扰,使计数值变大。但是你使用的是外中断0,是最高优先,大概率不会有丢脉冲的情况。
回复

使用道具 举报

沙发
ID:232693 发表于 2024-6-29 09:47 | 只看该作者
如果要调整占空比,那就调整PWM4DUTY和占空比那高位的重载值 ,有一点要注意就是占空比的值不能大于TMR4的重载值,不然就是一直有效电平了。如果把TM34RH=0,PWM4DUTY=占空比了吗?   如果要调整频率,那就是调整分频比和TMR4重载值。 TMR3 重载值=100,向下计数的话,是不是我频率是1us,这里就是100us?但是我要调成红外发射频率38KHz,也就是TMR3=26us的话,又和上面的注意事项冲突了。
回复

使用道具 举报

楼主
ID:866313 发表于 2024-6-29 08:10 | 只看该作者
您的代码遇到了性能和脉冲计数准确性的问题,这是由于中断和定时器处理方式所致。以下是一些洞察和建议,以解决这些问题:
问题分析
  • 低频问题:
    • 主要问题是,您的定时器中断服务例程(ISR)每1毫秒被调用一次。如果ISR内的处理时间过长,可能会错过一些脉冲,如果它们的发生频率高于ISR执行时间。

  • 脉冲计数准确性:
    • 脉冲计数不准确可能源于多个因素,包括中断服务例程的触发时间以及在ISRs中禁用中断。这可能导致如果在中断被禁用的同时新脉冲到达,就会错过脉冲。


解决步骤1. 优化ISR执行时间
尽量减少ISR中的代码,以确保它能够尽快执行。例如,在timer0_ISR中不要调用显示函数,而是在主循环中设置一个标志并处理显示更新。
bit displayUpdateFlag = 0;

void timer0_ISR(void) interrupt 1
{
     TR0 = 0;  // 停止Timer0
     displayUpdateFlag = 1;
     TL0 = 0x18; // 重置Timer0初始值
     TH0 = 0xFC;
     TR0 = 1;  // 重新启动Timer0
}
在主循环中检查这个标志,并在需要时调用显示更新函数:
void main()
{
     Timer0Init();
     EX0_Init();
     EX1_Init();
     EA = 1;  // 启用全局中断

     while (1)
     {
         if (displayUpdateFlag)
         {
             displayUpdateFlag = 0;
             display_Service();
         }
     }
}2. 确保脉冲计数准确
尽可能短暂地禁用和重新启用你的ISRs中的中断,以防错过脉冲。
void EX0_ISR() interrupt 0
{
     numCnt++;
     if (numCnt >= 9999)
         numCnt = 0;
}
注意,在其ISR中无需禁用EX0,因为进入ISR时中断标志会自动清除。这减少了中断被禁用的时间。
3. 高效使用Timer0
定时器ISR应仅负责基于时间的任务,而不是处理复杂操作如更新显示。
最终代码调整
以下是根据上述建议修改后的代码:
#include <reg51.h>
#include "display.h"

sbit LED = P1^0;

void Timer0Init(void);
void EX0_Init();
void EX1_Init();
void display_Service();

unsigned int numCnt = 0; // 用于存储要显示的脉冲数量
bit displayUpdateFlag = 0;
unsigned char temp0, temp1, temp2, temp3;

void main()
{
     Timer0Init();
     EX0_Init();
     EX1_Init();
     EA = 1; // 启用全局中断

     while (1)
     {
         if (displayUpdateFlag)
         {
             displayUpdateFlag = 0;
             display_Service();
         }
     }
}

void display_Service()
{
     temp0 = numCnt / 1000;
     temp1 = (numCnt / 100) % 10;
     temp2 = (numCnt / 10) % 10;
     temp3 = numCnt % 10;

     LEDBuf[1] = (numCnt < 1000)? 12 : temp0;
     LEDBuf[2] = (numCnt < 100)? 12 : temp1;
     LEDBuf[3] = (numCnt < 10)? 12 : temp2;
     LEDBuf[4] = temp3;
}

void EX0_Init()
{
     IT0 = 1; // 边缘触发中断
     EX0 = 1; // 启用EX0
}

void EX1_Init()
{
     IT1 = 1; // 边缘触发中断
     EX1 = 1; // 启用EX1
}

void Timer0Init(void) // 1ms @ 12.000MHz
{
     TMOD &= 0xF0; // 设置定时器模式
     TMOD |= 0x01; // 设置定时器模式
     TL0 = 0x18; // 设置初始定时器值
     TH0 = 0xFC; // 设置初始定时器值
     TF0 = 0; // 清除TF0标志
     ET0 = 1; // 启用Timer0中断
     TR0 = 1; // 启动Timer0
}

void timer0_ISR(void) interrupt 1
{
     TR0 = 0; // 停止Timer0
     displayUpdateFlag = 1; // 设置标志以更新显示
     TL0 = 0x18; // 重置Timer0初始值
     TH0 = 0xFC;
     TR0 = 1; // 重新启动Timer0
}

void EX0_ISR() interrupt 0
{
     numCnt++;
     if (numCnt >= 9999)
         numCnt = 0;
}

void EX1_ISR() interrupt 2
{
     flag = 1;
     display_Service();
     numCnt = 0; // 清除计数以重置显示
}
这应该提高了嵌入式系统的性能和准确性,确保它能处理更高频率的信号并更准确地计数脉冲。

回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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