wwwxxx国产_337p日本欧洲亚洲大胆张筱雨_免费在线看成人av_日本黄色不卡视频_国产精品成熟老女人_99视频一区_亚洲精品97久久中文字幕_免费精品视频在线_亚洲色图欧美视频_欧美一区二三区

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 4755|回復: 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 單片機教程網

快速回復 返回頂部 返回列表
亚洲国产精品无码久久| 朝桐光一区二区| 亚洲AV无码精品国产| 亚洲av毛片基地| 国产特级黄色大片| 黄色一区三区| 毛片精品免费在线观看| 欧洲国内综合视频| 国产欧美视频一区二区| 日韩专区中文字幕一区二区| 欧美激情久久久久久久久久久| 好看的中文字幕在线播放| 天天激情综合| 翔田千里精品久久一区二 | 成年片费网站色大全免费视频| 国产一区二区三区成人| 农村老熟妇乱子伦视频| 九九九九九国产| 91免费国产精品| 好看的日韩精品视频在线| 欧美一级黑人aaaaaaa做受| 亚洲人成在线免费观看| 欧美在线制服丝袜| 亚洲美女免费在线| 91亚洲精品一区二区乱码| 丝瓜av网站精品一区二区| 亚洲午夜精品一区二区国产| 日本成人中文| 高清国产一区二区三区四区五区| 欧美韩日亚洲| 9色在线视频| 青娱在线视频| 日本成人a视频| 国产精品入口麻豆免费| 亚洲成a人片77777老司机| 一级黄色录像大片| 中文精品99久久国产香蕉| 欧美另类z0zxhd电影| 国产亚洲精品精华液| 国产精品88888| 天堂久久久久va久久久久| 欧美日韩亚洲国产精品| 欧美日韩有码| 伊人春色精品| 精品三级av| 91精品入口| 日韩成人精品| 国产黄色高清在线| 尤物在线观看| 高清视频国产| 国产青草视频在线观看视频| 黄网站在线观看永久免费| 色哟哟中文字幕| 丰满少妇一级片| 亚洲国产www| 亚洲第一免费视频| 亚洲伦理在线观看| 人妻少妇一区二区三区| 隣の若妻さん波多野结衣| 亚洲精品一区二区三区不卡| 亚洲av无码乱码国产精品久久| 国产av精国产传媒| 人妻偷人精品一区二区三区| 粉嫩小泬无遮挡久久久久久| 亚洲奶汁xxxx哺乳期| 理论片中文字幕| 亚洲人成影院在线| 鲁一鲁一鲁一鲁一澡| 国产资源在线视频| 日韩视频第二页| 国产又大又硬又粗| 五月婷婷六月丁香激情| 亚洲一级片av| 中文字幕第3页| 国产精品三级在线观看无码| 黄色免费一级视频| www青青草原| 天天爽夜夜爽夜夜爽精品| 亚洲熟女综合色一区二区三区| 欧美性受xxx黑人xyx性爽| 国产三级视频在线播放| 无码精品视频一区二区三区 | 欧美不卡视频一区| 日韩激情片免费| 最新国产精品拍自在线播放| 欧美激情videos| 欧洲成人性视频| 成人激情在线播放| 蜜桃臀一区二区三区| 亚洲国产一区二区精品视频 | 国产精品扒开腿做爽爽爽的视频| 国产精品亚洲欧美导航| a级国产乱理论片在线观看99| 蜜桃av色综合| 国内少妇毛片视频| 狠狠操狠狠干视频| 成人精品在线观看视频| 日韩a级片在线观看| 国产精品欧美综合| 黄色一级大片在线免费看国产| 免费永久在线观看黄网| 黄网址在线看| 小草av在线播放| 黄在线免费观看| 国产综合色在线观看| 精品国产乱子伦一区二区| 天天做天天爱天天综合网2021| 一区二区三区成人精品| 成人av网站免费观看| 国产精品久久久久久妇女6080| 懂色aⅴ精品一区二区三区蜜月| 日韩一级二级三级| 久久天天躁夜夜躁狠狠躁2022| 欧美在线xxx| 国产精品国产一区二区| 2022中文字幕| 在线观看免费视频国产| 欧美成人手机视频| 国精产品一品二品国精品69xx| 日本老妇乱子| 成人免费在线电影| 欧美日韩午夜电影网| 亚洲国产黄色| 国产无遮挡一区二区三区毛片日本 | 中文字幕日本一区二区| 国产成人三级| 美女高潮久久久| 亚洲色图丝袜美腿| 欧美一二三区在线| 性欧美激情精品| 久久99国产精品99久久| 日韩视频在线免费看| 国产jizz18女人高潮| 99久久精品免费看国产交换| 加勒比免费视频| 91精品国产91久久久久游泳池 | 国产午夜精品一区二区三区四区| 欧美亚洲综合网| 久久亚洲春色中文字幕| 国产在线精品二区| 成人性生交免费看| 久久国产精品波多野结衣av| 天天综合在线视频| 理论片在线观看理伦片| 在线一区视频观看| 激情综合激情| 中文字幕一区三区| 日韩精品在线观看一区二区| 成人精品久久一区二区三区| 日韩中字在线观看| 最新av电影网站| 2018中文字幕在线观看| 亚洲人性生活视频| 成人综合日日夜夜| 日韩av一区二区三区四区| 亚洲一区二区三区视频在线播放| 国产一区二区美女视频| 精品一区二区三区国产| 国产精九九网站漫画| 中文字幕无码乱码人妻日韩精品| 成年人免费影院| 亚洲啊v在线| 欧美视频一区| 亚洲人成网站色在线观看| 一本色道久久88综合亚洲精品ⅰ| 九九九九九九精品| 国产激情视频网站| 天天操天天干天天插| 国产h视频在线观看| 精品在线观看入口| 久久精品一区二区三区四区| 日韩精品视频中文在线观看| 国产视频一区二区三区四区| 久久国产劲爆∧v内射| 亚洲精品无amm毛片| 精品亚洲综合| 日本a口亚洲| 亚洲人成网站影音先锋播放| 欧美成人精品激情在线观看| 成年在线观看视频| 久久久夜色精品| jizzz18| 日韩高清一区| 99r精品视频| 在线成人激情黄色| 亚洲一区二区四区| 久久综合亚洲色hezyo国产| 九色.com| 一区二区三区| 99久久综合狠狠综合久久| 亚洲欧美一区二区三区四区| 视频在线观看成人| 久久久精品国产sm调教| 成年网站在线在免费播放| 2019中文亚洲字幕| 91在线精品一区二区| 深夜成人在线观看| 久草视频这里只有精品| 久久久久久久久久久久久av| 亚洲精品第一国产综合野草社区| 美女av一区| 亚洲视频狠狠干| 茄子视频成人在线| 少妇丰满尤物大尺度写真| 四虎影院影音| 99欧美精品| 久久一夜天堂av一区二区三区| www.日韩av.com| 欧洲熟妇精品视频| 午夜av免费在线观看| 深夜成人影院| 久久中文字幕电影| 亚洲18私人小影院| 97免费公开视频| 99久久精品一区二区三区| 国产人与zoxxxx另类91| 日本一区二区高清| 日本不卡高字幕在线2019| 一区二区免费在线观看视频| 国产免费av网站| 精品一区二区三区亚洲| 亚洲欧洲精品天堂一级| 国产精品久久久av久久久| 亚洲欧美在线不卡| eeuss影院eeuss最新直达| 亚洲尤物av| 精品日韩中文字幕| 久久久久久国产精品免费免费| 一区二区三区免费高清视频| 日韩一二三四| 六月天综合网| 在线看福利67194| 五月婷婷狠狠操| 麻豆国产传媒av福利| 超碰97久久国产精品牛牛| 亚洲图片自拍偷拍| 精品国产一区二区三区久久久久久| 免费视频一二三区| 国产三级视频在线播放线观看| 日日摸夜夜添夜夜添精品视频| 亚洲欧美国产一区二区三区 | 99精品福利视频| 亚洲精品99999| 精品人妻一区二区三区四区在线 | 国产精品久久久免费看| 首播影院在线观看免费观看电视| 黄色成人av网站| 日韩电影中文字幕一区| 欧美成人高潮一二区在线看| 一区二区三区电影网| 视频亚洲一区二区| 精品国产999| 亚洲亚洲精品三区日韩精品在线视频| 在线免费观看一区二区| 亚洲日本天堂| 亚洲欧美综合另类在线卡通| 成人三级在线| 青青艹在线观看| mm视频在线视频| 国产精品久久久久久久午夜片 | 久久久久无码国产精品不卡| 午夜免费视频在线国产| 成人久久18免费网站麻豆 | 999精品视频在线观看| 亚洲自拍偷拍综合| 日韩在线电影一区| 欧日韩在线视频| japanese色系久久精品| 欧美人妇做爰xxxⅹ性高电影| 国产欧美日韩小视频| 欧美性巨大欧美| 不卡日本视频| 亚洲女人被黑人巨大进入al| 成人做爰69片免费| 丁香花高清电影在线观看完整版| 美女网站色91| 国产精品久久久久久久久影视| 久久精品第一页| 性孕妇free特大另类| 99久久亚洲精品日本无码| 欧美日韩a v| 小视频免费在线观看| 一区二区在线免费观看| 婷婷亚洲婷婷综合色香五月| 午夜影院在线视频| 精品久久久中文字幕| 日韩精品视频免费| 在线天堂www在线国语对白| 亚洲美女欧洲| 26uuu国产电影一区二区| 懂色一区二区三区av片| 丰满人妻一区二区三区无码av| 8848成人影院| 亚洲а∨天堂久久精品9966| 亚洲一级Av无码毛片久久精品| 中文在线有码| 欧美国产视频在线观看| 美女亚洲精品| 人人妻人人澡人人爽人人欧美一区| 亚洲三级av| 亚洲成人黄色网| 无码精品一区二区三区在线播放| 国产人成在线观看| 日本一区二区三区四区 | 亚洲国产成人精品久久久国产成人一区| 男生操女生视频在线观看| 欧美成人明星100排名| 粉嫩蜜臀av国产精品网站| 国产精品日韩欧美一区二区| 天天射,天天干| 亚洲最大黄网| 欧美在线xxx| 国产欧美第一页| 日韩88av| 国产一区二区三区国产精品| 欧美专区亚洲专区| 中文字幕中文在线| 欧美日本网站| 亚洲欧洲一区二区在线播放| 成年人网站国产| av超碰在线观看| 国产精品无人区| 国产资源在线视频| 亚洲成人男人天堂| 亚洲欧美日韩国产综合| 欧美 日韩 国产一区| 青青操在线视频| 夜夜精品视频一区二区| 欧美精品性生活| av在线电影网| 欧美视频二区36p| 肉丝美足丝袜一区二区三区四| 怡红院av在线| 欧美日韩黄视频| av手机在线播放| 日本精品久久| 中文字幕亚洲欧美日韩2019| 亚洲不卡视频在线观看| 久久99青青| 日韩美女视频免费看| 亚洲日本在线播放| 蜜臀精品久久久久久蜜臀 | 日韩a级在线观看| 无码人妻精品一区二区50| 国产成人aa在线观看网站站| 在线午夜精品自拍| 亚洲va在线观看| 俺要去色综合狠狠| 日韩av第一页| 一本岛在免费一二三区| 麻豆精品视频在线| 翔田千里亚洲一二三区| 99re6热在线精品视频播放| 一区二区三区免费网站| 亚洲天堂2024| 在线播放成人| 国产最新精品视频| 五月婷婷一区二区三区| 国内精品久久久久影院薰衣草| 青青草原网站在线观看| 午夜影院在线免费观看| 色婷婷激情一区二区三区| 综合区小说区图片区在线一区| 色噜噜一区二区三区| 免费在线亚洲欧美| 久久久99国产精品免费| av在线dvd| 五月天久久比比资源色| 中文精品在线观看| 成人免费直播在线| 日韩女在线观看| 国产永久免费| 久久女同精品一区二区| 九九热精品在线播放| 天堂资源在线| 少妇高潮 亚洲精品| 欧美一区二区三区激情| 国产精品亚洲人在线观看| www.玖玖玖| 成人在线黄色电影| 日韩一区二区在线视频| 免费看日韩av| 伊人狠狠色j香婷婷综合| 欧美三级电影在线观看| 欧美人与禽zoz0善交| 亚洲免费成人av在线| 国产美女91呻吟求| 人与牲动交xxxbbb| 一区二区在线看| 无码少妇一区二区| 国产一区不卡| 国产一区二区不卡视频在线观看| 一本免费视频| 欧美一区二区成人| 国产又粗又长又黄| 国产乱对白刺激视频不卡| 欧美韩国日本在线| 日本少妇一区| 97视频在线观看播放| 一级黄色免费|