久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索

STC 1T單片機的奇怪情況

查看數: 5504 | 評論數: 32 | 收藏 5
關燈 | 提示:支持鍵盤翻頁<-左 右->
    組圖打開中,請稍候......
發布時間: 2021-10-24 12:27

正文摘要:

先上單片機代碼 #include <reg52.h> sbit LED=P3^5; unsigned short TMR_XX_OT; sfr AUXR = 0x8E; void Timer0Init(void)                //1毫秒@12.00 ...

回復

ID:161164 發表于 2024-7-7 23:10
老董 發表于 2024-7-7 16:42
引腳設置了 嗎?P0M0 P0M1--P7M0 P7M1

不知道為啥舊帖子被推上來了
問題已經解決很久了
就是8樓wulin 說的原因
8位機要避免同時在中斷和主循環運算和比較多于8位的變量
ID:849913 發表于 2024-7-7 16:42
引腳設置了 嗎?P0M0 P0M1--P7M0 P7M1
ID:476652 發表于 2022-1-28 12:50
大神過招,我只能看來看去,啥也看不懂!!
ID:235055 發表于 2022-1-6 22:49
受教了,還以為是13位的方式0呢!
ID:155507 發表于 2022-1-5 22:52
sunny118 發表于 2022-1-5 22:23
怎么后面的幾個程序中定時器中斷響應后沒有重復初值了?

因為是 自動重裝
ID:235055 發表于 2022-1-5 22:23
怎么后面的幾個程序中定時器中斷響應后沒有重復初值了?
ID:161164 發表于 2021-10-28 00:55
188610329 發表于 2021-10-26 17:59
雖然,你這個修正解決了你目前的問題,但是,這個方案是有缺陷的:如果你程序比較長,定時器定時比較短, ...

受教了
ID:624769 發表于 2021-10-26 17:59
lkc8210 發表于 2021-10-26 01:14
有點覆雜

借鑒了你, 188610329總和wulin總的回覆

雖然,你這個修正解決了你目前的問題,但是,這個方案是有缺陷的:如果你程序比較長,定時器定時比較短,會出現掉幀的問題,即:當定時器把 INT0_EN 置1之后,你的主程序還沒有來的及判斷 INT0_EN 是否為1,你的定時器再次觸發,又一次把 INT0_EN 置一, 這個時候,你的主程序 才開始第一次判斷,那么就會少減一次(那么頻率就會不對)。所以這時候,通常會用傳char來避免這樣的情況發生。

代碼如下:

unsigned char INT0_Times,Temp;

void timer0_int (void) interrupt 1
{
        INT0_Times++;
}

void main()
{
    Timer0Init();
                ET0 = 1;
                EA = 1;
    while(1)
                {                        
                         if(INT0_Times != 0)                        {
                               Temp = INT0_Times;                               INT0_Times  -= Temp;     //防止這個時候中斷觸發又改寫了  INT0_Times  所以不直接 = 0,而用減法
                               TMR_01_OT  -= Temp;
                               if(CY)                       //有借位則反轉LED以及賦新值
                               {
                                   TMR_01_OT  +=270;
                                   LED1 = !LED1;
                                }
                                TMR_02_OT -=  Temp;
                                if(CY)
                               {         
                                    TMR_02_OT   +=273;
                                    LED2 = !LED2;
                                }                                TMR_03_OT -=  Temp;
                                if(CY)
                               {
                                     TMR_03_OT   +=277;
                                     LED3 = !LED3;
                               }                               TMR_04_OT -=  Temp;
                               if(CY)
                               {
                                     TMR_04_OT   +=281;
                                      LED4 = !LED4;
                               }
                        }
                }
}




這樣,就能避免掉幀的問題,并且如果這次少了1拍,下次會補回來,總的頻率不會發生變化,你可以參考一下。
ID:161164 發表于 2021-10-26 01:14
npn 發表于 2021-10-25 19:38
你遇到的問題和這個程序一樣,很多新人都會遇到:

有點覆雜

