|
一份比較通俗易懂的學(xué)習(xí)資料
深入淺出 STM32系列
--ARM Cortex-M3
學(xué)習(xí)共享電子書 整理: 劉君華(石家莊)
STM32學(xué)前班教程之一:為什么是它
經(jīng)過幾天的學(xué)習(xí),基本掌握了 STM32的調(diào)試環(huán)境和一些基本知識(shí)。想拿出來與大家共享,笨教程本著最大限度簡化刪減 STM32入門的過程的思想,會(huì)把我的整個(gè)入門前的工作推薦給大家。就算是給網(wǎng)上的眾多教程、筆記的一種補(bǔ)充吧,所 以叫學(xué)前班教程。其中涉及產(chǎn)品一律隱去來源和品牌,以防廣告之嫌。全部漢字內(nèi)容為個(gè)人筆記。所有相關(guān)參考資料也 全部列出。:lol
教程會(huì)分幾篇,因?yàn)樘L啦。今天先來說說為什么是它——我選擇 STM32的原因。 我對(duì)未來的規(guī)劃是以功能性為主的,在功能和面積之間做以平衡是我的首要選擇,而把運(yùn)算放在第二位,這根我的專業(yè)
有關(guān)系。里面的運(yùn)算其實(shí)并不復(fù)雜,在入門階段想盡量減少所接觸的東西。
不過說實(shí)話,對(duì) DSP 的外設(shè)并和開發(fā)環(huán)境不滿意,這是為什么 STM32一出就轉(zhuǎn)向的原因。下面是我自己做過的兩塊 DSP28 的全功能最小系統(tǒng)板,在做這兩塊板子的過程中發(fā)現(xiàn)要想盡力縮小 DSP 的面積實(shí)在不容易(目前只能達(dá)到50mm×45mm, 這還是沒有其他器件的情況下),尤其是雙電源的供電方式和1.9V 的電源讓人很頭疼。
后來因?yàn)橐粋(gè)項(xiàng)目,接觸了 LPC2148并做了一塊板子,發(fā)現(xiàn)小型的 ARM7在外設(shè)夠用的情況下其實(shí)很不錯(cuò),于是開始搜 集相關(guān)芯片資料,也同時(shí)對(duì)小面積的 AVR 和51都進(jìn)行了大致的比較,這個(gè)時(shí)候發(fā)現(xiàn)了 CortexM3的 STM32,比2148擁有 更豐富和靈活的外設(shè),性能幾乎是2148兩倍(按照 MIPS 值計(jì)算)。正好2148我還沒上手,就直接轉(zhuǎn)了這款 STM32F103。
與2811相比較(核心1.8V 供電情況下),135MHz×1MIPS,F(xiàn)在用 STM32F103,72MHz×1.25MIPS,性能是 DSP 的66%, STM32F103R 型(64管腳)芯片面積只有2811的51%,STM32F103C 型(48管腳)面積是2811的25%,最大功耗是 DSP 的20%,單片價(jià)格是 DSP 的30%。且有更多的串口,CAP 和 PWM,這是有用的。高端型號(hào)有 SDIO,理論上比 SPI 速度 快。
由以上比較,準(zhǔn)備將未來的擁有操作系統(tǒng)的高端應(yīng)用交給 DSP 的新型浮點(diǎn)型單片機(jī)28335,而將所有緊湊型小型、 微型應(yīng)用交給 STM32。
的 STM32學(xué)前班教程:怎么開發(fā)
sw 笨笨的 STM32學(xué)前班教程之二:怎么開發(fā)目前手頭的入門階段使用的開發(fā)器概述 該產(chǎn)品為簡易 STM32調(diào)試器和 DEMO 板一體化的調(diào)試學(xué)習(xí)設(shè)備,價(jià)格在一百多塊。
2、硬件配置
仿真部分:USB 口,reset,指示燈,JTAG
DEMO 部分:4按鍵(IO),4LED(IO),一個(gè)串口,啟動(dòng)方式跳線,所有引腳的焊盤(可自行焊接插針進(jìn)行擴(kuò)展)
DEMO 芯片:STM32F103C8T6(程序空間64K) 參數(shù)和擴(kuò)展:
注:學(xué)習(xí)的目標(biāo)芯片是 STM32F103CBT6(7×7mm,128K flash,16K RAM)以及 STM32F103RET6(10×10mm,512K flash,
64K RAM)。
STM32-SK 的硬件連接方法(用板載調(diào)試器調(diào)試板載 DEMO):
JP3、JP5 須全部短接
USB 通過電纜連接至 PC 的 USB
串口連接至 PC 的串口或者通過 USB 轉(zhuǎn)串口電纜連接(力特 Z-TEC,USB2.0與 RS232轉(zhuǎn)接電纜)
WindowsXP 自動(dòng)安裝驅(qū)動(dòng)
安裝完成后如果 DEMO 板里面有程序就會(huì)自動(dòng)運(yùn)行了。這是 ST-Link-II 的通用連接方法 以上是學(xué)習(xí)階段比較方便的仿真器,進(jìn)入工程階段后準(zhǔn)備換 J-Link V7的仿真器進(jìn)行開發(fā)。目前比較滿意的產(chǎn)品:JLink
v7+USB 轉(zhuǎn)串口:
購買后所需的改造:打開殼體,將 USB 的+5V 供電跟 JTAG20針的第二腳 Vsupply 飛線,提供目標(biāo)板5V500mA 的供電。 看中的特點(diǎn):集成串口,擁有20針 JTAG 可以改造 Vspply 為供電接口,小巧好帶,便宜。
常見的用于 STM32單片機(jī)的仿真器分類
a) Ulink2:之前常用的仿真器。Keil 公司產(chǎn)品,之前專用于 ARM7,現(xiàn)擴(kuò)展到 CortexM3,調(diào)試接口支持 JTAG 和 SWD, 連接到 PC 主機(jī)的 USB。現(xiàn)在這種調(diào)試器已經(jīng)用的越來越少了。
b) ST-Link-II:ST 公司的仿真接口,支持 IAR EWARM,USB 1.1全速,USB 電源供電,自適應(yīng)目標(biāo)系統(tǒng) JTAG 電平3.3V-5V, 可向目標(biāo)系統(tǒng)提供不大于5V/200mA 電源。這種調(diào)試器不多見,但是許多調(diào)試器與目標(biāo)板一體設(shè)計(jì)的學(xué)習(xí)板上常見。
c) J-Link V6/V7:SEGGER 公司產(chǎn)品,調(diào)試接口支持 JTAG 和 SWV(V7速度是 V6的12倍),USB 2.0接口,通過 USB 供 電,下載速度達(dá)到720k byte/s, 與 IAR WEARM 無縫集成,寬目標(biāo)板電壓范圍:1.2V-3.3V(V7支持5V),多核調(diào)試,給 目標(biāo)板提供3.3V50mA 電源。這種調(diào)試器現(xiàn)在出現(xiàn)的越來越多,兼容性比較好(主要是指能夠與 IAR WEARM 無縫集成 這點(diǎn)),國內(nèi)山寨貨和各種變種也很多。
6、目標(biāo)板主要分為一體化設(shè)計(jì)(與調(diào)試器、供電整合)和單獨(dú)設(shè)計(jì)兩類,詳細(xì)產(chǎn)品比較見豆皮的《如何選擇 STM32開 發(fā)板》。
STM32學(xué)前班教程之三:讓 PC 工作
開發(fā)軟件的選擇
1、 軟件與版本的選擇
需求:支持 STLink2或未來的 Jlink V7調(diào)試接口(因?yàn)?STM32-SK 使用這個(gè)接口),能夠找到去除軟件限制的方法,最好 具有中文版幫助和界面,最好帶有純軟件仿真
選擇:RealView MDK 3.23RPC 或者 IAR EWARM 4.42A(5版本觀望一下)。
2、 RealView MDK 3.23RPC(中國版)安裝與去除限制 第一步:執(zhí)行安裝程序完成基本安裝,最后選項(xiàng)選擇加入虛擬硬件,便于純軟件調(diào)試。
第二步:執(zhí)行軟件,點(diǎn)擊 File-->Licence Manager,復(fù)制 CID 的數(shù)據(jù)到破解器的 CID,其他選項(xiàng)如下圖,然后點(diǎn)擊 Generate。
第三步:復(fù)制 LIC0的數(shù)據(jù)到軟件的 LIC 框里面,點(diǎn)擊 Add LIC。注意添加序列號(hào)后 Licence Manager 會(huì)算出這個(gè)號(hào)對(duì)應(yīng) 的有效期,如果到期會(huì)顯示為紅色,需要重新點(diǎn)擊破解軟件的 Generate,再算一個(gè)填進(jìn)去就行了。
第四步:將 ST-LINKII-KEIL Driver 所需的文件(兩個(gè) DLL)拷貝到\Keil\ARM\BIN 下,替換原有文件。
第 五 步 : 打 開 Keil 安 裝 目 錄 下 的 TOOLS.INI 文 件 , 在 [ARM] 、 [ARMADS] 、 [KARM] 項(xiàng) 目 下 添 加
TDRV7=BIN\ST-LINKII-KEIL.dll("ST LinkII Debugger")行,并保存修改。
第六步:打開 MDK,在項(xiàng)目的 options 設(shè)置的 Debug 選項(xiàng)中選擇 ST LINKII Debugger,同時(shí)在 Utilities 的選項(xiàng)中選擇 ST LINKII Debugger。
完成以上步驟,就完成了 ST-LINKII 的相關(guān)配置,可以作為調(diào)試器開始使用。注意:目前 ST-LINKII 不支持 Flash 菜單中 的 Download 和 Erase 命令,程序在使用 Start/Stop Debug Session 時(shí)自動(dòng)載入 flash 中供調(diào)試。
3、 IAR EWARM 4.42A 安裝與破解
第一步:開始/運(yùn)行…/CMD 顯示 DOS 界面,執(zhí)行 iarid.exe>>ID.TXT 得到本機(jī) ID 碼,復(fù)制這個(gè) ID 碼,再執(zhí)行 iarkg.exe ID
碼>>Lic422A.TXT,得到一組注冊(cè)碼。
第二步:使用 EWARM-EV-WEB-442A.exe(30天限制版,其他版本無法使用第一步中的注冊(cè)碼 ),執(zhí)行安裝程序完成基 本安裝,過程中需要添入第一步里面算出來的注冊(cè)碼,可以取消時(shí)間限制,但是那一組當(dāng)中只有一個(gè)有效,需要實(shí)驗(yàn)。
4、 鏈接硬件調(diào)試程序
RealView MDK:找到一個(gè) STM32-SK 的基礎(chǔ)程序,最好是只關(guān)于 IO 的且與當(dāng)前板子程序不同,這樣在板上就可以看到 結(jié)果,點(diǎn)擊 Project/open project。例如 GPIO、TIMER(另兩個(gè)例程是關(guān)于串口的,需要連接串口才能夠看到運(yùn)行結(jié)果)。
使用“Open Project”打開,然后設(shè)置 Option 里面的 linker 和 Utilities 里面的項(xiàng)目為“ST LinkII Debuger”。 編譯程序,再使用“Start/Stop Debug Session”來寫入程序。
IAR EWARM:與以上相同,找到一個(gè)符合條件的例程。打開一個(gè) eww 工程文件,右鍵選取 Option,在 Debuger 里面選 擇“Third-Party Driver”,在“Third-Party Driver”里面添上“$PROJ_DIR$\..\ddl\STM32Driver.dll”。
使用“Make”或“Rebuild All”來編譯程序,點(diǎn)“Debug”就燒寫進(jìn) Flash。使用調(diào)試欄里面的“go”等等運(yùn)行程序。 注:由于目前版本 MDK 與我手頭的 ST-LINK-II 編程器不兼容,所以后面的所有工作均改用 IAR。
STM32學(xué)前班教程之四:打好基礎(chǔ)建立模板
1、 新建目錄 Project_IAR4,按照自己的順序重新組織 dll(驅(qū)動(dòng));inc、src 函數(shù)庫;settings,其他所有文件全部放這個(gè) 新建的目錄下。
2、 雙擊打開 Project.eww,繼續(xù)更改內(nèi)部設(shè)置。
3、 需更改的內(nèi)容列表: 位置和項(xiàng)目 目標(biāo) 說明
Project\Edir confignations 新建基于 STM3210B 的配置 編譯目標(biāo)和過程文件存放
Project\Option\General Option\Target ST STM32F10x 選擇芯片類型
Project\Option\ C/C++ Compiler\Preprocessor\Additional include directories $PROJ_DIR$\
$PROJ_DIR$\inc 頭文件相對(duì)位置,需要包括“map/lib/type”的位置
Project\Option\ C/C++ Compiler\Preprocessor\Defined symbols 空 空白是在 Flash 里面調(diào)試程序,VECT_TAB_RAM 是在
RAM 里調(diào)試程序
Project\Option\ C/C++ Compiler\Optimizations\Size 最終編譯一般選擇 High
調(diào)試可選 None None,Low,Medium,High 是不同的代碼優(yōu)化等級(jí)
Project\Option\ Linker\Output 去掉 Overrride default 輸出格式使用默認(rèn)
Project\Option\ Linker\Extra Output 打開 General Extra Output 去掉 Overrride default 廠家要求
Project\Option\ Linker\Config 打開 Overrride default
$PROJ_DIR$\lnkarm_flash.xcl 使用 Flash 調(diào)試程序,如果需要使用 RAM 調(diào)試則改為 lnkarm_RAM.xcl
Project\Option\ Debugger\Setup\Driver Third-Party Driver 使用第三方驅(qū)動(dòng)連接單片機(jī)
Project\Option\ Debugger\ Download Use flash loader 下載到 flash 所需的設(shè)置
Project\Option\ Debugger\ Third-Party Driver\ Third-Party Driver\IAR debugger driver $PROJ_DIR$\ddl\STM32Driver.dll 驅(qū)動(dòng) 文件路徑
注1:所有跟路徑相關(guān)的設(shè)置需要根據(jù)實(shí)際情況編寫,相對(duì)路徑的編寫——“$PROJ_DIR$”代表 eww 文件所在文件夾,“..”
代表向上一層。 注2:其他設(shè)置使用庫函數(shù)里面的工程文件的默認(rèn)選項(xiàng)即可,初學(xué)不用了解太多。
4、 需要重新刪除并重新添加 Project 下“FWLib”和“User”的所有文件,為了刪減外設(shè)模塊方便需要在“USER”額外添加
“stm32f10x_conf.h”(不添加也可以,需要展開 main.c 找到它)。然后執(zhí)行 Project\Rebuid All,通過則設(shè)置完畢。
5、 完成以上步驟,第一個(gè)自己習(xí)慣的程序庫就建立完畢了,以后可以從 “stm32f10x_conf.h”中刪減各種庫文件,從 “stm32f10x_it.c”編輯中斷,從“main.c”編寫得到自己的程序。最后需要將這個(gè)庫打包封存,每次解壓縮并修改主目錄名稱 即可。
6、 我的程序庫特點(diǎn):
a) 默認(rèn)兼容 ST-LINK-II,IAR EWARM 4.42A,F(xiàn)lash 調(diào)試,其他有可能需要更改設(shè)置
b) 為操作方便減少了目錄的層次
c) 為學(xué)習(xí)方便使用網(wǎng)友漢化版2.0.2固件,主要是庫函數(shù)中 c 代碼的注釋。 后面隨著學(xué)習(xí)深入將在我的模板里面加入如下內(nèi)容:
d) 加入必用的 flash(讀取優(yōu)化),lib(debug),nvic(中斷位置判斷、開中斷模板),rcc(時(shí)鐘管理模板,開啟外設(shè)時(shí)鐘 模板),gpio(管腳定義模板)的初始化代碼,所有模板代碼用到的時(shí)候只要去掉前面的注釋“//”,根據(jù)需求填入相應(yīng)值 就可以了。
e) 因?yàn)樽约河浶圆缓,所?main 函數(shù)中的代碼做到每行注釋,便于自己以后使用。
f) 集成 Print_U 函數(shù)簡單串口收發(fā)函數(shù)代碼,便于調(diào)試,改變使用 Printf 函數(shù)的調(diào)試習(xí)慣。
g) 集成使用 systick 的精確延時(shí)函數(shù) delay。
h) 集成時(shí)鐘故障處理代碼。
i) 集成電壓監(jiān)控代碼。
j) 集成片上溫度檢測(cè)代碼。
k) 逐步加入所有外設(shè)的初始化模塊 一、編寫程序所需的步驟
1、解壓縮,改目錄名稱,和 eww 文件名,以便跟其他程序區(qū)分。
2、更改設(shè)置:在“stm32f10x_conf.h”關(guān)閉不用的外設(shè)(在其聲明函數(shù)前面加注釋符號(hào)“//”)。并根據(jù)外部晶振速度更改其中
“HSE_Value”的數(shù)值,其單位是 Hz。
3、完成各種頭文件的包含(#i nclude "xxx.h";),公共變量的聲明(static 數(shù)據(jù)類型 變量名稱;),子程序聲明(void 函 數(shù)名稱(參數(shù));)……C 語言必須的前置工作。
4、改寫我的程序庫里面所預(yù)設(shè)的模板,再進(jìn)行其他模塊的初始化子程序代碼的編寫,并在程序代碼的開始部分調(diào)用。注 意:必須記住所有外設(shè)的使用需要考慮4個(gè)問題:
a) 開時(shí)鐘 RCC(在 RCC 初始化中);
b) 自身初始化;
c) 相關(guān)管腳配置(在 GPIO 初始化中);
d) 是否使用中斷(在 NVIC 初始化中)
5、編寫 main.c 中的主要代碼和各種子函數(shù)。
6、在“stm32f10x_it.c”填寫各種中斷所需的執(zhí)行代碼,如果用不到中斷的簡單程序則不用編寫此文件。
7、編譯生成 “bin”的方法:Project\Option\ Linker\Output\Format,里面選擇“Other”,在下面的“Output”選 “raw-binary”生 成 bin。
8、編譯生成“hex”的方法:Project\Option\ Linker\Output\Format,里面選擇“Other”,在下面的“Output”選“intel-extended”, 生成 a79直接改名成為 hex 或者選中上面的“Output Flie”在“Overrride default”項(xiàng)目里面改擴(kuò)展名為 hex。
使用軟件界面的 Debug 燒寫并按鈕調(diào)試程序。注意,ST-Link-II 是直接將程序燒寫進(jìn) Flash 進(jìn)行調(diào)試,而不是使用 RAM
的方式。
STM32學(xué)前班教程之五:給等待入門的人一點(diǎn)點(diǎn)建議
入門必須閱讀的相關(guān)文檔
1、 幾個(gè)重要官方文檔的功能:
a) Datasheet——芯片基本數(shù)據(jù),功能參數(shù)封裝管腳定義和性能規(guī)范。
b) 固件函數(shù)庫用戶手冊(cè)——函數(shù)庫功能,庫函數(shù)的定義、功能和用法。 c) 參考手冊(cè)——各種功能的具體描述,使用方法,原理,相關(guān)寄存器。 d) STM32F10xxx 硬件開發(fā):使用入門——相關(guān)基礎(chǔ)硬件設(shè)計(jì)
e) STM32F10XXX 的使用限制:芯片內(nèi)部未解決的硬件設(shè)計(jì) bug,開發(fā)需要注意繞開。
f) 一本簡單的 C 語言書,相信我,不用太復(fù)雜。
2、 其他的有用文檔,對(duì)初學(xué)幫助很大
a) 如何使用 STM32的軟件庫在 IAR 的 EWARM 下進(jìn)行應(yīng)用開發(fā)——IAR 基礎(chǔ)設(shè)置。
b) 輕松進(jìn)入 STM32+Cortex-M3世界.ppt——開發(fā)板和最小系統(tǒng)設(shè)計(jì)需求。
c) 如何選擇 STM32開發(fā)板.pdf——各種開發(fā)板介紹和功能比較。
d) MXCHIP 的系列視頻教程——全部芯片基礎(chǔ)及其外設(shè)的教程,使用函數(shù)庫編程的話就不用看每個(gè)視頻后半段的關(guān)于寄 存器的介紹了。
e) STM32_Technical_Slide(常見問題)——一些優(yōu)化設(shè)計(jì)方案。
3、 關(guān)于參考書,買了兩本但是基本對(duì)學(xué)習(xí)沒什么幫助,如果湊齊以上資料,建議慎重買書,不如留著那 n 個(gè)幾十塊錢, 攢到一起買開發(fā)板。
我自己的學(xué)習(xí)過程
1、 一共24個(gè)庫,不可能都學(xué),都學(xué)也沒用。按照我的工作需求必須學(xué)的有16個(gè),這16個(gè)也不是全學(xué)。主要學(xué)習(xí)來源是
各種例程代碼、“固件函數(shù)庫用戶手冊(cè)”和“參考手冊(cè)”。
具體學(xué)習(xí)方法是通讀不同來源的程序,在程序中找到相關(guān)的函數(shù)庫的應(yīng)用,然后再閱讀相關(guān)文檔,有條件的實(shí)驗(yàn)。對(duì)于 內(nèi)容的選擇方面,根據(jù)入門內(nèi)容和未來應(yīng)用,將所涉及的范圍精簡到最低,但是對(duì)所選擇的部分的學(xué)習(xí)則力求明確。以 下是我按照自己的需求對(duì)程序庫函數(shù)排列的學(xué)習(xí)順序:
a) 絕大部分程序都要涉及到的庫——flash,lib,nvic,rcc,只學(xué)基礎(chǔ)的跟最簡單應(yīng)用相關(guān)必用的部分,其他部分后期再 返回頭學(xué)。
b) 各種程序通用但不必用的庫——exti,MDA,systic,只通讀理解其作用。
c) DEMO 板擁有的外設(shè)庫——gpio,usart,編寫代碼實(shí)驗(yàn)。
d) 未來需要用到的外設(shè)的庫——tim,tim1,adc,i2c,spi,先理解等待有條件后實(shí)驗(yàn)。
e) 開發(fā)可靠性相關(guān)庫——bkp,iwdg,wwdg,pwr,參考其他例程的做法。
f) 其他,根據(jù)興趣來學(xué)。
STM32學(xué)前班教程之六:這些代碼大家都用得到
2、 閱讀 flash: 芯片內(nèi)部存儲(chǔ)器 flash 操作函數(shù)
我的理解——對(duì)芯片內(nèi)部 flash 進(jìn)行操作的函數(shù),包括讀取,狀態(tài),擦除,寫入等等,可以允許程序去操作 flash 上的數(shù) 據(jù)。
基礎(chǔ)應(yīng)用1,F(xiàn)LASH 時(shí)序延遲幾個(gè)周期,等待總線同步操作。推薦按照單片機(jī)系統(tǒng)運(yùn)行頻率,0—24MHz 時(shí),取 Latency=0;
24—48MHz 時(shí),取 Latency=1;48~72MHz 時(shí),取 Latency=2。所有程序中必須的 用法:FLASH_SetLatency(FLASH_Latency_2);
位置:RCC 初始化子函數(shù)里面,時(shí)鐘起振之后。
基礎(chǔ)應(yīng)用2,開啟 FLASH 預(yù)讀緩沖功能,加速 FLASH 的讀取。所有程序中必須的 用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
位置:RCC 初始化子函數(shù)里面,時(shí)鐘起振之后。
3、 閱讀 lib:調(diào)試所有外設(shè)初始化的函數(shù)。
我的理解——不理解,也不需要理解。只要知道所有外設(shè)在調(diào)試的時(shí)候,EWRAM 需要從這個(gè)函數(shù)里面獲得調(diào)試所需信 息的地址或者指針之類的信息。
基礎(chǔ)應(yīng)用1,只有一個(gè)函數(shù) debug。所有程序中必須的。 用法: #ifdef DEBUG
debug();
#endif
位置:main 函數(shù)開頭,聲明變量之后。
4、 閱讀 nvic:系統(tǒng)中斷管理。 我的理解——管理系統(tǒng)內(nèi)部的中斷,負(fù)責(zé)打開和關(guān)閉中斷。 基礎(chǔ)應(yīng)用1,中斷的初始化函數(shù),包括設(shè)置中斷向量表位置,和開啟所需的中斷兩部分。所有程序中必須的。 用法: void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;//中斷管理恢復(fù)默認(rèn)參數(shù)
#ifdef VECT_TAB_RAM
//如果 C/C++ Compiler\Preprocessor\Defined symbols 中的定義了 VECT_TAB_RAM(見程序庫更改內(nèi)容的表格)
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //則在 RAM 調(diào)試
#else //如果沒有定義 VECT_TAB_RAM NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//則在 Flash 里調(diào)試
#endif //結(jié)束判斷語句
//以下為中斷的開啟過程,不是所有程序必須的。
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//設(shè)置 NVIC 優(yōu)先級(jí)分組,方式。
//注:一共16個(gè)優(yōu)先級(jí),分為搶占式和響應(yīng)式。兩種優(yōu)先級(jí)所占的數(shù)量由此代碼確定,NVIC_PriorityGroup_x 可以是0、1、
2、3、4,分別代表搶占優(yōu)先級(jí)有1、2、4、8、16個(gè)和響應(yīng)優(yōu)先級(jí)有16、8、4、2、1個(gè)。規(guī)定兩種優(yōu)先級(jí)的數(shù)量后,所有 的中斷級(jí)別必須在其中選擇,搶占級(jí)別高的會(huì)打斷其他中斷優(yōu)先執(zhí)行,而響應(yīng)級(jí)別高的會(huì)在其他中斷執(zhí)行完優(yōu)先執(zhí)行。
//NVIC_InitStructure.NVIC_IRQChannel = 中斷通道名;
//開中斷,中斷名稱見函數(shù)庫
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
//搶占優(yōu)先級(jí)
//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
//響應(yīng)優(yōu)先級(jí)
//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//啟動(dòng)此通道的中斷
//NVIC_Init(&NVIC_InitStructure); //中斷初始化
}
5、 閱讀 rcc:單片機(jī)時(shí)鐘管理。 我的理解——管理外部、內(nèi)部和外設(shè)的時(shí)鐘,設(shè)置、打開和關(guān)閉這些時(shí)鐘。 基礎(chǔ)應(yīng)用1:時(shí)鐘的初始化函數(shù)過程——
用法:void RCC_Configuration(void) //時(shí)鐘初始化函數(shù)
{
ErrorStatus HSEStartUpStatus; //等待時(shí)鐘的穩(wěn)定 RCC_DeInit(); //時(shí)鐘管理重置 RCC_HSEConfig(RCC_HSE_ON); //打開外部晶振 HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部晶振就緒
if (HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//flash 讀取緩沖,加速
FLASH_SetLatency(FLASH_Latency_2); //flash 操作的延時(shí) RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB 使用系統(tǒng)時(shí)鐘 RCC_PCLK2Config(RCC_HCLK_Div2); //APB2(高速)為 HCLK 的一半 RCC_PCLK1Config(RCC_HCLK_Div2); //APB1(低速)為 HCLK 的一半
//注:AHB 主要負(fù)責(zé)外部存儲(chǔ)器時(shí)鐘。PB2負(fù)責(zé) AD,I/O,高級(jí) TIM,串口1。APB1負(fù)責(zé) DA,USB,SPI,I2C,CAN, 串口2345,普通 TIM。
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//PLLCLK = 8MHz * 9 = 72 MHz
RCC_PLLCmd(ENABLE); //啟動(dòng) PLL
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}
//等待 PLL 啟動(dòng)
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//將 PLL 設(shè)置為系統(tǒng)時(shí)鐘源
while (RCC_GetSYSCLKSource() != 0x08){}
//等待系統(tǒng)時(shí)鐘源的啟動(dòng)
}
//RCC_AHBPeriphClockCmd(ABP2設(shè)備1 | ABP2設(shè)備2 |, ENABLE);
//啟動(dòng) AHP 設(shè)備
//RCC_APB2PeriphClockCmd(ABP2設(shè)備1 | ABP2設(shè)備2 |, ENABLE);
//啟動(dòng) ABP2設(shè)備
//RCC_APB1PeriphClockCmd(ABP2設(shè)備1 | ABP2設(shè)備2 |, ENABLE);
//啟動(dòng) ABP1設(shè)備
}
1、閱讀 exti:外部設(shè)備中斷函數(shù) 我的理解——外部設(shè)備通過引腳給出的硬件中斷,也可以產(chǎn)生軟件中斷,19個(gè)上升、下降或都觸發(fā)。EXTI0~EXTI15連
接到管腳,EXTI 線16連接到 PVD(VDD 監(jiān)視),EXTI 線17連接到 RTC(鬧鐘),EXTI 線18連接到 USB(喚醒)。 基礎(chǔ)應(yīng)用1,設(shè)定外部中斷初始化函數(shù)。按需求,不是必須代碼。
用法: void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure; //外部設(shè)備中斷恢復(fù)默認(rèn)參數(shù)
EXTI_InitStructure.EXTI_Line = 通道1|通道2;
//設(shè)定所需產(chǎn)生外部中斷的通道,一共19個(gè)。
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //產(chǎn)生中斷
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
//上升下降沿都觸發(fā)
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //啟動(dòng)中斷的接收
EXTI_Init(&EXTI_InitStructure); //外部設(shè)備中斷啟動(dòng)
}
2、閱讀 dma:通過總線而越過 CPU 讀取外設(shè)數(shù)據(jù)
我的理解——通過 DMA 應(yīng)用可以加速單片機(jī)外設(shè)、存儲(chǔ)器之間的數(shù)據(jù)傳輸,并在傳輸期間不影響 CPU 進(jìn)行其他事情。 這對(duì)于入門開發(fā)基本功能來說沒有太大必要,這個(gè)內(nèi)容先行跳過。
3、閱讀 systic:系統(tǒng)定時(shí)器
我的理解——可以輸出和利用系統(tǒng)時(shí)鐘的計(jì)數(shù)、狀態(tài)。 基礎(chǔ)應(yīng)用1,精確計(jì)時(shí)的延時(shí)子函數(shù)。推薦使用的代碼。
用法:
static vu32 TimingDelay;//全局變量聲明
void SysTick_Config(void)//systick 初始化函數(shù)
{
SysTick_CounterCmd(SysTick_Counter_Disable);//停止系統(tǒng)定時(shí)器
SysTick_ITConfig(DISABLE); //停止 systick 中斷
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//systick 使用 HCLK 作為時(shí)鐘源,頻率值除以8。 SysTick_SetReload(9000);//重置時(shí)間1毫秒(以72MHz 為基礎(chǔ)計(jì)算) SysTick_ITConfig(ENABLE);//開啟 systic 中斷
}
void Delay (u32 nTime) //延遲一毫秒的函數(shù)
{
SysTick_CounterCmd(SysTick_Counter_Enable); //systic 開始計(jì)時(shí)
TimingDelay = nTime; //計(jì)時(shí)長度賦值給遞減變量
while(TimingDelay != 0); //檢測(cè)是否計(jì)時(shí)完成
SysTick_CounterCmd(SysTick_Counter_Disable); //關(guān)閉計(jì)數(shù)器
SysTick_CounterCmd(SysTick_Counter_Clear); //清除計(jì)數(shù)值
}
void TimingDelay_Decrement(void)
//遞減變量函數(shù),函數(shù)名由“stm32f10x_it.c”中的中斷響應(yīng)函數(shù)定義好了。
{
if (TimingDelay != 0x00) //檢測(cè)計(jì)數(shù)變量是否達(dá)到0
{
TimingDelay--; //計(jì)數(shù)變量遞減
}
}
注:建議熟練后使用,所涉及知識(shí)和設(shè)備太多,新手出錯(cuò)的可能性比較大。新手可用簡化的延時(shí)函數(shù)代替:
void Delay(vu32 nCount)//簡單延時(shí)函數(shù)
{
for(; nCount != 0; nCount--);(循環(huán)變量遞減計(jì)數(shù))
}
當(dāng)延時(shí)較長,又不需要精確計(jì)時(shí)的時(shí)候可以使用嵌套循環(huán):
void Delay(vu32 nCount) //簡單的長時(shí)間延時(shí)函數(shù)
{int i; //聲明內(nèi)部遞減變量
for(; nCount != 0; nCount--) //遞減變量計(jì)數(shù)
{for (i=0; i<0xffff; i++)} //內(nèi)部循環(huán)遞減變量計(jì)數(shù)
}
4、閱讀 gpio:I/O 設(shè)置函數(shù)
我的理解——所有輸入輸出管腳模式設(shè)置,可以是上下拉、浮空、開漏、模擬、推挽模式,頻率特性為2M,10M,50M。 也可以向該管腳直接寫入數(shù)據(jù)和讀取數(shù)據(jù)。
基礎(chǔ)應(yīng)用1,gpio 初始化函數(shù)。所有程序必須。 用法:void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //GPIO 狀態(tài)恢復(fù)默認(rèn)參數(shù)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_標(biāo)號(hào) | GPIO_Pin_標(biāo)號(hào) ;
//管腳位置定義,標(biāo)號(hào)可以是 NONE、ALL、0至15。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//輸出速度2MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模擬輸入模式 GPIO_Init(GPIOC, &GPIO_InitStructure); //C 組 GPIO 初始化
//注:以上四行代碼為一組,每組 GPIO 屬性必須相同,默認(rèn)的 GPIO 參數(shù)為:ALL,2MHz,F(xiàn)LATING。如果其中任意 一行與前一組相應(yīng)設(shè)置相同,那么那一行可以省略,由此推論如果前面已經(jīng)將此行參數(shù)設(shè)定為默認(rèn)參數(shù)(包括使 用 GPIO_InitTypeDef GPIO_InitStructure 代碼),本組應(yīng)用也是默認(rèn)參數(shù)的話,那么也可以省略。以下重復(fù)這個(gè)過程直到所有 應(yīng)用的管腳全部被定義完畢。
……
}
基礎(chǔ)應(yīng)用2,向管腳寫入0或1
用法:GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1
STM32筆記之七:讓它跑起來,基本硬件功能的建立
0、 實(shí)驗(yàn)之前的準(zhǔn)備
a) 接通串口轉(zhuǎn)接器
b) 下載 IO 與串口的原廠程序,編譯通過保證調(diào)試所需硬件正常。
1、 flash,lib,nvic,rcc 和 GPIO,基礎(chǔ)程序庫編寫
a) 這幾個(gè)庫函數(shù)中有一些函數(shù)是關(guān)于芯片的初始化的,每個(gè)程序中必用。為保障程序品質(zhì),初學(xué)階段要求嚴(yán)格 遵守官方習(xí)慣。注意,官方程序庫例程中有個(gè) platform_config.h 文件,是專門用來指定同類外設(shè)中第幾號(hào)外設(shè)被使用, 就是說在 main.c 里面所有外設(shè)序號(hào)用 x 代替,比如 USARTx,程序會(huì)到這個(gè)頭文件中去查找到底是用那些外設(shè),初學(xué)的 時(shí)候參考例程別被這個(gè)所迷惑住。
b) 全部必用代碼取自庫函數(shù)所帶例程,并增加逐句注釋。
c) 習(xí)慣順序——Lib(debug),RCC(包括 Flash 優(yōu)化),NVIC,GPIO
d) 必用模塊初始化函數(shù)的定義:
void RCC_Configuration(void); //定義時(shí)鐘初始化函數(shù)
void GPIO_Configuration(void); //定義管腳初始化函數(shù)
void NVIC_Configuration(void); //定義中斷管理初始化函數(shù) void Delay(vu32 nCount); //定義延遲函數(shù) e) Main 中的初始化函數(shù)調(diào)用:
RCC_Configuration(); //時(shí)鐘初始化函數(shù)調(diào)用 NVIC_Configuration(); //中斷初始化函數(shù)調(diào)用 GPIO_Configuration(); //管腳初始化函數(shù)調(diào)用
f) Lib 注意事項(xiàng):
屬于 Lib 的 Debug 函數(shù)的調(diào)用,應(yīng)該放在 main 函數(shù)最開始,不要改變其位置。
g) RCC 注意事項(xiàng):
Flash 優(yōu)化處理可以不做,但是兩句也不難也不用改參數(shù)…… 根據(jù)需要開啟設(shè)備時(shí)鐘可以節(jié)省電能 時(shí)鐘頻率需要根據(jù)實(shí)際情況設(shè)置參數(shù)
h) NVIC 注意事項(xiàng)
注意理解占先優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)的分組的概念 i) GPIO 注意事項(xiàng) 注意以后的過程中收集不同管腳應(yīng)用對(duì)應(yīng)的頻率和模式的設(shè)置。 作為高低電平的 I/O,所需設(shè)置:RCC 初始化里面打開 RCC_APB2
PeriphClockCmd(RCC_APB2Periph_GPIOA);GPIO 里面管腳設(shè)定:IO 輸出(50MHz,Out_PP);IO 輸入(50MHz,IPU);
j) GPIO 應(yīng)用
GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET);//重置
GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1
GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//寫入0
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) ;//讀入 IO
k) 簡單 Delay 函數(shù)
void Delay(vu32 nCount)//簡單延時(shí)函數(shù)
{for(; nCount != 0; nCount--);}
實(shí)驗(yàn)步驟:
RCC 初 始 化 函 數(shù) 里 添 加 : RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB , ENABLE);
不用其他中斷,NVIC 初始化函數(shù)不用改
GPIO 初始化代碼:
//IO 輸入,GPIOB 的2、10、11腳輸出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;//管腳號(hào) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //輸出速度
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //輸入輸出模式
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化 簡單的延遲函數(shù):
void Delay(vu32 nCount) //簡單延時(shí)函數(shù)
{ for (; nCount != 0; nCount--);} //循環(huán)計(jì)數(shù)延時(shí) 完成之后再在 main.c 的 while 里面寫一段: GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1
Delay(0xffff);
GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//寫入0
Delay(0xffff);
就可以看到連接在 PB2腳上的 LED 閃爍了,單片機(jī)就跑起來了。
STM32筆記之八:來跟 PC 打個(gè)招呼,基本串口通訊
a) 目的:在基礎(chǔ)實(shí)驗(yàn)成功的基礎(chǔ)上,對(duì)串口的調(diào)試方法進(jìn)行實(shí)踐。硬件代碼順利完成之后,對(duì)日后調(diào)試需要用 到的 printf 重定義進(jìn)行調(diào)試,固定在自己的庫函數(shù)中。
b) 初始化函數(shù)定義:
void USART_Configuration(void); //定義串口初始化函數(shù)
c) 初始化函數(shù)調(diào)用:
void UART_Configuration(void); //串口初始化函數(shù)調(diào)用 初始化代碼:
void USART_Configuration(void) //串口初始化函數(shù)
{
//串口參數(shù)初始化
USART_InitTypeDef USART_InitStructure; //串口設(shè)置恢復(fù)默認(rèn)參數(shù)
//初始化參數(shù)設(shè)置
USART_InitStructure.USART_BaudRate = 9600; //波特率9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長8位 USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止字節(jié) USART_InitStructure.USART_Parity = USART_Parity_No; //無奇偶校驗(yàn) USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//打開 Rx 接收和 Tx 發(fā)送功能
USART_Init(USART1, &USART_InitStructure); //初始化
USART_Cmd(USART1, ENABLE); //啟動(dòng)串口
}
RCC 中打開相應(yīng)串口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE); GPIO 里面設(shè)定相應(yīng)串口管腳模式
//串口1的管腳初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //管腳9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出 GPIO_Init(GPIOA, &GPIO_InitStructure); //TX 初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //管腳10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //RX 初始化
d) 簡單應(yīng)用:
發(fā)送一位字符
USART_SendData(USART1, 數(shù)據(jù)); //發(fā)送一位數(shù)據(jù)
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}
//等待發(fā)送完畢 接收一位字符
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){}
//等待接收完畢
變量= (USART_ReceiveData(USART1)); //接受一個(gè)字節(jié) 發(fā)送一個(gè)字符串
先定義字符串:char rx_data[250];
然后在需要發(fā)送的地方添加如下代碼
int i; //定義循環(huán)變量
while(rx_data!='\0') //循環(huán)逐字輸出,到結(jié)束字'\0'
{USART_SendData(USART1, rx_data); //發(fā)送字符
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符發(fā)送完畢
i++;}
e) USART 注意事項(xiàng): 發(fā)動(dòng)和接受都需要配合標(biāo)志等待。 只能對(duì)一個(gè)字節(jié)操作,對(duì)字符串等大量數(shù)據(jù)操作需要寫函數(shù) 使用串口所需設(shè)置:RCC 初始化里面打開 RCC_APB2PeriphClockCmd
(RCC_APB2Periph_USARTx);GPIO 里面管腳設(shè)定:串口 RX(50Hz,IN_FLOATING);串口 TX(50Hz,AF_PP);
f) printf 函數(shù)重定義(不必理解,調(diào)試通過以備后用)
(1) 需要 c 標(biāo)準(zhǔn)函數(shù):
#i nclude "stdio.h"
(2) 粘貼函數(shù)定義代碼
#define PUTCHAR_PROTOTYPE int io_putchar(int ch) //定義為 putchar 應(yīng)用
(3) RCC 中打開相應(yīng)串口
(4) GPIO 里面設(shè)定相應(yīng)串口管腳模式
(6) 增加為 putchar 函數(shù)。
int putchar(int c) //putchar 函數(shù)
{
if (c == '\n'){putchar('\r');} //將 printf 的\n 變成\r USART_SendData(USART1, c); //發(fā)送字符 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發(fā)送結(jié)束 return c; //返回值
}
(8) 通過,試驗(yàn)成功。printf 使用變量輸出:%c 字符,%d 整數(shù),%f 浮點(diǎn)數(shù),%s 字符串,/n 或/r 為換行。注意: 只能用于 main.c 中。
3、 NVIC 串口中斷的應(yīng)用
a) 目的:利用前面調(diào)通的硬件基礎(chǔ),和幾個(gè)函數(shù)的代碼,進(jìn)行串口的中斷輸入練習(xí)。因?yàn)樵趯?shí)際應(yīng)用中,不使 用中斷進(jìn)行的輸入是效率非常低的,這種用法很少見,大部分串口的輸入都離不開中斷。
b) 初始化函數(shù)定義及函數(shù)調(diào)用:不用添加和調(diào)用初始化函數(shù),在指定調(diào)試地址的時(shí)候已經(jīng)調(diào)用過,在那 個(gè)
NVIC_Configuration 里面添加相應(yīng)開中斷代碼就行了。
c) 過程:
i. 在串口初始化中 USART_Cmd 之前加入中斷設(shè)置:
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE 發(fā)送中斷,TC 傳輸完成中斷,RXNE 接收中斷,PE 奇偶 錯(cuò)誤中斷,可以是多個(gè)。
ii. RCC、GPIO 里面打開串口相應(yīng)的基本時(shí)鐘、管腳設(shè)置
iii. NVIC 里面加入串口中斷打開代碼: NVIC_InitTypeDef NVIC_InitStructure;//中斷默認(rèn)參數(shù) NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道設(shè)置為串口1中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中斷占先等級(jí)0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中斷響應(yīng)優(yōu)先級(jí)0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打開中斷
NVIC_Init(&NVIC_InitStructure); //初始化
iv. 在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數(shù),在其中添入執(zhí)行代碼。一般最少三個(gè)步驟:先 使用 if 語句判斷是發(fā)生那個(gè)中斷,然后清除中斷標(biāo)志位,最后給字符串賦值,或做其他事情。
void USART1_IRQHandler(void) //串口1中斷
{
char RX_dat; //定義字符變量
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判斷發(fā)生接收中斷
{USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中斷標(biāo)志
GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01); //開始傳輸 RX_dat=USART_ReceiveData(USART1) & 0x7F; //接收數(shù)據(jù),整理除去前兩位 USART_SendData(USART1, RX_dat); //發(fā)送數(shù)據(jù) while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待發(fā)送結(jié)束
}
}
d) 中斷注意事項(xiàng):
可以隨時(shí)在程序中使用 USART_ITConfig(USART1, USART_IT_TXE, DISABLE);來關(guān)閉中斷響應(yīng)。
NVIC_InitTypeDef NVIC_InitStructure 定義一定要加在 NVIC 初始化模塊的第一句。
全局變量與函數(shù)的定義:在任意.c 文件中定義的變量或函數(shù),在其它.c 文件中使用 extern+定義代碼再次定義就可以直接 調(diào)用了。
STM32筆記之九:打斷它來為我辦事,EXIT (外部 I/O 中斷)應(yīng)用
a) 目的:跟串口輸入類似,不使用中斷進(jìn)行的 IO 輸入效率也很低,而且可以通過 EXTI 插入按鈕事件,本節(jié)聯(lián) 系 EXTI 中斷。
b) 初始化函數(shù)定義:
void EXTI_Configuration(void); //定義 IO 中斷初始化函數(shù)
c) 初始化函數(shù)調(diào)用:
EXTI_Configuration();//IO 中斷初始化函數(shù)調(diào)用簡單應(yīng)用:
d) 初始化函數(shù):
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure; //EXTI 初始化結(jié)構(gòu)定義
EXTI_ClearITPendingBit(EXTI_LINE_KEY_BUTTON);//清除中斷標(biāo)志
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//管腳選擇
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//事件選擇 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//觸發(fā)模式 EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //線路選擇 EXTI_InitStructure.EXTI_LineCmd = ENABLE;//啟動(dòng)中斷 EXTI_Init(&EXTI_InitStructure);//初始化
}
e) RCC 初始化函數(shù)中開啟 I/O 時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);
GPIO 初始化函數(shù)中定義輸入 I/O 管腳。
//IO 輸入,GPIOA 的4腳輸入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化
f) 在 NVIC 的初始化函數(shù)里面增加以下代碼打開相關(guān)中斷: NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先級(jí) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)級(jí)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動(dòng)
NVIC_Init(&NVIC_InitStructure); //初始化
g) 在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數(shù),在其中添入執(zhí)行代碼。一般最少三個(gè)步驟:先 使用 if 語句判斷是發(fā)生那個(gè)中斷,然后清除中斷標(biāo)志位,最后給字符串賦值,或做其他事情。
if(EXTI_GetITStatus(EXTI_Line3) != RESET) //判斷中斷發(fā)生來源
{ EXTI_ClearITPendingBit(EXTI_Line3); //清除中斷標(biāo)志 USART_SendData(USART1, 0x41); //發(fā)送字符“a” GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED 發(fā) 生 明 暗
交替
}
h) 中斷注意事項(xiàng): 中斷發(fā)生后必須清除中斷位,否則會(huì)出現(xiàn)死循環(huán)不斷發(fā)生這個(gè)中斷。然后需要對(duì)中斷類型進(jìn)行判斷再執(zhí)行代碼。
使用 EXTI 的 I/O 中斷,在完成 RCC 與 GPIO 硬件設(shè)置之后需要做三件事:初始化 EXTI、NVIC 開中斷、編寫中斷執(zhí)行 代碼。
STM32筆記之十:工作工作,PWM 輸出
a) 目的:基礎(chǔ) PWM 輸出,以及中斷配合應(yīng)用。輸出選用 PB1,配置為 TIM3_CH4,是目標(biāo)板的 LED6控制腳。
b) 對(duì)于簡單的 PWM 輸出應(yīng)用,暫時(shí)無需考慮 TIM1的高級(jí)功能之區(qū)別。
c) 初始化函數(shù)定義:
void TIM_Configuration(void); //定義 TIM 初始化函數(shù)
d) 初始化函數(shù)調(diào)用:
TIM_Configuration(); //TIM 初始化函數(shù)調(diào)用
e) 初始化函數(shù),不同于前面模塊,TIM 的初始化分為兩部分——基本初始化和通道初始化:
void TIM_Configuration(void)//TIM 初始化函數(shù)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定時(shí)器初始化結(jié)構(gòu)
TIM_OCInitTypeDef TIM_OCInitStructure;//通道輸出初始化結(jié)構(gòu)
//TIM3初始化
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFF TIM_TimeBaseStructure.TIM_Prescaler = 5; //時(shí)鐘分頻 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時(shí)鐘分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //基本初始化 TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打開中斷,中斷需要這行代碼
//TIM3通道初始化
TIM_OCStructInit(& TIM_OCInitStructure); //默認(rèn)參數(shù) TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //工作狀態(tài) TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //設(shè)定為輸出,需要 PWM 輸出才需要這行
代碼
TIM_OCInitStructure.TIM_Pulse = 0x2000; //占空長度 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高電平 TIM_OC4Init(TIM3, &TIM_OCInitStructure); //通道初始化
TIM_Cmd(TIM3, ENABLE); //啟動(dòng)
TIM3
}
f) RCC 初始化函數(shù)中加入 TIM 時(shí)鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g) GPIO 里面將輸入和輸出管腳模式進(jìn)行設(shè)置。信號(hào):AF_PP,50MHz。
h) 使用中斷的話在 NVIC 里添加如下代碼:
//打開 TIM2中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級(jí) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //響應(yīng)級(jí) NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動(dòng) NVIC_Init(&NVIC_InitStructure); //初始化
中斷代碼:
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET) //判斷中斷來源
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除中斷標(biāo)志
GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_11)));// 變 換 LED 色
彩
IC4value = TIM_GetCapture4(TIM2); //獲取捕捉數(shù)值
}
}
i) 簡單應(yīng)用:
//改變占空比
TIM_SetCompare4(TIM3, 變量);
j) 注意事項(xiàng):
管腳的 IO 輸出模式是根據(jù)應(yīng)用來定,比如如果用 PWM 輸出驅(qū)動(dòng) LED 則應(yīng)該將相應(yīng)管腳設(shè)為 AF_PP,否則單片機(jī)沒有 輸出。
STM32筆記之十一:捕捉精彩瞬間,脈沖方波長度捕獲
a) 目的:基礎(chǔ) PWM 輸入也叫捕獲,以及中斷配合應(yīng)用。使用前一章的輸出管腳 PB1(19腳),直接使用跳線連 接輸入的 PA3(13腳),配置為 TIM2_CH4,進(jìn)行實(shí)驗(yàn)。
b) 對(duì)于簡單的 PWM 輸入應(yīng)用,暫時(shí)無需考慮 TIM1的高級(jí)功能之區(qū)別,按照目前我的應(yīng)用目標(biāo)其實(shí)只需要采集 高電平寬度,而不必知道周期,所以并不采用 PWM 輸入模式,而是普通脈寬捕獲模式。
c) 初始化函數(shù)定義:
void TIM_Configuration(void); //定義 TIM 初始化函數(shù)
d) 初始化函數(shù)調(diào)用:
TIM_Configuration(); //TIM 初始化函數(shù)調(diào)用
e) 初始化函數(shù),不同于前面模塊,TIM 的 CAP 初始化分為三部分——計(jì)時(shí)器基本初始化、通道初始化和時(shí)鐘啟 動(dòng)初始化:
void TIM_Configuration(void)//TIM2的 CAP 初始化函數(shù)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定時(shí)器初始化結(jié)構(gòu)
TIM_ICInitTypeDef TIM_ICInitStructure; //通道輸入初始化結(jié)構(gòu)
//TIM2輸出初始化
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFF TIM_TimeBaseStructure.TIM_Prescaler = 5; //時(shí)鐘分頻 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時(shí)鐘分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式 TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//基本初始化
//TIM2通道的捕捉初始化
TIM_ICInitStructure.TIM_Channel = TIM_Channel_4;//通道選擇 TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Falling;//下降沿 TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;//管腳與寄存器對(duì)應(yīng)關(guān)系 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分頻器
TIM_ICInitStructure.TIM_ICFilter = 0x4; //濾波設(shè)置,經(jīng)歷幾個(gè)周期跳變認(rèn)定波形穩(wěn)定0x0~0xF TIM_ICInit(TIM2, &TIM_ICInitStructure); //初始化
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); //選擇時(shí)鐘觸發(fā)源
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);//觸發(fā)方式
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable); //啟動(dòng)定時(shí)器的被動(dòng)觸發(fā)
TIM_ITConfig(TIM2, TIM_IT_CC4, ENABLE); //打開中斷
TIM_Cmd(TIM2, ENABLE); //啟動(dòng) TIM2
}
f) RCC 初始化函數(shù)中加入 TIM 時(shí)鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g) GPIO 里面將輸入和輸出管腳模式進(jìn)行設(shè)置。IN_FLOATING,50MHz。
h) 使用中斷的話在 NVIC 里添加如下代碼:
//打開 TIM 中斷(與前一章相同)
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
i) 簡單應(yīng)用:
變量 = TIM_GetCapture4(TIM2);
j) 注意事項(xiàng):
i. 由于我的需求只跟高電平寬度有關(guān),所以避免了使用 PWM 輸入模式,這樣可以每個(gè)管腳捕捉一路信號(hào)。如果
使用 PWM 模式,每一路需要占用兩個(gè)寄存器,所以一個(gè)定時(shí)器只能同時(shí)使用兩路 PWM 輸入。
ii. 由于捕捉需要觸發(fā)啟動(dòng)定時(shí)器,所以 PWM 輸出與捕捉不容易在同一個(gè) TIM 通道上實(shí)現(xiàn)。如果必須的話只能 增加計(jì)數(shù)溢出的相關(guān)代碼。
iii. 有些程序省略了捕捉通道的初始化代碼,這是不對(duì)的
iv. 在基本計(jì)時(shí)器初始化代碼里面注意選擇適當(dāng)?shù)挠?jì)數(shù)器長度,最好讓波形長度不要長于一個(gè)計(jì)數(shù)周期,否則需 要增加溢出代碼很麻煩。一個(gè)計(jì)數(shù)周期的長度計(jì)算跟如下幾個(gè)參數(shù)有關(guān):
(1) RCC 初始化代碼里面的 RCC_PCLKxConfig,這是 TIM 的基礎(chǔ)時(shí)鐘源與系統(tǒng)時(shí)鐘的關(guān)系。
(2) TIM 初始化的 TIM_Period,這是計(jì)數(shù)周期的值
(3) TIM 初始化的 TIM_Prescaler,這是計(jì)數(shù)周期的倍頻計(jì)數(shù)器,相當(dāng)于調(diào)節(jié)計(jì)數(shù)周期,可以使 TIM_Period 盡 量大,提高計(jì)數(shù)精度。
STM32筆記之十二:時(shí)鐘不息工作不止,systic 時(shí)鐘應(yīng)用
a) 目的:使用系統(tǒng)時(shí)鐘來進(jìn)行兩項(xiàng)實(shí)驗(yàn)——周期執(zhí)行代碼與精確定時(shí)延遲。
b) 初始化函數(shù)定義:
void SysTick_Configuration(void);
c) 初始化函數(shù)調(diào)用:
SysTick_Configuration();
d) 初始化函數(shù):
void SysTick_Configuration(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//時(shí)鐘除8
SysTick_SetReload(250000); //計(jì)數(shù)周期長度
SysTick_CounterCmd(SysTick_Counter_Enable); //啟動(dòng)計(jì)時(shí)器
SysTick_ITConfig(ENABLE); //打開中斷
}
e) 在 NVIC 的初始化函數(shù)里面增加以下代碼打開相關(guān)中斷: NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中斷等級(jí)設(shè)置,一般設(shè)置的高一些會(huì)少受其他影響 f) 在 stm32f10x_it.c 文件中找到 void SysTickHandler 函數(shù)
void SysTickHandler(void)
{
執(zhí)行代碼
}
g) 簡單應(yīng)用:精確延遲函數(shù),因?yàn)?systic 中斷往往被用來執(zhí)行周期循環(huán)代碼,所以一些例程中使用其中斷的啟動(dòng) 和禁止來編寫的精確延時(shí)函數(shù)實(shí)際上不實(shí)用,我自己編寫了精確計(jì)時(shí)函數(shù)反而代碼更精簡,思路更簡單。思路是調(diào)用后, 變量清零,然后使用時(shí)鐘來的曾變量,不斷比較變量與延遲的數(shù)值,相等則退出函數(shù)。代碼和步驟如下:
i. 定義通用變量:u16 Tic_Val=0; //變量用于精確計(jì)時(shí)
ii. 在 stm32f10x_it.c 文件中相應(yīng)定義:
extern u16 Tic_Val;//在本文件引用 MAIN.c 定義的精確計(jì)時(shí)變量
iii. 定義函數(shù)名稱:void Tic_Delay(u16 Tic_Count);//精確延遲函數(shù)
iv. 精確延時(shí)函數(shù):
void Tic_Delay(u16 Tic_Count) //精確延時(shí)函數(shù)
{ Tic_Val=0; //變量清零
while(Tic_Val != Tic_Count){printf("");}//計(jì)時(shí)
}
v. 在 stm32f10x_it.c 文件中 void SysTickHandler 函數(shù)里面添加
Tic_Val++;//變量遞增
vi. 調(diào)用代碼:Tic_Delay(10); //精確延時(shí)
vii. 疑問:如果去掉計(jì)時(shí)行那個(gè)沒用的 printf("");函數(shù)將停止工作,這個(gè)現(xiàn)象很奇怪
STM32筆記之十三:惡搞,兩只看門狗 a) 目的: 了解兩種看門狗(我叫它:系統(tǒng)運(yùn)行故障探測(cè)器和獨(dú)立系統(tǒng)故障探測(cè)器,新手往往被這個(gè)并不形象的象形名稱搞糊涂)
之間的區(qū)別和基本用法。
b) 相同: 都是用來探測(cè)系統(tǒng)故障,通過編寫代碼定時(shí)發(fā)送故障清零信號(hào)(高手們都管這個(gè)代碼叫做“喂狗”),告訴它系統(tǒng)運(yùn)行正常。
一旦系統(tǒng)故障,程序清零代碼(“喂狗”)無法執(zhí)行,其計(jì)數(shù)器就會(huì)計(jì)數(shù)不止,直到記到零并發(fā)生故障中斷(狗餓了開始 叫喚),控制 CPU 重啟整個(gè)系統(tǒng)(不行啦,開始咬人了,快跑……)。
c) 區(qū)別:
獨(dú)立看門狗 Iwdg——我的理解是獨(dú)立于系統(tǒng)之外,因?yàn)橛歇?dú)立時(shí)鐘,所以不受系統(tǒng)影響的系統(tǒng)故障探測(cè)器。(這條狗是 借來的,見誰偷懶它都咬!)主要用于監(jiān)視硬件錯(cuò)誤。
窗口看門狗 wwdg——我的理解是系統(tǒng)內(nèi)部的故障探測(cè)器,時(shí)鐘與系統(tǒng)相同。如果系統(tǒng)時(shí)鐘不走了,這個(gè)狗也就失去作 用了。(這條狗是老板娘養(yǎng)的,老板不干活兒他不管。┲饕糜诒O(jiān)視軟件錯(cuò)誤。
d) 初始化函數(shù)定義:鑒于兩只狗作用差不多,使用過程也差不多初始化函數(shù)栓一起了,用的時(shí)候根據(jù)情況刪減。
void WDG_Configuration(void);
e) 初始化函數(shù)調(diào)用:
WDG_Configuration();
f) 初始化函數(shù)
void WDG_Configuration() //看門狗初始化
{
//軟件看門狗初始化
WWDG_SetPrescaler(WWDG_Prescaler_8); //時(shí)鐘8分頻4ms
// (PCLK1/4096)/8= 244 Hz (~4 ms)
WWDG_SetWindowValue(65); //計(jì)數(shù)器數(shù)值
WWDG_Enable(127); //啟動(dòng)計(jì)數(shù)器,設(shè)置喂狗時(shí)間
// WWDG timeout = ~4 ms * 64 = 262 ms
WWDG_ClearFlag(); //清除標(biāo)志位
WWDG_EnableIT(); //啟動(dòng)中斷
//獨(dú)立看門狗初始化 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//啟動(dòng)寄存器讀寫 IWDG_SetPrescaler(IWDG_Prescaler_32);//40K 時(shí)鐘32分頻 IWDG_SetReload(349); //計(jì)數(shù)器數(shù)值 IWDG_ReloadCounter(); //重啟計(jì)數(shù)器 IWDG_Enable(); //啟動(dòng)看門狗
}
g) RCC 初始化:只有軟件看門狗需要時(shí)鐘初始化,獨(dú)立看門狗有自己的時(shí)鐘不需要但是需要 systic 工作相關(guān)設(shè) 置。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
h) 獨(dú)立看門狗使用 systic 的中斷來喂狗,所以添加 systic 的中斷打開代碼就行了。軟件看門狗需要在 NVIC 打開 中斷添加如下代碼:
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //占先中斷等級(jí) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)中斷優(yōu)先級(jí) NVIC_Init(&NVIC_InitStructure); //打開中斷
i) 中斷程序,軟件看門狗在自己的中斷中喂狗,獨(dú)立看門狗需要使用 systic 的定時(shí)中斷來喂狗。以下兩個(gè)程序都
在 stm32f10x_it.c 文件中。
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(0x7F); //更新計(jì)數(shù)值
WWDG_ClearFlag(); //清除標(biāo)志位
}
void SysTickHandler(void)
{ IWDG_ReloadCounter(); //重啟計(jì)數(shù)器(喂狗)
}
j) 注意事項(xiàng):
i. 有狗平常沒事情可以不理,但是千萬別忘了喂它,否則死都不知道怎么死的!
ii. 初始化程序的調(diào)用一定要在 systic 的初始化之后。
iii. 獨(dú)立看門狗需要 systic 中斷來喂,但是 systic 做別的用處不能只做這件事,所以我寫了如下幾句代碼,可以 不影響 systic 的其他應(yīng)用,其他 systic 周期代碼也可參考:
第一步:在 stm32f10x_it.c 中定義變量
int Tic_IWDG; //喂狗循環(huán)程序的頻率判斷變量 第二步:將 SysTickHandler 中喂狗代碼改為下面: Tic_IWDG++; //變量遞增 if(Tic_IWDG>=100) //每100個(gè) systic 周期喂狗
{ IWDG_ReloadCounter();//重啟計(jì)數(shù)器(喂狗)
Tic_IWDG=0; //變量清零
}
STM32筆記之十四:基本問題,來討論一下軟件架構(gòu)
網(wǎng)上大家都在討論和學(xué)習(xí),但是對(duì)于架構(gòu)這個(gè)基本問題卻沒幾個(gè)人討論。個(gè)人認(rèn)為有個(gè)好的架構(gòu)是寫好代碼的基礎(chǔ),可 以使后期的調(diào)式工作事半功倍。
1、 架構(gòu)組成:我的程序代碼分為四種結(jié)構(gòu) a) 順序執(zhí)行代碼 定義:按照順序逐行執(zhí)行的代碼 優(yōu)點(diǎn):是思路簡單,代碼可靠不易被干擾。 缺點(diǎn):占用資源
用途:只用來各種變量、函數(shù)的定義,硬件的初始化程序 位置:main.c 的開始一直到 main 函數(shù)的 while 函數(shù)之前
b) 空閑執(zhí)行代碼
定義:在 CPU 空閑的時(shí)候才執(zhí)行的代碼 優(yōu)點(diǎn):不占用資源 缺點(diǎn):執(zhí)行的實(shí)時(shí)性不能保證
用途:非實(shí)時(shí)任務(wù),調(diào)試信息輸出,不重要的狀態(tài)指示 位置:main.c 的 main 函數(shù)的 while 函數(shù)內(nèi)部
c) 中斷執(zhí)行代碼 定義:由軟硬件事件打斷整個(gè)程序而執(zhí)行的代碼 優(yōu)點(diǎn):可以保證實(shí)時(shí)性,各種中斷可以安排優(yōu)先順序 缺點(diǎn):關(guān)系相對(duì)復(fù)雜,互相之間容易干擾 用途:觸發(fā)性的代碼,比如接收數(shù)據(jù),響應(yīng)外部設(shè)備,按鈕的相應(yīng) 位置:stm32f10x_it.c 內(nèi)部
d) 循環(huán)執(zhí)行代碼
定義:按照時(shí)間周期執(zhí)行的代碼 優(yōu)點(diǎn):定期自動(dòng)執(zhí)行 缺點(diǎn):實(shí)時(shí)性不好
用途:需要周期執(zhí)行的任務(wù),狀態(tài)檢查及相關(guān)信息輸出,數(shù)據(jù)記錄 位置:stm32f10x_it.c 的 SysTickHandler 內(nèi)部
e) DMA 自動(dòng)代碼 定義:不需要主程序干預(yù),外設(shè)自動(dòng)執(zhí)行 優(yōu)點(diǎn):自動(dòng)刷新數(shù)據(jù),不占用 CPU 資源 缺點(diǎn):不能控制 用途:數(shù)據(jù)通信存儲(chǔ),AD 轉(zhuǎn)換 位置:不需要
2、架構(gòu)執(zhí)行順序圖 下載 (51.33 KB)
深入淺出 STM32(2)
STM32學(xué)習(xí)筆記之十五——IAR4的最后瘋狂,笨笨的開發(fā)模板下載 準(zhǔn)備大換血了,包括開發(fā)環(huán)境升級(jí)和固件升級(jí),那個(gè)需要一定過程,吧之前完成的模板跟大家共享一下。 我的程序庫特點(diǎn):
a) 默認(rèn)兼容 ST-LINK-II,IAR EWARM 4.42A,F(xiàn)lash 調(diào)試,使用串口1,GPIOA 的3、4、
5、6腳輸入,GPIOB 的1、2、10、11腳輸出,其他有可能需要更改設(shè)置
b) 為操作方便減少了目錄的層次
c) 為學(xué)習(xí)方便使用網(wǎng)友漢化版2.0.2固件,主要是庫函數(shù)中 c 代碼的注釋。
d) 加入必用的 flash(讀取優(yōu)化),nvic(RAM 與 Flash 調(diào)試選擇),rcc(時(shí)鐘管理模 板,開啟外設(shè)時(shí)鐘模板),gpio(管腳定義模板)的初始化代碼,所有模板代碼用到的 時(shí)候只要去掉前面的注釋"//",根據(jù)需求填入相應(yīng)值就可以了。
e) 因?yàn)樽约河浶圆缓茫?main 函數(shù)中的代碼做到每行注釋,便于自己以后使用。
f) 列出常見應(yīng)用代碼模板與 ASCII 常用列表。
g) 集成 putchar 字符輸出和 Printf 的重定義到串口的代碼,便于調(diào)試。
h) 集成 NVIC 中斷管理模板,EXTI 外部 I/O 中斷模板
i) 針對(duì)自己情況集成 PWM 輸出模板和 CAP 脈寬捕捉模板,并全部注釋。
j) 集成系統(tǒng)循環(huán)時(shí)鐘的初始化函數(shù)模板
k) 集成自己編寫精確延時(shí)代碼,不會(huì)影響 systic 的周期代碼的執(zhí)行。
l) 集成兩種看門狗的使用代碼,小心使用
M) 集成 hex 生成設(shè)置命令,位置在編譯目錄(STM32F103C8)的 Exe 下,集成 ISP 軟件便 于脫離仿真器的串口調(diào)試 STMISP.exe。
由于注釋寫的太多,還加入自己編程以來的許多格式習(xí)慣,所以許多人會(huì)覺得混亂不堪,在
此聲明,此程序庫僅僅為個(gè)人學(xué)習(xí)之用!
STM32學(xué)習(xí)筆記之十六——題外話,自己做塊工程板 一、我的學(xué)習(xí)計(jì)劃將 STM32單片機(jī)的硬件設(shè)計(jì)工作:
第一步——用 STM32F103CBT6的48腳芯片,為光電平臺(tái)的簡單控制為目標(biāo),實(shí)現(xiàn)基本外圍硬件、PWM、串口、I/O。 將 SPI、I2C 留插針。
第二步——為集成傳感器應(yīng)用為目標(biāo),在第一步硬件基礎(chǔ)上制作功能性的套版,兩板連接實(shí)現(xiàn) AD、SPI、I2C、RTC 等 等功能。
二、硬件規(guī)劃
選用 STM32F103CBT6,面積7×7mm,128K flash,16K RAM,4個(gè)16bit PWM,12個(gè)12bit PWM 或 CAP,2個(gè) SPI,2個(gè)
I2C,3個(gè)串口,1個(gè) CAN,1個(gè) USB,),12ADC。
管腳分配目標(biāo)1如圖,之后的功能包括:4個(gè) AD,3個(gè)串口(1個(gè)與 I2C 復(fù)用),1個(gè) SPI,8個(gè)(兩組)PWM 輸入輸出,1
個(gè) USB,1個(gè) I/O,1個(gè) MCO。 三、管腳分配:
下載 (32.83 KB)
2009-4-26 16:14
四、ALTIUM DESIGNER 6(Protel 的第六個(gè)版本)操作筆記
之所以選擇這個(gè)軟件三個(gè)理由:1、界面習(xí)慣兼容 Protel。2、操作習(xí)慣于 Windows 類似方便。3、可輸出 igs 用于結(jié)構(gòu)設(shè) 計(jì)。
軟件使用筆記如下:
a) 流程:新建工程,添加原理圖,添加 SCH 庫,畫原理圖,添加 PCB 庫,設(shè)定封裝,添加 PCB,布線,檢查, 導(dǎo)出生產(chǎn)文件。
b) 新建工程:最好使用自己以前的同版本文檔設(shè)置,會(huì)包含各種庫省去大量工作
c) 添加器件到 SCH,可使用復(fù)制粘貼的辦法,注意管腳,有些需要外殼接地的器件把外殼的焊點(diǎn)畫出來。完成 后點(diǎn)擊放置,改動(dòng)后再器件名稱點(diǎn)擊右鍵更改。
d) 畫原理圖:操作類似其他 windows 軟件,會(huì)自動(dòng)檢查錯(cuò)誤連接和重復(fù)硬件。
e) 添加器件到 PCB 庫,最好使用拷貝粘貼的辦法,最好有官方的焊點(diǎn)圖。沒有的話可以按照封裝的型號(hào)直接去
http://www.***search.com/搜索封裝型號(hào)(不是器件型號(hào)),也有封裝的相關(guān)尺寸和焊點(diǎn)圖。
f) 雙擊原理圖的器件,在右下角改封裝名稱。 g) 添加新的 PCB 到工程: “設(shè)計(jì)/規(guī)則”改線寬、線距、器件距離……;
“設(shè)計(jì)/板子形狀/重新定義板子形狀”改工作區(qū)域大小,然后左鍵點(diǎn)擊前置 Keepout 層,畫電路板外形;
“設(shè)計(jì)/板參數(shù)選項(xiàng)”改網(wǎng)格大小,器件和走線中鼠標(biāo)捕捉的間隔大小……;
“設(shè)計(jì)/Import changes From……”引入原理圖的器件和連接方式,包括改動(dòng)(出現(xiàn)對(duì) match 提示選擇繼續(xù)就可以了);
“查看/切換單位”改公制和英制; “工具/取消布線”取消已經(jīng)布好的線; “自動(dòng)布線”計(jì)算機(jī)自動(dòng)布線,功能比 Protel 增強(qiáng)不少; “報(bào)告/測(cè)量距離”測(cè)量實(shí)際距離; 在層標(biāo)簽單擊,前置這個(gè)層。右鍵有隱藏層和顯示層比較常用。
屏幕中點(diǎn)擊右鍵菜單中“設(shè)計(jì)/規(guī)則”、“選項(xiàng)/板參數(shù)選項(xiàng)”、 “選項(xiàng)/層疊管理”(添加和刪除層)、“選項(xiàng)/顯示掩藏”(針對(duì) 各種類型進(jìn)行顯示和隱藏,查找未布的線就使用此功能后在操作框中點(diǎn)擊“所有最終”然后點(diǎn)擊“Apply”,再手工點(diǎn)擊所有 的選項(xiàng)為“隱藏的”再點(diǎn)“Apply”就能看到未布線的連線了)
快捷鍵:空格鍵旋轉(zhuǎn)器件,TAB 鍵切換線寬和放置過孔。左鍵單擊選擇,左鍵按住移動(dòng)器件(多個(gè)重疊會(huì)有列表選擇, 未松開時(shí)右鍵取消操作),左鍵雙擊改器件屬性(所在層、位置……),右鍵按住移動(dòng)鼠標(biāo)平移視野,滾輪上下移動(dòng),滾 輪按住移動(dòng)鼠標(biāo)放大縮小
五、基本電路原理設(shè)計(jì)
拋棄復(fù)雜設(shè)計(jì),專注于可獨(dú)立調(diào)式的 CPU 板設(shè)計(jì)。計(jì)劃設(shè)計(jì)模塊包括:供電、JTAG、晶振、RTC(電池引出)。 注:未使用標(biāo)準(zhǔn) JTAG 設(shè)計(jì),原因有三:
1、原設(shè)計(jì)太占管腳,這個(gè)尺寸實(shí)在難實(shí)現(xiàn)
2、這只是 CPU 板具體應(yīng)用會(huì)再做功能套版,上面可以連接標(biāo)準(zhǔn) JTAG
3、有可能向 USB 燒寫和 SW 雙線調(diào)式方向轉(zhuǎn)變,所以以后不一定會(huì)使用標(biāo)準(zhǔn) JTAG
本文來自 CSDN 博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/feiniao_lql/archive/2010/06/21/5684074.aspx
STM32 GPIO 應(yīng)用筆記
1 STM32的輸入輸出管腳有下面8種可能的配置:(4輸入+2輸出+2復(fù)用輸出)
① 浮空輸入_IN_FLOATING
② 帶上拉輸入_IPU
③ 帶下拉輸入_IPD
④ 模擬輸入_AIN
⑤ 開漏輸出_OUT_OD
⑥ 推挽輸出_OUT_PP
⑦ 復(fù)用功能的推挽輸出_AF_PP
⑧ 復(fù)用功能的開漏輸出_AF_OD
1.1 I/O 口的輸出模式下,有3種輸出速度可選(2MHz、10MHz 和50MHz),這個(gè)速度是指 I/O 口驅(qū)動(dòng)電路的響應(yīng) 速度而不是輸出信號(hào)的速度,輸出信號(hào)的速度與程序有關(guān)(芯片內(nèi)部在 I/O 口的輸出部分安排了多個(gè)響應(yīng)速度不同的輸 出驅(qū)動(dòng)電路,用戶可以根據(jù)自己的需要選擇合適的驅(qū)動(dòng)電路)。通過選擇速度來選擇不同的輸出驅(qū)動(dòng)模塊,達(dá)到最佳的噪 聲控制和降低功耗的目的。高頻的驅(qū)動(dòng)電路,噪聲也高,當(dāng)不需要高的輸出頻率時(shí),請(qǐng)選用低頻驅(qū)動(dòng)電路,這樣非常有 利于提高系統(tǒng)的 EMI 性能。當(dāng)然如果要輸出較高頻率的信號(hào),但卻選用了較低頻率的驅(qū)動(dòng)模塊,很可能會(huì)得到失真的輸 出信號(hào)。
關(guān)鍵是 GPIO 的引腳速度跟應(yīng)用匹配(推薦10倍以上?)。比如:
1.1.1 對(duì)于串口,假如最大波特率只需115.2k,那么用2M 的 GPIO 的引腳速度就夠了,既省電也噪聲小。
1.1.2 對(duì)于 I2C 接口,假如使用400k 波特率,若想把余量留大些,那么用2M 的 GPIO 的引腳速度或許不夠,這時(shí) 可以選用10M 的 GPIO 引腳速度。
1.1.3 對(duì)于 SPI 接口,假如使用18M 或9M 波特率,用10M 的 GPIO 的引腳速度顯然不夠了,需要選用50M 的 GPIO
的引腳速度。
1.2 GPIO 口設(shè)為輸入時(shí),輸出驅(qū)動(dòng)電路與端口是斷開,所以輸出速度配置無意義。
1.3 在復(fù)位期間和剛復(fù)位后,復(fù)用功能未開啟,I/O 端口被配置成浮空輸入模式。
1.4 所有端口都有外部中斷能力。為了使用外部中斷線,端口必須配置成輸入模式。
1.5 GPIO 口的配置具有上鎖功能,當(dāng)配置好 GPIO 口后,可以通過程序鎖住配置組合,直到下次芯片復(fù)位才能 解鎖。
2 在 STM32中如何配置片內(nèi)外設(shè)使用的 IO 端口
首先,一個(gè)外設(shè)經(jīng)過 ①配置輸入的時(shí)鐘和 ②初始化后即被激活(開啟);③如果使用該外設(shè)的輸入輸出管腳,則需要配 置相應(yīng)的 GPIO 端口(否則該外設(shè)對(duì)應(yīng)的輸入輸出管腳可以做普通 GPIO 管腳使用);④再對(duì)外設(shè)進(jìn)行詳細(xì)配置。
對(duì)應(yīng)到外設(shè)的輸入輸出功能有下述三種情況: 一、外設(shè)對(duì)應(yīng)的管腳為輸出:需要根據(jù)外圍電路的配置選擇對(duì)應(yīng)的管腳為復(fù)用功能的推挽輸出或復(fù)用功能的開漏輸出。 二、外設(shè)對(duì)應(yīng)的管腳為輸入:則根據(jù)外圍電路的配置可以選擇浮空輸入、帶上拉輸入或帶下拉輸入。
三、ADC 對(duì)應(yīng)的管腳:配置管腳為模擬輸入。
如果把端口配置成復(fù)用輸出功能,則引腳和輸出寄存器斷開,并和片上外設(shè)的輸出信號(hào)連接。將管腳配置成復(fù)用輸出功 能后,如果外設(shè)沒有被激活,那么它的輸出將不確定。
3 通用 IO 端口(GPIO)初始化:
3.1 GPIO 初始化
3.1.1 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | B | C, ENABLE):使能 APB2總線外設(shè)時(shí)鐘
3.1.2 RCC_ APB2PeriphResetCmd (RCC_APB2Periph_GPIOA | B | C, DISABLE):釋放 GPIO 復(fù)位
3.2 配置各個(gè) PIN 端口(模擬輸入_AIN、輸入浮空_IN_FLOATING、輸入上拉_IPU、輸入下拉_IPD、開漏 輸出_OUT_OD、推挽式輸出_OUT_PP、推挽式復(fù)用輸出_AF_PP、開漏復(fù)用輸出_AF_OD)
3.3 GPIO 初始化完成
下面我就在做個(gè)拋磚引玉,根據(jù) ST 手冊(cè)上的內(nèi)容,簡單地綜述一下 GPIO 的功能:
一、共有8種模式,可以通過編程選擇:
1. 浮空輸入
2. 帶上拉輸入
3. 帶下拉輸入
4. 模擬輸入
5. 開漏輸出——(此模式可實(shí)現(xiàn) hotpower 說的真雙向 IO)
6. 推挽輸出
7. 復(fù)用功能的推挽輸出
8. 復(fù)用功能的開漏輸出 模式7和模式8需根據(jù)具體的復(fù)用功能決定。
二、專門的寄存器(GPIOx_BSRR 和 GPIOx_BRR)實(shí)現(xiàn)對(duì) GPIO 口的原子操作,即回避了設(shè)置或清除 I/O 端口時(shí)的“讀-修 改-寫”操作,使得設(shè)置或清除 I/O 端口的操作不會(huì)被中斷處理打斷而造成誤動(dòng)作。
三、每個(gè) GPIO 口都可以作為外部中斷的輸入,便于系統(tǒng)靈活設(shè)計(jì)。
四、I/O 口的輸出模式下,有3種輸出速度可選(2MHz、10MHz 和50MHz),這有利于噪聲控制。 五、所有 I/O 口兼容 CMOS 和 TTL,多數(shù) I/O 口兼容5V 電平。
六、大電流驅(qū)動(dòng)能力:GPIO 口在高低電平分別為0.4V 和 VDD-0.4V 時(shí),可以提供或吸收8mA 電流;如果把輸入輸出電 平分別放寬到1.3V 和 VDD-1.3V 時(shí),可以提供或吸收20mA 電流。
七、具有獨(dú)立的喚醒 I/O 口。
八、很多 I/O 口的復(fù)用功能可以重新映射。
九、GPIO 口的配置具有上鎖功能,當(dāng)配置好 GPIO 口后,可以通過程序鎖住配置組合,直到下次芯片復(fù)位才能解鎖。此 功能非常有利于在程序跑飛的情況下保護(hù)系統(tǒng)中其他的設(shè)備,不會(huì)因?yàn)槟承?I/O 口的配置被改變而損壞——如一個(gè)輸入 口變成輸出口并輸出電流。
STM32第一個(gè)例子
//**********************************************************************
// 作者:YYYtech
// 時(shí)間:2007/12/14
//***********************************************************************
/***********************************************************************
main 文件,GPIO 操作,完成最簡單的 IO 操作實(shí)驗(yàn),就是控制 LED 燈
4個(gè) LED 分別對(duì)應(yīng) PC 的6、7、8、9引腳。4個(gè) LED 流水顯示
**************************************************************************/
#i nclude "stm32f10x_lib.h"
GPIO_InitTypeDef GPIO_InitStructure;
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void LED_TurnOn(u8 led)
{
}
void Delay(vu32 nCount)
{
for(; nCount != 0; nCount--);
}
main()
{
//RCC_Configuration(); LED_Init();
while(1)
{
GPIO_SetBits(GPIOC, GPIO_Pin_9); Delay(0x8ffff);
GPIO_ResetBits(GPIOC, GPIO_Pin_9); Delay(0x8ffff);
GPIO_SetBits(GPIOC, GPIO_Pin_10); Delay(0x8ffff);
GPIO_ResetBits(GPIOC, GPIO_Pin_10); Delay(0x8ffff);
GPIO_SetBits(GPIOC, GPIO_Pin_11); Delay(0x8ffff);
GPIO_ResetBits(GPIOC, GPIO_Pin_11); Delay(0x8ffff);
GPIO_SetBits(GPIOC, GPIO_Pin_12); Delay(0x8ffff);
GPIO_ResetBits(GPIOC, GPIO_Pin_12); Delay(0x8ffff);
}
}
注意:在這里用到了 RCC 和 GPIO 的庫函數(shù),所以必須把這兩個(gè)函數(shù)加入工程。
關(guān)于固件庫函數(shù)在文件夾:C:\Keil\ARM\RV31\LIB\ST\STM32F10x
為 了 不 在 操 作 過 程 中 避 免 改 變 KEIL 文 件 夾 下 的 庫 函 數(shù) , 可 以 固 件 函 數(shù) 庫 放 到 其 他 文 件 夾 下 , 如 :
E:\jy\work\STM\WxlStm32\LAB\library
其中 stm32f10x_lib.c 文件是整個(gè)庫的一些定義,是必須要的。 加入后的工程為:
GPIO 庫函數(shù)簡單說明: 函數(shù)名稱 功能描述
GPIO_DeInit 重新初始化外圍設(shè)備 GPIOx 相關(guān)寄存器到它的默認(rèn)復(fù)位值 GPIO_AFIODeInit 初始化交錯(cuò)功能(remap, event control 和 EXTI 配置) 寄存器 GPIO_Init 根據(jù) GPIO_初始化結(jié)構(gòu)指定的元素初始化外圍設(shè)備 GPIOx GPIO_StructInit 填充 GPIO_初始化結(jié)構(gòu)(GPIO_InitStruct)內(nèi)的元素為復(fù)位值 GPIO_ReadInputDataBit 讀指定端口引腳輸入數(shù)據(jù)
GPIO_ReadInputData 讀指定端口輸入數(shù)據(jù) GPIO_ReadOtputDataBit 讀指定端口引腳輸出數(shù)據(jù) GPIO_ReadOtputData 讀指定端口輸出數(shù)據(jù) GPIO_SetBits 置1指定的端口引腳
GPIO_ResetBits 清0指定的端口引腳 GPIO_WriteBit 設(shè)置或清除選擇的數(shù)據(jù)端口引腳 GPIO_Write 寫指定數(shù)據(jù)到 GPIOx 端口寄存器 GPIO_ANAPinConfig 允許或禁止 GPIO 4 模擬輸入模式 GPIO_PinLockConfig 鎖定 GPIO 引腳寄存器 GPIO_EventOutputConfig 選擇 GPIO 引腳作為事件輸出 GPIO_EventOutputCmd 允許或禁止事件輸出 GPIO_PinRemapConfig 改變指定引腳的影射 GPIO_EMIConfig 允許或禁止 GPIO 8 和 9 的 EMI 模式 拓展實(shí)驗(yàn):
在上面 LED 燈流水顯示的基礎(chǔ)之上加上按鍵程序,首先來看看按鍵的原理圖:
當(dāng)然這個(gè)原理圖也是相當(dāng)之簡單的,不用讀解釋了,唯一注意的是 OK 鍵與其他三個(gè)鍵的區(qū)別是按下為高電平,其余三 個(gè)按下為低電平。
加入后的完整清單如下:
//**********************************************************************
// 作者:JingYong
// 時(shí)間:2008/4/24
//***********************************************************************
/*********************************************************************** GPIO 操作,完成最簡單的 IO 操作實(shí)驗(yàn),用按鍵控制 LED 燈閃爍
**************************************************************************/
#i nclude "stm32f10x_lib.h"
GPIO_InitTypeDef GPIO_InitStructure;
//鍵盤定義
#define KEY_OK GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0)
#define KEY_DOWN GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_1)
#define KEY_UP GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_2)
#define KEY_ESC GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_3)
//LED 初始化
void LED_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOC, &GPIO_InitStructure);
}
//按鍵初始化
void KEY_Init (void)
{
GPIO_InitTypeDef gpio_init; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
gpio_init.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
gpio_init.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &gpio_init);
}
//延遲函數(shù)
void Delay(vu32 nCount)
{
for(; nCount != 0; nCount--);
}
//主函數(shù)
main()
{
//RCC_Configuration(); LED_Init();
KEY_Init ();
while(1)
{
if(!KEY_ESC)
{
while(!KEY_ESC) ; GPIO_SetBits(GPIOC, GPIO_Pin_9); Delay(0x8ffff);
GPIO_ResetBits(GPIOC, GPIO_Pin_9); Delay(0x8ffff);
}
else if(!KEY_UP)
{
while(!KEY_UP) ; GPIO_SetBits(GPIOC, GPIO_Pin_10); Delay(0x8ffff);
GPIO_ResetBits(GPIOC, GPIO_Pin_10); Delay(0x8ffff);
}
else if(!KEY_DOWN)
{
while(!KEY_DOWN) ; GPIO_SetBits(GPIOC, GPIO_Pin_11); Delay(0x8ffff);
GPIO_ResetBits(GPIOC, GPIO_Pin_11); Delay(0x8ffff);
}
else if(KEY_OK)
{
while(KEY_OK) ; GPIO_SetBits(GPIOC, GPIO_Pin_12); Delay(0x8ffff);
GPIO_ResetBits(GPIOC, GPIO_Pin_12); Delay(0x8ffff);
}
}
}
該例子是按下不同的按鍵,閃爍對(duì)應(yīng)的 LED 燈。 推挽輸出與開漏輸出的區(qū)別:
>>推挽輸出:可以輸出高,低電平,連接數(shù)字器件
STM32的 GPIO 口的輸出:開漏輸出和推挽輸出 收藏
>>開漏輸出:輸出端相當(dāng)于三極管的集電極. 要得到高電平狀態(tài)需要上拉電阻才行. 適合于做電流型的驅(qū)動(dòng),其吸收電流
的能力相對(duì)強(qiáng)(一般20ma 以內(nèi)).
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 三極管的開漏輸出 有什么特性,和推挽是不是一回事,
問題:
很多芯片的供電電壓不一樣,有3.3v 和5.0v,需要把幾種 IC 的不同口連接在一起,是不是直接連接就可以了?實(shí)際 上系統(tǒng)是應(yīng)用在 I2C 上面。
簡答:
1、部分3.3V 器件有5V 兼容性,可以利用這種容性直接連接
2、應(yīng)用電壓轉(zhuǎn)換器件,如 TPS76733就是5V 輸入,轉(zhuǎn)換成3.3V、1A 輸出。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
開漏電路特點(diǎn)及應(yīng)用
在電路設(shè)計(jì)時(shí)我們常常遇到開漏(open drain)和開集(open collector)的概念。所謂開漏電路概念中提到的“漏”就 是指 MOSFET 的漏極。同理,開集電路中的“集”就是指三極管的集電極。開漏電路就是指以 MOSFET 的漏極為輸出的 電路。一般的用法是會(huì)在漏極外部的電路添加上拉電阻。完整的開漏電路應(yīng)該由開漏器件和開漏上拉電阻組成。
組成開漏形式的電路有以下幾個(gè)特點(diǎn):
1. 利用 外部電路的驅(qū)動(dòng)能力,減少 IC 內(nèi)部的驅(qū)動(dòng)。當(dāng) IC 內(nèi)部 MOSFET 導(dǎo)通時(shí),驅(qū)動(dòng)電流是從外部的 VCC 流經(jīng) R
pull-up ,MOSFET 到 GND。IC 內(nèi)部僅需很下的柵極驅(qū)動(dòng)電流。如圖1。
2. 可以將多個(gè)開漏輸出的 Pin,連接到一條線上。形成 “與邏輯” 關(guān)系。如圖1,當(dāng) PIN_A、PIN_B、PIN_C 任意一個(gè)變 低后,開漏線上的邏輯就為0了。這也是 I2C,SMBus 等總線判斷總線占用狀態(tài)的原理。
3. 可以利用改變上拉電源的電壓,改變傳輸電平。如圖2, IC 的邏輯電平由電源 Vcc1決定,而輸出高電平則由 Vcc2決定。 這樣我們就可以用低電平邏輯控制輸出高電平邏輯了。
4. 開漏 Pin 不連接外部的上拉電阻,則只能輸出低電平(因此對(duì)于經(jīng)典的51單片機(jī)的 P0口而言,要想做輸入輸出功能必 須加外部上拉電阻,否則無法輸出高電平邏輯)。
5. 標(biāo)準(zhǔn)的開漏腳一般只有輸出的能力。添加其它的判斷電路,才能具備雙向輸入、輸出的能力。
應(yīng)用中需注意:
1. 開漏和開集的原理類似,在許多應(yīng)用中我們利用開集電路代替開漏電路。例如,某輸入 Pin 要求由開漏電路驅(qū)動(dòng)。 則我們常見的驅(qū)動(dòng)方式是利用一個(gè)三極管組成開集電路來驅(qū)動(dòng)它,即方便又節(jié)省成本。如圖3。
2. 上拉電阻 R pull-up 的 阻值 決定了 邏輯電平轉(zhuǎn)換的沿的速度 。阻值越大,速度越低功耗越小。反之亦然。
Push-Pull 輸出就是一般所說的推挽輸出,在 CMOS 電路里面應(yīng)該較 CMOS 輸出更合適,應(yīng)為在 CMOS 里面的 push
-pull 輸出能力不可能做得雙極那么大。輸出能力看 IC 內(nèi)部輸出極 N 管 P 管的面積。和開漏輸出相比,push-pull 的高 低電平由 IC 的電源低定,不能簡單的做邏輯操作等。 push-pull 是現(xiàn)在 CMOS 電路里面用得最多的輸出級(jí)設(shè)計(jì)方式。
at91rm9200 GPIO 模擬 I2C 接口時(shí)注意! 一.什么是 OC、OD
集電極開路門(集電極開路 OC 或源極開路 OD)
open-drain 是漏極開路輸出的意思,相當(dāng)于集電極開路(open-collector)輸出,即 ttl 中的集電極開路(oc)輸出。一般用于 線或、線與,也有的用于電流驅(qū)動(dòng)。
open-drain 是對(duì) mos 管而言,open-collector 是對(duì)雙極型管而言,在用法上沒啥區(qū)別。
開漏形式的電路有以下幾個(gè)特點(diǎn):
1.利用外部電路的驅(qū)動(dòng)能力,減少 IC 內(nèi)部的驅(qū)動(dòng)。 或驅(qū)動(dòng)比芯片電源電壓高的負(fù)載.
2. 可以將多個(gè)開漏輸出的 Pin,連接到一條線上。通過一只上拉電阻,在不增加任何器件的情況下,形成“與邏輯”關(guān)系。 這也是 I2C,SMBus 等總線判斷總線占用狀態(tài)的原理。如果作為圖騰輸出必須接上拉電阻。接容性負(fù)載時(shí),下降延是芯 片內(nèi)的晶體管,是有源驅(qū)動(dòng),速度較快;上升延是無源的外接電阻,速度慢。如果要求速度高電阻選擇要小,功耗會(huì)大。 所以負(fù)載電阻的選擇要兼顧功耗和速度。
3.可以利用改變上拉電源的電壓,改變傳輸電平。例如加上上拉電阻就可以提供 TTL/CMOS 電平輸出等。
4.開漏 Pin 不連接外部的上拉電阻,則只能輸出低電平。一般來說,開漏是用來連接不同電平的器件,匹配電平用的。
5.正常的 CMOS 輸出級(jí)是上、下兩個(gè)管子,把上面的管子去掉就是 OPEN-DRAIN 了。這種輸出的主要目的有兩個(gè):電 平轉(zhuǎn)換和線與。
6.由于漏級(jí)開路,所以后級(jí)電路必須接一上拉電阻,上拉電阻的電源電壓就可以決定輸出電平。這樣你就可以進(jìn)行任意 電平的轉(zhuǎn)換了。
7. 線 與 功 能 主 要 用 于 有 多 個(gè) 電 路 對(duì) 同 一 信 號(hào) 進(jìn) 行 拉 低 操 作 的 場(chǎng) 合 , 如 果 本 電 路 不 想 拉 低 , 就 輸 出 高 電 平 , 因?yàn)?OPEN-DRAIN 上面的管子被拿掉,高電平是靠外接的上拉電阻實(shí)現(xiàn)的。(而正常的 CMOS 輸出級(jí),如果出現(xiàn)一個(gè)輸出為 高另外一個(gè)為低時(shí),等于電源短路。)
8.OPEN-DRAIN 提供了靈活的輸出方式,但是也有其弱點(diǎn),就是帶來上升沿的延時(shí)。因?yàn)樯仙厥峭ㄟ^外接上拉無源電 阻對(duì)負(fù)載充電,所以當(dāng)電阻選擇小時(shí)延時(shí)就小,但功耗大;反之延時(shí)大功耗小。所以如果對(duì)延時(shí)有要求,則建議用下降 沿輸出。
二.什么是線或邏輯與線與邏輯?
在一個(gè)結(jié)點(diǎn)(線)上, 連接一個(gè)上拉電阻到電源 VCC 或 VDD 和 n 個(gè) NPN 或 NMOS 晶體管的集電極 C 或漏極 D, 這些晶體管的發(fā)射極 E 或源極 S 都接到地線上, 只要有一個(gè)晶體管飽和, 這個(gè)結(jié)點(diǎn)(線)就被拉到地線電平上. 因?yàn)檫@些晶體管的基極注入電流(NPN)或柵極加上高電平(NMOS), 晶體管就會(huì)飽和, 所以這些基極或柵極對(duì)這個(gè)結(jié)點(diǎn) (線)的關(guān)系是或非 NOR 邏輯. 如果這個(gè)結(jié)點(diǎn)后面加一個(gè)反相器, 就是或 OR 邏輯.
注:個(gè)人理解:線與,接上拉電阻至電源。(~A)&(~B)=~(A+B),由公式較容易理解線與此概念的由來 ; 如果用下拉電阻和 PNP 或 PMOS 管就可以構(gòu)成與非 NAND 邏輯, 或用負(fù)邏輯關(guān)系轉(zhuǎn)換與/或邏輯. 注:線或,接下拉電阻至地。(~A)+(~B)=~(AB);
這些晶體管常常是一些邏輯電路的集電極開路 OC 或源極開路 OD 輸出端. 這種邏輯通常稱為線與/線或邏輯, 當(dāng)你看
到一些芯片的 OC 或 OD 輸出端連在一起, 而有一個(gè)上拉電阻時(shí), 這就是線或/線與了, 但有時(shí)上拉電阻做在芯片的輸 入端內(nèi).
順便提示如果不是 OC 或 OD 芯片的輸出端是不可以連在一起的, 總線 BUS 上的雙向輸出端連在一起是有管理的,
同時(shí)只能有一個(gè)作輸出, 而其他是高阻態(tài)只能輸入.
三.什么是推挽結(jié)構(gòu) 一般是指兩個(gè)三極管分別受兩互補(bǔ)信號(hào)的控制,總是在一個(gè)三極管導(dǎo)通的時(shí)候另一個(gè)截止.要實(shí)現(xiàn)線與需要用 OC(open collector)門電路 .如果輸出級(jí)的有兩個(gè)三極管,始終處于一個(gè)導(dǎo)通、一個(gè)截止的狀態(tài),也就是兩個(gè)三級(jí)管推挽相連,這 樣的電路結(jié)構(gòu)稱為推拉式電路或圖騰柱(Totem- pole)輸出電路(可惜,圖無法貼上)。當(dāng)輸出低電平時(shí),也就是下級(jí)負(fù) 載門輸入低電平時(shí),輸出端的電流將是下級(jí)門灌入 T4;當(dāng)輸出高電平時(shí),也就是下級(jí)負(fù)載門輸入高電平時(shí),輸出端的電
流將是下級(jí)門從本級(jí)電源經(jīng) T3、D1 拉出。這樣一來,輸出高低電平時(shí),T3 一路和 T4 一路將交替工作,從而減低了 功耗,提高了每個(gè)管的承受能力。又由于不論走哪一路,管子導(dǎo)通電阻都很小,使 RC 常數(shù)很小,轉(zhuǎn)變速度很快。因此, 推拉式輸出級(jí)既提高電路的負(fù)載能力,又提高開關(guān)速度。供你參考。
推挽電路是兩個(gè)參數(shù)相同的三極管或 MOSFET,以推挽方式存在于電路中,各負(fù)責(zé)正負(fù)半周的波形放大任務(wù),電路工作時(shí), 兩只對(duì)稱的功率開關(guān)管每次只有一個(gè)導(dǎo)通,所以導(dǎo)通損耗小效率高。
輸出既可以向負(fù)載灌電流,也可以從負(fù)載抽取電流
本文來自 CSDN 博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/feiniao_lql/archive/2010/06/13/5668585.aspx
STM32時(shí)鐘控制 RCC
對(duì)于單片機(jī)系統(tǒng)來說,CPU 和總線以及外設(shè)的時(shí)鐘設(shè)置是非常重要的,因?yàn)闆]有時(shí)鐘就沒有時(shí)序,組合電路能干什么想 必各位心里都清楚。其實(shí)時(shí)鐘的學(xué)習(xí)這部分應(yīng)該提前一些,但由于一開始時(shí)間比較短,有些急于求成,所以直接使用了 萬利給的例程,姑且跳過了這一步。介于下面我計(jì)劃要學(xué)習(xí)的任務(wù)都涉及到兆級(jí)的高速傳輸,例如全速 USB,DMA 等 等,所以不能再忽略時(shí)鐘啦,必須要仔細(xì)研究一下。
我學(xué)習(xí) RCC 的參考資料:
技術(shù)文檔0427及其中文翻譯版 STM32F10xxx_Library_Manual_ChineseV2的第十五章和 RM0008_CH 參考手冊(cè)。
準(zhǔn)備知識(shí):
片上總線標(biāo)準(zhǔn)種類繁多,而由 ARM 公司推出的 AMBA 片上總線受到了廣大 IP 開發(fā)商和 SoC 系統(tǒng)集成者的青睞,已成 為 一 種 流 行 的 工 業(yè) 標(biāo) 準(zhǔn) 片 上 結(jié) 構(gòu) 。 AMBA 規(guī) 范 主 要 包 括 了 AHB(Advanced High performance Bus) 系 統(tǒng) 總 線 和 APB(Advanced Peripheral Bus)外圍總線。二者分別適用于高速與相對(duì)低速設(shè)備的連接。
由于時(shí)鐘是一個(gè)由內(nèi)而外的東西,具體設(shè)置要從寄存器開始。
RCC 寄存器結(jié)構(gòu),RCC_TypeDeff,在文件“stm32f10x_map.h”中定義如下:
typedef struct
{
vu32 CR; vu32 CFGR; vu32 CIR;
vu32 APB2RSTR;
vu32 APB1RSTR; vu32 AHBENR; vu32 APB2ENR; vu32 APB1ENR; vu32 BDCR;
vu32 CSR;
} RCC_TypeDef;
這些寄存器的具體定義和使用方式參見芯片手冊(cè),在此不贅述,因?yàn)?C 語言的開發(fā)可以不和他們直接打交道,當(dāng)然如果 能夠加以理解和記憶,無疑是百利而無一害。
相信細(xì)心的朋友早就發(fā)現(xiàn)板子上只有8Mhz 的晶振,而增強(qiáng)型最高工作頻率為72Mhz,顯然需要用 PLL 倍頻9倍,這些設(shè) 置都需要在初始化階段完成。為了方便說明,我借用一下例程的 RCC 設(shè)置函數(shù),并用中文注釋的形式加以說明:
/*******************************************************************************
* Name : Set_System
* Deion : Configures Main system clocks & power
* Input : None.
* Return : None.
*******************************************************************************/
//在此指出上面的注釋頭應(yīng)該是復(fù)制過來的,寫錯(cuò)了...不過沒關(guān)系,反正沒參數(shù)需要說明,重要的是函數(shù)體。
static void RCC_Config(void)
{
/* 這里是重置了 RCC 的設(shè)置,類似寄存器復(fù)位 */ RCC_DeInit();
/* 使能外部高速晶振 */ RCC_HSEConfig(RCC_HSE_ON);
/* 等待高速晶振穩(wěn)定 */
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if (HSEStartUpStatus == SUCCESS)
{
/* 使能 flash 預(yù)讀取緩沖區(qū) */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* 令 Flash 處于等待狀態(tài),2是針對(duì)高頻時(shí)鐘的,這兩句跟 RCC 沒直接關(guān)系,可以暫且略過 */ FLASH_SetLatency(FLASH_Latency_2);
/* HCLK = SYSCLK 設(shè)置高速總線時(shí)鐘=系統(tǒng)時(shí)鐘*/ RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK2 = HCLK 設(shè)置低速總線2時(shí)鐘=高速總線時(shí)鐘*/ RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK/2 設(shè)置低速總線1的時(shí)鐘=高速時(shí)鐘的二分頻*/ RCC_PCLK1Config(RCC_HCLK_Div2);
/* ADCCLK = PCLK2/6 設(shè)置 ADC 外設(shè)時(shí)鐘=低速總線2時(shí)鐘的六分頻*/ RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/* Set PLL clock output to 72MHz using HSE (8MHz) as entry clock */
//上面這句例程中缺失了,但卻很關(guān)鍵
/* 利用鎖相環(huán)講外部8Mhz 晶振9倍頻到72Mhz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* Enable PLL 使能鎖相環(huán)*/ RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready 等待鎖相環(huán)輸出穩(wěn)定*/
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{}
/* Select PLL as system clock source 將鎖相環(huán)輸出設(shè)置為系統(tǒng)時(shí)鐘 */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source 等待校驗(yàn)成功*/
while (RCC_GetSYSCLKSource() != 0x08)
{}
}
/* Enable FSMC, GPIOD, GPIOE, GPIOF, GPIOG and AFIO clocks */
//使能外圍接口總線時(shí)鐘,注意各外設(shè)的隸屬情況,不同芯片的分配不同,到時(shí)候查手冊(cè)就可以
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG | RCC_APB2Periph_AFIO, ENABLE);
}
由上述程序可以看出系統(tǒng)時(shí)鐘的設(shè)定是比較復(fù)雜的,外設(shè)越多,需要考慮的因素就越多。同時(shí)這種設(shè)定也是有規(guī)律可循 的,設(shè)定參數(shù)也是有順序規(guī)范的,這是應(yīng)用中應(yīng)當(dāng)注意的,例如 PLL 的設(shè)定需要在使能之前,一旦 PLL 使能后參數(shù)不 可更改。
經(jīng)過此番設(shè)置后,由于我的電路板上是8Mhz 晶振,所以系統(tǒng)時(shí)鐘為72Mhz,高速總線和低速總線2都為72Mhz,低速總 線1為36Mhz,ADC 時(shí)鐘為12Mhz,USB 時(shí)鐘經(jīng)過1.5分頻設(shè)置就可以實(shí)現(xiàn)48Mhz 的數(shù)據(jù)傳輸。
一般性的時(shí)鐘設(shè)置需要先考慮系統(tǒng)時(shí)鐘的來源,是內(nèi)部 RC 還是外部晶振還是外部的振蕩器,是否需要 PLL。然后考慮 內(nèi)部總線和外部總線,最后考慮外設(shè)的時(shí)鐘信號(hào)。遵從先倍頻作為 CPU 時(shí)鐘,然后在由內(nèi)向外分頻,下級(jí)遷就上級(jí)的原 則有點(diǎn)兒類似 PCB 制圖的規(guī)范化要求,在這里也一樣。
(原文件名:STM32系統(tǒng)時(shí)鐘框圖.gif)
引用圖片
STM32的時(shí)鐘系統(tǒng)分析
在 STM32中,有五個(gè)時(shí)鐘源,為 HSI、HSE、LSI、LSE、PLL。
①、HSI 是高速內(nèi)部時(shí)鐘,RC 振蕩器,頻率為8MHz。
②、HSE 是高速外部時(shí)鐘,可接石英/陶瓷諧振器,或者接外部時(shí)鐘源,頻率范圍為4MHz~16MHz。
③、LSI 是低速內(nèi)部時(shí)鐘,RC 振蕩器,頻率為40kHz。
④、LSE 是低速外部時(shí)鐘,接頻率為32.768kHz 的石英晶體。
⑤、PLL 為鎖相環(huán)倍頻輸出,其時(shí)鐘輸入源可選擇為 HSI/2、HSE 或者 HSE/2。倍頻可選擇為2~16倍,但是其輸出 頻率最大不得超過72MHz。
其中40kHz 的 LSI 供獨(dú)立看門狗 IWDG 使用,另外它還可以被選擇為實(shí)時(shí)時(shí)鐘 RTC 的時(shí)鐘源。另外,實(shí)時(shí)時(shí)鐘 RTC
的時(shí)鐘源還可以選擇 LSE,或者是 HSE 的128分頻。RTC 的時(shí)鐘源通過 RTCSEL[1:0]來選擇。
STM32中有一個(gè)全速功能的 USB 模塊,其串行接口引擎需要一個(gè)頻率為48MHz 的時(shí)鐘源。該時(shí)鐘源只能從 PLL 輸 出端獲取,可以選擇為1.5分頻或者1分頻,也就是,當(dāng)需要使用 USB 模塊時(shí),PLL 必須使能,并且時(shí)鐘頻率配置為48MHz 或72MHz。
另外,STM32還可以選擇一個(gè)時(shí)鐘信號(hào)輸出到 MCO 腳(PA8)上,可以選擇為 PLL 輸出的2分頻、HSI、HSE、或者系 統(tǒng)時(shí)鐘。
系統(tǒng)時(shí)鐘 SYSCLK,它是供 STM32中絕大部分部件工作的時(shí)鐘源。系統(tǒng)時(shí)鐘可選擇為 PLL 輸出、HSI 或者 HSE。 系統(tǒng)時(shí)鐘最大頻率為72MHz,它通過 AHB 分頻器分頻后送給各模塊使用,AHB 分頻器可選擇1、2、4、8、16、64、128、
256、512分頻。其中 AHB 分頻器輸出的時(shí)鐘送給5大模塊使用:
①、送給 AHB 總線、內(nèi)核、內(nèi)存和 DMA 使用的 HCLK 時(shí)鐘。
②、通過8分頻后送給 Cortex 的系統(tǒng)定時(shí)器時(shí)鐘。
③、直接送給 Cortex 的空閑運(yùn)行時(shí)鐘 FCLK。
④、送給 APB1分頻器。APB1分頻器可選擇1、2、4、8、16分頻,其輸出一路供 APB1外設(shè)使用(PCLK1,最大頻率
36MHz),另一路送給定時(shí)器(Timer)2、3、4倍頻器使用。該倍頻器可選擇1或者2倍頻,時(shí)鐘輸出供定時(shí)器2、3、4使用。
⑤、送給 APB2分頻器。APB2分頻器可選擇1、2、4、8、16分頻,其輸出一路供 APB2外設(shè)使用(PCLK2,最大頻率
72MHz),另一路送給定時(shí)器(Timer)1倍頻器使用。該倍頻器可選擇1或者2倍頻,時(shí)鐘輸出供定時(shí)器1使用。另外,APB2
分頻器還有一路輸出供 ADC 分頻器使用,分頻后送給 ADC 模塊使用。ADC 分頻器可選擇為2、4、6、8分頻。
在以上的時(shí)鐘輸出中,有很多是帶使能控制的,例如 AHB 總線時(shí)鐘、內(nèi)核時(shí)鐘、各種 APB1外設(shè)、APB2外設(shè)等等。 當(dāng)需要使用某模塊時(shí),記得一定要先使能對(duì)應(yīng)的時(shí)鐘。
需要注意的是定時(shí)器的倍頻器,當(dāng) APB 的分頻為1時(shí),它的倍頻值為1,否則它的倍頻值就為2。
連接在 APB1(低速外設(shè))上的設(shè)備有:電源接口、備份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、 窗口看門狗、Timer2、Timer3、Timer4。注意 USB 模塊雖然需要一個(gè)單獨(dú)的48MHz 時(shí)鐘信號(hào),但它應(yīng)該不是供 USB 模 塊工作的時(shí)鐘,而只是提供給串行接口引擎(SIE)使用的時(shí)鐘。USB 模塊工作的時(shí)鐘應(yīng)該是由 APB1提供的。
連接在 APB2(高速外設(shè))上的設(shè)備有:UART1、SPI1、Timer1、ADC1、ADC2、所有普通 IO 口(PA~PE)、第二功能
IO 口。
/*******************************************************************************
* Name : RCC_Configuration
* Deion : Configures the different system clocks.
* Input : None
* Output : None
* Return : None
*******************************************************************************/
void RCC_Configuration(void)
{
ErrorStatus HSEStartUpStatus;
/* RCC system reset(for debug purpose) */
// RCC_DeInit();
/* Enable HSE */ RCC_HSEConfig(RCC_HSE_ON);
/* Wait till HSE is ready */
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS)
{
/* HCLK = SYSCLK */ RCC_HCLKConfig(RCC_SYSCLK_Div1);
/* PCLK2 = HCLK */ RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK/2 */ RCC_PCLK1Config(RCC_HCLK_Div2);
/* ADCCLK = PCLK2/6 */ RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/* Flash 2 wait state */ FLASH_SetLatency(FLASH_Latency_2);
/* Enable Prefetch Buffer */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* PLLCLK = 8MHz * 9 = 72 MHz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);//Pll 在最后設(shè)置
/* Enable PLL */ RCC_PLLCmd(ENABLE);
/* Wait till PLL is ready */
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
/* Select PLL as system clock source */ RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
/* Enable GPIOA, GPIOB, GPIOC, GPIOD, GPIOE and AFIO clocks */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB |RCC_APB2Periph_GPIOC
| RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_AFIO, ENABLE);
/* TIM2 clocks enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
/* CAN Periph clock enable */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN, ENABLE);
}
基本的配置定時(shí)器的基本設(shè)置
STM32的學(xué)習(xí)心得之 TIMx(通用定時(shí)器)
1、TIM_TimeBaseStructure.TIM_Prescaler = 0x0;//時(shí)鐘預(yù)分頻數(shù) 例如:時(shí)鐘頻率=72/(時(shí)鐘預(yù)分頻+1)
2、TIM_TimeBaseStructure.TIM_CounterMode = TIM1_CounterMode_Up; //定時(shí)器模式 向上計(jì)數(shù)
3、TIM_TimeBaseStructure.TIM_Period = 0xFFFF; // 自動(dòng)重裝載寄存器周期的值(定時(shí)時(shí)間) 累計(jì) 0xFFFF 個(gè)頻率后產(chǎn)生 個(gè)更新或者中斷(也是說定時(shí)時(shí)間到)
4、TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //時(shí)間分割值
5、TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//初始化定時(shí)器2
6、TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //打開中斷 溢出中斷
7、TIM_Cmd(TIM2, ENABLE);//打開定時(shí)器 此外要記住一定要打開定時(shí)器的時(shí)鐘(RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);),定時(shí)器的頻率的
可以編程的,有對(duì)應(yīng)的模式設(shè)置和中斷處理。
STM32學(xué)習(xí)筆記之 串口通訊 主要功能是把 PC 機(jī)發(fā)送的數(shù)據(jù)接收后再返回給 PC 機(jī)參數(shù)9600,8,1,N。
/************************************************************************ Copyright (c) 2008 wormchen
All rights reserved
文 件 名: main.c
說 明: 串口發(fā)送接收數(shù)據(jù) 將 PC 端發(fā)來的數(shù)據(jù)返回給 PC
主要硬件: EMSTM32V1+miniSTMV100(外部8MRC)
編譯環(huán)境: MDK3.10
當(dāng)前版本: 1.0
************************************************************************/
#i nclude
void RCC_Config(void); void GPIO_Config(void); void USART_Config(void); void Put_String(u8 *p);
int main(void)
{ RCC_Config(); GPIO_Config(); USART_Config();
Put_String("\r\n 請(qǐng)發(fā)送數(shù)據(jù)_\r\n");
while(1)
{
while(1)
{
if(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == SET)
{
USART_SendData(USART2, USART_ReceiveData(USART2));
}
}
}
}
/*************************************************
函數(shù): void RCC_Config(void)
功能: 配置系統(tǒng)時(shí)鐘 參數(shù): 無
返回: 無
**************************************************/
void RCC_Config(void)
{
ErrorStatus HSEStartUpStatus;//定義外部高速晶體啟動(dòng)狀態(tài)枚舉變量 RCC_DeInit();//復(fù)位 RCC 外部設(shè)備寄存器到默認(rèn)值 RCC_HSEConfig(RCC_HSE_ON); //打開外部高速晶振
HSEStartUpStatus = RCC_WaitForHSEStartUp();//等待外部高速時(shí)鐘準(zhǔn)備好
if(HSEStartUpStatus == SUCCESS)//外部高速時(shí)鐘已經(jīng)準(zhǔn)別好
{
RCC_HCLKConfig(RCC_SYSCLK_Div1);//配置 AHB(HCLK)時(shí)鐘等于==SYSCLK RCC_PCLK2Config(RCC_HCLK_Div1); //配置 APB2(PCLK2)鐘==AHB 時(shí)鐘
RCC_PCLK1Config(RCC_HCLK_Div2);//配置 APB1(PCLK1)鐘==AHB1/2時(shí)鐘
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//配置 PLL 時(shí)鐘 == 外部高速晶體時(shí)鐘*9
RCC_PLLCmd(ENABLE);//使能 PLL 時(shí)鐘
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) //等待 PLL 時(shí)鐘就緒
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//配置系統(tǒng)時(shí)鐘 = PLL 時(shí)鐘
while(RCC_GetSYSCLKSource() != 0x08) //檢查 PLL 時(shí)鐘是否作為系統(tǒng)時(shí)鐘
{
}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
//打開 GPIOD 和 AFIO 時(shí)鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//使能串口2時(shí)鐘
}
/*************************************************
函數(shù): void GPIO_Config(void) 功能: GPIO 配置
參數(shù): 無 返回: 無
**************************************************/
void GPIO_Config(void)
{
//設(shè)置 RTS(PD.04),Tx(PD.05)為推拉輸出模式
GPIO_InitTypeDef GPIO_InitStructure; //定義 GPIO 初始化結(jié)構(gòu)體
GPIO_PinRemapConfig(GPIO_Remap_USART2, ENABLE);//使能 GPIO 端口映射 USART2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5;//選擇 PIN4 PIN5
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //引腳頻率50M GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//引腳設(shè)置推拉輸出 GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化 GPIOD
//配置 CTS (PD.03),USART2 Rx (PD.06)為浮點(diǎn)輸入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOD, &GPIO_InitStructure);
}
/*************************************************
函數(shù): void USART_Config(void)
功能: USART 配置
參數(shù): 無 返回: 無
**************************************************/
void USART_Config(void)
{
USART_InitTypeDef USART_InitStructure; //定義串口初始化結(jié)構(gòu)體
USART_InitStructure.USART_BaudRate = 9600;//波特率9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位數(shù)據(jù) USART_InitStructure.USART_StopBits = USART_StopBits_1;//1個(gè)停止位 USART_InitStructure.USART_Parity = USART_Parity_No ; //無校驗(yàn)位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
//禁用 RTSCTS 硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//使能發(fā)送接收 USART_InitStructure.USART_Clock = USART_Clock_Disable; //串口時(shí)鐘禁止 USART_InitStructure.USART_CPOL = USART_CPOL_Low; //時(shí)鐘下降沿有效 USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;//數(shù)據(jù)在第二個(gè)時(shí)鐘沿捕捉
USART_InitStructure.USART_LastBit = USART_LastBit_Disable;
//最后數(shù)據(jù)位的時(shí)鐘脈沖不輸出到 SCLK 引腳
USART_Init(USART2, &USART_InitStructure);//初始化串口2
USART_Cmd(USART2, ENABLE);//串口2使能
}
/*************************************************
函數(shù): void Put_String(void) 功能: 向串口輸出字符串 參數(shù): 無
返回: 無
**************************************************/
void Put_String(u8 *p)
{
while(*p)
{
USART_SendData(USART2, *p++);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
{
}
}
}
基于 STM32的 PWM 輸出
) 初始化函數(shù)定義:
void TIM_Configuration(void); //定義 TIM 初始化函數(shù)
d) 初始化函數(shù)調(diào)用:
TIM_Configuration(); //TIM 初始化函數(shù)調(diào)用
e) 初始化函數(shù),不同于前面模塊,TIM 的初始化分為兩部分——基本初始化和通道初始化:
void TIM_Configuration(void)//TIM 初始化函數(shù)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定時(shí)器初始化結(jié)構(gòu)
TIM_OCInitTypeDef TIM_OCInitStructure;//通道輸出初始化結(jié)構(gòu)
//TIM3初始化
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFF TIM_TimeBaseStructure.TIM_Prescaler = 5; //時(shí)鐘分頻 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時(shí)鐘分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //基本初始化 TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打開中斷,中斷需要這行代碼
//TIM3通道初始化
TIM_OCStructInit(& TIM_OCInitStructure); //默認(rèn)參數(shù) TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //工作狀態(tài) TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //設(shè)定為輸出,需要 PWM 輸出才需要這行代
碼
TIM_OCInitStructure.TIM_Pulse = 0x2000; //占空長度 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高電平 TIM_OC4Init(TIM3, &TIM_OCInitStructure); //通道初始化
TIM_Cmd(TIM3, ENABLE); //啟動(dòng)
TIM3
}
f) RCC 初始化函數(shù)中加入 TIM 時(shí)鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g) GPIO 里面將輸入和輸出管腳模式進(jìn)行設(shè)置。信號(hào):AF_PP,50MHz。
h) 使用中斷的話在 NVIC 里添加如下代碼:
//打開 TIM2中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; //通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級(jí)
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //響應(yīng)級(jí)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動(dòng)
NVIC_Init(&NVIC_InitStructure); //初始化
中斷代碼:
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET) //判斷中斷來源
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除中斷標(biāo)志
GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_11)));//變換 LED 色彩
IC4value = TIM_GetCapture4(TIM2); //獲取捕捉數(shù)值
}
}
i) 簡單應(yīng)用:
//改變占空比
TIM_SetCompare4(TIM3, 變量);
j) 注意事項(xiàng):
管腳的 IO 輸出模式是根據(jù)應(yīng)用來定,比如如果用 PWM 輸出驅(qū)動(dòng) LED 則應(yīng)該將相應(yīng)管腳設(shè)為 AF_PP,否則單片機(jī)沒有 輸出。
STM32資料一(轉(zhuǎn)載)
注:下面是一些常用的代碼,網(wǎng)上很多但是大多注釋不全。高手看沒問題,對(duì)于我們這些新手就費(fèi)勁了……所以我把這 些代碼集中,進(jìn)行了逐句注釋,希望對(duì)新手們有價(jià)值。
flash: 芯片內(nèi)部存儲(chǔ)器 flash 操作函數(shù)
我的理解——對(duì)芯片內(nèi)部 flash 進(jìn)行操作的函數(shù),包括讀取,狀態(tài),擦除,寫入等等,可以允許程序去操作 flash 上的數(shù) 據(jù)。
基礎(chǔ)應(yīng)用1,F(xiàn)LASH 時(shí)序延遲幾個(gè)周期,等待總線同步操作。推薦按照單片機(jī)系統(tǒng)運(yùn)行頻率,0—24MHz 時(shí),取 Latency=0;
24—48MHz 時(shí),取 Latency=1;48~72MHz 時(shí),取 Latency=2。所有程序中必須的
用法:FLASH_SetLatency(FLASH_Latency_2);
位置:RCC 初始化子函數(shù)里面,時(shí)鐘起振之后。
基礎(chǔ)應(yīng)用2,開啟 FLASH 預(yù)讀緩沖功能,加速 FLASH 的讀取。所有程序中必須的 用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
位置:RCC 初始化子函數(shù)里面,時(shí)鐘起振之后。
3、 lib:調(diào)試所有外設(shè)初始化的函數(shù)。 我的理解——不理解,也不需要理解。只要知道所有外設(shè)在調(diào)試的時(shí)候,EWRAM 需要從這個(gè)函數(shù)里面獲得調(diào)試所需信
息的地址或者指針之類的信息。 基礎(chǔ)應(yīng)用1,只有一個(gè)函數(shù) debug。所有程序中必須的。 用法: #ifdef DEBUG
debug();
#endif
位置:main 函數(shù)開頭,聲明變量之后。
4、 nvic:系統(tǒng)中斷管理。 我的理解——管理系統(tǒng)內(nèi)部的中斷,負(fù)責(zé)打開和關(guān)閉中斷。 基礎(chǔ)應(yīng)用1,中斷的初始化函數(shù),包括設(shè)置中斷向量表位置,和開啟所需的中斷兩部分。所有程序中必須的。 用法: void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure; //中斷管理恢復(fù)默認(rèn)參數(shù)
#ifdef VECT_TAB_RAM //如果 C/C++ Compiler\Preprocessor\Defined symbols 中的定義了 VECT_TAB_RAM(見程 序庫更改內(nèi)容的表格)
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //則在 RAM 調(diào)試
#else //如果沒有定義 VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//則在 Flash 里調(diào)試
#endif //結(jié)束判斷語句
//以下為中斷的開啟過程,不是所有程序必須的。
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//設(shè)置 NVIC 優(yōu)先級(jí)分組,方式。
//注:一共16個(gè)優(yōu)先級(jí),分為搶占式和響應(yīng)式。兩種優(yōu)先級(jí)所占的數(shù)量由此代碼確定,NVIC_PriorityGroup_x 可以是0、1、
2、3、4,分別代表搶占優(yōu)先級(jí)有1、2、4、8、16個(gè)和響應(yīng)優(yōu)先級(jí)有16、8、4、2、1個(gè)。規(guī)定兩種優(yōu)先級(jí)的數(shù)量后,所有 的中斷級(jí)別必須在其中選擇,搶占級(jí)別高的會(huì)打斷其他中斷優(yōu)先執(zhí)行,而響應(yīng)級(jí)別高的會(huì)在其他中斷執(zhí)行完優(yōu)先執(zhí)行。
//NVIC_InitStructure.NVIC_IRQChannel = 中斷通道名; //開中斷,中斷名稱見函數(shù)庫
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占優(yōu)先級(jí)
//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)優(yōu)先級(jí)
//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動(dòng)此通道的中斷
//NVIC_Init(&NVIC_InitStructure); //中斷初始化
}
5、 rcc:單片機(jī)時(shí)鐘管理。 我的理解——管理外部、內(nèi)部和外設(shè)的時(shí)鐘,設(shè)置、打開和關(guān)閉這些時(shí)鐘。 基礎(chǔ)應(yīng)用1:時(shí)鐘的初始化函數(shù)過程——
用法:void RCC_Configuration(void) //時(shí)鐘初始化函數(shù)
{
ErrorStatus HSEStartUpStatus; //等待時(shí)鐘的穩(wěn)定
RCC_DeInit(); //時(shí)鐘管理重置 RCC_HSEConfig(RCC_HSE_ON); //打開外部晶振 HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部晶振就緒
if (HSEStartUpStatus == SUCCESS)
{ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//flash 讀取緩沖,加速
FLASH_SetLatency(FLASH_Latency_2); //flash 操作的延時(shí) RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB 使用系統(tǒng)時(shí)鐘 RCC_PCLK2Config(RCC_HCLK_Div2); //APB2(高速)為 HCLK 的一半 RCC_PCLK1Config(RCC_HCLK_Div2); //APB1(低速)為 HCLK 的一半
//注:AHB 主要負(fù)責(zé)外部存儲(chǔ)器時(shí)鐘。PB2負(fù)責(zé) AD,I/O,高級(jí) TIM,串口1。APB1負(fù)責(zé) DA,USB,SPI,I2C,CAN, 串口2345,普通 TIM。
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHz * 9 = 72 MH RCC_PLLCmd(ENABLE); //啟動(dòng) PLL
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){} //等待 PLL 啟動(dòng) RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //將 PLL 設(shè)置為系統(tǒng)時(shí)鐘源 while (RCC_GetSYSCLKSource() != 0x08){} //等待系統(tǒng)時(shí)鐘源的啟動(dòng)
}
//RCC_AHBPeriphClockCmd(ABP2設(shè)備1 | ABP2設(shè)備2 |, ENABLE); //啟動(dòng) AHP 設(shè)備
//RCC_APB2PeriphClockCmd(ABP2設(shè)備1 | ABP2設(shè)備2 |, ENABLE);//啟動(dòng) ABP2設(shè)備
//RCC_APB1PeriphClockCmd(ABP2設(shè)備1 | ABP2設(shè)備2 |, ENABLE); //啟動(dòng) ABP1設(shè)備
}
6、 exti:外部設(shè)備中斷函數(shù) 我的理解——外部設(shè)備通過引腳給出的硬件中斷,也可以產(chǎn)生軟件中斷,19個(gè)上升、下降或都觸發(fā)。EXTI0~EXTI15連
接到管腳,EXTI 線16連接到 PVD(VDD 監(jiān)視),EXTI 線17連接到 RTC(鬧鐘),EXTI 線18連接到 USB(喚醒)。
基礎(chǔ)應(yīng)用1,設(shè)定外部中斷初始化函數(shù)。按需求,不是必須代碼。 用法: void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure; //外部設(shè)備中斷恢復(fù)默認(rèn)參數(shù) EXTI_InitStructure.EXTI_Line = 通道1|通道2; //設(shè)定所需產(chǎn)生外部中斷的通道,一共19個(gè)。 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //產(chǎn)生中斷 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //上升下降沿都觸發(fā) EXTI_InitStructure.EXTI_LineCmd = ENABLE; //啟動(dòng)中斷的接收 EXTI_Init(&EXTI_InitStructure); //外部設(shè)備中斷啟動(dòng)
}
7、 dma:通過總線而越過 CPU 讀取外設(shè)數(shù)據(jù)
我的理解——通過 DMA 應(yīng)用可以加速單片機(jī)外設(shè)、存儲(chǔ)器之間的數(shù)據(jù)傳輸,并在傳輸期間不影響 CPU 進(jìn)行其他事情。 這對(duì)于入門開發(fā)基本功能來說沒有太大必要,這個(gè)內(nèi)容先行跳過。
8、 systic:系統(tǒng)定時(shí)器 我的理解——可以輸出和利用系統(tǒng)時(shí)鐘的計(jì)數(shù)、狀態(tài)。 基礎(chǔ)應(yīng)用1,精確計(jì)時(shí)的延時(shí)子函數(shù)。推薦使用的代碼。 用法:
static vu32 TimingDelay; //全 局變量聲明
void SysTick_Config(void)
//systick 初始化函數(shù)
{
SysTick_CounterCmd(SysTick_Counter_Disable); //停止系統(tǒng)定時(shí)器
SysTick_ITConfig(DISABLE); //停止 systick 中斷
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //systick 使用 HCLK 作為時(shí)鐘源,頻率值除以8。
SysTick_SetReload(9000); //重置時(shí)間1
毫秒(以72MHz 為基礎(chǔ)計(jì)算)
SysTick_ITConfig(ENABLE); //開啟 systic 中 斷
}
void Delay (u32 nTime) //
延遲一毫秒的函數(shù)
{
SysTick_CounterCmd(SysTick_Counter_Enable); //systic 開始計(jì)時(shí)
TimingDelay = nTime; //計(jì)時(shí)長度賦值給遞減變量
while(TimingDelay != 0); //檢測(cè)是否計(jì)時(shí)完成
SysTick_CounterCmd(SysTick_Counter_Disable); //關(guān)閉計(jì)數(shù)器
SysTick_CounterCmd(SysTick_Counter_Clear); //清除計(jì)數(shù)值
}
void TimingDelay_Decrement(void) //遞減變量函數(shù),函數(shù)名由“stm32f10x_it.c”中的中斷響應(yīng)函數(shù)定義好了。
{
if (TimingDelay != 0x00) //檢測(cè)計(jì)數(shù)變量是否達(dá)到0
{ TimingDelay--; //計(jì)數(shù)變量遞減
}
}
注:建議熟練后使用,所涉及知識(shí)和設(shè)備太多,新手出錯(cuò)的可能性比較大。新手可用簡化的延時(shí)函數(shù)代替:
void Delay(vu32 nCount) //簡 單延時(shí)函數(shù)
{
for(; nCount != 0; nCount--); //循 環(huán)變量遞減計(jì)數(shù)
}
當(dāng)延時(shí)較長,又不需要精確計(jì)時(shí)的時(shí)候可以使用嵌套循環(huán):
void Delay(vu32 nCount) //簡單的長時(shí)間延時(shí)函數(shù)
{int i; //聲明內(nèi)部遞減變量
for(; nCount != 0; nCount--) //遞減變量計(jì)數(shù)
{for (i=0; i<0xffff; i++)} //
內(nèi)部循環(huán)遞減變量計(jì)數(shù)
}
9、 gpio:I/O 設(shè)置函數(shù) 我的理解——所有輸入輸出管腳模式設(shè)置,可以是上下拉、浮空、開漏、模擬、推挽模式,頻率特性為2M,10M,50M。
也可以向該管腳直接寫入數(shù)據(jù)和讀取數(shù)據(jù)。 基礎(chǔ)應(yīng)用1,gpio 初始化函數(shù)。所有程序必須。 用法:void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //GPIO 狀態(tài)恢復(fù)默認(rèn)參數(shù)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_標(biāo)號(hào) | GPIO_Pin_標(biāo)號(hào) ; //管腳位置定義,標(biāo)號(hào)可以是 NONE、ALL、0至15。
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;//輸出速度2MHz GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模擬輸入模式 GPIO_Init(GPIOC, &GPIO_InitStructure); //C 組 GPIO 初始化
//注:以上四行代碼為一組,每組 GPIO 屬性必須相同,默認(rèn)的 GPIO 參數(shù)為:ALL,2MHz,F(xiàn)LATING。如果其中任意 一行與前一組相應(yīng)設(shè)置相同,那么那一行可以省略,由此推論如果前面已經(jīng)將此行參數(shù)設(shè)定為默認(rèn)參數(shù)(包括使 用
GPIO_InitTypeDef GPIO_InitStructure 代碼),本組應(yīng)用也是默認(rèn)參數(shù)的話,那么也可以省略。以下重復(fù)這個(gè)過程直到所 有應(yīng)用的管腳全部被定義完畢。
……
}
基礎(chǔ)應(yīng)用2,向管腳寫入0或1
用法:GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01); //寫入1
基礎(chǔ)應(yīng)用3,從管腳讀入0或1
用法:GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)
讓它跑起來,基本硬件功能的建立
0、 實(shí)驗(yàn)之前的準(zhǔn)備
a) 接通串口轉(zhuǎn)接器
b) 下載 IO 與串口的原廠程序,編譯通過保證調(diào)試所需硬件正常。
1、 flash,lib,nvic,rcc 和 GPIO,基礎(chǔ)程序庫編寫
a) 這幾個(gè)庫函數(shù)中有一些函數(shù)是關(guān)于芯片的初始化的,每個(gè)程序中必用。為保障程序品質(zhì),初學(xué)階段要求嚴(yán)格遵守官方 習(xí)慣。注意,官方程序庫例程中有個(gè) platform_config.h 文件,是專門用來指定同類外設(shè)中第幾號(hào)外設(shè)被使用,就是說在 main.c 里面所有外設(shè)序號(hào)用 x 代替,比如 USARTx,程序會(huì)到這個(gè)頭文件中去查找到底是用那些外設(shè),初學(xué)的時(shí)候參考 例程別被這個(gè)所迷惑住。
b) 全部必用代碼取自庫函數(shù)所帶例程,并增加逐句注釋。
c) 習(xí)慣順序——Lib(debug),RCC(包括 Flash 優(yōu)化),NVIC,GPIO
d) 必用模塊初始化函數(shù)的定義:
void RCC_Configuration(void); //定義時(shí)鐘初始化函數(shù)
void GPIO_Configuration(void); //定義管腳初始化函數(shù)
void NVIC_Configuration(void); //定義中斷管理初始化函數(shù)
void Delay(vu32 nCount); //定義延遲函數(shù) e) Main 中的初始化函數(shù)調(diào)用: RCC_Configuration(); //時(shí)鐘初始化函數(shù)調(diào)用 NVIC_Configuration(); //中斷初始化函數(shù)調(diào)用 GPIO_Configuration(); //管腳初始化函數(shù)調(diào)用 f) Lib 注意事項(xiàng):
屬于 Lib 的 Debug 函數(shù)的調(diào)用,應(yīng)該放在 main 函數(shù)最開始,不要改變其位置。
g) RCC 注意事項(xiàng):
Flash 優(yōu)化處理可以不做,但是兩句也不難也不用改參數(shù)…… 根據(jù)需要開啟設(shè)備時(shí)鐘可以節(jié)省電能 時(shí)鐘頻率需要根據(jù)實(shí)際情況設(shè)置參數(shù)
h) NVIC 注意事項(xiàng) 注意理解占先優(yōu)先級(jí)和響應(yīng)優(yōu)先級(jí)的分組的概念 i) GPIO 注意事項(xiàng)
注意以后的過程中收集不同管腳應(yīng)用對(duì)應(yīng)的頻率和模式的設(shè)置。 作為高低電平的 I/O,所需設(shè)置:RCC 初始化里面打開 RCC_APB2
PeriphClockCmd(RCC_APB2Periph_GPIOA);GPIO 里面管腳設(shè)定:IO 輸出(50MHz,Out_PP);IO 輸入(50MHz,IPU);
j) GPIO 應(yīng)用
GPIO_WriteBit(GPIOB, GPIO_Pin_2, Bit_RESET);//重置
GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1
GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//寫入0
GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6) ;//讀入 IO
k) 簡單 Delay 函數(shù)
void Delay(vu32 nCount)//簡單延時(shí)函數(shù)
{for(; nCount != 0; nCount--);}
實(shí)驗(yàn)步驟:
RCC 初 始 化 函 數(shù) 里 添 加 : RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB , ENABLE);
不用其他中斷,NVIC 初始化函數(shù)不用改
GPIO 初始化代碼:
//IO 輸入,GPIOB 的2、10、11腳輸出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 ;//管腳號(hào) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //輸出速度 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //輸入輸出模式 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化
簡單的延遲函數(shù):
void Delay(vu32 nCount) //簡單延時(shí)函數(shù)
{ for (; nCount != 0; nCount--);} //循環(huán)計(jì)數(shù)延時(shí) 完成之后再在 main.c 的 while 里面寫一段: GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1
Delay(0xffff);
GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x00);//寫入0
Delay(0xffff);
就可以看到連接在 PB2腳上的 LED 閃爍了,單片機(jī)就跑起來了。
深入淺出 STM32 (3)
STM32筆記之八:來跟 PC 打個(gè)招呼,基本串口通訊
a) 目的:在基礎(chǔ)實(shí)驗(yàn)成功的基礎(chǔ)上,對(duì)串口的調(diào)試方法進(jìn)行實(shí)踐。硬件代碼順利完成之后,對(duì)日后調(diào)試需要用到的
printf 重定義進(jìn)行調(diào)試,固定在自己的庫函數(shù)中。
b) 初始化函數(shù)定義:
void USART_Configuration(void); //定義串口初始化函數(shù)
c) 初始化函數(shù)調(diào)用:
void UART_Configuration(void); //串口初始化函數(shù)調(diào)用 初始化代碼:
void USART_Configuration(void) //串口初始化函數(shù)
{
//串口參數(shù)初始化
USART_InitTypeDef USART_InitStructure; //串口設(shè)置恢復(fù)默認(rèn)參數(shù)
//初始化參數(shù)設(shè)置
USART_InitStructure.USART_BaudRate = 9600; //波特率9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長8位 USART_InitStructure.USART_StopBits = USART_StopBits_1; //1位停止字節(jié) USART_InitStructure.USART_Parity = USART_Parity_No; //無奇偶校驗(yàn) USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//無流控制 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//打開 Rx 接收和 Tx 發(fā)送功能
USART_Init(USART1, &USART_InitStructure); //初始化
USART_Cmd(USART1, ENABLE); //啟動(dòng)串口
}
RCC 中打開相應(yīng)串口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
GPIO 里面設(shè)定相應(yīng)串口管腳模式
//串口1的管腳初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //管腳9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽輸出
GPIO_Init(GPIOA, &GPIO_InitStructure); //TX 初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; //管腳10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //RX 初始化
d) 簡單應(yīng)用: 發(fā)送一位字符
USART_SendData(USART1, 數(shù)據(jù)); //發(fā)送一位數(shù)據(jù)
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發(fā)送完畢 接收一位字符
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){} //等待接收完畢 變量= (USART_ReceiveData(USART1)); //接受一個(gè)字節(jié)
發(fā)送一個(gè)字符串 先定義字符串:char rx_data[250];
然后在需要發(fā)送的地方添加如下代碼
int i; //定義循環(huán)變量
while(rx_data!='\0') //循環(huán)逐字輸出,到結(jié)束字'\0'
{USART_SendData(USART1, rx_data); //發(fā)送字符
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符發(fā)送完畢
i++;}
e) USART 注意事項(xiàng): 發(fā)動(dòng)和接受都需要配合標(biāo)志等待。 只能對(duì)一個(gè)字節(jié)操作,對(duì)字符串等大量數(shù)據(jù)操作需要寫函數(shù) 使用串口所需設(shè)置:RCC 初始化里面打開 RCC_APB2PeriphClockCmd
(RCC_APB2Periph_USARTx);GPIO 里面管腳設(shè)定:串口 RX(50Hz,IN_FLOATING);串口 TX(50Hz,AF_PP);
f) printf 函數(shù)重定義(不必理解,調(diào)試通過以備后用)
(1) 需要 c 標(biāo)準(zhǔn)函數(shù):
#i nclude "stdio.h"
(2) 粘貼函數(shù)定義代碼
#define PUTCHAR_PROTOTYPE int io_putchar(int ch) //定義為 putchar 應(yīng)用
(3) RCC 中打開相應(yīng)串口
(4) GPIO 里面設(shè)定相應(yīng)串口管腳模式
(6) 增加為 putchar 函數(shù)。
int putchar(int c) //putchar 函數(shù)
{
if (c == '\n'){putchar('\r');} //將 printf 的\n 變成\r USART_SendData(USART1, c); //發(fā)送字符 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發(fā)送結(jié)束 return c; //返回值
}
(8) 通過,試驗(yàn)成功。printf 使用變量輸出:%c 字符,%d 整數(shù),%f 浮點(diǎn)數(shù),%s 字符串,/n 或/r 為換行。注意:只
能用于 main.c 中。
3、 NVIC 串口中斷的應(yīng)用
a) 目的:利用前面調(diào)通的硬件基礎(chǔ),和幾個(gè)函數(shù)的代碼,進(jìn)行串口的中斷輸入練習(xí)。因?yàn)樵趯?shí)際應(yīng)用中,不使用中 斷進(jìn)行的輸入是效率非常低的,這種用法很少見,大部分串口的輸入都離不開中斷。
b) 初 始 化 函 數(shù) 定 義 及 函 數(shù) 調(diào) 用 : 不 用 添 加 和 調(diào) 用 初 始 化 函 數(shù) , 在 指 定 調(diào) 試 地 址 的 時(shí) 候 已 經(jīng) 調(diào) 用 過 , 在 那 個(gè)
NVIC_Configuration 里面添加相應(yīng)開中斷代碼就行了。
c) 過程:
i. 在串口初始化中 USART_Cmd 之前加入中斷設(shè)置:
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE 發(fā)送中斷,TC 傳輸完成中斷,RXNE 接收中斷,PE
奇偶錯(cuò)誤中斷,可以是多個(gè)。
ii. RCC、GPIO 里面打開串口相應(yīng)的基本時(shí)鐘、管腳設(shè)置
iii. NVIC 里面加入串口中斷打開代碼: NVIC_InitTypeDef NVIC_InitStructure;//中斷默認(rèn)參數(shù) NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道設(shè)置為串口1中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中斷占先等級(jí)0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中斷響應(yīng)優(yōu)先級(jí)0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打開中斷
NVIC_Init(&NVIC_InitStructure); //初始化
iv. 在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數(shù),在其中添入執(zhí)行代碼。一般最少三個(gè)步驟:先使用
if 語句判斷是發(fā)生那個(gè)中斷,然后清除中斷標(biāo)志位,最后給字符串賦值,或做其他事情。
void USART1_IRQHandler(void) //串口1中斷
{
char RX_dat; //定義字符變量
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判斷發(fā)生接收中斷
{USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中斷標(biāo)志
GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01); //開始傳輸 RX_dat=USART_ReceiveData(USART1) & 0x7F; //接收數(shù)據(jù),整理除去前兩位 USART_SendData(USART1, RX_dat); //發(fā)送數(shù)據(jù) while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待發(fā)送結(jié)束
}
}
d) 中斷注意事項(xiàng):
可以隨時(shí)在程序中使用 USART_ITConfig(USART1, USART_IT_TXE, DISABLE);來關(guān)閉中斷響應(yīng)。 NVIC_InitTypeDef NVIC_InitStructure 定義一定要加在 NVIC 初始化模塊的第一句。 全局變量與函數(shù)的定義:在任意.c 文件中定義的變量或函數(shù),在其它.c 文件中使用 extern+定義代碼再次定義就可以
直接調(diào)用了。
STM32筆記之九:打斷它來為我辦事,EXIT (外部 I/O 中斷)應(yīng)用
a) 目的:跟串口輸入類似,不使用中斷進(jìn)行的 IO 輸入效率也很低,而且可以通過 EXTI 插入按鈕事件,本節(jié)聯(lián)系
EXTI 中斷。
b) 初始化函數(shù)定義:
void EXTI_Configuration(void); //定義 IO 中斷初始化函數(shù)
c) 初始化函數(shù)調(diào)用:
EXTI_Configuration();//IO 中斷初始化函數(shù)調(diào)用簡單應(yīng)用:
d) 初始化函數(shù):
void EXTI_Configuration(void)
{ EXTI_InitTypeDef EXTI_InitStructure; //EXTI 初始化結(jié)構(gòu)定義
EXTI_ClearITPendingBit(EXTI_LINE_KEY_BUTTON);//清除中斷標(biāo)志
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource3);//管腳選擇
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource4); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource5); GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource6);
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//事件選擇
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//觸發(fā)模式 EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //線路選擇 EXTI_InitStructure.EXTI_LineCmd = ENABLE;//啟動(dòng)中斷 EXTI_Init(&EXTI_InitStructure);//初始化
}
e) RCC 初始化函數(shù)中開啟 I/O 時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); GPIO 初始化函數(shù)中定義輸入 I/O 管腳。
//IO 輸入,GPIOA 的4腳輸入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉輸入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化
f) 在 NVIC 的初始化函數(shù)里面增加以下代碼打開相關(guān)中斷: NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先級(jí) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)級(jí)
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動(dòng)
NVIC_Init(&NVIC_InitStructure); //初始化
g) 在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數(shù),在其中添入執(zhí)行代碼。一般最少三個(gè)步驟:先使用
if 語句判斷是發(fā)生那個(gè)中斷,然后清除中斷標(biāo)志位,最后給字符串賦值,或做其他事情。
if(EXTI_GetITStatus(EXTI_Line3) != RESET) //判斷中斷發(fā)生來源
{ EXTI_ClearITPendingBit(EXTI_Line3); //清除中斷標(biāo)志 USART_SendData(USART1, 0x41); //發(fā)送字符“a” GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED 發(fā) 生 明 暗
交替
}
h) 中斷注意事項(xiàng): 中斷發(fā)生后必須清除中斷位,否則會(huì)出現(xiàn)死循環(huán)不斷發(fā)生這個(gè)中斷。然后需要對(duì)中斷類型進(jìn)行判斷再執(zhí)行代碼。 使用 EXTI 的 I/O 中斷,在完成 RCC 與 GPIO 硬件設(shè)置之后需要做三件事:初始化 EXTI、NVIC 開中斷、編寫中斷
執(zhí)行代碼。
STM32筆記之十:工作工作,PWM 輸出
a) 目的:基礎(chǔ) PWM 輸出,以及中斷配合應(yīng)用。輸出選用 PB1,配置為 TIM3_CH4,是目標(biāo)板的 LED6控制腳。
b) 對(duì)于簡單的 PWM 輸出應(yīng)用,暫時(shí)無需考慮 TIM1的高級(jí)功能之區(qū)別。
c) 初始化函數(shù)定義:
void TIM_Configuration(void); //定義 TIM 初始化函數(shù)
d) 初始化函數(shù)調(diào)用:
TIM_Configuration(); //TIM 初始化函數(shù)調(diào)用
e) 初始化函數(shù),不同于前面模塊,TIM 的初始化分為兩部分——基本初始化和通道初始化:
void TIM_Configuration(void)//TIM 初始化函數(shù)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定時(shí)器初始化結(jié)構(gòu)
TIM_OCInitTypeDef TIM_OCInitStructure;//通道輸出初始化結(jié)構(gòu)
//TIM3初始化
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFF TIM_TimeBaseStructure.TIM_Prescaler = 5; //時(shí)鐘分頻 TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時(shí)鐘分割 TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //基本初始化 TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打開中斷,中斷需要這行代碼
//TIM3通道初始化
TIM_OCStructInit(& TIM_OCInitStructure); //默認(rèn)參數(shù) TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //工作狀態(tài) TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //設(shè)定為輸出,需要 PWM 輸出才需要這
行代碼
TIM_OCInitStructure.TIM_Pulse = 0x2000; //占空長度 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //高電平 TIM_OC4Init(TIM3, &TIM_OCInitStructure); //通道初始化
TIM_Cmd(TIM3, ENABLE); //啟動(dòng)
TIM3
}
f) RCC 初始化函數(shù)中加入 TIM 時(shí)鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g) GPIO 里面將輸入和輸出管腳模式進(jìn)行設(shè)置。信號(hào):AF_PP,50MHz。
h) 使用中斷的話在 NVIC 里添加如下代碼:
//打開 TIM2中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級(jí) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //響應(yīng)級(jí) NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動(dòng) NVIC_Init(&NVIC_InitStructure); //初始化
中斷代碼:
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET) //判斷中斷來源
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除中斷標(biāo)志
GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_11)));// 變 換 LED 色 彩
IC4value = TIM_GetCapture4(TIM2); //獲取捕捉數(shù)值
}
}
i) 簡單應(yīng)用:
//改變占空比 TIM_SetCompare4(TIM3, 變量); j) 注意事項(xiàng):
管腳的 IO 輸出模式是根據(jù)應(yīng)用來定,比如如果用 PWM 輸出驅(qū)動(dòng) LED 則應(yīng)該將相應(yīng)管腳設(shè)為 AF_PP,否則單片機(jī) 沒有輸出
我的測(cè)試程序可以發(fā)出不斷循環(huán)三種波長并捕獲,對(duì)比結(jié)果如下: 捕捉的穩(wěn)定性很好,也就是說,同樣的方波捕捉到數(shù)值相差在一兩個(gè)數(shù)值。 捕捉的精度跟你設(shè)置的濾波器長度有關(guān),在這里
TIM_ICInitStructure.TIM_ICFilter = 0x4; //濾波設(shè)置,經(jīng)歷幾個(gè)周期跳變認(rèn)定波形穩(wěn)定0x0~0xF
這個(gè)越長就會(huì)捕捉數(shù)值越小,但是偏差幾十個(gè)數(shù)值,下面是0、4、16個(gè)周期濾波的比較,out 是輸出的數(shù)值,in 是捕 捉到的。
現(xiàn)在有兩個(gè)疑問:
1、在 TIM2的捕捉輸入通道初始化里面這句
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); //選擇時(shí)鐘觸發(fā)源
按照硬件框圖,4通道應(yīng)該對(duì)應(yīng) TI4FP4?墒菍(shí)際使用 TI1FP1,TI2FP2都行,其他均編譯錯(cuò)誤未注冊(cè)。這是為什么?
2、關(guān)閉調(diào)試器和 IAR 程序,直接供電跑出來的結(jié)果第一個(gè)周期很正常,當(dāng)輸出脈寬第二次循環(huán)變小后捕捉的數(shù)值就 差的遠(yuǎn)了。不知道是為什么
時(shí)鐘不息工作不止,systic 時(shí)鐘應(yīng)用
a) 目的:使用系統(tǒng)時(shí)鐘來進(jìn)行兩項(xiàng)實(shí)驗(yàn)——周期執(zhí)行代碼與精確定時(shí)延遲。
b) 初始化函數(shù)定義:
void SysTick_Configuration(void);
c) 初始化函數(shù)調(diào)用:
SysTick_Configuration();
d) 初始化函數(shù):
void SysTick_Configuration(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//時(shí)鐘除8
SysTick_SetReload(250000); //計(jì)數(shù)周期長度 SysTick_CounterCmd(SysTick_Counter_Enable); //啟動(dòng)計(jì)時(shí)器 SysTick_ITConfig(ENABLE); //打開中斷
}
e) 在 NVIC 的初始化函數(shù)里面增加以下代碼打開相關(guān)中斷:
NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中斷等級(jí)設(shè)置,一般設(shè)置的高一些會(huì)少受其他影響
f) 在 stm32f10x_it.c 文件中找到 void SysTickHandler 函數(shù)
void SysTickHandler(void)
{
執(zhí)行代碼
}
g) 簡單應(yīng)用:精確延遲函數(shù),因?yàn)?systic 中斷往往被用來執(zhí)行周期循環(huán)代碼,所以一些例程中使用其中斷的啟動(dòng)和 禁止來編寫的精確延時(shí)函數(shù)實(shí)際上不實(shí)用,我自己編寫了精確計(jì)時(shí)函數(shù)反而代碼更精簡,思路更簡單。思路是調(diào)用 后,變量清零,然后使用時(shí)鐘來的曾變量,不斷比較變量與延遲的數(shù)值,相等則退出函數(shù)。代碼和步驟如下:
i. 定義通用變量:u16 Tic_Val=0; //變量用于精確計(jì)時(shí)
ii. 在 stm32f10x_it.c 文件中相應(yīng)定義:
extern u16 Tic_Val;//在本文件引用 MAIN.c 定義的精確計(jì)時(shí)變量
iii. 定義函數(shù)名稱:void Tic_Delay(u16 Tic_Count);//精確延遲函數(shù)
iv. 精確延時(shí)函數(shù):
void Tic_Delay(u16 Tic_Count) //精確延時(shí)函數(shù)
{ Tic_Val=0; //變量清零
while(Tic_Val != Tic_Count){printf("");}//計(jì)時(shí)
}
v. 在 stm32f10x_it.c 文件中 void SysTickHandler 函數(shù)里面添加
Tic_Val++;//變量遞增
vi. 調(diào)用代碼:Tic_Delay(10); //精確延時(shí)
vii. 疑問:如果去掉計(jì)時(shí)行那個(gè)沒用的 printf("");函數(shù)將停止工作,這個(gè)現(xiàn)象很奇怪
C 語言功底問題。是的,那個(gè)“注意事項(xiàng)”最后的疑問的原因就是這個(gè)
Tic_Val 應(yīng)該改為 vu16
while(Tic_Val != Tic_Count){printf("");}//計(jì)時(shí) 就可以改為:
while(Tic_Val != Tic_Count); //檢查變量是否計(jì)數(shù)到位
STM32筆記之十三:惡搞,兩只看門狗 a) 目的: 了解兩種看門狗(我叫它:系統(tǒng)運(yùn)行故障探測(cè)器和獨(dú)立系統(tǒng)故障探測(cè)器,新手往往被這個(gè)并不形象的象形名稱搞糊
涂)之間的區(qū)別和基本用法。
b) 相同: 都是用來探測(cè)系統(tǒng)故障,通過編寫代碼定時(shí)發(fā)送故障清零信號(hào)(高手們都管這個(gè)代碼叫做“喂狗”),告訴它系統(tǒng)運(yùn)行
正常。一旦系統(tǒng)故障,程序清零代碼(“喂狗”)無法執(zhí)行,其計(jì)數(shù)器就會(huì)計(jì)數(shù)不止,直到記到零并發(fā)生故障中斷(狗 餓了開始叫喚),控制 CPU 重啟整個(gè)系統(tǒng)(不行啦,開始咬人了,快跑……)。
c) 區(qū)別:
獨(dú)立看門狗 Iwdg——我的理解是獨(dú)立于系統(tǒng)之外,因?yàn)橛歇?dú)立時(shí)鐘,所以不受系統(tǒng)影響的系統(tǒng)故障探測(cè)器 。(這條 狗是借來的,見誰偷懶它都咬。┲饕糜诒O(jiān)視硬件錯(cuò)誤。
窗口看門狗 wwdg——我的理解是系統(tǒng)內(nèi)部的故障探測(cè)器,時(shí)鐘與系統(tǒng)相同。如果系統(tǒng)時(shí)鐘不走了,這個(gè)狗也就失去 作用了。(這條狗是老板娘養(yǎng)的,老板不干活兒他不管。┲饕糜诒O(jiān)視軟件錯(cuò)誤。
d) 初始化函數(shù)定義:鑒于兩只狗作用差不多,使用過程也差不多初始化函數(shù)栓一起了,用的時(shí)候根據(jù)情況刪減。
void WDG_Configuration(void);
e) 初始化函數(shù)調(diào)用:
WDG_Configuration();
f) 初始化函數(shù)
void WDG_Configuration() //看門狗初始化
{
//軟件看門狗初始化
WWDG_SetPrescaler(WWDG_Prescaler_8); //時(shí)鐘8分頻4ms
// (PCLK1/4096)/8= 244 Hz (~4 ms) WWDG_SetWindowValue(65); //計(jì)數(shù)器數(shù)值
WWDG_Enable(127); //啟動(dòng)計(jì)數(shù)器,設(shè)置喂狗時(shí)間
// WWDG timeout = ~4 ms * 64 = 262 ms
WWDG_ClearFlag(); //清除標(biāo)志位
WWDG_EnableIT(); //啟動(dòng)中斷
//獨(dú)立看門狗初始化 IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//啟動(dòng)寄存器讀寫 IWDG_SetPrescaler(IWDG_Prescaler_32);//40K 時(shí)鐘32分頻 IWDG_SetReload(349); //計(jì)數(shù)器數(shù)值 IWDG_ReloadCounter(); //重啟計(jì)數(shù)器
IWDG_Enable(); //啟動(dòng)看門狗
}
g) RCC 初始化:只有軟件看門狗需要時(shí)鐘初始化,獨(dú)立看門狗有自己的時(shí)鐘不需要但是需要 systic 工作相關(guān)設(shè)置。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
h) 獨(dú)立看門狗使用 systic 的中斷來喂狗,所以添加 systic 的中斷打開代碼就行了。軟件看門狗需要在 NVIC 打開中 斷添加如下代碼:
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //占先中斷等級(jí) NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)中斷優(yōu)先級(jí) NVIC_Init(&NVIC_InitStructure); //打開中斷
i) 中斷程序,軟件看門狗在自己的中斷中喂狗,獨(dú)立看門狗需要使用 systic 的定時(shí)中斷來喂狗。以下兩個(gè)程序都在
stm32f10x_it.c 文件中。
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(0x7F); //更新計(jì)數(shù)值
WWDG_ClearFlag(); //清除標(biāo)志位
}
void SysTickHandler(void)
{ IWDG_ReloadCounter(); //重啟計(jì)數(shù)器(喂狗)
}
j) 注意事項(xiàng):
i. 有狗平常沒事情可以不理,但是千萬別忘了喂它,否則死都不知道怎么死的!
ii. 初始化程序的調(diào)用一定要在 systic 的初始化之后。
iii. 獨(dú)立看門狗需要 systic 中斷來喂,但是 systic 做別的用處不能只做這件事,所以我寫了如下幾句代碼,可以不影
響 systic 的其他應(yīng)用,其他 systic 周期代碼也可參考: 第一步:在 stm32f10x_it.c 中定義變量
int Tic_IWDG; //喂狗循環(huán)程序的頻率判斷變量 第二步:將 SysTickHandler 中喂狗代碼改為下面: Tic_IWDG++; //變量遞增
if(Tic_IWDG>=100) //每100個(gè) systic 周期喂狗
{ IWDG_ReloadCounter();//重啟計(jì)數(shù)器(喂狗)
Tic_IWDG=0; //變量清零
}
完整的pdf格式文檔51黑下載地址(共87頁):
深入淺出STM32系列ARM_Cortex-M3.pdf
(408.48 KB, 下載次數(shù): 54)
2018-10-19 15:46 上傳
點(diǎn)擊文件名下載附件
下載積分: 黑幣 -5
|
評(píng)分
-
查看全部評(píng)分
|