遼寧工業大學 單片機原理及接口技術課程設計(論文) 題目:簡易函數信號發生器設計 院(系): 電氣工程學院 專業班級:自動化134班 學 號:130*2115 學生姓名:宋*鵬 指導教師:(簽字) 課程設計(論文)任務及評語 院(系):電氣工程學院 教研室:自動化 | | | | | | | | | 課題完成的功能、設計任務及要求、技術參數 實現功能 (1)設計一個基于單片機的信號發生器; (2)能夠輸出四種波形,用按鍵控制輸出正弦波、三角波、方波、鋸齒波,輸出波形時分別對應指示燈亮; (3)能夠通過按鍵進行波形參數設置; (4)能夠通過顯示模塊輸出波形的主要參數,如頻率。 設計任務及要求 1、分析系統功能,選擇控制方案,繪制系統組成框圖; 2、設計系統的硬件電路,包括單片機最小系統、指示燈電路、鍵盤電路和顯示電 路以及完整的電路,并進行實物的制作; 3、編寫相應的軟件,寫完控制系統的控制要求,并編寫完整程序; 4、上機調試、完善程序; 5、按學校規定格式,撰寫、打印設計說明書一份;設計說明書應在4000字以上。 技術參數 波形幅值5V,頻率1Hz-50Hz之間。 | | 1、布置任務,查閱資料,確定系統設計方案(2天) 2、系統硬件設計及實物制作(3天) 3、系統軟件設計及編寫功能程序及調試(3天) 4、撰寫、打印設計說明書(1天) 5、驗收及答辯(1天) | | 平時:論文質量:答辯: 總成績: 指導教師簽字: 年 月 日 |
注:成績:平時20% 論文質量60% 答辯20% 以百分制計算
摘 要 本課題是采用低成本的MCS-51系列單片機構成具有高可靠性的函數信號發生器的應用設計,采用具有51內核的STC12C5A60S2單片機芯片通過單片機運算產生二進制控制信號去控制有
總線結構并且同時具有AD/DA功能的 PCF8591集成電路產生正弦波、鋸齒波、三角波、梯形波4種函數波形。 本系統以51單片機為控制核心,由電源模塊、單片機最小系統模塊、中斷鍵盤模塊、函數信號發生模塊、顯示模塊組成。通過加入按鍵電路來切換不同波形的輸出同時用相應的指示燈來表示,并且通過設置按鍵來改變頻率。在波形和頻率改變的同時通過形參之間的傳遞將此時刻的波形類型和頻率大小通過液晶LCD12864來顯示其參數的改變狀態。 用其示波器采集觀察和檢測波形的輸出,制作的實物電路簡單、操作方便、運行穩定可靠、抗干擾性強、功耗低、成本低、易實現、其頻率值精準、對采用總線結構設計信號發生器具有參考價值。
目 錄 第1章 緒論 第2章 課程設計的方案 2.1 概述 2.2 系統組成總體結構 第3章 硬件設計 3.1 單片機最小系統設計 3.2 按鍵電路 3.3 信號發生電路 3.4 顯示電路 第4章 軟件設計 4.1 系統總流程 4.2 系統子流程圖 第5章 系統測試與分析 5.1 波形種類測試與分析 5.2 頻率大小測試與分析 5.3 實物焊接與整體效果展示 第6章 課程設計總結 參考文獻 附錄Ⅰ系統總原理圖 附錄Ⅱ程序代碼 第1章 緒論近年來隨著計算機在社會領域的滲透,單片機的應用正在不斷地走向深入,同時帶動傳統函數信號發生器日新月益更新。傳統的函數信號發生器大多數采用了模擬鎖相環、數字鎖相環、小數分頻鎖相環(fractional-N PLL Synthesis)技術,但是隨著科技的進步,出現了直接數字合成(Direct Digital Synthesis-DDS)的FS技術。單片集成的DDS產品是一種可代替鎖相環的快速頻率合成器件。DDS是產生高精度、快速變換頻率、輸出波形失真小的優先選用技術。DDS以穩定度高的參考時鐘為參考源,通過精密的相位累加器和數字信號處理,通過高速D/A變換器產生所需的數字波形,這個數字波經過一個模擬濾波器后,得到最終的模擬信號波形。通過高速DAC產生數字正弦數字波形,通過帶通濾波器后得到一個對應的模擬正弦波信號。在人們認識自然、改造自然的過程中,經常需要對各種各樣的電子信號進行測量,因而如何根據被測量電子信號的不同特征和測量要求,靈活、快速的選用不同特征的信號源成了現代測量技術值得深入研究的課題。信號源主要給被測電路提供所需要的已知信號(各種波形),然后用其它儀表測量感興趣的參數。可見信號源在各種實驗應用和實驗測試處理中,它不是測量儀器,而是根據使用者的要求,作為激勵源,仿真各種測試信號,提供給被測電路,以滿足測量或各種實際需要。波形發生器就是信號源的一種,能夠給被測電路提供所需要的波形。傳統的波形發生器多采用模擬電子技術,由分立元件或模擬集成電路構成,其電路結構復雜,不能根據實際需要靈活擴展。隨著微電子技術的發展,運用單片機技術,通過巧妙的軟件設計和簡易的硬件電路,產生數字式的正弦波、方波、三角波、鋸齒等幅值可調的信號。與現有各類型波形發生器比較而言,產生的數字信號干擾小,輸出穩定,可靠性高,特別是操作簡單方便。 函數發生器亦稱信號發生器,主要作為實驗用信號源,是現今各種電子電路實驗設計應用中必不可少的儀器設備之一。目前,市場上常見的波形發生器多為純硬件的搭接而成,波形種類多為鋸齒、正弦、方波、三角等波形。用分立元件組成的函數發生器,通常是單函數發生器且頻率不高,其工作不很穩定,不易調試;用集成芯片的函數發生器,可達到較高的頻率和產生多種波形信號,但電路較為復雜且不易調試。利用單片集成芯片的函數發生器,能產生多種波形,達到較高的頻率,且易于調試;利用專用直接數字合成DDS 芯片的函數發生器,能產生任意波形并達到很高的頻率,但成本較高。 函數發生器作為一種常見的應用電子儀器設備,傳統的一般可以完全由硬件電路搭接而成,如采用555振蕩電路發生正弦波、三角波和方波的電路便是可取的路徑之一,不用依靠單片機。但是這種電路存在波形質量差,控制難,可調范圍小,電路復雜和體積大等缺點。在科學研究和生產實踐中,如工業過程控制,生物醫學,地震模擬機械振動等領域常常要用到低頻信號源。而由硬件電路構成的低頻信號其性能難以令人滿意,而且由于低頻信號源所需的RC要很大。大電阻,大電容在制作上有困難,參數的精度亦難以保證。體積大,漏電,損耗顯著更是其致命的弱點。一旦工作需求功能有增加,則電路復雜程度會大大增加。
利用單片機采用程序設計方法來產生低頻信號,其頻率底線很低。具有線路相對簡單,結構緊湊,價格低廉,頻率穩定度高,抗干擾能力強,用途廣泛等優點,并且能夠對波形進行細微調整,改良波形,使其滿足系統的要求。只要對電路稍加修改,調整程序,即可完成功能升級。
第2章 課程設計的方案2.1 概述本次設計主要是綜合應用所學知識,設計簡易函數信號發生器,能夠產生正弦波、鋸齒波、三角波、梯形波4種函數波形。并在實踐的基本技能方面進行一次系統的訓練。能夠較全面地鞏固和應用“單片機”課程中所學的基本理論和基本方法,并初步掌握小型單片機系統設計的基本方法。 應用場合:在人們認識自然、改造自然的過程中,經常需要對各種各樣的電子信號進行測量,因而如何根據被測量電子信號的不同特征和測量要求,靈活、快速的選用不同特征的信號源成了現代測量技術值得深入研究的課題。信號源主要給被測電路提供所需要的已知信號(各種波形),然后用其它儀表測量感興趣的參數。 系統功能介紹:通過按鍵切換不同波形的輸出同時相應的指示燈亮,并且通過設置按鍵調整延時函數的時間達到調節信號頻率。 2.2 系統組成總體結構本次設計系統如圖2.1所示,以51單片機為控制核心,由電源模塊、單片機最小系統模塊、中斷鍵盤模塊、函數信號發生模塊、顯示模塊組成。
圖2.1 控制結構框圖 第3章 硬件設計3.1 單片機最小系統設計單片機最小系統或者稱為最小應用系統,是指用最少的元件組成的單片機可以工作的系統。對51系列單片機來說,最小系統一般包括:單片機、晶振電路、復位電路、電源電路。 3.1.1 單片機的選擇根據需要本次設計選擇了一片與51系列兼容的STC12C5A60S2,其引腳與STC89C52相同,圖中用其89C52代替,其引腳圖如圖3.1所示。
圖3.1 CPU引腳圖 3.1.2 晶振電路晶振電路:典型的晶振取11.0592MHz(因為可以準確地得到9600波特率和19200波特率,用于有串口通訊的場合)/12MHz(產生精確的us級時間,方便定時操作)其中與晶振并聯的電容根據經驗一般選取10pF~30pF,本次設計選取了11.0592MHz的晶振和20pF的電容,本次設計原理圖中晶振兩端的連線采用了網絡標號的方法,可以使得電路比較清晰,模塊化,易于觀看,后面電路也是一樣,將不再敘述,圖中X1與單片機的19引腳相連,X2與18引腳連接,原理圖如圖3.2所示。
圖3.2 晶振電路 3.1.3 復位電路復位電路:由電容串聯電阻構成,由“電容電壓不能突變”的性質,可以知道,當系統一上電,RST腳將會出現高電平,并且這個高電平持續的時間由電路的RC值來決定。典型的51單片機當REST腳的高電平持續兩個機器周期以上就將復位,所以適當組合RC的取值就可以保證可靠的復位。一般教科書推薦C 取10uF,R取10K。當然也有其他取法的,原則就是要讓RC組合可以在RST腳上產生不少于2個機周期的高電平。至于如何具體定量計算,可以參考電路分析相關書籍。本次設計選取電容為10uF,電阻為10K。電路如圖3.3所示。
圖3.3 復位電路 3.1.4 電源電路本次課程設計中,通過外來+5V電源,接一個六角開關,當開關按下時,電流流過R1,經過LED,此時表示電路導通,加入LED燈起了提示的作用,當電源指示燈亮時表示電源接通。六角開關下端,也就是R1的上端接線觸為整個電路的VCC,圖中VCC未畫出,在此聲明,以后將不再敘述,電源電路如圖3.4所示。
圖3.4 電源電路 3.2 按鍵電路鍵盤從結構上分為獨立式鍵盤與矩陣式鍵盤。一般按鍵較少時采用獨立式鍵盤,按鍵較多時采用矩陣式鍵盤。本次設計只用三個按鍵,因此選取獨立按鍵,矩陣按鍵沒有用到故而將不介紹。 獨立式鍵盤:在由單片機組成的測控系統及智能化儀器中,用的最多的是獨立式鍵盤。這種鍵盤具有硬件與軟件相對簡單的特點,其缺點是按鍵數量較多時,要占用大量口線。圖3.5是一個利用MCS-51單片機的P2口的低三位設計的編碼鍵盤,其編碼分別為P20、P21、P22。CPU對應的I/O接口外部接了上拉電阻原因跟灌電流大小有關,其實P2口內部也有上拉電阻,這里不沖突,當按鍵沒按下時,其輸入為高電平;當某鍵被按下后,對應的I/O接口變為低電平。只要在程序中判斷I/O接口的狀態,即可知道哪個鍵處于閉合狀態。
圖3.5 按鍵電路 3.3 信號發生電路本次設計中選取PCF8591芯片作為DA轉換,其原因是因為是它具有總線接口,這樣大大節約了單片機的I/O口。本次設計芯片的接線如圖3.6,采用了經典電路,其中芯片14引腳接5V基準電壓。
圖3.6 信號發生電路 總線是Philips公司推出的新型單片機系統。它采用串行總線,主控器與外圍器件僅靠兩條線進行信息傳輸,一條稱為時鐘線(SCL),另一條位數據線(SDA)。總線單片機系統較通用單片機系統電路簡單。由普通CPU芯片同專用器件組成的系統為模擬系統,它性能穩定,價格較低,目前已得到廣泛應用。 3.4 顯示電路本次設計中顯示電路包括了兩部分,一部分為液晶LCD1284顯示其參數,另一部分為三個LED燈用來指示此時的波形種類。 3.4.1 液晶顯示電路設計中選用帶中文字庫的128X64作為參數顯示,帶中文字庫的128X64是一種具有4位/8位并行、2線或3線串行多種接口方式,內部含有國標一級、二級簡體中文字庫的點陣圖形液晶顯示模塊;其顯示分辨率為128×64,內置8192個16*16點漢字,和128個16*8點ASCII字符集。利用該模塊靈活的接口方式和簡單、方便的操作指令,可構成全中文人機交互圖形界面。可以顯示8×4行16×16點陣的漢字,也可完成圖形顯示。低電壓低功耗是其又一顯著特點。 系統中當用按鍵來切換波形和調整頻率的時候,用液晶LCD12864來顯示此時波形的種類和頻率值的大小,其引腳接線圖如圖3.7所示。
圖3.7 液晶顯示電路 3.4.2 LED顯示電路本次設計中當用其按鍵來切換波形時,除了在液晶12864上來顯示參數,還用了這個LED顯示電路,當切換到某一個波形時,與其相對應的小燈就會亮來提示現在是什么波形輸出,方便的解決了沒有用示波器采集時依然能準確判斷出輸出的波形的種類,其電路圖如圖3.8所示。
圖3.8 LED顯示電路 第4章 軟件設計4.1 系統總流程本設計上電或復位時,將默認輸出10Hz的正弦波,并開始在主程序里一直掃描按鍵程序,當檢測到有按鍵下,通過查詢P2口狀態,便知道是對應的哪個按鍵按下,并給按鍵賦上鍵值,賦完鍵值以后,立刻將P2口還原,以便下一次檢測。然后通過查詢鍵值便可知道是哪一個按鍵按下,以鍵值為標志,傳遞給相應的子程序,從而實現頻率的增減和波形的切換,將頻率的值和波形作為變量,再傳遞給相應的程序,從而可以實現在液晶LCD上顯示此時的頻率和波形,同樣當波形改變時,賦上標志位,對應的標志位用來實現LED的顯示,達到波形改變時對應的LED顯示,其系統總流程圖如圖4.1所示。
圖4.1 系統總流程圖 4.2 系統子流程圖本次設計中,由上面總流程圖中可以清晰的看出將程序進行了模塊化,分為了幾大部分,其中可以大致分為波形發生、按鍵掃描、LCD12864液晶顯示、LED顯示四部分組成。 4.2.1 波形發生設計中采用PCF8591芯片作為D/A轉換,芯片PCF8591與單片機通過總線與單片機相連,其地址端A2、A1、A0接地,基準電壓接5V電壓,其連線圖具體見圖3.6,開始時單片機通過在總線上發送一個器件地址,當PCF8591與總線上發送的這個地址相匹配時,通過總線給單片機發送一個應答信號,單片機識別到這個應答信號時將在總線上發送一個控制字,此時由于前一個地址已經與PCF8591相匹配,那么此時的控制字則用來控制PCF8591,使其進行相應的動作,當芯片收到控制字后再次給單片機發送一個應答信號表示收到,最后單片機通過總線發送數據,使其芯片進行工作。器件工作流程圖如圖4.2所示。
圖4.2 波形產生流程圖 4.2.2 按鍵掃描設計中通過中斷對按鍵進行掃描,當有按鍵下時,掃描程序中查詢P2口狀態,便可知道是對應的按鍵按下,并給按鍵賦上鍵值,賦完鍵值以后,立刻將P2口還原,以便下一次檢測。然后通過查詢鍵值,以鍵值為標志,傳遞給相應的子程序,從而實現頻率的增減和波形的切換。其按鍵掃描流程圖如圖4.3所示。
圖4.3 按鍵掃描流程圖 4.2.3 參數顯示本設計當按鍵按下時除了給按鍵賦鍵值以外,還在按鍵按下時給程序中加入了表示頻率參數的加減來和波形的切換,此時的頻率加減對應著實際頻率值,再將表示頻率和波形參數的變量通過形參傳遞給液晶顯示程序中的實參,從而實現了頻率和波形在液晶上的顯示。 與此同時,當按鍵按下時,對應的鍵值被賦值,在表示波形切換的那個賦值的鍵值程序中,我們進行了變量i++,當變量i=0時,實現正弦波輸出,i=1時,三角波輸出,i=2時鋸齒波輸出,i=3時,方波輸出,然后將i清零,如此循環,進而實現了對波形的切換,當對應的i值改變時,令其對應的I/O口變為低電平,使得LED燈發光,從而實現了不同的LED發光表示了不同的波形,由于此節比較簡單,流程圖進行省略。 第5章 系統測試與分析5.1 波形種類測試與分析通過示波器的采集,當上電復位時,觀察到的波形如圖5.1所示,此時沒有按鍵按下,觀察到此時的波形為正弦波,頻率為10Hz,與設計中的相符合,然而當仔細觀察時便可以看到正弦波并不平滑,而是有一格一格的小齒,這是因為在正弦波發生器時,一個周期只賦值了32個點,如果點數夠多,將會使得波形更加平滑,但這并不影響,可以在后波形輸出加上一個低通濾波電路,進而可以讓其波形變得平滑可觀,但是此設計中并沒有包含濾波電路。當按下波形切換按鍵時,可觀察到三角波、鋸齒波、方波波形,對應圖5.2,5.3,5.4。
圖5.1 正弦波波形圖
圖5.2 三角波波形圖
圖5.3 鋸齒波波形圖
圖5.4 方波波形圖 5.2 頻率大小測試與分析通過按鍵按下,可以調整波形頻率大小的輸出,此次測試中以正弦波為例,由圖5.1正弦波波形圖可以通過示波器測出此時的頻率為10Hz,通過按鍵調整,可以得到如圖5.5所示的頻率35Hz和圖5.6所示的頻率50Hz,在圖中可以看出與理論值大小只有很小很小的誤差,這充分展示了本設計的合理性。
圖5.5 35Hz方波波形圖
圖5.6 50Hz方波波形圖
5.3 實物焊接與整體效果展示如圖5.7與5.8展示了整體電路的顯示效果與焊接。在圖中可以通過LCD12864清晰的看到此時的波形為正弦波,頻率值為10Hz,同樣對應的紅色小燈發光,作為此時為正弦波。
圖5.7 實物顯示效果
圖5.8 實物焊接
第6章 課程設計總結本次系統以設計一個頻率可調,波形可調的信號發生器為目的。在設計中通過按鍵進行波形切換和頻率改變,并且能夠通過液晶顯示其參數的變化,相應的有其指示燈來表示此時的波形種類。 在芯片選擇上選擇具有IIC總線的D/A轉換芯片PCF8591進行數模轉換,通過對總線的操作實現與單片機的通信。此芯片與單片機只進行了兩個I/O口連接,大大節約了單片機的I/O口,在進行波形切換和頻率改變上,采用了獨立按鍵的選擇,因為涉及的按鍵比較少,這樣的選擇直觀,電路簡單,程序也方便,顯示電路中,選擇了LCD12864對參數進行顯示,雖然在成本上可能會高了些,不過讓整個設計顯得比較大氣。 程序中將各個部分的子程序進行了模塊化,使得程序清晰,條理清楚,便于修改,程序中巧妙的應用了形參和實參的傳遞將參數傳遞給子程序,實現了液晶顯示和波形改變,頻率改變時能夠達到同步,在設計過程中,遇到的問題先獨立思考,然后一頓百度,自己解決不了時再通過詢問身邊的師哥師姐得以解決。
參考文獻[1]陳貞. 簡易函數信號發生器的設計與實現[J].武漢工程職業技術學院學報,2014,(03):75-78 [2]孫鵬. 51單片機綜合學習系統——12864點陣型液晶顯示篇[J].電子制作,2008,(02):22-24 [3]羅佰綏,熊小民,熊鍇. 簡易函數信號發生器與計數器設計[J].國外電子元器件,2008,(07):49-51 [4]張曉增,趙曰峰,董鴻江.低頻信號發生器的設計[J].現代電子技術,2009,(06):1-3 [5]陶炳坤,石龍宇,黃天辰,高秀峰. 基于AT89S51和MAX038的函數信號發生器的設計[J].現代電子技術,2013,(09):165-167 [6]趙道新,李炳辰. 基于PCF8591的IIC總線多路溫度測量系統[J].制造業自動化,2013,(05):36-37+55 [7]任曉芳. PCF8591在數據采集過程中的應用[J].自動化應用,2015,(10):42-43 [8]彭志剛. 基于PCF8591簡易低頻信號發生器的設計[J].自動化與儀器儀表,2015,(11):41-42+45 [9]柴西林,劉遠聰,車瑋. 基于STC89C52的低頻信號發生器設計[J].自動化與儀器儀表,2016,(03):11-12+14 [10]羅俊杰. 單片機的簡易信號發生器的設計[J].林區教學,2013,(11):79-80 [11]江世明. 12864圖形液晶顯示模塊與51系列單片機接口技術[J].電子世界,2005,(06):35-36 [12]周劍利,郭建波,崔濤. 具有IIC總線接口的A/D芯片PCF8591及其應用[J].微計算機信息,2005,(07):150-151 [13]河北 梁廷貴. A/D芯片PCF8591原理及其應用[N]. 電子報,2005-10-23014 [14]辛阿阿,厲善亨. 基于12864液晶模塊的動態波形顯示實現方法[J].儀器儀表用戶,2010,(05):56-57 [15]李金群. 基于51單片機的12864液晶圖文顯示研究[J].機電信息,2010,(36):139-140 附錄Ⅰ
系統總原理圖 附錄Ⅱ程序代碼 程序設計 頭文件<12864.h>
- #ifndef __12864_H__
- #define __12864_H__
- #define uint unsigned int
- #define uchar unsigned char
- void mainxianshi();
- void ready();
- void write_com(unsigned char com);
- void write_date(unsigned char date);
- void lcd_pos(unsigned char X,unsigned char Y);
- void init();
- void delay(unsigned int ms) ;
- void main_sinwave();
- void main_triwave();
- void main_sawwave();
- void main_squwave();
- void main_freqwave(unsigned char i);
- #endif
- /******************************************/
復制代碼
主函數main.c 單片機源程序如下: - /* 可調頻率的信號發生器
- :針對STC12系列單片機修改定時器中斷延時補償參數
- * 1、由按鍵切換不同波形,由上下鍵增減頻率
- * 2、頻率可調范圍限定在1~50Hz,因受限于PCF8591訪問速度而無法做到很高
- *****************************************************************/
- #include
- #include "12864.H"
- #include
- unsigned char code SinWave[] = { //正弦波波表
- 127, 152, 176, 198, 217, 233, 245, 252,
- 255, 252, 245, 233, 217, 198, 176, 152,
- 127, 102, 78, 56, 37, 21, 9, 2,
- 0, 2, 9, 21, 37, 56, 78, 102,
- };
- unsigned char code TriWave[] = { //三角波波表
- 0, 16, 32, 48, 64, 80, 96, 112,
- 128, 144, 160, 176, 192, 208, 224, 240,
- 255, 240, 224, 208, 192, 176, 160, 144,
- 128, 112, 96, 80, 64, 48, 32, 16,
- };
- unsigned char code SawWave[] = { //鋸齒波表
- 0, 8, 16, 24, 32, 40, 48, 56,
- 64, 72, 80, 88, 96, 104, 112, 120,
- 128, 136, 144, 152, 160, 168, 176, 184,
- 192, 200, 208, 216, 224, 232, 240, 248,
- };
- unsigned char code SquWave[] ={ //方波波表
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255,
- };
- unsigned char fWave = 10; //波形頻率
- unsigned char code *pWave; //波表指針
- unsigned char T0RH = 0; //T0重載值的高字節
- unsigned char T0RL = 0; //T0重載值的低字節
- unsigned char T1RH = 1; //T1重載值的高字節
- unsigned char T1RL = 1; //T1重載值的低字節
- //void draw_point(uchar x,uchar y,uchar colour);
- void ConfigTimer0(unsigned int ms);
- void SetWaveFreq(unsigned char freq);
- extern void KeyScan();
- extern void KeyDriver();
- extern void I2CStart();
- extern void I2CStop();
- extern bit I2CWrite(unsigned char dat);
- sbit R_LED = P1^5;
- sbit Y_LED = P1^4;
- sbit G_LED = P1^3;
- void main()
- {
- R_LED = 0;
- Y_LED = 0;
- G_LED = 0;
- EA = 1; //開總中斷
- ConfigTimer0(1); //配置T0定時1ms
- pWave = SinWave; //默認正弦波
- SetWaveFreq(fWave); //默認頻率10Hz
- mainxianshi();
- while (1)
- {
- KeyDriver(); //調用按鍵驅動
- }
- }
- /* 按鍵動作函數,根據鍵碼執行相應的操作,keycode-按鍵鍵碼 */
- void KeyAction(unsigned char keycode)
- {
- static unsigned char i = 0;
-
- if (keycode == '1') //1鍵,切換波形
- {
- //在3種波形間循環切換
- if (i == 0)
- {
- i = 1;
- pWave = TriWave;
- main_triwave();
- R_LED= 1;
- Y_LED = 0;
- G_LED = 0;
- }
- else if (i == 1)
- {
- i = 2;
- pWave = SawWave;
- main_sawwave();
- R_LED = 0;
- Y_LED = 1;
- G_LED = 0;
- }
- else if (i == 2)
- {
- i = 3;
- pWave = SquWave;
- main_squwave();
-
- R_LED = 0;
- Y_LED = 0;
- G_LED = 1;
- }
- else
- {
- i = 0;
- pWave = SinWave;
- main_sinwave();
- }
- }
- else if (keycode == '3') //向上鍵,增加頻率
- {
- if (fWave < 1000) //達到最大值50之前可遞增頻率值
- {
- fWave++;
- SetWaveFreq(fWave);
- main_freqwave(fWave);
- }
- }
- else if(keycode == '4') //向下鍵,降低頻率
- {
- if (fWave > 1) //達到最小值1之前可遞減頻率值
- {
- fWave--;
- SetWaveFreq(fWave);
- main_freqwave(fWave);
- }
- }
- }
- /* 設置DAC輸出值,val-設定值 */
- void SetDACOut(unsigned char val)
- {
- I2CStart();
- if (!I2CWrite(0x48<<1)) //尋址PCF8591,如未應答,則停止操作并返回
- {
- I2CStop();
- return;
- }
- I2CWrite(0x40); //寫入控制字節
- I2CWrite(val); //寫入DA值
- I2CStop();
- }
- /* 設置輸出波形的頻率,freq-設定頻率 */
- void SetWaveFreq(unsigned char freq)
- {
- unsigned long tmp;
-
- tmp = (11059200/12) / (freq*32); //定時器計數頻率,是波形頻率的32倍
- tmp = 65536 - tmp; //計算定時器重載值
- tmp = tmp + 6; //修正中斷響應延時造成的誤差
- T1RH = (unsigned char)(tmp>>8); //定時器重載值拆分為高低字節
- T1RL = (unsigned char)tmp;
- TMOD &= 0x0F; //清零T1的控制位
- TMOD |= 0x10; //配置T1為模式1
- TH1 = T1RH; //加載T1重載值
- TL1 = T1RL;
- ET1 = 1; //使能T1中斷
- PT1 = 1; //設置為高優先級
- TR1 = 1; //啟動T1
- }
- /* 配置并啟動T0,ms-T0定時時間 */
- void ConfigTimer0(unsigned int ms)
- {
- unsigned long tmp; //臨時變量
-
- tmp = 11059200 / 12; //定時器計數頻率
- tmp = (tmp * ms) / 1000; //計算所需的計數值
- tmp = 65536 - tmp; //計算定時器重載值
- tmp = tmp + 5; //補償中斷響應延時造成的誤差
- T0RH = (unsigned char)(tmp>>8); //定時器重載值拆分為高低字節
- T0RL = (unsigned char)tmp;
- TMOD &= 0xF0; //清零T0的控制位
- TMOD |= 0x01; //配置T0為模式1
- TH0 = T0RH; //加載T0重載值
- TL0 = T0RL;
- ET0 = 1; //使能T0中斷
- TR0 = 1; //啟動T0
- }
- /* T0中斷服務函數,執行按鍵掃描 */
- void InterruptTimer0() interrupt 1
- {
- TH0 = T0RH; //重新加載重載值
- TL0 = T0RL;
- KeyScan(); //按鍵掃描
- }
- /* T1中斷服務函數,執行波形輸出 */
- void InterruptTimer1() interrupt 3
- {
- static unsigned char i = 0;
-
- TH1 = T1RH; //重新加載重載值
- TL1 = T1RL;
- //循環輸出波表中的數據
- SetDACOut(pWave[i]);
- i++;
- if (i >= 32)
- {
- i = 0;
- }
- }
- 按鍵keyboard.c
- #include"reg52.h"
- sbit K1 = P2^2;
- sbit K2 = P2^1;
- sbit K3 = P2^0;
- unsigned char code KeyCodeMap[3] = { '1','4','3'};
- unsigned char pdata KeySta[3] = {1, 1, 1};
- extern void KeyAction(unsigned char keycode);
- void KeyDriver()
- {
- unsigned char i;
- static unsigned char pdata backup[3] = {1, 1, 1}; //按鍵值備份,保存前一次的值
- for (i=0; i<3; i++)
- {
- if (backup[i] != KeySta[i]) //檢測按鍵動作
- {
- if (backup[i] != 0) //按鍵按下時執行動作
- {
- KeyAction(KeyCodeMap[i]); //調用按鍵動作函數
- }
- backup[i] = KeySta[i]; //刷新前一次的備份值
- }
- }
- }
- /* 按鍵掃描函數,需在定時中斷中調用,推薦調用間隔1ms */
- void KeyScan()
- {
- unsigned char i;
- static unsigned char keybuf[3]={0xFF, 0xFF, 0xFF}; //矩陣按鍵掃描緩沖區
- //將一行的4個按鍵值移入緩沖區
- keybuf[0] = (keybuf[0] << 1) | K1;
- keybuf[1] = (keybuf[1] << 1) | K2;
- keybuf[2] = (keybuf[2] << 1) | K3;
- //消抖后更新按鍵狀態
- for (i=0; i<3; i++) //每行4個按鍵,所以循環4次
- {
- if ((keybuf[i] & 0x0F) == 0x00)
- { //連續4次掃描值為0,即4*4ms內都是按下狀態時,可認為按鍵已穩定的按下
- KeySta[i] = 0;
- }
- else if ((keybuf[i] & 0x0F) == 0x0F)
- { //連續4次掃描值為1,即4*4ms內都是彈起狀態時,可認為按鍵已穩定的彈起
- KeySta[i] = 1;
- }
- }
- }
- LCD12864顯示12864xianshi.c
- #include"reg52.h"
- #define LCDP0 P0
- #include
- #include
- #include "12864.h"
- sbit RS = P1^0;
- sbit RW = P1^1;
- sbit E = P1^2;
- unsigned char num;
- unsigned char code dis0[]={"090 115"};
- unsigned char code dis1[]={"簡易低頻信號源"};
- unsigned char code dis2[]={"波形:"};
- unsigned char code dis3[]={"頻率:"};
- unsigned char code dis4[]={"學號:"};
- unsigned char code dis5[]={"SinWave"};
- unsigned char code dis6[]={"TriWave"};
- unsigned char code dis7[]={"SawWave"};
- unsigned char code dis8[]={"SquWave"};
- unsigned char code dis9[]={"HZ"};
- void delay(unsigned int ms)
- {
- unsigned int s,t;
- for(s=ms;s>0;s--)
- for(t=110;t>0;t--);
- }
- void ready() //讀狀態
- {
- unsigned char sta;
- LCDP0 = 0xFF;
- RS = 0 ;
- RW = 1 ;
- do {
- E = 1;
- sta = LCDP0;
- E = 0;
- }
- while(sta&0x80);
- }
- void write_com(unsigned char com) //寫命令
- {
- ready();
- RS = 0;
- RW = 0;
- LCDP0 = com;
- E = 1;
- E = 0;
- }
- void write_date(unsigned char date) //寫數據
- {
- ready();
- RS = 1;
- RW = 0;
- LCDP0 = date;
- E = 1;
- E = 0;
- }
- void lcd_pos(unsigned char X,unsigned char Y)
- {
- unsigned char pos;
- if(X==0)
- {
- X = 0x81;
- }
- else if(X==1)
- {
- X = 0x90;
- }
- else if(X==2)
- {
- X = 0x88;
- }
- else if(X==3)
- {
- X =0x98;
- }
- pos = X+Y;
- write_com(pos);
- }
- void init() //初始化
- {
- write_com(0x30);
- write_com(0x0C);
- write_com(0x06);
- write_com(0x01);
- }
- void mainxianshi()
- {
- unsigned char i;
- init();
- lcd_pos(0,0);
- i = 0;
- while(dis1[i]!='')
- {
- write_date(dis1[i]);
- i++;
- }
- lcd_pos(1,0);
- i = 0;
- while(dis2[i]!='')
- {
- write_date(dis2[i]);
- i++;
- }
- lcd_pos(2,0);
- i = 0;
- while(dis3[i]!='')
- {
- write_date(dis3[i]);
- i++;
- }
- lcd_pos(3,0);
- i = 0;
- while(dis4[i]!='')
- {
- write_date(dis4[i]);
- i++;
- }
- lcd_pos(3,3);
- i = 0;
- while(dis0[i]!='')
- {
- write_date(dis0[i]);
- i++;
- }
- lcd_pos(1,3);
- i = 0;
- while(dis5[i]!='')
- {
- write_date(dis5[i]);
- i++;
- }
- lcd_pos(2,5);
- i = 0;
- while(dis9[i]!='')
- {
- write_date(dis9[i]);
- i++;
- }
- }
- void main_sinwave()
- {
- unsigned char i;
- lcd_pos(1,3);
- i = 0;
- while(dis5[i]!='')
- {
- write_date(dis5[i]);
- i++;
- }
- }
- void main_triwave()
- {
- unsigned char i;
- lcd_pos(1,3);
- i = 0;
- while(dis6[i]!='')
- {
- write_date(dis6[i]);
- i++;
- }
- }
- void main_sawwave()
- {
- unsigned char i;
- lcd_pos(1,3);
- i = 0;
- while(dis7[i]!='')
- {
- write_date(dis7[i]);
- i++;
- }
- }
- void main_squwave()
- {
- unsigned char i;
- lcd_pos(1,3);
- i = 0;
- while(dis8[i]!='')
- {
- write_date(dis8[i]);
- i++;
- }
- }
- void main_freqwave(unsigned char i)
- {
- unsigned int a;
- unsigned int value1, value2;
- a=i;
- if(a>0x09)
- {
- value1 = a/10 + 0x30;
- value2 = a%10 + 0x30;
- }
- else
- {
- value1 = 0 + 0x30;
- value2 = a + 0x30;
- }
- lcd_pos(2,3);
- write_date(value1);
- write_date(value2);
- }
- I2c總線I2C.c
- /*
- * 文件名:I2C.c
- * 描 述:I2C總線驅動模塊
- * 版本號:v1.0.0
- * 備 注:基于IO口模擬實現,總線時序延時等皆由軟件方式實現
- * 軟件延時函數的準確度基于STC12系列單片機在12M晶振的情況
- *******************************************************************************
- */
- #include
- #include
- #define I2CDelay() Delay_us(5)
- sbit I2C_SCL = P1^6;
- sbit I2C_SDA = P1^7;
- void Delay_us(unsigned char us)
- {
- do {
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- } while (--us);
- }
- /* 產生總線起始信號 */
- void I2CStart()
- {
- I2C_SDA = 1; //首先確保SDA、SCL都是高電平
- I2C_SCL = 1;
- I2CDelay();
- I2C_SDA = 0; //先拉低SDA
- I2CDelay();
- I2C_SCL = 0; //再拉低SCL
- }
- /* 產生總線停止信號 */
- void I2CStop()
- {
- I2C_SCL = 0; //首先確保SDA、SCL都是低電平
- I2C_SDA = 0;
- I2CDelay();
- I2C_SCL = 1; //先拉高SCL
- I2CDelay();
- I2C_SDA = 1; //再拉高SDA
- I2CDelay();
- }
- /* I2C總線寫操作,dat-待寫入字節,返回值-從機應答位的值 */
- bit I2CWrite(unsigned char dat)
- {
- bit ack; //用于暫存應答位的值
- unsigned char mask; //用于探測字節內某一位值的掩碼變量
- for (mask=0x80; mask!=0; mask>>=1) //從高位到低位依次進行
- {
- if ((mask&dat) == 0) //該位的值輸出到SDA上
- I2C_SDA = 0;
- else
- I2C_SDA = 1;
- I2CDelay();
- I2C_SCL = 1; //拉高SCL
- I2CDelay();
- I2C_SCL = 0; //再拉低SCL,完成一個位周期
- }
- I2C_SDA = 1; //8位數據發送完后,主機釋放SDA,以檢測從機應答
- I2CDelay();
- I2C_SCL = 1; //拉高SCL
- ack = I2C_SDA; //讀取此時的SDA值,即為從機的應答值
- I2CDelay();
- I2C_SCL = 0; //再拉低SCL完成應答位,并保持住總線
- return (~ack); //應答值取反以符合通常的邏輯:
- //0=不存在或忙或寫入失敗,1=存在且空閑或寫入成功
- }
- /* I2C總線讀操作,并發送非應答信號,返回值-讀到的字節 */
- unsigned char I2CReadNAK()
- {
- unsigned char mask;
- unsigned char dat;
- I2C_SDA = 1; //首先確保主機釋放SDA
- for (mask=0x80; mask!=0; mask>>=1) //從高位到低位依次進行
- {
- I2CDelay();
- I2C_SCL = 1; //拉高SCL
- if(I2C_SDA == 0) //讀取SDA的值
- dat &= ~mask; //為0時,dat中對應位清零
- else
- dat |= mask; //為1時,dat中對應位置1
- I2CDelay();
- I2C_SCL = 0; //再拉低SCL,以使從機發送出下一位
- }
- I2C_SDA = 1; //8位數據發送完后,拉高SDA,發送非應答信號
- I2CDelay();
- I2C_SCL = 1; //拉高SCL
- I2CDelay();
- I2C_SCL = 0; //再拉低SCL完成非應答位,并保持住總線
- return dat;
- }
- /* I2C總線讀操作,并發送應答信號,返回值-讀到的字節 */
- unsigned char I2CReadACK()
- {
- unsigned char mask;
- unsigned char dat;
- I2C_SDA = 1; //首先確保主機釋放SDA
- for (mask=0x80; mask!=0; mask>>=1) //從高位到低位依次進行
- {
- I2CDelay();
- I2C_SCL = 1; //拉高SCL
- if(I2C_SDA == 0) //讀取SDA的值
- dat &= ~mask; //為0時,dat中對應位清零
- else
- dat |= mask; //為1時,dat中對應位置1
- I2CDelay();
- I2C_SCL = 0; //再拉低SCL,以使從機發送出下一位
- }
- I2C_SDA = 0; //8位數據發送完后,拉低SDA,發送應答信號
復制代碼
|