2007年4月11日 星期三

ATmega-128 Pulse IV...

今天,我利用公司的示波器檢查 ATmega-128 的訊號,發現機乎十六隻輸出腳的訊號都是 2.760ms,超出了馬達訊號的範圍。正常來說,我是設定了三個不同的闊度...。最奇怪的是,原先迴圈十次使用了 730us 的時間出現不準確的情況。從今次迴圈三十五次所得出的 2760us,可以計出每一次迴圈會花上 78.85714us,比起之前 73us 每次多了 5us。真的不知道那個才是準確...。

28 則留言:

iRobot 提到...

可以用聲效卡Line-in當CRO用啊!這樣便可以在家中進行簡單測試了。
硬體:2粒電阻,任何數值。只要能做出 1比20的數值便可以。測試電壓約為5V, 經降壓後便只有 5/21 = 0.23V (低於0.8V 便安全了),直接輸入line-in 左或右聲道便可,記得要接地線啊。
軟體:用 Visual Analyser 8 好了(免費)
http://sillanumsoft.altervista.org/prod01.htm

Pacess 提到...

Thanks irobot!
由於我對電子方面沒有認識,請問有沒有相關的線路圖?謝謝~

irobot 提到...

有興趣看一下這個線路吧。
http://us.f2.yahoofs.com/hkblog/zGxmuXqfHxm_l5ZAbK1G6gQ-/blog/ap_20070402120513270.jpg?ibAsWIGBnBIKxILQ

irobot 提到...

還是簡單的用左聲道說明一下吧。設輸入的待測電壓最大為15V。經過 20k 及 1k 電阻返回待測電壓的地線,則電流為 15/21000 安培。
輸入至 line-in 左聲道的電壓如下計算
電壓 = 電流 x 1k 電阻
= (15/21000) x 1000 = 15/21
= 0.71 < 0.8V
所以15V 以內都不會燒掉聲效卡的。
這分壓電路是不是很容易呢。

Pacess 提到...

謝謝 irobot

irobot 提到...

不客氣。
請問你有否使用atmega128 的 pwm channel 做 servo 的控制呢?

Pacess 提到...

irobot,看完你的線路圖之後,我有一個疑問。圖中的待測電壓分別有左、中、右三條線,是不是指有三個 Channel 的意思?還是在量度 Pulse 或電壓時,應該自行決定用左或右?

對,我原本是使用 ATmega-128 的 Counter-1 來產生 20ms

的 Pulse,及使用 Counter-0 來產生 Pulse width。但這個方法每次只能服務一個 Servo,而在 20ms 裡最多只能服務八個 Servo(20ms/8 = 2.5ms,剛剛好是一個 Servo 最大 Pulse with 的完結)。

由於我在 CQ7144A 中學會了只使用一個計時器,便能支持無限 Servo 的原故,所以我想把相同的技術應用在 ATmega-128 之上。基本上,程式是做了出來,亦能運作。但是 Pulse width 的計算還不準確,而且 Resolution 也很低,支持十六個 Servo 的時候,只能有 180/24 左右的
Resolution,亦即是說每次移動是 7.5 度...。

irobot 提到...

最多只能有 2 channel ,你可以用左或右。最多只能同時檢查2個servo。
控制 servo其實我也不太懂,想請教你。為什麼CQ7144A 能控制無限servo而atmega128又不能呢。兩者的分別在哪裡?

另外我的想法不知對不對, atmega128 不是有 6 channel PWM 的嗎,若每 1 channel 能控制8個servo,那它應該可以控制很servo。知 6 channel PWM 是不是這個意思呢。

iRobot 提到...

