標(biāo)題: 51單片機(jī)Uart和定時器0同時使用問題 [打印本頁]

作者: wen1989jun    時間: 2023-8-19 15:13
標(biāo)題: 51單片機(jī)Uart和定時器0同時使用問題
如下為STC89C52單片機(jī)制作智能小車,藍(lán)牙遙控,紅外循跡均可單獨(dú)使用,兩個功能整合在一起時候藍(lán)牙遙控指令只有紅外循跡可使用了,其他指令小車不執(zhí)行對應(yīng)動作,請問代碼是哪里有問題,望指出,感謝!
1、懷疑藍(lán)牙發(fā)1-6時候,電機(jī)驅(qū)動并未使能,所以相應(yīng)動作未執(zhí)行,不太確認(rèn)是否是Timer0定時器未工作原因?
2、我用Timer0做電機(jī)驅(qū)動使能控制,Timer1做Uart,可T0的中斷優(yōu)先級比T1的要高,如何讓兩個同時用而不沖突呢?
3、另外,是否能在主函數(shù)給電機(jī)驅(qū)動定義變量,其他子函數(shù),包括中斷都能調(diào)用呢?如下代碼有在主函數(shù)定義變量,同時在紅外循跡中也定義了相同變量,如不定義,無法編譯
以上問題,希望各位大神指點(diǎn)下思路。

主函數(shù)

#include <REGX52.H>
#include "UART.H"
#include "MotorDrive.H"
#include "Timer0.H"
#include "IR_Tracking.H"

sbit L298N_ENA=P1^4;
sbit L298N_ENB=P1^5;
sbit L298N_ENA1=P1^1;
sbit L298N_ENB1=P0^2;

extern unsigned char Compare,Compare1,Compare2,Compare3;
extern unsigned char Counter,Counter1,Counter2,Counter3;



void main()
{
        UART_Init();
        Timer0_Init();
//        L298N_ENA=1;
//        L298N_ENB=1;
//        L298N_ENA1=1;
//        L298N_ENB1=1;
        while(1)
        {
               
        }
}


void Timer0_Routine() interrupt 1
{
        TL0=0xA4;  //設(shè)置定時初值
        TH0=0xFF;  //設(shè)置定時初值
        Counter++;
        Counter%=100;                //計(jì)數(shù)值變化范圍限制在0~99
        Counter1++;
        Counter1%=100;        //計(jì)數(shù)值變化范圍限制在0~99
        Counter2++;
        Counter2%=100;        //計(jì)數(shù)值變化范圍限制在0~99
        Counter3++;
        Counter3%=100;        //計(jì)數(shù)值變化范圍限制在0~99
        if(Counter<Compare)
        {
                L298N_ENA=1;
        }
        else
        {
                L298N_ENA=0;
        }
        if(Counter1<Compare1)
        {
                L298N_ENB=1;
        }
        else
        {
                L298N_ENB=0;
        }
        if(Counter2<Compare2)
        {
                L298N_ENA1=1;
        }
        else
        {
                L298N_ENA1=0;
        }
        if(Counter3<Compare3)
        {
                L298N_ENB1=1;
        }
        else
        {
                L298N_ENB1=0;
        }
}

void UART_Routine() interrupt 4    //串口中斷
{         
unsigned char Data;
if(RI==1)   //允許單片機(jī)接收數(shù)據(jù)
{
        Data=SBUF;                   //讀取數(shù)據(jù)
        UART_SendByte(SBUF);  //將接收到的數(shù)據(jù)發(fā)回串口
        RI=0;  //接收標(biāo)志位清0 軟件復(fù)位
switch(Data)
  {
        case 0:StopIt();                break;
        case 1:Forward();                break;
        case 2:BackOff();                break;
        case 3:TurnLeft();        break;
        case 4:TurnRight();        break;
        case 5:TurnLeftCircle();                break;
        case 6:TurnRightCircle();                break;
        case 7:IR_Tracking(); break;

  }
}
}



UART

#include <REGX52.H>

