找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2057|回復(fù): 5
收起左側(cè)

怎么在原有的超聲波避障程序里增加PWM調(diào)速的功能

[復(fù)制鏈接]
ID:428425 發(fā)表于 2020-3-13 11:25 | 顯示全部樓層 |閱讀模式

******************************************************************/
//上電后按下K4鍵程序運(yùn)行,小車進(jìn)行超聲波避障跑
//LCD1602液晶屏上顯示探測到的實時距離

/**************************************************************
//重要說明:沒有LCD1602液晶顯示屏的師兄,需要用杜邦線將P0.7接地程序才能正常運(yùn)行
****************************************************************/

//注意程序只做參考之用,要達(dá)到最理想的避障效果,還需要師兄們細(xì)心調(diào)試。

#include <reg52.h>           //52芯片配置文件
#include <intrins.h>   //包含nop等系統(tǒng)函數(shù)
#include "bst_car.h"   //包含bst—v51智能小車頭文件

#define LCM_Data  P0   //定義液晶屏數(shù)據(jù)口
#define Busy    0x80   //用于檢測LCM狀態(tài)字中的Busy標(biāo)識

sbit DU = P2^6;                   //數(shù)碼管段選
sbit WE = P2^7;                   //數(shù)碼管位選

sbit LCM_RW=P1^1 ;     //定義LCD引腳
sbit LCM_RS=P1^0 ;
sbit LCM_E=P2^5         ;

unsigned char code Range[] ="==Range Finder==";//LCD1602顯示格式
unsigned char code ASCII[13] = "0123456789.-M";
unsigned char code table[]="Distance:000.0cm";
unsigned char code table1[]="!!! Out of range";

unsigned char disbuff[4]={0,0,0,0};//用于分別存放距離的值0.1mm、mm、cm和m的值

unsigned int  time=0;//用于存放定時器時間值
unsigned long S=0;//用于存放距離的值
bit  flag =0; //量程溢出標(biāo)志位
char a=0;

//=========================================================================================================================
void delay(unsigned int xms)                                
{
    unsigned int i,j;
        for(i=xms;i>0;i--)                      //i=xms即延時約xms毫秒
    for(j=112;j>0;j--);
}

void Delay10us(unsigned char i)            //10us延時函數(shù) 啟動超聲波模塊時使用
{
   unsigned char j;
do{
  j = 10;
  do{
   _nop_();
   }while(--j);
}while(--i);
}  

void cmg88()//關(guān)數(shù)碼管
{
    DU=1;  
    P0=0X00;
    DU=0;
}
/************************************LCD1602液晶屏驅(qū)動函數(shù)************************************************/
//*******************讀狀態(tài)*************************//
unsigned char ReadStatusLCM(void)
{
        LCM_Data = 0xFF;
        LCM_RS = 0;
        Delay10us(1);
        LCM_RW = 1;
        Delay10us(1);
        do{
        LCM_E = 0;
        Delay10us(1);
        LCM_E = 0;
        Delay10us(1);
        LCM_E = 1;
        Delay10us(1);
        }
        while (LCM_Data & Busy); //檢測忙信號
        return(LCM_Data);
}

/****************寫數(shù)據(jù)************************/
void WriteDataLCM(unsigned char WDLCM)
{
        ReadStatusLCM(); //檢測忙
        LCM_Data = WDLCM;
        LCM_RS = 1;
        Delay10us(1);
        LCM_RW = 0;
        Delay10us(1);
        LCM_E = 0; //若晶振速度太高可以在這后加小的延時
        Delay10us(1);
        LCM_E = 0; //延時
        Delay10us(1);
        LCM_E = 1;
        Delay10us(1);
}

//****************寫指令*************************//
void WriteCommandLCM(unsigned char WCLCM,BuysC) //BuysC為0時忽略忙檢測
{
        if (BuysC) ReadStatusLCM(); //根據(jù)需要檢測忙
        LCM_Data = WCLCM;
        LCM_RS = 0;
        Delay10us(1);
        LCM_RW = 0;        
        Delay10us(1);
        LCM_E = 0;
        Delay10us(1);
        LCM_E = 0;
        Delay10us(1);
        LCM_E = 1;
        Delay10us(1);
}



//*******************LCM初始化**********************//
void LCMInit(void)
{
        LCM_Data = 0;
        WriteCommandLCM(0x38,0); //三次顯示模式設(shè)置,不檢測忙信號
        delay(5);
        WriteCommandLCM(0x38,0);
        delay(5);
        WriteCommandLCM(0x38,0);
        delay(5);

        WriteCommandLCM(0x38,1); //顯示模式設(shè)置,開始要求每次檢測忙信號
        WriteCommandLCM(0x08,1); //關(guān)閉顯示
        WriteCommandLCM(0x01,1); //顯示清屏
        WriteCommandLCM(0x06,1); // 顯示光標(biāo)移動設(shè)置
        WriteCommandLCM(0x0c,1); // 顯示開及光標(biāo)設(shè)置
}