借鑒了你, 188610329總和wulin總的回覆
得出改善的代碼如下

  1. #include <reg52.h>

  2. typedef         unsigned char        u8;  //0 to 255
  3. typedef         unsigned int        u16;  //0 to 65535
  4. typedef         unsigned long        u32;  //0 to 4294967295
  5. sbit LED1=P3^5;
  6. sbit LED2=P3^4;
  7. sbit LED3=P3^3;
  8. sbit LED4=P3^2;
  9. bit T0_INT;
  10. u16 TMR_01_OT;
  11. u16 TMR_02_OT;
  12. u16 TMR_03_OT;
  13. u16 TMR_04_OT;

  14. sfr AUXR = 0x8E;
  15. void Timer0Init(void)                //1毫秒@12.000MHz
  16. {
  17.         AUXR &= 0x7F;                //定時器時鐘12T模式
  18.         TMOD &= 0xF0;                //設置定時器模式
  19.         TMOD |= 0x00;                //設置定時器模式
  20.         TL0 = 0x18;                //設置定時初始值
  21.         TH0 = 0xFC;                //設置定時初始值
  22.         TF0 = 0;                //清除TF0標志
  23.         TR0 = 1;                //定時器0開始計時
  24. }
  25. void timer0_int (void) interrupt 1
  26. {
  27.         INT0_EN = 1;
  28. }

  29. void main()
  30. {
  31.     Timer0Init();
  32.                 ET0 = 1;
  33.                 EA = 1;
  34.     while(1)
  35.                 {                       
  36.                         if(!TMR_01_OT)
  37.                         {TMR_01_OT=270;
  38.                                 LED1 = !LED1;
  39.                         }
  40.                         if(!TMR_02_OT)
  41.                         {TMR_02_OT=273;
  42.                                 LED2 = !LED2;
  43.                         }
  44.                         if(!TMR_03_OT)
  45.                         {TMR_03_OT=277;
  46.                                 LED3 = !LED3;
  47.                         }
  48.                         if(!TMR_04_OT)
  49.                         {TMR_04_OT=281;
  50.                                 LED4 = !LED4;
  51.                         }
  52.                         if(INT0_EN)
  53.                         {
  54.                                 INT0_EN = 0;
  55.                                 if(TMR_01_OT)TMR_01_OT--;
  56.                                 if(TMR_02_OT)TMR_02_OT--;
  57.                                 if(TMR_03_OT)TMR_03_OT--;
  58.                                 if(TMR_04_OT)TMR_04_OT--;
  59.                         }
  60.                 }
  61. }
復制代碼
ID:161164 發表于 2021-10-26 01:10
yzwzfyz 發表于 2021-10-25 17:31
都是不認真讀手冊的結果:

15.        TMOD &= 0xF0;                //設置定時器模式

你是不認真看貼子的結果

就算是用了13位定時器也不會出現閃爍不均勻的情況
ID:161164 發表于 2021-10-26 01:07
Jiang_YY 發表于 2021-10-25 16:07
TR0 = 0;TMR_XX_OT=270;TR0 = 1;
你在關閉定時器后清除一下定時器中斷標志,然后加2個NOP,看看。
按你 ...

不懂如何插入匯編
試了賦值兩次,都是重覆那個問題

已找到解決方法
ID:161164 發表于 2021-10-26 01:02
188610329 發表于 2021-10-25 13:56
說了,不是賦值的問題,是判斷的問題,
你要關定時器的話,得在 if 之前關,然后,整個 if 結束之后開才能徹 ...

因為一個TMR_XX就加一個傳標志
如果有幾個TMR_XX就要加幾個傳標志

借鑒了你的代碼
已找到解決方法
ID:57657 發表于 2021-10-25 19:38
你遇到的問題和這個程序一樣,很多新人都會遇到:
  1. #include "reg51.h"
  2. #include "intrins.h"
  3. #define u8 unsigned char
  4. #define u16 unsigned int
  5. u16 i;
  6. sbit CLK = P3 ^ 0;
  7. sbit ERR = P3 ^ 1;
  8. sbit ERR2 = P3 ^ 2;

  9. void InitTimer0(){
  10.     TMOD = 0x01;
  11.     TH0 = 0xFC;
  12.     TL0 = 0x18;
  13.     EA = 1;
  14.     ET0 = 1;
  15.     TR0 = 1;
  16. }

  17. void main() {
  18.     InitTimer0();
  19.     ERR = 1; ERR2 = 1;
  20.         while (1) {
  21.                 i = 0xABCD;     //16位變量:先賦值高8位,再賦值低8位
  22.                 i = 0x1234;     //觸發中斷只等待指令執行完成,不等待低8位賦值完成,中斷返回后才會去賦值低8位
  23.         //正確寫法:
  24.         //_push_(IE); IE = 0; i = 0xABCD; _pop_(IE);
  25.         //_push_(IE); IE = 0; i = 0x1234; _pop_(IE);
  26.         }
  27. }

  28. void Timer0Interrupt() interrupt 1{
  29.     TH0 = 0xFC;
  30.     TL0 = 0x18;
  31.     CLK = !CLK;
  32.     if (i != 0xABCD && i != 0x1234) {       //中斷讀取變量i,既不是0xABCD,也不是0x1234
  33.         ERR = 0;        //讀取出錯點亮
  34.         if (i != 0xAB34 && i != 0x12CD) {   //如果讀取出錯,會讀到這兩個值
  35.             ERR2 = 0;       //此燈如果被點亮則程序跑飛
  36.         }
  37.     }

  38. }