/**
*@brief  串口初始化9600bps@11.0592MHz
*@param  無
*retval  無
**/
void UART_Init()                //9600bps@11.0592MHz
{
        PCON &= 0x7F;                //波特率不倍速
        SCON = 0x50;                //8位數(shù)據(jù),可變波特率
        TMOD &= 0x0F;                //清除定時器1模式位
        TMOD |= 0x20;                //設(shè)定定時器1為8位自動重裝方式
        TL1 = 0xFD;                //設(shè)定定時初值
        TH1 = 0xFD;                //設(shè)定定時器重裝值
        ET1 = 0;                //禁止定時器1中斷
        TR1 = 1;        //啟動定時器1
        EA        =1;
        ES        =1;
}

/**
*@brief  串口發(fā)送一個數(shù)據(jù)
*@param  Byte
*retval  無
*/

void UART_SendByte(unsigned char Byte)
{
        SBUF=Byte;
        while(TI==0);
        TI=0;
}

電機(jī)驅(qū)動

#include <REGX52.H>

sfr P4=0xe8;

sbit L298N_IN1        =P1^2;
sbit L298N_IN2        =P1^3;        //IN1&1N2是右前輪
sbit L298N_IN3        =P1^6;
sbit L298N_IN4        =P1^7;        //IN3&IN4是右后輪

sbit L298N_IN41        =P0^1;
sbit L298N_IN31        =P0^0;        //IN31&IN41是左前輪
sbit L298N_IN21        =P4^2;
sbit L298N_IN11        =P1^0;        //IN21&IN11是左后輪

void Forward()  //前進(jìn)
{
                L298N_IN1=0;
                L298N_IN2=1;
                L298N_IN3=0;
                L298N_IN4=1;
                L298N_IN11=1;
                L298N_IN21=0;
                L298N_IN31=1;
                L298N_IN41=0;
}

void BackOff()        //后退
{

                L298N_IN1=1;
                L298N_IN2=0;
                L298N_IN3=1;
                L298N_IN4=0;
                L298N_IN11=0;
                L298N_IN21=1;
                L298N_IN31=0;
                L298N_IN41=1;
}

void TurnRight()        //右轉(zhuǎn)
{
                L298N_IN11=1;
                L298N_IN21=0;
                L298N_IN31=1;
                L298N_IN41=0;
}

void TurnRightCircle()        //右轉(zhuǎn)圈
{
                L298N_IN1=1;
                L298N_IN2=0;
                L298N_IN3=1;
                L298N_IN4=0;
                L298N_IN11=1;
                L298N_IN21=0;
                L298N_IN31=1;
                L298N_IN41=0;
}

void TurnLeft()        //左轉(zhuǎn)
{
                L298N_IN1=0;
                L298N_IN2=1;
                L298N_IN3=0;
                L298N_IN4=1;
        
}

void TurnLeftCircle()        //左轉(zhuǎn)圈
{
                L298N_IN1=0;
                L298N_IN2=1;
                L298N_IN3=0;
                L298N_IN4=1;
                L298N_IN11=0;
                L298N_IN21=1;
                L298N_IN31=0;
                L298N_IN41=1;
}

void StopIt()        //停止
{
                L298N_IN1=0;
                L298N_IN2=0;
                L298N_IN3=0;
                L298N_IN4=0;
                L298N_IN11=0;
                L298N_IN21=0;
                L298N_IN31=0;
                L298N_IN41=0;
}


Timer0

#include <REGX52.H>

void Timer0_Init()        //100微秒@11.0592MHz
{
        TMOD &= 0xF0;                //設(shè)置定時器模式
        TMOD |= 0x01;                //設(shè)置定時器模式
        TL0 = 0xA4;                //設(shè)置定時初值
        TH0 = 0xFF;                //設(shè)置定時初值
        TF0 = 0;                //清除TF0標(biāo)志
        TR0 = 1;                //定時器0開始計(jì)時
        ET0=1;
        EA=1;
        PT0=1;
}




紅外循跡

#include <REGX52.H>
#include "MotorDrive.H"

sbit LM339_OUT1=P0^4;        //IR_1
sbit LM339_OUT2=P0^5;        //IR_2
sbit LM339_OUT3=P0^7;        //IR_3
sbit LM339_OUT4=P0^6;        //IR_4

unsigned char Compare,Compare1,Compare2,Compare3;
unsigned char Counter,Counter1,Counter2,Counter3;

