電路原理圖如下:
原理圖.png (167.37 KB, 下載次數: 309)
下載附件
2019-1-5 22:58 上傳
目錄
1 概述 1.1 背景 1.2 設計的目的與意義 2 方案簡述 3 硬件電路 3.1 單片機的選擇 3.2 MCU模塊電路 3.3 人體紅外檢測模塊電路 3.4 光照強度檢測模塊電路 3.5 照明燈模塊電路 3.6 蜂鳴器模塊電路和心跳燈模塊電路 3.7 模式選擇按鍵和模式指示燈模塊電路 3.8 復位電路 3.9 USB轉串口模塊電路和SWD下載接口電路 3.10 電源模塊電路 4 系統軟件設計及實現 4.1 主程序流程圖 4.2 手動模式流程圖 4.3 自動模式流程圖 5 調試 5.1 硬件調試規則 5.2 軟件調試 5.3 調試的最終結果 設計心得 參 考 文 獻 附錄 1 概述
1.1 背景 隨著計算機網絡、通信、控制等技術的發展,智能建筑的發展越來越迅猛。目前,國內大多數智能建筑存在效率低、能耗高的現象。就智能建筑的照明系統來說,許多地方的燈是從早到晚開著的,不管這些房間或樓道是否有人,或者,當自然光照度很好時,不能及時關閉;當自然光照度不能滿足人的需求時,又不能及時打開。這種照明系統,不僅造成能源的浪費,而且不能滿足人對照明的需求,同時也給人的視力造成了很壞的影響。現代照明除了滿足人的基本需求,應更注重能量的節省和使用上的便利。要做到合理、經濟、節能,首先應采用先進成熟的技術和產品,如電光源、燈具、照明控制系統。 在大學校園的建設中,各大高校意識到了智能照明的重要性。相對商業樓宇而言,大學校園里的大功率動力和制冷設備比重較少,照明燈具則相對比重更多,所以控制教室照明是節能的關鍵。使用照明控制系統,更能體現其在節能方面的優勢,提高學校的科學管理水平,而且還能節省開支。 1.2 設計的目的與意義 ① 良好的節能效果和延長燈具壽命 節能是照明控制系統的最大優勢。傳統的樓宇公共區域照明工作模式,只能是白天關燈,晚上開燈。而采用了智能照明控制系統后,可以根據不同場合、不同的人流量,進行時間段、工作模式的細分,把不必要的照明關掉,在需要時自動開啟。同時,系統還能充分利用自然光,自動調節室內照度。控制系統實現了不同工作場合的多種照明工作模式,在保證必要照明的同時,有效減少了燈具的工作時間,節省了不必要的能源開支,也延長了燈具的壽命。 ② 改善工作環境,提高工作效率 良好的工作環境是提高工作效率的一個必要條件。合理地選用光源、燈具及性能優越的照明控制系統,都能提高照明質量。智能照明控制系統具有開關和調光兩種控制方法,可以有效地控制各種照明場所的平均照度值,從而提高照度均勻性。同時,系統能根據不同的時間段,人們的不同需要,自動調節照度。 ③ 提高管理水平 智能照明控制系統是以自動控制為主、人工控制為輔的系統。在一般的情況下,不需要有人的參與,照明系統自動實現開關和調光功能,既大大減少了管理人員的數量,也排除了由于人為因素而出現的不定時開關,影響學校的正常教學、生活秩序的情況。 ④ 較好的投資收益效果 智能照明控制系統在節能和節省燈具使用的同時,有效節省了電費與管理費用的支出。根據一般的辦公大樓運營的經驗來看,節能效果能達到40%以上,一般的商場、酒店、地鐵站等節能效果也能達到25%~30%。
2 方案簡述
針對上述節能、環保、健康等問題研究,基于STM32微控制器和PWM調光的LED燈以STM32F103C8作為主控芯片,設置了手動控制模式和自動控制模式。在手動控制時,分為五個檔,輸出不同的PWM占空比對LED的電流進行控制,從而實現了對光度的手動調節。 在自動控制時,通過STM32F103C8芯片自帶的AD轉換不斷檢驗光敏電阻的電壓來間接測量感應光度,將電壓和預設的閾值進行對比,調整PWM的占空比對LED的電流進行控制,從而實現了對光度的自動調節。 總體框圖如下圖2.1: 
圖2.1總體框圖 在實現主要功能的基礎上,增加了自動模式和手動模式的指示燈以及蜂鳴器的提示功能。選擇自動模式時,自動模式的指示燈亮,選擇手動模式時,手動模式的指示燈亮。同時伴隨著呼吸燈的閃爍。當進行關機的時候,蜂鳴器會發出聲響,提示操作者系統已經關機。
3 硬件電路
3.1 單片機的選擇 STM32是目前最流行的一款單片機, 現在以STM32F103為代表介紹它的各個參數。STM32微控制器是把那些作為控制應用所必需的基本內容都集成在一個尺寸有限的集成電路芯片上。按功能劃分,它由如下功能部件組成,即內核,存儲器,時鐘、復位和電源管理,模數轉換器,DMA控制器,I/O口,定時器,通信接口等。它們都是通過片內總線連接而成,對各種功能部件的控制是采用特殊功能寄存器的集中控制方式。其內部結構主要有以下幾部分: - 內核:ARM32位的CortexTM-M3 CPU,最高72MHz工作頻率,在存儲器的0等待周期訪問時可達1.25DMips/MHz(Dhrystone2.1),單周期乘法和硬件除法。
- 存儲器:從64K或128K字節的閃存程序存儲器,高達20K字節的SRAM。
- 時鐘、復位和電源管理:2.0~3.6V供電和I/O引腳, 上電/斷電復位(POR/PDR)、可編程電壓監測器(PVD), 4~16MHz晶體振蕩器,內嵌經出廠調校的8MHz的RC振蕩器,內嵌帶校準的40kHz的RC振蕩器,產生CPU時鐘的PLL,帶校準功能的32kHz RTC振蕩器。
- 2個12位模數轉換器,1μs轉換時間(多達16個輸入通道):轉換范圍:0至3.6V,雙采樣和保持功能,溫度傳感器。
- DMA:7通道DMA控制器,支持的外設:定時器、ADC、SPI、USART等。
- 多達80個快速I/O端口:26/37/51/80個I/O口,所有的I/O口可以映像到16個外部中斷,幾乎所有的端口均可容忍5V的信號。
- 多達7個定時器:3個16位定時器,每個定時器有多達4個用于輸入捕獲/輸出比較/PWM或脈沖計數的通道和增量編碼器輸入,1個16位帶死區控制和緊急剎車,用于電機控制PWM高級控制定時器,系統時間定時器:24位自減型計數器。
- 多達9個通信接口:多達3個USART接口(支持ISO7816接口,LIN,IrDA接口和調制解調控制),多達2個SPI接口(18M位/秒),CAN接口(2.0B主動),USB2.0全速接口。
STM32具有較強的代表性以及該系列單片機資料較多,本設計采用STM32F103C8來實現。 3.2 MCU模塊電路 MCU模塊電路在整個控制系統中起到至關重要的作用,如圖3.2所示。圖中包含了時鐘電路,采用8MHz的晶振和兩個22pF的電容構成的振蕩器,為MCU的工作提供有序的時間。電源引腳VBAT、VDD_1、VDD_2、VDD_3和VDDA接的是3.3V的高電平,VSS_1、VSS_2、VSS_3和VSSA接的是GND。 圖中PA1引腳GZ_ADC連接的是光照強度檢測模塊,PA3引腳PERSON_CHECK連接的是人體紅外檢測模塊的PC817的第4引腳,PA9引腳USART1_TX連接的是USB轉串口模塊的CH340G的第3引腳,PA10引腳USART1_RX連接的是USB轉串口模塊的CH340G的第2引腳,PA11引腳HM_key連接的是模式選擇按鍵模塊的KEY1,PA12引腳AUTO_key連接的是模式選擇按鍵模塊的KEY2,PA13引腳SWDIO連接的是SWD下載接口的第2引腳,PA14引腳SWCLK連接的是SWD下載接口的第3引腳,PA15引腳的BEEP連接的是蜂鳴器模塊,PB3引腳的LED0連接的是心跳燈模塊,PB4引腳的HM_led連接的是模式指示燈模塊的HM_led,PB5引腳的AUTO_led連接的是模式指示燈模塊的AUTO_led,PB7引腳的LEDPWM連接的是照明燈模塊,PB8引腳和PB9引腳暫時沒有用到。 以上提到的各個電路模塊將在下面詳細介紹。 
圖3.2 MCU模塊電路 3.3 人體紅外檢測模塊電路 采用集成電路BIS0001,該芯片是一款具有較高性能的傳感信號處理集成電路。它配以熱釋電紅外傳感器和少量外接元器件就可構成被動式的熱釋電紅外開關、報警用人體熱釋電傳感器等。它能自動快速開啟各類白熾燈、熒光燈、蜂鳴器、自動門、電風扇、烘干機和自動洗手池等裝置,特別適用于企業、賓館、商場、庫房及家庭的過道、走廊等敏感區域,或用于安全區域的自動燈光、照明和報警系統。BIS0001的引腳圖如圖3.3.1: 
圖3.3.1 BIS0001的引腳圖 由BIS0001構成的人體紅外檢測電路如圖3.3.2所示:: 圖3.3.2 人體紅外檢測電路 圖3.3.2中,RE200B是熱釋電紅外傳感器,運算放大器OP1將熱釋電紅外傳感器的輸出信號作第一級放大,然后由C9耦合給運算放大器OP2進行第二級放大,再經由電壓比較器COP1和COP2構成的雙向鑒幅器處理后,檢出有效觸發信號Vs去啟動延遲時間定時器,輸出信號Vo,Vo引腳的OUT連接PC817的第2引腳,Vo通過PC817對PERSON_CHECK進行控制,PERSON_CHECK連接的是MCU模塊的PA3引腳,由此MCU可以知道此時PERSON_CHECK是高電平還是低電平,從而可以判斷出有人經過還是無人經過。這個電路模塊就是對人進行檢測。 3.4 光照強度檢測模塊電路 光敏電阻又稱光導管,由于光照產生的載流子都參與導電,在外加電場的作用下作漂移運動,電子奔向電源的正極,空穴奔向電源的負極,從而使光敏電阻器的阻值迅速下降。光敏電阻器是利用半導體的光電導效應制成的一種電阻值隨入射光的強弱而改變的電阻器,又稱為光電導探測器。入射光強,電阻減小,入射光弱,電阻增大。電路如下圖3.4所示: 
圖3.4 光照強度檢測電路 圖3.5 照明燈電路 圖3.4中,光照強度檢測電路由一個光敏電阻和一個普通電阻組成。GZ_ADC是和MCU模塊的PA1引腳連接在一起的,通過檢測外部光照的強弱,從而改變光敏電阻的阻值,使得GZ_ADC的到不同的電平信號,也即是PA1上的電平。光照強時,光敏電阻的阻值小,GZ_ADC得到低電平,光照較弱時,光敏電阻的阻值大,GZ_ADC得到高電平。由于以上現象,可以實現此次設計的一個必不可少的重要功能:有光的時候,LED燈不亮,無光的時候,LED燈亮。 3.5 照明燈模塊電路 上圖3.5展示了照明燈的驅動電路,此電路由一個發光二極管,一個三極管以及三個電阻組成。圖中LEDPWM連接的是MCU模塊的PB7引腳,當LEDPWM輸出高電平時,三極管Q4導通,接通發光二極管DS1,使其發光,而LEDPWM輸出低電平時,三極管截止,發光二極管也截止。通過編程可以實現PB7腳輸出不同占空比的PWM波,可以調節通過三極管中的電流,從而實現不同亮度的調節。這個電路一方面是驅動LED燈,另一方面實現對LED燈的控制和亮度調節。 3.6 蜂鳴器模塊電路和心跳燈模塊電路 蜂鳴器模塊電路如下圖3.6.1所示,蜂鳴器模塊電路主要是由一個蜂鳴器,一個三極管和兩個電阻組成。蜂鳴器模塊電路中的BEEP連接的是MCU模塊的PA15引腳,此電路和照明燈驅動電路基本類似。當三極管基極BEEP輸出高電平時,三極管Q1導通,接通蜂鳴器BEEP發聲,而三極管基極BEEP輸出低電平時,三極管截止,蜂鳴器BEEP構不成完整的回路,不能發聲。 心跳燈模塊電路如下圖3.6.2所示,心跳燈模塊電路主要是由一個發光二極管和一個電阻組成。LED0連接的是MCU模塊的PB3引腳。LED0一旦接收到低電平,發光二極管就接通。所以,可以通過編程對PB3引腳在不同時刻輸出高低電平,從而實現不同情況下的燈亮和燈滅。  圖3.6.1蜂鳴器模塊電路 圖3.6.2心跳燈模塊電路 3.7 模式選擇按鍵和模式指示燈模塊電路 模式選擇按鍵模塊電路如下圖3.7.1所示,模式選擇按鍵模塊電路主要是由兩個開關和兩個電阻組成。模式選擇按鍵電路中,HM_key連接的是MCU模塊的PA11引腳,AUTO_key連接的是MCU模塊的PA12引腳。PA11和PA12主要是用來檢測HM_key和AUTO_key上是高電平還是低電平,通過軟件編程,當PA11引腳得到低電平,也就是KEY1按下時,選擇手動模式;當PA12引腳得到高電平,也就是KEY2按下,選擇自動模式。 模式指示燈模塊電路如下圖3.7.1所示,模式指示燈模塊電路主要是由兩個發光二極管和兩個電阻組成。模式指示燈電路中,HM_led連接的是MCU模塊中的PB4引腳,AUTO_led連接的是MCU模塊的PB5引腳。當MCU給PB4或PB5低電平時,模式指示燈電路中的DS3或DS4導通發光。選擇手動模式時,手動模式指示燈亮,選擇自動模式時,自動模式指示燈亮。 
圖3.7.1 模式選擇按鍵電路 圖3.7.2 模式指示燈電路 3.8 復位電路 復位電路是一種用來使電路恢復到起始狀態的電路。就像計算器的清零按鈕的作用一樣,以便回到原始狀態,重新進行計算。當系統死機或者程序跑飛的時候,通過復位電路可以使系統恢復到初始狀態。所以復位電路是系統中不可或缺的一部分。復位方式有手動復位和上電復位。 本設計的手動復位電路如圖3.8所示,復位電路由一個按鍵,一個電阻和一個電容組成。圖中的RESET連接的是MCU模塊的NRST引腳,一旦按鍵按下,NRST就收到一個低電平,使MCU模塊復位,從起始狀態重新開始執行。 
圖3.8 復位電路 3.9 USB轉串口模塊電路和SWD下載接口電路 USB轉串口模塊電路如圖3.9.1所示,圖中的USB中的VCC連接的是電源模塊的VUSB,為USB模塊的工作提供電壓,CH340D-和CH340+分別連接CH340G驅動芯片的第6腳和第5腳,圖中CH340G的TXD和RXD引腳分別連接MCU模塊的USART1_RX和USART1_TX。USB得到的信息經過CH340G芯片的處理,通過TXD發送到MCU,MCU的信息通過RXD傳達給USB實現外設與MCU的通信。 由一個12MHz的晶振和兩個電容構成的振蕩器,為CH340G提供時鐘,讓通信有條不紊的持續下去。 
圖3.9.1 USB轉串口電路 大家比較常用的是Jlink下載器,這種下載器有一個缺點就是使用的Jtag 20PIN接口,太多的PIN會導致一些小型的PCB板很擁擠,也會增加布線的難度。而使用SWD接口下載調試,只需要要使用4個PIN:GND,RST,SWDIO,SWDCLK ,而且下載速度可以達到10M/s,優勢顯而易見。SWD下載接口電路如下圖3.9.2所示,圖中SWDIO和SWCLK分別連接MCU模塊的SWDIO和SWCLK引腳,上位機就可以通過這個下載接口把程序下載到板子里面,實現功能控制。 圖3.9.2 SWD下載接口電路 3.10 電源模塊電路 電源模塊是可以直接貼裝在印刷電路板上的電源供應器,其特點是可為專用集成電路(ASIC)、數字信號處理器 (DSP)、微處理器、存儲器、現場可編程門陣列 (FPGA) 及其他數字或模擬負載供電。由于模塊式結構的優點甚多,因此模塊電源廣泛用于交換設備、接入設備、移動通訊、微波通訊以及光傳輸、路由器等通信領域和汽車電子、航空航天等。 本設計的電源模塊電路如下圖3.10所示,電源模塊有一塊集成芯片AMS1117,三個電容,一個電阻和一個發光二極管組成。電源模塊為中整個系統提供合適有效的電壓。當通電時,發光二極管PWR會亮,提示本系統已經供電,可以進行其他操作了。 
圖3.10電源模塊電路
4 系統軟件設計及實現
4.1 主程序流程圖 軟件部分的主要任務是完成對光照檢測電路和對熱釋電傳感器信號處理電路的輸出信號進行處理。基于上述分析,系統軟件設計流程如圖4.1所示。