復制代碼
ID:123289 發表于 2021-10-25 17:31
都是不認真讀手冊的結果:

15.        TMOD &= 0xF0;                //設置定時器模式

在89C52中,這是13位定時器模式(注意不是16位),TH0TL0=FC18,中只有13位起作用,即時常數不是真正的FC18!
在STC中,設計者將定時器做了改進,增加了一個TH0TL0,的影子TH0TL0’,它們共用一個地址,這樣做的好處是,可以進行16自動重裝,所以在
在STC中,它是16位自動重裝模式,時常數是真正的16位:FC18!
ID:959346 發表于 2021-10-25 16:07
lkc8210 發表于 2021-10-25 11:22
在STC89上可以正常運行
應該不會是代碼或邏輯的問題

TR0 = 0;TMR_XX_OT=270;TR0 = 1;
你在關閉定時器后清除一下定時器中斷標志,然后加2個NOP,看看。
按你10樓回復,你把TMR_XX.Dat_i=270;改成插入匯編,然后先賦值低字節的,然后賦值高字節的,
MOV      0x09,#0x0E
MOV      TMR_XX(0x08),#0x01
或者直接TMR_XX.Dat_i=270;TMR_XX.Dat_i=270;寫2次,
看看是什么情況?
ID:624769 發表于 2021-10-25 13:56
lkc8210 發表于 2021-10-25 11:12
10樓有新發現但審批遲了

我試過停止定時器再賦值再運行定時器

說了,不是賦值的問題,是判斷的問題,
你要關定時器的話,得在 if 之前關,然后,整個 if 結束之后開才能徹底杜絕這個問題,而且,在if之前關,因為是15系列,要在ET0=0 之后放一個NOP,

其實,一個簡單的傳標志搞定的事情,不知道為啥你非要傳short……
ID:161164 發表于 2021-10-25 11:22
TTQ001 發表于 2021-10-25 08:50
應該是代碼的原因。 請仔細檢查程序。

在STC89上可以正常運行
應該不會是代碼或邏輯的問題
ID:161164 發表于 2021-10-25 11:16
wulin 發表于 2021-10-24 21:16
從邏輯上看程序沒有問題,但同一個16位變量在主函數和中斷中都可以操作容易出錯,有前輩就此問題詳細闡述 ...

10樓有新發現但審批遲了

我試過停止定時器再賦值再運行定時器
TR0 = 0;TMR_XX_OT=270;TR0 = 1;
已經確保定時器中斷不會打斷變量的賦值
也會出現這種情況
停止運行定時器和禁止定時中斷在防止打斷賦值的功能上是等價的吧?
ID:161164 發表于 2021-10-25 11:12
188610329 發表于 2021-10-25 00:24
不是 1T 的問題, 12T也會有這個問題,只是相比1T不容易出現(或者說不容易顯現出來)。而且你原程序,不 ...

10樓有新發現但審批遲了

我試過停止定時器再賦值再運行定時器
TR0 = 0;TMR_XX_OT=270;TR0 = 1;
已經確保定時器中斷不會打斷變量的賦值
也會出現這種情況
ID:420836 發表于 2021-10-25 08:50
應該是代碼的原因。 請仔細檢查程序。
ID:401564 發表于 2021-10-25 08:34
lkc8210 發表于 2021-10-24 21:38
改了后可以是可以,但是為什么1T會這樣,12T就正常?

這跟什么T的沒有關系
12T能正常只是運氣好而已,程序本身就是錯誤的
ID:624769 發表于 2021-10-25 00:24
lkc8210 發表于 2021-10-24 21:38
改了后可以是可以,但是為什么1T會這樣,12T就正常?

不是 1T 的問題, 12T也會有這個問題,只是相比1T不容易出現(或者說不容易顯現出來)。而且你原程序,不是那么簡單的幾句吧?應該有更多的內容,這次是為了測試才變那么“迷你”的吧?這是好事,以后程序復雜了,你沒有注意這點的話,發生“詭異”事件,反而更麻煩。

