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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 9247|回復: 24
打印 上一主題 下一主題
收起左側

STC12 串口通訊問題 程序非常簡單 困擾好幾天了

[復制鏈接]
跳轉到指定樓層
樓主
ID:64911 發表于 2014-8-10 06:34 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
現象:
1:我用stc-isp軟件給單片機下載程序后重啟開發板,
2:再次點stc-isp軟件上的下載/編程按鈕,這次我不重啟開發板,為了模擬通訊,一直循環給開發板發數據。
3:沒過多久,led1或者led2會點亮。
我的理解:
1:理論上TEnd=0或者1,但是這里TEnd還會等于256或者-255。不會再等于其他任何數據。
2:如果是定時器太短,導致主程序跑不動延時了,TEnd完全會不定期等于其他數據,但是沒有,他只會等于256或者-255這兩個特殊數據。
3:我懷疑是數據溢出 因為這兩個數據跟8bit,byte有關系。
#include<reg52.h>
#define uchar8 unsigned char //8
#define uint16 unsigned int //16
#define ulong32 unsigned long //32

sbit led0=P1^0;
sbit led1=P1^1;
sbit led2=P1^2;

ulong32 TStar=0;//記錄時間
ulong32 TEnd=0;
ulong32 sys1ms=0;//1ms累加,可以一直累加到49.7天

void main()
{        
        //1ms@12.000MHz
        TMOD &= 0xF0;                //設置定時器模式
        TMOD |= 0x01;                //設置定時器模式
        TL0 = 0x18;                //設置定時初值
        TH0 = 0xFC;                //設置定時初值
        TF0 = 0;                //清除TF0標志
        TR0 = 1;                //定時器0開始計時
        //4800bps@12.000MHz
        PCON |= 0x80;                //使能波特率倍速位SMOD
        SCON = 0x50;                //8位數據,可變波特率
        TMOD &= 0x0F;                //清除定時器1模式位
        TMOD |= 0x20;                //設定定時器1為8位自動重裝方式
        TL1 = 0xF3;                //設定定時初值
        TH1 = 0xF3;                //設定定時器重裝值
        ET1 = 0;                //禁止定時器1中斷
        TR1 = 1;                //啟動定時器1

        EA=1;//開啟總中斷
        ES=1;//開串口中斷
        ET0=1;//開定時器0中斷
        while(1)
        {
                ulong32 temp;
                TStar=sys1ms;//掃描周期記錄初始值

                //todo_something1();
                //todo_something2 ();

                temp=sys1ms-TStar;
                if(TEnd<=temp)TEnd=temp;//掃描周期計時
               
                if(TEnd!=256 && TEnd!=-255)led0=0;
                if(TEnd==256)led1=0;
                if(TEnd==-255)led2=0;
        }
}

void Timer0_Interrupt() interrupt 1//定時器0 1ms 中斷程序
{        
        TL0 = 0x18;                //設置定時初值
        TH0 = 0xFC;                //設置定時初值
        sys1ms++;                //1ms累加,可以一直累加到49.7天
}

void Comm_Interrupt() interrupt 4//串行中斷程序
{
        if(TI)
        {
                TI = 0;
        }
        if(RI)
        {        
                 char value;
         value=SBUF;
         RI=0;
        }
}
分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:19715 發表于 2014-8-10 10:57 | 只看該作者
void Comm_Interrupt() interrupt 4//串行中斷程序
{
        if(TI)
        {
                TI = 0;
        }
         if(RI)
        {        
                char value;
                value=SBUF;
                RI=0;
        }
}

回復

使用道具 舉報

