|
|||||||||||
| 技術(shù)交流 | 電路欣賞 | 工控天地 | 數(shù)字廣電 | 通信技術(shù) | 電源技術(shù) | 測(cè)控之家 | EMC技術(shù) | ARM技術(shù) | EDA技術(shù) | PCB技術(shù) | 嵌入式系統(tǒng) 驅(qū)動(dòng)編程 | 集成電路 | 器件替換 | 模擬技術(shù) | 新手園地 | 單 片 機(jī) | DSP技術(shù) | MCU技術(shù) | IC 設(shè)計(jì) | IC 產(chǎn)業(yè) | CAN-bus/DeviceNe |
《角度測(cè)量器》C程序范例 |
| 作者:ocon 欄目:單片機(jī) |
這幾天呆在窩里無(wú)聊,做了個(gè)小禮物送給搞機(jī)械的朋友,貼出來(lái)給新人看看: /* 《角度測(cè)量器》 用光電編碼器測(cè)量角度,每個(gè)脈沖為0.72度。 測(cè)量范圍:-198.0~450.0度 為保證不錯(cuò)過(guò)脈沖,計(jì)數(shù)用電平跳變中斷實(shí)現(xiàn),盡量加快處理過(guò)程。 數(shù)碼管掃描顯示和數(shù)據(jù)換算在主循環(huán)實(shí)現(xiàn)。 譯碼器用10米長(zhǎng)5芯屏蔽線與數(shù)顯器的兩片74HC595連接。 MCU為12F629,使用內(nèi)部4兆R(shí)C振蕩和內(nèi)部復(fù)位功能。 LED燈顯示工作狀態(tài),平時(shí)長(zhǎng)亮,收到光電編碼器脈沖時(shí)暫滅。 經(jīng)驗(yàn)教訓(xùn):有些早期批號(hào)74HC595在3.3V下會(huì)發(fā)生數(shù)據(jù)異常移位。 完成時(shí)間:2006年1月31日 編譯器:CCSC V3.182 程序版本:V1.0 南寧?仉娮佑邢薰 http://www.ocon.cn/ 作者:Wind */ #include "12f629.h" #use delay(CLOCK=4000000,RESTART_WDT) #use fast_io(A) #define NO 2 //連接74HC595的個(gè)數(shù) #define CPR 72 //光電編碼器分辨率 #define ZO 275 //歸零位 #define GPIO 0x5 //GP口地址 #bit DOUT=GPIO.0 #bit CLK =GPIO.1 #bit INA =GPIO.2 #bit INB =GPIO.3 #bit LED =GPIO.4 #bit STR =GPIO.5 int led_data[2]; //緩存74HC595顯示數(shù)據(jù) int bcd[5]={0,0,0,0,0}; //5位BCD碼 int led_bit=0; //當(dāng)前顯示位 SHORT fu=0; //負(fù)號(hào)標(biāo)志 LONG count; //16位計(jì)數(shù)器 int const segs[11]={0b11111100,0b0110000.html">100000,0b11011010,0b11110010,0b01100110,0b10110110,0b10111110,0b1110000.html">100000,0b11111110,0b11110110,0b00000000}; int const digs[4]={0b01111111,0b10111111,0b11011111,0b11101111}; //int16到5位BCD的轉(zhuǎn)換 void int16_to_bcd5(LONG counter, int * bcd5) { const LONG c[5]={10000.html">10000,1000,100,10,1}; int i; LONG k; for(i=0;i<5;i++) { k=0; while(counter>=c[i]) { counter-=c[i]; ++k; } bcd5[i]= k; } } //將數(shù)據(jù)寫(xiě)入74HC595 void out_595(int* eo) { int i; CLK=0; STR=0; for(i=1;i<=NO*8;++i) { if((*(eo)&0x01)==0) //將最低位輸出到DOUT DOUT=0; else DOUT=1; rotate_right(eo,NO); //數(shù)組循環(huán)右移一位 CLK=1; CLK=0; } STR=1; //輸出到數(shù)碼管 STR=0; } //LED數(shù)碼管譯碼顯示 void out_led(int c) { led_data[1]=0xf0; out_595(led_data); //數(shù)碼管消隱 led_data[0]=segs[bcd[c]]; led_data[1]=digs[c]; if(led_bit==2) bit_set(led_data[0],0); //顯示小數(shù)點(diǎn) if(fu&&(led_bit==0)) bit_set(led_data[0],1); //顯示負(fù)號(hào) out_595(led_data); //刷新數(shù)碼管數(shù)據(jù) } //EXT中斷處理,根據(jù)轉(zhuǎn)動(dòng)方向(脈沖相位)加減計(jì)數(shù) #int_ext get_data() { if(bit_test(INB,0)&&(count<900)) //A相跳高時(shí),若B相為高則加, count++; if(!bit_test(INB,0)&&(count>0)) //B相為低則減 count--; LED=1; } //主程序 void main() { count =ZO; //角度零位值 set_tris_a(0xC); //初始化IO口 setup_comparator(NC_NC_NC_NC); //關(guān)閉比較器,全部設(shè)成IO disable_interrupts(GLOBAL); //關(guān)總中斷 ext_int_edge(L_TO_H); //設(shè)置成上跳沿觸發(fā)中斷 enable_interrupts(INT_EXT); //開(kāi)EXT中斷 enable_interrupts(GLOBAL); //開(kāi)總中斷 while (1) { int i; LONG con; LED=0; if(count>=ZO) //負(fù)數(shù)處理 { fu=0; //負(fù)數(shù)標(biāo)志 con=count-ZO; } else { fu=1; con=ZO-count; } int16_to_bcd5(con*CPR,bcd); if(con*CPR<10000.html">10000) //消去數(shù)碼管左邊多余的零,節(jié)電 bcd[0]=10; if(con*CPR<1000) bcd[1]=10; //數(shù)碼管掃描循環(huán),每掃100次跳出重新計(jì)算一次BCD數(shù)據(jù) for(i=1;i<=100;i++) { if(i!=1) //若剛忙完BCD運(yùn)算,則免去本次延時(shí)以提升顯示效果 delay_us(500); out_led(led_bit); led_bit++; if(led_bit>=4) //共掃描4位數(shù)碼管 led_bit=0; } } } * - 本貼最后修改時(shí)間:2006-2-11 23:56:33 修改者:ocon |
| 2樓: | >>參與討論 |
| 作者: ocon 于 2006/2/1 11:48:00 發(fā)布:
電路圖1
|
|
| 3樓: | >>參與討論 |
| 作者: ocon 于 2006/2/1 11:51:00 發(fā)布:
電路圖2
|
|
| 4樓: | >>參與討論 |
| 作者: 旋風(fēng)羊 于 2006/2/6 22:41:00 發(fā)布:
好東西收下 |
|
| 5樓: | >>參與討論 |
| 作者: 陳雙君 于 2006/2/9 18:39:00 發(fā)布:
你圖都不給我看一下的啊. 你圖都不給我看一下的。 |
|
| 6樓: | >>參與討論 |
| 作者: ZHOUYH 于 2006/2/10 20:31:00 發(fā)布:
好貼呀! |
|
| 7樓: | >>參與討論 |
| 作者: ocon 于 2006/2/11 23:50:00 發(fā)布:
譯碼器
|
|
| 8樓: | >>參與討論 |
| 作者: ocon 于 2006/2/11 23:51:00 發(fā)布:
數(shù)顯器
|
|
| 9樓: | >>參與討論 |
| 作者: ocon 于 2006/2/11 23:54:00 發(fā)布:
整體
|
|
| 10樓: | >>參與討論 |
| 作者: xymxym 于 2006/2/13 14:37:00 發(fā)布:
好貼!頂! 沖著樓主正月之際還在埋頭苦干的精神就該頂,更何況貼于此分享更該頂!頂頂頂.... ^_^ |
|
| 11樓: | >>參與討論 |
| 作者: 蘭天白云 于 2006/2/15 20:53:00 發(fā)布:
74HC595的驅(qū)動(dòng)能力很強(qiáng)嗎? |
|
| 12樓: | >>參與討論 |
| 作者: ocon 于 2006/2/16 2:23:00 發(fā)布:
和PIC差不多,驅(qū)動(dòng)幾個(gè)數(shù)碼管足夠了。 |
|
| 13樓: | >>參與討論 |
| 作者: jackwu 于 2006/2/16 14:12:00 發(fā)布:
rotate_right()函數(shù)內(nèi)容? rotate_right(eo,NO); //數(shù)組循環(huán)右移一位 |
|
| 14樓: | >>參與討論 |
| 作者: ocon 于 2006/2/16 18:41:00 發(fā)布:
CCSC的內(nèi)建函數(shù) Syntax: rotate_right (address, bytes) Parameters: address is a pointer to MEMORY, bytes is a count of the NUMBER of bytes to work with. Returns: undefined Function: Rotates a bit through an array or structure. The address may be an array identifier or an address to a byte or structure (such as &data). Bit 0 of the lowest BYTE in RAM is considered the LSB. Examples: struct { int cell_1 : 4; int cell_2 : 4; int cell_3 : 4; int cell_4 : 4; } cells; rotate_right( &cells, 2); rotate_right( &cells, 2); rotate_right( &cells, 2); rotate_right( &cells, 2); // cell_1->4, 2->1, 3->2 and 4-> 3 |
|
| 15樓: | >>參與討論 |
| 作者: liao_43 于 2006/2/17 22:06:00 發(fā)布:
我覺(jué)得你這個(gè)測(cè)量角度方法,響應(yīng)速度不是很快. 我估算了一下,在不丟失脈沖下,光電旋轉(zhuǎn)編碼器最大的轉(zhuǎn)速為10轉(zhuǎn)每秒. |
|
| 16樓: | >>參與討論 |
| 作者: ocon 于 2006/2/18 8:33:00 發(fā)布:
有錢(qián)途!你很認(rèn)真。這個(gè)東西后來(lái)進(jìn)行了改進(jìn),速度已不成問(wèn)題 /* 《角度測(cè)量器》 用光電編碼器測(cè)量角度,每個(gè)脈沖為0.72度。 測(cè)量范圍:0.0~360.0度 為保證不錯(cuò)過(guò)脈沖,用timer1計(jì)數(shù),在電平跳變中斷里判斷轉(zhuǎn)動(dòng)方向,盡量加快處理過(guò)程。 數(shù)據(jù)換算和數(shù)碼管掃描顯示在主循環(huán)中實(shí)現(xiàn)。 譯碼器用10米長(zhǎng)5芯屏蔽線與數(shù)顯器的兩片74HC595連接。 MCU為12F629,使用內(nèi)部4兆R(shí)C振蕩和內(nèi)部復(fù)位功能。 經(jīng)驗(yàn):有些早期批號(hào)74HC595在3.3V下會(huì)發(fā)生數(shù)據(jù)異常移位。 編譯器:CCSC V3.182 程序版本: V1.0 2006年1月31日 測(cè)量范圍為-198~450度 V1.1 2006年2月1日 測(cè)量范圍改成0.0~360度,循環(huán)復(fù)零,增加四舍五入 V1.2 2006年2月2日 增加絕對(duì)零位Z檢測(cè) v1.3 2006年2月10日 為了增加精度用齒輪將分辨率放大6.4倍,取消零位Z檢測(cè), 改用timer1計(jì)數(shù)以提高速度,通過(guò)提取差值來(lái)計(jì)算角度。為避免在兩次讀取timer1 期間發(fā)生換向而導(dǎo)致計(jì)算錯(cuò)誤,將計(jì)算工作移到掃描循環(huán)中進(jìn)行以加快速度。 因機(jī)械的慣性,換向之前定會(huì)停一段時(shí)間,只要掃描周期小于此停止時(shí)間就可保證精度。 南寧?仉娮佑邢薰 http://www.ocon.cn/ 作者:Wind */ #include "12f629.h" #use delay(CLOCK=4000000,RESTART_WDT) #use fast_io(A) #define NO 2 //連接74HC595的個(gè)數(shù) #define CPR 72 //36000/500光電編碼器分辨率 #define GPIO 0x5 //GP口地址 #define WPU 0x95 // #define OSCCAL 0x90 // #bit DOUT=GPIO.0 #bit CLK =GPIO.1 #bit INA =GPIO.2 #bit INB =GPIO.3 #bit STR =GPIO.4 #bit INZ =GPIO.5 int led_data[2]; //緩存74HC595顯示數(shù)據(jù) int bcd[5]={11,11,11,11,11}; //5位BCD碼 int led_bit=0; //當(dāng)前顯示位 LONG count=0; //16位計(jì)數(shù)器 LONG count_new=0; //計(jì)數(shù)器新值 LONG count_old=0; //計(jì)數(shù)器舊值 SHORT direct=1; //轉(zhuǎn)動(dòng)方向 int const segs[13]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,0x0,0x92,0x2}; int const digs[4]={0x7f,0xbf,0xdf,0xef}; //int16到5位BCD的轉(zhuǎn)換 void int16_to_bcd5(LONG counter, int * bcd5) { const LONG c[5]={10000.html">10000,1000,100,10,1}; int i; LONG k; for(i=0;i<5;i++) { k=0; while(counter>=c[i]) { counter-=c[i]; ++k; } bcd5[i]= k; } } //將數(shù)據(jù)寫(xiě)入74HC595 void out_595(int* eo) { int i; CLK=0; STR=0; for(i=1;i<=NO*8;++i) { if((*(eo)&0x01)==0) //將最低位輸出到DOUT DOUT=0; else DOUT=1; rotate_right(eo,NO); //數(shù)組循環(huán)右移一位 CLK=1; delay_cycles(2); CLK=0; } STR=1; //輸出到數(shù)碼管 delay_cycles(2); STR=0; } //LED數(shù)碼管譯碼顯示 void out_led(int c) { led_data[1]=0xf0; out_595(led_data); //數(shù)碼管消隱 led_data[0]=segs[bcd[c]]; led_data[1]=digs[c]; if(led_bit==2) bit_set(led_data[0],0); //顯示小數(shù)點(diǎn) out_595(led_data); //刷新數(shù)碼管數(shù)據(jù) } //計(jì)算計(jì)數(shù)器差值 LONG get_margin(LONG c_new,LONG c_old) { if(c_new<c_old) //如果計(jì)數(shù)器溢出翻轉(zhuǎn) return(65536-c_old+c_new); else return(c_new-c_old); } //根據(jù)差值、舊角度值、轉(zhuǎn)動(dòng)方向計(jì)算新的角度值 LONG get_count(LONG c,LONG ct,SHORT d) { if(d==1) //如果正轉(zhuǎn) { ct=c+ct; if(ct>=3200) ct=ct%3200; } else //如果反轉(zhuǎn) { if(c>ct) ct=3200-(c-ct); else ct=ct-c; } return(ct); } //EXT中斷處理,根據(jù)脈沖相位判斷轉(zhuǎn)動(dòng)方向 #int_ext void get_data() { if(bit_test(INB,0)) //A相跳高時(shí),若B相為高則正轉(zhuǎn) direct=1; else //B相為低則反轉(zhuǎn) direct=0; } //主程序 void main() { disable_interrupts(GLOBAL); //關(guān)總中斷 setup_comparator(NC_NC_NC_NC); //關(guān)閉比較器,全部設(shè)成IO port_a_pullups(FALSE); *OSCCAL=0xff; //全速運(yùn)行 set_tris_a(0b00101100); //初始化IO口 ext_int_edge(L_TO_H); //設(shè)置成上跳沿觸發(fā)中斷 setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1); set_timer1(0); enable_interrupts(INT_EXT); //開(kāi)EXT中斷 enable_interrupts(GLOBAL); //開(kāi)總中斷 while (1) { LONG cou; LONG margin; restart_wdt(); count_new=get_timer1(); //獲得新的計(jì)數(shù)值 margin=get_margin(count_new,count_old); //獲得差值 count_old=count_new; //刷新舊的計(jì)數(shù)值 count=get_count(margin,count,direct); //獲得新的角度值 cou=(count* |
|
| 17樓: | >>參與討論 |
| 作者: ocon 于 2006/2/18 8:40:00 發(fā)布:
這個(gè)小工具用于校準(zhǔn)大型印刷機(jī)。 |
|
| 18樓: | >>參與討論 |
| 作者: liao_43 于 2006/2/18 23:49:00 發(fā)布:
我覺(jué)得你的新的程序里還有點(diǎn)問(wèn)題. "因機(jī)械的慣性,換向之前定會(huì)停一段時(shí)間,只要掃描周期小于此停止時(shí)間就可保證精度" 我覺(jué)得齒輪嚙合會(huì)產(chǎn)生抖動(dòng),特別是齒輪在慢速轉(zhuǎn)動(dòng)時(shí),會(huì)使光電編碼器在極短時(shí)間內(nèi)來(lái)回?cái)[動(dòng),而你主程序處理的時(shí)間比較長(zhǎng),有可能漏掉脈沖. |
|
| 19樓: | >>參與討論 |
| 作者: ocon 于 2006/2/19 7:06:00 發(fā)布:
已經(jīng)經(jīng)過(guò)現(xiàn)場(chǎng)測(cè)試,目前沒(méi)有發(fā)現(xiàn)你說(shuō)的抖動(dòng)現(xiàn)象。 這個(gè)東西在檢修機(jī)器的時(shí)候用,機(jī)器運(yùn)行在人工點(diǎn)動(dòng)方式,效果很好。如果要處理好極短時(shí)間內(nèi)的頻繁換向,就不能用一般的單片機(jī),這樣成本會(huì)高很多,這是送給好友的小禮物,不能做得太貴了。 |
|
| 20樓: | >>參與討論 |
| 作者: liao_43 于 2006/2/19 14:35:00 發(fā)布:
我前一段時(shí)間也做了一個(gè)角度測(cè)量器. 用的光電編碼器是2000P/R,16F74,20MHZ,在頻繁換向時(shí),檢測(cè)脈波的速度可以達(dá)到50KHz,不過(guò)我覺(jué)得這個(gè)速度不理想.所以一直在想,怎樣才能做到檢測(cè)速度達(dá)到5MHZ.因?yàn)槲矣幸粋(gè)光電編碼器是81000P/R的,一直沒(méi)有用上. 今天早上起床時(shí),靈感一來(lái),想到一個(gè)辦法,用12F629,在頻繁換向時(shí),也可以做到5MHz的檢測(cè)速度(理論上).有空時(shí),我再做一個(gè)試試,驗(yàn)證一下. |
|
| 21樓: | >>參與討論 |
| 作者: ocon 于 2006/2/20 6:47:00 發(fā)布:
有什么辦法?說(shuō)說(shuō)看 我試過(guò)在換向中斷里記錄timer1的即時(shí)值,但在角度刷新之前換多幾次就沒(méi)用了,沒(méi)那么多RAM來(lái)緩存。 |
|
| 22樓: | >>參與討論 |
| 作者: 陳雙君 于 2006/2/28 10:50:00 發(fā)布:
電路圖呢? 電路圖呢? 我看不懂的。 |
|
| 23樓: | >>參與討論 |
| 作者: kowajw 于 2006/3/11 15:48:00 發(fā)布:
re:《角度測(cè)量器》C程序范例 關(guān)注 |
|
| 24樓: | >>參與討論 |
| 作者: 長(zhǎng)天秋水 于 2007/1/10 19:12:00 發(fā)布:
蠻有用的 謝謝樓主啊 |
|
|
|
| 免費(fèi)注冊(cè)為維庫(kù)電子開(kāi)發(fā)網(wǎng)會(huì)員,參與電子工程師社區(qū)討論,點(diǎn)此進(jìn)入 |
Copyright © 1998-2006 m.58mhw.cn 浙ICP證030469號(hào) |