其實道理很簡單,中斷和主程序 或者 高級中斷和低級中斷之間傳參的話,8位機(51屬于8位機)必須避免16位傳參,因為不可必免會發生這樣的事情(程序越簡單發生概率越高):主程序在處理16位的變量,處理了其中的8位,這個時候中斷打斷,改寫了整個16位,這個時候返回主程序,主程序繼續處理剩下沒處理的8位(這8位已經是新的數據了),那么這個結果會錯的離譜。
所以,一旦有16位甚至32位的數據在中斷里累加累減計數,達到你預期值的時候,必須轉換成一個標志(bit),然后讓主程序按這個標志去執行。
ID:161164 發表于 2021-10-24 22:34
本帖最后由 lkc8210 于 2021-10-24 23:01 編輯

改用聯合體又正常了
  1. #include <reg52.h>

  2. sbit LED1=P3^5;

  3. typedef union{
  4.    unsigned char Dat_c[2];
  5.    unsigned int Dat_i;
  6. }EData;

  7. EData TMR_XX;
  8. sfr AUXR = 0x8E;
  9. void Timer0Init(void)                //1毫秒@12.000MHz
  10. {
  11.         AUXR &= 0x7F;                //定時器時鐘12T模式
  12.         TMOD &= 0xF0;                //設置定時器模式
  13.         TMOD |= 0x00;                //設置定時器模式
  14.         TL0 = 0x18;                //設置定時初始值
  15.         TH0 = 0xFC;                //設置定時初始值
  16.         TF0 = 0;                //清除TF0標志
  17.         TR0 = 1;                //定時器0開始計時
  18. }
  19. void timer0_int (void) interrupt 1
  20. {
  21.                 if(TMR_XX.Dat_i)TMR_XX.Dat_i--;
  22. }

  23. void main()
  24. {
  25.     Timer0Init();
  26.                 ET0 = 1;
  27.                 EA = 1;
  28.     while(1)
  29.                 {                        
  30.                         if(!TMR_XX.Dat_c[0] && !TMR_XX.Dat_c[1])
  31.                         {TMR_XX.Dat_i=270;
  32.                                 LED1 = !LED1;
  33.                         }
  34.                 }
  35. }
復制代碼



