久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

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

單片機+GP2D12紅外測距傳感器的智能避障小車教程與源碼

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:377068 發(fā)表于 2018-7-22 11:57 | 只看該作者 |只看大圖 回帖獎勵 |倒序瀏覽 |閱讀模式
包含了智能避障小車的程序和論文
圓夢小車  Step by Step  之六
——  讓小車“看到”障礙物

前一篇講述了如何在“路”上行走,本篇讓小車學(xué)會“看到”避障物! 機器視覺中最接近人眼的莫過于攝像頭了,可圖像處理小車的“大腦”對付不了,至少目前的“大腦”能力不夠,等進化后也許能夠應(yīng)付。 為了能“看到”障礙物,小車目前能用的主要是各類測距傳感器,典型的有超聲波和紅外兩種,此外還有利用光線的反射強弱來判斷的,這種方式不具備“測距”功能,但可以判斷有無!因為不同物體表面及顏色反射的能力不同(看后面的數(shù)據(jù)) 。 本文主要討論的是機器人中最常用的紅外測距傳感器  ——  GP2D12。

機器人配件供應(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ā)射管確定,此時便可通過底邊推算出高,也就是我們所要的距離。如下圖所示:


從圖中可以看出,這是一個頂角極銳的等腰三角形,底邊只有  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ù)留位置即可方便使用。


此時,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 制作的電子表,表格的格式如下:


里面有作者根據(jù) GP2D12 特性建立的數(shù)學(xué)模型(線性化公式) ,并預(yù)留的使用者輸入?yún)?shù)的地方,只需按其要求填入:
AD 的位數(shù)、AD 供電電壓(滿量程) ,并采集 8 點(10cm 間隔)GP2D12  的輸出電壓,填入表中,它就可自動生成線性化公式的參數(shù),提供了整形和浮點兩種格式,還附有由此產(chǎn)生的結(jié)果與實際的偏差表,并用生動的圖形表示,十分直觀、實用。



第一列為實際距離,第二列障礙物表面為白紙,第三列障礙物為褐色木盒,讀者可比照Excel 表中的數(shù)據(jù),可以看出基本吻合。同時還可以從上面數(shù)據(jù)中看出,GP2D12  確實如其手冊中所說,基本不受障礙物的顏色影響。

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 界面: (余下見附件)