圖4.1主程序流程圖 由系統軟件流程圖4.1可以進行邏輯編程,通過編程基本實現了智能燈的各項功能。編程的代碼見附錄。 4.2 手動模式流程圖 

 



圖4.2 手動模式流程圖 4.3 自動模式流程圖

圖4.3 自動模式流程圖
5 調試
5.1 硬件調試規則 硬件調試是利用基本測試儀器(萬用表、示波器等),檢查用戶系統硬件中存在的故障。 硬件調試可分為靜態調試與動態調試兩步進行。 靜態調試是在用戶系統未工作時的一種硬件檢測。 第一步:目測。檢查外部的各種元件或者是電路是否有斷點。 第二步:用萬用表測試。先用萬用表復核目測中有疑問的連接點,再檢測各種電源線與地線之間是否有短路現象。 第三步:加電檢測。給板加電,檢測所有插座或是器件的電源端是否符合要求的值。 第四步是聯機檢查。因為只有用單片機開發系統才能完成對用戶系統的調試。 動態調試是在用戶系統工作的情況下發現和排除用戶系統硬件中存在的器件內部故障、器件連接邏輯錯誤等的一種硬件檢查。動態調試的一般方法是由近及遠、由分到合。由分到合是指首先按邏輯功能將用戶系統硬件電路分為若干塊,當調試電路時,與該元件無關的 器件全部從用戶系統中去掉,這樣可以將故障范圍限定在某個局部的電路上。當各塊電路無故障后,將各電路逐塊加入系統中,在對各塊電路功能及各電路間可能存在的相互聯系進行調試。由分到合的調試既告完成。由近及遠是將信號流經的各器件按照距離單片機的邏輯距離進行由近及遠的分層,然后分層調試。調試時,仍采用去掉無關元件的方法,逐層調試下去,就會定位故障元件了。 結果如圖5.1所示: 
圖5.1 硬件調試 5.2 軟件調試 軟件調試是通過對程序的連接、執行來發現程序中存在的語法錯誤與邏輯錯誤并加以排除糾正的過程,也可以通過keil軟件,能大大的減少設計過程中的錯誤。 正確建立keil工程,在工程中添加各個頭文件和源程序,編寫好自己的程序后進行調試,找錯誤。如圖5.2.1所示錯誤: 
圖5.2.1 軟件調試過程中的錯誤 通過查閱資料以及請教他人,發現這個問題是由于一個宏定義沒有添加,導致出現一個錯誤和這么多的警告。解決辦法如圖5.2.2所示,在Define欄中加上這個宏定義。 
圖5.2.1 軟件調試解決 5.3 調試的最終結果 軟件調試的最終結果,如圖5.3.1所示: 
圖5.3.1 軟件調試結果 硬件調試的最終結果,如圖5.3.2所示: 
圖5.3.2 硬件調試結果 設計心得
基于STM32的智能燈以STM32F103作為主控芯片,設置了手動控制、自動控制。在手動控制時,輸出不同的PWM占空比實現了對光度的手動調節。在自動控制時,通過熱釋電傳感器和處理電路,檢測此時有沒有人;通過檢驗光敏電阻的電壓來間接測量感應光度,將電壓和預設的閾值進行對比,調整PWM的占空比實現了對光度的自動調節。該LED燈電路簡單,很大程度上節省電能,延長LED燈壽命,如果要用大量的燈,這種燈便于管理。 在本次課程設計中,主要有以下體會: 一、掌握了Altium Designer軟件的用法和原理圖的繪制以及PCB的布板; 二、掌握了keil軟件的工程建立,以及對程序的編寫。 三、熟悉了熱釋電繼電器的應用。 通過這次課程設計使我懂得了理論與實際相結合是很重要的,只有理論知識是遠遠不夠的,只有把所學的理論知識與實踐相結合起來,從理論和實踐中得出結論,才能真正為社會服務,從而提高自己的實際動手潛力和獨立思考的潛力。在設計的過程中遇到問題,能夠說得是困難重重,主要是對所學過的知識理解得不夠深刻,掌握得不夠牢固,理論和實踐不能有機的結合在一起。在設計中遇到的很多專業知識問題,在同學和老師的耐心指導下,最后都迎刃而解了。此次設計也讓我明白了思路即出路,有什么不懂不明白的地方要及時請教或上網查詢,只要認真鉆研,動腦思考,動手實踐,就沒有弄不懂的知識,而且收獲頗豐。 此次課程設計,學到了很多課內學不到的東西,比如獨立思考解決問題,查閱資料,出現差錯的隨機應變和與人溝通的能力,希望今后高質量的完成其他項目。同時,在老師的身上我們學也到很多實用的知識,對給過我幫忙的所有同學和各位指導老師表示衷心的感謝!
main.c文件
#include "main.h"
#define UART_LENTH 1024
char uart1_buff[UART_LENTH]="\0";
void SW_Config(void);
//手動模式的檔位
#define LIGHT_MAX 90
#define LIGHT_MIN 2
#define HM_LEVEL 5
uint8_t now_hmlevel = 0;
#define CHPWM(x) ((LIGHT_MAX - LIGHT_MIN)*x/HM_LEVEL)
//光照的閾值
#define GZ_MAX 3980
#define GZ_MIN 585
#define GZ_ERROR 900
//熱釋電的濾波
#define PERSON_COUNT 20 //判斷n次采樣
uint8_t value = 0;
uint8_t flag_bitled = 1;
uint8_t beep_count = 0;
uint8_t flag_gz = 1;//有光 1 無光 0
uint8_t flag_person = 0;//有人 1 無人 0
uint8_t flag_auto = 1; //默認自動模式
int main()
{
uint8_t key = 0xff;//獲取的按鍵值
uint16_t person_count[3]={PERSON_COUNT,0,0};//[0] -- 時間片的長度 [1] -- 高電平的次數 [2] -- 低電平的次數
uint16_t gz_value = 0; //光敏電阻的值
NVIC_SetPriorityGrouping(5);//設置中斷優先級分組 占先 2 + 次級 2
SW_Config();//SWD模式
USART1_Config(115200);//串口初始化
// USART1_DMATx();
Delay_Init();//延時函數初始化
LED_Config();//LED初始化
BEEP_Config();//BEEP初始化
KEY_Config(); //按鍵初始化
Person_Config();//熱釋電初始化
TIM4_Config(72,1000,0); //定時器4初始化 產生PWM控制電燈
TIM3_Config(72,600); //定時器3初始化 實現無極調速 10us的速度
ADC1_Config();//ADC初始化
ADC1_DMAConfig();//DMA初始化
ADC1->CR2 |= (1<<22);//觸發ADC1轉換
LEDx_ON(LED3_PORT,LED3_PIN);//自動模式的指示燈打開
LEDx_OFF(LED2_PORT,LED2_PIN);//手動模式的指示燈關閉
while(1)
{
if(flag_auto)
{
if(flag_person == 1 && flag_gz == 0)//有人且無光
PWM_ChangeLight(100);//開燈
else
PWM_ChangeLight(0);//關燈
}
if(timeperson[0] > timeperson[1])//采樣周期
{
if(person_count[0])
{
person_count[0]--;
if(PERSON) person_count[1]++;
else person_count[2]++;
}
else //啟動下一次
{
printf("person_count[1] = %d\r\n",person_count[1]);
printf("person_count[2] = %d\r\n",person_count[2]);
//判斷是否有人
if(person_count[1] > person_count[2]) //有人
{
flag_person = 1;
timeperson[1] = 1000;//檢測到有人之后,采樣變為1s一次,減少采樣的頻率
}
else
{
timeperson[1] = 20;////檢測到無人之后,采樣變為20ms一次,增加采樣的頻率
flag_person = 0;//無人
}
person_count[0] = PERSON_COUNT;
//清零
person_count[1] = 0;
person_count[2] = 0;
}
timeperson[0] = 0;
}
if(timekey[0] > timekey[1])//按鍵
{
key = Get_KeyValue();
switch(key)
{
case 11://關機
flag_auto = 0; //關閉自動模式
flag_bitled = 0; LEDx_OFF(LED1_PORT,LED1_PIN);//關心跳燈
LEDx_OFF(LED3_PORT,LED3_PIN);//自動模式的指示燈關閉
LEDx_OFF(LED2_PORT,LED2_PIN); //手動模式的指示燈關閉
beep_count = 4; //響2次
PWM_ChangeLight(0);//燈珠
break;//關機 -- 關閉燈 -- 蜂鳴器響 -- 指示燈關
case 1:
LEDx_OFF(LED3_PORT,LED3_PIN);//自動模式的指示燈關閉
LEDx_ON(LED2_PORT,LED2_PIN);//手動模式的指示燈打開
flag_bitled = 1; LEDx_ON(LED1_PORT,LED1_PIN);//開心跳燈
now_hmlevel++;//調節亮度等級
now_hmlevel%=5;
PWM_ChangeLight(CHPWM(now_hmlevel));
flag_auto = 0;
break;//手動
case 2:
LEDx_ON(LED3_PORT,LED3_PIN);//自動模式的指示燈打開
LEDx_OFF(LED2_PORT,LED2_PIN);//手動模式的指示燈關閉
flag_bitled = 1; LEDx_ON(LED1_PORT,LED1_PIN);//開心跳燈
//啟動光照+熱釋電
flag_auto = 1;
break;//自動
}
timekey[0] = 0;
}
if(timebeep[0] > timebeep[1])
{
if(beep_count)
{
beep_count--;
BEEP_TOGGLE();//翻轉
}
timebeep[0] = 0;
}
if(timeadc[0]>timeadc[1])//ADC開關量
{
gz_value = Get_GzValue(NULL);
// printf("gz_value =%d\r\n",gz_value);
// printf("flag_gz =%d\r\n",flag_gz);
if(gz_value != 0xffff)//判斷是否獲得數據
{
if(gz_value >= (GZ_MAX - GZ_ERROR))//無光
flag_gz = 0;
else
flag_gz = 1;
}
timeadc[0] = 0;
}
if(timeled[0] > timeled[1])//指示燈
{
if(flag_bitled)
LEDx_TOGGLE(LED1_PORT,LED1_PIN);
timeled[0] = 0;
}
}
}
void SW_Config(void)
{
//打開AFIO時鐘
RCC->APB2ENR |= (1<<0);
//SWD模式
AFIO->MAPR &= ~(0x7<<24);
AFIO->MAPR |= (0x2<<24);
}
adc.c文件
#include "adc.h"
#include "stdio.h"
void ADC1_Config(void)
{
//配置ADC1_IN1 -- PA1
//打開時鐘 A端口+ADC1
RCC->APB2ENR |= (1<<2)|(1<<9);
//PA1配置為模擬輸入
GPIOA->CRL &= ~(0xF<<4);
//配置ADC1_IN1
//1.ADCCLK -- PCLK/8 -- 84/8
RCC->CFGR &= ~(0x3<<14);
RCC->CFGR |= (0x3<<14);
//2.配置規則組的轉換長度+IN1放在第一位
ADC1->SQR1 &= ~(0xf<<20);
ADC1->SQR1 |= (0x0<<20);//n次轉換
//規則組第1位置
ADC1->SQR3 &= ~(0x1f<<0);
ADC1->SQR3 |= (0x1<<0);
//3.配置轉換模式:單次/連續 掃描/不連續
//單次/連續 -- ADC_CR2 CONT位
ADC1->CR2 |= (1<<1);
//ADC1->CR2 &= ~(1<<1);
//掃描 -- ADC_CR1 SCAN
ADC1->CR1 &= ~(1<<8);//不掃描
//ADC1->CR1 |= (1<<8);//掃描
//4.設置采樣速率 3+12 = 15 ADCCLK
//設置采樣速率:ADC_IN1 -- ADC_SMPR2 3個周期
ADC1->SMPR2 &= ~(0x7<<3);
ADC1->SMPR2 |= (0x7<<3);
//5.禁止不連續采樣
ADC1->CR1 &= ~(1<<11);
//6.選擇觸發類型 軟件觸發
ADC1->CR2 |= (0x1<<20);
ADC1->CR2 |= (0x7<<17);
//7.設置數據對齊 -- 右對齊
ADC1->CR2 &= ~(1<<11);
//復位校準
ADC1->CR2 |= (1<<3);
while((ADC1->CR2 & (1<<3)) == 1);
//校準
ADC1->CR2 |= (1<<2);
while((ADC1->CR2 & (1<<2)) == 1);
//8.啟動ADC ADC_CR2 -- ADON
ADC1->CR2 |= (1<<0);
}
#define ADC_A(x) (3.3*x/4096)
u16 dma_adcbuff[30];
void ADC1_DMAConfig(void)
{
//時鐘打開
RCC->AHBENR |= (1<<0);
//ADC1配置DMA模式
ADC1->CR2 |= (1<<8);
//關閉DMA1
DMA1_Channel1->CCR &= ~(1<<0);
//清相關標志位
DMA1->IFCR |= (1<<0)|(1<<1)|(1<<2)|(1<<3);
//設置源和目標 -- 源 -- 外設(ADC_DR) 目標 -- 存儲器(dma_adcbuff)
DMA1_Channel1->CPAR = (uint32_t)&ADC1->DR;
DMA1_Channel1->CMAR = (uint32_t)dma_adcbuff;
//配置傳輸數據的總數
DMA1_Channel1->CNDTR = sizeof(dma_adcbuff)/sizeof(dma_adcbuff[0]);
//優先級 -- 高
DMA1_Channel1->CCR &= ~(0x3<<12);
DMA1_Channel1->CCR |= (0x2<<12);
//方向:外設到存儲器
DMA1_Channel1->CCR &= ~(0x1<<4);
//外設不增量
DMA1_Channel1->CCR &= ~(0x1<<6);
//存儲器不增量
DMA1_Channel1->CCR |= (0x1<<7);
//外設數據的寬度
DMA1_Channel1->CCR &= ~(0x3<<8);
DMA1_Channel1->CCR |= (0x1<<8);
//存儲器數據的寬度
DMA1_Channel1->CCR &= ~(0x3<<10);
DMA1_Channel1->CCR |= (0x1<<10);
//循環模式
DMA1_Channel1->CCR |= (0x1<<5);
//啟動DMA1_1
DMA1_Channel1->CCR |= (0x1<<0);
}
//通過DMA處理數據 -- 濾波
//0xffff -- 數據沒有獲得
uint16_t Get_GzValue(uint16_t *pdata)
{
uint16_t value = 0XFFFF;
uint32_t i = 0;
uint32_t lenth = sizeof(dma_adcbuff)/sizeof(dma_adcbuff[0]);
uint32_t sum = 0;
if(DMA1->ISR &(1<<1))//DMA傳輸完成
{
//清標志位
DMA1->IFCR |= (1<<1);
for(i=0;i<lenth;i++)
sum+= dma_adcbuff[ i];
value = sum/lenth;
if(pdata != NULL)
*pdata = value;
}
return value;
}
beep.c文件
#include "beep.h"
void BEEP_Config(void)
{
//打開時鐘 -- PA15
RCC->APB2ENR |= (1<<2);
//配置PA8-- 通用推挽輸出 速度50MHz 無上拉下拉
GPIOA->CRH &= ~((0xf<<28));
GPIOA->CRH |= (0x3<<28);
//關閉蜂鳴器
BEEP(0);
}
delay.c文件
#include "delay.h"
void Delay_nus(uint32_t time)
{
while(time--)
{
__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();__nop();
}
}
#define DELAY_1US 72
#define DELAY_1MS 72000
uint32_t runtime = 0;//保存當前系統運行的時間 單位ms
vu32 timeled[2] = {0,1000};//初始值 延時值
vu32 timebeep[2] = {0,100};
vu32 timekey[2] = {0,8};
vu32 timeusart1[2] = {0,100};
vu32 timeadc[2] = {0,1000};
vu32 timeperson[2] = {0,100};
void Delay_Init(void)
{
if(SysTick_Config(DELAY_1MS) == 1)//初始化滴答定時器
{
while(1);
}
TIM2_Config(1,72);
}
void SysTick_Handler(void)
{
runtime++;//每1ms加1次
timeled[0]++;
timebeep[0]++;
timekey[0]++;
timeusart1[0]++;
timeadc[0]++;
timeperson[0]++;
}
void Delay_ms(uint32_t time)
{
uint32_t time1 = runtime;//保存當前的系統時間
while((runtime - time1 )< time);
}
void TIM2_Config(uint16_t psc,uint16_t reload)
{
//打開時鐘 TIM2
RCC->APB1ENR |= (1<<0);
//初始化TIM7
//分頻
TIM2->PSC = psc-1;
//計數器清零
TIM2->CNT = 0;
//重裝載初始化
TIM2->ARR = reload-1;
//TIM6 CR1 -- 使能(定時器、重裝載值緩存區、事件)
TIM2->CR1 = 0;
//中斷配置
//中斷打開
TIM2->DIER |= (1<<0);
//設置中斷通道使能以及優先級
NVIC_SetPriority(TIM2_IRQn,0xf);//2 2 11 11
NVIC_DisableIRQ(TIM2_IRQn);
//定時打開
TIM2->CR1 &= ~(1<<0);
}
//1us 進入中斷一次
uint32_t run_ustime = 0;
void TIM2_IRQHandler(void)
{
TIM2->SR &= ~(1<<0);//清標志位
if(run_ustime > 0) run_ustime--;
}
void Delay_us(uint32_t time)
{
run_ustime = time;
TIM2->CNT = 0;//計數器清零
TIM2->CR1 |= (1<<0);//定時器打開
while(run_ustime); //延時等待
TIM2->CR1 &= ~(1<<0);//關閉定時器
}
key.c文件
#include "key.h"
#include "delay.h"
//KEY1 -- PA11 KEY2 -- PA12
void KEY_Config(void)
{
//打開端口時鐘
RCC->APB2ENR |= (1<<2);
//配置為輸入模式 -- 浮空輸入
GPIOA->CRH &= ~((0xf<<12)|(0xf<<16));
GPIOA->CRH |= (0x4<<12)|(0x4<<16);
}
uint8_t Get_KeyValue(void)
{
static uint32_t count1 = 0;//檢測到低電平的次數
static uint32_t count2 = 0;//檢測到低電平的次數
if(KEY1 == 0)
{
count1++;
if(count1 > 120)
{
count1 = 0;
return 11;
}
}
else if(count1 > 15 && count1 <50)
{
count1 = 0;
return 1;
}
else //濾波
count1 = 0;
if(KEY2 == 0) count2++;
else if(count2 > 15)
{
count2 = 0;
return 2;
}
else //濾波
count2 = 0;
return 0xff;
}
led.c文件
#include "led.h"
#include "delay.h"
#include "bitband.h"
void LED_Config(void)
{
//打開LED1 2 3燈的時鐘 -- B
RCC->APB2ENR |= sbit(3);
//配置PB3 4 5-- 通用推挽輸出 速度50MHz 無上拉下拉
//通用輸出 -- 清零賦值
GPIOB->CRL &= ~((0xf<<12)|(0xf<<16)|(0xf<<20));
GPIOB->CRL |= (0x3<<12)|(0x3<<16)|(0x3<<20);
//滅燈
LEDx_OFF(LED1_PORT,LED1_PIN);
LEDx_OFF(LED2_PORT,LED2_PIN);
LEDx_OFF(LED3_PORT,LED3_PIN);
}
light.c文件
#include "light.h"
void TIM3_Config(uint16_t psc,uint16_t reload)
{
//打開時鐘 TIM3
RCC->APB1ENR |= (1<<1);
//初始化TIM3
//分頻
TIM3->PSC = psc-1;
//計數器清零
TIM3->CNT = 0;
//重裝載初始化
TIM3->ARR = reload-1;
//TIM3 CR1 -- 使能(定時器、重裝載值緩存區、事件)
TIM3->CR1 = 0;
//中斷配置
//中斷打開
TIM3->DIER |= (1<<0);
//設置中斷通道使能以及優先級
NVIC_SetPriority(TIM3_IRQn,0xf);//2 2 11 11
NVIC_EnableIRQ(TIM3_IRQn);
//定時關閉
TIM3->CR1 &= ~(1<<0);
}
uint16_t new_ccr = 0;
void TIM3_IRQHandler(void)
{
int offset = new_ccr - TIM4->CCR2;//求出偏差值
TIM3->SR &= ~(1<<0);//清標志位
if(TIM4->CCR2 <= TIM4->ARR && TIM4->CCR2 >= 0)//
{
//分為三種情況
if(offset == 0) TIM3->CR1 &= ~(1<<0);//關閉定時器,不修改CCR值
else if(offset > 0) TIM4->CCR2 += 1;
else if(offset < 0) TIM4->CCR2 -= 1;
}
}
//參數:pwmvalue 0~100
void PWM_ChangeLight(uint32_t pwmvalue)
{
//把PWMValue轉換為CCR寄存器的值 pwmvalue(0~100) -- CCR(0~ARR重裝載值)
uint16_t arr = TIM4->ARR;
//計算出要修改的PWM波的占空比所對應的CCR寄存器值
new_ccr = arr*pwmvalue/100;
//啟動一個定時器去實現無極調光
TIM3->CR1 |= (1<<0);
}
person.c文件
#include "person.h"
void Person_Config(void)
{
//打開端口時鐘
RCC->APB2ENR |= (1<<2);
//配置為輸入模式 -- 浮空輸入
GPIOA->CRL &= ~((0xf<<12));
GPIOA->CRL |= (0x4<<12);
}
tim.c文件
#include "tim.h"
//1KHz -- 1ms -- 72 1000 500
//PB7 -- TIM_CH2 -- 復用
void TIM4_Config(uint16_t psc,uint16_t arr,uint16_t ccr)
{
//B端口時鐘 PB7 TIM4時鐘打開
RCC->APB2ENR |= (1<<3);
RCC->APB1ENR |= (1<<2);
//PB7配置為復用功能
GPIOB->CRL &= ~((0xf<<28));
GPIOB->CRL |= (0xb<<28);
//TIM4的定時時長 -- 1ms
TIM4->CNT = 0;
TIM4->PSC = psc-1;
TIM4->ARR = arr-1;
TIM4->CCR2 = ccr;//比較寄存器值
//ARR的預裝載 -- CR1
TIM4->CR1 = 0;
//輸出模式、CCR預裝載、快速使能
TIM4->CCMR1 = 0;
//PWM1模式
TIM4->CCMR1 &= ~(0x7<<12);
TIM4->CCMR1 |= (0x6<<12);
//有效電平高電平 使能OC輸出
TIM4->CCER = 0;
TIM4->CCER |= (1<<4);
//開啟定時器
TIM4->CR1 |= (1<<0);
}
usart.c文件
#include "usart.h"
#include "beep.h"
#include "led.h"
#include "string.h"
#include "stdio.h"
void USART1_Config(uint32_t brr)
{
float div;//分頻數
uint32_t div_m;//整數部分
uint32_t div_f;//小數部分
//A端口時鐘 PA9 PA10 USART1時鐘打開
RCC->APB2ENR |= (1<<2)|(1<<14);
//PA9 PA10配置為復用功能
GPIOA->CRH &= ~((0xf<<4)|(0xf<<8));
GPIOA->CRH |= (0xb<<4);
GPIOA->CRH |= (0x4<<8);
//配置串口 232協議:字長 + 奇偶校驗使能
USART1->CR1 = 0;
//停止位 1位
USART1->CR2 &= ~(0x3<<12);
//配置全雙工模式:接收發送打開
USART1->CR1 |= (0x1<<2)|(0x1<<3);
//配置波特率
div = 72000000.0/(16.0*brr);
div_m = (uint32_t)div;
div_f = (uint32_t)((div-div_m)*16);
USART1->BRR = div_m<<4|div_f;
//使能串口1
USART1->CR1 |= (1<<13);
}
void USART1_NVICConfig(void)
{
//接收中斷使能
USART1->CR1 |= (1<<5);
//NVIC
NVIC_SetPriority(USART1_IRQn,1);//占先 0 次級 1
NVIC_EnableIRQ(USART1_IRQn);
}
void USART1_Echo(void)
{
uint8_t data;
//接收數據 -- 判斷數據是否到來(SR) -- 阻塞
while((USART1->SR & (1<<5)) == 0);
//保存數據
data = USART1->DR;
//發送數據 -- 等待上次發送完成(SR -- 7/6)
while((USART1->SR & (1<<7)) == 0);
USART1->DR = data;
}
uint8_t USART1_RecvData(void)
{
//uint8_t data;
//接收數據 -- 判斷數據是否到來(SR) -- 阻塞
while((USART1->SR & (1<<5)) == 0);
//保存數據
//data = USART1->DR;
return USART1->DR;
}
void USART1_SendData(uint8_t data)
{
//發送數據 -- 等待上次發送完成(SR -- 7/6)
while((USART1->SR & (1<<7)) == 0);
USART1->DR = data;
}
void USART1_SendString(uint8_t *p)
{
while(*p)
{
USART1_SendData(*p++);
}
}
int fputc(int c, FILE *stream)
{
USART1_SendData((uint8_t)c);
return c;
}
uint8_t dmabuff[]="深圳信盈達鄭州分公司\r\n";
void USART1_DMATx(void)
{
//時鐘打開
RCC->AHBENR |= (1<<0);
//USART1_Tx配置DMA模式
USART1->CR3 |= (1<<7);
//關閉DMA1
DMA1_Channel4->CCR &= ~(1<<0);
//清相關標志位
DMA1->IFCR |= (1<<12)|(1<<13)|(1<<14)|(1<<15);
//設置源和目標 -- 源 -- 外設(USART1_DR) 目標 -- 存儲器(dma_buff)
DMA1_Channel4->CPAR = (uint32_t)&USART1->DR;
DMA1_Channel4->CMAR = (uint32_t)dmabuff;
//配置傳輸數據的總數
DMA1_Channel4->CNDTR = sizeof(dmabuff)/sizeof(dmabuff[0]);
//優先級 -- 高
DMA1_Channel4->CCR &= ~(0x3<<12);
DMA1_Channel4->CCR |= (0x2<<12);
//方向:存儲器到外設
DMA1_Channel4->CCR |= (0x1<<4);
//外設不增量
DMA1_Channel4->CCR &= ~(0x1<<6);
//存儲器增量
DMA1_Channel4->CCR |= (0x1<<7);
//外設數據的寬度
DMA1_Channel4->CCR &= ~(0x3<<8);
DMA1_Channel4->CCR |= (0x0<<8);
//存儲器數據的寬度
DMA1_Channel4->CCR &= ~(0x3<<10);
DMA1_Channel4->CCR |= (0x0<<10);
//循環模式
DMA1_Channel4->CCR &= ~(0x1<<5);
//關閉DMA1_4
DMA1_Channel4->CCR &= ~(0x1<<0);
}
////void USART1_DMATxTest(void)
////{
//// //關閉數據流
//// DMA2_Stream7->CR &=~(1<<0);
//// //清相關標志位
//// DMA2->HIFCR |= (1<<22)|(1<<24)|(1<<25)|(1<<26)|(1<<27);
//// //確定傳輸的次數
//// DMA2_Stream7->NDTR = sizeof(dmabuff)/sizeof(dmabuff[0]);
//// //啟動DMA
//// DMA2_Stream7->CR |= (1<<0);
////}
////0 -- 失敗 1 -- 成功
void Uart1_DMA_Printf(char *p,uint32_t lenth)
{
//關閉DMA1
DMA1_Channel4->CCR &= ~(1<<0);
//清相關標志位
DMA1->IFCR |= (1<<12)|(1<<13)|(1<<14)|(1<<15);
//修改存儲器地址
DMA1_Channel4->CMAR = (uint32_t)p;
//確定傳輸的次數
DMA1_Channel4->CNDTR = lenth;
//啟動DMA
DMA1_Channel4->CCR |= (0x1<<0);
}
完整的Word格式文檔51黑下載地址:
基于STM32的智能燈.docx
(1.51 MB, 下載次數: 575)
2019-1-5 22:57 上傳
點擊文件名下載附件
下載積分: 黑幣 -5
|