|
|||||||||||
| 技術(shù)交流 | 電路欣賞 | 工控天地 | 數(shù)字廣電 | 通信技術(shù) | 電源技術(shù) | 測控之家 | EMC技術(shù) | ARM技術(shù) | EDA技術(shù) | PCB技術(shù) | 嵌入式系統(tǒng) 驅(qū)動編程 | 集成電路 | 器件替換 | 模擬技術(shù) | 新手園地 | 單 片 機 | DSP技術(shù) | MCU技術(shù) | IC 設(shè)計 | IC 產(chǎn)業(yè) | CAN-bus/DeviceNe |
一次程序編寫筆記:簡潔的提示音程序(附代碼及說明) |
| 作者:winsu 欄目:單片機 |
=====前提===== 有些項目要驅(qū)動蜂鳴器,復(fù)雜點時,蜂鳴器就有好幾種鳴響方式。 如"bi------"長鳴; "bi.bi.bi."短促提示音; "bi.........bi.........."慢的提示音; 用單片機控制蜂鳴發(fā)出滿足以上要求當然并不是難事。但要做到最簡潔,所用資源最小,卻是考人的。 本人開始所寫程序較長,近來重寫程序,用大半天時間分析提示音,終于可用最簡潔的程序?qū)崿F(xiàn)相同的功能。 =====題目===== 總結(jié)一下,出個題目,考一下大家的編寫程序能力。 用單片機驅(qū)動蜂鳴器,要求蜂鳴器響時間與間隔時間可任意設(shè)定。用一函數(shù)實現(xiàn),參數(shù)是時間設(shè)置,返回蜂鳴器開關(guān)值。如: CHAR soud_pulse_gap(CHAR on, CHAR off) { ... } on是蜂鳴器響時間,off是關(guān)時間,返回蜂鳴器當前開關(guān)狀態(tài)。該函數(shù)在主程序中每隔例如30ms執(zhí)行一次。假設(shè)已經(jīng)有蜂鳴器驅(qū)動函數(shù): void soud_on(CHAR on); 則在系統(tǒng)中這樣引用: void main(void) { ......; soud_on(soud_pulse_gap(1, 3)); //其他程序執(zhí)行30ms ......; } 以上程序?qū)崿F(xiàn)“響30ms停90ms響30ms停90ms......"的功能。 請各位大俠寫出函數(shù)CHAR soud_pulse_gap(CHAR on, CHAR off)的內(nèi)容。遲點本人會附上自己寫的。 =====程序===== 用簡潔的方法寫出發(fā)音函數(shù),其實只有兩句,不知是不是最簡單的。 程序中涉及以下定義: typedef unsigned CHAR u8; typedef unsigned int u16; “bi.bi.bi”提示音的產(chǎn)生,參數(shù)on為響時間,off為間隔,返回聲音的開或關(guān) u8 sd_pulse_gap(u8 on, u8 off) { static u16 cnt; return ((cnt++ % (on + off)) < on); } 聲音的開與關(guān),我使用AVR單片機,用CTC方式產(chǎn)生音頻 void sd_audio_on(u8 on) { ......; } 在程序中可象上面所說的引用 void main(void) { ......; sd_audio_on(soud_pulse_gap(1, 3)); //其他程序執(zhí)行25ms ......; } =====原理===== 或許有些人對這句程序: return ((cnt++ % (on + off)) < on); 有不明白之處,其實如果不作注釋,甚至沒有相關(guān)說明文檔,時間長后自己也記不起了。 首先我用些時間分析一下聲音的規(guī)律,在我的項目中有幾種聲音模式,用圖形把它畫出來,如下圖: ![]() Excel文件:http://bbs.21ic.com/upfiles/img/200611/2006111002058205.rar 其中T0是長鳴,T6是不響。 這是在excel中畫的,并把它數(shù)字化,最后就可轉(zhuǎn)化成程序 [ 如果程序都這樣簡單,低手立即變高手了 :) 原理基本過程是這樣:我們需要一個計數(shù)器來作為節(jié)拍,其實就象單片機中的時鐘。然后把這個“時鐘”進行“分頻”,再根據(jù)需要在某處為“1”某處為“0”,“1”即響;“0”即停。 第一行紅色數(shù)字就是”時鐘“,每個波形圖上面的藍色數(shù)字就是”分頻“后的結(jié)果,面下面的黑色數(shù)字是最后結(jié)果。也就是((cnt++ % (on + off)) < on)得出的結(jié)果。 =====應(yīng)用===== 要實現(xiàn)圖中T0~T6,可用以下的程序,這里用“緩沖”簡化程序,“農(nóng)民講習(xí)所”的拿手好戲(若說得不對,請勿見怪) 提示音數(shù)據(jù),7種提示音,包括長鳴與不響.第1列是鳴(1=25ms),第2列是滅(1=25ms) const u8 sd_tone][7][2] = { { 11,0 }, { 1,2 }, { 1,3 }, { 2,4 }, { 2,5 }, { 1,10 }, { 0,11 }, }; T0~T6各種提示音模式 void sd_main(u8 tone) { sd_audio_on(sd_pulse_gap(sd_tone[tone][0], sd_tone[tone][1])); } 也可用一維數(shù)據(jù)代替二維數(shù)據(jù)。 =====總結(jié)===== 再啰嗦一下,重寫一次程序,可”長一智“。 1)多用算法,少用”程序“; 2)寫程序前先分析,可借助一些自己熟悉的工具。 3)適當用”緩沖“,可簡化程序。 ...... * - 本貼最后修改時間:2006-11-10 0:36:47 修改者:winsu |
| 2樓: | >>參與討論 |
| 作者: conwh 于 2006/11/9 1:01:00 發(fā)布:
這里拽的人是越來越多了 |
|
| 3樓: | >>參與討論 |
| 作者: IceAge 于 2006/11/9 1:28:00 發(fā)布:
不用這么麻煩吧。 用狀態(tài)機的原理: SWITCH (status) { case 0: break; // stop; case 1: sound_on(); // 響 30 ms status++; break; case 2: sound_off(); timer = SOMEVALUE; //or from an array, 停 N ms status++; break; case 3: // delay for off timer--; if (timer != 0) break; sound_on(); timer = ANOTHERVALUE; //or from an array, 響 N ms status++; break; case 4: //delay for on ... status -= 2; //goto status 2 原理大致如此, 細節(jié)和形式可以不同,例如如果僅僅幾種聲音,所有延時都在 SWITCH-case 里,如果需要靈活性,那么可以使用數(shù)組甚至隊列。 又比如: case 4: case 5: case 6: status++; break; case 7: sound_off() // delay 120 ms |
|
| 4樓: | >>參與討論 |
| 作者: wangkj 于 2006/11/9 8:15:00 發(fā)布:
又不是多任務(wù),用for循環(huán)就得了。 復(fù)雜點就用中斷,計是器 |
|
| 5樓: | >>參與討論 |
| 作者: zhiwei 于 2006/11/9 9:16:00 發(fā)布:
這也太復(fù)雜了吧 用一個8bit或16bit位數(shù)據(jù)來移位輸出就可以了,以30mS為時基來中斷處理就可以了,占用CPU很少。30mS的定時由系統(tǒng)的Tick提供。 |
|
| 6樓: | >>參與討論 |
| 作者: 農(nóng)民講習(xí)所 于 2006/11/9 9:30:00 發(fā)布:
簡單的 unsigned CHAR code cBZTime[]={ 3,1, //on,off 3,1, ....... 0 }; unsigned CHAR mTaskId; unsigned CHAR mTimer; void BZ_Loop(void) { if( 系統(tǒng)30MS到 ){ if( mTimer ){ //有BZ任務(wù) if( --mTimer == 0 ){ //改變輸出狀態(tài) mTimer = cBZTime[++mTaskId]; IO_BZ_Change(); } } } } void BZ_On(void) { mTaskId=0; mTimer = cBZTime[0]; } void BZ_Off(void) { mTimer = 0; } 所有功能執(zhí)行都在狀態(tài)變化時刻執(zhí)行,外部程序有最大執(zhí)行時間。 * - 本貼最后修改時間:2006-11-9 9:32:35 修改者:農(nóng)民講習(xí)所 |
|
| 7樓: | >>參與討論 |
| 作者: xwj 于 2006/11/9 10:17:00 發(fā)布:
哈哈,“響30ms停90ms響30ms停90ms......”LZ你自己聽過效果嗎? 很簡單的東西,而且一般是幾長幾短的響,誰會這樣響去? 象2這種小東西, 不是接近0資源占用的都不是好程序 |
|
| 8樓: | >>參與討論 |
| 作者: winsu 于 2006/11/9 11:52:00 發(fā)布:
感謝各位回復(fù) 農(nóng)民講習(xí)所也來了,用"緩沖法"來簡化程序,我可是學(xué)你的. conwh: 哪里看得出我"拽"? xwj: 我說的有什么錯處嗎?請?zhí)岢?我作出修改.我是指寫一個任何方式響的程序,至于“響30ms停90ms響30ms停90ms......”只是例子,效果如何就看情況了.我的應(yīng)用并不是這樣,但只是時間不同. zhiwei: 不用中斷,計時器等資源. |
|
| 9樓: | >>參與討論 |
| 作者: NE5532 于 2006/11/9 12:26:00 發(fā)布:
又沒說是多任務(wù)系統(tǒng)啊 開,延遲,關(guān),延遲……可否? |
|
| 10樓: | >>參與討論 |
| 作者: winsu 于 2006/11/9 13:58:00 發(fā)布:
這只是項目中的一個函數(shù) 不管是否多任務(wù),反正單片機不是只做這項工作. 它越省就越好. 正如xwj所說: "象2這種小東西, 不是接近0資源占用的都不是好程序" |
|
| 11樓: | >>參與討論 |
| 作者: huangqi412 于 2006/11/9 17:55:00 發(fā)布:
高人真多,學(xué)習(xí)了 |
|
| 12樓: | >>參與討論 |
| 作者: oyggj 于 2006/11/9 18:39:00 發(fā)布:
這個有意思. 這個有意思. |
|
| 13樓: | >>參與討論 |
| 作者: conwh 于 2006/11/9 18:55:00 發(fā)布:
拽的來源: 考者,為先人、長者和智者;被考者為學(xué)生。LZ出個簡單題目來考大家,難道不是“拽”,呵呵。 |
|
| 14樓: | >>參與討論 |
| 作者: happystar 于 2006/11/9 20:47:00 發(fā)布:
恩,我們這里屬于干凈的一片天。 我在單位研發(fā)部工作,在這里大家談?wù)摰亩际羌夹g(shù),像我們這些小輩們有不懂的地方只管問老工程師。每天辦公室里就是幾壺?zé)崴筒枞~。大家以做技術(shù)為樂,很是清閑。老板也是比較尊重我們的,不像對待其他部門的人一樣。他也是做技術(shù)出生,只不過現(xiàn)在沒時間干這些拉。他一有時間就過來和我們談技術(shù)什么的,還經(jīng)常談他以前做過的項目怎樣怎樣。 嘿嘿,我本來是個比較內(nèi)向的人,我覺得自己正適合這樣的工作?傊杏X我們這一行少了社會的紛雜?吹竭@個帖子,我也感覺這邊也很純潔。 嘿嘿,我語文不好,不回組織語言,大家理解我意思就行拉 |
|
| 15樓: | >>參與討論 |
| 作者: IceAge 于 2006/11/9 21:30:00 發(fā)布:
conwh 老弟不必如此。技術(shù)討論,如同 happystar 所說, 應(yīng)單純些,更何況 winsu 還寫了那么長。 就 “響30ms停90ms響30ms停90ms“而言,最簡潔我想莫過于采用 state machine, 可以不使用任何條件判斷,C 下面用 SWITCH-case 不算明顯,匯編下使用散轉(zhuǎn)非常簡潔。此塊每 30 ms 進入一次: SWITCH (state) { case 0: break; case 1: sound_on(); state++; break; case 2: sound_off(); case 3: state++; break; case 4: state =1; break; 程序行數(shù)雖比所長多,但更直截了當。程序任何地方可以通過 state = 1 啟動,state = 0 停止。 |
|
| 16樓: | >>參與討論 |
| 作者: winsu 于 2006/11/9 22:44:00 發(fā)布:
關(guān)于“考” 或許我用“考”字的語氣太重,請conwh勿太在意。我查了一下字典,并沒說明要先人、長者和智者考學(xué)生的。 并且,我有資格考別人,特別是比我年齡小的。但“農(nóng)民講習(xí)所”等我就沒資格考了。 這單純是技術(shù)討論,請勿涉及以個人人格問題,如果我用詞不當,請指出,我會改過。 |
|
| 17樓: | >>參與討論 |
| 作者: winsu 于 2006/11/10 0:17:00 發(fā)布:
我寫的程序 這是我寫的程序: u8 sd_pulse_gap(u8 on, u8 off) { static u16 cnt; return ((cnt++ % (on + off)) < on); } 更詳細說明請看樓主位置原文 * - 本貼最后修改時間:2006-11-10 12:56:42 修改者:winsu |
|
| 18樓: | >>參與討論 |
| 作者: abszero 于 2006/11/10 12:53:00 發(fā)布:
頂住了看看 |
|
|
|
| 免費注冊為維庫電子開發(fā)網(wǎng)會員,參與電子工程師社區(qū)討論,點此進入 |
Copyright © 1998-2006 m.58mhw.cn 浙ICP證030469號 |