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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 3771|回復(fù): 3
打印 上一主題 下一主題
收起左側(cè)

STC15F單片機的自動控制位移小車程序設(shè)計

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
#
ID:424995 發(fā)表于 2019-6-19 21:03 | 只看該作者 |只看大圖 回帖獎勵 |正序瀏覽 |閱讀模式
概述
此系統(tǒng)采用IAP15F2K60S2單片機作為主控芯片,控制直流電機的轉(zhuǎn)動,帶動小車移動,使用超聲波傳感器來測量小車位移,實現(xiàn)小車行進指定位移的功能。顯示部分使用LCD1602液晶屏。
主要由單片機控制器、直流電機驅(qū)動電路、超聲波傳感器測距電路、顯示電路、鎖定裝置等部分組成。
核心在于如何能夠驅(qū)動電機穩(wěn)定又準確轉(zhuǎn)動,以及如何構(gòu)建適當?shù)姆答佅到y(tǒng)來確保小車位移的準確性。
反饋控制系統(tǒng)如圖2.1所示;系統(tǒng)通過按鍵模塊將目標位移值輸入反饋控制鏈中,當前位移值與目標值作差;控制系統(tǒng)對差值控制,在某一閾值之前,系統(tǒng)保持高速前進,到達閾值之后,使得小車能夠逐漸減速并且最終能夠在目標值處停下。其中使用超聲波測距作為負反饋,在密閉的空間內(nèi)能夠擁有很好地精度,也能確定小車當前的位移,是良好的反饋系統(tǒng)。

圖2.1 反饋控制系統(tǒng)框圖

圖2.2 系統(tǒng)連接框圖
以模型小車為載體,各個模塊都需要安裝在小車上。系統(tǒng)的連接如圖2.2所示,按鍵模塊對應(yīng)位移控制系統(tǒng)的輸入,CUP對應(yīng)著系統(tǒng)的程序部分,超聲波測距對應(yīng)著反饋部分。驅(qū)動部分接收來自MCU的命令,通過ENA的PWM的占空比以調(diào)節(jié)小車的行進。直流電機控制著傳動系統(tǒng),驅(qū)動小車的位移。具體的連線圖參考圖2.3.
按鍵模塊接收輸入信息和控制命令,系統(tǒng)通過測距模塊采集距離信息,經(jīng)過反饋算法之后,將通過ENA、IN1和IN2的狀態(tài)自動控制直流電機轉(zhuǎn)動等,最終使得小車的行進距離與輸入值相等。

圖2.3 電路連線圖
一、       機驅(qū)
1、  模塊簡介
該模塊主控芯片為L298N,一種雙H橋電機驅(qū)動芯片,其中每個H橋可以提供2A的電流,功率部分的供電電壓范圍是2.5-48v,邏輯部分5v供電,接受5vTTL電平。其實質(zhì)類似于一個單刀雙擲開關(guān),不過能夠提供較大的電流。
該模塊共有13個接口,此次項目將會使用到的共有8個:兩個使能接口IN1、IN2,12V供電接口,GND接口,5V電源接口,驅(qū)動接口C、D,PWM控制接口ENA。本系統(tǒng)中12V供電接口接入的是9V電池,作為整個系統(tǒng)的供電;5V接口作為電源輸出為單片機及其它外設(shè)供電;C、D接口與直流電機相連,當IN1、IN2接口接入的數(shù)值是10時,電機正轉(zhuǎn),01電機反轉(zhuǎn),00及11電機不轉(zhuǎn)。
表3.1  L298N控制
  
IN1
  