//*********************按指定位置顯示一個字符***********************//
void DisplayOneChar(unsigned char X, unsigned char Y, unsigned char DData)
{
        Y &= 0x1;
        X &= 0xF; //限制X不能大于15,Y不能大于1
        if (Y) X |= 0x40; //當(dāng)要顯示第二行時地址碼+0x40;
        X |= 0x80; //算出指令碼
        WriteCommandLCM(X, 1); //發(fā)命令字
        WriteDataLCM(DData); //發(fā)數(shù)據(jù)
}

//**********************按指定位置顯示一串字符*************************//
void DisplayListChar(unsigned char X, unsigned char Y, unsigned char code *DData)
{
        unsigned char ListLength;

  ListLength = 0;
        Y &= 0x1;
        X &= 0xF; //限制X不能大于15,Y不能大于1
        while (DData[ListLength]>0x19) //若到達(dá)字串尾則退出
                {
                        if (X <= 0xF) //X坐標(biāo)應(yīng)小于0xF
                                {
                                        DisplayOneChar(X, Y, DData[ListLength]); //顯示單個字符
                                        ListLength++;
                                        X++;
                                }
                }
}


/***************************************************************************/


void  StartModule()                          //啟動超聲波模塊
{
          TX=1;                                             //啟動一次模塊
      Delay10us(2);
          TX=0;
}

void Forward(void)//前進(jìn)
{

         IN2=1;
         IN3=1;
         IN1=0;
         IN4=0;
}

void Stop(void)        //停車
{

         IN1=0;
         IN2=0;
         IN3=0;
         IN4=0;
}

void back(void)        //后退
{

         IN1=1;
         IN2=0;
         IN3=0;
         IN4=1;
}   
void Turn_Right(void)         //向右旋轉(zhuǎn)
{
    IN1=0;
        IN2=1;
        IN3=0;
        IN4=1;

}
//=========================================================================================================================
/********距離計算程序***************/
void conut1(void)
{
        time=TH1*256+TL1;
        TH1=0;
        TL1=0;
        
                       //此時time的時間單位決定于晶振的頻率,外接晶振為11.0592MHZ
                               //那么1us聲波能走多遠(yuǎn)的距離呢?1s=1000ms=1000000us
                                   // 340/1000000=0.00034米
                                   //0.00034米/1000=0.34毫米  也就是1us能走0.34毫米
                                   //但是,我們現(xiàn)在計算的是從超聲波發(fā)射到反射接收的雙路程,
                                   //所以我們將計算的結(jié)果除以2才是實際的路程
    S=time*0.17+10;//此時計算到的結(jié)果為毫米,并且是精確到毫米的后兩位了,有兩個小數(shù)點(diǎn)
}

void Conut(void)
{
         
    conut1();
        //========顯示部分===========================================
        if((S>=5000)||flag==1) //超出測量范圍
        {
            a=0;        
            flag=0;
        DisplayListChar(0, 1, table1);
        }
        else
        {
        disbuff[0]=S%10;
            disbuff[1]=S/10%10;
            disbuff[2]=S/100%10;
            disbuff[3]=S/1000;
            DisplayListChar(0, 1, table);
            DisplayOneChar(9, 1, ASCII[disbuff[3]]);
            DisplayOneChar(10, 1, ASCII[disbuff[2]]);        
            DisplayOneChar(11, 1, ASCII[disbuff[1]]);
        DisplayOneChar(12, 1, ASCII[10]);
            DisplayOneChar(13, 1, ASCII[disbuff[0]]);
         }
         //========避障部分===========================================
         if(S<=240)         ////////////////////////////  剎車障礙物距離        跟車速有關(guān) 可更改
         {        
              a++;
              if(a>=2)
              {
                  a=0;
                  FM=0;
                      Stop();
                      back();  //后退緩沖
                      delay(230);//////////////////////////////////////////        后退緩沖時間 跟車速有關(guān) 可更改

                  B:Turn_Right();
                        delay(50);                  ///////////////////////////////////  旋轉(zhuǎn)角度 跟環(huán)境復(fù)雜程度有關(guān) 可更改
                        Stop();
                        delay(100);                ////////////////////////////////////   旋轉(zhuǎn)頓挫時間 視覺效果 可更改
                        StartModule();                                 
                        while(RX==0);
                        TR1=1;                            //開啟計數(shù)
                    while(RX);                        //當(dāng)RX為1計數(shù)并等待
                    TR1=0;                                //關(guān)閉計數(shù)
                        conut1();


                        if(S>340)         ////////////////////////         可直行方向無障礙物距離 跟環(huán)境有關(guān) 可更改
                        {
        
                            Turn_Right();
                            delay(90);        
                        Stop();                                  //微調(diào)前進(jìn)方向 避免車寬對前進(jìn)影響
                            delay(200);                  
                            FM=1;
                            Forward();
                        }               
                        else
                       {
                           goto B;                                //若沒轉(zhuǎn)到空曠方向 回到B點(diǎn) 繼續(xù)旋轉(zhuǎn)一次
                       }
               
               }
               else
                   {
                   Forward();        //無障礙物 直行
               }
        
         }

         else
         {
              a=0;
                   Forward();           //無障礙物 直行
         }
         //=======================================
         
}

