|
包含了智能避障小車的程序和論文
圓夢小車 Step by Step 之六
—— 讓小車“看到”障礙物
前一篇講述了如何在“路”上行走,本篇讓小車學(xué)會“看到”避障物! 機器視覺中最接近人眼的莫過于攝像頭了,可圖像處理小車的“大腦”對付不了,至少目前的“大腦”能力不夠,等進化后也許能夠應(yīng)付。 為了能“看到”障礙物,小車目前能用的主要是各類測距傳感器,典型的有超聲波和紅外兩種,此外還有利用光線的反射強弱來判斷的,這種方式不具備“測距”功能,但可以判斷有無!因為不同物體表面及顏色反射的能力不同(看后面的數(shù)據(jù)) 。 本文主要討論的是機器人中最常用的紅外測距傳感器 —— GP2D12。
0.png (158.39 KB, 下載次數(shù): 83)
下載附件
2018-7-22 15:50 上傳
機器人配件供應(yīng)商都提供。 使用Google英文版搜索一下 “MiniSumo”, 你將會發(fā)現(xiàn)GP2D12 使用是多么普遍。
其二是因為它的測距范圍和小車的“個頭”及運動速度匹配,對于 10cm 見方、運動速度 10 – 30cm/s 的小個頭,能“看到”幾米開外的東西意義不大,而 10 – 80cm 正是它所要關(guān)注的范圍。
GP2D12 的工作原理我理解為(僅供參考,歡迎指正) : 它是由一個紅外發(fā)射管和一個 PSD(Position Sensing Device 位置敏感檢測裝置)以及相應(yīng)的計算電路構(gòu)成, Sharp 公司的 PSD 很有特色, 它可以檢測到光點落在它上面的微小位移,分辨率達微米,GP2D12 正是利用這個特性實現(xiàn)了幾何方式測距。 紅外發(fā)射管發(fā)出的光束,遇到障礙物反射回來,落在 PSD 上,構(gòu)成了一個等腰三角形,借助于 PSD 可以測得三角形的底,而兩個底角是固定的,由發(fā)射管確定,此時便可通過底邊推算出高,也就是我們所要的距離。如下圖所示:
0.png (21.18 KB, 下載次數(shù): 79)
下載附件
2018-7-22 15:51 上傳
從圖中可以看出,這是一個頂角極銳的等腰三角形,底邊只有 2cm ,高卻要有 10 – 80cm,所以 PSD 的分辨率必須極高,否則微小的偏差都會帶來距離的巨大誤差。從這一點也可以得出,它的測距結(jié)果很難穩(wěn)定、精確,畢竟比值太大。
因為 PSD 的尺寸有限, 從圖中就很容易理解為何它的測量距離超出范圍后就不可能是有效數(shù)據(jù),連趨勢都得不到。
從上述原理描述還可以知道,它不是連續(xù)測量,得到底邊長度后,必須經(jīng)過計算才能得到距離值,然后轉(zhuǎn)換為模擬信號輸出。
這兩個推論在那篇“Sharp GP2D12 applicationNote” (應(yīng)用指南)有所印證,具體表現(xiàn)為它測距的強指向性和輸出的不確定性(噪音高達 200mV,相對于 2.4V的滿量程輸出而言達 5%) 。 這篇文章好像是國外一個愛好者寫的,他做了大量的測試,對使用者掌握GP2D12 的性能及合理的使用它極有幫助。
總有人問 GP2D12 是否能用于某些場合?如果能仔細吃透上述指標(biāo),自然會有答案。還有人問它與超聲波傳感器那個好,我想這些指標(biāo)也會告訴你! 至于更詳細的內(nèi)容,讀者可進一步閱讀 GP2D12 的數(shù)據(jù)手冊以及上面介紹的應(yīng)用指南,在此我就不再贅述。
二、GP2D12 的使用
從手冊上可知,GP2D12 的輸出為 0.4V – 2.4V 模擬信號,對應(yīng) 80 – 10 cm 距離,輸出與距離間的關(guān)系成反比,且為非線性。 要使用它,首先必須具有 AD 轉(zhuǎn)換,這點圓夢小車具備,且十分適合,因為圓夢小車的MCU 供電電壓為 3.3V,其內(nèi)帶的 AD 滿量程也為 3.3V,對于 2.4V的 GP2D12 輸出信號,利用率較高(如果 AD 是 5V滿量程,也許要考慮增加一級放大) 。
而且小車使用 4 節(jié)充電電池供電, 4 節(jié)串聯(lián)為 4.8– 5V, 正好滿足 GP2D12 的 4.5-5.5V供電要求 (注意: 千萬不要使用普通電池供電, 因為普通電池的電壓為1.5V, 新的通常有1.6V,4 節(jié)串聯(lián)將達 6.4V,有可能損壞 GP2D12!此外,普通電池的電壓不穩(wěn)定,內(nèi)阻隨使用逐漸增大,導(dǎo)致靜態(tài)時電壓還湊合,電機一轉(zhuǎn)小車就復(fù)位) 。
圓夢小車設(shè)計時在底盤上預(yù)留了 GP2D12 的安裝位置,并在擴展板上預(yù)留了 GP2D12的接口,購買 GP2D12 時還提供了連線和插座,用戶只需將插座焊在擴展板預(yù)留位置即可方便使用。
0.png (206.88 KB, 下載次數(shù): 92)
下載附件
2018-7-22 15:53 上傳
此時,GP2D12 接入 STC12LE5412AD 的 P1.4 腳,即內(nèi)部 AD 的第四通道。
在硬件上,沒有太多的難度,但是要用好 GP2D12,軟件上似乎要做些努力,必須解決的有兩個問題:
一是信號的線性化,因為輸出與距離的關(guān)系是非線性的,為便于程序中使用距離信息,必須將模擬信號轉(zhuǎn)換為相應(yīng)得距離值。
二是濾波,因為按照上述應(yīng)用指南的測量分析,GP2D12 的輸出噪聲很大;此外,還由于測量的非連續(xù)性,導(dǎo)致連續(xù)的距離變化對應(yīng)的輸出為階躍信號,也需要通過濾波將其平滑。
2.1 線性化
關(guān)于線性化,開始時我也一籌莫展,曾想用折線近似實現(xiàn),但嘗試后覺得代碼量太大,而且需要做大量數(shù)據(jù)采集。
后來在 acroname網(wǎng)站上(二年前) ,發(fā)現(xiàn)了一個極好的“東東” —— 一個用 Excel 制作的電子表,表格的格式如下:
0.png (270.67 KB, 下載次數(shù): 89)
下載附件
2018-7-22 15:54 上傳
里面有作者根據(jù) GP2D12 特性建立的數(shù)學(xué)模型(線性化公式) ,并預(yù)留的使用者輸入?yún)?shù)的地方,只需按其要求填入:
AD 的位數(shù)、AD 供電電壓(滿量程) ,并采集 8 點(10cm 間隔)GP2D12 的輸出電壓,填入表中,它就可自動生成線性化公式的參數(shù),提供了整形和浮點兩種格式,還附有由此產(chǎn)生的結(jié)果與實際的偏差表,并用生動的圖形表示,十分直觀、實用。
0.png (75.66 KB, 下載次數(shù): 82)
下載附件
2018-7-22 15:55 上傳
0.png (26.47 KB, 下載次數(shù): 83)
下載附件
2018-7-22 15:55 上傳
第一列為實際距離,第二列障礙物表面為白紙,第三列障礙物為褐色木盒,讀者可比照Excel 表中的數(shù)據(jù),可以看出基本吻合。同時還可以從上面數(shù)據(jù)中看出,GP2D12 確實如其手冊中所說,基本不受障礙物的顏色影響。
0.png (273.17 KB, 下載次數(shù): 88)
下載附件
2018-7-22 15:56 上傳
2.2 濾波
濾波主要解決兩個問題,一是在 GP2D12 恒定輸出階段,按應(yīng)用指南的分析,有不小的噪聲,需要通過濾波消除。
二是由于其非連續(xù)測量的特性,導(dǎo)致其測量連續(xù)變化的距離時,輸出是階躍形式的,這對程序判斷極為不利,為了弱化這個影響,也期望通過濾波實現(xiàn)。 根據(jù) GP2D12 的手冊,其測量周期為 40ms 左右(38ms) ,綜合小車單片機的內(nèi)存及處理需求,采用 5ms采樣一次,取最近 8 次的結(jié)果平均值的濾波方式,也就是說,一個測量周期采 8 個數(shù)據(jù)平均。
這樣處理可以降低噪聲的影響, 這點容易理解。 至于弱化階躍信號, 不知讀者是否認同?
我是這樣考慮:在出現(xiàn)階躍信號時,8 個數(shù)據(jù)中隨著時間推移,新的信號所占的權(quán)重不斷加大,使得信號逐漸從前一個信號平緩的過渡到新的信號上。但是這樣處理,導(dǎo)致了距離信號反映滯后,要到下一個信號快到時,本次的輸出才接近本次的信號。就這一點而言,似乎有些不盡合理,有待讀者深入探討。
按此方式所編的小車程序為:YM1_Prog_6.C,對應(yīng)寫了 PC 程序,可讀出 8 次采樣數(shù)據(jù)和平均值,上面所示的結(jié)果就是由此程序產(chǎn)生的。
注意,此篇中的 AD 使用了 10 位精度,讀者可比照一下上一篇軌跡采樣的 AD 數(shù)據(jù)采集,看區(qū)別何在?
三、如何“看到”障礙物
為了演示一下距離信號的作用,我嘗試做了一個簡單的功能:讓小車與障礙物保持一定
距離。
因為前面做過小車走直線的例子,此次就在走直線的基礎(chǔ)上做改動,小車發(fā)現(xiàn)距離近了就向后直行,反之向前直行。
對應(yīng)的小車程序為:YM1_Prog_6A.C。
控制還是使用 PC,按照前面添加“走軌跡”的方式,在下拉選項中增加了一項:保持距離,同時添加了一個距離值輸入。具體看下面關(guān)于 PC 程序的描述。
程序的運行效果見所附視頻,讀者從中可以發(fā)現(xiàn)什么?造成的原因又是什么?我想學(xué)過自動控制的一定知道!本篇的目的是介紹如何使用 GP2D12,這方面的內(nèi)容就不展開了。
四、PC 機側(cè)程序的相應(yīng)改進
為配合測距功能的測試,PC 機側(cè)需要增加:
¾ 距離數(shù)據(jù)的讀取
¾ 應(yīng)用功能的控制
距離數(shù)據(jù)的讀取方式和軌跡采樣數(shù)據(jù)類似,為了便于一次讀取,還是將平均值和 8 次采樣值放在一個數(shù)組中,一次將 9 個數(shù)據(jù)讀出,程序的修改與軌跡部分類似。
應(yīng)用功能的控制增加方式也與軌跡相同,只是由于保持距離值的設(shè)置需要,添加了一個輸入框。
同樣,為此擴充了一個命令:
保持距離
命令字 —— 0x06
數(shù)據(jù)域 —— 保持的距離(2 字節(jié)) PWM 基準(zhǔn)值(2 字節(jié),先低后高)
其中“保持的距離”為小車與障礙物間的距離值,單位 cm, PWM 基準(zhǔn)值為小車移動的電機驅(qū)動值。
返回數(shù)據(jù)幀:
幀頭 發(fā)送方地址 自己的地址 幀長 命令 校驗和
修改后的 PC 界面: (余下見附件)
單片機程序源碼:
- /*******************************************************/
- /* 圓夢小車StepbyStep 程序之6 */
- /* —— 教小車“看到”障礙物 */
- /*******************************************************/
- // 注:以下文檔的 TAB 為 2 個字符!
- /*-----------------------------------------------------
- 這段程序是以StepByStep之五的程序YM1_Prog-5A.C
- 為基礎(chǔ),增加測距功能,使小車能夠“看到”障礙物,
- 并據(jù)此躲避之。
-
- -------------StepByStep之一 070609 ---------------
- 因為程序簡單,故所有內(nèi)容合并在一個文件中。
- 硬件資源分配:
- Timer0 仍然作為 1ms 定時器,作為工作的時基;
- Timer1 作為UART的波特率發(fā)生器。
-
- ------------StepByStep之二 070615 ----------------------
- 通訊協(xié)議:
- 字節(jié)格式 —— 19200 8 N 1
- 數(shù)據(jù)幀格式:
- 幀頭(2字節(jié)) 接收方地址(1字節(jié)) 發(fā)送方地址(1字節(jié)) 幀長(1字節(jié)) 命令(1字節(jié)) 數(shù)據(jù)域(N字節(jié)) 校驗和(1字節(jié))
-
- 幀頭 —— 由2個特殊的字節(jié) 0x55 0xAA構(gòu)成;
- 接收方地址 —— 通訊對象的“名字”,在有線通訊時也許多余,但無線時就需要了。
- 發(fā)送方地址 —— 告訴接收方,是誰和你“說話”,便于接收方回答。
- 幀長 —— 從命令開始到數(shù)據(jù)域結(jié)束的字節(jié)數(shù)
- 校驗和 —— 數(shù)據(jù)幀中從命令開始到數(shù)據(jù)域結(jié)束所有字節(jié)的算術(shù)和,取最低字節(jié)的反碼。
- ------------StepByStep之三 070618 -------------
- 電機驅(qū)動所用資源:
- PCA2 —— 產(chǎn)生左側(cè)電機的PWM信號
- PCA3 —— 產(chǎn)生右側(cè)電機的PWM信號
- PWM 時鐘源 —— Fosc/12
- PWM頻率 —— 7200
- 因為PWM為 8 位的,將有效 PWM 值定為 1 - 250,0 作為剎車控制, 255 作為惰行控制
-
- P2.0 —— 左側(cè)電機PWM控制
- P2.1、P2.2 ——左側(cè)電機工作狀態(tài)控制
-
- P2.4 —— 右側(cè)電機PWM控制
- P2.5、P2.6 ——右側(cè)電機工作狀態(tài)控制
-
- 將P2口設(shè)置為強輸出模式。
-
- 補充定義命令:電機PWM控制命令
- 命令字 —— 0x03
- 數(shù)據(jù)域 —— 左電機PWM值(2字節(jié),先低后高) 右電機PWM值
- 返回數(shù)據(jù)幀:
- 幀頭 發(fā)送方地址 自己的地址 幀長 命令 電機控制輸出(P2) 校驗和
- -------------StepByStep之四 070622 -----------------------
- 碼盤監(jiān)測所用資源:
- PCA0 —— 右側(cè)電機碼盤信號輸入
- PCA1 —— 左側(cè)電機碼盤信號輸入
-
- 將PCA0、PCA1 設(shè)置為正、負沿脈沖捕獲模式,允許中斷。
-
- 走直線控制邏輯:
- 1、初級:
- 如果右側(cè)快,則將右側(cè)置為惰行
- 如果左側(cè)快,則將左側(cè)置為惰行
- 如果相等,則均置為啟動的PWM值
-
- 補充定義命令: 走直線
- 命令字 —— 0x04
- 數(shù)據(jù)域 —— 行走距離(2字節(jié))PWM 基準(zhǔn)值(2字節(jié),先低后高)
- 其中行走距離為左側(cè)車輪的脈沖計數(shù)值,按目前的幾何尺寸,最大值65535 應(yīng)該可以走 655圈,約合86m,為“0" 時連續(xù)行走。
-
- 返回數(shù)據(jù)幀:
- 幀頭 發(fā)送方地址 自己的地址 幀長 命令 校驗和
- ---------------StepByStep之五 070715 -----------------------
- 軌跡檢測所用資源:
- P1.0 - P1.3 —— 4路軌跡信號輸入,模擬方式輸入,使用前 4 通道A/D
- P3.3(INT1) —— 控制背景采樣和信號采樣,推挽輸出
- 注意,P3 口的狀態(tài)寄存器作了修改,請參照原理圖理解!!
-
- 采樣器對應(yīng)關(guān)系:
- 頂視: 左 —— 右
- 采樣器 1 2 3 4
- PORT P1. 3 2 1 0
- 因為小車速度不快,通常小于 0.5m/s,所以將采樣設(shè)計為 2 ms 一次,對應(yīng)移動只有1mm,
- 安排在中斷外執(zhí)行。
- 具體處理步驟為:
- 設(shè)計一個采樣標(biāo)志位,每1ms中斷取反一次,為真時處理;
- 在中斷時,如果標(biāo)志為真,則打開采樣LED;
- 在主程序中檢測Timer0,如果打開LED時間超過一定值,則啟動AD,
- 完成后關(guān)閉采樣LED,結(jié)束一個采樣周期。
- 采樣處理將軌跡信號轉(zhuǎn)換為邏輯值,存放在一個狀態(tài)字中,每位對應(yīng)一個傳感器,0 —— 不在軌跡,1 —— 在軌跡,
- 默認軌跡為深色(黑色)。
-
- 之后再根據(jù)這個狀態(tài)字控制小車行走,因為是示例,所以只處理中間兩個軌跡傳感器的狀態(tài),兩側(cè)的留給讀者去發(fā)揮!
-
- 控制邏輯:
- 只處理 2、3號傳感器,即位 b1、b2,
- 兩個均在軌跡上,左右電機為同樣值,
- b1 不在,右側(cè)電機惰行,
- b2 不在,左側(cè)電機惰行。
- 和走直線類似,只是控制變量從碼盤計數(shù)差變?yōu)檐壽E采樣的狀態(tài)。
- 補充定義命令: 走軌跡
- 命令字 —— 0x05
- 數(shù)據(jù)域 —— 行走距離(2字節(jié))PWM 基準(zhǔn)值(2字節(jié),先低后高)
- 其中行走距離為左側(cè)車輪的脈沖計數(shù)值,按目前的幾何尺寸,最大值65535 應(yīng)該可以走 655圈,約合86m,為“0" 時連續(xù)行走。
-
- 返回數(shù)據(jù)幀:
- 幀頭 發(fā)送方地址 自己的地址 幀長 命令 校驗和
- ----------------StepByStep之六 070818 -----------------------
-
- 首先,做一個GP2D12 的應(yīng)用程序,實現(xiàn):
- 1、讀會 GP2D12 的模擬輸出信號;
- 2、濾波并線性化,因 GP2D12 的輸出與距離的關(guān)系是非線性的;
- 3、結(jié)合前面的走直線功能,讓小車自動保持與一個物體間的距離。
-
- 按照擴展PCB上預(yù)留的 GP2D12 接口,模擬信號輸入到 STC12LE5412AD的 P1.4 端, 對應(yīng)A/D的第4通道。
- 因為 GP2D12 的輸出有噪音,且為階梯輸出(不連續(xù)測量),擬采用滑動濾波,按照手冊,GP2D12 約 40 ms測量一次。
- 采用 8 組數(shù)據(jù)的平均值作為結(jié)果,即5ms采樣一次。
- 同時為提高精度, A/D使用 10 位(在上篇軌跡采樣中用的是 8 位)。
-
- 線性化方式采用 Acroname 網(wǎng)站上提供的線性化公式。
-
- 演示功能為,設(shè)定一個距離值,用一個物體靠近及移遠,小車因跟隨移動;
- 為簡化程序,物體只在一維移動,小車也只是進行直線的前進和后退。
-
- -------------------------------------------------------*/
- #include <STC12C5410AD.h> /* STC12C5410AD 的頭文件,為MCU中各個硬件寄存器定個名稱,以便C語言中使用*/
- sbit Work_Display = P3^4; // 根據(jù)硬件設(shè)計用與“主控工作指示”接近的名稱取代硬件,使程序減少與硬件的相關(guān)性
- sbit g_bSample = P3^3; // 軌跡采樣控制端, 070715
- // --------- 常數(shù)定義 --------------------------
- #define TRUE 1
- #define FALSE 0
- #define LIGHT 0 // 亮邏輯值,用直觀的符號化常數(shù)替換與硬件密切相關(guān)的邏輯值,增加程序的可讀性、可移植性。
- #define DARK 1 // 暗邏輯值
- #define LIGHT_TIME 1000 // 亮?xí)r間,使用符號化常數(shù),便于修改,增加程序可讀性
- #define DARK_TIME 1000 // 暗時間
- #define P3MODE0 0xB0 /* 1011 0000,P3.0 P3.1 P3.2 標(biāo)準(zhǔn)51口,P3.3 推挽輸出 ,P3.4 OC輸出, P3.5 P3.7 輸入*/
- #define P3MODE1 0x18 /* 0001 1000 ----- 070715 ----- */
- /* 定時器參數(shù)定義 */
- #define T0MODE0 0x00 // 0000 0000,Timer0工作在模式0 ,13位定時;
- #define T0MODE1 0x01 // 0000 0001,Timer0工作在模式1 ,16位定時;
- #define T0MODE2 0x02 // 0000 0010,Timer0工作在模式2 ,8 位自動重加載定時;
- #define T0MODE3 0x03 // 0000 0011,Timer0工作在模式3
- #define T0_TIMER 0x00 // Timer0 工作在定時器模式
- #define T0_COUNTER 0x04 // Timer0 工作在計數(shù)器模式
- #define T0_DISGATE 0x00 // Timer0 禁止INT0引腳控制
- #define T0_ENGATE 0x08 // Timer0 允許INT0引腳控制
- #define T1MODE0 0x00 // 0000 0000,Timer0工作在模式0 ,13位定時;
- #define T1MODE1 0x10 // 0000 0001,Timer0工作在模式1 ,16位定時;
- #define T1MODE2 0x20 // 0000 0010,Timer0工作在模式2 ,8 位自動重加載定時;
- #define T1MODE3 0x30 // 0000 0011,Timer0工作在模式3
- #define T1_TIMER 0x00 // Timer1 工作在定時器模式
- #define T1_COUNTER 0x40 // Timer1 工作在計數(shù)器模式
- #define T1_DISGATE 0x00 // Timer1 禁止INT1引腳控制
- #define T1_ENGATE 0x80 // Timer1 允許INT1引腳控制
- #define SET_T0X12_C 0x80 // or AUXR
- #define CLR_T0X12_C 0x7F // and AUXR
- #define SET_T1X12_C 0x40 // or AUXR
- #define CLR_T1X12_C 0xBF // and AUXR
- #define TIME1ms_C 0xF8D0 /* 1ms 定時的加載值字節(jié),對應(yīng) 22.1184MHz 定時器12分頻 */
- #define TIME1msH_C 0xF8 /* 1ms 定時的加載值高字節(jié) */
- #define TIME1msL_C 0xD0 /* 1ms 定時的加載值低字節(jié) */
- /* 中斷處理參數(shù)定義 */
- #define EnINT0_C 0x01
- #define EnT0_C 0x02
- #define EnINT1_C 0x04
- #define EnT1_C 0x08
- #define EnUART_C 0x10
- #define EnADCSPI_C 0x20
- #define EnPCALVD_C 0x40
- #define INT0_DOWN 0x01 // TCON 中對INT0中斷信號的控制,下降沿觸發(fā);
- #define INT0_LOW 0x00 // TCON 中對INT0中斷信號的控制,低電平觸發(fā);
- #define INT1_DOWN 0x04 // TCON 中對INT1中斷信號的控制,下降沿觸發(fā);
- #define INT1_LOW 0x00 // TCON 中對INT1中斷信號的控制,低電平觸發(fā);
- #define NOIP_C 0x00 /* 無優(yōu)先級 */
- #define INT0_HIGH 0x01 // IP 寄存器中的優(yōu)先級設(shè)置,IPH暫不處理。
- #define T0_HIGH 0x02
- #define INT1_HIGH 0x04
- #define T1_HIGH 0x08
- #define UART_HIGH 0x10
- #define ADCSPI_HIGH 0x20
- #define PCALVD_HIGH 0x40
- // 顯示摩爾斯電碼用
- #define MAX_CHAR_NUM 30 // 最多允許顯示字符數(shù)
- #define MAX_GAP_NUM 9 // 一個字母最多所需的亮、暗變化次數(shù)
- #define BASE_TIME 200 // 莫爾斯電碼的基本時間,暫定 200ms
- /* 莫爾斯電碼表,將大寫字母轉(zhuǎn)換為一個亮、暗序列表 */
- unsigned char code ga_ucMorseCode[26][9]={1,2,3,7,0,0,0,0,0,
- 3,2,1,2,1,2,1,7,0,
- 3,2,1,2,3,2,1,7,0,
- 3,2,1,2,1,7,0,0,0,
- 1,7,0,0,0,0,0,0,0,
- 1,2,1,2,3,2,1,7,0,
- 3,2,3,2,1,2,1,7,0,
- 1,2,1,2,1,2,1,7,0,
- 1,2,1,7,0,0,0,0,0,
- 1,2,3,2,3,2,3,7,0,
- 3,2,1,2,3,7,0,0,0,
- 1,2,3,2,1,2,1,7,0,
- 3,2,3,7,0,0,0,0,0,
- 3,2,1,7,0,0,0,0,0,
- 3,2,3,2,3,7,0,0,0,
- 1,2,3,2,3,2,1,7,0,
- 3,2,3,2,1,2,3,7,0,
- 1,2,3,2,1,7,0,0,0,
- 1,2,1,2,1,7,0,0,0,
- 3,7,0,0,0,0,0,0,0,
- 1,2,1,2,3,7,0,0,0,
- 1,2,1,2,1,2,3,7,0,
- 1,2,3,2,3,7,0,0,0,
- 3,2,1,2,1,2,3,7,0,
- 3,2,1,2,3,2,3,7,0,
- 3,2,3,2,1,2,1,7,0};
-
- //————————————————————————————————————————————————————
- // 以下為StepByStep之二所增加的通訊程序用常量, 070615
- /* 串口參數(shù) */
- #define B_57600 4
- #define B_38400 3
- #define B_19200 2
- #define B_9600 1
- #define B_4800 0
- // 在 22.1184Hz 下用 T1 作波特率發(fā)生器, 1 分頻。
- #define B57600_C 244
- #define B38400_C 238
- #define B19200_C 220
- #define B9600_C 184
- #define B4800_C 144
- #define UART_MODE1_C 0x40 // SM0,SM1= 01
- #define EN_RCV_C 0x10 // REN=1
- // 允許串口中斷
- #define EnUART_C 0x10
- // 串口中斷優(yōu)先級
- #define UART_HIGH 0x10
- // 數(shù)據(jù)接收用常數(shù)
- #define MaxRcvByte_C 32 // 接收緩沖區(qū)的大小,此值必須對應(yīng)一定位數(shù)的二進制數(shù),便于利用屏蔽高位的方式處理指針。
- #define MaxTxdByte_C 32
- // 幀命令字
- #define READ_MEMORY 0x01 // 讀內(nèi)存命令字
- #define WRITE_MEMORY 0x02 // 寫內(nèi)存命令字
- #define MOTOR_PWM_CTRL 0x03 // 電機PWM控制命令,之三增加, 070618
- #define RUN_STRAIGHT 0x04 // 走直線命令, 之四增加, 070622
- #define RUN_ON_LINE 0x05 // 走軌跡, 之五增加, 070715
- // 自己的設(shè)備地址
- #define MY_ADDR 0x01
- //————————————————————————————————————————————————————
- // 以下為StepByStep之三所增加的電機控制程序用常量, 070618
- // 馬達控制口
- #define MotorDrv P2 // P2.0 - P2.2 控制左電機, P2.4 - P2.6 控制右電機,輸出
- #define P2MODE0 0x00 /* 0000 0000,P2 口作為馬達控制,均作為推挽輸出*/
- #define P2MODE1 0xFF /* 1111 1111,*/
- // PCA 初始化常數(shù),
- #define STARTPCA_C 0x40; // or CCON 中的CR位控制 啟動 PCA
- #define STOPPCA_C 0xBF; // and CCON 中的CR位控制 停止 PCA
- #define FOSCdiv12_C 0x00
- #define FOSCdiv2_C 0x02
- #define T0Over_C 0x04 // T0 溢出
- #define ECI_C 0x06 // 外部脈沖輸入
- #define EnCF_C 0x01 // 允許PCA溢出中斷
- #define EnCMP_C 0x40 // 0100 0000, CCAPMn 中控制位6, 允許比較器
- #define EnCAPP_C 0x20 // 0010 0000, CCAPMn 中控制位5, 允許上升沿捕獲
- #define EnCAPN_C 0x10 // 0001 0000, CCAPMn 中控制位4, 允許下降沿捕獲
- #define EnMAT_C 0x08 // 0000 1000, CCAPMn 中控制位3, 允許匹配或捕獲后置位 CCFn
- #define EnTOG_C 0x04 // 0000 0100, CCAPMn 中控制位2, 允許匹配或捕獲后觸發(fā)輸出翻轉(zhuǎn)
- #define EnPWM_C 0x02 // 0000 0010, CCAPMn 中控制位1, 允許對應(yīng)的端子輸出PWM信號
- #define EnCCFI_C 0x01 // 0000 0001, CCAPMn 中控制位0, 允許CCF產(chǎn)生中斷
- // PCA 中斷
- #define EnPCALVD_C 0x40
- // PCA 優(yōu)先級
- #define PCALVD_HIGH 0x40
- #define MOTOR_L 0
- #define MOTOR_R 1
- #define BRAKE_PWM 0 // 剎車 PWM 控制值
- #define FLOAT_PWM 255 // 惰行 PWM 控制值
- // 電機控制輸出
- /* 控制位對應(yīng)關(guān)系:
- 電機1(左)
- P2.0 - CtrlL1, H 橋的左、右上臂,1 電平輸出導(dǎo)通 0 電平輸出截止,只有在對應(yīng)下臂截止時有效
- P2.1 - CtrlL2, H 橋的左下臂,1 電平輸出導(dǎo)通 0 電平輸出截止
- P2.2 - CtrlL3, H 橋的右下臂,0 電平輸出導(dǎo)通 1 電平輸出截止
- 電機 2(右)
- P2.4 - CtrlR1, H 橋的左、右上臂,1 電平輸出導(dǎo)通 0 電平輸出截止,只有在對應(yīng)下臂截止時有效
- P2.5 - CtrlR2, H 橋的左下臂,1 電平輸出導(dǎo)通 0 電平輸出截止
- P2.6 - CtrlR3, H 橋的右下臂,0 電平輸出導(dǎo)通 1 電平輸出截止
- 控制邏輯:
- Ctrl1 Ctrl2 Ctrl3 Drv1 Drv2 Drv3 Drv4 電機狀態(tài)
- X 0 0 0/截止 0/導(dǎo)通 0/截止 0/導(dǎo)通 剎車
- PWM 1 0 PWM 1/截止 0/截止 0/導(dǎo)通 正轉(zhuǎn)
- PWM 0 1 0/截止 0/導(dǎo)通 PWM 1/截止 反轉(zhuǎn)
- 0 1 1 0/截止 1/截止 0/截止 1/截止 惰行
- 1 1 1 1/導(dǎo)通 1/截止 1/導(dǎo)通 1/截止 剎車
- 電機 2 控制邏輯相同,只是對應(yīng)高 3 位。
- */
- // 左電機控制
- #define ML_FORWARD 0x02 // 0000 0010 前進,左上、右下導(dǎo)通,
- #define ML_BACK 0x04 // 0000 0100 后退,左下、右上導(dǎo)通
- #define ML_FLOAT 0x06 // 0000 0110 浮空,4 個臂都截止,此時 Ctrl1 應(yīng)停止PWM輸出,維持“0”。
- #define ML_BRAKE 0x00 // 0000 0000 剎車,兩個下臂導(dǎo)通,上臂截止
- #define ML_MASK 0xF8 // 清除原來輸出值,保留另一個電機的輸出
- // 右電機控制
- #define MR_FORWARD 0x20 // 0010 0000 前進,左上、右下導(dǎo)通,
- #define MR_BACK 0x40 // 0100 0000 后退,左下、右上導(dǎo)通
- #define MR_FLOAT 0x60 // 0110 0000 行進控制浮空,4 個臂都截止
- #define MR_BRAKE 0x00 // 0000 0000 行進控制剎車,兩個下臂導(dǎo)通,上臂截止
- #define MR_MASK 0x8F // 清除原來輸出值,保留另一個電機的輸出
- //————————————————————————————————————————————————————
- // 以下為StepByStep之四所增加的走直線用常量, 070622
- // 無!
- //————————————————————————————————————————————————————
- // 以下為StepByStep之五所增加的走軌跡用常量, 070715
- #define P1MODE0 0xFF /* 1111 1111,P1口均作為高阻輸入,使用模擬功能 */
- #define P1MODE1 0x00 /* 0000 0000 */
- // AD 轉(zhuǎn)換器初始化常數(shù)
- #define ADPWRON_C 0x80
- #define ADSPEED3_C 0x60 // AD速度分為 4 級,0 最低 3 最高, 210 個時鐘周期轉(zhuǎn)換一次
- #define ADSPEED2_C 0x40
- #define ADSPEED1_C 0x20
- #define ADSPEED0_C 0x00
- #define CLRADFLAG_C 0xEF // and AD_CONTR
- #define GETADFLAG_C 0x10 // and AD_CONTR, 得到AD結(jié)束標(biāo)志
- #define STARTAD_C 0x08 // OR AD_CONTR
- unsigned char code DEFAULT_THRES[4] = {127,150,127,127}; // 默認判斷閾值
- #define DEFAULT_THRES_DELTA 20 // 默認判斷回差
- #define EN_SAMPLE 1 // 采樣控制,此時為允許采樣。
- #define DIS_SAMPLE 0
- #define SAMP_LED_ONTIME 600 // 打開采樣 LED 后的延時時間,約 300us
- #define STRAIGHT 0 // 小車運動狀態(tài)
- #define LEFT_ROTATE 1
- #define RIGHT_ROTATE 2
- //————————————————————————————————————————————————————
- // 以下為StepByStep之六所增加的走軌跡用常量, 070818
- #define AD_CHANEL4GP2D12 4 // GP2D12 所用的 AD通道
- // 線性化系數(shù)
- #define M_C 10485 // 這三個數(shù)是根據(jù) Acroname 網(wǎng)站提供的一個線性化計算表得到的,需要自己測量原始數(shù)據(jù)標(biāo)定。
- #define B_C 5
- #define K_C 4
- // 設(shè)定的距離(cm)
- #define GAP_VALUE 20 // 與障礙物之間的間隙定值,
- #define GAP_DELTA 2 // 允許的間隙偏差,
- // 采樣間隔時間
- #define TIME_GAP4GP2D12 5 // 暫定 5 ms 采樣一次
- // --- 全局變量定義 --------------------
- bit g_b1msFlag; // 1ms中斷標(biāo)志
- unsigned char ga_ucDispBuf[MAX_CHAR_NUM+1]; // 顯示緩沖區(qū),存放要顯示的字符,為“0”表示結(jié)束
- unsigned char gi_ucGetCharPtr; // 從顯示緩沖區(qū)取字符指針
- unsigned char ga_ucCharDispBuf[MAX_GAP_NUM]; // 一個字符顯示時亮、暗顯示序列,存放顯示基本時間單位的個數(shù),為“0”表示結(jié)束
- unsigned char gi_ucGetDispNum; // 取亮、暗基本時間數(shù)指針
- unsigned char gc_ucDispNumCnt; // 基本時間數(shù)計數(shù)器
- unsigned int gc_uiBaseTime; // 基本時間計數(shù)器, 1ms 計數(shù)
- unsigned char code DISP_CONTENT[MAX_CHAR_NUM+1] = {"HELLOWORLD"}; // 要顯示的內(nèi)容,因為莫爾斯電碼沒有定義空格
- // -------- 以下為StepByStep之二增加的變量 070615 ------------------
- // 數(shù)據(jù)接收用
- unsigned char xdata ga_ucRcvBuf[MaxRcvByte_C]; // 接收緩沖區(qū)
- unsigned char data gi_ucSavePtr; // 存數(shù)指針,每收到一個字節(jié)保存到緩沖區(qū)后加“1”。
- unsigned char data gi_ucGetPtr; // 從緩沖區(qū)中取數(shù)的指針,每取出一個字節(jié)后加“1”。
- unsigned char idata gi_ucStartPtr; // 幀起始位置,指向數(shù)據(jù)區(qū)開始。
- unsigned char idata gi_ucEndPtr; // 幀結(jié)束位置。
- unsigned char idata gc_ucDataLen; // 幀長,即數(shù)據(jù)區(qū)字節(jié)數(shù)。
- bit g_bNewData; // 串口收到一個字節(jié)標(biāo)志,為減少變量交互。
- bit g_bStartRcv; // 開始接收數(shù)據(jù)幀標(biāo)志。
- unsigned char xdata ga_ucTxdBuf[MaxTxdByte_C]; // 發(fā)送緩沖區(qū),用于返回轉(zhuǎn)速值等。
- unsigned char data gi_ucTxdPtr; // 發(fā)送指針
- unsigned char data gc_ucTxdCnt; // 發(fā)送字節(jié)計數(shù)
- // -------- 以下為StepByStep之三增加的變量 070618 ------------------
- unsigned char code ga_ucForward[2] = {ML_FORWARD,MR_FORWARD}; // 前進控制
- unsigned char code ga_ucBack[2] = {ML_BACK,MR_BACK}; // 后退控制
- unsigned char code ga_ucFloat[2] = {ML_FLOAT,MR_FLOAT}; // 惰行控制
- unsigned char code ga_ucBrake[2] = {ML_BRAKE,MR_BRAKE}; // 剎車控制
- unsigned char code ga_ucMask[2] = {ML_MASK,MR_MASK}; // 屏蔽字,為了輸出新的控制信號,清除原來的控制值
- unsigned int ga_uiMotorCtrl[2]; // 電機控制參數(shù),高字節(jié)控制方向, 0 - 前進 0xFF - 后退,低字節(jié)PWM值
- // -------- 以下為StepByStep之四增加的變量 070622 ------------------
- unsigned char data gac_ucWheel_Cnt[2]; // 碼盤輸入信號計數(shù),用計數(shù)方式而非標(biāo)志,是為了避免丟失。
- unsigned int idata gac_uiRunCnt[2]; // 對車輪轉(zhuǎn)動的碼盤信號計數(shù),以達到計算行走距離的目的
- unsigned int idata g_uiBase_PWM; // 基準(zhǔn) PWM 值
- unsigned int idata g_uiLeftRunNum; // 左側(cè)車輪行走計數(shù)設(shè)定值
- unsigned int data gc_uiLeftRunCnt; // 左輪行走減計數(shù)器
- bit g_bStopRunStraight; // 停止運行標(biāo)志
- // -------- 以下為StepByStep之五增加的變量 070715 ------------------
- bit g_bEnSample; // 允許采樣標(biāo)志
- bit g_bSampleStart; // 通知采樣
- unsigned char idata ga_ucSampleVal[5]; // 4 路采樣值,暫時取 8 位, 第 5 個單元存放轉(zhuǎn)換后的邏輯狀態(tài)
- // 存放4個傳感器的狀態(tài),一個對應(yīng)一位,“1”為在軌跡上
-
- unsigned char idata ga_ucThreshold[4]; // 4 路黑白判斷值
- unsigned char idata g_ucThresDelta; // 判斷回差,用于消除判斷時的臨界毛刺
- bit g_bStopRunOnLine; // 停止運行標(biāo)志
- unsigned char g_ucRotateStat; // 轉(zhuǎn)動狀態(tài),指示小車是直行還是左、右轉(zhuǎn)
- // -------- 以下為StepByStep之六增加的變量 070818 ------------------
- bit g_bStopHoldingGap; // 停止保持間隙運動
- unsigned char xdata ga_ucGapValue[9]; // 間隙采樣值,存放線性化后的距離值,單位 cm,最后一個單元存放平均值
- unsigned char data gi_ucSaveGapValPtr; // 保存采樣值指針
- unsigned char data gc_ucGetGapValCnt; // 采樣計數(shù),保證采滿8次后再處理數(shù)據(jù)
- unsigned char data gc_ucTimeGap4GP2D12Cnt; // 5ms 測量間隔計時器
- bit g_bRead_GP2D12; // 讀GP2D12 值
- // ------------- 函數(shù)聲明 -----------------
- void print(unsigned char *p_ucDispConPtr);
- bit getNextGap(void);
- void getNextChar(void);
- // -------- 以下為StepByStep之二增加的函數(shù) 070615 ------------------
- void init_SIO(unsigned char baud);
- bit dataFrame_OK(void);
- void do_Command(void);
- // -------- 以下為StepByStep之三增加的函數(shù) 070618 ------------------
- unsigned char DriveMotor(unsigned char No,unsigned int uiPWM_Val);
- // -------- 以下為StepByStep之四增加的函數(shù) 070622 ------------------
- void run_Straight(void);
- void StopRunStraight(void);
- // -------- 以下為StepByStep之五增加的函數(shù) 070715 ------------------
- unsigned char lineSamp_proc(unsigned char ucOldSenStat);
- void run_Online(unsigned char ucSensorStat);
- void StopRunOnLine(void);
- // -------- 以下為StepByStep之六增加的函數(shù) 070818 ------------------
- unsigned char read_GP2D12(void);
- unsigned char cal_MeanVal(unsigned char *p_ucDataStarAddr);
- /*********** 主程序 *****************/
- void main(void)
- {
- unsigned char i;
-
- // ----------- 初始化硬件 ---------------
- P3M0 = P3MODE0; // 因為只涉及 P3 口,所以此處只初始化 P3
- P3M1 = P3MODE1;
- /* 初始化定時器 */
-
- TMOD = T0MODE1|T1MODE2; // Timer0工作在模式1 ,16位定時,Timer1 工作在模式 2 ,8位重加載,作為波特率發(fā)生器;
- AUXR = AUXR&CLR_T0X12_C; // Timer0 工作在12分頻
-
-
- TCON = 0; /* 未使用外部中斷,所以不用定義中斷的觸發(fā)方式 */
-
- TH0 = TIME1msH_C;
- TL0 = TIME1msH_C;
- TR0 = TRUE;
-
- /* 初始化中斷 */
- IE = EnT0_C; // 此處只允許 Timer0 中斷,
-
- IPH = NOIP_C; // 此處不設(shè)優(yōu)先級
- IP = NOIP_C;
-
- // ----- StepByStep之二增加的硬件初始化 070615 ------------------
-
- //初始化串口 070615
- init_SIO(B_19200);
-
- // 初始化相關(guān)中斷 070615
- IE = IE|EnUART_C; // 允許 UART 中斷
- // ----- StepByStep之三增加的硬件初始化 070618 ------------------
-
- P2M0 = P2MODE0; // 電機涉及 P2 口,初始化 P2
- P2M1 = P2MODE1;
-
- // 初始化 PCA
- CMOD = FOSCdiv12_C; // PCA 時鐘源為 Fosc/12 , 不允許 count 溢出中斷 CF。休眠時 PCA 工作
-
- CCAPM2 = EnCMP_C|EnPWM_C; // PCA 的模塊 2 用于左電機控制,8 位PWM模式;
- PCA_PWM2 = 0x03; // 初始化為PWM恒輸出 0, 以便進入惰行狀態(tài)。
- CCAP2L = 0xFF;
- CCAP2H = 0xFF;
- CCAPM3 = EnCMP_C|EnPWM_C; // PCA 的模塊 3 用于右電機控制,8 位PWM 模式;
- PCA_PWM3 = 0x03; // 初始化為PWM恒輸出 0, 以便進入惰行狀態(tài)。
- CCAP3L = 0xFF;
- CCAP3H = 0xFF;
-
- CL = 0;
- CH = 0;
- CCON = CCON|STARTPCA_C; // 啟動 PCA
- // ----- StepByStep之四增加的硬件初始化 070622 ------------------
- // 初始化 PCA0、1 用于碼盤采樣 ---- 070622
- CCAPM0 = EnCAPP_C|EnCAPN_C|EnCCFI_C; // PCA 的模塊 0 正、負跳均捕獲,允許中斷 ,右側(cè)碼盤輸入
- CCAPM1 = EnCAPP_C|EnCAPN_C|EnCCFI_C; // PCA 的模塊 1 正、負跳均捕獲,允許中斷 ,左側(cè)碼盤輸入
- // 初始化相關(guān)中斷
- IE = IE|EnPCALVD_C; // PCA 中斷
- IP = IP|PCALVD_HIGH; // PCA置為優(yōu)先級 1
- // ----- StepByStep之五增加的硬件初始化 070715 ------------------
-
- P1M0 = P1MODE0; // 采樣涉及 P1 口,初始化 P1
- P1M1 = P1MODE1;
-
- /* 初始化 AD 用于軌跡采樣 ----*/
-
- ADC_CONTR = ADPWRON_C|ADSPEED3_C;
- // ----- StepByStep之六只使用AD,不需要增加的硬件初始化 070818 ------------------
- // ------ 初始化起始變量 ----------------
- g_b1msFlag = FALSE;
- print(DISP_CONTENT); // 顯示內(nèi)容初始化
- gi_ucGetCharPtr = MAX_CHAR_NUM; // 為了啟動第一次顯示
-
- Work_Display = DARK; // 熄滅
- gi_ucGetDispNum = MAX_GAP_NUM; // 為了啟動第一次顯示
- gc_ucDispNumCnt = 1;
- gc_uiBaseTime = 1;
-
- // ----- StepByStep之二增加的變量初始化 070615 ------------------
-
- gi_ucSavePtr=0;
- gi_ucGetPtr=0;
-
- g_bNewData = FALSE;
- g_bStartRcv = FALSE;
- // ----- StepByStep之三增加的變量初始化 070618 ------------------
- ga_uiMotorCtrl[MOTOR_L] = FLOAT_PWM;
- ga_uiMotorCtrl[MOTOR_R] = FLOAT_PWM;
-
- DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]);
- DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]); // 上電時將電機置于惰行狀態(tài)
-
- // ----- StepByStep之四增加的變量初始化 070622 ------------------
-
- gac_ucWheel_Cnt[MOTOR_L] = 0;
- gac_ucWheel_Cnt[MOTOR_R] = 0;
-
- gac_uiRunCnt[MOTOR_L] = 0;
- gac_uiRunCnt[MOTOR_R] = 0;
-
- g_bStopRunStraight = TRUE;
- g_bStopRunOnLine = TRUE;
-
- // ----- StepByStep之五增加的變量初始化 070715 ------------------
-
- g_bSample = DIS_SAMPLE; // 采樣器初始化為采背景光狀態(tài),關(guān)閉發(fā)射管
-
- g_bEnSample = FALSE;
- g_bSampleStart = FALSE;
-
- for(i=0;i<4;i++)
- {
- ga_ucSampleVal[i] = 0; // 軌跡信號模擬值清“0”
- ga_ucThreshold[i] = DEFAULT_THRES[i]; // 軌跡判斷閾值初始化
- }
- g_ucThresDelta = DEFAULT_THRES_DELTA; // 軌跡判斷回差初始化
- ga_ucSampleVal[4] = 0; // 邏輯狀態(tài)清“0”
-
- // ----- StepByStep之六增加的變量初始化 070818 ------------------
-
- g_bStopHoldingGap = TRUE;
- gi_ucSaveGapValPtr = 0;
- gc_ucGetGapValCnt = 8;
- gc_ucTimeGap4GP2D12Cnt = TIME_GAP4GP2D12;
- g_bRead_GP2D12 = FALSE;
-
- // --------- 主循環(huán) ------------------------
-
- EA = TRUE; // 啟動中斷,開始正常工作
-
- while(1)
- {
- if(g_b1msFlag == TRUE)
- {
- g_b1msFlag = FALSE;
-
- // ----- 主控工作指示燈控制 ----------- 070609
- gc_uiBaseTime--; // 基本時間計時
- if(gc_uiBaseTime ==0)
- {
- gc_uiBaseTime = BASE_TIME;
-
- if(getNextGap()) // 當(dāng)前字符顯示,如果顯示完則取下一個字符
- {
- getNextChar(); // 取下一個字符
- }
- }
-
- // ------- GP2D12 采樣間隔處理 ------ 070818
- if(gc_ucTimeGap4GP2D12Cnt>0)
- {
- gc_ucTimeGap4GP2D12Cnt--;
- if(gc_ucTimeGap4GP2D12Cnt==0)
- {
- g_bRead_GP2D12 = TRUE;
- gc_ucTimeGap4GP2D12Cnt = TIME_GAP4GP2D12;
- }
- }
- }
- // ----- 小車走直線控制 ---------- 070622
- if(gac_ucWheel_Cnt[MOTOR_L]>0)
- {
- // 左側(cè)碼盤計數(shù)
- gac_uiRunCnt[MOTOR_L]++;
- gac_ucWheel_Cnt[MOTOR_L]--;
- if(g_bStopRunStraight == FALSE)
- {
- run_Straight();
- }
-
- // 行走距離控制
- if(gc_uiLeftRunCnt>0)
- {
- gc_uiLeftRunCnt--;
- if(gc_uiLeftRunCnt == 0)
- {
- if(g_bStopRunStraight == FALSE)
- {
- StopRunStraight(); // 停止直線行走
- }
-
- if(g_bStopRunOnLine == FALSE)
- {
- StopRunOnLine(); // 停止走軌跡 070715
- }
- }
- }
- }
-
- if(gac_ucWheel_Cnt[MOTOR_R]>0)
- {
- // 右側(cè)碼盤計數(shù)
- gac_uiRunCnt[MOTOR_R]++;
- gac_ucWheel_Cnt[MOTOR_R]--;
- if(g_bStopRunStraight == FALSE)
- {
- run_Straight();
- }
- }
-
- // -------- 走軌跡處理 --------- 070715
- if(g_bSampleStart)
- {
- union
- {
- unsigned int all;
- unsigned char b[2];
- }uiTemp;
-
- uiTemp.b[0] = TH0;
- uiTemp.b[1] = TL0;
- if(uiTemp.all > (TIME1ms_C + SAMP_LED_ONTIME))
- {
- g_bSampleStart = FALSE;
- ga_ucSampleVal[4] = lineSamp_proc(ga_ucSampleVal[4]); // 處理軌跡采樣
- g_bSample = DIS_SAMPLE; // 退出采樣狀態(tài),回到背景采樣
- if(g_bStopRunOnLine == FALSE)
- {
- run_Online(ga_ucSampleVal[4]); // 走軌跡處理
- }
- }
- }
- // -------- 測距處理 --------- 070818
- if(g_bRead_GP2D12)
- {
- g_bRead_GP2D12 = FALSE;
- ga_ucGapValue[gi_ucSaveGapValPtr] = read_GP2D12();
- gi_ucSaveGapValPtr = (gi_ucSaveGapValPtr+1)&0x07; //用 Mask 方式保證指針在 0 - 7 范圍中
-
- if(gc_ucGetGapValCnt >0 )
- {
- // 還未采集到 8 次數(shù)據(jù)
- gc_ucGetGapValCnt--;
- }
- else
- {
- // 采滿 8 次,計算平均值
- ga_ucGapValue[8] = cal_MeanVal(&ga_ucGapValue[0]);
- }
- }
-
- // -------- 通訊處理 --------- 070618
- if(g_bNewData)
- {
- g_bNewData = FALSE;
- if(dataFrame_OK()) // 串口收到數(shù)據(jù)后的處理,與PC程序中的函數(shù) DataFrame_OK() 相當(dāng)
- {
- do_Command(); // 執(zhí)行數(shù)據(jù)幀中的命令
- }
- }
- } // 不斷循環(huán), 在所有嵌入式應(yīng)用的主程序中,都有這樣一個無限循環(huán).
- }
- /************** 函數(shù) **************************************/
- /********************************************/
- /* 將要顯示的字符送顯示緩沖區(qū) */
- /********************************************/
- void print(unsigned char *p_ucDispConPtr)
- {
- unsigned char i;
- i = 0;
-
- while(*p_ucDispConPtr != 0)
- {
- ga_ucDispBuf[i] = *p_ucDispConPtr;
- i++;
- p_ucDispConPtr++;
- }
- ga_ucDispBuf[i] = 0; // 字符串結(jié)束符
- }
- /********************************************/
- /* 取下一個顯示間隔 */
- /* 返回為 FALSE - 表示繼續(xù)顯示此字符 */
- /* 返回為 TRUE - 表示要取下一個顯示字符 */
- /********************************************/
- bit getNextGap(void)
- {
- bit flag = FALSE;
-
- gc_ucDispNumCnt--;
- if(gc_ucDispNumCnt == 0)
- {
- gi_ucGetDispNum++;
- if(gi_ucGetDispNum >MAX_GAP_NUM)
- {
- gi_ucGetDispNum = 0; // 如果已經(jīng)超過最后界限,則準(zhǔn)備取下一個字符
- flag = TRUE;
- }
- else
- {
- if(ga_ucCharDispBuf[gi_ucGetDispNum] == 0)
- {
- gi_ucGetDispNum = 0; // 如果顯示基本時間數(shù)為“0”,則準(zhǔn)備取下一個字符
- flag = TRUE;
- }
- else
- {
- gc_ucDispNumCnt = ga_ucCharDispBuf[gi_ucGetDispNum];
- if(gi_ucGetDispNum&0x01)
- {
- Work_Display = DARK; // gucGetDispNum 奇數(shù)位置:暗
- }
- else
- {
- Work_Display = LIGHT; // gucGetDispNum 偶數(shù)位置:亮
- }
- flag = FALSE;
- }
- }
- }
-
- return(flag);
- }
- /********************************************/
- /* 取下一個顯示字符 */
- /********************************************/
- void getNextChar(void)
- {
- unsigned char ucCharOrder,i;
-
- gi_ucGetCharPtr++;
- if((gi_ucGetCharPtr > MAX_CHAR_NUM)||(ga_ucDispBuf[gi_ucGetCharPtr]==0))
- {
- gi_ucGetCharPtr = 0; // 已取字符到結(jié)尾,回到頭。
- }
-
- ucCharOrder = ga_ucDispBuf[gi_ucGetCharPtr] - 0x41; // 將大寫字母ASCII嗎轉(zhuǎn)換為字母順序,暫時只支持大寫字母
- for(i=0;i<MAX_GAP_NUM;i++)
- {
- ga_ucCharDispBuf[i] = ga_ucMorseCode[ucCharOrder][i]; // 取出該字符對應(yīng)的亮、暗序列
- }
-
- Work_Display = LIGHT; // 每個字符都是從“亮”開始
- gi_ucGetDispNum = 0;
- gc_ucDispNumCnt = ga_ucCharDispBuf[gi_ucGetDispNum];
- }
- /********************************************/
- /* 定時器 0 中斷服務(wù) */
- /* 說明: 1ms 中斷一次, */
- /********************************************/
- void Timer0_Int(void) interrupt 1 using 1
- {
-
- TH0 = TIME1msH_C;
- TL0 = TIME1msL_C;
-
- g_b1msFlag = TRUE;
- // ------- 以下為StepByStep之五增加的處理 070715 ------------------
-
- g_bEnSample = ~g_bEnSample;
- if(g_bEnSample)
- {
- g_bSample = EN_SAMPLE; // 打開采樣LED
- g_bSampleStart = TRUE;
- }
- }
- // -------- 以下為StepByStep之二增加的函數(shù) 070615 ------------------
- /********************************************/
- /* 名稱:init_SIO */
- /* 用途:初始化串口, */
- /* 參數(shù): 波特率 , 模式固定為:1 */
- /* 1 START 8 DATA 1 STOP */
- /********************************************/
- void init_SIO(unsigned char baud)
- {
- // 波特率表
- unsigned char code TH_Baud[5]={B4800_C,B9600_C,B19200_C,B38400_C,B57600_C};
-
- AUXR = AUXR|SET_T1X12_C;
- TH1 = TH_Baud[baud];
- TL1 = TH_Baud[baud];
- TR1 = TRUE;
-
- SCON = UART_MODE1_C|EN_RCV_C; // 8 位模式( MODE 1)
- }
-
- /********************************************/
- /* 串口中斷服務(wù) */
- /* 說明: 將收到的數(shù)據(jù)保存到接收緩沖區(qū) */
- /********************************************/
- void SioInt(void) interrupt 4 using 1
- {
- if(RI==TRUE)
- {
- RI=FALSE;
- ga_ucRcvBuf[gi_ucSavePtr]=SBUF; // 將數(shù)據(jù)填入緩沖區(qū)
- gi_ucSavePtr=(gi_ucSavePtr+1)&(MaxRcvByte_C-1); // 利用屏蔽高位的方式實現(xiàn)指針的環(huán)形處理
- g_bNewData = TRUE;
- }
-
- if(TI == TRUE)
- {
- TI = FALSE; // 處理發(fā)送
- gc_ucTxdCnt--; // 發(fā)送計數(shù)
- if(gc_ucTxdCnt>0)
- {
- gi_ucTxdPtr++;
- SBUF = ga_ucTxdBuf[gi_ucTxdPtr]; // 取下一字節(jié)
- }
- }
- }
- /********************************************/
- /*名稱: dataFrame_OK */
- /*用途: 檢測接收緩沖區(qū)數(shù)據(jù), */
- /*說明: 如果收到正確的數(shù)據(jù)幀則返回真 */
- /********************************************/
- bit dataFrame_OK(void)
- {
- unsigned char i,j,k;
- bit flag;
-
- flag = FALSE;
-
- while(gi_ucGetPtr != gi_ucSavePtr)
- {
- if(g_bStartRcv == FALSE)
- {
- /* 檢測幀頭 0x55 0xAA LEN */
- k = 0;
-
- i = (gi_ucGetPtr - 5)&(MaxRcvByte_C-1);
- if(ga_ucRcvBuf[i]==0x55)
- {
- k++;
- }
-
- i = (gi_ucGetPtr - 4)&(MaxRcvByte_C-1);
- if(ga_ucRcvBuf[i]==0xAA)
- {
- k++;
- }
-
- i = (gi_ucGetPtr - 3)&(MaxRcvByte_C-1);
- if(ga_ucRcvBuf[i]==MY_ADDR)
- {
- k++;
- }
-
- if(k == 3)
- {
- //幀頭正確,啟動數(shù)據(jù)區(qū)接收
- g_bStartRcv=TRUE;
- i=(gi_ucGetPtr-1)&(MaxRcvByte_C-1);
- gc_ucDataLen = ga_ucRcvBuf[i];
- gi_ucStartPtr = gi_ucGetPtr;
- gi_ucEndPtr= (gi_ucGetPtr + gc_ucDataLen)&(MaxRcvByte_C-1);
- }
- }
- else
- {
- //開始接收數(shù)據(jù)處理
- if(gi_ucGetPtr==gi_ucEndPtr)
- {
- /* 數(shù)據(jù)幀接收完 */
- g_bStartRcv=FALSE;
-
- j=gi_ucStartPtr;
- k= 0;
- for(i=0;i<gc_ucDataLen;i++)
- {
- // 計算CS
- k +=ga_ucRcvBuf[j];
- j=(j+1)&(MaxRcvByte_C-1);
- }
-
- // 取校驗和
- k = ~k;
- if(k==ga_ucRcvBuf[j])
- {
- flag = TRUE; // 數(shù)據(jù)校驗正確
- }
- }
- }
- gi_ucGetPtr=(gi_ucGetPtr+1)&(MaxRcvByte_C-1);
- }
- return (flag);
- }
- /********************************************/
- /*名稱: do_Command */
- /*用途: 根據(jù)收到的數(shù)據(jù)幀命令做相應(yīng)處理 */
- /********************************************/
- /*
- 地址與硬件的對應(yīng)關(guān)系:
- 0x0000 — 0x00FF —— 對應(yīng)STC12LE5412的256字節(jié)內(nèi)部RAM(idata);
- 0x0100 — 0x01FF —— 對應(yīng)STC12LE5412的256字節(jié)外部RAM(xdata);
- 0x0200 — 0x7F7F —— 保留,為大RAM的單片機預(yù)留;
- 0x7F80 — 0x7FFF —— 對應(yīng)STC12LE5412的128字節(jié)SFR;
- 0x8000 — 0xAFFF —— 對應(yīng)STC12LE5412的12K FlashROM;
- 0xB000 — 0xFFFF —— 保留,為大ROM的單片機預(yù)留;
- */
- // 增加電機PWM控制命令處理, 070618
- void do_Command(void)
- {
- unsigned char ucCommand,i,j,sum,n;
-
- union
- {
- unsigned int all;
- unsigned char b[2];
- }uitemp;
-
- unsigned char idata *ucI_Ptr;
- unsigned char xdata *ucX_Ptr;
- unsigned char code *ucC_Ptr;
- ucCommand = ga_ucRcvBuf[gi_ucStartPtr]; // 取出數(shù)據(jù)幀中的命令
-
- switch (ucCommand)
- {
- case READ_MEMORY:
- {
- // 讀內(nèi)存數(shù)據(jù)處理
- i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);
- uitemp.b[1] = ga_ucRcvBuf[i]; // 取讀數(shù)據(jù)地址, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[0] = ga_ucRcvBuf[i];
- i =(i+1)&(MaxRcvByte_C-1);
- n = ga_ucRcvBuf[i]; // 取讀數(shù)據(jù)長度
- if(n>(MaxTxdByte_C - 10))
- {
- n = (MaxTxdByte_C - 10); // 受發(fā)送緩沖區(qū)限制,減 10 個字節(jié)對應(yīng):
- // 幀頭2 設(shè)備地址2 長度1 命令1 數(shù)據(jù)地址2 字節(jié)數(shù)1 .... 校驗和1
- }
-
- ga_ucTxdBuf[0] = 0x55;
- ga_ucTxdBuf[1] = 0xAA; // 幀頭
- i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1); // 取發(fā)送方地址
- ga_ucTxdBuf[2] = ga_ucRcvBuf[i]; // 作為接收方地址發(fā)送
- ga_ucTxdBuf[3] = MY_ADDR; // 自己的地址作為發(fā)送方送出
- ga_ucTxdBuf[4] = n + 4; // 幀長
- ga_ucTxdBuf[5] = READ_MEMORY; // 返回命令
- ga_ucTxdBuf[6] = uitemp.b[1]; // 將要讀數(shù)據(jù)的地址和長度返回
- ga_ucTxdBuf[7] = uitemp.b[0];
- ga_ucTxdBuf[8] = n;
- sum = ga_ucTxdBuf[5]+ga_ucTxdBuf[6]+ga_ucTxdBuf[7]+ga_ucTxdBuf[8];
- i = 9; // 數(shù)據(jù)區(qū)起始指針
-
- if(uitemp.b[0] == 0x00)
- {
- // 如果高地址為 0 ,則讀IDATA內(nèi)容
- ucI_Ptr = uitemp.b[1];
- for(j=0;j<n;j++)
- {
- ga_ucTxdBuf[i] = *ucI_Ptr;
- sum += ga_ucTxdBuf[i];
- i++;
- ucI_Ptr++;
- }
- }
- if(uitemp.b[0] == 0x01)
- {
- // 如果高地址為“0x01”,則讀XDATA內(nèi)容
- ucX_Ptr = uitemp.b[1]; // 因為只有256字節(jié)的XDATA,所以只取低字節(jié)。
- for(j=0;j<n;j++)
- {
- ga_ucTxdBuf[i] = *ucX_Ptr;
- sum += ga_ucTxdBuf[i];
- i++;
- ucX_Ptr++;
- }
- }
- // 讀 SFR 暫不支持,讀者可以思考一下如何添加?
-
- if(uitemp.b[0] >= 0x80)
- {
- // 如果高地址大于“0x80”,則讀code(程序區(qū))內(nèi)容
- ucC_Ptr = uitemp.all - 0x8000;
- for(j=0;j<n;j++)
- {
- ga_ucTxdBuf[i] = *ucC_Ptr; // 注意,此功能將使你的程序泄密 :P
- sum += ga_ucTxdBuf[i];
- i++;
- ucC_Ptr++;
- }
- }
-
- ga_ucTxdBuf[i] = ~sum; // 校驗和
-
- gc_ucTxdCnt = i+1; // 發(fā)送字節(jié)計數(shù)
- gi_ucTxdPtr = 0; // 發(fā)送指針
- SBUF = ga_ucTxdBuf[0]; // 啟動發(fā)送
-
- break;
- }
-
- case WRITE_MEMORY:
- {
- // 寫內(nèi)存數(shù)據(jù)處理
- i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);
- uitemp.b[1] = ga_ucRcvBuf[i]; // 取讀數(shù)據(jù)地址
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[0] = ga_ucRcvBuf[i];
- i =(i+1)&(MaxRcvByte_C-1);
- n = ga_ucRcvBuf[i]; // 取讀數(shù)據(jù)長度
- i =(i+1)&(MaxRcvByte_C-1); // 數(shù)據(jù)區(qū)起始指針
-
- j = 0; // 返回實際寫的字節(jié)數(shù)
-
- if(uitemp.b[0] == 0x00)
- {
- // 如果高地址為 0 ,則寫IDATA內(nèi)容
- ucI_Ptr = uitemp.b[1];
- for(j=0;j<n;j++)
- {
- *ucI_Ptr = ga_ucRcvBuf[i]; // 注意,此功能會導(dǎo)致程序崩潰 :(
- i = (i+1)&(MaxRcvByte_C-1);
- ucI_Ptr++;
- }
- }
- if(uitemp.b[0] == 0x01)
- {
- // 如果高地址為“0x01”,則寫XDATA內(nèi)容
- ucX_Ptr = uitemp.b[1]; // 因為只有256字節(jié)的XDATA,所以只取低字節(jié)。
- for(j=0;j<n;j++)
- {
- *ucX_Ptr = ga_ucRcvBuf[i];
- i = (i+1)&(MaxRcvByte_C-1);
- ucX_Ptr++;
- }
- }
- // 寫 SFR和程序區(qū)暫不支持,讀者可自己添加,看看有什么難度 :D
-
- ga_ucTxdBuf[0] = 0x55;
- ga_ucTxdBuf[1] = 0xAA; // 幀頭
- i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1); // 取發(fā)送方地址
- ga_ucTxdBuf[2] = ga_ucRcvBuf[i]; // 作為接收方地址發(fā)送
- ga_ucTxdBuf[3] = MY_ADDR; // 自己的地址作為發(fā)送方送出
- ga_ucTxdBuf[4] = 4; // 幀長
- ga_ucTxdBuf[5] = WRITE_MEMORY; // 返回命令
- ga_ucTxdBuf[6] = uitemp.b[1]; // 將要讀數(shù)據(jù)的地址和長度返回
- ga_ucTxdBuf[7] = uitemp.b[0];
- ga_ucTxdBuf[8] = j; // 返回寫成功的字節(jié)數(shù)
- sum = ga_ucTxdBuf[5]+ga_ucTxdBuf[6]+ga_ucTxdBuf[7]+ga_ucTxdBuf[8];
-
- ga_ucTxdBuf[9] = ~sum; // 校驗和
-
- gc_ucTxdCnt = 10; // 發(fā)送字節(jié)計數(shù)
- gi_ucTxdPtr = 0; // 發(fā)送指針
- SBUF = ga_ucTxdBuf[0]; // 啟動發(fā)送
-
- break;
- }
-
- case MOTOR_PWM_CTRL:
- {
- // 電機PWM控制 StepbyStep之三增加 070618
- i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);
- uitemp.b[1] = ga_ucRcvBuf[i]; // 取左側(cè)電機數(shù)據(jù), 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[0] = ga_ucRcvBuf[i];
- ga_uiMotorCtrl[MOTOR_L] = uitemp.all;
-
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[1] = ga_ucRcvBuf[i]; // 取右側(cè)電機數(shù)據(jù), 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[0] = ga_ucRcvBuf[i];
- ga_uiMotorCtrl[MOTOR_R] = uitemp.all;
- j = DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]); // 輸出電機控制
- j = DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]);
-
- ga_ucTxdBuf[0] = 0x55;
- ga_ucTxdBuf[1] = 0xAA; // 幀頭
- i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1); // 取發(fā)送方地址
- ga_ucTxdBuf[2] = ga_ucRcvBuf[i]; // 作為接收方地址發(fā)送
- ga_ucTxdBuf[3] = MY_ADDR; // 自己的地址作為發(fā)送方送出
- ga_ucTxdBuf[4] = 2; // 幀長
- ga_ucTxdBuf[5] = MOTOR_PWM_CTRL; // 返回命令
- ga_ucTxdBuf[6] = j; // 返回 P2 控制字
-
- sum = ga_ucTxdBuf[5]+ga_ucTxdBuf[6];
-
- ga_ucTxdBuf[7] = ~sum; // 校驗和
-
- gc_ucTxdCnt = 8; // 發(fā)送字節(jié)計數(shù)
- gi_ucTxdPtr = 0; // 發(fā)送指針
- SBUF = ga_ucTxdBuf[0]; // 啟動發(fā)送
-
- break;
- }
-
- case RUN_STRAIGHT:
- {
- // 啟動走直線 StepbyStep之四增加 070622
-
- i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);
- uitemp.b[1] = ga_ucRcvBuf[i]; // 取左輪行走設(shè)定值, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[0] = ga_ucRcvBuf[i];
- g_uiLeftRunNum = uitemp.all;
- gc_uiLeftRunCnt = g_uiLeftRunNum; // 啟動行走距離控制
-
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[1] = ga_ucRcvBuf[i]; // 取基準(zhǔn)PWM值, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[0] = ga_ucRcvBuf[i];
- g_uiBase_PWM = uitemp.all;
-
- ga_uiMotorCtrl[MOTOR_L] = g_uiBase_PWM; // 保存電機控制 PWM 值
- ga_uiMotorCtrl[MOTOR_R] = g_uiBase_PWM;
- gac_uiRunCnt[MOTOR_L] = 0; // 啟動時清除行走計數(shù)值
- gac_uiRunCnt[MOTOR_R] = 0;
- if(g_uiBase_PWM == BRAKE_PWM)
- {
- g_bStopRunStraight = TRUE;
- }
- else
- {
- g_bStopRunStraight = FALSE; // 啟動
- }
-
- DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]); // 輸出電機控制
- DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]);
-
-
- ga_ucTxdBuf[0] = 0x55;
- ga_ucTxdBuf[1] = 0xAA; // 幀頭
- i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1); // 取發(fā)送方地址
- ga_ucTxdBuf[2] = ga_ucRcvBuf[i]; // 作為接收方地址發(fā)送
- ga_ucTxdBuf[3] = MY_ADDR; // 自己的地址作為發(fā)送方送出
- ga_ucTxdBuf[4] = 1; // 幀長
- ga_ucTxdBuf[5] = RUN_STRAIGHT; // 返回命令
-
- sum = ga_ucTxdBuf[5];
-
- ga_ucTxdBuf[6] = ~sum; // 校驗和
-
- gc_ucTxdCnt = 7; // 發(fā)送字節(jié)計數(shù)
- gi_ucTxdPtr = 0; // 發(fā)送指針
- SBUF = ga_ucTxdBuf[0]; // 啟動發(fā)送
-
- break;
- }
- case RUN_ON_LINE:
- {
- // 啟動走軌跡 StepbyStep之五增加 070715
-
- i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);
- uitemp.b[1] = ga_ucRcvBuf[i]; // 取左輪行走設(shè)定值, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[0] = ga_ucRcvBuf[i];
- g_uiLeftRunNum = uitemp.all;
- gc_uiLeftRunCnt = g_uiLeftRunNum; // 啟動行走距離控制
-
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[1] = ga_ucRcvBuf[i]; // 取基準(zhǔn)PWM值, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
- i =(i+1)&(MaxRcvByte_C-1);
- uitemp.b[0] = ga_ucRcvBuf[i];
- g_uiBase_PWM = uitemp.all;
-
- ga_uiMotorCtrl[MOTOR_L] = g_uiBase_PWM; // 保存電機控制 PWM 值
- ga_uiMotorCtrl[MOTOR_R] = g_uiBase_PWM;
- gac_uiRunCnt[MOTOR_L] = 0; // 啟動時清除行走計數(shù)值
- gac_uiRunCnt[MOTOR_R] = 0;
- if(g_uiBase_PWM == BRAKE_PWM)
- {
- g_bStopRunOnLine = TRUE;
- }
- else
- {
- g_bStopRunOnLine = FALSE; // 啟動
- g_ucRotateStat = STRAIGHT; // 初始狀態(tài)為直行
- }
-
- DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]); // 輸出電機控制
- DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]);
-
-
- ga_ucTxdBuf[0] = 0x55;
- ga_ucTxdBuf[1] = 0xAA; // 幀頭
- i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1); // 取發(fā)送方地址
- ga_ucTxdBuf[2] = ga_ucRcvBuf[i]; // 作為接收方地址發(fā)送
- ga_ucTxdBuf[3] = MY_ADDR; // 自己的地址作為發(fā)送方送出
- ga_ucTxdBuf[4] = 1; // 幀長
- ga_ucTxdBuf[5] = RUN_ON_LINE; // 返回命令
-
- sum = ga_ucTxdBuf[5];
-
- ga_ucTxdBuf[6] = ~sum; // 校驗和
-
- gc_ucTxdCnt = 7; // 發(fā)送字節(jié)計數(shù)
- gi_ucTxdPtr = 0; // 發(fā)送指針
- SBUF = ga_ucTxdBuf[0]; // 啟動發(fā)送
-
- break;
- }
-
- default: break;
- }
- }
- // -------- 以下為StepByStep之三增加的函數(shù) 070618 ------------------
- /********************************************/
- /*名稱: DriveMotor */
- /*用途: 根據(jù)得到的參數(shù)計算電機控制輸出值, */
- /********************************************/
- //輸入 No —— 電機序號, iPWM_Val —— 電機控制值
- // 返回電機控制信號
- unsigned char DriveMotor(unsigned char No,unsigned int uiPWM_Val)
- {
- unsigned char ucCtrl_Out,ucCtrl_Buf,ucPCA_CCAP,ucPCA_MODE;
- union
- {
- unsigned int all;
- unsigned char b[2];
- }uiPWM_Buf;
-
- uiPWM_Buf.all = uiPWM_Val;
- ucCtrl_Out = MotorDrv; // 讀回電機控制輸出,注意,此操作會影響P2.3和P2.7口的狀態(tài)!!!
-
- switch(uiPWM_Buf.b[1])
- {
- case FLOAT_PWM:
- {
- // 惰行命令
- ucCtrl_Buf = ga_ucFloat[No];
- ucPCA_MODE = 0x03; // PWM恒輸出 0,
- ucPCA_CCAP = 0xFF;
- break;
- }
-
- case BRAKE_PWM:
- {
- // 剎車命令
- ucCtrl_Buf = ga_ucBrake[No];
- ucPCA_MODE = 0x03; // PWM恒輸出 0,
- ucPCA_CCAP = 0xFF;
- break;
- }
-
- default:
- {
- // 調(diào)功處理
- if(uiPWM_Buf.b[0] == 0)
- {
- // 前進
- ucCtrl_Buf = ga_ucForward[No];
- }
- else
- {
- // 后退控制
- ucCtrl_Buf = ga_ucBack[No];
- }
-
- ucPCA_MODE = 0x00;
- ucPCA_CCAP = 255 - uiPWM_Buf.b[1]; // PWM值, 注意:需要用 255 減,否則值越大功率越小! 070622
-
- break;
- }
- }
-
- ucCtrl_Out = (ucCtrl_Out&ga_ucMask[No])|ucCtrl_Buf;
- MotorDrv = ucCtrl_Out; // 輸出控制信號, 如果使用P2.3和P2.7 則要特殊處理
-
- if(No == MOTOR_L)
- {
- PCA_PWM2 = ucPCA_MODE;
- CCAP2L = ucPCA_CCAP;
- CCAP2H = ucPCA_CCAP;
- }
- else
- {
- PCA_PWM3 = ucPCA_MODE;
- CCAP3L = ucPCA_CCAP;
- CCAP3H = ucPCA_CCAP;
- }
-
- return (ucCtrl_Out); // 將電機控制信號返回
- }
- // -------- 以下為StepByStep之四增加的函數(shù) 070622 ------------------
- /********************************************/
- /* PCA 中斷服務(wù) */
- /* 說明: CCF0、1 用于碼盤輸入 */
- /* CCF2、3 用于電機控制 */
- /********************************************/
- void PCA_Int(void) interrupt 6 using 2
- {
- if(CF == TRUE)
- {
- CF = FALSE; // 出錯保護
- }
-
- if(CCF0 == TRUE)
- {
- // 右側(cè)碼盤信號輸入
- CCF0 = FALSE;
- gac_ucWheel_Cnt[MOTOR_R]++; // 每來一個脈沖 +1
- }
-
- if(CCF1 == TRUE)
- {
- // 左側(cè)碼盤信號輸入
- CCF1 = FALSE;
- gac_ucWheel_Cnt[MOTOR_L]++; // 每來一個脈沖 +1
- }
-
- if(CCF2 == TRUE)
- {
- CCF2 = FALSE; // 出錯保護
- }
-
- if(CCF3 == TRUE)
- {
- CCF3 = FALSE; // 出錯保護
- }
- }
- /********************************************/
- /*名稱: run_Straight */
- /*用途: 根據(jù)車輪行走計數(shù)修正電機輸出值, */
- /********************************************/
- /*
- 涉及如下全局變量:
- gac_uiRunCnt[2] —— 兩輪的行走計數(shù)值
- ga_uiMotorCtrl[MOTOR_R] —— 右側(cè)電機的PWM控制值
- */
- void run_Straight(void)
- {
- bit flag;
-
- flag = FALSE;
-
- if(gac_uiRunCnt[MOTOR_R]!= gac_uiRunCnt[MOTOR_L])
- {
- if(gac_uiRunCnt[MOTOR_R]> gac_uiRunCnt[MOTOR_L])
- {
- // 右輪快,右輪置為惰行
- ga_uiMotorCtrl[MOTOR_R] = FLOAT_PWM;
- }
- else
- {
- // 左輪快,左輪置為惰行
- ga_uiMotorCtrl[MOTOR_L] = FLOAT_PWM;
- }
-
- flag =TRUE;
- }
- else
- {
- if(ga_uiMotorCtrl[MOTOR_L] == FLOAT_PWM)
- {
- ga_uiMotorCtrl[MOTOR_L] = g_uiBase_PWM;
- flag = TRUE;
- }
-
- if(ga_uiMotorCtrl[MOTOR_R] == FLOAT_PWM)
- {
- ga_uiMotorCtrl[MOTOR_R] = g_uiBase_PWM;
- flag = TRUE;
- }
- }
-
- if(flag == TRUE)
- {
- DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]); // 輸出電機控制
- DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]);
- }
- }
- /********************************************/
- /*名稱: StopRunStraight */
- /*用途: 停止直線行走狀態(tài) */
- /********************************************/
- void StopRunStraight(void)
- {
- g_bStopRunStraight = TRUE; // 停止走直線控制
-
- DriveMotor(MOTOR_R,BRAKE_PWM); // 輸出電機控制
- DriveMotor(MOTOR_L,BRAKE_PWM);
- }
- // -------- 以下為StepByStep之五增加的函數(shù) 070715 ------------------
- /********************************************/
- /* 名稱:lineSamp_proc */
- /* 用途:采樣并處理 */
- /********************************************/
- /* 采樣器對應(yīng)關(guān)系:
- 頂視: 左 —— 右
- 采樣器 1 2 3 4
- PORT P1. 3 2 1 0
- SampleVal 1 2 3 4
- SensorStat b0 b1 b2 b3
- OldSenStat b0 b1 b2 b3
- */
- unsigned char lineSamp_proc(unsigned char ucOldSenStat)
- {
- unsigned char i,temp;
-
- // 啟動 AD 并讀數(shù), 大約占用 56 us, 對應(yīng) 22.1184MHz
- for(i = 0; i <4; i++)
- {
- // 循環(huán)采樣
- ADC_CONTR = ADPWRON_C|ADSPEED3_C|STARTAD_C|i; // 啟動 AD
-
- temp = ADC_CONTR & GETADFLAG_C; // 讀轉(zhuǎn)換結(jié)束標(biāo)志
- while(temp==0)
- {
- temp = ADC_CONTR & GETADFLAG_C; // 讀轉(zhuǎn)換結(jié)束標(biāo)志
- }
- ga_ucSampleVal[3-i] = ADC_DATA; // 獲取AD值, 暫時取 8 位值, 此處將順序反過來。!
-
- ADC_CONTR = ADC_CONTR & CLRADFLAG_C;
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復(fù)制代碼
0.png (43.91 KB, 下載次數(shù): 79)
下載附件
2018-7-22 15:59 上傳
全部資料51hei下載地址:
基于單片機的智能避障小車(程序 論文).rar
(910.43 KB, 下載次數(shù): 61)
2018-7-22 11:57 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|
評分
-
查看全部評分
|