編譯出來發現if(!TMR_XX_OT)是用ORL
  1.     30:                         if(!TMR_01_OT)
  2. C:0x0013    E509     MOV      A,0x09
  3. C:0x0015    4508     ORL      A,TMR_01_OT(0x08)
  4. C:0x0017    70FA     JNZ      C:0013
  5.     31:                         {TMR_01_OT=270;
  6. C:0x0019    750801   MOV      TMR_01_OT(0x08),#0x01
  7. C:0x001C    75090E   MOV      0x09,#0x0E
復制代碼



if(!TMR_XX.Dat_c[0] && !TMR_XX.Dat_c[1]) 是用兩個JNZ
  1.     34:                         if(!TMR_XX.Dat_c[0] && !TMR_XX.Dat_c[1])
  2. C:0x0013    E508     MOV      A,TMR_XX(0x08)
  3. C:0x0015    70FC     JNZ      C:0013
  4. C:0x0017    E509     MOV      A,0x09
  5. C:0x0019    70F8     JNZ      C:0013
  6.     35:                         {TMR_XX.Dat_i=270;
  7. C:0x001B    750801   MOV      TMR_XX(0x08),#0x01
  8. C:0x001E    75090E   MOV      0x09,#0x0E
復制代碼



是ORL有問題嗎?
ID:161164 發表于 2021-10-24 21:38
188610329 發表于 2021-10-24 21:08
你按我寫的改了之后,不就知道了?

改了后可以是可以,但是為什么1T會這樣,12T就正常?
ID:213173 發表于 2021-10-24 21:16

從邏輯上看程序沒有問題,但同一個16位變量在主函數和中斷中都可以操作容易出錯,有前輩就此問題詳細闡述過。擇錄如下:
        /* 注釋二:
        * ET0=0;uiTimeCnt=0;ET0=1;----在清零 uiTimeCnt 之前,為什么要先禁止定時中斷?
        * 因為 uiTimeCnt 是 unsigned int 類型,本質上是由兩個字節組成。
        * 在 C 語言中 uiTimeCnt=0 看似一條指令,實際上經過編譯之后它不只一條匯編指令。
        * 由于定時中斷函數里也對這個變量進行累加操作,如果不禁止定時中斷,
        * 那么 uiTimeCnt 這個變量在 main()函數中還沒被完全清零的時候,如果這個時候
        * 突然來一個定時中斷,并且在中斷里又更改了此變量,這種情況在某些要求高的
        * 項目上會是一個不容易察覺的漏洞,為項目帶來隱患。當然,大部分的普通項目,
        * 都可以不用那么嚴格,可以不用禁止定時中斷。在這里只是提醒各位初學者有這種情況。
        */
建議改寫為:
void timer0_int (void) interrupt 1
{
        TL0 = 0x18;                //設置定時初始值
        TH0 = 0xFC;                //設置定時初始值
        if(--TMR_XX_OT==0)
        {
                TMR_XX_OT=270;
                flag=1;
        }
}

void main()
{
        Timer0Init();
        IE = 0;
        ET0 = 1;
        EA = 1;
        while(1)
        {
                if(flag)
                {
                        flag=0;
                        LED = !LED;
                }
        }
}
ID:624769 發表于 2021-10-24 21:08

你按我寫的改了之后,不就知道了?
ID:161164 發表于 2021-10-24 19:36
188610329 發表于 2021-10-24 19:25
你的問題不是 定時器賦值,而是那個TMR_XX_OT 的判斷,必須放到定時器里判斷是否為0,不能放在外面判斷。

為什么?
ID:624769 發表于 2021-10-24 19:25
lkc8210 發表于 2021-10-24 19:06
不太可能
我試過停止定時器再賦值再運行定時器都會出現這種情況
TR0 = 0;TMR_XX_OT=270;TR0 = 1;

你的問題不是 定時器賦值,而是那個TMR_XX_OT 的判斷,必須放到定時器里判斷是否為0,不能放在外面判斷。
ID:161164 發表于 2021-10-24 19:06
npn 發表于 2021-10-24 18:15
8位單片機向16位變量賦值,是分成兩條指令完成的。
先賦值高8位,此時中斷觸發改變了該變量的值。
中斷返 ...

不太可能
我試過停止定時器再賦值再運行定時器都會出現這種情況
TR0 = 0;TMR_XX_OT=270;TR0 = 1;

反而在while(1)底加上4個_nop_()就可以正常運作
是因為1T單片機太快了嗎?
ID:624769 發表于 2021-10-24 18:52
TMOD = 0x00;     //16位自動重載模式

bit     T_OT_Flag;    //增加一個標志位

void timer0_int (void) interrupt 1
{
//        TL0 = 0x18;                //設置定時初始值
//        TH0 = 0xFC;                //設置定時初始值    自動重載不需要設置
        if(--TMR_XX_OT==0)
        {
              TMR_XX_OT = 270;
              T_OT_Flag = 1;
        }
}

while 里面這么寫:

    while(1)
                {                        
                        if(T_OT_Flag)
                        {
                                T_OT_Flag = 0;
                                LED = !LED;
                        }
                }


然后試試看。
ID:57657 發表于 2021-10-24 18:15
8位單片機向16位變量賦值,是分成兩條指令完成的。
先賦值高8位,此時中斷觸發改變了該變量的值。
中斷返回后再去賦值低8位,導致程序出錯。

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 日本涩涩网 | 国产精品视频网 | 美女日皮网站 | 国产乱码精品一区二区三区五月婷 | 免费高清av | av在线播放网址 | 日韩欧美专区 | 曰韩三级| 欧美无乱码久久久免费午夜一区 | 精品久久久久久亚洲综合网 | 日韩电影在线一区 | 午夜手机在线 | 国产精品成人国产乱一区 | 国产免费看 | 久久在线 | 日韩高清国产一区在线 | 新91视频网 | 中文字幕视频在线 | 精品久久中文字幕 | www.99热这里只有精品 | 欧美激情精品久久久久 | 免费看a | 亚洲高清视频在线观看 | 亚洲国产成人av | 国产在线区 | 中文字幕av网 | 国产小视频在线观看 | 亚洲色综合 | 亚洲va中文字幕 | 亚洲欧美在线视频 | 欧美色999 | 伊人久久综合 | 久久免费视频观看 | 欧美日韩中文国产一区发布 | 亚洲一区视频在线 | 在线观看视频91 | 国产在线观看一区二区三区 | 中文字幕1区| 亚洲第一天堂 | 亚洲精品久久久久久久久久久 | 在线观看中文字幕视频 |