void IR_Tracking()
{
        while(1)
        {
                if(LM339_OUT2==0&&LM339_OUT3==0)
{        
                        Compare=8;
                        Compare1=8;
                        Compare2=8;
                        Compare3=8;
                        Forward();
}

                if(LM339_OUT2==1&&LM339_OUT3==1)
{
                        StopIt();
}
               
                if(LM339_OUT2==1&&LM339_OUT3==0)
{
                        Compare=50;
                        Compare1=50;
                        TurnLeftCircle();
}
                if(LM339_OUT2==0&&LM339_OUT3==1)
{
                        Compare2=50;
                        Compare3=50;
                        TurnRightCircle();
}

        }

                }







作者: wen1989jun    時間: 2023-8-19 15:54
自己先頂下帖子
作者: wen1989jun    時間: 2023-8-21 09:23
自頂下,求大神解惑
作者: yzwzfyz    時間: 2023-8-21 09:27
2、我用Timer0做電機(jī)驅(qū)動使能控制,Timer1做Uart,可T0的中斷優(yōu)先級比T1的要高,如何讓兩個同時用而不沖突呢?
說明你很聰明,發(fā)現(xiàn)問題了。
解決的方案:
讓T0的中斷服務(wù)程序運(yùn)行時間,低于串行CLK的半個周期,如波特率=2400,周期=417us。
如何辦到:
在【T0的中斷服務(wù)程序】中,只做一個標(biāo)記【ZDT0=1】,表示發(fā)生了中斷。其它需要處理的事項(xiàng),放在主程序去做。主程序識別到【ZDT0=1】,就處理中斷事件,處理完成后復(fù)柆【ZDT0=0】。
這樣就不會影響T1中斷了。
明白了這個道理之后,記住【這是精華】:所有的【中斷服務(wù)程序】都要盡可能的短。方法:【中斷服務(wù)程序】只做標(biāo)記,不做中斷事件處理(除非萬不得矣),中斷事件的處理,盡可能放在主程序中去做!


作者: devcang    時間: 2023-8-21 10:16
主要原因是在中斷中,語句耗時太多。

~
作者: wen1989jun    時間: 2023-8-21 15:16
devcang 發(fā)表于 2023-8-21 10:16
主要原因是在中斷中,語句耗時太多。

~

能展開詳細(xì)說說么,我來驗(yàn)證下
作者: wen1989jun    時間: 2023-8-21 15:51
yzwzfyz 發(fā)表于 2023-8-21 09:27
2、我用Timer0做電機(jī)驅(qū)動使能控制,Timer1做Uart,可T0的中斷優(yōu)先級比T1的要高,如何讓兩個同時用而不沖突 ...

Uart中斷做標(biāo)志位,主程序做識別,之前中斷里面的Switch可以放在主程序里面去做即可對么?

其它需要處理的事項(xiàng),放在主程序去做。主程序識別到【ZDT0=1】,就處理中斷事件,處理完成后復(fù)柆【ZDT0=0】。
通過這句話我又感覺不能用Switch去做了

真是抱歉,C語言和單片機(jī)都是初學(xué),還有很多不理解的地方,一會兒我去試試寫代碼驗(yàn)證看看,還是非常感謝您的解答!!

作者: wen1989jun    時間: 2023-8-23 18:04
經(jīng)過4樓大神的指導(dǎo),現(xiàn)在把紅外循跡代碼放到主程序來了,把Uart里面中斷處理事情放在主程序來了之后,實(shí)現(xiàn)了藍(lán)牙遙控小車及紅外循跡功能了。
出現(xiàn)了一個新的問題,當(dāng)紅外循跡指令發(fā)給MCU后,其他指令MCU能識別及返回,但不執(zhí)行相應(yīng)的動作了

#include <REGX52.H>
#include <Timer0.H>
#include "UART.H"
#include "MotorDrive.H"

sbit L298N_ENA=P1^4;
sbit L298N_ENB=P1^5;
sbit L298N_ENA1=P1^1;
sbit L298N_ENB1=P0^2;

sbit LM339_OUT1=P0^4;        //IR_1
sbit LM339_OUT2=P0^5;        //IR_2
sbit LM339_OUT3=P0^7;        //IR_3
sbit LM339_OUT4=P0^6;        //IR_4

unsigned char Compare,Compare1,Compare2,Compare3;
unsigned char Counter,Counter1,Counter2,Counter3;