板凳
ID:64911 發表于 2014-8-10 11:47 | 只看該作者
明白 發表于 2014-8-10 10:57
void Comm_Interrupt() interrupt 4//串行中斷程序
{
        if(TI)

你好 我把串行中斷程序改成你這樣后   癥狀1確實沒有了,
但是癥狀2就出來了,我是這樣做的:
1:我用stc-isp給單片機下載修改后的程序,
2:重啟開發板,然后點stc-isp下載/編程按鈕,我不重啟開發板,相當于模擬通訊。
3:大概在2分鐘之內,led2還是會點亮。。
回復

使用道具 舉報

地板
ID:19715 發表于 2014-8-10 12:37 | 只看該作者
程序運行,TEnd完全有可能去到256,
主要是因為定時器0的中斷周期太短,主程序跑不動

評分

參與人數 1威望 +20 收起 理由
admin + 20 贊一個!

查看全部評分

回復

使用道具 舉報

5#
ID:64911 發表于 2014-8-10 13:10 | 只看該作者
本帖最后由 xiehuipeng 于 2014-8-10 13:57 編輯
明白 發表于 2014-8-10 12:37
程序運行,TEnd完全有可能去到256,
主要是因為定時器0的中斷周期太短,主程序跑不動

那個Tend還會=-255.
我覺得這應該是溢出的問題 Tend只會出現這兩個特殊的數字256或者-255  因為這兩個數據跟8bit,byte有關系。
如果是按你說的,那應該會不定期出現其他數值。我最開始的程序就是通訊讀到Tend只會等于256或者-255 。
再次說明一下:只會等于256和-255,不可能出現其他值。大哥可以試一下。。



回復

使用道具 舉報

6#
ID:19715 發表于 2014-8-10 22:20 | 只看該作者
xiehuipeng 發表于 2014-8-10 13:10
那個Tend還會=-255.
我覺得這應該是溢出的問題 Tend只會出現這兩個特殊的數字256或者-255  因為這兩個數 ...

確實不解???應該問問老姚
回復

使用道具 舉報

7#
ID:19715 發表于 2014-8-10 22:56 | 只看該作者
問題找到了,是因為程序做減法太過頻繁導致
回復

使用道具 舉報

8#
ID:19715 發表于 2014-8-10 23:14 | 只看該作者
操作太過于頻繁導致
有可能【TStar=sys1ms;】之后的數值TStar=0x*****1ff,sys1ms=0x******100,
意思就是說在移動最低字節的時候,TStar和ys1ms都是TStar=0x******ff,在沒有來得及次低字節的時候,
定時器中斷來了,中斷響應處理之后sys1ms肯定變成0x******100,又回到移動次低字節,
這個時候次低字節不再是原來值,而是多1了,
所以出現,執行【TStar=sys1ms】之后,TStar=0x*****1ff,而sys1ms=0x******100,
temp=(sys1ms-TStar);的結果就是:
(0x******100)-(0x*****1ff)=FFFFFF01=-255
回復

使用道具 舉報

9#
ID:19715 發表于 2014-8-10 23:23 | 只看該作者
數值中的‘* ’可以是任意十六進制數,所以出現這種可能性就更多
回復

使用道具 舉報

10#
ID:19715 發表于 2014-8-10 23:36 | 只看該作者
既然問題找到了,就可以解決了,
加上(sys1ms加1)標志位:incOK
void main()
{        
        //1ms@12.000MHz
        TMOD &= 0xF0;                //設置定時器模式
        TMOD |= 0x01;                //設置定時器模式
        TL0 = 0x18;                //設置定時初值
        TH0 = 0xFC;                //設置定時初值
        TF0 = 0;                //清除TF0標志
        TR0 = 1;                //定時器0開始計時

        //4800bps@12.000MHz
        PCON |= 0x80;                //使能波特率倍速位SMOD
        SCON = 0x50;                //8位數據,可變波特率
        TMOD &= 0x0F;                //清除定時器1模式位
        TMOD |= 0x20;                //設定定時器1為8位自動重裝方式
        TL1 = 0xF3;                //設定定時初值
        TH1 = 0xF3;                //設定定時器重裝值
        ET1 = 0;                //禁止定時器1中斷
        TR1 = 1;                //啟動定時器1

        EA=1;//開啟總中斷
        ES=1;//開串口中斷
        ET0=1;//開定時器0中斷
                incOK=0;   //sys1ms加1標志位就可以incOK
        while(1)
        {
                ulong32 temp;
           if(incOK)        //是加上1,才做減法                {
                        TStar=sys1ms;//掃描周期記錄初始值
                   temp=(sys1ms-TStar);
                incOK=0;
                }
                if(TEnd<=temp)TEnd=temp;//掃描周期計時               
           if((TEnd!=256) && (TEnd!=-255))led0=0;
                if(TEnd==256)led1=0;
                if(TEnd==-255)led2=0;
        }
}
回復

使用道具 舉報