/********************************************************/
void zd0() interrupt 3                  //T0中斷用來計數(shù)器溢出,超過測距范圍
{
    flag=1;                         //中斷溢出標(biāo)志
        RX=0;
}

/********超聲波高電平脈沖寬度計算程序***************/
void Timer_Count(void)
{
        TR1=1;                            //開啟計數(shù)
        while(RX);                        //當(dāng)RX為1計數(shù)并等待
        TR1=0;                                //關(guān)閉計數(shù)
    Conut();                        //計算

}
/********************************************************/
void keyscan(void)              //按鍵掃描函數(shù)
{
    A:    if(K4==0)                        //判斷是否有按下信號
                {
                    delay(10);                  //延時10ms
                        if(K4==0)                        //再次判斷是否按下
                         {
                            FM=0;               //蜂鳴器響                  
                            while(K4==0);        //判斷是否松開按鍵
                            FM=1;               //蜂鳴器停止  
                          }
                    else
                     {
                       goto A;        //跳轉(zhuǎn)到A重新檢測
                      }
                }
                else
                {
                  goto A;             //跳轉(zhuǎn)到A重新檢測
                }
}
/********************************************************/

/*************主程序********************/
void main(void)
{

        unsigned int a;
        cmg88();//關(guān)數(shù)碼管
        delay(400); //啟動等待,等LCM講入工作狀態(tài)
        LCMInit(); //LCM初始化
        delay(5);//延時片刻

        DisplayListChar(0, 0, Range);
        DisplayListChar(0, 1, table);
    TMOD=TMOD|0x10;//設(shè)T0為方式1,GATE=1;
    EA=1;                                           //開啟總中斷
    TH1=0;
    TL1=0;         
    ET1=1;             //允許T0中斷
    keyscan() ;  //按鍵掃描


        //=======================================================================================================================                        
         while(1)
        {
                RX=1;
            StartModule();                                 //啟動模塊
        for(a=951;a>0;a--)
            {
                  
               if(RX==1)
                   {
              Timer_Count();                 //超聲波高電平脈沖寬度計算函數(shù)
                   }
             }
           }
}





智能小車超聲波避障實驗.zip

34.76 KB, 下載次數(shù): 5

源程序

回復(fù)

使用道具 舉報

ID:342451 發(fā)表于 2020-3-13 12:06 | 顯示全部樓層
首先,你一下子粘出來這么多程序,就知道你沒有好好看懂這個程序,可能不是你寫的吧。拋出那些固定的函數(shù),每個自定義函數(shù)抬頭都有注釋,你理解下功能,看懂壁障那部分,你就會改車速了。
回復(fù)

使用道具 舉報

ID:648281 發(fā)表于 2020-3-13 12:30 | 顯示全部樓層
你好!
PWM 控制會用到中斷,注意避免和超聲波中斷別產(chǎn)生沖突就好
回復(fù)

使用道具 舉報

ID:687694 發(fā)表于 2020-3-13 12:59 | 顯示全部樓層
使用帶PWM輸出的單片機(jī),配置好PWM就好,只需要將占空比設(shè)定值與你程序變量關(guān)聯(lián)即可。
回復(fù)

使用道具 舉報

ID:428425 發(fā)表于 2020-3-13 17:10 | 顯示全部樓層
之一知足 發(fā)表于 2020-3-13 12:06
首先,你一下子粘出來這么多程序,就知道你沒有好好看懂這個程序,可能不是你寫的吧。拋出那些固定的函數(shù), ...

是的,這個不是我寫的,本人還有沒有達(dá)到寫出代碼的能力,然而這里也確實沒有調(diào)速的代碼,所以來求助一下,想知道具體怎么編寫
回復(fù)

使用道具 舉報

ID:428425 發(fā)表于 2020-3-13 17:11 | 顯示全部樓層
51hei**1140 發(fā)表于 2020-3-13 12:30
你好!
PWM 控制會用到中斷,注意避免和超聲波中斷別產(chǎn)生沖突就好

想知道怎么編寫,代碼不是我編寫,我還有沒能編寫代碼的能力,所以來求助下
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

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

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表