unsigned char Data;

void IR_Tracking()
{
        while(1)
        {
                if(LM339_OUT2==0&&LM339_OUT3==0)
{       
                        Compare=8;
                        Compare1=8;
                        Compare2=8;
                        Compare3=8;
                        Forward();
}

                if(LM339_OUT2==1&&LM339_OUT3==1)
{
                        StopIt();
}
               
                if(LM339_OUT2==1&&LM339_OUT3==0)
{
                        Compare=50;
                        Compare1=50;
                        TurnLeftCircle();
}
                if(LM339_OUT2==0&&LM339_OUT3==1)
{
                        Compare2=50;
                        Compare3=50;
                        TurnRightCircle();
}

        }

                }

void main()
{
        UART_Init();
        Timer0_Init();
        Compare=20;
        Compare1=20;
        Compare2=20;
        Compare3=20;
        while(1)
        {
                if(Data==1)
                {
                        Compare=20;
                        Compare1=20;
                        Compare2=20;
                        Compare3=20;
                        Forward();
                }
                if(Data==2)
                {
                        Compare=20;
                        Compare1=20;
                        Compare2=20;
                        Compare3=20;
                        BackOff();
                }
                if(Data==7)
                {
                        IR_Tracking();
                }
                if(Data==0)
                {
                        StopIt();
                }
        }
}


void Timer0_Routine() interrupt 1
{
        TL0=0xA4;  //設(shè)置定時初值
        TH0=0xFF;  //設(shè)置定時初值
        Counter++;
        Counter%=100;                //計(jì)數(shù)值變化范圍限制在0~99
        Counter1++;
        Counter1%=100;        //計(jì)數(shù)值變化范圍限制在0~99
        Counter2++;
        Counter2%=100;        //計(jì)數(shù)值變化范圍限制在0~99
        Counter3++;
        Counter3%=100;        //計(jì)數(shù)值變化范圍限制在0~99
        if(Counter<Compare)
        {
                L298N_ENA=1;
        }
        else
        {
                L298N_ENA=0;
        }
        if(Counter1<Compare1)
        {
                L298N_ENB=1;
        }
        else
        {
                L298N_ENB=0;
        }
        if(Counter2<Compare2)
        {
                L298N_ENA1=1;
        }
        else
        {
                L298N_ENA1=0;
        }
        if(Counter3<Compare3)
        {
                L298N_ENB1=1;
        }
        else
        {
                L298N_ENB1=0;
        }
}

void UART_Routine() interrupt 4    //串口中斷
{         

if(RI==1)   //允許單片機(jī)接收數(shù)據(jù)
{
        Data=SBUF;                   //讀取數(shù)據(jù)
        UART_SendByte(SBUF);  //將接收到的數(shù)據(jù)發(fā)回串口
        RI=0;  //接收標(biāo)志位清0 軟件復(fù)位
}
}
作者: glinfei    時間: 2023-8-24 10:43

UART_SendByte(SBUF);  //將接收到的數(shù)據(jù)發(fā)回串口
的后邊加一句:
Data-=48;
作者: ydatou    時間: 2023-8-24 12:01
wen1989jun 發(fā)表于 2023-8-23 18:04
經(jīng)過4樓大神的指導(dǎo),現(xiàn)在把紅外循跡代碼放到主程序來了,把Uart里面中斷處理事情放在主程序來了之后,實(shí)現(xiàn) ...
當(dāng)紅外循跡指令發(fā)給MCU后,其他指令MCU能識別及返回,但不執(zhí)行相應(yīng)的動作了

只需要把IR_Tracking()函數(shù)中的“while(1)”這行注釋就可以了。