11#
ID:19715 發表于 2014-8-10 23:38 | 只看該作者
#include<reg52.h>
#define uchar8 unsigned char //8
#define uint16 unsigned int //16
#define ulong32 unsigned long //32
sbit led0=P2^0;
sbit led1=P2^1;
sbit led2=P2^2;
bit  incOK;
ulong32 TStar=0;//記錄時間
ulong32 TEnd=0;
ulong32 sys1ms=0;//1ms累加,可以一直累加到49.7天
void Timer0_Interrupt() interrupt 1//定時器0 1ms 中斷程序
{        
        TL0 = 0x18;                //設置定時初值
        TH0 = 0xFC;                //設置定時初值
        sys1ms++;                //1ms累加,可以一直累加到49.7天
                incOK=1;
}
void Comm_Interrupt() interrupt 4//串行中斷程序
{
        if(TI)
        {
                TI = 0;
        }
        else if(RI)
        {        
              unsigned  char value;
                value=SBUF;
                        RI=0;
        }
}
void main()
{         //1ms@12.000MHz
        TMOD &= 0xF0;                //設置定時器模式
        TMOD |= 0x01;                //設置定時器模式
        TL0 = 0x18;                //設置定時初值
        TH0 = 0xFC;                //設置定時初值
        TF0 = 0;                //清除TF0標志
        TR0 = 1;                //定時器0開始計時
        //4800bps@12.000MHz
        PCON |= 0x80;                //使能波特率倍速位SMOD
        SCON = 0x50;                //8位數據,可變波特率
        TMOD &= 0x0F;                //清除定時器1模式位
        TMOD |= 0x20;                //設定定時器1為8位自動重裝方式
        TL1 = 0xF3;                //設定定時初值
        TH1 = 0xF3;                //設定定時器重裝值
        ET1 = 0;                //禁止定時器1中斷
        TR1 = 1;                //啟動定時器1

        EA=1;//開啟總中斷
        ES=1;//開串口中斷
        ET0=1;//開定時器0中斷
                incOK=0;   //sys1ms加1標志位就可以incOK
        while(1)
        {
                ulong32 temp;
                                if(incOK)  //是加上1,才做減法
                                        {
                        TStar=sys1ms;//掃描周期記錄初始值
                        temp=(sys1ms-TStar);
                                        incOK=0;
                                        }
                if(TEnd<=temp)TEnd=temp;//掃描周期計時               
                if((TEnd!=256) && (TEnd!=-255))led0=0;
                if(TEnd==256)led1=0;
                if(TEnd==-255)led2=0;
        }
}
回復

使用道具 舉報

12#
ID:19715 發表于 2014-8-10 23:46 | 只看該作者
32位的二進制做計算,消耗時間多一點。
這樣可以確保在計算過程,不來中斷
回復

使用道具 舉報

13#
ID:19715 發表于 2014-8-10 23:53 | 只看該作者
同樣道理:原來癥狀2也可能出現于
TEnd==-65535,不過機辨少很多
回復

使用道具 舉報

14#
ID:19715 發表于 2014-8-11 10:35 | 只看該作者
也可以停止定時器TR0 =0;      
處理好數據之后,
才重新啟動定時器, TR0 =1;
用定時初始值為0,        TL0 =TH0 = 0;
加上16位中斷溢出(比如uchar型:sys65ms),
構成18位二進制定時器
這樣定時時間可以去到16秒(晶振12mhz)

#include<reg52.h>
#define uchar8 unsigned char //8
#define uint16 unsigned int //16
#define ulong32 unsigned long //32
sbit led0=P2^0;
sbit led1=P2^1;
sbit led2=P2^2;
ulong32 TEnd=0;        //記錄時間
uchar8 sys65ms=0;//65ms累加,可以一直累加到16秒
void Timer0_Interrupt() interrupt 1//定時器0 1ms 中斷程序
{        
        sys65ms++;                //1ms累加,可以一直累加到49.7天
}
void Comm_Interrupt() interrupt 4//串行中斷程序
{
        if(TI)
        {
                TI = 0;
        }
        else if(RI)
        {        
              unsigned  char value;
                value=SBUF;
                        RI=0;
        }
}
void main()
{         //1ms@12.000MHz
        TMOD &= 0xF0;                //設置定時器模式
        TMOD |= 0x01;                //設置定時器模式
        TL0 = 0;                //從0開始跑時
        TH0 = 0;                //從0開始跑時
        TF0 = 0;                //清除TF0標志
        TR0 = 1;                //定時器0開始計時
        //4800bps@12.000MHz
        PCON |= 0x80;                //使能波特率倍速位SMOD
        SCON = 0x50;                //8位數據,可變波特率
        TMOD &= 0x0F;                //清除定時器1模式位
        TMOD |= 0x20;                //設定定時器1為8位自動重裝方式
        TL1 = 0xF3;                //設定定時初值
        TH1 = 0xF3;                //設定定時器重裝值
        ET1 = 0;                //禁止定時器1中斷
        TR1 = 1;                //啟動定時器1

           EA=1;//開啟總中斷
        ES=1;//開串口中斷
        ET0=1;//開定時器0中斷
        while(1)
        {       ulong32 temp;
               TR0=0;
                       temp=sys65ms;//掃描周期記錄
               temp<<=8;        //掃描周期記錄
               temp+=TH0;        //掃描周期記錄
               temp<<=8;        //掃描周期記錄
               temp+=TL0;   //掃描周期記錄
                               
                sys65ms = 0;     //重新計時
                TL0 = 0;         //重新計時      
                        TH0 = 0;         //重新計時   
                TR0=1;                               
                if(TEnd<=temp)TEnd=temp;//掃描周期計時              
           if((TEnd!=256) && (TEnd!=-255))led0=0;
                if(TEnd==256)led1=0;
                if(TEnd==-255)led2=0;
        }
}
回復