當你要用聲效卡測試1個servo時,應把待測電壓左接線駁至atmega128的對應針腳。而把待測電壓的地線接至atmega128線路版的地線。接線另一邊應為一個line-in 的接駁頭,可以直接插在 sound card。
(p.s. 第一次用最好不把 servo 同時接駁,減少其它的干擾因素。
另外用 notebook 亦可,不過一般沒有line-in,只能用 mic-in ,所以只能用左聲道。
line-in 的接駁頭最簡單便是用壞了的earphone,剪掉耳塞,在中間加上電阻便可以了。

iRobot 提到...

由於我不懂 avr 的pwm,剛看了兩篇文章。不知對你有否參考價值。
1.http://www.avrvi.com/bbs/htm_data/30/0611/288.html

2. http://www.avrvi.com/avr_examples/pwm.html

Pacess 提到...

ATmega-128 其實理論上也能支持無限 Servo,我剛剛製作的程式就是這樣。但問題是支持 Servo 數量越多,就越要犧牲 Resolution。

為什麼 CQ7144A 又可以呢?其實它一樣有極限,但由於它比 ATmega-128 快,所以同樣支持 16 個 Servo,CQ7144A 會比 ATmega-128 的 Resolution 好得多,做出來的效果亦較為流暢。如果可以的話,我真想 ATmega-128 能做出支持 16 個 Servo,畢竟現時我有 13 個 S3003 騰空了出來...。

以我所知 ATmega-128 只有三個計時器,但為了程式能準確等待指定 ms,所以必須預留一個計時器。你給我的兩個網頁,說的是利用計時器產生準確 PWM 的方法;我第一次編程也是用上相同的方法,但最多只能支持八個 Servo。

iRobot 提到...

那真是奇啊。我試過一只機械狗有13個Servo的,用的是atmega16。它的resolution是0.72度,而且可以即時做反應的。
如果只當servo controller用, at89c2051 也可控制13個servo。(因它的記憶體只有128個否則可以控制更多也沒有問題),只是更新角度時慢了點,要等待20ms。

iRobot 提到...

剛翻看了你在06年7月份的程序,當時你是用來控制4個servo的。Timer1 是 每5ms 中斷一次,在中斷時設定某一servo腳為on,再在Timer0設定隔多久把再把它設為off。(不過實際是4個servo同時設為off)。用這方法最多便只能控制8個servo了。可否說說用CQ7144A 而只使用一個計時器的大約方法呢?我猜 Resolution 低是因為從中斷後到載入下個 servo 的中斷資料已經花去很多機械週期了。所以Resolution 的高低是取決於這中間花去的時間。不知對不對呢。

Pacess 提到...

請問有沒有 ATmega-16 的那段程式可以給我參考呢?

CQ7144A 的 PWM 輸出程式已列於下方:

void ServoOut(short *g_pPulseWidth, int iLoop) {
unsigned int iPortData;
int iChannel;

// The following while loop takes 6.29us for 1 loop when SERVO_MAX = 32 //
while (iLoop > 0) {
iPortData = 0;
for (iChannel=0; iChannel < SERVO_MAX; iChannel++) {

// Set bit on/off of each channel //
iPortData = (iPortData<<1) | (g_pPulseWidth[iChannel] >= iLoop);
}

// Output to PC0~15 and PD0~15 //
PD.DR.WORD.L = (unsigned short)(iPortData);
PC.DR.WORD = (unsigned short)(iPortData>>16);

iLoop--;
}

// Just for safety, set LOW to PC0~15 and PD0~15 //
PC.DR.WORD = 0;
PD.DR.WORD.L = 0;
}

Pacess 提到...

這段代碼是當 20ms 的中斷產生時便會執行。它主要是按 Loop 的數目來把引腳拉至高位,而當所有 Loop 完後,便一次過把十六個 Servo 腳拉回低位。

iRobot 提到...

那機械狗內的程式我也沒看過呢。因它是商業產品,一般也不能讀回的。
現正研究你提供的CQ7144A程式。

iRobot 提到...

由於C語言和MCU我也不是太熟的,看了一會也不肯定是否百分百理解。以下只是我的點推想。
根據你所說一個loop 只要 6.29 us,粗略計算在一個loop 內的工作,居然要處理32個servo的比較和設定。就算是RISC cpu,每個servo 最少也花掉 8至10個machine cylce 吧,總共便要256至320個m.c.了。那麼CQ7144A的工作頻率最少也有40至50MHz了。比16MHz的atmega128快上3至4倍。按理atmega的resolution應也有它的4分1吧。
但你說 atmega 只能做 180/24 的精確度,顯然是落後很多了。
從程式看,你沒有提供 iLoop 的參考數值,是不是要計算一個loop 所花的時間後才可決定的呢?我有2個想法,一個是整個中斷循環花2.5ms,而iLoop的數值是397。timer的時間則是17.5ms。合共20ms。
另一個則是中斷循環花的時間不定,看servo的最大轉向角而定,但不超過2.5ms。而timer的時間與前者相加則為20ms,或干脆固定為20ms好了,反正servo的週期是有一定容錯度的。
最後還是請你指點一二吧,讓我也可理解。我也很想讓atmega也做到類似的效果呢。畢竟我看見那只機械狗也能做到。

Pacess 提到...

我的程序是從日本人身上學到的。程序本身使用了 Counter-1 來產生 20ms 的中斷,即中斷之間為 20ms。而當 Counter-1 中斷發生時,便會執行 ServoOut 函數。根據實際運作,iLoop 的數目設定為 30。這是因為 Loop 30 次便大於 2.5ms,再繼續輸出訊號也沒有意思,Servo 是不會有反應的,所以當做完 2.5ms 之後,中斷便完,剩下來的 17.5ms 時間便留給主程序或系統之用。

在數值上,ATmega-128 是 16MHz,而 CQ7144A 是 12MHz,理應是 ATmega-128 較快,但其實 CQ7144A 內部的頻率是原來的四倍,亦即是 48MHz,所以其實是快很多。

iRobot 提到...

這樣便證實我的推想是對了。按你的說法CQ7144A只是快上4倍,那它也不能算很準確,只是 180/120。根據atmega的特性,我想可以提出一些建議,大慨有3種可以嘗試的方法,你看哪一個可行吧。不過詳情要待晚上才可寫出來了。

iRobot 提到...

你post出來的方法真是很好,既簡單也很有系統。而且能將橫向的思考轉成垂直的思考來解決問題。其實我也看過台灣的人有另外的解決方案,就是使用多核心的MCU了(FPPA),可惜不知那裡可以買來試試。
http://chamberplus.myweb.hinet.net/fppa_sa4.htm

iRobot 提到...

另外我有以下問題想請教你:
1. 在CQ7144A 的 PWM 輸出程式中的這句是否錯的。// The following while loop takes 6.29us for 1 loop when SERVO_MAX = 32 //,因為若這是真的,iLoop 便等於397,那CQ7144A便比atmega128快上不只4倍了。

2. 這兩句我不太懂。
PD.DR.WORD.L = (unsigned short)(iPortData);
PC.DR.WORD = (unsigned short)(iPortData>>16);
它是16位元操作的嗎,這 (unsigned short)是什麼意思?

iRobot 提到...

最後我的看法是在 2.5ms 時間內完成 PWM 輸出程式內的工作,對atmega128來說是太繁重了,不可能完成的。若要保留這程式的精髓,第一個解決方案是利用atmega128,4k SRAM 強大的記憶體來彌補速度上的不足。即是說把大量的比較工作和對各針腳的on / off 設定均擺在main loop 內完成,而把運算結果存在另一陣列(new_value)內,有新數值接收後要設定旗標通知pwm程式。陣列大小取決於精確度,以16個servo(即 2 byte)精確度為180度/200(即約200步)計,便需要(200x2) x 2 = 800了。為什麼要再乘2呢,因為在pwm 輸出程式內操作的是另一組陣列(present_value)。pwm 輸出程式內的iLoop 設為200,它只負責把陣列(present_value)內的值分200次抄至port address 內,當中要加入延時程式,保證做200次的時間是2.5ms (嘻嘻atmega128太快了!!)。最後檢查有新數值的旗標是否設定了,若有便要在此時把陣列(new_value)的值抄至陣列(present_value)內。然後便結束PWM程式。
這樣便可利用閒著的17.5ms時間幫補pwm程式了,缺點是要花大量記憶體。你看是否可行呢?

Pacess 提到...

1. 這句 // The following while loop takes 6.29us for 1 loop when SERVO_MAX = 32 // 應該是真的,是我從日本人的代碼中翻譯過來,再加上實際的運作,真的能控制 Servo。

2. 由於程序中設定為 32 個 Servo,所以便找了一個 int 類型來儲存 32 個 Servo 的高低位情報。而 PD.DR.WORD.L 是 short 類型,只有 16-bits,所以把 iPortData 的低 16-bits 分給 PD,而高 16-bits(iPortData>>16 的意思是把 iPortData 的高 16-bits 移到低 16-bits 的位置)就分給 PC。

這是日本人的原碼:
http://misumi.sakura.ne.jp/blog/archives/programs/060427-sh7144_1.c

你所指的方法應該行得通,等我也想想有沒有其他的方法~

iRobot 提到...

好啊。也很想看看你的想法。
你介紹的網誌很好看啊,它居然一之購入8本6月號Interface。看來你用的servo controller 真的很好和超值呢。
另外想問問你,你從日本訂的素子測距器和3軸加速度傳感器大約要多少錢呢,是否只付一次運費?從日本運來是否很貴呢?
我也只是從你的網誌第一次知道有素子測距器這東西呢,你有否試過它的性能呢?

Pacess 提到...

是呀!真的平靚正架!連郵費都係 HK$150 左右,可惜已經絕版...。

果次我一次買左幾樣野,成 HK$1400,當中有兩塊 ATmega-128、PSD 素子測距 Sensor 及三軸加速度 Sensor。我晌 Tsukumo 買既,所以郵費好貴,應該係 HK$500 左右,而 ATmega-128 係賣 HK$280 左右,所以兩粒 Sensor 應該平均 HK$100 左右。如果依家訂會平d,一來 Yen 平左,二來有間叫 DankeDanke 的公司可以幫人轉寄貨物出(日本)國,運費平好多,分分鐘 HK$100 就可以~

iRobot 提到...

嘩!$900貨要$500元運費真的不便宜啊!
我覺得當中最抵買的是那個3軸加速器star ACA302,因它有類似Wii遙控手制用緊的Analog Devices adxl 330的功能,而且價錢也只是2百多元。其次便是那較少見 sharp 的 psd 了。至於 atmega128 的價錢也算合理。你可否發一個較大的 atmega128照片讓我看看呢?

iRobot 提到...

忘了問你關於C語言的問題。
1. 8bit RISC atmega128 用 Winavr作編譯,是否也可以像CQ7144A一樣,開32位元的變量的?如果可以是怎樣寫的?

2. 這種(unsigned short)(iPortData)是否標準的C語言寫法?是否可用相同方法把16位元的值抄至2個8位元的變量。

Pacess 提到...

我的 ATmega-128 是日本 Best Technology (http://www.besttechnology.co.jp/goods/cpu/index.htm#BTC068) 製的,圖片如下:

http://www.besttechnology.co.jp/goods/goodlist/BTC068-1.png
http://www.besttechnology.co.jp/goods/goodlist/BTC068-2.png

------------------
32-Bits 類型是有的,你可以使用 unsigned long int 或簡單點 uint32_t

------------------
PORTA = (unsigned short)(iPortData) 是標準的 C 語言寫法,它的意思是把 iPortData 以 unsigned short 的類型儲存到 PORTA 內。而 PORTA 通常都是所指定的類型,在這裡即是 unsigned short。

這個方法可以同樣地把 16-Bits 的值設定到 8-Bits 的變量。例如:

int iValue = 1024;
char cValueLo, cValueHi;

cValueLo = (char)iValue;
cValueHi = (char)(iValue>>8);