IN2
工作狀態(tài)
0
0
停止
1
0
正轉(zhuǎn)
0
1
反轉(zhuǎn)
1
1
停止
2、功能實現(xiàn)
控制小車行進速度的方法就是,通過調(diào)節(jié)控制接口ENA的PWM波占空比,來控制電機轉(zhuǎn)動與否以及時長,如此控制小車的勻速減速等工作狀態(tài)。
       這里使用定時器來實現(xiàn)PWM波的輸出:每當定時時間來臨,計數(shù)單位加一,達到一百就置零;而當計數(shù)單位小于占空比時,PWM輸出口置1,否則清零。代碼參考附錄L298N.c。

二、       超聲波測距
1、模塊簡介
選用常見的HC-SR04超聲波模塊,該模塊使用直流5.0V供電,可探測距離為2cm-450cm,精度能夠達到0.2cm,各參數(shù)基本符合此次項目的設(shè)計。該模塊共有四個接口,其中VCC、GND為電源接口,TRIG控制接口、Echo為數(shù)據(jù)接口。
使用步驟有三:
(1)    觸發(fā)測距:IO口TRIG觸發(fā),至少給10us的高電平信號;
(2)    模塊內(nèi)部自動發(fā)送8個40KHz的方波,自動檢測是否有信號返回;
(3)    有信號返回,Echo輸出一個高電平,高電平持續(xù)的時間就是超聲波從發(fā)射到接收的時間。
可以根據(jù)超聲波傳輸?shù)臅r間計算出測量的距離:
2
t即為高電平持續(xù)的時間,c為聲速340m/s。
2、功能實現(xiàn)
程序里,利用外部中斷來接受來自Echo的高電平,上升沿定時器1開始計數(shù),下降沿定時器計數(shù)結(jié)束。將計數(shù)時間乘以音速,再除以2便可得到測距的結(jié)果。
值得注意的是:此超聲波測距模塊測得的距離并不是那么準確,導(dǎo)致前后數(shù)據(jù)的差值較大。鑒于此,在獲得距離之前,先進行五次測距,取它們的平均值作為當前測得的距離。另外這部分的重要性是毋庸置疑的,在實驗過程之初,沒有進行均值濾波之前,小車在到達目標1cm左右的位置時,小車會來回的抖動。一方面是由于當時控制的頻率太高,而另一方面正是由于測得的距離有著十足的誤差。代碼請參考附錄wave.c。

三、       控制算法
為了實現(xiàn)速度的閉環(huán)控制,這里使用了業(yè)內(nèi)常常使用到了PID算法來控制PWM波的占空比,通過對偏差的比例、積分、微分進行控制,使偏差趨于零的過程。
系統(tǒng)每隔1ms進行一次采樣,之后進行一次PID算法。
PID控制一般有兩種寫法,一個是位置式,另一個是增量式。位置式需要進行累加的操作,而此系統(tǒng)的主控芯片為IAP15F2K61S2,其存儲與計算能力一般,于是這里采用增量式。
增量式程序:
//PID控制
       //move 與 deta的關(guān)系,最終使得 move = objective
       if(caiyang_FLAG_)
       {
              deta_ID[2]=deta;//采樣                                                             PWM_deta=Kp*(deta_ID[2]-deta_ID[1])+Ki*deta_ID[2]+Kd*(deta_ID[2]-2*deta_ID[1]+deta_ID[0]);
              PWM_ID[1]= PWM_ID[0]+PWM_deta;
              PWM=(uint)PWM_ID[1];
              //準備下一輪控制
              PWM_ID[0]=PWM_ID[1];
              deta_ID[0]=deta_ID[1];
              deta_ID[1]=deta_ID[2];
       }
       if(deta>0)
              Z_F= 1;
       else
              Z_F= 2;
       mada();