單片機程序源碼:
  1. /*******************************************************/
  2. /*                                        圓夢小車StepbyStep 程序之6                                                                 */       
  3. /*                                                                —— 教小車“看到”障礙物                                                                 */
  4. /*******************************************************/
  5. // 注:以下文檔的 TAB 為 2 個字符!

  6. /*-----------------------------------------------------
  7.         這段程序是以StepByStep之五的程序YM1_Prog-5A.C
  8.         為基礎(chǔ),增加測距功能,使小車能夠“看到”障礙物,
  9.         并據(jù)此躲避之。
  10.        
  11.         -------------StepByStep之一 070609 ---------------
  12.         因為程序簡單,故所有內(nèi)容合并在一個文件中。
  13.         硬件資源分配:
  14.         Timer0 仍然作為 1ms 定時器,作為工作的時基;
  15.         Timer1 作為UART的波特率發(fā)生器。
  16.        
  17.         ------------StepByStep之二 070615 ----------------------
  18.         通訊協(xié)議:
  19.         字節(jié)格式  ——  19200  8  N  1
  20.         數(shù)據(jù)幀格式:
  21.         幀頭(2字節(jié)) 接收方地址(1字節(jié)) 發(fā)送方地址(1字節(jié)) 幀長(1字節(jié)) 命令(1字節(jié)) 數(shù)據(jù)域(N字節(jié)) 校驗和(1字節(jié))
  22.        
  23.         幀頭 —— 由2個特殊的字節(jié) 0x55 0xAA構(gòu)成;
  24.         接收方地址 —— 通訊對象的“名字”,在有線通訊時也許多余,但無線時就需要了。
  25.         發(fā)送方地址 —— 告訴接收方,是誰和你“說話”,便于接收方回答。
  26.         幀長 —— 從命令開始到數(shù)據(jù)域結(jié)束的字節(jié)數(shù)
  27.         校驗和 —— 數(shù)據(jù)幀中從命令開始到數(shù)據(jù)域結(jié)束所有字節(jié)的算術(shù)和,取最低字節(jié)的反碼。

  28.         ------------StepByStep之三 070618 -------------
  29.         電機驅(qū)動所用資源:
  30.         PCA2 —— 產(chǎn)生左側(cè)電機的PWM信號
  31.         PCA3 —— 產(chǎn)生右側(cè)電機的PWM信號
  32.         PWM 時鐘源 —— Fosc/12
  33.         PWM頻率 —— 7200
  34.         因為PWM為 8 位的,將有效 PWM 值定為  1 - 250,0 作為剎車控制, 255 作為惰行控制
  35.        
  36.         P2.0 —— 左側(cè)電機PWM控制
  37.         P2.1、P2.2  ——左側(cè)電機工作狀態(tài)控制
  38.        
  39.         P2.4 —— 右側(cè)電機PWM控制
  40.         P2.5、P2.6  ——右側(cè)電機工作狀態(tài)控制
  41.        
  42.         將P2口設(shè)置為強輸出模式。
  43.          
  44.         補充定義命令:電機PWM控制命令
  45.         命令字 —— 0x03
  46.         數(shù)據(jù)域 —— 左電機PWM值(2字節(jié),先低后高) 右電機PWM值
  47.         返回數(shù)據(jù)幀:
  48.         幀頭 發(fā)送方地址 自己的地址  幀長 命令 電機控制輸出(P2) 校驗和

  49.         -------------StepByStep之四 070622 -----------------------
  50.         碼盤監(jiān)測所用資源:
  51.         PCA0 —— 右側(cè)電機碼盤信號輸入
  52.         PCA1 —— 左側(cè)電機碼盤信號輸入
  53.        
  54.         將PCA0、PCA1 設(shè)置為正、負沿脈沖捕獲模式,允許中斷。
  55.        
  56.         走直線控制邏輯:
  57.         1、初級:
  58.         如果右側(cè)快,則將右側(cè)置為惰行
  59.         如果左側(cè)快,則將左側(cè)置為惰行
  60.         如果相等,則均置為啟動的PWM值
  61.        
  62.         補充定義命令: 走直線
  63.         命令字 —— 0x04
  64.         數(shù)據(jù)域 —— 行走距離(2字節(jié))PWM 基準(zhǔn)值(2字節(jié),先低后高)
  65.         其中行走距離為左側(cè)車輪的脈沖計數(shù)值,按目前的幾何尺寸,最大值65535 應(yīng)該可以走 655圈,約合86m,為“0" 時連續(xù)行走。
  66.        
  67.         返回數(shù)據(jù)幀:
  68.         幀頭 發(fā)送方地址 自己的地址  幀長 命令 校驗和

  69.         ---------------StepByStep之五 070715 -----------------------
  70.         軌跡檢測所用資源:
  71.         P1.0 - P1.3 ——  4路軌跡信號輸入,模擬方式輸入,使用前  4 通道A/D
  72.         P3.3(INT1) —— 控制背景采樣和信號采樣,推挽輸出
  73.         注意,P3 口的狀態(tài)寄存器作了修改,請參照原理圖理解!!
  74.        
  75.         采樣器對應(yīng)關(guān)系:
  76.          頂視:                          左  ——  右
  77.          采樣器                          1  2  3  4
  78.          PORT P1.                        3  2  1  0

  79.         因為小車速度不快,通常小于 0.5m/s,所以將采樣設(shè)計為 2 ms 一次,對應(yīng)移動只有1mm,
  80.         安排在中斷外執(zhí)行。

  81.         具體處理步驟為:
  82.         設(shè)計一個采樣標(biāo)志位,每1ms中斷取反一次,為真時處理;
  83.         在中斷時,如果標(biāo)志為真,則打開采樣LED;
  84.         在主程序中檢測Timer0,如果打開LED時間超過一定值,則啟動AD,
  85.         完成后關(guān)閉采樣LED,結(jié)束一個采樣周期。

  86.         采樣處理將軌跡信號轉(zhuǎn)換為邏輯值,存放在一個狀態(tài)字中,每位對應(yīng)一個傳感器,0 —— 不在軌跡,1 —— 在軌跡,
  87.         默認軌跡為深色(黑色)。
  88.        
  89.         之后再根據(jù)這個狀態(tài)字控制小車行走,因為是示例,所以只處理中間兩個軌跡傳感器的狀態(tài),兩側(cè)的留給讀者去發(fā)揮!
  90.        
  91.         控制邏輯:
  92.          只處理 2、3號傳感器,即位 b1、b2,
  93.          兩個均在軌跡上,左右電機為同樣值,
  94.          b1 不在,右側(cè)電機惰行,
  95.          b2 不在,左側(cè)電機惰行。
  96.          和走直線類似,只是控制變量從碼盤計數(shù)差變?yōu)檐壽E采樣的狀態(tài)。

  97.         補充定義命令: 走軌跡
  98.         命令字 —— 0x05
  99.         數(shù)據(jù)域 —— 行走距離(2字節(jié))PWM 基準(zhǔn)值(2字節(jié),先低后高)
  100.         其中行走距離為左側(cè)車輪的脈沖計數(shù)值,按目前的幾何尺寸,最大值65535 應(yīng)該可以走 655圈,約合86m,為“0" 時連續(xù)行走。
  101.        
  102.         返回數(shù)據(jù)幀:
  103.         幀頭 發(fā)送方地址 自己的地址  幀長 命令 校驗和


  104.         ----------------StepByStep之六 070818 -----------------------
  105.        
  106.         首先,做一個GP2D12 的應(yīng)用程序,實現(xiàn):
  107.         1、讀會 GP2D12 的模擬輸出信號;
  108.         2、濾波并線性化,因 GP2D12 的輸出與距離的關(guān)系是非線性的;
  109.         3、結(jié)合前面的走直線功能,讓小車自動保持與一個物體間的距離。
  110.        
  111.         按照擴展PCB上預(yù)留的 GP2D12 接口,模擬信號輸入到 STC12LE5412AD的 P1.4 端, 對應(yīng)A/D的第4通道。
  112.         因為 GP2D12 的輸出有噪音,且為階梯輸出(不連續(xù)測量),擬采用滑動濾波,按照手冊,GP2D12 約 40 ms測量一次。
  113.         采用 8 組數(shù)據(jù)的平均值作為結(jié)果,即5ms采樣一次。
  114.         同時為提高精度, A/D使用 10 位(在上篇軌跡采樣中用的是 8 位)。
  115.        
  116.         線性化方式采用 Acroname 網(wǎng)站上提供的線性化公式。
  117.        
  118.         演示功能為,設(shè)定一個距離值,用一個物體靠近及移遠,小車因跟隨移動;
  119.         為簡化程序,物體只在一維移動,小車也只是進行直線的前進和后退。
  120.        

  121. -------------------------------------------------------*/

  122. #include         <STC12C5410AD.h>                                /* STC12C5410AD 的頭文件,為MCU中各個硬件寄存器定個名稱,以便C語言中使用*/

  123. sbit                        Work_Display = P3^4;                // 根據(jù)硬件設(shè)計用與“主控工作指示”接近的名稱取代硬件,使程序減少與硬件的相關(guān)性
  124. sbit                        g_bSample = P3^3;                                // 軌跡采樣控制端, 070715

  125. //  --------- 常數(shù)定義 --------------------------
  126. #define                TRUE                1
  127. #define                FALSE                0

  128. #define                LIGHT                0                                                                // 亮邏輯值,用直觀的符號化常數(shù)替換與硬件密切相關(guān)的邏輯值,增加程序的可讀性、可移植性。
  129. #define                DARK                1                                                                // 暗邏輯值

  130. #define                LIGHT_TIME                1000                        // 亮?xí)r間,使用符號化常數(shù),便于修改,增加程序可讀性
  131. #define                DARK_TIME                        1000                        // 暗時間

  132. #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 輸入*/
  133. #define                P3MODE1                                0x18                        /* 0001 1000   ----- 070715 ----- */

  134. /* 定時器參數(shù)定義 */

  135. #define                T0MODE0 0x00                // 0000 0000,Timer0工作在模式0 ,13位定時;
  136. #define                T0MODE1 0x01                // 0000 0001,Timer0工作在模式1 ,16位定時;
  137. #define                T0MODE2 0x02                // 0000 0010,Timer0工作在模式2 ,8 位自動重加載定時;
  138. #define                T0MODE3 0x03                // 0000 0011,Timer0工作在模式3

  139. #define                T0_TIMER 0x00                // Timer0 工作在定時器模式
  140. #define                T0_COUNTER 0x04        // Timer0 工作在計數(shù)器模式
  141. #define                T0_DISGATE 0x00        // Timer0 禁止INT0引腳控制
  142. #define                T0_ENGATE 0x08        // Timer0 允許INT0引腳控制

  143. #define                T1MODE0 0x00                // 0000 0000,Timer0工作在模式0 ,13位定時;
  144. #define                T1MODE1 0x10                // 0000 0001,Timer0工作在模式1 ,16位定時;
  145. #define                T1MODE2 0x20                // 0000 0010,Timer0工作在模式2 ,8 位自動重加載定時;
  146. #define                T1MODE3 0x30                // 0000 0011,Timer0工作在模式3

  147. #define                T1_TIMER 0x00                // Timer1 工作在定時器模式
  148. #define                T1_COUNTER 0x40        // Timer1 工作在計數(shù)器模式
  149. #define                T1_DISGATE 0x00        // Timer1 禁止INT1引腳控制
  150. #define                T1_ENGATE 0x80        // Timer1 允許INT1引腳控制

  151. #define                SET_T0X12_C 0x80                // or AUXR
  152. #define                CLR_T0X12_C 0x7F                // and AUXR

  153. #define                SET_T1X12_C 0x40                // or AUXR
  154. #define                CLR_T1X12_C 0xBF                // and AUXR

  155. #define                TIME1ms_C                0xF8D0        /* 1ms 定時的加載值字節(jié),對應(yīng) 22.1184MHz 定時器12分頻 */               
  156. #define                TIME1msH_C        0xF8                /* 1ms 定時的加載值高字節(jié) */
  157. #define                TIME1msL_C        0xD0                /* 1ms 定時的加載值低字節(jié) */

  158. /* 中斷處理參數(shù)定義 */
  159. #define                EnINT0_C         0x01
  160. #define                EnT0_C                 0x02
  161. #define                EnINT1_C        0x04
  162. #define                EnT1_C                 0x08
  163. #define                EnUART_C        0x10
  164. #define                EnADCSPI_C         0x20
  165. #define                EnPCALVD_C         0x40

  166. #define                INT0_DOWN        0x01                // TCON 中對INT0中斷信號的控制,下降沿觸發(fā);
  167. #define                INT0_LOW        0x00                // TCON 中對INT0中斷信號的控制,低電平觸發(fā);

  168. #define                INT1_DOWN        0x04                // TCON 中對INT1中斷信號的控制,下降沿觸發(fā);
  169. #define                INT1_LOW        0x00                // TCON 中對INT1中斷信號的控制,低電平觸發(fā);

  170. #define                NOIP_C                0x00                /* 無優(yōu)先級 */

  171. #define                INT0_HIGH         0x01        // IP 寄存器中的優(yōu)先級設(shè)置,IPH暫不處理。
  172. #define                T0_HIGH                        0x02
  173. #define                INT1_HIGH                0x04
  174. #define                T1_HIGH                        0x08
  175. #define                UART_HIGH                0x10
  176. #define                ADCSPI_HIGH        0x20
  177. #define                PCALVD_HIGH 0x40       

  178. // 顯示摩爾斯電碼用
  179. #define                MAX_CHAR_NUM  30                                        // 最多允許顯示字符數(shù)
  180. #define                MAX_GAP_NUM                9                                                // 一個字母最多所需的亮、暗變化次數(shù)
  181. #define                BASE_TIME                        200                                        // 莫爾斯電碼的基本時間,暫定 200ms

  182. /* 莫爾斯電碼表,將大寫字母轉(zhuǎn)換為一個亮、暗序列表 */
  183. unsigned char code ga_ucMorseCode[26][9]={1,2,3,7,0,0,0,0,0,
  184.                                                                                                                                                                         3,2,1,2,1,2,1,7,0,
  185.                                                                                                                                                                         3,2,1,2,3,2,1,7,0,
  186.                                                                                                                                                                         3,2,1,2,1,7,0,0,0,
  187.                                                                                                                                                                         1,7,0,0,0,0,0,0,0,
  188.                                                                                                                                                                         1,2,1,2,3,2,1,7,0,
  189.                                                                                                                                                                         3,2,3,2,1,2,1,7,0,
  190.                                                                                                                                                                         1,2,1,2,1,2,1,7,0,
  191.                                                                                                                                                                         1,2,1,7,0,0,0,0,0,
  192.                                                                                                                                                                         1,2,3,2,3,2,3,7,0,
  193.                                                                                                                                                                         3,2,1,2,3,7,0,0,0,
  194.                                                                                                                                                                         1,2,3,2,1,2,1,7,0,
  195.                                                                                                                                                                         3,2,3,7,0,0,0,0,0,
  196.                                                                                                                                                                         3,2,1,7,0,0,0,0,0,
  197.                                                                                                                                                                         3,2,3,2,3,7,0,0,0,
  198.                                                                                                                                                                         1,2,3,2,3,2,1,7,0,
  199.                                                                                                                                                                         3,2,3,2,1,2,3,7,0,
  200.                                                                                                                                                                         1,2,3,2,1,7,0,0,0,
  201.                                                                                                                                                                         1,2,1,2,1,7,0,0,0,
  202.                                                                                                                                                                         3,7,0,0,0,0,0,0,0,
  203.                                                                                                                                                                         1,2,1,2,3,7,0,0,0,
  204.                                                                                                                                                                         1,2,1,2,1,2,3,7,0,
  205.                                                                                                                                                                         1,2,3,2,3,7,0,0,0,
  206.                                                                                                                                                                         3,2,1,2,1,2,3,7,0,
  207.                                                                                                                                                                         3,2,1,2,3,2,3,7,0,
  208.                                                                                                                                                                         3,2,3,2,1,2,1,7,0};
  209.                                                                                                                                                                        
  210. //————————————————————————————————————————————————————                                                                                                                                                                  
  211. // 以下為StepByStep之二所增加的通訊程序用常量, 070615

  212. /* 串口參數(shù) */
  213. #define                B_57600                4
  214. #define                B_38400                3
  215. #define         B_19200                2
  216. #define         B_9600                1
  217. #define         B_4800                0

  218. // 在 22.1184Hz 下用 T1 作波特率發(fā)生器, 1 分頻。

  219. #define                B57600_C  244
  220. #define   B38400_C  238
  221. #define         B19200_C        220               
  222. #define         B9600_C                184               
  223. #define         B4800_C                144               

  224. #define                UART_MODE1_C 0x40                // SM0,SM1= 01
  225. #define                EN_RCV_C        0x10                        // REN=1

  226. // 允許串口中斷
  227. #define                EnUART_C        0x10

  228. // 串口中斷優(yōu)先級
  229. #define                UART_HIGH                0x10

  230. // 數(shù)據(jù)接收用常數(shù)
  231. #define         MaxRcvByte_C        32                  // 接收緩沖區(qū)的大小,此值必須對應(yīng)一定位數(shù)的二進制數(shù),便于利用屏蔽高位的方式處理指針。
  232. #define                MaxTxdByte_C        32

  233. // 幀命令字
  234. #define         READ_MEMORY                  0x01                // 讀內(nèi)存命令字
  235. #define                WRITE_MEMORY          0x02                // 寫內(nèi)存命令字
  236. #define                MOTOR_PWM_CTRL         0x03                // 電機PWM控制命令,之三增加, 070618
  237. #define                RUN_STRAIGHT                 0x04                // 走直線命令, 之四增加,  070622
  238. #define         RUN_ON_LINE                        0x05                // 走軌跡, 之五增加, 070715

  239. // 自己的設(shè)備地址
  240. #define                MY_ADDR                                 0x01

  241. //————————————————————————————————————————————————————                                                                                                                                                                  
  242. // 以下為StepByStep之三所增加的電機控制程序用常量, 070618

  243. // 馬達控制口
  244. #define         MotorDrv                P2                        // P2.0 - P2.2 控制左電機, P2.4 - P2.6 控制右電機,輸出

  245. #define                P2MODE0                        0x00                        /* 0000 0000,P2 口作為馬達控制,均作為推挽輸出*/
  246. #define                P2MODE1                        0xFF                        /* 1111 1111,*/

  247. // PCA 初始化常數(shù),
  248. #define                STARTPCA_C         0x40;                // or CCON 中的CR位控制 啟動 PCA
  249. #define                STOPPCA_C         0xBF;                // and CCON 中的CR位控制 停止 PCA

  250. #define                FOSCdiv12_C 0x00
  251. #define                FOSCdiv2_C         0x02       
  252. #define                T0Over_C                 0x04                // T0 溢出
  253. #define                ECI_C                         0x06                // 外部脈沖輸入

  254. #define                EnCF_C                0x01                        // 允許PCA溢出中斷

  255. #define                EnCMP_C                0x40                        // 0100 0000, CCAPMn 中控制位6, 允許比較器
  256. #define                EnCAPP_C        0x20                        // 0010 0000, CCAPMn 中控制位5, 允許上升沿捕獲
  257. #define                EnCAPN_C        0x10                        // 0001 0000, CCAPMn 中控制位4, 允許下降沿捕獲
  258. #define                EnMAT_C                0x08                        // 0000 1000, CCAPMn 中控制位3, 允許匹配或捕獲后置位 CCFn
  259. #define                EnTOG_C                0x04                        // 0000 0100, CCAPMn 中控制位2, 允許匹配或捕獲后觸發(fā)輸出翻轉(zhuǎn)
  260. #define                EnPWM_C                0x02                        // 0000 0010, CCAPMn 中控制位1, 允許對應(yīng)的端子輸出PWM信號
  261. #define                EnCCFI_C        0x01                        // 0000 0001, CCAPMn 中控制位0, 允許CCF產(chǎn)生中斷


  262. // PCA 中斷
  263. #define                EnPCALVD_C         0x40

  264. // PCA 優(yōu)先級
  265. #define                PCALVD_HIGH 0x40       

  266. #define                MOTOR_L                        0
  267. #define                MOTOR_R                        1

  268. #define                BRAKE_PWM                0                        // 剎車 PWM 控制值
  269. #define                FLOAT_PWM                255                // 惰行 PWM 控制值

  270. // 電機控制輸出

  271. /* 控制位對應(yīng)關(guān)系:
  272. 電機1(左)
  273. P2.0 - CtrlL1, H 橋的左、右上臂,1 電平輸出導(dǎo)通 0 電平輸出截止,只有在對應(yīng)下臂截止時有效
  274. P2.1 - CtrlL2, H 橋的左下臂,1 電平輸出導(dǎo)通 0 電平輸出截止
  275. P2.2 - CtrlL3, H 橋的右下臂,0 電平輸出導(dǎo)通 1 電平輸出截止


  276. 電機 2(右)
  277. P2.4 - CtrlR1, H 橋的左、右上臂,1 電平輸出導(dǎo)通 0 電平輸出截止,只有在對應(yīng)下臂截止時有效
  278. P2.5 - CtrlR2, H 橋的左下臂,1 電平輸出導(dǎo)通 0 電平輸出截止
  279. P2.6 - CtrlR3, H 橋的右下臂,0 電平輸出導(dǎo)通 1 電平輸出截止

  280. 控制邏輯:
  281. Ctrl1                Ctrl2                Ctrl3                Drv1                Drv2                Drv3                Drv4                電機狀態(tài)
  282.         X                                0                                0                        0/截止        0/導(dǎo)通        0/截止        0/導(dǎo)通                剎車
  283.         PWM                        1                                0                        PWM                        1/截止        0/截止        0/導(dǎo)通                正轉(zhuǎn)
  284.         PWM                        0                                1                        0/截止        0/導(dǎo)通        PWM                        1/截止                反轉(zhuǎn)
  285.         0                                1                                1                        0/截止        1/截止        0/截止        1/截止                惰行
  286.         1                                1                                1                        1/導(dǎo)通        1/截止        1/導(dǎo)通        1/截止                剎車

  287. 電機 2 控制邏輯相同,只是對應(yīng)高 3 位。

  288. */

  289. // 左電機控制
  290. #define         ML_FORWARD        0x02                        // 0000 0010 前進,左上、右下導(dǎo)通,

  291. #define         ML_BACK                        0x04                        // 0000 0100 后退,左下、右上導(dǎo)通

  292. #define         ML_FLOAT                0x06                        // 0000 0110 浮空,4 個臂都截止,此時 Ctrl1 應(yīng)停止PWM輸出,維持“0”。
  293. #define         ML_BRAKE                0x00                        // 0000 0000 剎車,兩個下臂導(dǎo)通,上臂截止

  294. #define                ML_MASK                        0xF8                        // 清除原來輸出值,保留另一個電機的輸出

  295. // 右電機控制
  296. #define         MR_FORWARD        0x20                        // 0010 0000 前進,左上、右下導(dǎo)通,

  297. #define         MR_BACK                        0x40                        // 0100 0000 后退,左下、右上導(dǎo)通

  298. #define         MR_FLOAT                0x60                        // 0110 0000 行進控制浮空,4 個臂都截止
  299. #define         MR_BRAKE                0x00                        // 0000 0000 行進控制剎車,兩個下臂導(dǎo)通,上臂截止

  300. #define                MR_MASK                        0x8F                        // 清除原來輸出值,保留另一個電機的輸出

  301. //————————————————————————————————————————————————————                                                                                                                                                                  
  302. // 以下為StepByStep之四所增加的走直線用常量, 070622
  303. // 無!

  304. //————————————————————————————————————————————————————                                                                                                                                                                  
  305. // 以下為StepByStep之五所增加的走軌跡用常量, 070715

  306. #define                        P1MODE0                        0xFF                        /* 1111 1111,P1口均作為高阻輸入,使用模擬功能 */
  307. #define                        P1MODE1                        0x00                        /* 0000 0000 */

  308. // AD 轉(zhuǎn)換器初始化常數(shù)
  309. #define                        ADPWRON_C                0x80
  310. #define                        ADSPEED3_C         0x60                        // AD速度分為 4 級,0 最低  3 最高, 210 個時鐘周期轉(zhuǎn)換一次
  311. #define                        ADSPEED2_C         0x40
  312. #define                        ADSPEED1_C         0x20
  313. #define                        ADSPEED0_C         0x00

  314. #define                        CLRADFLAG_C 0xEF                        // and AD_CONTR
  315. #define                        GETADFLAG_C 0x10                        // and AD_CONTR, 得到AD結(jié)束標(biāo)志

  316. #define                        STARTAD_C                0x08                        // OR AD_CONTR

  317. unsigned char code DEFAULT_THRES[4] = {127,150,127,127};        // 默認判斷閾值
  318. #define                        DEFAULT_THRES_DELTA         20                                                                                        // 默認判斷回差

  319. #define                        EN_SAMPLE  1                                                                                                 // 采樣控制,此時為允許采樣。
  320. #define                        DIS_SAMPLE 0

  321. #define                        SAMP_LED_ONTIME                600                                                                // 打開采樣 LED 后的延時時間,約 300us

  322. #define                        STRAIGHT                                 0                                                                                // 小車運動狀態(tài)
  323. #define                        LEFT_ROTATE                        1
  324. #define                        RIGHT_ROTATE                2

  325. //————————————————————————————————————————————————————                                                                                                                                                                  
  326. // 以下為StepByStep之六所增加的走軌跡用常量, 070818

  327. #define         AD_CHANEL4GP2D12 4         // GP2D12 所用的 AD通道

  328. // 線性化系數(shù)
  329. #define         M_C                                        10485                // 這三個數(shù)是根據(jù) Acroname 網(wǎng)站提供的一個線性化計算表得到的,需要自己測量原始數(shù)據(jù)標(biāo)定。
  330. #define                B_C                                        5
  331. #define                K_C                                        4

  332. // 設(shè)定的距離(cm)
  333. #define                GAP_VALUE                20      // 與障礙物之間的間隙定值,
  334. #define                GAP_DELTA         2                                // 允許的間隙偏差,

  335. // 采樣間隔時間
  336. #define                TIME_GAP4GP2D12                5        // 暫定 5 ms 采樣一次

  337. // --- 全局變量定義 --------------------
  338. bit                                                 g_b1msFlag;                                        // 1ms中斷標(biāo)志

  339. unsigned char ga_ucDispBuf[MAX_CHAR_NUM+1];                // 顯示緩沖區(qū),存放要顯示的字符,為“0”表示結(jié)束
  340. unsigned char gi_ucGetCharPtr;                                                                // 從顯示緩沖區(qū)取字符指針

  341. unsigned char ga_ucCharDispBuf[MAX_GAP_NUM];        // 一個字符顯示時亮、暗顯示序列,存放顯示基本時間單位的個數(shù),為“0”表示結(jié)束
  342. unsigned char        gi_ucGetDispNum;                                                                // 取亮、暗基本時間數(shù)指針

  343. unsigned char        gc_ucDispNumCnt;                                                                // 基本時間數(shù)計數(shù)器
  344. unsigned int        gc_uiBaseTime;                                                                        // 基本時間計數(shù)器, 1ms 計數(shù)

  345. unsigned char code         DISP_CONTENT[MAX_CHAR_NUM+1] = {"HELLOWORLD"};                // 要顯示的內(nèi)容,因為莫爾斯電碼沒有定義空格

  346. // -------- 以下為StepByStep之二增加的變量 070615 ------------------

  347. // 數(shù)據(jù)接收用
  348. unsigned char xdata        ga_ucRcvBuf[MaxRcvByte_C];                // 接收緩沖區(qū)
  349. unsigned char data        gi_ucSavePtr;                                                                        // 存數(shù)指針,每收到一個字節(jié)保存到緩沖區(qū)后加“1”。

  350. unsigned char        data        gi_ucGetPtr;                                                                        // 從緩沖區(qū)中取數(shù)的指針,每取出一個字節(jié)后加“1”。
  351. unsigned char        idata        gi_ucStartPtr;                                                                // 幀起始位置,指向數(shù)據(jù)區(qū)開始。
  352. unsigned char        idata        gi_ucEndPtr;                                                                        // 幀結(jié)束位置。
  353. unsigned char        idata        gc_ucDataLen;                                                                        // 幀長,即數(shù)據(jù)區(qū)字節(jié)數(shù)。
  354. bit                                                                        g_bNewData;                                                                                // 串口收到一個字節(jié)標(biāo)志,為減少變量交互。
  355. bit                                                                        g_bStartRcv;                                                                        // 開始接收數(shù)據(jù)幀標(biāo)志。

  356. unsigned char        xdata        ga_ucTxdBuf[MaxTxdByte_C];                // 發(fā)送緩沖區(qū),用于返回轉(zhuǎn)速值等。
  357. unsigned char        data        gi_ucTxdPtr;                                                                        // 發(fā)送指針
  358. unsigned char        data        gc_ucTxdCnt;                                                                        // 發(fā)送字節(jié)計數(shù)

  359. // -------- 以下為StepByStep之三增加的變量 070618 ------------------

  360. unsigned char code         ga_ucForward[2] = {ML_FORWARD,MR_FORWARD};                // 前進控制
  361. unsigned char code         ga_ucBack[2] = {ML_BACK,MR_BACK};                                                        // 后退控制

  362. unsigned char code         ga_ucFloat[2] = {ML_FLOAT,MR_FLOAT};                                        // 惰行控制
  363. unsigned char code         ga_ucBrake[2] = {ML_BRAKE,MR_BRAKE};                                        // 剎車控制

  364. unsigned char code         ga_ucMask[2] = {ML_MASK,MR_MASK};                                                        // 屏蔽字,為了輸出新的控制信號,清除原來的控制值

  365. unsigned int                                ga_uiMotorCtrl[2];                                                // 電機控制參數(shù),高字節(jié)控制方向, 0 - 前進 0xFF - 后退,低字節(jié)PWM值

  366. // -------- 以下為StepByStep之四增加的變量 070622 ------------------

  367. unsigned char data         gac_ucWheel_Cnt[2];                                                // 碼盤輸入信號計數(shù),用計數(shù)方式而非標(biāo)志,是為了避免丟失。
  368. unsigned int        idata gac_uiRunCnt[2];                                                        // 對車輪轉(zhuǎn)動的碼盤信號計數(shù),以達到計算行走距離的目的

  369. unsigned int        idata        g_uiBase_PWM;                                                                        // 基準(zhǔn) PWM 值

  370. unsigned int        idata        g_uiLeftRunNum;                                                                // 左側(cè)車輪行走計數(shù)設(shè)定值
  371. unsigned int  data        gc_uiLeftRunCnt;                                                        // 左輪行走減計數(shù)器
  372. bit                                                                        g_bStopRunStraight;                                                // 停止運行標(biāo)志

  373. // -------- 以下為StepByStep之五增加的變量 070715 ------------------

  374. bit                                                                        g_bEnSample;                                                                        // 允許采樣標(biāo)志
  375. bit                                                                        g_bSampleStart;                                                                // 通知采樣

  376. unsigned char        idata        ga_ucSampleVal[5];                                                // 4 路采樣值,暫時取 8 位, 第 5 個單元存放轉(zhuǎn)換后的邏輯狀態(tài)
  377.                                                                                                                                                                                                         // 存放4個傳感器的狀態(tài),一個對應(yīng)一位,“1”為在軌跡上
  378.                                                                                                                                                                                                        
  379. unsigned char idata        ga_ucThreshold[4];                                                // 4 路黑白判斷值
  380. unsigned char        idata        g_ucThresDelta;                                                                // 判斷回差,用于消除判斷時的臨界毛刺

  381. bit                                                                        g_bStopRunOnLine;                                                        // 停止運行標(biāo)志

  382. unsigned char                         g_ucRotateStat;                                                                // 轉(zhuǎn)動狀態(tài),指示小車是直行還是左、右轉(zhuǎn)

  383. // -------- 以下為StepByStep之六增加的變量 070818 ------------------
  384. bit                                                                        g_bStopHoldingGap;                                                // 停止保持間隙運動

  385. unsigned char        xdata        ga_ucGapValue[9];                                                        // 間隙采樣值,存放線性化后的距離值,單位 cm,最后一個單元存放平均值
  386. unsigned char        data        gi_ucSaveGapValPtr;                                                // 保存采樣值指針
  387. unsigned char        data        gc_ucGetGapValCnt;                                                // 采樣計數(shù),保證采滿8次后再處理數(shù)據(jù)

  388. unsigned char        data        gc_ucTimeGap4GP2D12Cnt;                                // 5ms 測量間隔計時器
  389. bit                                                                        g_bRead_GP2D12;                                                                // 讀GP2D12 值

  390. // ------------- 函數(shù)聲明 -----------------
  391. void print(unsigned char *p_ucDispConPtr);
  392. bit getNextGap(void);
  393. void getNextChar(void);

  394. // -------- 以下為StepByStep之二增加的函數(shù) 070615 ------------------
  395. void init_SIO(unsigned char baud);
  396. bit dataFrame_OK(void);
  397. void do_Command(void);

  398. // -------- 以下為StepByStep之三增加的函數(shù) 070618 ------------------
  399. unsigned char DriveMotor(unsigned char No,unsigned int uiPWM_Val);

  400. // -------- 以下為StepByStep之四增加的函數(shù) 070622 ------------------
  401. void run_Straight(void);
  402. void StopRunStraight(void);

  403. // -------- 以下為StepByStep之五增加的函數(shù) 070715 ------------------
  404. unsigned char lineSamp_proc(unsigned char ucOldSenStat);
  405. void run_Online(unsigned char ucSensorStat);
  406. void StopRunOnLine(void);

  407. // -------- 以下為StepByStep之六增加的函數(shù) 070818 ------------------
  408. unsigned char read_GP2D12(void);
  409. unsigned char cal_MeanVal(unsigned char *p_ucDataStarAddr);


  410. /*********** 主程序 *****************/
  411. void main(void)
  412. {
  413.         unsigned char i;       
  414.        
  415.         // ----------- 初始化硬件 ---------------
  416.         P3M0 = P3MODE0;                                                                        // 因為只涉及 P3 口,所以此處只初始化 P3
  417.         P3M1 = P3MODE1;

  418.         /* 初始化定時器 */
  419.        
  420.         TMOD = T0MODE1|T1MODE2;                // Timer0工作在模式1 ,16位定時,Timer1 工作在模式 2 ,8位重加載,作為波特率發(fā)生器;
  421.         AUXR = AUXR&CLR_T0X12_C;        // Timer0 工作在12分頻
  422.        
  423.        
  424.         TCON = 0;                                                                        /* 未使用外部中斷,所以不用定義中斷的觸發(fā)方式 */
  425.                
  426.         TH0 = TIME1msH_C;
  427.         TL0 = TIME1msH_C;
  428.         TR0 = TRUE;
  429.        
  430.         /* 初始化中斷 */
  431.         IE = EnT0_C;                                                        // 此處只允許 Timer0 中斷,
  432.        
  433.         IPH = NOIP_C;                                                        // 此處不設(shè)優(yōu)先級
  434.         IP = NOIP_C;                                       
  435.        
  436.         // ----- StepByStep之二增加的硬件初始化 070615 ------------------
  437.        
  438.         //初始化串口 070615
  439.         init_SIO(B_19200);
  440.        
  441.         // 初始化相關(guān)中斷 070615
  442.         IE = IE|EnUART_C;                                                                // 允許 UART 中斷

  443.         // ----- StepByStep之三增加的硬件初始化 070618 ------------------
  444.        
  445.         P2M0 = P2MODE0;                                                                                                // 電機涉及 P2 口,初始化 P2
  446.         P2M1 = P2MODE1;
  447.        
  448.         // 初始化 PCA
  449.         CMOD = FOSCdiv12_C;                                                                                // PCA 時鐘源為 Fosc/12 , 不允許 count 溢出中斷 CF。休眠時 PCA 工作
  450.        
  451.         CCAPM2 = EnCMP_C|EnPWM_C;                                                        // PCA 的模塊 2 用于左電機控制,8 位PWM模式;
  452.         PCA_PWM2 = 0x03;                                                                                        // 初始化為PWM恒輸出 0, 以便進入惰行狀態(tài)。
  453.         CCAP2L = 0xFF;
  454.         CCAP2H = 0xFF;

  455.         CCAPM3 = EnCMP_C|EnPWM_C;                                                        // PCA 的模塊 3 用于右電機控制,8 位PWM 模式;
  456.         PCA_PWM3 = 0x03;                                                                                        // 初始化為PWM恒輸出 0, 以便進入惰行狀態(tài)。
  457.         CCAP3L = 0xFF;
  458.         CCAP3H = 0xFF;
  459.        
  460.         CL = 0;
  461.         CH = 0;
  462.         CCON = CCON|STARTPCA_C;                                                                // 啟動 PCA

  463.         // ----- StepByStep之四增加的硬件初始化 070622 ------------------

  464.         // 初始化 PCA0、1 用于碼盤采樣 ---- 070622
  465.         CCAPM0 = EnCAPP_C|EnCAPN_C|EnCCFI_C;        // PCA 的模塊 0 正、負跳均捕獲,允許中斷        ,右側(cè)碼盤輸入
  466.         CCAPM1 = EnCAPP_C|EnCAPN_C|EnCCFI_C;        // PCA 的模塊 1 正、負跳均捕獲,允許中斷        ,左側(cè)碼盤輸入

  467.         // 初始化相關(guān)中斷
  468.         IE = IE|EnPCALVD_C;                                                                                // PCA 中斷
  469.         IP = IP|PCALVD_HIGH;                                                                        // PCA置為優(yōu)先級 1

  470.         // ----- StepByStep之五增加的硬件初始化 070715 ------------------
  471.        
  472.         P1M0 = P1MODE0;                                                                                                // 采樣涉及 P1 口,初始化 P1
  473.         P1M1 = P1MODE1;
  474.        
  475.         /* 初始化 AD 用于軌跡采樣  ----*/       
  476.        
  477.         ADC_CONTR         = ADPWRON_C|ADSPEED3_C;

  478.         // ----- StepByStep之六只使用AD,不需要增加的硬件初始化 070818 ------------------



  479.         // ------ 初始化起始變量 ----------------

  480.         g_b1msFlag = FALSE;

  481.         print(DISP_CONTENT);                                                // 顯示內(nèi)容初始化
  482.         gi_ucGetCharPtr = MAX_CHAR_NUM;        // 為了啟動第一次顯示
  483.        
  484.         Work_Display = DARK;                                                // 熄滅
  485.         gi_ucGetDispNum = MAX_GAP_NUM;        // 為了啟動第一次顯示
  486.         gc_ucDispNumCnt = 1;
  487.         gc_uiBaseTime = 1;
  488.        
  489.         // ----- StepByStep之二增加的變量初始化 070615 ------------------
  490.        
  491.         gi_ucSavePtr=0;
  492.         gi_ucGetPtr=0;
  493.        
  494.         g_bNewData = FALSE;
  495.         g_bStartRcv = FALSE;

  496.         // ----- StepByStep之三增加的變量初始化 070618 ------------------
  497.         ga_uiMotorCtrl[MOTOR_L] = FLOAT_PWM;
  498.         ga_uiMotorCtrl[MOTOR_R] = FLOAT_PWM;
  499.        
  500.         DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]);
  501.         DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]);                        // 上電時將電機置于惰行狀態(tài)
  502.        
  503.         // ----- StepByStep之四增加的變量初始化 070622 ------------------
  504.        
  505.         gac_ucWheel_Cnt[MOTOR_L] = 0;
  506.         gac_ucWheel_Cnt[MOTOR_R] = 0;                                       
  507.        
  508.         gac_uiRunCnt[MOTOR_L] = 0;
  509.         gac_uiRunCnt[MOTOR_R] = 0;
  510.        
  511.         g_bStopRunStraight = TRUE;
  512.         g_bStopRunOnLine = TRUE;
  513.        
  514.         // ----- StepByStep之五增加的變量初始化 070715 ------------------
  515.        
  516.         g_bSample = DIS_SAMPLE;                                                                                        // 采樣器初始化為采背景光狀態(tài),關(guān)閉發(fā)射管
  517.        
  518.         g_bEnSample = FALSE;
  519.         g_bSampleStart = FALSE;
  520.        
  521.         for(i=0;i<4;i++)
  522.         {
  523.                 ga_ucSampleVal[i] = 0;                                                                        // 軌跡信號模擬值清“0”
  524.                 ga_ucThreshold[i] = DEFAULT_THRES[i];                // 軌跡判斷閾值初始化
  525.         }

  526.         g_ucThresDelta = DEFAULT_THRES_DELTA;                        // 軌跡判斷回差初始化

  527.         ga_ucSampleVal[4] = 0;                                                                                // 邏輯狀態(tài)清“0”
  528.        
  529.         //  ----- StepByStep之六增加的變量初始化 070818 ------------------
  530.        
  531.         g_bStopHoldingGap = TRUE;
  532.         gi_ucSaveGapValPtr = 0;
  533.         gc_ucGetGapValCnt = 8;
  534.         gc_ucTimeGap4GP2D12Cnt = TIME_GAP4GP2D12;
  535.         g_bRead_GP2D12 = FALSE;
  536.                
  537.         // --------- 主循環(huán) ------------------------
  538.        
  539.         EA = TRUE;                                                                                                                // 啟動中斷,開始正常工作
  540.        
  541.         while(1)
  542.         {
  543.                 if(g_b1msFlag == TRUE)
  544.                 {
  545.                         g_b1msFlag = FALSE;
  546.                        
  547.                         // ----- 主控工作指示燈控制 ----------- 070609
  548.                         gc_uiBaseTime--;                                                // 基本時間計時
  549.                         if(gc_uiBaseTime ==0)
  550.                         {
  551.                                 gc_uiBaseTime = BASE_TIME;
  552.                                
  553.                                 if(getNextGap())                                        // 當(dāng)前字符顯示,如果顯示完則取下一個字符
  554.                                 {
  555.                                         getNextChar();                                        // 取下一個字符
  556.                                 }
  557.                         }
  558.                        
  559.                         // ------- GP2D12 采樣間隔處理 ------ 070818
  560.                         if(gc_ucTimeGap4GP2D12Cnt>0)
  561.                         {
  562.                                 gc_ucTimeGap4GP2D12Cnt--;
  563.                                 if(gc_ucTimeGap4GP2D12Cnt==0)
  564.                                 {
  565.                                         g_bRead_GP2D12 = TRUE;
  566.                                         gc_ucTimeGap4GP2D12Cnt = TIME_GAP4GP2D12;
  567.                                 }
  568.                         }
  569.                 }

  570.                 // ----- 小車走直線控制 ----------  070622
  571.                 if(gac_ucWheel_Cnt[MOTOR_L]>0)
  572.                 {
  573.                         // 左側(cè)碼盤計數(shù)
  574.                         gac_uiRunCnt[MOTOR_L]++;
  575.                         gac_ucWheel_Cnt[MOTOR_L]--;
  576.                         if(g_bStopRunStraight == FALSE)
  577.                         {
  578.                                 run_Straight();
  579.                         }
  580.                        
  581.                         // 行走距離控制
  582.                         if(gc_uiLeftRunCnt>0)
  583.                         {
  584.                                 gc_uiLeftRunCnt--;
  585.                                 if(gc_uiLeftRunCnt == 0)
  586.                                 {
  587.                                         if(g_bStopRunStraight == FALSE)
  588.                                         {
  589.                                                 StopRunStraight();                                                        // 停止直線行走
  590.                                         }
  591.                                        
  592.                                         if(g_bStopRunOnLine == FALSE)
  593.                                         {
  594.                                                 StopRunOnLine();                                                                // 停止走軌跡                        070715
  595.                                         }
  596.                                 }
  597.                         }
  598.                 }
  599.                
  600.                 if(gac_ucWheel_Cnt[MOTOR_R]>0)
  601.                 {
  602.                         // 右側(cè)碼盤計數(shù)
  603.                         gac_uiRunCnt[MOTOR_R]++;
  604.                         gac_ucWheel_Cnt[MOTOR_R]--;
  605.                         if(g_bStopRunStraight == FALSE)
  606.                         {
  607.                                 run_Straight();
  608.                         }
  609.                 }
  610.                
  611.                 // -------- 走軌跡處理  --------- 070715
  612.                 if(g_bSampleStart)
  613.                 {
  614.                         union
  615.                         {
  616.                                 unsigned int all;
  617.                                 unsigned char b[2];
  618.                         }uiTemp;
  619.                        
  620.                         uiTemp.b[0] = TH0;
  621.                         uiTemp.b[1] = TL0;
  622.                         if(uiTemp.all > (TIME1ms_C + SAMP_LED_ONTIME))
  623.                         {
  624.                                 g_bSampleStart = FALSE;
  625.                                 ga_ucSampleVal[4] = lineSamp_proc(ga_ucSampleVal[4]);        // 處理軌跡采樣
  626.                                 g_bSample = DIS_SAMPLE;                                                                                                                                // 退出采樣狀態(tài),回到背景采樣
  627.                                 if(g_bStopRunOnLine == FALSE)
  628.                                 {
  629.                                         run_Online(ga_ucSampleVal[4]);                                                                                        // 走軌跡處理
  630.                                 }
  631.                         }                       
  632.                 }

  633.                 // -------- 測距處理 --------- 070818
  634.                 if(g_bRead_GP2D12)
  635.                 {
  636.                         g_bRead_GP2D12 = FALSE;
  637.                         ga_ucGapValue[gi_ucSaveGapValPtr] = read_GP2D12();
  638.                         gi_ucSaveGapValPtr = (gi_ucSaveGapValPtr+1)&0x07;                                        //用 Mask 方式保證指針在 0 - 7 范圍中
  639.                        
  640.                         if(gc_ucGetGapValCnt >0 )
  641.                         {
  642.                                 // 還未采集到 8 次數(shù)據(jù)
  643.                                 gc_ucGetGapValCnt--;
  644.                         }
  645.                         else
  646.                         {
  647.                                 // 采滿 8 次,計算平均值
  648.                                 ga_ucGapValue[8] = cal_MeanVal(&ga_ucGapValue[0]);
  649.                         }
  650.                 }
  651.                
  652.                 // -------- 通訊處理 --------- 070618
  653.                 if(g_bNewData)
  654.                 {
  655.                         g_bNewData = FALSE;
  656.                         if(dataFrame_OK())                                        // 串口收到數(shù)據(jù)后的處理,與PC程序中的函數(shù) DataFrame_OK() 相當(dāng)
  657.                         {
  658.                                 do_Command();                                                        // 執(zhí)行數(shù)據(jù)幀中的命令
  659.                         }                                               
  660.                 }               
  661.         }                                                                                                                                // 不斷循環(huán), 在所有嵌入式應(yīng)用的主程序中,都有這樣一個無限循環(huán).
  662. }


  663. /************** 函數(shù) **************************************/

  664. /********************************************/
  665. /* 將要顯示的字符送顯示緩沖區(qū)                                                         */
  666. /********************************************/

  667. void print(unsigned char *p_ucDispConPtr)
  668. {
  669.         unsigned char i;
  670.         i = 0;
  671.        
  672.         while(*p_ucDispConPtr != 0)
  673.         {
  674.                 ga_ucDispBuf[i] = *p_ucDispConPtr;
  675.                 i++;
  676.                 p_ucDispConPtr++;
  677.         }
  678.         ga_ucDispBuf[i] = 0;                                // 字符串結(jié)束符
  679. }

  680. /********************************************/
  681. /*                 取下一個顯示間隔                                                                                         */
  682. /* 返回為 FALSE - 表示繼續(xù)顯示此字符                                */
  683. /* 返回為 TRUE -  表示要取下一個顯示字符                */
  684. /********************************************/

  685. bit getNextGap(void)
  686. {
  687.         bit flag = FALSE;
  688.        
  689.         gc_ucDispNumCnt--;
  690.         if(gc_ucDispNumCnt == 0)
  691.         {
  692.                 gi_ucGetDispNum++;
  693.                 if(gi_ucGetDispNum >MAX_GAP_NUM)
  694.                 {
  695.                         gi_ucGetDispNum = 0;                                        // 如果已經(jīng)超過最后界限,則準(zhǔn)備取下一個字符
  696.                         flag = TRUE;
  697.                 }
  698.                 else
  699.                 {
  700.                         if(ga_ucCharDispBuf[gi_ucGetDispNum] == 0)
  701.                         {
  702.                                 gi_ucGetDispNum = 0;                                        // 如果顯示基本時間數(shù)為“0”,則準(zhǔn)備取下一個字符
  703.                                 flag = TRUE;
  704.                         }
  705.                         else
  706.                         {
  707.                                 gc_ucDispNumCnt = ga_ucCharDispBuf[gi_ucGetDispNum];
  708.                                 if(gi_ucGetDispNum&0x01)
  709.                                 {
  710.                                         Work_Display = DARK;                        // gucGetDispNum 奇數(shù)位置:暗
  711.                                 }
  712.                                 else
  713.                                 {
  714.                                         Work_Display = LIGHT;                        // gucGetDispNum 偶數(shù)位置:亮
  715.                                 }
  716.                                 flag = FALSE;
  717.                         }
  718.                 }
  719.         }
  720.        
  721.         return(flag);
  722. }

  723. /********************************************/
  724. /*                                                 取下一個顯示字符                                                         */
  725. /********************************************/
  726. void getNextChar(void)
  727. {
  728.         unsigned char ucCharOrder,i;
  729.        
  730.         gi_ucGetCharPtr++;
  731.         if((gi_ucGetCharPtr > MAX_CHAR_NUM)||(ga_ucDispBuf[gi_ucGetCharPtr]==0))
  732.         {
  733.                 gi_ucGetCharPtr = 0;                                                                // 已取字符到結(jié)尾,回到頭。
  734.         }
  735.        
  736.         ucCharOrder = ga_ucDispBuf[gi_ucGetCharPtr] - 0x41;                        // 將大寫字母ASCII嗎轉(zhuǎn)換為字母順序,暫時只支持大寫字母
  737.         for(i=0;i<MAX_GAP_NUM;i++)
  738.         {
  739.                 ga_ucCharDispBuf[i] = ga_ucMorseCode[ucCharOrder][i];        // 取出該字符對應(yīng)的亮、暗序列
  740.         }
  741.        
  742.         Work_Display = LIGHT;                                                        // 每個字符都是從“亮”開始
  743.         gi_ucGetDispNum = 0;
  744.         gc_ucDispNumCnt = ga_ucCharDispBuf[gi_ucGetDispNum];
  745. }


  746. /********************************************/
  747. /*          定時器 0 中斷服務(wù)               */
  748. /* 說明:  1ms 中斷一次,                                                                                 */
  749. /********************************************/

  750. void  Timer0_Int(void) interrupt 1 using 1
  751. {
  752.        
  753.         TH0 = TIME1msH_C;
  754.         TL0 = TIME1msL_C;
  755.                        
  756.         g_b1msFlag = TRUE;

  757.         //  ------- 以下為StepByStep之五增加的處理 070715 ------------------
  758.        
  759.         g_bEnSample = ~g_bEnSample;
  760.         if(g_bEnSample)
  761.         {
  762.                 g_bSample = EN_SAMPLE;                                                                                        // 打開采樣LED
  763.                 g_bSampleStart = TRUE;
  764.         }       
  765. }

  766. // -------- 以下為StepByStep之二增加的函數(shù) 070615 ------------------

  767. /********************************************/
  768. /* 名稱:init_SIO                                                                                                                */
  769. /* 用途:初始化串口,                                                                                                 */
  770. /* 參數(shù): 波特率 , 模式固定為:1                                                         */
  771. /*                 1 START 8 DATA 1 STOP                                                                 */
  772. /********************************************/

  773. void init_SIO(unsigned char baud)
  774. {
  775.         // 波特率表
  776.         unsigned char        code        TH_Baud[5]={B4800_C,B9600_C,B19200_C,B38400_C,B57600_C};
  777.        
  778.         AUXR = AUXR|SET_T1X12_C;
  779.         TH1 = TH_Baud[baud];
  780.         TL1 = TH_Baud[baud];
  781.         TR1 = TRUE;
  782.        
  783.         SCON        =        UART_MODE1_C|EN_RCV_C;        // 8 位模式( MODE 1)
  784. }


  785.                                                                                                                                                                   
  786. /********************************************/
  787. /*          串口中斷服務(wù)                                 */
  788. /* 說明:  將收到的數(shù)據(jù)保存到接收緩沖區(qū)                        */
  789. /********************************************/

  790. void  SioInt(void)  interrupt 4  using 1
  791. {
  792.         if(RI==TRUE)
  793.         {
  794.                 RI=FALSE;
  795.                 ga_ucRcvBuf[gi_ucSavePtr]=SBUF;                                                                                                // 將數(shù)據(jù)填入緩沖區(qū)
  796.                 gi_ucSavePtr=(gi_ucSavePtr+1)&(MaxRcvByte_C-1);                                // 利用屏蔽高位的方式實現(xiàn)指針的環(huán)形處理
  797.                 g_bNewData = TRUE;
  798.         }
  799.        
  800.         if(TI == TRUE)
  801.         {
  802.                 TI = FALSE;                                                                                                                                                                                // 處理發(fā)送
  803.                 gc_ucTxdCnt--;                                                                                                                                                                // 發(fā)送計數(shù)
  804.                 if(gc_ucTxdCnt>0)
  805.                 {
  806.                         gi_ucTxdPtr++;
  807.                         SBUF = ga_ucTxdBuf[gi_ucTxdPtr];                                                                                // 取下一字節(jié)
  808.                 }
  809.         }       
  810. }

  811. /********************************************/
  812. /*名稱:        dataFrame_OK                                                                                                */
  813. /*用途: 檢測接收緩沖區(qū)數(shù)據(jù),                                                     */
  814. /*說明:        如果收到正確的數(shù)據(jù)幀則返回真                                */
  815. /********************************************/

  816. bit dataFrame_OK(void)
  817. {
  818.         unsigned char i,j,k;
  819.         bit flag;
  820.        
  821.         flag = FALSE;
  822.        
  823.         while(gi_ucGetPtr != gi_ucSavePtr)
  824.         {
  825.                 if(g_bStartRcv == FALSE)
  826.                 {
  827.                         /*  檢測幀頭 0x55 0xAA LEN */
  828.                         k = 0;                       
  829.                        
  830.                         i = (gi_ucGetPtr - 5)&(MaxRcvByte_C-1);                       
  831.                         if(ga_ucRcvBuf[i]==0x55)
  832.                         {
  833.                                 k++;
  834.                         }
  835.                        
  836.                         i = (gi_ucGetPtr - 4)&(MaxRcvByte_C-1);                       
  837.                         if(ga_ucRcvBuf[i]==0xAA)
  838.                         {
  839.                                 k++;
  840.                         }
  841.                        
  842.                         i = (gi_ucGetPtr - 3)&(MaxRcvByte_C-1);                       
  843.                         if(ga_ucRcvBuf[i]==MY_ADDR)
  844.                         {
  845.                                 k++;
  846.                         }
  847.                        
  848.                         if(k == 3)
  849.                         {
  850.                                 //幀頭正確,啟動數(shù)據(jù)區(qū)接收
  851.                                 g_bStartRcv=TRUE;       
  852.                                 i=(gi_ucGetPtr-1)&(MaxRcvByte_C-1);                                               
  853.                                 gc_ucDataLen = ga_ucRcvBuf[i];
  854.                                 gi_ucStartPtr = gi_ucGetPtr;
  855.                                 gi_ucEndPtr= (gi_ucGetPtr + gc_ucDataLen)&(MaxRcvByte_C-1);
  856.                         }
  857.                 }
  858.                 else
  859.                 {
  860.                         //開始接收數(shù)據(jù)處理
  861.                         if(gi_ucGetPtr==gi_ucEndPtr)
  862.                         {
  863.                                 /* 數(shù)據(jù)幀接收完 */
  864.                                 g_bStartRcv=FALSE;
  865.                        
  866.                                 j=gi_ucStartPtr;       
  867.                                 k= 0;
  868.                                 for(i=0;i<gc_ucDataLen;i++)
  869.                                 {
  870.                                         // 計算CS
  871.                                         k +=ga_ucRcvBuf[j];               
  872.                                         j=(j+1)&(MaxRcvByte_C-1);
  873.                                 }
  874.                        
  875.                                 // 取校驗和
  876.                                 k = ~k;
  877.                                 if(k==ga_ucRcvBuf[j])
  878.                                 {
  879.                                         flag = TRUE;                                                        // 數(shù)據(jù)校驗正確
  880.                                 }
  881.                         }
  882.                 }
  883.                 gi_ucGetPtr=(gi_ucGetPtr+1)&(MaxRcvByte_C-1);               
  884.         }       
  885.         return (flag);
  886. }                                                                                                                                                                       

  887. /********************************************/
  888. /*名稱:        do_Command                                                                                                        */
  889. /*用途: 根據(jù)收到的數(shù)據(jù)幀命令做相應(yīng)處理                        */
  890. /********************************************/
  891. /*
  892. 地址與硬件的對應(yīng)關(guān)系:
  893. 0x0000 — 0x00FF —— 對應(yīng)STC12LE5412的256字節(jié)內(nèi)部RAM(idata);
  894. 0x0100 — 0x01FF —— 對應(yīng)STC12LE5412的256字節(jié)外部RAM(xdata);
  895. 0x0200 — 0x7F7F —— 保留,為大RAM的單片機預(yù)留;
  896. 0x7F80 — 0x7FFF —— 對應(yīng)STC12LE5412的128字節(jié)SFR;
  897. 0x8000 — 0xAFFF —— 對應(yīng)STC12LE5412的12K FlashROM;
  898. 0xB000 — 0xFFFF —— 保留,為大ROM的單片機預(yù)留;
  899. */

  900. // 增加電機PWM控制命令處理, 070618

  901. void do_Command(void)
  902. {
  903.         unsigned char ucCommand,i,j,sum,n;
  904.        
  905.         union
  906.         {
  907.                 unsigned int all;
  908.                 unsigned char b[2];
  909.         }uitemp;
  910.        
  911.         unsigned char idata *ucI_Ptr;
  912.         unsigned char xdata *ucX_Ptr;
  913.         unsigned char code        *ucC_Ptr;

  914.         ucCommand = ga_ucRcvBuf[gi_ucStartPtr];                         // 取出數(shù)據(jù)幀中的命令
  915.        
  916.         switch (ucCommand)
  917.         {
  918.                 case READ_MEMORY:
  919.                 {
  920.                         // 讀內(nèi)存數(shù)據(jù)處理
  921.                         i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);               
  922.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 取讀數(shù)據(jù)地址, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
  923.                         i =(i+1)&(MaxRcvByte_C-1);
  924.                         uitemp.b[0] = ga_ucRcvBuf[i];
  925.                         i =(i+1)&(MaxRcvByte_C-1);
  926.                         n = ga_ucRcvBuf[i];                                                                                                        // 取讀數(shù)據(jù)長度
  927.                         if(n>(MaxTxdByte_C - 10))
  928.                         {
  929.                                 n = (MaxTxdByte_C - 10);                                                                        // 受發(fā)送緩沖區(qū)限制,減 10 個字節(jié)對應(yīng):
  930.                                                                                                                                                                                                         //        幀頭2 設(shè)備地址2 長度1 命令1 數(shù)據(jù)地址2 字節(jié)數(shù)1 .... 校驗和1
  931.                         }
  932.                        
  933.                         ga_ucTxdBuf[0] = 0x55;
  934.                         ga_ucTxdBuf[1] = 0xAA;                                                                                        // 幀頭
  935.                         i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1);                        // 取發(fā)送方地址
  936.                         ga_ucTxdBuf[2] = ga_ucRcvBuf[i];                                                // 作為接收方地址發(fā)送
  937.                         ga_ucTxdBuf[3] = MY_ADDR;                                                                                // 自己的地址作為發(fā)送方送出
  938.                         ga_ucTxdBuf[4] = n + 4;                                                                                        // 幀長
  939.                         ga_ucTxdBuf[5] = READ_MEMORY;                                                                // 返回命令
  940.                         ga_ucTxdBuf[6] = uitemp.b[1];                                                                // 將要讀數(shù)據(jù)的地址和長度返回
  941.                         ga_ucTxdBuf[7] = uitemp.b[0];
  942.                         ga_ucTxdBuf[8] = n;
  943.                         sum = ga_ucTxdBuf[5]+ga_ucTxdBuf[6]+ga_ucTxdBuf[7]+ga_ucTxdBuf[8];

  944.                         i = 9;                                                                                                                                                        // 數(shù)據(jù)區(qū)起始指針
  945.                        
  946.                         if(uitemp.b[0] == 0x00)
  947.                         {
  948.                                 // 如果高地址為 0 ,則讀IDATA內(nèi)容
  949.                                 ucI_Ptr = uitemp.b[1];                                                                               
  950.                                 for(j=0;j<n;j++)
  951.                                 {
  952.                                         ga_ucTxdBuf[i] = *ucI_Ptr;
  953.                                         sum += ga_ucTxdBuf[i];
  954.                                         i++;
  955.                                         ucI_Ptr++;
  956.                                 }
  957.                         }

  958.                         if(uitemp.b[0] == 0x01)
  959.                         {
  960.                                 // 如果高地址為“0x01”,則讀XDATA內(nèi)容
  961.                                 ucX_Ptr = uitemp.b[1];                                                                                // 因為只有256字節(jié)的XDATA,所以只取低字節(jié)。
  962.                                 for(j=0;j<n;j++)
  963.                                 {
  964.                                         ga_ucTxdBuf[i] = *ucX_Ptr;
  965.                                         sum += ga_ucTxdBuf[i];
  966.                                         i++;
  967.                                         ucX_Ptr++;
  968.                                 }
  969.                         }

  970.                         // 讀 SFR 暫不支持,讀者可以思考一下如何添加?
  971.                        
  972.                         if(uitemp.b[0] >= 0x80)
  973.                         {
  974.                                 // 如果高地址大于“0x80”,則讀code(程序區(qū))內(nèi)容
  975.                                 ucC_Ptr = uitemp.all - 0x8000;                                                               
  976.                                 for(j=0;j<n;j++)
  977.                                 {
  978.                                         ga_ucTxdBuf[i] = *ucC_Ptr;                // 注意,此功能將使你的程序泄密 :P
  979.                                         sum += ga_ucTxdBuf[i];
  980.                                         i++;
  981.                                         ucC_Ptr++;
  982.                                 }
  983.                         }
  984.                        
  985.                         ga_ucTxdBuf[i] = ~sum;                                                // 校驗和
  986.                                
  987.                         gc_ucTxdCnt = i+1;                                                                // 發(fā)送字節(jié)計數(shù)
  988.                         gi_ucTxdPtr = 0;                                                                        // 發(fā)送指針
  989.                         SBUF = ga_ucTxdBuf[0];                                                // 啟動發(fā)送
  990.                        
  991.                         break;
  992.                 }
  993.                
  994.                 case WRITE_MEMORY:
  995.                 {
  996.                         // 寫內(nèi)存數(shù)據(jù)處理
  997.                         i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);               
  998.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 取讀數(shù)據(jù)地址
  999.                         i =(i+1)&(MaxRcvByte_C-1);
  1000.                         uitemp.b[0] = ga_ucRcvBuf[i];
  1001.                         i =(i+1)&(MaxRcvByte_C-1);
  1002.                         n = ga_ucRcvBuf[i];                                                                                                        // 取讀數(shù)據(jù)長度
  1003.                         i =(i+1)&(MaxRcvByte_C-1);                                                                        // 數(shù)據(jù)區(qū)起始指針
  1004.                        
  1005.                         j = 0;                                                                                                                                                        // 返回實際寫的字節(jié)數(shù)
  1006.                        
  1007.                         if(uitemp.b[0] == 0x00)
  1008.                         {
  1009.                                 // 如果高地址為 0 ,則寫IDATA內(nèi)容
  1010.                                 ucI_Ptr = uitemp.b[1];                                                                               
  1011.                                 for(j=0;j<n;j++)
  1012.                                 {
  1013.                                         *ucI_Ptr = ga_ucRcvBuf[i];                                                        // 注意,此功能會導(dǎo)致程序崩潰 :(
  1014.                                         i = (i+1)&(MaxRcvByte_C-1);                                               
  1015.                                         ucI_Ptr++;
  1016.                                 }
  1017.                         }

  1018.                         if(uitemp.b[0] == 0x01)
  1019.                         {
  1020.                                 // 如果高地址為“0x01”,則寫XDATA內(nèi)容
  1021.                                 ucX_Ptr = uitemp.b[1];                                                                                // 因為只有256字節(jié)的XDATA,所以只取低字節(jié)。
  1022.                                 for(j=0;j<n;j++)
  1023.                                 {
  1024.                                          *ucX_Ptr = ga_ucRcvBuf[i];
  1025.                                         i = (i+1)&(MaxRcvByte_C-1);                                               
  1026.                                         ucX_Ptr++;
  1027.                                 }
  1028.                         }

  1029.                         // 寫 SFR和程序區(qū)暫不支持,讀者可自己添加,看看有什么難度 :D
  1030.                        
  1031.                         ga_ucTxdBuf[0] = 0x55;
  1032.                         ga_ucTxdBuf[1] = 0xAA;                                                                                        // 幀頭
  1033.                         i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1);                        // 取發(fā)送方地址
  1034.                         ga_ucTxdBuf[2] = ga_ucRcvBuf[i];                                                // 作為接收方地址發(fā)送
  1035.                         ga_ucTxdBuf[3] = MY_ADDR;                                                                                // 自己的地址作為發(fā)送方送出
  1036.                         ga_ucTxdBuf[4] = 4;                                                                                                        // 幀長
  1037.                         ga_ucTxdBuf[5] = WRITE_MEMORY;                                                        // 返回命令
  1038.                         ga_ucTxdBuf[6] = uitemp.b[1];                                                                // 將要讀數(shù)據(jù)的地址和長度返回
  1039.                         ga_ucTxdBuf[7] = uitemp.b[0];
  1040.                         ga_ucTxdBuf[8] = j;                                                                                                        // 返回寫成功的字節(jié)數(shù)
  1041.                         sum = ga_ucTxdBuf[5]+ga_ucTxdBuf[6]+ga_ucTxdBuf[7]+ga_ucTxdBuf[8];
  1042.                        
  1043.                         ga_ucTxdBuf[9] = ~sum;                                                // 校驗和
  1044.                                
  1045.                         gc_ucTxdCnt = 10;                                                                        // 發(fā)送字節(jié)計數(shù)
  1046.                         gi_ucTxdPtr = 0;                                                                        // 發(fā)送指針
  1047.                         SBUF = ga_ucTxdBuf[0];                                                // 啟動發(fā)送
  1048.                        
  1049.                         break;
  1050.                 }
  1051.                
  1052.                 case MOTOR_PWM_CTRL:
  1053.                 {
  1054.                         // 電機PWM控制  StepbyStep之三增加 070618
  1055.                         i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);               
  1056.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 取左側(cè)電機數(shù)據(jù), 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
  1057.                         i =(i+1)&(MaxRcvByte_C-1);
  1058.                         uitemp.b[0] = ga_ucRcvBuf[i];
  1059.                         ga_uiMotorCtrl[MOTOR_L] = uitemp.all;
  1060.                        
  1061.                         i =(i+1)&(MaxRcvByte_C-1);
  1062.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 取右側(cè)電機數(shù)據(jù), 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
  1063.                         i =(i+1)&(MaxRcvByte_C-1);
  1064.                         uitemp.b[0] = ga_ucRcvBuf[i];
  1065.                         ga_uiMotorCtrl[MOTOR_R] = uitemp.all;

  1066.                         j = DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]);        // 輸出電機控制
  1067.                         j = DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]);       
  1068.                        
  1069.                         ga_ucTxdBuf[0] = 0x55;
  1070.                         ga_ucTxdBuf[1] = 0xAA;                                                                                        // 幀頭
  1071.                         i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1);                        // 取發(fā)送方地址
  1072.                         ga_ucTxdBuf[2] = ga_ucRcvBuf[i];                                                // 作為接收方地址發(fā)送
  1073.                         ga_ucTxdBuf[3] = MY_ADDR;                                                                                // 自己的地址作為發(fā)送方送出
  1074.                         ga_ucTxdBuf[4] = 2;                                                                                                        // 幀長
  1075.                         ga_ucTxdBuf[5] = MOTOR_PWM_CTRL;                                                // 返回命令
  1076.                         ga_ucTxdBuf[6] = j;                                                                                                        // 返回 P2 控制字
  1077.                        
  1078.                         sum = ga_ucTxdBuf[5]+ga_ucTxdBuf[6];
  1079.                        
  1080.                         ga_ucTxdBuf[7] = ~sum;                                                // 校驗和
  1081.                                
  1082.                         gc_ucTxdCnt = 8;                                                                        // 發(fā)送字節(jié)計數(shù)
  1083.                         gi_ucTxdPtr = 0;                                                                        // 發(fā)送指針
  1084.                         SBUF = ga_ucTxdBuf[0];                                                // 啟動發(fā)送
  1085.                
  1086.                         break;
  1087.                 }
  1088.                
  1089.                 case RUN_STRAIGHT:
  1090.                 {
  1091.                         // 啟動走直線  StepbyStep之四增加 070622
  1092.                        
  1093.                         i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);               
  1094.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 取左輪行走設(shè)定值, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
  1095.                         i =(i+1)&(MaxRcvByte_C-1);
  1096.                         uitemp.b[0] = ga_ucRcvBuf[i];
  1097.                         g_uiLeftRunNum = uitemp.all;
  1098.                         gc_uiLeftRunCnt = g_uiLeftRunNum;                                                // 啟動行走距離控制
  1099.                        
  1100.                         i =(i+1)&(MaxRcvByte_C-1);
  1101.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 取基準(zhǔn)PWM值, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
  1102.                         i =(i+1)&(MaxRcvByte_C-1);
  1103.                         uitemp.b[0] = ga_ucRcvBuf[i];
  1104.                         g_uiBase_PWM = uitemp.all;
  1105.                                                
  1106.                         ga_uiMotorCtrl[MOTOR_L] = g_uiBase_PWM;                        // 保存電機控制 PWM 值
  1107.                         ga_uiMotorCtrl[MOTOR_R] = g_uiBase_PWM;

  1108.                         gac_uiRunCnt[MOTOR_L] = 0;                                                                        // 啟動時清除行走計數(shù)值
  1109.                         gac_uiRunCnt[MOTOR_R] = 0;                       

  1110.                         if(g_uiBase_PWM == BRAKE_PWM)
  1111.                         {
  1112.                                 g_bStopRunStraight = TRUE;
  1113.                         }
  1114.                         else
  1115.                         {
  1116.                                 g_bStopRunStraight = FALSE;                                                                        // 啟動
  1117.                         }
  1118.                        
  1119.                         DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]);        // 輸出電機控制
  1120.                         DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]);       
  1121.                        
  1122.                                                
  1123.                         ga_ucTxdBuf[0] = 0x55;
  1124.                         ga_ucTxdBuf[1] = 0xAA;                                                                                        // 幀頭
  1125.                         i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1);                        // 取發(fā)送方地址
  1126.                         ga_ucTxdBuf[2] = ga_ucRcvBuf[i];                                                // 作為接收方地址發(fā)送
  1127.                         ga_ucTxdBuf[3] = MY_ADDR;                                                                                // 自己的地址作為發(fā)送方送出
  1128.                         ga_ucTxdBuf[4] = 1;                                                                                                        // 幀長
  1129.                         ga_ucTxdBuf[5] = RUN_STRAIGHT;                                                        // 返回命令
  1130.                        
  1131.                         sum = ga_ucTxdBuf[5];
  1132.                        
  1133.                         ga_ucTxdBuf[6] = ~sum;                                                // 校驗和
  1134.                                
  1135.                         gc_ucTxdCnt = 7;                                                                        // 發(fā)送字節(jié)計數(shù)
  1136.                         gi_ucTxdPtr = 0;                                                                        // 發(fā)送指針
  1137.                         SBUF = ga_ucTxdBuf[0];                                                // 啟動發(fā)送
  1138.                        
  1139.                         break;
  1140.                 }

  1141.                 case RUN_ON_LINE:
  1142.                 {
  1143.                         // 啟動走軌跡  StepbyStep之五增加 070715
  1144.                        
  1145.                         i = (gi_ucStartPtr + 1)&(MaxRcvByte_C-1);               
  1146.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 取左輪行走設(shè)定值, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
  1147.                         i =(i+1)&(MaxRcvByte_C-1);
  1148.                         uitemp.b[0] = ga_ucRcvBuf[i];
  1149.                         g_uiLeftRunNum = uitemp.all;
  1150.                         gc_uiLeftRunCnt = g_uiLeftRunNum;                                                // 啟動行走距離控制
  1151.                        
  1152.                         i =(i+1)&(MaxRcvByte_C-1);
  1153.                         uitemp.b[1] = ga_ucRcvBuf[i];                                                                // 取基準(zhǔn)PWM值, 注意 C51 中的多字節(jié)數(shù)據(jù)與PC中相反
  1154.                         i =(i+1)&(MaxRcvByte_C-1);
  1155.                         uitemp.b[0] = ga_ucRcvBuf[i];
  1156.                         g_uiBase_PWM = uitemp.all;
  1157.                                                
  1158.                         ga_uiMotorCtrl[MOTOR_L] = g_uiBase_PWM;                        // 保存電機控制 PWM 值
  1159.                         ga_uiMotorCtrl[MOTOR_R] = g_uiBase_PWM;

  1160.                         gac_uiRunCnt[MOTOR_L] = 0;                                                                        // 啟動時清除行走計數(shù)值
  1161.                         gac_uiRunCnt[MOTOR_R] = 0;                       

  1162.                         if(g_uiBase_PWM == BRAKE_PWM)
  1163.                         {
  1164.                                 g_bStopRunOnLine = TRUE;
  1165.                         }
  1166.                         else
  1167.                         {
  1168.                                 g_bStopRunOnLine = FALSE;                                                                                                        // 啟動
  1169.                                 g_ucRotateStat = STRAIGHT;                                                                                                // 初始狀態(tài)為直行
  1170.                         }
  1171.                        
  1172.                         DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]);        // 輸出電機控制
  1173.                         DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]);       
  1174.                        
  1175.                                                
  1176.                         ga_ucTxdBuf[0] = 0x55;
  1177.                         ga_ucTxdBuf[1] = 0xAA;                                                                                        // 幀頭
  1178.                         i = (gi_ucStartPtr-2)&(MaxRcvByte_C-1);                        // 取發(fā)送方地址
  1179.                         ga_ucTxdBuf[2] = ga_ucRcvBuf[i];                                                // 作為接收方地址發(fā)送
  1180.                         ga_ucTxdBuf[3] = MY_ADDR;                                                                                // 自己的地址作為發(fā)送方送出
  1181.                         ga_ucTxdBuf[4] = 1;                                                                                                        // 幀長
  1182.                         ga_ucTxdBuf[5] = RUN_ON_LINE;                                                                // 返回命令
  1183.                        
  1184.                         sum = ga_ucTxdBuf[5];
  1185.                        
  1186.                         ga_ucTxdBuf[6] = ~sum;                                                // 校驗和
  1187.                                
  1188.                         gc_ucTxdCnt = 7;                                                                        // 發(fā)送字節(jié)計數(shù)
  1189.                         gi_ucTxdPtr = 0;                                                                        // 發(fā)送指針
  1190.                         SBUF = ga_ucTxdBuf[0];                                                // 啟動發(fā)送
  1191.                        
  1192.                         break;
  1193.                 }
  1194.                
  1195.                 default: break;
  1196.         }
  1197. }

  1198. // -------- 以下為StepByStep之三增加的函數(shù) 070618 ------------------

  1199. /********************************************/
  1200. /*名稱:        DriveMotor                                                                                                        */
  1201. /*用途: 根據(jù)得到的參數(shù)計算電機控制輸出值,        */
  1202. /********************************************/
  1203. //輸入 No ——  電機序號, iPWM_Val —— 電機控制值
  1204. // 返回電機控制信號

  1205. unsigned char DriveMotor(unsigned char No,unsigned int uiPWM_Val)
  1206. {
  1207.         unsigned char ucCtrl_Out,ucCtrl_Buf,ucPCA_CCAP,ucPCA_MODE;
  1208.         union
  1209.         {
  1210.                 unsigned int all;
  1211.                 unsigned char b[2];
  1212.         }uiPWM_Buf;
  1213.        
  1214.         uiPWM_Buf.all = uiPWM_Val;
  1215.         ucCtrl_Out = MotorDrv;                                                                // 讀回電機控制輸出,注意,此操作會影響P2.3和P2.7口的狀態(tài)!!!
  1216.        
  1217.         switch(uiPWM_Buf.b[1])
  1218.         {
  1219.                 case FLOAT_PWM:
  1220.                 {
  1221.                         // 惰行命令
  1222.                         ucCtrl_Buf = ga_ucFloat[No];
  1223.                         ucPCA_MODE = 0x03;                                                                // PWM恒輸出 0,
  1224.                         ucPCA_CCAP = 0xFF;
  1225.                         break;
  1226.                 }
  1227.                
  1228.                 case BRAKE_PWM:
  1229.                 {               
  1230.                         // 剎車命令
  1231.                         ucCtrl_Buf = ga_ucBrake[No];
  1232.                         ucPCA_MODE = 0x03;                                                                // PWM恒輸出 0,
  1233.                         ucPCA_CCAP = 0xFF;
  1234.                         break;
  1235.                 }
  1236.                
  1237.                 default:
  1238.                 {
  1239.                         // 調(diào)功處理
  1240.                         if(uiPWM_Buf.b[0] == 0)
  1241.                         {
  1242.                                 // 前進
  1243.                                 ucCtrl_Buf = ga_ucForward[No];
  1244.                         }
  1245.                         else
  1246.                         {
  1247.                                 // 后退控制
  1248.                                 ucCtrl_Buf = ga_ucBack[No];
  1249.                         }
  1250.                        
  1251.                         ucPCA_MODE = 0x00;
  1252.                         ucPCA_CCAP = 255 - uiPWM_Buf.b[1];                        // PWM值, 注意:需要用 255 減,否則值越大功率越小! 070622
  1253.                        
  1254.                         break;
  1255.                 }
  1256.         }       
  1257.        
  1258.         ucCtrl_Out = (ucCtrl_Out&ga_ucMask[No])|ucCtrl_Buf;
  1259.         MotorDrv = ucCtrl_Out;                                                        //         輸出控制信號, 如果使用P2.3和P2.7 則要特殊處理
  1260.        
  1261.         if(No == MOTOR_L)
  1262.         {
  1263.                 PCA_PWM2 = ucPCA_MODE;
  1264.                 CCAP2L = ucPCA_CCAP;
  1265.                 CCAP2H = ucPCA_CCAP;
  1266.         }
  1267.         else
  1268.         {
  1269.                 PCA_PWM3 = ucPCA_MODE;
  1270.                 CCAP3L = ucPCA_CCAP;
  1271.                 CCAP3H = ucPCA_CCAP;
  1272.         }
  1273.        
  1274.         return (ucCtrl_Out);                                                                // 將電機控制信號返回
  1275. }

  1276. // -------- 以下為StepByStep之四增加的函數(shù) 070622 ------------------

  1277. /********************************************/
  1278. /*          PCA 中斷服務(wù)                                      */
  1279. /* 說明: CCF0、1 用于碼盤輸入                                                                */
  1280. /*                         CCF2、3 用于電機控制                                                                */
  1281. /********************************************/

  1282. void  PCA_Int(void) interrupt 6 using 2
  1283. {       
  1284.         if(CF == TRUE)
  1285.         {
  1286.                 CF = FALSE;                                                                                                //         出錯保護
  1287.         }
  1288.        
  1289.         if(CCF0 == TRUE)
  1290.         {
  1291.                 // 右側(cè)碼盤信號輸入
  1292.                 CCF0 = FALSE;
  1293.                 gac_ucWheel_Cnt[MOTOR_R]++;                                // 每來一個脈沖 +1
  1294.         }
  1295.        
  1296.         if(CCF1 == TRUE)
  1297.         {
  1298.                 // 左側(cè)碼盤信號輸入
  1299.                 CCF1 = FALSE;
  1300.                 gac_ucWheel_Cnt[MOTOR_L]++;                                // 每來一個脈沖 +1
  1301.         }
  1302.        
  1303.         if(CCF2 == TRUE)
  1304.         {
  1305.                 CCF2 = FALSE;                                                                                //         出錯保護
  1306.         }
  1307.        
  1308.         if(CCF3 == TRUE)
  1309.         {
  1310.                 CCF3 = FALSE;                                                                                //         出錯保護
  1311.         }               
  1312. }

  1313. /********************************************/
  1314. /*名稱:        run_Straight                                                                                                */
  1315. /*用途: 根據(jù)車輪行走計數(shù)修正電機輸出值,                */
  1316. /********************************************/
  1317. /*
  1318. 涉及如下全局變量:
  1319. gac_uiRunCnt[2] —— 兩輪的行走計數(shù)值
  1320. ga_uiMotorCtrl[MOTOR_R] ——  右側(cè)電機的PWM控制值
  1321. */

  1322. void run_Straight(void)
  1323. {
  1324.         bit flag;
  1325.                
  1326.         flag = FALSE;
  1327.                        
  1328.         if(gac_uiRunCnt[MOTOR_R]!= gac_uiRunCnt[MOTOR_L])
  1329.         {
  1330.                 if(gac_uiRunCnt[MOTOR_R]> gac_uiRunCnt[MOTOR_L])
  1331.                 {
  1332.                         // 右輪快,右輪置為惰行
  1333.                         ga_uiMotorCtrl[MOTOR_R] = FLOAT_PWM;                                       
  1334.                 }
  1335.                 else
  1336.                 {
  1337.                         // 左輪快,左輪置為惰行
  1338.                         ga_uiMotorCtrl[MOTOR_L] = FLOAT_PWM;                                       
  1339.                 }
  1340.                
  1341.                 flag =TRUE;                               
  1342.         }
  1343.         else
  1344.         {
  1345.                 if(ga_uiMotorCtrl[MOTOR_L] == FLOAT_PWM)
  1346.                 {
  1347.                         ga_uiMotorCtrl[MOTOR_L] = g_uiBase_PWM;
  1348.                         flag = TRUE;
  1349.                 }
  1350.                
  1351.                 if(ga_uiMotorCtrl[MOTOR_R] == FLOAT_PWM)
  1352.                 {
  1353.                         ga_uiMotorCtrl[MOTOR_R] = g_uiBase_PWM;
  1354.                         flag = TRUE;
  1355.                 }
  1356.         }
  1357.        
  1358.         if(flag == TRUE)
  1359.         {
  1360.                 DriveMotor(MOTOR_R,ga_uiMotorCtrl[MOTOR_R]);        // 輸出電機控制
  1361.                 DriveMotor(MOTOR_L,ga_uiMotorCtrl[MOTOR_L]);               
  1362.         }
  1363. }

  1364. /********************************************/
  1365. /*名稱:        StopRunStraight                                                                                        */
  1366. /*用途: 停止直線行走狀態(tài)                                                                                */
  1367. /********************************************/

  1368. void StopRunStraight(void)
  1369. {
  1370.         g_bStopRunStraight = TRUE;                                                                                                                // 停止走直線控制
  1371.        
  1372.         DriveMotor(MOTOR_R,BRAKE_PWM);                                                                // 輸出電機控制
  1373.         DriveMotor(MOTOR_L,BRAKE_PWM);       
  1374. }

  1375. // -------- 以下為StepByStep之五增加的函數(shù) 070715 ------------------

  1376. /********************************************/
  1377. /* 名稱:lineSamp_proc                                                                                        */
  1378. /* 用途:采樣并處理                                                                                                        */
  1379. /********************************************/
  1380. /* 采樣器對應(yīng)關(guān)系:
  1381.          頂視:                          左  ——  右
  1382.          采樣器                          1  2  3  4
  1383.          PORT P1.                        3  2  1  0
  1384.          SampleVal                1  2  3  4
  1385.          SensorStat   b0 b1 b2 b3
  1386.          OldSenStat   b0 b1 b2 b3
  1387. */

  1388. unsigned char lineSamp_proc(unsigned char ucOldSenStat)
  1389. {
  1390.         unsigned char i,temp;
  1391.        
  1392.         // 啟動 AD 并讀數(shù), 大約占用 56 us, 對應(yīng) 22.1184MHz

  1393.         for(i = 0; i <4; i++)
  1394.         {
  1395.                 // 循環(huán)采樣
  1396.                 ADC_CONTR = ADPWRON_C|ADSPEED3_C|STARTAD_C|i;                        // 啟動 AD
  1397.                
  1398.                 temp = ADC_CONTR & GETADFLAG_C;                                                                                // 讀轉(zhuǎn)換結(jié)束標(biāo)志
  1399.                 while(temp==0)
  1400.                 {
  1401.                         temp = ADC_CONTR & GETADFLAG_C;                                                                        // 讀轉(zhuǎn)換結(jié)束標(biāo)志
  1402.                 }

  1403.                 ga_ucSampleVal[3-i] = ADC_DATA;                                                                                // 獲取AD值, 暫時取 8 位值, 此處將順序反過來。!
  1404.                
  1405.                 ADC_CONTR = ADC_CONTR & CLRADFLAG_C;
  1406. ……………………

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



全部資料51hei下載地址:
基于單片機的智能避障小車(程序 論文).rar (910.43 KB, 下載次數(shù): 61)


評分

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

查看全部評分

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

使用道具 舉報

沙發(fā)
ID:328014 發(fā)表于 2018-7-23 04:16 | 只看該作者
完整表格等資料詳見:http://www.zg4o1577.cn/bbs/dpj-99534-1.html
回復(fù)

使用道具 舉報

板凳
ID:652804 發(fā)表于 2020-1-3 09:19 | 只看該作者
謝謝,學(xué)習(xí)學(xué)習(xí)。
回復(fù)

使用道具 舉報

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

本版積分規(guī)則

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

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

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 激情在线视频 | 成人黄色电影在线播放 | 91久久精品国产91久久性色tv | 九九九视频 | 亚洲精品国产电影 | 北条麻妃一区二区三区在线视频 | 91精品久久久久久久久久 | 人妖无码 | 精产嫩模国品一二三区 | 亚洲精品日本 | 中文字幕亚洲欧美日韩在线不卡 | 国产中的精品av涩差av | 久久精品一 | 美女黄色在线观看 | 中文字幕第十一页 | 欧美一级特黄aaa大片在线观看 | 特黄小视频 | 国产精品女人久久久 | 午夜免费视频观看 | 精品一区二区三区在线观看 | 国产伦精品一区二区三区精品视频 | 亚洲欧美在线免费观看 | 欧美日韩国产精品一区 | 国产一极毛片 | 亚洲精品一区二区网址 | 福利二区 | 国产日韩欧美一区 | 亚洲三区在线 | 天天干天天玩天天操 | 亚洲一区在线观看视频 | 91资源在线播放 | 8x国产精品视频一区二区 | 国产成人99久久亚洲综合精品 | 色综合一区二区三区 | 一区二区三区日韩 | 久久久久久久久淑女av国产精品 | 亚洲大片在线观看 | 91在线视频一区 | 亚洲综合大片69999 | 国内精品久久久久久影视8 最新黄色在线观看 | 国产亚洲精品久久久久动 |