你代碼還有些問題。
Data這個全局變量表示最后收到的數(shù)據(jù),還需要增加一個全局變量表示這數(shù)據(jù)是否已經(jīng)處理。
  1. bit gbTrack=0;
  2. bit gbRI=0;
  3. void main()
  4. {
  5.         UART_Init();
  6.         Timer0_Init();
  7.         Compare = Compare1 = Compare2 = Compare3 = 20;
  8.         while(1)
  9.         {
  10.                 if(gbTrack)
  11.                         IR_Tracking();//循跡
  12.                 if(gbRI)//有新的串口數(shù)據(jù) 在串口接收中斷中加入gbRI=1;
  13.                 {
  14.                         gbRI=0;//新的串口數(shù)據(jù)已處理
  15.                         gbTrack=0;//除循跡指令外,其它指令不循跡
  16.                         if(Data == 7)
  17.                                 gbTrack=1;//收到循跡指令
  18.                         else if(Data == 0)
  19.                                 StopIt();
  20.                         else if(Data == 1)
  21.                         {
  22.                                 Compare = Compare1 = Compare2 = Compare3 = 20;
  23.                                 Forward();
  24.                         }
  25.                         else if(Data == 2)
  26.                         {
  27.                                 Compare = Compare1 = Compare2 = Compare3 = 20;
  28.                                 BackOff();
  29.                         }
  30.                 }
  31.         }
  32. }
復(fù)制代碼



作者: wen1989jun    時間: 2023-8-24 16:53
glinfei 發(fā)表于 2023-8-24 10:43

UART_SendByte(SBUF);  //將接收到的數(shù)據(jù)發(fā)回串口
的后邊加一句:

按照您的指點(diǎn)在:UART_SendByte(SBUF); 后面增加了Data-=48;
驗(yàn)證失敗,串口能收到數(shù)據(jù),但所有指令均不識別,小車無任何動作
作者: wen1989jun    時間: 2023-8-24 16:57
ydatou 發(fā)表于 2023-8-24 12:01
只需要把IR_Tracking()函數(shù)中的“while(1)”這行注釋就可以了。

你代碼還有些問題。

把IR_Tracking()函數(shù)中的“while(1)”這行注釋就可以了。
//如上信息經(jīng)過驗(yàn)證,藍(lán)牙控制和紅外循跡指令均能識別。謝謝您

你代碼還有些問題。
Data這個全局變量表示最后收到的數(shù)據(jù),還需要增加一個全局變量表示這數(shù)據(jù)是否已經(jīng)處理。
//這部分代碼驗(yàn)證中,感謝您的指導(dǎo)
作者: wen1989jun    時間: 2023-8-29 16:45
ydatou 發(fā)表于 2023-8-24 12:01
只需要把IR_Tracking()函數(shù)中的“while(1)”這行注釋就可以了。

你代碼還有些問題。

此部分代碼已驗(yàn)證,可行。
作者: wen1989jun    時間: 2023-8-29 16:47
有一個小小的疑問,在主程序中定義了:
unsigned char Compare,Compare1,Compare2,Compare3;
unsigned char Counter,Counter1,Counter2,Counter3;
如果要把IR_Tracking()模塊化,那么是否也需要在IR_Tracking()里面再次定義?有點(diǎn)不太明白
作者: ydatou    時間: 2023-8-30 08:36
要在多個文件使用同一變量做法:
只在一個文件正常定義變量,其它文件變量定義加“extern”修飾,“extern”表示該變量定義在其它文件中。

其它方法,只在一個文件正常定義變量,其它文件不直接操作該變量,依賴函數(shù)操作。


作者: wen1989jun    時間: 2023-9-1 10:44
ydatou 發(fā)表于 2023-8-30 08:36
要在多個文件使用同一變量做法:
只在一個文件正常定義變量,其它文件變量定義加“extern”修飾,“extern ...

驗(yàn)證可行,感謝哦!
作者: rayin    時間: 2023-9-5 07:48
建議把中斷里的函數(shù)拿出來, 放到main()中來執(zhí)行.
中斷函數(shù)只需要做檢測外部事件, 根據(jù)外部事件設(shè)標(biāo)志位,
main()
{
  while(1)
  {
   if(標(biāo)志位1) function1();
  }
}
中根據(jù)外部事件標(biāo)志位來執(zhí)行相應(yīng)的執(zhí)行功能.
作者: wen1989jun    時間: 2023-9-5 09:28
rayin 發(fā)表于 2023-9-5 07:48
建議把中斷里的函數(shù)拿出來, 放到main()中來執(zhí)行.
中斷函數(shù)只需要做檢測外部事件, 根據(jù)外部事件設(shè)標(biāo)志位,
...

謝謝您的指點(diǎn),當(dāng)前按在您的方式來做,驗(yàn)證功能可行




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