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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

單片機循跡小車完整資料 包括注釋詳細的程序和硬件設計

  [復制鏈接]
跳轉到指定樓層
樓主
資料大家看吧!截圖截得不全。


單片機源程序如下:
  1. /***************************************************/
  2. /*                                        尋跡小車 FollowMe 項目                                                                 */
  3. /*          —— 主控程序軌跡控制模塊                                                                 */
  4. /*              之程序部分                                                                                            */
  5. /*                                            20060905                           */
  6. /*              By DingQi                          */
  7. /***************************************************/
  8. // 注:以下文檔的 TAB 為 2 個字符!

  9. /*------------------------------------------------------------------------
  10. 此程序為"尋跡小車FollowMe"項目中單板控制模式的走軌跡控制部分,附帶相關調試功能。
  11. 要實現:

  12.         1)接收各種調試命令,并解析;
  13.         2)通過串口反饋所需的調試信息;
  14.         3)獲取軌跡采樣部分處理后的信息,產生對策,發給電機驅動部分實施。
  15.        
  16.         根據上述要實現的功能,通訊部分歸此模塊管理。
  17.        
  18.         第一步先將原來的電機驅動功能整合到一個MCU中,將原來的通訊功能從電機驅動模塊中分解出來。

  19.        
  20. 目前的電機控制由串口實現,通訊協議定義如下:
  21. 1、幀格式:
  22.         幀頭(2字節)  幀長(1字節) 命令字(1字節) 數據區(N字節)校驗和(1字節)

  23. 其中:
  24.         幀頭 —— 0x55  0xAA       
  25.         幀長 ——  命令字 + 數據區的長度
  26.         命令字 ——         0x01 :電機轉動控制參數,開環模式,電機的PWM值、轉動持續脈沖數;
  27.                                                    0x02 :電機轉動控制參數,閉環模式,電機的轉速、轉動持續脈沖數;
  28.                                                          0x03 :電機工作參數,PWM頻率、PID參數
  29.         數據區 —— 命令01:電機1數據(2字節PWM值,2字節轉動持續脈沖數)電機2數據(2字節PWM值,2字節轉動持續脈沖數),共 8字節;
  30.                                                 命令02:電機1數據(2字節轉速值,2字節轉動持續脈沖數)電機2數據(2字節轉速值,2字節轉動持續脈沖數),共 8字節;
  31.                                                 命令03:2字節PWM頻率,2字節比例系數,2字節積分系數,2字節微分系數,2字節PID系數的分母, 共10字節,兩個電機驅動器相同;
  32.         校驗和 —— 從命令字開始到數據區結束所有字節的算術和的反碼,取低字節。

  33. 上述數據中,PWM值,速度值、PWM頻率、PID系數等定義如下:
  34.         PWM值 ——         2字節有符號數,正對應正轉,負對應反轉,數值為占空比的百分數,
  35.                                                 取值范圍:- 1000 ——  +1000, 對應 0.1% ~ 100%;1001為電機“惰行”,1002為“剎車”;
  36.        
  37.         轉動持續脈沖數 ——  2字節無符號數,0 表示連續轉動;
  38.        
  39.         轉速值 —— 2字節有符號數,正對應正轉,負對應反轉,單位為:0.1轉/每分鐘;
  40.                                                 取值范圍:- 10000~ +10000,10001為電機“惰行”,10002為“剎車”;
  41.        
  42.         PWM頻率 —— 2字節整數,單位Hz,取值范圍:200 – 2000;
  43.        
  44.         PID系數 —— 均為 2字節無符號數;
  45.         PID系數分母 ——  2字節無符號數,為避免使用浮點數而增加了此參數,實際作用的PID系數為上述值除此值;
  46.                                                                         如:比例系數為190 ,PID分母為200,實際比例系數為0.95。

  47. 以上所有2字節的數據均為先低后高。
  48. 暫時不設計應答幀,因為一幀命令包含了兩個電機的驅動數據。

  49. 通訊數據格式為:19200  8  N  1。
  50. 此時,一幀數據約占 7ms。

  51. 為了調試,添加轉速讀取命令 0x04 ,原來的讀轉速命令是分開實現的:
  52.         0x55  0xAA  0x02(幀長) 0x04 (讀轉速命令)  電機序號(1字節)校驗和(1字節)
  53.        
  54.         對應的返回幀為:
  55.         0xAA 0x55  0x04(幀長) 0x84 (轉速值返回) 電機序號(1字節)轉速(2字節)校驗和(1字節)
  56.        

  57. 因為合并到一個MCU中了,所以對應將協議改為:
  58.         0x55  0xAA  0x01(幀長) 0x04 (讀轉速命令) 校驗和(1字節)
  59.        
  60.         對應的返回幀為:
  61.         0xAA 0x55  0x05(幀長) 0x84 (轉速值返回) 電機1轉速(2字節)電機2轉速(2字節)校驗和(1字節)


  62. 因為集成了走軌跡控制功能,所以要添加一個控制命令,使小車啟動,進入到走軌跡狀態或結束走軌跡的狀態。
  63.         走軌跡控制命令: 0x05 .   命令參數 ——  1 啟動走軌跡, 2 ——  啟動走直線 ,0 停止,
  64.         命令幀為:
  65.         0x55 0xAA 0x02 0x05 0x01 CS        ——  啟動走軌跡命令
  66.         0x55 0xAA 0x02 0x05 0x02 CS        ——  啟動直線走命令
  67.         0x55 0xAA 0x02 0x05 0x00 CS        ——  停止命令

  68. 為了調試方便,增加一個內存數據讀取命令:
  69.         內存數據讀取命令:0x06
  70.         命令幀為:
  71.         0x55 0xAA 0x04 0x06 讀數據低地址 讀數據高地址 讀數據長度 CS
  72.         返回幀為:
  73.         0x55 0xAA 幀長 0x86 讀數據低地址 讀數據高地址 讀數據長度 數據N字節 CS

  74. ------------------------------------------------------------------------
  75.         因為用雙輪驅動的小車由于電機等驅動元素的差異,導致走直線成為問題,故在此嘗試
  76. 用這兩個簡易的碼盤來實現直線行走。               

  77.         因為碼盤的分辨率太低,所以直接用脈沖計數方式控制似乎有些不夠精確,所以考慮用
  78. 兩路脈沖的觸發時間差別來控制。
  79.         實質上這是一種周期測量的變換,因為不能保證每個脈沖周期是真實的(即由于干擾會
  80. 導致某個周期變大或變。杂美塾嫷姆绞较。

  81.         具體的方式如下:
  82.         設立兩個 4 字節的計數器,2字節紀錄PCA的溢出值,2字節紀錄 PCA 的計時器值,這樣
  83. 構成了一個對PCA計數脈沖(Fosc/2)的長整形計數器,可紀錄約 388秒(2^32/11.0592M),
  84. 這個值一般可以應付大部分比賽項目中的需要。

  85.         將這個時間計數器作為兩個輪子采樣脈沖(只取下降沿)的時標,根據兩者的差值確定兩輪
  86. 的驅動差。也就是要保證兩個輪子對應脈沖到達的時間相同,這樣,如果沒有漏計或打滑,兩
  87. 個輪子行走的距離應當是一樣的,軌跡也應當是直線!

  88.         這個控制也可以考慮使用PID控制,其控制的量為兩個計數器的差值,定值為“0”。
  89.        
  90. ------------------------------------------------------------------------*/

  91. #pragma PR
  92. #pragma OT(5,size)

  93. #pragma Listinclude
  94. #pragma code

  95. #include <E:\dingqi\keilc51\inc\math.h>

  96. #include <STC12C5410AD.h>                                /* STC12C5410AD 的頭文件*/

  97. #include <Port_Def.H>

  98. #include <ComConst.H>

  99. #include <LC_Const.H>

  100. #include <LC_Var.H>

  101. void init_SIO(unsigned char baud);                                                // 初始化串口
  102. void rcvdata_proc(void);                                                                                        // 接收數據幀
  103. void getCommandData(void);                                                                                // 從數據幀中取出命令數據
  104. unsigned int calStopCntValue(unsigned int uiRun_Num,unsigned char No); // 根據命令中的行走脈沖數計算出停止點
  105. char setMotorStat(int iRunValue);                                                        // 根據命令中的PWM值或轉速設置電機狀態
  106. void followLineControl(void);                                                                        // 走軌跡控制
  107. void straightRun(void);                                                                                                // 走直線控制

  108. /******************************** 外部調用函數 *********************************/

  109. // 以下函數為公共函數,需要在調用的模塊中聲明。

  110. /********************************************/
  111. /* 名稱:init_LineCtrl_Hardware                                                        */
  112. /* 用途:初始化串口等, 以保證相應硬件工作                */
  113. /********************************************/

  114. void init_LineCtrl_Hardware(void)
  115. {
  116.         //初始化串口
  117.         init_SIO(B_19200);
  118.        
  119.         // 初始化相關中斷
  120.         IE = IE|EnUART_C;                                                                                // 允許 UART 中斷
  121. }

  122. /********************************************/
  123. /* 名稱:init_LineCtrl_Var                                                                        */
  124. /* 用途:初始化自身工作變量                                                                        */
  125. /********************************************/

  126. void init_LineCtrl_Var(void)
  127. {
  128.         unsigned char j;
  129.        
  130.         // 接收數據變量初始化
  131.         gi_ucSavePtr=0;
  132.         gi_ucGetPtr=0;
  133.        
  134.         gb_NewData = FALSE;
  135.         gb_StartRcv = FALSE;
  136.         gb_DataOK = FALSE;
  137.        
  138.         // 命令數據存放單元初始化
  139.         for(j=0;j<2;j++)
  140.         {
  141.                 ga_iPWM_Value[j] = FLOAT_PWM;
  142.                 ga_iRotateSpeed[j] = FLOAT_SPEED;
  143.                
  144.                 ga_uiRotateNum[j] = 0;
  145.         }
  146.        
  147.         g_uiPWM_Freq = INIT_PWM_FREQ;                                                        // 初始化時,將PWM的頻率置為 200Hz
  148.        
  149.         gb_M1CalOutValue = TRUE;                                                                        // 上電計算一次輸出,以保證電機的正常工作狀態
  150.         gb_M2CalOutValue = TRUE;                                                                        // 上電計算一次輸出,以保證電機的正常工作狀態
  151.                        
  152.         // PID 控制初始化
  153.         g_uiKp = DEFAULT_KP;                                                                                        // 加載默認系數
  154.         g_uiTi = DEFAULT_TI;
  155.         g_uiTd = DEFAULT_TD;
  156.         g_uiPID_Ratio = DEFAULT_PID_RATIO;
  157.        
  158.         g_fKp = ((float)g_uiKp)/g_uiPID_Ratio;                        // 在此處計算好,減少每次 PID 的運算量
  159.         g_fTi = ((float)g_uiTi)/g_uiPID_Ratio;
  160.         g_fTd = ((float)g_uiTd)/g_uiPID_Ratio;

  161.         gb_EnablePID = FALSE;                                                                                        // 禁止調速 PID 功能
  162.        
  163.         gb_StartLineFollow = FALSE;
  164.         gb_StartStraightRun = FALSE;
  165.         g_ucDownSampCnt = 0;                                                                                        // 初始化時將脈沖采樣計數清為“0”       

  166. }

  167. /********************************************/
  168. /* 名稱:lineCtrl_proc                                                                                        */
  169. /* 用途:軌跡控制部分處理入口函數,根據帶入        */
  170. /*       的消息作相應處理。                                                                        */
  171. /*入口參數:要處理的消息                                                                                */
  172. /********************************************/

  173. void lineCtrl_proc(unsigned char ucMessage)
  174. {
  175.         switch(ucMessage)
  176.         {
  177.                 case NEW_RCV_DATA:
  178.                 {
  179.                         rcvdata_proc();                                                                                        // 處理接收緩沖區數據                        

  180.                         if(gb_DataOK)
  181.                         {
  182.                                 gb_DataOK = FALSE;
  183.                                 getCommandData();                                                                        // 從數據幀中提取命令數據
  184.                         }                               
  185.                         break;
  186.                 }
  187.                
  188.                 case NEW_SAMP_DATA:
  189.                 {
  190.                         followLineControl();
  191.                         break;
  192.                 }
  193.                
  194.                 case         SAMPLE_DOWN_PULS:
  195.                 {
  196.                         straightRun();
  197.                         break;
  198.                 }
  199.                
  200.                 default:         break;
  201.                
  202.         }
  203. }



  204. /***************************** 模塊自用函數 *******************************/

  205. // 以下函數只由模塊自身使用,別的模塊不用聲明。

  206. /********************************************/
  207. /* 名稱:init_SIO                                                                                                                */
  208. /* 用途:初始化串口,                                                                                                 */
  209. /* 參數: 波特率 , 模式固定為:1                                                         */
  210. /*                 1 START 8 DATA 1 STOP                                                                 */
  211. /********************************************/

  212. void init_SIO(unsigned char baud)
  213. {
  214.         // 波特率表
  215.         unsigned char        code        TH_Baud[5]={B4800_C,B9600_C,B19200_C,B38400_C,B57600_C};
  216.        
  217.         AUXR = AUXR|SET_T1X12_C;
  218.         TH1 = TH_Baud[baud];
  219.         TL1 = TH_Baud[baud];
  220.         TR1 = TRUE;
  221.        
  222.         SCON        =        UART_MODE1_C|EN_RCV_C;        // 8 位模式( MODE 1)
  223. }

  224. /********************************************/
  225. /*名稱:        rcvdata_proc                                                                                                */
  226. /*用途: 檢測接收緩沖區數據,                                                     */
  227. /*說明:        如果收到正確的數據幀則建立標志                        */
  228. /********************************************/

  229. void rcvdata_proc(void)
  230. {
  231.         unsigned char i,j,k;
  232.        
  233.        
  234.         if(gb_StartRcv == FALSE)
  235.         {
  236.                 /*  檢測幀頭 0x55 0xAA LEN */
  237.                
  238.                 i=(gi_ucGetPtr-2)&(MaxRcvByte_C-1);                // 指向0x55
  239.                 j=(gi_ucGetPtr-1)&(MaxRcvByte_C-1);                // 指向0xAA
  240.                
  241.                 if((ga_ucRcvBuf[i]==0x55)&&(ga_ucRcvBuf[j]==0xAA))
  242.                 {
  243.                         i=gi_ucGetPtr;
  244.                                                
  245.                         if(ga_ucRcvBuf[i]<= (MaxRcvByte_C-1));
  246.                         {
  247.                                 //幀頭正確,啟動數據區接收
  248.                                 gb_StartRcv=TRUE;       
  249.                                 gc_ucDataLen=ga_ucRcvBuf[i];
  250.                                 gi_ucStartPtr=(gi_ucGetPtr+1)&(MaxRcvByte_C-1);
  251.                                 gi_ucEndPtr= (gi_ucGetPtr + gc_ucDataLen+1)&(MaxRcvByte_C-1);
  252.                         }
  253.                 }
  254.                 gi_ucGetPtr=(gi_ucGetPtr+1)&(MaxRcvByte_C-1);
  255.         }
  256.         else
  257.         {
  258.                 //開始接收數據處理
  259.                 if(gi_ucGetPtr==gi_ucEndPtr)
  260.                 {
  261.                         /* 數據幀接收完 */
  262.                         gb_StartRcv=FALSE;
  263.                        
  264.                         j=gi_ucStartPtr;       
  265.                         k= 0;
  266.                         for(i=0;i<gc_ucDataLen;i++)
  267.                         {
  268.                                 // 計算CS
  269.                                 k +=ga_ucRcvBuf[j];               
  270.                                 j=(j+1)&(MaxRcvByte_C-1);
  271.                         }
  272.                        
  273.                         // 取校驗和
  274.                         k +=ga_ucRcvBuf[j];                       
  275.                         if( k == 0xFF)
  276.                         {
  277.                                 // 數據校驗正確
  278.                                 gb_DataOK=TRUE;
  279.                         }
  280.                 }
  281.                 gi_ucGetPtr=(gi_ucGetPtr+1)&(MaxRcvByte_C-1);
  282.         }                       
  283. }

  284. /********************************************/
  285. /*名稱:        getCommandData                                                                                        */
  286. /*用途: 從接收緩沖區中取出數據,                                                 */
  287. /*說明:        建立對應標志,通知相應的處理                          */
  288. /********************************************/

  289. void getCommandData(void)
  290. {
  291.         union
  292.         {
  293.                 unsigned int all;
  294.                 unsigned char b[2];
  295.         }uitemp;
  296.        
  297.         union
  298.         {
  299.                 int        all;
  300.                 unsigned char b[2];
  301.         }itemp;
  302.        
  303.         unsigned char ucCommand,i,j,sum,n;
  304.         unsigned char idata *ucI_Ptr;
  305.         unsigned char xdata *ucX_Ptr;
  306.        
  307.         ucCommand = ga_ucRcvBuf[gi_ucStartPtr];                                // 取出數據幀中的命令字
  308.        
  309.         switch (ucCommand)
  310.         {
  311.                 case PWM_MODE:
  312.                 {
  313.                         // 處理PWM開環控制命令
  314.                         i = (gi_ucStartPtr + 1)&(MaxRcvByte_C - 1);                        // 指向電機 1 數據區
  315.                        
  316.                         for(j=0;j<2;j++)                                                                                                                                // 循環 2 次完成兩個電機的數據提取
  317.                         {
  318.                                 itemp.b[1] = ga_ucRcvBuf[i];                                                                                // 注意,在C51中,整形等多字節數據在內存中是先高后低存放!
  319.                                 i =(i+1)&(MaxRcvByte_C-1);
  320.                                 itemp.b[0] = ga_ucRcvBuf[i];                               
  321.                                
  322.                                 if(itemp.all < (-1000))                                                                                                // PWM值合法性處理
  323.                                 {
  324.                                         itemp.all = -1000;
  325.                                 }
  326.                                 if(itemp.all > 1002)
  327.                                 {
  328.                                         itemp.all = 1000;
  329.                                 }                               
  330.                                 ga_iPWM_Value[j] = itemp.all;                                                                        // 得到 PWM 值

  331.                                 // 行走脈沖計數數據處理
  332.                                 i =(i+1)&(MaxRcvByte_C-1);
  333.                                 uitemp.b[1] = ga_ucRcvBuf[i];
  334.                                 i =(i+1)&(MaxRcvByte_C-1);
  335.                                 uitemp.b[0] = ga_ucRcvBuf[i];
  336.                                 ga_uiRotateNum[j] = uitemp.all;                                                                                                        // 得到轉動脈沖計數值
  337.                                
  338.                                 ga_uiStopCnt[j] = calStopCntValue(ga_uiRotateNum[j],j);        // 計算出停止計數值
  339.                                
  340.                                 ga_cMotorStat[j] = setMotorStat(ga_iPWM_Value[j]);                // 根據命令設置電機運轉標志
  341.                                
  342.                                 i = (gi_ucStartPtr + 1+4)&(MaxRcvByte_C - 1);                                        // 指向電機 2 數據區
  343.                         }
  344.                        
  345.                         gb_EnablePID = FALSE;                                                                                                                                                // 收到PWM控制命令后,禁止 PID 控制
  346.                                                        
  347.                         gb_M1CalOutValue =TRUE;                                                                                                                                        // 建立計算電機控制輸出值標志,因為PWM數據變化
  348.                         gb_M2CalOutValue =TRUE;       
  349.                        
  350.                         break;
  351.                 }
  352.                
  353.                 case SPEED_MODE:
  354.                 {
  355.                         // 處理轉速閉環控制命令
  356.                         i = (gi_ucStartPtr + 1 )&(MaxRcvByte_C-1);                                                        // 指向電機 1 數據區
  357.                        
  358.                         for(j=0;j<2;j++)                                                                                                                                                                // 循環 2 次完成兩個電機的數據提取
  359.                         {
  360.                                 itemp.b[1] = ga_ucRcvBuf[i];                                                                // 注意,在C51中,整形等多字節數據在內存中是先高后低存放!
  361.                                 i =(i+1)&(MaxRcvByte_C-1);
  362.                                 itemp.b[0] = ga_ucRcvBuf[i];                               

  363.                                 if(itemp.all < (-10000))                                                                                // 轉速數據合法性處理
  364.                                 {
  365.                                         itemp.all = -10000;
  366.                                 }
  367.                                 if(itemp.all > 10002)
  368.                                 {
  369.                                         itemp.all = 10000;
  370.                                 }
  371.                                 ga_iRotateSpeed[j] = itemp.all;                                                                // 得到轉速

  372.                                 // 行走脈沖數據處理       
  373.                                 i =(i+1)&(MaxRcvByte_C-1);
  374.                                 uitemp.b[1] = ga_ucRcvBuf[i];
  375.                                 i =(i+1)&(MaxRcvByte_C-1);
  376.                                 uitemp.b[0] = ga_ucRcvBuf[i];
  377.                                 ga_uiRotateNum[j] = uitemp.all;                                                                                                                // 得到轉動脈沖計數值
  378.                                
  379.                                 ga_uiStopCnt[j] = calStopCntValue(ga_uiRotateNum[j],j);        // 計算出停止計數值
  380.        
  381.                                 ga_cMotorStat[j] = setMotorStat(ga_iRotateSpeed[j]);                // 根據命令設置電機運轉標志
  382.                        
  383.                                 i = (gi_ucStartPtr + 1 + 4)&(MaxRcvByte_C-1);                                                // 指向電機 2 數據區
  384.                         }
  385.                        
  386.                         if(gb_EnablePID)
  387.                         {
  388.                                 // 已啟動PID控制       
  389.                         }
  390.                         else
  391.                         {
  392.                                 // 啟動 PID 控制
  393.                                 gb_EnablePID = TRUE;
  394.                                 gac_ucGetSpeedCnt[MOTOR1] = 3;                                                                // 電機 1 采集3次速度數據后才允許計算PID
  395.                                 gac_ucGetSpeedCnt[MOTOR2] = 3;                                                                // 電機 2 采集3次速度數據后才允許計算PID
  396.                                 ga_iPWM_Value[MOTOR1] = INI_PWM_VALUE;                                // 電機 1 輸出PWM初值,啟動電機
  397.                                 ga_iPWM_Value[MOTOR2] = INI_PWM_VALUE;                                // 電機 2 輸出PWM初值,啟動電機
  398.                                 gb_M1CalOutValue = TRUE;                                                                                        // 通知輸出計算
  399.                                 gb_M2CalOutValue = TRUE;
  400.                         }
  401.                                                
  402.                         break;
  403.                 }
  404.                
  405.                 case SET_PARA:
  406.                 {
  407.                         // 處理參數設置命令
  408.                         i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);               
  409.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 注意,在C51中,整形等多字節數據在內存中是先高后低存放!
  410.                         i =(i+1)&(MaxRcvByte_C-1);
  411.                         uitemp.b[0] = ga_ucRcvBuf[i];
  412.                         g_uiPWM_Freq = uitemp.all;
  413.                         if(g_uiPWM_Freq <200)                                                // 數據合法性處理
  414.                         {
  415.                                 g_uiPWM_Freq = 200;
  416.                         }
  417.                         if(g_uiPWM_Freq >2000)
  418.                         {
  419.                                 g_uiPWM_Freq = 2000;
  420.                         }
  421.                         gb_M1CalOutValue =TRUE;                                        // 建立計算電機控制輸出值標志,因為PWM的頻率變了。
  422.                         gb_M2CalOutValue =TRUE;
  423.                        
  424.                         // 取 PID 參數
  425.                         i =(i+1)&(MaxRcvByte_C-1);
  426.                         uitemp.b[1] = ga_ucRcvBuf[i];
  427.                         i =(i+1)&(MaxRcvByte_C-1);
  428.                         uitemp.b[0] = ga_ucRcvBuf[i];
  429.                         g_uiKp = uitemp.all;
  430.                        
  431.                         i =(i+1)&(MaxRcvByte_C-1);
  432.                         uitemp.b[1] = ga_ucRcvBuf[i];
  433.                         i =(i+1)&(MaxRcvByte_C-1);
  434.                         uitemp.b[0] = ga_ucRcvBuf[i];
  435.                         g_uiTi = uitemp.all;

  436.                         i =(i+1)&(MaxRcvByte_C-1);
  437.                         uitemp.b[1] = ga_ucRcvBuf[i];
  438.                         i =(i+1)&(MaxRcvByte_C-1);
  439.                         uitemp.b[0] = ga_ucRcvBuf[i];                       
  440.                         g_uiTd = uitemp.all;
  441.                        
  442.                         i =(i+1)&(MaxRcvByte_C-1);
  443.                         uitemp.b[1] = ga_ucRcvBuf[i];
  444.                         i =(i+1)&(MaxRcvByte_C-1);
  445.                         uitemp.b[0] = ga_ucRcvBuf[i];
  446.                         if(uitemp.all >0)
  447.                         {
  448.                                 g_uiPID_Ratio = uitemp.all;
  449.                         }
  450.                        
  451.                         g_fKp = ((float)g_uiKp)/g_uiPID_Ratio;                        // 在此處計算好,減少每次 PID 的運算量
  452.                         g_fTi = ((float)g_uiTi)/g_uiPID_Ratio;
  453.                         g_fTd = ((float)g_uiTd)/g_uiPID_Ratio;
  454.                                                
  455.                         break;
  456.                 }
  457.                
  458.                 case READ_SPEED:
  459.                 {
  460.                         // 讀取轉速命令處理
  461.                         ga_ucTxdBuf[0] = 0xAA;
  462.                         ga_ucTxdBuf[1] = 0x55;                                                // 幀頭
  463.                         ga_ucTxdBuf[2] = 0x05;                                                // 幀長
  464.                         ga_ucTxdBuf[3] = 0x80+READ_SPEED;        // 返回命令
  465.                         sum = ga_ucTxdBuf[3];
  466.                         i=4;
  467.                         for(j=0;j<2;j++)                                                                        // 循環 2 次,返回 2 個電機的轉速
  468.                         {                                                               
  469.                                 itemp.all = ga_iCurSpeed[j];
  470.                                 ga_ucTxdBuf[i] = itemp.b[1];                // 返回轉速值,先低后高
  471.                                 sum += ga_ucTxdBuf[i];
  472.                                 i++;
  473.                                 ga_ucTxdBuf[i] = itemp.b[0];
  474.                                 sum += ga_ucTxdBuf[i];
  475.                                 i++;
  476.                         }
  477.                        
  478.                         ga_ucTxdBuf[i] = ~sum;                                                // 校驗和
  479.                                
  480.                         gc_ucTxdCnt = 9;                                                                        // 發送字節計數
  481.                         gi_ucTxdPtr = 0;                                                                        // 發送指針
  482.                         SBUF = ga_ucTxdBuf[0];                                                // 啟動發送
  483.                        
  484.                         break;
  485.                 }
  486.                
  487.                 case FOLLOW_LINE_CTRL:
  488.                 {
  489.                         i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);
  490.                         switch (ga_ucRcvBuf[i])
  491.                         {
  492.                                 case FOLLOW_LINE:
  493.                                 {
  494.                                         break;
  495.                                 }
  496.                                
  497.                                 case STRAIGHT_RUN:
  498.                                 {
  499.                                         gb_StartStraightRun =  TRUE;
  500.                                        
  501.                                         gc_uiPCA_OverCnt = 0;
  502.                                         g_ucDownSampCnt = 0;
  503.                                                                                
  504.                                         //gb_EnSpeed_Hi_Low = TRUE;                                // 啟動速度上下限控制
  505.                                        
  506.                                         g_iInit_PWM = INI_PWM_VALUE;                 // 啟動電機
  507.                                         ga_iPWM_Value[MOTOR1] = g_iInit_PWM;
  508.                                         ga_cMotorStat[MOTOR1] = setMotorStat(ga_iPWM_Value[MOTOR1]);                // 設置電機運轉標志
  509.                                         ga_iPWM_Value[MOTOR2] = g_iInit_PWM;
  510.                                         ga_cMotorStat[MOTOR2] = setMotorStat(ga_iPWM_Value[MOTOR2]);                // 設置電機運轉標志
  511.                                        
  512.                                         m_iDiffPWM = 0;                                       

  513.                                         gb_M1CalOutValue =TRUE;                                        // 建立計算電機控制輸出值標志,
  514.                                         gb_M2CalOutValue =TRUE;       
  515.                                                                                
  516.                                         m_iError_Int = 0;                                                                // 初始化PID計算數據
  517.                                         m_iErrorOld = 0;
  518.                                        
  519.                                         break;
  520.                                 }
  521.                                
  522.                                 case STOP_RUN:
  523.                                 {
  524.                                         ga_iPWM_Value[MOTOR1] = BRAKE_PWM;
  525.                                         ga_cMotorStat[MOTOR1] = setMotorStat(ga_iPWM_Value[MOTOR1]);                // 設置電機運轉標志
  526.                                         ga_iPWM_Value[MOTOR2] = BRAKE_PWM;
  527.                                         ga_cMotorStat[MOTOR2] = setMotorStat(ga_iPWM_Value[MOTOR2]);                // 設置電機運轉標志

  528.                                         gb_EnSpeed_Hi_Low = FALSE;
  529.                                         gb_StartStraightRun = FALSE;
  530.                                         gb_StartLineFollow = FALSE;

  531.                                         gb_M1CalOutValue =TRUE;                                        // 建立計算電機控制輸出值標志,
  532.                                         gb_M2CalOutValue =TRUE;       
  533.                                         break;
  534.                                 }
  535.                                
  536.                                 default: break;
  537.                         }
  538.                        
  539.                         break;
  540.                 }
  541.                
  542.                 case READ_MEMORY:
  543.                 {
  544.                         // 讀內存數據處理
  545.                         i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);               
  546.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 取讀數據地址
  547.                         i =(i+1)&(MaxRcvByte_C-1);
  548.                         uitemp.b[0] = ga_ucRcvBuf[i];
  549.                         i =(i+1)&(MaxRcvByte_C-1);
  550.                         n = ga_ucRcvBuf[i];                                                                                                        // 取讀數據長度
  551.                         if(n>(MaxTxdByte_C - 4))
  552.                         {
  553.                                 n = (MaxTxdByte_C - 4);                                                                                // 受發送緩沖區限制,減 4 個字節對應: 命令 地址 長度
  554.                         }
  555.                        
  556.                         ga_ucTxdBuf[0] = 0xAA;
  557.                         ga_ucTxdBuf[1] = 0x55;                                                                                        // 幀頭
  558.                         ga_ucTxdBuf[2] = n + 4;                                                                                        // 幀長
  559.                         ga_ucTxdBuf[3] = 0x80+READ_MEMORY;                                        // 返回命令
  560.                         ga_ucTxdBuf[4] = uitemp.b[1];                                                                // 將要讀數據的地址和長度返回
  561.                         ga_ucTxdBuf[5] = uitemp.b[0];
  562.                         ga_ucTxdBuf[6] = n;
  563.                         sum = ga_ucTxdBuf[3]+ga_ucTxdBuf[4]+ga_ucTxdBuf[5]+ga_ucTxdBuf[6];

  564.                         i = 7;                                                                                                                                                        // 數據區起始指針
  565.                        
  566.                         if(uitemp.b[0] == 0)
  567.                         {
  568.                                 ucI_Ptr = uitemp.b[1];                                                                                // 如果高地址為 0 ,則讀IDATA內容
  569.                                 for(j=0;j<n;j++)
  570.                                 {
  571.                                         ga_ucTxdBuf[i] = *ucI_Ptr;
  572.                                         i++;
  573.                                         ucI_Ptr++;
  574.                                 }
  575.                         }
  576.                         else
  577.                         {
  578.                                 ucX_Ptr = uitemp.b[1];                                                                                // 如果高地址不為“0”,則讀XDATA內容,因為只有256字節的XDATA,所以只取低字節。
  579.                                 for(j=0;j<n;j++)
  580.                                 {
  581.                                         ga_ucTxdBuf[i] = *ucX_Ptr;
  582.                                         i++;
  583.                                         ucX_Ptr++;
  584.                                 }
  585.                         }

  586.                         ga_ucTxdBuf[i] = ~sum;                                                // 校驗和
  587.                                
  588.                         gc_ucTxdCnt = i+1;                                                                // 發送字節計數
  589.                         gi_ucTxdPtr = 0;                                                                        // 發送指針
  590.                         SBUF = ga_ucTxdBuf[0];                                                // 啟動發送
  591.                        
  592.                         break;
  593.                 }
  594.                
  595.                 default:
  596.                 {
  597.                         break;
  598.                 }
  599.         }
  600. }

  601. /********************************************/
  602. /*名稱:        calStopCntValue                                                                                        */
  603. /*用途: 根據得到的行走脈沖數計算出停止點          */
  604. /********************************************/

  605. unsigned int calStopCntValue(unsigned int uiRun_Num,unsigned char No)
  606. {
  607.         unsigned int cnt1;
  608.        
  609.         if(uiRun_Num !=0)
  610.         {
  611.                 cnt1 = gac_uiPulsCnt[No];
  612.                 while(cnt1 != gac_uiPulsCnt[No])
  613.                 {
  614.                         cnt1 = gac_uiPulsCnt[No];                                                                        // 防護處理,避免正好在PCA中斷時取數
  615.                 }
  616.                
  617.                 cnt1 = cnt1 + uiRun_Num;                                                                                // 得到停止的判斷點
  618.         }
  619.         else
  620.         {
  621.                 cnt1 = 65535;                                                                                                                                // g_uiRotateNum =0;設置為最大值,永不停止
  622.         }       

  623.         return(cnt1);
  624. }

  625. /*********************************************/
  626. /*名稱:        setMotorStat                                                                                                 */
  627. /*用途: 根據命令中的PWM值或轉速值設置電機狀態*/
  628. /*********************************************/
  629. char setMotorStat(int iRunValue)
  630. {
  631.         char stat;
  632.        
  633.         switch (iRunValue)
  634.         {
  635.                 case 0:
  636.                 {
  637.                         stat = IN_STOP;
  638.                         break;
  639.                 }
  640.                
  641.                 case FLOAT_PWM:
  642.                 {
  643.                         stat = IN_STOP;
  644.                         break;
  645.                 }
  646.                
  647.                 case BRAKE_PWM:
  648.                 {
  649.                         stat = IN_STOP;
  650.                         break;
  651.                 }
  652.                
  653.                 case FLOAT_SPEED:
  654.                 {
  655.                         stat = IN_STOP;
  656.                         break;
  657.                 }
  658.                
  659.                 case BRAKE_SPEED:
  660.                 {
  661.                         stat = IN_STOP;
  662.                         break;
  663.                 }
  664.                
  665.                 default:
  666.                 {
  667.                         if(iRunValue >0)
  668.                         {
  669.                                 stat = IN_FORWARD;
  670.                         }
  671.                         else
  672.                         {
  673.                                 stat = IN_BACKWARD;
  674.                         }
  675.                         break;
  676.                 }               
  677.         }
  678.         return(stat);
  679. }

  680. /*********************************************/
  681. /*名稱:        followLineControl                                                                                 */
  682. /*用途: 根據采樣輸出值g_cSampleOut 控制尋跡         */
  683. /*********************************************/

  684. ……………………

  685. …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼

所有資料51hei提供下載:
循跡小車詳細資料包括電路圖、軟件編程.rar (238.93 KB, 下載次數: 150)


評分

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

查看全部評分

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

使用道具 舉報

無效樓層,該帖已經被刪除
板凳
ID:539016 發表于 2020-4-28 00:14 | 只看該作者
好東西,值得學習
回復

使用道具 舉報

地板
ID:539016 發表于 2020-4-28 00:14 | 只看該作者
好東西,值得學習
回復

使用道具 舉報

5#
ID:958455 發表于 2021-9-7 20:35 | 只看該作者
最近學校也在組織循跡小車的比賽,頂
回復

使用道具 舉報

6#
無效樓層,該帖已經被刪除
您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表