此外,為了解決系統(tǒng)到達位置之后的原地抖動問題,以及消除到達之后受到人為遮擋會引起小車強烈反應(yīng)的情況。又引入了消抖算法:小車位于指定位置±0.5cm的距離1秒鐘以上時,視為調(diào)節(jié)結(jié)束,小車停止運動。這里使用定時器來確定一秒的時間。
代碼如下:
START是能直接控制小車是否運動的標志,STOP是記錄小車能否保持±0.5cm的標志。
if(deta<= 0.5 && deta >= -0.5)                        
                           sanmiao = 1;
                    //一旦deta的絕對值小于0.5,電機暫停控制
                    if(sanmiao == 1)
                    {
                           if(deta > 0.5 ||deta < -0.5)
                           {//跳出暫停
                                  STOP = 0;
                                  sanmiao_flag =0;
                                  sanmiao = 0;
                           }
                           else
                           {     
                                  STOP = 1;
                           }
                    }     
定時器處理函數(shù)里面:
if(sanmiao== 1 )
      {
             if(sanmiao_flag++ == 10000)
             {
                    sanmiao_flag = 0;
                    sanmiao = 0;
                    if(STOP == 1)
                           START = 0;
             }            
      }
四、       其他功能模塊14*4按鍵模塊:
4*4矩陣功能如下:
1    2     3     A
4    5     6     B
7    8     9     C
*  0     #     D,
其中A按鍵控制讀入初始距離,B按鍵一鍵開始,C按鍵停止運動,D按鍵切換前進后退,*按鍵重新輸入,#按鍵確認輸入,各數(shù)字按鍵進行數(shù)字讀入。

2、 電源模塊
由于小車需要移動,系統(tǒng)必須使用移動電源。而普通電池電量不夠充足,而且質(zhì)量太大,影響電機的運轉(zhuǎn)。故系統(tǒng)使用一節(jié)9V可充電電池供電,利用L298N的5V電源接口給單片機及其外設(shè)供電,電機驅(qū)動模塊使用9V供電。

3、 顯示模塊
顯示部分使用LCD1602液晶顯示屏,也叫1602字符型液晶,它是一種專門用來顯示字母、數(shù)字、符號等的點陣型液晶模塊。它由若干個5X7或者5X11等點陣字符位組成。
共有16個接口,其中VSS、VDD、VO、A、K是電源接口,VSS、K接單片機的GND,VDD、A接單片機的VCC,VO接上變阻器;RS、RW、EN作為使能接口;其余8個引腳作為數(shù)據(jù)接口,以便顯示不同的ASCII或者自定義的字符。
實驗中顯示初始距離、設(shè)定位移、當前距離以及實時誤差。