使用道具 舉報

15#
ID:64911 發表于 2014-8-11 12:18 | 只看該作者
本帖最后由 xiehuipeng 于 2014-8-11 12:34 編輯
明白 發表于 2014-8-11 10:35
也可以停止定時器TR0 =0;      
處理好數據之后,
才重新啟動定時器, TR0 =1;

非常感謝你 解決我大問題了 應該就是這個原因。。
是這樣的 我原本程序比這個復雜很多 因為有以上這個問題 才把程序精簡到最小化 便于大家看懂。
如果按照你這種解決方法 那我整個程序的計時架構就整個變掉了
里面很多地方都要32bit計時 精度要1ms  大概要10幾或者20個獨立的計時器 每個計時器 是靠2個變量 初值和終值 互不干涉 獨立計時
計時規則就是:取當前syst1ms為初值,計時到終值就是當前syst1ms -初值

原本程序的主函數是這樣的
void main()
{        
        Timer0Init();//0-0定時器0初始化
        UartInit();//0-1串口初始化
        EA=1;//開啟總中斷
        ES=1;//開串口中斷
        ET0=1;//開定時器0中斷
        while(1)
        {
                ulong32 temp;
                x_sysScan.TStar=x_sys1ms;//最大掃描周期 記錄初始值

                GetInput();//1-輸入采集
                Check();//2-主程序檢查
                SetOutput();//3-輸出刷新
                CommJudge();//4-通訊邏輯判斷

                temp=x_sys1ms-x_sysScan.TStar;
                if(x_sysScan.TEnd<=temp)x_sysScan.TEnd=temp;//最大掃描周期計算
        }
}


回復

使用道具 舉報

16#
ID:19715 發表于 2014-8-11 13:26 | 只看該作者
15個獨立的32bit計時器,
入棧出棧需要20條指令,
每一個32bit計時器,自加自判大概25條指令
這樣中斷要執行的指令數差不多:400條
假如平均每一條指令需要時間2us,
中斷周期1毫秒,能夠執行500條指令,
自身就用去400條,
剩下的100條指令時間,還要被串口所中斷,
。。
。。
主程序“跑得動”嗎

回復

使用道具 舉報

17#
ID:64911 發表于 2014-8-11 13:41 | 只看該作者
本帖最后由 xiehuipeng 于 2014-8-11 13:42 編輯
明白 發表于 2014-8-11 13:26
15個獨立的32bit計時器,
入棧出棧需要20條指令,
每一個32bit計時器,自加自判大概25條指令

不是這樣的
定時器0中斷程序只有這3條指令 因為sys1ms可以一直累加運行49.7天,一般機器運行一天就關機重啟了
在主程序里 這20個32bit的計時器的初值 和終值計算都是用這同一個sys1ms來計算的
比如 ulong32 sys_time_初值[20],sys_time_終值[20];
void mian()
{
if(條件1==1)sys_time_初值[0]=sys1ms;
if(條件2==1)sys_time_初值[1]=sys1ms;
if(條件3==1)sys_time_初值[2]=sys1ms;
if(條件1==0)sys_time_終值[0]=sys1ms-sys_time_初值[0];
if(條件2==0)sys_time_終值[1]=sys1ms-sys_time_初值[1];
if(條件3==0)sys_time_終值[2]=sys1ms-sys_time_初值[2];
}
void Timer0_Interrupt() interrupt 1//0-0定時器0 1ms 中斷程序
{        
        TL0 = 0x18;                //設置定時初值
        TH0 = 0xFC;                //設置定時初值
        sys1ms++;                //1ms累加,可以一直累加到49.7天
}這就是我程序的核心思想。。
回復

