欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136

標題: 關于51單片機計脈沖程序問題 [打印本頁]

作者: guhuawei19    時間: 2024-6-28 15:54
標題: 關于51單片機計脈沖程序問題
#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的信號無顯示
問題二:跑出來計的脈沖數不準確


作者: cedtek    時間: 2024-6-29 08:10
您的代碼遇到了性能和脈沖計數準確性的問題,這是由于中斷和定時器處理方式所致。以下是一些洞察和建議,以解決這些問題:
問題分析解決步驟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; // 清除計數以重置顯示
}
這應該提高了嵌入式系統的性能和準確性,確保它能處理更高頻率的信號并更準確地計數脈沖。


作者: tonny126    時間: 2024-6-29 09:47
如果要調整占空比,那就調整PWM4DUTY和占空比那高位的重載值 ,有一點要注意就是占空比的值不能大于TMR4的重載值,不然就是一直有效電平了。如果把TM34RH=0,PWM4DUTY=占空比了嗎?   如果要調整頻率,那就是調整分頻比和TMR4重載值。 TMR3 重載值=100,向下計數的話,是不是我頻率是1us,這里就是100us?但是我要調成紅外發射頻率38KHz,也就是TMR3=26us的話,又和上面的注意事項沖突了。
作者: xiaobendan001    時間: 2024-6-29 10:35
不知道你的準確意圖,看起來脈沖是接外中斷0,外中斷1是清零。如果不清零就一直在0-9999之間循環。顯示一直在更新,是啥意思,如果脈沖速度很快,可能都看不清了。超過5K的信號無顯示是說的頻率,還是計數值達到5000以后就不顯示了?脈沖的頻率是多少?外中斷采集脈沖比較容易受到干擾,使計數值變大。但是你使用的是外中斷0,是最高優先,大概率不會有丟脈沖的情況。
作者: lkc8210    時間: 2024-6-29 14:51
一:不要用外部中斷,用定時器的計數模式
二: 同上
作者: guhuawei19    時間: 2024-6-29 17:00
xiaobendan001 發表于 2024-6-29 10:35
不知道你的準確意圖,看起來脈沖是接外中斷0,外中斷1是清零。如果不清零就一直在0-9999之間循環。顯示一直 ...

程序的主要原理就是測編碼器轉一圈測試實際的脈沖數,有個零位是起始到終止的總脈沖數,然后在顯示函數里顯示,可能顯示函數放到中斷了造成顯示過快,是不是要把顯示函數放到MAIN函數下面?
作者: xiaobendan001    時間: 2024-6-29 18:14
guhuawei19 發表于 2024-6-29 17:00
程序的主要原理就是測編碼器轉一圈測試實際的脈沖數,有個零位是起始到終止的總脈沖數,然后在顯示函數里 ...

你的顯示數據只在外中斷1里面更新一次的,就是計數過程看不到,清零時才能看到?
作者: xiaobendan001    時間: 2024-6-30 07:37
ZCF03 發表于 2024-6-29 19:08
不知道你的準確意圖,看起來脈沖是接外中斷0,外中斷1是清零。如果不清零就一直在0-9999之間循環。顯示一直 ...

干嘛要抄啊,賺個積分不容易。刪除幾個字比較容易是吧
作者: guhuawei19    時間: 2024-7-1 07:56
xiaobendan001 發表于 2024-6-29 18:14
你的顯示數據只在外中斷1里面更新一次的,就是計數過程看不到,清零時才能看到?

不需要一直更新顯示,只需要讀出最后的脈沖數,然后顯示在數碼管上,比如500脈沖只要顯示500,不需要顯示增加的過程
作者: guhuawei19    時間: 2024-7-1 09:51
xiaobendan001 發表于 2024-6-29 10:35
不知道你的準確意圖,看起來脈沖是接外中斷0,外中斷1是清零。如果不清零就一直在0-9999之間循環。顯示一直 ...

while(1)               
        {
        if(flag==1)
        {
        DelayXms(100);
                 display_Service();
       
        }
改成這樣能否正常顯示
作者: xiaobendan001    時間: 2024-7-1 11:41
DelayXms(100);的意圖是什么啊?
作者: xiaobendan001    時間: 2024-7-1 13:03
guhuawei19 發表于 2024-7-1 07:56
不需要一直更新顯示,只需要讀出最后的脈沖數,然后顯示在數碼管上,比如500脈沖只要顯示500,不需要顯示 ...

這意思是外中斷1是接在編碼器的Z相了?
作者: guhuawei19    時間: 2024-7-1 16:26
xiaobendan001 發表于 2024-7-1 11:41
DelayXms(100);的意圖是什么啊?

不加延時的話,進一次中斷就顯示一次速度太快了吧?會顯示不清楚吧

作者: guhuawei19    時間: 2024-7-1 16:27
xiaobendan001 發表于 2024-7-1 13:03
這意思是外中斷1是接在編碼器的Z相了?

是的,中斷1接到Z相
作者: xiaobendan001    時間: 2024-7-2 07:16
guhuawei19 發表于 2024-7-1 16:26
不加延時的話,進一次中斷就顯示一次速度太快了吧?會顯示不清楚吧

無論調用多少次顯示,都只是在Z相信號到來時的瞬間才更新顯示,其余時間都是在現實之前的內容,所以從視覺上是看不到的。
比如我在研究TM1650的時候,顯示在主循環,顯示內容是定時器,1秒變一次,主循環在1秒里面不知道循環了多少次了,顯示依舊穩定的很。
可惜1650的按鍵掃描太慢了,做不了編碼器。
作者: guhuawei19    時間: 2024-7-2 10:45
xiaobendan001 發表于 2024-7-2 07:16
無論調用多少次顯示,都只是在Z相信號到來時的瞬間才更新顯示,其余時間都是在現實之前的內容,所以從視 ...

那使用脈沖計數呢





歡迎光臨 (http://www.raoushi.com/bbs/) Powered by Discuz! X3.1