單片機源程序如下:
  1. /*******
  2. 位移控制系統(tǒng)設(shè)計:小車
  3. 設(shè)計編寫:汪佳鋅
  4. 開始時間:2019/6/4
  5. 結(jié)束時間:2019/6/8
  6. 最終時間:2019/6/8
  7. 功    能:按鍵輸入指定位移,小于4米;
  8.                                         小車行進到指定距離(位置);
  9. 使用模塊:矩陣按鍵、超聲波、電機驅(qū)動、顯示模塊;
  10.                                         KBD_key.c\wave.c\L298N.c\LCD1602.c
  11. 按鍵功能:按鍵A:位置初始化;
  12.                                         數(shù)字按鍵 1,2,3,4,5,6,7,8,9,0:輸入數(shù)字,百十個CM
  13.                                         按鍵#:確認輸入;
  14.                                         按鍵*:重新輸入;
  15.                                         按鍵A:位置初始化;
  16.                                         按鍵B:一鍵開始;
  17.                                         按鍵C:手動停止;
  18.                                         按鍵D: '+'/'-';
  19.                                         1、2、3、A
  20.                                         4、5、6、B
  21.                                         7、8、9、C
  22.                                         *、0、#、D
  23. 顯示區(qū)域:1:
  24.                                         2:
  25. *******/

  26. #include <STC15F2K60S2.h>
  27. #include <intrins.h>
  28. #include "timer0.h"
  29. #include "L298N.h"
  30. #include "wave.h"
  31. #include "LCD1602.h"
  32. #include "KBD_keys.h"

  33. #define MAX 400
  34. //#ifndef uchar
  35. //typedef unsigned char uchar;
  36. //#endif
  37. //#ifndef uchar
  38. //typedef unsigned int uint;
  39. //#endif

  40. enum keyState {state0,state1,state2};

  41. bit key_FLAG_=1,mada_FLAG_=0,caiyang_FLAG_,wave_FLAG_,dsp_FLAG_,//定時器FLAG
  42.                 QJ_HT=1,//前進、后退
  43.                 sanmiao=1,//一秒消抖
  44.                 STOP=0,                //一秒消抖就停止運動
  45.                 START=0;        //開始、停止

  46. uint key_flag=0,countB=0,caiyang_flag,wave_flag,dsp_flag,
  47.                  sanmiao_flag,
  48.                  T;                                                                                //超聲波測距返回的時間

  49. uchar Z_F,                                                //馬達的狀態(tài):0代表停,1正轉(zhuǎn),2反轉(zhuǎn);
  50.                         key_value=44,                //指按下了哪個按鍵;
  51.                         add=0,                                        //按鍵的指針,三位數(shù) 150、010、007
  52.                         PWM=0;                                        //0~100表示占空比
  53. uchar aim[]={0,0,0};        //按鍵的輸入

  54. float distance_caiyang=0,
  55.                         deta=20,                                                                        //                                                                                        --------------------------                墻壁
  56.                         //deta = 當前位置-目標位置,也是程序的控制對象                           ----------------        d                         終點 目標位置distance_aim
  57.                         distance=0,                                //當前位置                                                                                                        o                        d                                          i
  58.                         distance_init=0,        //初始位置                                                                                                        b                        eta                                        s
  59.                         distance_aim=0,                //目標位置=初始位置-目標位移                                j                 ^--^                                tance                現(xiàn)在 當前位置
  60.                         objective=0;                        //目的位移CM                                                                                                 e                                |                                                                                       
  61. //                                                                                                                                                                                                                                        ctive                |
  62. //使用PID算法:P比例,I微分,D積分;                                                                                --------------------------                起點 初始位置distance_init
  63. float deta_ID[3];                        //用于微分和積分
  64. float PWM_deta,Kp,Ki,Kd,zhongjian;
  65. uchar PWM_ID[2];

  66. void display(void);
  67. void control();

  68. void main()
  69. {
  70.         uchar p=0;
  71.        
  72.         Kp = 0.06;
  73.         Ki = 0.25;
  74.         Kd = 0.01;
  75.         deta_ID[0]=deta_ID[1]=0;
  76.         PWM_ID[0]=0;
  77.        
  78.         Timer0_init();
  79.         LCD_init();       
  80.         while(1)
  81.         {
  82.                 //按鍵掃描,
  83.                 if(key_FLAG_)
  84.                 {       
  85.                         key_FLAG_ = 0;
  86.                         key_value = key_scan();
  87.                         if(key_value != 44)
  88.                         {
  89.                                 key_hand(key_value);
  90.                         }
  91.                 }
  92.                 //測距,六次取平均值
  93.                 if(wave_FLAG_)
  94.                 {
  95.                         wave_FLAG_ = 0;
  96.                         send_wave();               
  97.                         zhongjian += distance_caiyang;
  98.                         if(p++ == 5)
  99.                         {
  100.                                 distance=zhongjian/6;
  101.                                 zhongjian = 0;
  102.                                 p=0;
  103.                         }
  104.                 }
  105.                 //顯示
  106.                 if(dsp_FLAG_)
  107.                 {
  108.                         dsp_FLAG_ = 0;
  109.                         display();
  110.                 }
  111.                 //電機控制
  112.                 control();
  113. //                PWM = 50;
  114. //                Z_F = 1;
  115.                 mada();
  116.         }
  117. }
  118. void control()
  119. {
  120.         distance_aim = distance_init - objective;
  121.         deta = distance-distance_aim;
  122.         //deta = distance-distance_init+objective;
  123.         if(START == 1 && objective <= MAX && objective >= -MAX)
  124.                 {
  125.                         //控制部分
  126.                         if(deta <= 0.5 && deta >= -0.5)                               
  127.                                 sanmiao = 1;
  128.                         //一旦deta的絕對值小于0.5,電機暫停控制
  129.                         if(sanmiao == 1)
  130.                         {
  131.                                 if(deta > 0.5 || deta < -0.5)
  132.                                 {//跳出暫停
  133.                                         STOP = 0;
  134.                                         sanmiao_flag = 0;
  135.                                         sanmiao = 0;
  136.                                 }
  137.                                 else
  138.                                 {       
  139.                                         STOP = 1;
  140.                                 }
  141.                         }       
  142.                         else//
  143.                         {
  144.                                 //分段控制
  145.                                 if(deta >= 100)
  146.                                 {                PWM = 70;Z_F = 1;}
  147.                                 else if(deta >= 50)
  148.                                 {                PWM = 50;Z_F = 1;}
  149.                                 else if(deta >= 10)
  150.                                 {                PWM = 30;Z_F = 1;}
  151.                                 else if(deta > 5)
  152.                                 {                PWM = 10;Z_F = 1;}
  153.                                 else if(deta > 0.5)
  154.                                 {                PWM = 5;Z_F = 1;}
  155.                                 else if(deta >= -0.5 && deta <= 0.5)
  156.                                 {                //START = 0;
  157.                                 PWM = 0;Z_F = 0;}
  158.                                 else if(deta >= -5)
  159.                                 {                PWM = 5 ;Z_F = 2;}
  160.                                 else if(deta >= -10 && deta < -5)
  161.                                 {                PWM = 10;Z_F = 2;}
  162.                                 else if(deta >= -50)
  163.                                 {                PWM = 30;Z_F = 2;}
  164.                                 else if(deta >= -100)
  165.                                 {                PWM = 50;Z_F = 2;}
  166.                                 else
  167.                                 {                PWM = 70;Z_F = 2;}       
  168.                                 //PID控制
  169.                                 //move 與 deta的關(guān)系,最終使得 move = objective
  170. //                                if(caiyang_FLAG_)
  171. //                                {
  172. //                                        deta_ID[2]=deta;//采樣
  173. //                                       
  174. //                                        PWM_deta=Kp*(deta_ID[2]-deta_ID[1])+Ki*deta_ID[2]+Kd*(deta_ID[2]-2*deta_ID[1]+deta_ID[0]);
  175. //                                       
  176. //                                        PWM_ID[1] = PWM_ID[0]+PWM_deta;
  177. //                                        PWM=(uint)PWM_ID[1];
  178. //                                        //準備下一輪控制
  179. //                                        PWM_ID[0]=PWM_ID[1];
  180. //                                        deta_ID[0]=deta_ID[1];
  181. //                                        deta_ID[1]=deta_ID[2];
  182. //                                }
  183. //                                if(deta>0)
  184. //                                        Z_F = 1;
  185. //                                else
  186. //                                        Z_F = 2;
  187.                                
  188.                         }
  189.                 }
  190.         else
  191.         {               
  192.                 Z_F = 0;
  193.                 ENB = 0;
  194.                 ENA = 0;               
  195.         }
  196.         //一秒無變化,停止運動
  197.                
  198. }

  199. void key_hand(uchar key_value)
  200. {
  201.         switch(key_value)
  202.         {
  203.                 case 1:
  204.                 case 2:
  205.                 case 3:aim[add]=key_value;add++;break;
  206.                 case 4:distance_init = distance;break;       
  207.                
  208.                 case 5:
  209.                 case 6:
  210.                 case 7:aim[add]=key_value-1;add++;break;
  211.                 case 8:START = 1;               
  212.                                          sanmiao = 0;                                        //開始、停止
  213.                                          objective = aim[0]*100+aim[1]*10+aim[2];        //確認輸入
  214.                                          if(QJ_HT == 0)//后退
  215.                                          {       
  216.                                          objective = -objective;}
  217.                                          distance_init = distance;                                                                //位置初始化
  218.                                          break;//
  219.                
  220.                 case 9:
  221.                 case 10:
  222.                 case 11:aim[add]=key_value-2;add++;break;
  223.                 case 12:START = 0;
  224.                                                 break;
  225.                
  226.                 case 13:aim[0]=aim[1]=aim[2]=0;add=0;QJ_HT = 1;break;//重新輸入
  227.                 case 14:aim[add]=0;add++;break;
  228.                 case 15:objective = aim[0]*100+aim[1]*10+aim[2];//確認輸入
  229.                                                 if(QJ_HT == 0)//后退
  230.                                                 {        objective = -objective;}
  231.                                                 break;                                               
  232.                 case 16:QJ_HT = ~QJ_HT;break;                                        //輸入前進或后退
  233.                 default:break;
  234.         }
  235.         if(add == 3)
  236.                 add = 0;
  237. }
  238. void display()
  239. {
  240.         LCD_write_com(0x80);
  241.         if(START == 1)
  242.                 LCD_write_data('T');
  243.         else
  244.                 LCD_write_data('P');
  245.         LCD_write_data(':');
  246.         display_32(distance_init);
  247.         LCD_write_data(' ');
  248.         if(QJ_HT == 1)
  249.                 LCD_write_data('+');
  250.         else
  251.                 LCD_write_data('-');
  252.         LCD_write_data('0'+aim[0]);
  253.         LCD_write_data('0'+aim[1]);
  254.         LCD_write_data('0'+aim[2]);
  255.         LCD_write_data('C');
  256.         LCD_write_data('M');
  257.         Delayms(1);
  258.        
  259.         LCD_write_com(0x80+0x40);
  260.         if(objective >MAX || objective < -MAX)
  261.         {
  262.                 LCD_write_string(2,1,"INPUT ERROR!    ");
  263.         }
  264.         else
  265.         {
  266.                 display_32(distance);
  267.                 LCD_write_data(' ');
  268.                 display_32(deta);
  269.         }
  270.         Delayms(1);
  271. }

  272. void Timer0_handle(void) interrupt 1
  273. {
  274.         if(sanmiao == 1 )
  275.         {
  276.                 if(sanmiao_flag++ == 10000)
  277.                 {
  278.                         sanmiao_flag = 0;
  279.                         sanmiao = 0;
  280.                         if(STOP == 1)
  281.                                 START = 0;
  282.                         else
  283.                                 START = 1;
  284.                 }               
  285.         }
  286.         if(dsp_flag++ == 30)                                //LCD顯示3ms
  287.         {
  288.                 dsp_FLAG_=1;
  289.                 dsp_flag =0;
  290. ……………………

  291. …………限于本文篇幅 余下代碼請從51黑下載附件…………
復(fù)制代碼

所有資料51hei提供下載:
工程程序.rar (65.19 KB, 下載次數(shù): 26)



評分

參與人數(shù) 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏 分享淘帖 頂 踩
回復(fù)

使用道具 舉報

板凳
ID:637409 發(fā)表于 2020-6-10 17:02 | 只看該作者
老哥怎么圖片顯示不了啊
回復(fù)

使用道具 舉報

沙發(fā)
ID:702992 發(fā)表于 2020-3-6 10:44 | 只看該作者

RE: STC15F單片機的自動控制位移小車程序設(shè)計

大神你好,我做的是紅外線測距,然后控制小車位移,該怎么做
回復(fù)

使用道具 舉報

樓主
ID:444661 發(fā)表于 2019-10-15 21:07 | 只看該作者
謝謝,,,,,需要的
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

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

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

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