使用道具 舉報

18#
ID:19715 發表于 2014-8-11 13:48 | 只看該作者
這樣可以用TR0停止和啟動定時器,
回復

使用道具 舉報

19#
ID:19715 發表于 2014-8-11 13:49 | 只看該作者
void Timer0_Interrupt() interrupt 1//0-0定時器0 1ms 中斷程序
{        
        TL0 = 0x18;                //設置定時初值
        TH0 = 0xFC;                //設置定時初值
        sys1ms++;                //1ms累加,可以一直累加到49.7天
}
是3句c語言,不是3條指令
回復

使用道具 舉報

20#
ID:64911 發表于 2014-8-11 13:50 | 只看該作者
明白 發表于 2014-8-11 13:49
void Timer0_Interrupt() interrupt 1//0-0定時器0 1ms 中斷程序
{        
        TL0 = 0x18;         ...

嗯嗯 呵呵 寫錯了
回復

使用道具 舉報

21#
ID:64911 發表于 2014-8-11 13:59 | 只看該作者
明白 發表于 2014-8-11 13:48
這樣可以用TR0停止和啟動定時器,

本來1ms定時器會間隔1ms累加 我如果在主程序里頻繁地停止和啟動定時器 那應該就不準了吧 至少主程序執行消耗的時間就不計算了吧。
回復

使用道具 舉報

22#
ID:19715 發表于 2014-8-11 14:00 | 只看該作者
程序方式:
void main()
{        各個初始化
        while(1)
        {               TR0=0;
                       //記錄時間:time1
                //記錄時間:time2
                //記錄時間:time3
              開始重新計時                                 
                 //重新計時time1
                 //重新計時 time2   
                  //重新計時 time3   
                TR0=1;   
                  其他事情1                           
                 其他事情2   
        }
}
回復

使用道具 舉報

23#
ID:19715 發表于 2014-8-11 14:07 | 只看該作者
1ms,分辨率最大就只有1ms,
我前面介紹的18位二進制定時器,分辨率可以去到1us
相差多少倍,
程序很多地方是依靠自己的糾結,自己去衡量,然后自己做出處理,
想高精度,看一下匯編,
回復

使用道具 舉報

24#
ID:64911 發表于 2014-8-11 14:31 | 只看該作者
明白 發表于 2014-8-11 14:07
1ms,分辨率最大就只有1ms,
我前面介紹的18位二進制定時器,分辨率可以去到1us
相差多少倍,

謝謝大哥 我看懂你這個計時方式了 非常巧妙 學習了。。
回復

使用道具 舉報

25#
ID:19715 發表于 2014-8-11 15:15 | 只看該作者
xiehuipeng 發表于 2014-8-11 14:31
謝謝大哥 我看懂你這個計時方式了 非常巧妙 學習了。。

這種計時方式,不用重裝定時器初值,其實也是一種“純天然”重裝定時器初值
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 天堂一区在线观看 | 国产精品久久亚洲7777 | 国产婷婷色综合av蜜臀av | 国产线视频精品免费观看视频 | 精品亚洲一区二区三区 | 欧美一区二 | 欧美日韩18 | 伊人狠狠干 | 国产玖玖 | 狠狠操狠狠色 | 97avcc| 91免费在线 | 毛片在线视频 | 午夜视频在线播放 | 欧美一二三四成人免费视频 | 91精品国产91久久久久久三级 | 狠狠干2020| 久草视频在线播放 | 久久久xxx| 国外成人在线视频网站 | 一本一道久久a久久精品蜜桃 | 日韩www | 成人欧美一区二区三区在线播放 | 一级做a爰片性色毛片16美国 | 欧美成人视屏 | 久久久久国产一区二区三区 | 精品一区二区三区av | 九九色九九 | 日韩靠逼| 久久久久国产一区二区三区四区 | 欧美视频免费 | 久久亚洲欧美日韩精品专区 | 中文字幕二区 | 国产美女在线看 | 欧美一级精品片在线看 | 成人免费看黄网站在线观看 | 久草综合在线视频 | 国产高清av免费观看 | 亚洲视频一区在线观看 | 日本二区在线观看 | 久草网址 |