|
STM32學(xué)前班教程之一:為什么是它
經(jīng)過幾天的學(xué)習(xí),基本掌握了STM32的調(diào)試環(huán)境和一些基本知識。想拿出來與大家共享,笨教程本著最大限度簡化刪減STM32入門的過程的思想,會把我的整個入門前的工作推薦給大家。就算是給網(wǎng)上的眾多教程、筆記的一種補充吧,所以叫學(xué)前班教程。其中涉及產(chǎn)品一律隱去來源和品牌,以防廣告之嫌。全部漢字內(nèi)容為個人筆記。所有相關(guān)參考資料也全部列出。:lol
教程會分幾篇,因為太長啦。今天先來說說為什么是它——我選擇STM32的原因。
我對未來的規(guī)劃是以功能性為主的,在功能和面積之間做以平衡是我的首要選擇,而把運算放在第二位,這根我的專業(yè)有關(guān)系。里面的運算其實并不復(fù)雜,在入門階段想盡量減少所接觸的東西。
不過說實話,對DSP的外設(shè)并和開發(fā)環(huán)境不滿意,這是為什么STM32一出就轉(zhuǎn)向的原因。下面是我自己做過的兩塊DSP28的全功能最小系統(tǒng)板,在做這兩塊板子的過程中發(fā)現(xiàn)要想盡力縮小DSP的面積實在不容易(目前只能達到50mm×45mm,這還是沒有其他器件的情況下),尤其是雙電源的供電方式和1.9V的電源讓人很頭疼。
后來因為一個項目,接觸了LPC2148并做了一塊板子,發(fā)現(xiàn)小型的ARM7在外設(shè)夠用的情況下其實很不錯,于是開始搜集相關(guān)芯片資料,也同時對小面積的AVR和51都進行了大致的比較,這個時候發(fā)現(xiàn)了CortexM3的STM32,比2148擁有更豐富和靈活的外設(shè),性能幾乎是2148兩倍(按照MIPS值計算)。正好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%,單片價格是DSP的30%。且有更多的串口,CAP和PWM,這是有用的。高端型號有SDIO,理論上比SPI速度快。
由以上比較,準備將未來的擁有操作系統(tǒng)的高端應(yīng)用交給DSP的新型浮點型單片機28335,而將所有緊湊型小型、微型應(yīng)用交給STM32。
STM32學(xué)前班教程:怎么開發(fā)
sw笨笨的STM32學(xué)前班教程之二:怎么開發(fā)目前手頭的入門階段使用的開發(fā)器概述
該產(chǎn)品為簡易STM32調(diào)試器和DEMO板一體化的調(diào)試學(xué)習(xí)設(shè)備,價格在一百多塊。
2、硬件配置
仿真部分:USB口,reset,指示燈,JTAG
DEMO部分:4按鍵(IO),4LED(IO),一個串口,啟動方式跳線,所有引腳的焊盤(可自行焊接插針進行擴展)
DEMO芯片:STM32F103C8T6(程序空間64K)
參數(shù)和擴展:
注:學(xué)習(xí)的目標芯片是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自動安裝驅(qū)動
安裝完成后如果DEMO板里面有程序就會自動運行了。這是ST-Link-II的通用連接方法
以上是學(xué)習(xí)階段比較方便的仿真器,進入工程階段后準備換J-Link V7的仿真器進行開發(fā)。目前比較滿意的產(chǎn)品:JLink v7+USB轉(zhuǎn)串口:
購買后所需的改造:打開殼體,將USB的+5V供電跟JTAG20針的第二腳Vsupply飛線,提供目標板5V500mA的供電?粗械奶攸c:集成串口,擁有20針JTAG可以改造Vspply為供電接口,小巧好帶,便宜。
常見的用于STM32單片機的仿真器分類
a) Ulink2:之前常用的仿真器。Keil公司產(chǎn)品,之前專用于ARM7,現(xiàn)擴展到CortexM3,調(diào)試接口支持JTAG和SWD,連接到PC主機的USB,F(xiàn)在這種調(diào)試器已經(jīng)用的越來越少了。
b) ST-Link-II:ST公司的仿真接口,支持IAR EWARM,USB 1.1全速,USB電源供電,自適應(yīng)目標系統(tǒng)JTAG電平3.3V-5V,可向目標系統(tǒng)提供不大于5V/200mA電源。這種調(diào)試器不多見,但是許多調(diào)試器與目標板一體設(shè)計的學(xué)習(xí)板上常見。
c) J-Link V6/V7:SEGGER公司產(chǎn)品,調(diào)試接口支持JTAG和SWV(V7速度是V6的12倍),USB 2.0接口,通過USB供電,下載速度達到720k byte/s, 與IAR WEARM無縫集成,寬目標板電壓范圍:1.2V-3.3V(V7支持5V),多核調(diào)試,給目標板提供3.3V50mA電源。這種調(diào)試器現(xiàn)在出現(xiàn)的越來越多,兼容性比較好(主要是指能夠與IAR WEARM無縫集成這點),國內(nèi)山寨貨和各種變種也很多。
6、目標板主要分為一體化設(shè)計(與調(diào)試器、供電整合)和單獨設(shè)計兩類,詳細產(chǎn)品比較見豆皮的《如何選擇STM32開發(fā)板》。
STM32學(xué)前班教程之三:讓PC工作
開發(fā)軟件的選擇
1、 軟件與版本的選擇
需求:支持STLink2或未來的Jlink V7調(diào)試接口(因為STM32-SK使用這個接口),能夠找到去除軟件限制的方法,最好具有中文版幫助和界面,最好帶有純軟件仿真
選擇:RealView MDK 3.23RPC或者IAR EWARM 4.42A(5版本觀望一下)。
2、 RealView MDK 3.23RPC(中國版)安裝與去除限制
第一步:執(zhí)行安裝程序完成基本安裝,最后選項選擇加入虛擬硬件,便于純軟件調(diào)試。
第二步:執(zhí)行軟件,點擊File-->Licence Manager,復(fù)制CID的數(shù)據(jù)到破解器的CID,其他選項如下圖,然后點擊Generate。
第三步:復(fù)制LIC0的數(shù)據(jù)到軟件的LIC框里面,點擊Add LIC。注意添加序列號后Licence Manager會算出這個號對應(yīng)的有效期,如果到期會顯示為紅色,需要重新點擊破解軟件的Generate,再算一個填進去就行了。
第四步:將ST-LINKII-KEIL Driver所需的文件(兩個DLL)拷貝到\Keil\ARM\BIN下,替換原有文件。
第五步:打開Keil安裝目錄下的TOOLS.INI文件,在[ARM]、[ARMADS]、[KARM]項目下添加TDRV7=BIN\ST-LINKII-KEIL.dll("ST LinkII Debugger")行,并保存修改。
第六步:打開MDK,在項目的options設(shè)置的Debug選項中選擇ST LINKII Debugger,同時在Utilities的選項中選擇ST LINKII Debugger。
完成以上步驟,就完成了ST-LINKII的相關(guān)配置,可以作為調(diào)試器開始使用。注意:目前ST-LINKII不支持Flash菜單中的Download和Erase命令,程序在使用Start/Stop Debug Session時自動載入flash中供調(diào)試。
3、 IAR EWARM 4.42A安裝與破解
第一步:開始/運行…/CMD顯示DOS界面,執(zhí)行iarid.exe>>ID.TXT得到本機ID碼,復(fù)制這個ID碼,再執(zhí)行iarkg.exe ID碼>>Lic422A.TXT,得到一組注冊碼。
第二步:使用EWARM-EV-WEB-442A.exe(30天限制版,其他版本無法使用第一步中的注冊碼),執(zhí)行安裝程序完成基本安裝,過程中需要添入第一步里面算出來的注冊碼,可以取消時間限制,但是那一組當(dāng)中只有一個有效,需要實驗。
4、 鏈接硬件調(diào)試程序
RealView MDK:找到一個STM32-SK的基礎(chǔ)程序,最好是只關(guān)于IO的且與當(dāng)前板子程序不同,這樣在板上就可以看到結(jié)果,點擊Project/open project。例如GPIO、TIMER(另兩個例程是關(guān)于串口的,需要連接串口才能夠看到運行結(jié)果)。
使用“Open Project”打開,然后設(shè)置Option里面的linker和Utilities里面的項目為“ST LinkII Debuger”。
編譯程序,再使用“Start/Stop Debug Session”來寫入程序。
IAR EWARM:與以上相同,找到一個符合條件的例程。打開一個eww工程文件,右鍵選取Option,在Debuger里面選擇“Third-Party Driver”,在“Third-Party Driver”里面添上“$PROJ_DIR$\..\ddl\STM32Driver.dll”。
使用“Make”或“Rebuild All”來編譯程序,點“Debug”就燒寫進Flash。使用調(diào)試欄里面的“go”等等運行程序。
注:由于目前版本MDK與我手頭的ST-LINK-II編程器不兼容,所以后面的所有工作均改用IAR。
STM32學(xué)前班教程之四:打好基礎(chǔ)建立模板
1、 新建目錄Project_IAR4,按照自己的順序重新組織dll(驅(qū)動);inc、src函數(shù)庫;settings,其他所有文件全部放這個新建的目錄下。
2、 雙擊打開Project.eww,繼續(xù)更改內(nèi)部設(shè)置。
3、 需更改的內(nèi)容列表:
位置和項目 目標 說明
Project\Edir confignations 新建基于STM3210B的配置 編譯目標和過程文件存放
Project\Option\General Option\Target ST STM32F10x 選擇芯片類型
Project\Option\ C/C++ Compiler\Preprocessor\Additional include directories $PROJ_DIR$\
$PROJ_DIR$\inc 頭文件相對位置,需要包括“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)化等級
Project\Option\ Linker\Output 去掉Overrride default 輸出格式使用默認
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ū)動連接單片機
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ū)動文件路徑
注1:所有跟路徑相關(guān)的設(shè)置需要根據(jù)實際情況編寫,相對路徑的編寫——“$PROJ_DIR$”代表eww文件所在文件夾,“..”代表向上一層。
注2:其他設(shè)置使用庫函數(shù)里面的工程文件的默認選項即可,初學(xué)不用了解太多。
4、 需要重新刪除并重新添加Project下“FWLib”和“User”的所有文件,為了刪減外設(shè)模塊方便需要在“USER”額外添加“stm32f10x_conf.h”(不添加也可以,需要展開main.c找到它)。然后執(zhí)行Project\Rebuid All,通過則設(shè)置完畢。
5、 完成以上步驟,第一個自己習(xí)慣的程序庫就建立完畢了,以后可以從“stm32f10x_conf.h”中刪減各種庫文件,從“stm32f10x_it.c”編輯中斷,從“main.c”編寫得到自己的程序。最后需要將這個庫打包封存,每次解壓縮并修改主目錄名稱即可。
6、 我的程序庫特點:
a) 默認兼容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è)時鐘模板),gpio(管腳定義模板)的初始化代碼,所有模板代碼用到的時候只要去掉前面的注釋“//”,根據(jù)需求填入相應(yīng)值就可以了。
e) 因為自己記性不好,所以main函數(shù)中的代碼做到每行注釋,便于自己以后使用。
f) 集成Print_U函數(shù)簡單串口收發(fā)函數(shù)代碼,便于調(diào)試,改變使用Printf函數(shù)的調(diào)試習(xí)慣。
g) 集成使用systick的精確延時函數(shù)delay。
h) 集成時鐘故障處理代碼。
i) 集成電壓監(jiān)控代碼。
j) 集成片上溫度檢測代碼。
k) 逐步加入所有外設(shè)的初始化模塊
一、編寫程序所需的步驟
1、解壓縮,改目錄名稱,和eww文件名,以便跟其他程序區(qū)分。
2、更改設(shè)置:在“stm32f10x_conf.h”關(guān)閉不用的外設(shè)(在其聲明函數(shù)前面加注釋符號“//”)。并根據(jù)外部晶振速度更改其中“HSE_Value”的數(shù)值,其單位是Hz。
3、完成各種頭文件的包含(#include "xxx.h";),公共變量的聲明(static 數(shù)據(jù)類型 變量名稱;),子程序聲明(void 函數(shù)名稱(參數(shù));)……C語言必須的前置工作。
4、改寫我的程序庫里面所預(yù)設(shè)的模板,再進行其他模塊的初始化子程序代碼的編寫,并在程序代碼的開始部分調(diào)用。注意:必須記住所有外設(shè)的使用需要考慮4個問題:
a) 開時鐘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”項目里面改擴展名為hex。
使用軟件界面的Debug燒寫并按鈕調(diào)試程序。注意,ST-Link-II是直接將程序燒寫進Flash進行調(diào)試,而不是使用RAM的方式。
STM32學(xué)前班教程之五:給等待入門的人一點點建議
入門必須閱讀的相關(guān)文檔
1、 幾個重要官方文檔的功能:
a) Datasheet——芯片基本數(shù)據(jù),功能參數(shù)封裝管腳定義和性能規(guī)范。
b) 固件函數(shù)庫用戶手冊——函數(shù)庫功能,庫函數(shù)的定義、功能和用法。
c) 參考手冊——各種功能的具體描述,使用方法,原理,相關(guān)寄存器。
d) STM32F10xxx硬件開發(fā):使用入門——相關(guān)基礎(chǔ)硬件設(shè)計
e) STM32F10XXX的使用限制:芯片內(nèi)部未解決的硬件設(shè)計bug,開發(fā)需要注意繞開。
f) 一本簡單的C語言書,相信我,不用太復(fù)雜。
2、 其他的有用文檔,對初學(xué)幫助很大
a) 如何使用STM32的軟件庫在IAR的EWARM下進行應(yīng)用開發(fā)——IAR基礎(chǔ)設(shè)置。
b) 輕松進入STM32+Cortex-M3世界.ppt——開發(fā)板和最小系統(tǒng)設(shè)計需求。
c) 如何選擇STM32開發(fā)板.pdf——各種開發(fā)板介紹和功能比較。
d) MXCHIP的系列視頻教程——全部芯片基礎(chǔ)及其外設(shè)的教程,使用函數(shù)庫編程的話就不用看每個視頻后半段的關(guān)于寄存器的介紹了。
e) STM32_Technical_Slide(常見問題)——一些優(yōu)化設(shè)計方案。
3、 關(guān)于參考書,買了兩本但是基本對學(xué)習(xí)沒什么幫助,如果湊齊以上資料,建議慎重買書,不如留著那n個幾十塊錢,攢到一起買開發(fā)板。
我自己的學(xué)習(xí)過程
1、 一共24個庫,不可能都學(xué),都學(xué)也沒用。按照我的工作需求必須學(xué)的有16個,這16個也不是全學(xué)。主要學(xué)習(xí)來源是各種例程代碼、“固件函數(shù)庫用戶手冊”和“參考手冊”。
具體學(xué)習(xí)方法是通讀不同來源的程序,在程序中找到相關(guān)的函數(shù)庫的應(yīng)用,然后再閱讀相關(guān)文檔,有條件的實驗。對于內(nèi)容的選擇方面,根據(jù)入門內(nèi)容和未來應(yīng)用,將所涉及的范圍精簡到最低,但是對所選擇的部分的學(xué)習(xí)則力求明確。以下是我按照自己的需求對程序庫函數(shù)排列的學(xué)習(xí)順序:
a) 絕大部分程序都要涉及到的庫——flash,lib,nvic,rcc,只學(xué)基礎(chǔ)的跟最簡單應(yīng)用相關(guān)必用的部分,其他部分后期再返回頭學(xué)。
b) 各種程序通用但不必用的庫——exti,MDA,systic,只通讀理解其作用。
c) DEMO板擁有的外設(shè)庫——gpio,usart,編寫代碼實驗。
d) 未來需要用到的外設(shè)的庫——tim,tim1,adc,i2c,spi,先理解等待有條件后實驗。
e) 開發(fā)可靠性相關(guān)庫——bkp,iwdg,wwdg,pwr,參考其他例程的做法。
f) 其他,根據(jù)興趣來學(xué)。
STM32學(xué)前班教程之六:這些代碼大家都用得到
2、 閱讀flash: 芯片內(nèi)部存儲器flash操作函數(shù)
我的理解——對芯片內(nèi)部flash進行操作的函數(shù),包括讀取,狀態(tài),擦除,寫入等等,可以允許程序去操作flash上的數(shù)據(jù)。
基礎(chǔ)應(yīng)用1,F(xiàn)LASH時序延遲幾個周期,等待總線同步操作。推薦按照單片機系統(tǒng)運行頻率,0—24MHz時,取Latency=0;24—48MHz時,取Latency=1;48~72MHz時,取Latency=2。所有程序中必須的
用法:FLASH_SetLatency(FLASH_Latency_2);
位置:RCC初始化子函數(shù)里面,時鐘起振之后。
基礎(chǔ)應(yīng)用2,開啟FLASH預(yù)讀緩沖功能,加速FLASH的讀取。所有程序中必須的
用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
位置:RCC初始化子函數(shù)里面,時鐘起振之后。
3、 閱讀lib:調(diào)試所有外設(shè)初始化的函數(shù)。
我的理解——不理解,也不需要理解。只要知道所有外設(shè)在調(diào)試的時候,EWRAM需要從這個函數(shù)里面獲得調(diào)試所需信息的地址或者指針之類的信息。
基礎(chǔ)應(yīng)用1,只有一個函數(shù)debug。所有程序中必須的。
用法: #ifdef DEBUG
debug();
#endif
位置:main函數(shù)開頭,聲明變量之后。
4、 閱讀nvic:系統(tǒng)中斷管理。
我的理解——管理系統(tǒng)內(nèi)部的中斷,負責(zé)打開和關(guān)閉中斷。
基礎(chǔ)應(yīng)用1,中斷的初始化函數(shù),包括設(shè)置中斷向量表位置,和開啟所需的中斷兩部分。所有程序中必須的。
用法: void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;//中斷管理恢復(fù)默認參數(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)先級分組,方式。
//注:一共16個優(yōu)先級,分為搶占式和響應(yīng)式。兩種優(yōu)先級所占的數(shù)量由此代碼確定,NVIC_PriorityGroup_x可以是0、1、2、3、4,分別代表搶占優(yōu)先級有1、2、4、8、16個和響應(yīng)優(yōu)先級有16、8、4、2、1個。規(guī)定兩種優(yōu)先級的數(shù)量后,所有的中斷級別必須在其中選擇,搶占級別高的會打斷其他中斷優(yōu)先執(zhí)行,而響應(yīng)級別高的會在其他中斷執(zhí)行完優(yōu)先執(zhí)行。
//NVIC_InitStructure.NVIC_IRQChannel = 中斷通道名;
//開中斷,中斷名稱見函數(shù)庫
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
//搶占優(yōu)先級
//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
//響應(yīng)優(yōu)先級
//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//啟動此通道的中斷
//NVIC_Init(&NVIC_InitStructure); //中斷初始化
}
5、 閱讀rcc:單片機時鐘管理。
我的理解——管理外部、內(nèi)部和外設(shè)的時鐘,設(shè)置、打開和關(guān)閉這些時鐘。
基礎(chǔ)應(yīng)用1:時鐘的初始化函數(shù)過程——
用法:void RCC_Configuration(void) //時鐘初始化函數(shù)
{
ErrorStatus HSEStartUpStatus; //等待時鐘的穩(wěn)定
RCC_DeInit(); //時鐘管理重置
RCC_HSEConfig(RCC_HSE_ON); //打開外部晶振
HSEStartUpStatus = RCC_WaitForHSEStartUp(); //等待外部晶振就緒
if (HSEStartUpStatus == SUCCESS)
{
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//flash讀取緩沖,加速
FLASH_SetLatency(FLASH_Latency_2); //flash操作的延時
RCC_HCLKConfig(RCC_SYSCLK_Div1); //AHB使用系統(tǒng)時鐘
RCC_PCLK2Config(RCC_HCLK_Div2); //APB2(高速)為HCLK的一半
RCC_PCLK1Config(RCC_HCLK_Div2); //APB1(低速)為HCLK的一半
//注:AHB主要負責(zé)外部存儲器時鐘。PB2負責(zé)AD,I/O,高級TIM,串口1。APB1負責(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); //啟動PLL
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}
//等待PLL啟動
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//將PLL設(shè)置為系統(tǒng)時鐘源
while (RCC_GetSYSCLKSource() != 0x08){}
//等待系統(tǒng)時鐘源的啟動
}
//RCC_AHBPeriphClockCmd(ABP2設(shè)備1 | ABP2設(shè)備2 |, ENABLE);
//啟動AHP設(shè)備
//RCC_APB2PeriphClockCmd(ABP2設(shè)備1 | ABP2設(shè)備2 |, ENABLE);
//啟動ABP2設(shè)備
//RCC_APB1PeriphClockCmd(ABP2設(shè)備1 | ABP2設(shè)備2 |, ENABLE);
//啟動ABP1設(shè)備
}
1、閱讀exti:外部設(shè)備中斷函數(shù)
我的理解——外部設(shè)備通過引腳給出的硬件中斷,也可以產(chǎn)生軟件中斷,19個上升、下降或都觸發(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ù)默認參數(shù)
EXTI_InitStructure.EXTI_Line = 通道1|通道2;
//設(shè)定所需產(chǎn)生外部中斷的通道,一共19個。
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //產(chǎn)生中斷
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
//上升下降沿都觸發(fā)
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //啟動中斷的接收
EXTI_Init(&EXTI_InitStructure); //外部設(shè)備中斷啟動
}
2、閱讀dma:通過總線而越過CPU讀取外設(shè)數(shù)據(jù)
我的理解——通過DMA應(yīng)用可以加速單片機外設(shè)、存儲器之間的數(shù)據(jù)傳輸,并在傳輸期間不影響CPU進行其他事情。這對于入門開發(fā)基本功能來說沒有太大必要,這個內(nèi)容先行跳過。
3、閱讀systic:系統(tǒng)定時器
我的理解——可以輸出和利用系統(tǒng)時鐘的計數(shù)、狀態(tài)。
基礎(chǔ)應(yīng)用1,精確計時的延時子函數(shù)。推薦使用的代碼。
用法:
static vu32 TimingDelay;//全局變量聲明
void SysTick_Config(void)//systick初始化函數(shù)
{
SysTick_CounterCmd(SysTick_Counter_Disable);//停止系統(tǒng)定時器
SysTick_ITConfig(DISABLE); //停止systick中斷
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//systick使用HCLK作為時鐘源,頻率值除以8。
SysTick_SetReload(9000);//重置時間1毫秒(以72MHz為基礎(chǔ)計算)
SysTick_ITConfig(ENABLE);//開啟systic中斷
}
void Delay (u32 nTime) //延遲一毫秒的函數(shù)
{
SysTick_CounterCmd(SysTick_Counter_Enable); //systic開始計時
TimingDelay = nTime; //計時長度賦值給遞減變量
while(TimingDelay != 0); //檢測是否計時完成
SysTick_CounterCmd(SysTick_Counter_Disable); //關(guān)閉計數(shù)器
SysTick_CounterCmd(SysTick_Counter_Clear); //清除計數(shù)值
}
void TimingDelay_Decrement(void)
//遞減變量函數(shù),函數(shù)名由“stm32f10x_it.c”中的中斷響應(yīng)函數(shù)定義好了。
{
if (TimingDelay != 0x00) //檢測計數(shù)變量是否達到0
{
TimingDelay--; //計數(shù)變量遞減
}
}
注:建議熟練后使用,所涉及知識和設(shè)備太多,新手出錯的可能性比較大。新手可用簡化的延時函數(shù)代替:
void Delay(vu32 nCount)//簡單延時函數(shù)
{
for(; nCount != 0; nCount--);(循環(huán)變量遞減計數(shù))
}
當(dāng)延時較長,又不需要精確計時的時候可以使用嵌套循環(huán):
void Delay(vu32 nCount) //簡單的長時間延時函數(shù)
{int i; //聲明內(nèi)部遞減變量
for(; nCount != 0; nCount--) //遞減變量計數(shù)
{for (i=0; i<0xffff; i++)} //內(nèi)部循環(huán)遞減變量計數(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ù)默認參數(shù)
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_標號 | GPIO_Pin_標號 ;
//管腳位置定義,標號可以是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屬性必須相同,默認的GPIO參數(shù)為:ALL,2MHz,F(xiàn)LATING。如果其中任意一行與前一組相應(yīng)設(shè)置相同,那么那一行可以省略,由此推論如果前面已經(jīng)將此行參數(shù)設(shè)定為默認參數(shù)(包括使用GPIO_InitTypeDef GPIO_InitStructure代碼),本組應(yīng)用也是默認參數(shù)的話,那么也可以省略。以下重復(fù)這個過程直到所有應(yīng)用的管腳全部被定義完畢。
……
}
基礎(chǔ)應(yīng)用2,向管腳寫入0或1
用法:GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1
STM32筆記之七:讓它跑起來,基本硬件功能的建立
0、 實驗之前的準備
a) 接通串口轉(zhuǎn)接器
b) 下載IO與串口的原廠程序,編譯通過保證調(diào)試所需硬件正常。
1、 flash,lib,nvic,rcc和GPIO,基礎(chǔ)程序庫編寫
a) 這幾個庫函數(shù)中有一些函數(shù)是關(guān)于芯片的初始化的,每個程序中必用。為保障程序品質(zhì),初學(xué)階段要求嚴格遵守官方習(xí)慣。注意,官方程序庫例程中有個platform_config.h文件,是專門用來指定同類外設(shè)中第幾號外設(shè)被使用,就是說在main.c里面所有外設(shè)序號用x代替,比如USARTx,程序會到這個頭文件中去查找到底是用那些外設(shè),初學(xué)的時候參考例程別被這個所迷惑住。
b) 全部必用代碼取自庫函數(shù)所帶例程,并增加逐句注釋。
c) 習(xí)慣順序——Lib(debug),RCC(包括Flash優(yōu)化),NVIC,GPIO
d) 必用模塊初始化函數(shù)的定義:
void RCC_Configuration(void); //定義時鐘初始化函數(shù)
void GPIO_Configuration(void); //定義管腳初始化函數(shù)
void NVIC_Configuration(void); //定義中斷管理初始化函數(shù)
void Delay(vu32 nCount); //定義延遲函數(shù)
e) Main中的初始化函數(shù)調(diào)用:
RCC_Configuration(); //時鐘初始化函數(shù)調(diào)用
NVIC_Configuration(); //中斷初始化函數(shù)調(diào)用
GPIO_Configuration(); //管腳初始化函數(shù)調(diào)用
f) Lib注意事項:
屬于Lib的Debug函數(shù)的調(diào)用,應(yīng)該放在main函數(shù)最開始,不要改變其位置。
g) RCC注意事項:
Flash優(yōu)化處理可以不做,但是兩句也不難也不用改參數(shù)……
根據(jù)需要開啟設(shè)備時鐘可以節(jié)省電能
時鐘頻率需要根據(jù)實際情況設(shè)置參數(shù)
h) NVIC注意事項
注意理解占先優(yōu)先級和響應(yīng)優(yōu)先級的分組的概念
i) GPIO注意事項
注意以后的過程中收集不同管腳應(yīng)用對應(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ù)
{for(; nCount != 0; nCount--);}
實驗步驟:
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 ;//管腳號
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ù)
{ for (; nCount != 0; nCount--);} //循環(huán)計數(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閃爍了,單片機就跑起來了。
STM32筆記之八:來跟PC打個招呼,基本串口通訊
a) 目的:在基礎(chǔ)實驗成功的基礎(chǔ)上,對串口的調(diào)試方法進行實踐。硬件代碼順利完成之后,對日后調(diào)試需要用到的printf重定義進行調(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ù)默認參數(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; //無奇偶校驗
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); //啟動串口
}
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)); //接受一個字節(jié)
發(fā)送一個字符串
先定義字符串: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注意事項:
發(fā)動和接受都需要配合標志等待。
只能對一個字節(jié)操作,對字符串等大量數(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標準函數(shù):
#include "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) 通過,試驗成功。printf使用變量輸出:%c字符,%d整數(shù),%f浮點數(shù),%s字符串,/n或/r為換行。注意:只能用于main.c中。
3、 NVIC串口中斷的應(yīng)用
a) 目的:利用前面調(diào)通的硬件基礎(chǔ),和幾個函數(shù)的代碼,進行串口的中斷輸入練習(xí)。因為在實際應(yīng)用中,不使用中斷進行的輸入是效率非常低的,這種用法很少見,大部分串口的輸入都離不開中斷。
b) 初始化函數(shù)定義及函數(shù)調(diào)用:不用添加和調(diào)用初始化函數(shù),在指定調(diào)試地址的時候已經(jīng)調(diào)用過,在那個NVIC_Configuration里面添加相應(yīng)開中斷代碼就行了。
c) 過程:
i. 在串口初始化中USART_Cmd之前加入中斷設(shè)置:
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE發(fā)送中斷,TC傳輸完成中斷,RXNE接收中斷,PE奇偶錯誤中斷,可以是多個。
ii. RCC、GPIO里面打開串口相應(yīng)的基本時鐘、管腳設(shè)置
iii. NVIC里面加入串口中斷打開代碼:
NVIC_InitTypeDef NVIC_InitStructure;//中斷默認參數(shù)
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道設(shè)置為串口1中斷
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中斷占先等級0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //中斷響應(yīng)優(yōu)先級0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //打開中斷
NVIC_Init(&NVIC_InitStructure); //初始化
iv. 在stm32f10x_it.c文件中找到void USART1_IRQHandler函數(shù),在其中添入執(zhí)行代碼。一般最少三個步驟:先使用if語句判斷是發(fā)生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。
void USART1_IRQHandler(void) //串口1中斷
{
char RX_dat; //定義字符變量
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //判斷發(fā)生接收中斷
{USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除中斷標志
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) 中斷注意事項:
可以隨時在程序中使用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) 目的:跟串口輸入類似,不使用中斷進行的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);//清除中斷標志
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;//啟動中斷
EXTI_Init(&EXTI_InitStructure);//初始化
}
e) RCC初始化函數(shù)中開啟I/O時鐘
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;//占先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動
NVIC_Init(&NVIC_InitStructure); //初始化
g) 在stm32f10x_it.c文件中找到void USART1_IRQHandler函數(shù),在其中添入執(zhí)行代碼。一般最少三個步驟:先使用if語句判斷是發(fā)生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。
if(EXTI_GetITStatus(EXTI_Line3) != RESET) //判斷中斷發(fā)生來源
{ EXTI_ClearITPendingBit(EXTI_Line3); //清除中斷標志
USART_SendData(USART1, 0x41); //發(fā)送字符“a”
GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED發(fā)生明暗交替
}
h) 中斷注意事項:
中斷發(fā)生后必須清除中斷位,否則會出現(xiàn)死循環(huán)不斷發(fā)生這個中斷。然后需要對中斷類型進行判斷再執(zhí)行代碼。
使用EXTI的I/O中斷,在完成RCC與GPIO硬件設(shè)置之后需要做三件事:初始化EXTI、NVIC開中斷、編寫中斷執(zhí)行代碼。
STM32筆記之十:工作工作,PWM輸出
a) 目的:基礎(chǔ)PWM輸出,以及中斷配合應(yīng)用。輸出選用PB1,配置為TIM3_CH4,是目標板的LED6控制腳。
b) 對于簡單的PWM輸出應(yīng)用,暫時無需考慮TIM1的高級功能之區(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;//定時器初始化結(jié)構(gòu)
TIM_OCInitTypeDef TIM_OCInitStructure;//通道輸出初始化結(jié)構(gòu)
//TIM3初始化
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFF
TIM_TimeBaseStructure.TIM_Prescaler = 5; //時鐘分頻
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時鐘分割
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //基本初始化
TIM_ITConfig(TIM3, TIM_IT_CC4, ENABLE);//打開中斷,中斷需要這行代碼
//TIM3通道初始化
TIM_OCStructInit(& TIM_OCInitStructure); //默認參數(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); //啟動TIM3
}
f) RCC初始化函數(shù)中加入TIM時鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g) GPIO里面將輸入和輸出管腳模式進行設(shè)置。信號:AF_PP,50MHz。
h) 使用中斷的話在NVIC里添加如下代碼:
//打開TIM2中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel; //通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //響應(yīng)級
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動
NVIC_Init(&NVIC_InitStructure); //初始化
中斷代碼:
void TIM2_IRQHandler(void)
{
if (TIM_GetITStatus(TIM2, TIM_IT_CC4) != RESET) //判斷中斷來源
{
TIM_ClearITPendingBit(TIM2, TIM_IT_CC4); //清除中斷標志
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) 注意事項:
管腳的IO輸出模式是根據(jù)應(yīng)用來定,比如如果用PWM輸出驅(qū)動LED則應(yīng)該將相應(yīng)管腳設(shè)為AF_PP,否則單片機沒有輸出。
STM32筆記之十一:捕捉精彩瞬間,脈沖方波長度捕獲
a) 目的:基礎(chǔ)PWM輸入也叫捕獲,以及中斷配合應(yīng)用。使用前一章的輸出管腳PB1(19腳),直接使用跳線連接輸入的PA3(13腳),配置為TIM2_CH4,進行實驗。
b) 對于簡單的PWM輸入應(yīng)用,暫時無需考慮TIM1的高級功能之區(qū)別,按照目前我的應(yīng)用目標其實只需要采集高電平寬度,而不必知道周期,所以并不采用PWM輸入模式,而是普通脈寬捕獲模式。
c) 初始化函數(shù)定義:
void TIM_Configuration(void); //定義TIM初始化函數(shù)
d) 初始化函數(shù)調(diào)用:
TIM_Configuration(); //TIM初始化函數(shù)調(diào)用
e) 初始化函數(shù),不同于前面模塊,TIM的CAP初始化分為三部分——計時器基本初始化、通道初始化和時鐘啟動初始化:
void TIM_Configuration(void)//TIM2的CAP初始化函數(shù)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//定時器初始化結(jié)構(gòu)
TIM_ICInitTypeDef TIM_ICInitStructure; //通道輸入初始化結(jié)構(gòu)
//TIM2輸出初始化
TIM_TimeBaseStructure.TIM_Period = 0xFFFF; //周期0~FFFF
TIM_TimeBaseStructure.TIM_Prescaler = 5; //時鐘分頻
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //時鐘分割
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;//管腳與寄存器對應(yīng)關(guān)系
TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分頻器
TIM_ICInitStructure.TIM_ICFilter = 0x4; //濾波設(shè)置,經(jīng)歷幾個周期跳變認定波形穩(wěn)定0x0~0xF
TIM_ICInit(TIM2, &TIM_ICInitStructure); //初始化
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); //選擇時鐘觸發(fā)源
TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);//觸發(fā)方式
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable); //啟動定時器的被動觸發(fā)
TIM_ITConfig(TIM2, TIM_IT_CC4, ENABLE); //打開中斷
TIM_Cmd(TIM2, ENABLE); //啟動TIM2
}
f) RCC初始化函數(shù)中加入TIM時鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g) GPIO里面將輸入和輸出管腳模式進行設(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) 注意事項:
i. 由于我的需求只跟高電平寬度有關(guān),所以避免了使用PWM輸入模式,這樣可以每個管腳捕捉一路信號。如果使用PWM模式,每一路需要占用兩個寄存器,所以一個定時器只能同時使用兩路PWM輸入。
ii. 由于捕捉需要觸發(fā)啟動定時器,所以PWM輸出與捕捉不容易在同一個TIM通道上實現(xiàn)。如果必須的話只能增加計數(shù)溢出的相關(guān)代碼。
iii. 有些程序省略了捕捉通道的初始化代碼,這是不對的
iv. 在基本計時器初始化代碼里面注意選擇適當(dāng)?shù)挠嫈?shù)器長度,最好讓波形長度不要長于一個計數(shù)周期,否則需要增加溢出代碼很麻煩。一個計數(shù)周期的長度計算跟如下幾個參數(shù)有關(guān):
(1) RCC初始化代碼里面的RCC_PCLKxConfig,這是TIM的基礎(chǔ)時鐘源與系統(tǒng)時鐘的關(guān)系。
(2) TIM初始化的TIM_Period,這是計數(shù)周期的值
(3) TIM初始化的TIM_Prescaler,這是計數(shù)周期的倍頻計數(shù)器,相當(dāng)于調(diào)節(jié)計數(shù)周期,可以使TIM_Period盡量大,提高計數(shù)精度。
STM32筆記之十二:時鐘不息工作不止,systic時鐘應(yīng)用
a) 目的:使用系統(tǒng)時鐘來進行兩項實驗——周期執(zhí)行代碼與精確定時延遲。
b) 初始化函數(shù)定義:
void SysTick_Configuration(void);
c) 初始化函數(shù)調(diào)用:
SysTick_Configuration();
d) 初始化函數(shù):
void SysTick_Configuration(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//時鐘除8
SysTick_SetReload(250000); //計數(shù)周期長度
SysTick_CounterCmd(SysTick_Counter_Enable); //啟動計時器
SysTick_ITConfig(ENABLE); //打開中斷
}
e) 在NVIC的初始化函數(shù)里面增加以下代碼打開相關(guān)中斷:
NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中斷等級設(shè)置,一般設(shè)置的高一些會少受其他影響
f) 在stm32f10x_it.c文件中找到void SysTickHandler 函數(shù)
void SysTickHandler(void)
{
執(zhí)行代碼
}
g) 簡單應(yīng)用:精確延遲函數(shù),因為systic中斷往往被用來執(zhí)行周期循環(huán)代碼,所以一些例程中使用其中斷的啟動和禁止來編寫的精確延時函數(shù)實際上不實用,我自己編寫了精確計時函數(shù)反而代碼更精簡,思路更簡單。思路是調(diào)用后,變量清零,然后使用時鐘來的曾變量,不斷比較變量與延遲的數(shù)值,相等則退出函數(shù)。代碼和步驟如下:
i. 定義通用變量:u16 Tic_Val=0; //變量用于精確計時
ii. 在stm32f10x_it.c文件中相應(yīng)定義:
extern u16 Tic_Val;//在本文件引用MAIN.c定義的精確計時變量
iii. 定義函數(shù)名稱:void Tic_Delay(u16 Tic_Count);//精確延遲函數(shù)
iv. 精確延時函數(shù):
void Tic_Delay(u16 Tic_Count) //精確延時函數(shù)
{ Tic_Val=0; //變量清零
while(Tic_Val != Tic_Count){printf("");}//計時
}
v. 在stm32f10x_it.c文件中void SysTickHandler 函數(shù)里面添加
Tic_Val++;//變量遞增
vi. 調(diào)用代碼:Tic_Delay(10); //精確延時
vii. 疑問:如果去掉計時行那個沒用的printf("");函數(shù)將停止工作,這個現(xiàn)象很奇怪
STM32筆記之十三:惡搞,兩只看門狗
a) 目的:
了解兩種看門狗(我叫它:系統(tǒng)運行故障探測器和獨立系統(tǒng)故障探測器,新手往往被這個并不形象的象形名稱搞糊涂)之間的區(qū)別和基本用法。
b) 相同:
都是用來探測系統(tǒng)故障,通過編寫代碼定時發(fā)送故障清零信號(高手們都管這個代碼叫做“喂狗”),告訴它系統(tǒng)運行正常。一旦系統(tǒng)故障,程序清零代碼(“喂狗”)無法執(zhí)行,其計數(shù)器就會計數(shù)不止,直到記到零并發(fā)生故障中斷(狗餓了開始叫喚),控制CPU重啟整個系統(tǒng)(不行啦,開始咬人了,快跑……)。
c) 區(qū)別:
獨立看門狗Iwdg——我的理解是獨立于系統(tǒng)之外,因為有獨立時鐘,所以不受系統(tǒng)影響的系統(tǒng)故障探測器。(這條狗是借來的,見誰偷懶它都咬。┲饕糜诒O(jiān)視硬件錯誤。
窗口看門狗wwdg——我的理解是系統(tǒng)內(nèi)部的故障探測器,時鐘與系統(tǒng)相同。如果系統(tǒng)時鐘不走了,這個狗也就失去作用了。(這條狗是老板娘養(yǎng)的,老板不干活兒他不管。┲饕糜诒O(jiān)視軟件錯誤。
d) 初始化函數(shù)定義:鑒于兩只狗作用差不多,使用過程也差不多初始化函數(shù)栓一起了,用的時候根據(jù)情況刪減。
void WDG_Configuration(void);
e) 初始化函數(shù)調(diào)用:
WDG_Configuration();
f) 初始化函數(shù)
void WDG_Configuration() //看門狗初始化
{
//軟件看門狗初始化
WWDG_SetPrescaler(WWDG_Prescaler_8); //時鐘8分頻4ms
// (PCLK1/4096)/8= 244 Hz (~4 ms)
WWDG_SetWindowValue(65); //計數(shù)器數(shù)值
WWDG_Enable(127); //啟動計數(shù)器,設(shè)置喂狗時間
// WWDG timeout = ~4 ms * 64 = 262 ms
WWDG_ClearFlag(); //清除標志位
WWDG_EnableIT(); //啟動中斷
//獨立看門狗初始化
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);//啟動寄存器讀寫
IWDG_SetPrescaler(IWDG_Prescaler_32);//40K時鐘32分頻
IWDG_SetReload(349); //計數(shù)器數(shù)值
IWDG_ReloadCounter(); //重啟計數(shù)器
IWDG_Enable(); //啟動看門狗
}
g) RCC初始化:只有軟件看門狗需要時鐘初始化,獨立看門狗有自己的時鐘不需要但是需要systic工作相關(guān)設(shè)置。
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG, ENABLE);
h) 獨立看門狗使用systic的中斷來喂狗,所以添加systic的中斷打開代碼就行了。軟件看門狗需要在NVIC打開中斷添加如下代碼:
NVIC_InitStructure.NVIC_IRQChannel = WWDG_IRQChannel; //通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //占先中斷等級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應(yīng)中斷優(yōu)先級
NVIC_Init(&NVIC_InitStructure); //打開中斷
i) 中斷程序,軟件看門狗在自己的中斷中喂狗,獨立看門狗需要使用systic的定時中斷來喂狗。以下兩個程序都在stm32f10x_it.c文件中。
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(0x7F); //更新計數(shù)值
WWDG_ClearFlag(); //清除標志位
}
void SysTickHandler(void)
{ IWDG_ReloadCounter(); //重啟計數(shù)器(喂狗)
}
j) 注意事項:
i. 有狗平常沒事情可以不理,但是千萬別忘了喂它,否則死都不知道怎么死的!
ii. 初始化程序的調(diào)用一定要在systic的初始化之后。
iii. 獨立看門狗需要systic中斷來喂,但是systic做別的用處不能只做這件事,所以我寫了如下幾句代碼,可以不影響systic的其他應(yīng)用,其他systic周期代碼也可參考:
第一步:在stm32f10x_it.c中定義變量
int Tic_IWDG; //喂狗循環(huán)程序的頻率判斷變量
第二步:將SysTickHandler中喂狗代碼改為下面:
Tic_IWDG++; //變量遞增
if(Tic_IWDG>=100) //每100個systic周期喂狗
{ IWDG_ReloadCounter();//重啟計數(shù)器(喂狗)
Tic_IWDG=0; //變量清零
}
STM32筆記之十四:基本問題,來討論一下軟件架構(gòu)
網(wǎng)上大家都在討論和學(xué)習(xí),但是對于架構(gòu)這個基本問題卻沒幾個人討論。個人認為有個好的架構(gòu)是寫好代碼的基礎(chǔ),可以使后期的調(diào)式工作事半功倍!
1、 架構(gòu)組成:我的程序代碼分為四種結(jié)構(gòu)
a) 順序執(zhí)行代碼
定義:按照順序逐行執(zhí)行的代碼
優(yōu)點:是思路簡單,代碼可靠不易被干擾。
缺點:占用資源
用途:只用來各種變量、函數(shù)的定義,硬件的初始化程序
位置:main.c的開始一直到main函數(shù)的while函數(shù)之前
b) 空閑執(zhí)行代碼
定義:在CPU空閑的時候才執(zhí)行的代碼
優(yōu)點:不占用資源
缺點:執(zhí)行的實時性不能保證
用途:非實時任務(wù),調(diào)試信息輸出,不重要的狀態(tài)指示
位置:main.c的main函數(shù)的while函數(shù)內(nèi)部
c) 中斷執(zhí)行代碼
定義:由軟硬件事件打斷整個程序而執(zhí)行的代碼
優(yōu)點:可以保證實時性,各種中斷可以安排優(yōu)先順序
缺點:關(guān)系相對復(fù)雜,互相之間容易干擾
用途:觸發(fā)性的代碼,比如接收數(shù)據(jù),響應(yīng)外部設(shè)備,按鈕的相應(yīng)
位置:stm32f10x_it.c內(nèi)部
d) 循環(huán)執(zhí)行代碼
定義:按照時間周期執(zhí)行的代碼
優(yōu)點:定期自動執(zhí)行
缺點:實時性不好
用途:需要周期執(zhí)行的任務(wù),狀態(tài)檢查及相關(guān)信息輸出,數(shù)據(jù)記錄
位置:stm32f10x_it.c的SysTickHandler內(nèi)部
e) DMA自動代碼
定義:不需要主程序干預(yù),外設(shè)自動執(zhí)行
優(yōu)點:自動刷新數(shù)據(jù),不占用CPU資源
缺點:不能控制
用途:數(shù)據(jù)通信存儲,AD轉(zhuǎn)換
位置:不需要
2、架構(gòu)執(zhí)行順序圖
下載 (51.33 KB)
2009-4-22 15:39
STM32學(xué)習(xí)筆記之十五——IAR4的最后瘋狂,笨笨的開發(fā)模板下載
準備大換血了,包括開發(fā)環(huán)境升級和固件升級,那個需要一定過程,吧之前完成的模板跟大家共享一下。
我的程序庫特點:
a) 默認兼容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è)時鐘模板),gpio(管腳定義模板)的初始化代碼,所有模板代碼用到的
時候只要去掉前面的注釋"//",根據(jù)需求填入相應(yīng)值就可以了。
e) 因為自己記性不好,所以main函數(shù)中的代碼做到每行注釋,便于自己以后使用。
f) 列出常見應(yīng)用代碼模板與ASCII常用列表。
g) 集成putchar字符輸出和Printf的重定義到串口的代碼,便于調(diào)試。
h) 集成NVIC中斷管理模板,EXTI外部I/O中斷模板
i) 針對自己情況集成PWM輸出模板和CAP脈寬捕捉模板,并全部注釋。
j) 集成系統(tǒng)循環(huán)時鐘的初始化函數(shù)模板
k) 集成自己編寫精確延時代碼,不會影響systic的周期代碼的執(zhí)行。
l) 集成兩種看門狗的使用代碼,小心使用
M) 集成hex生成設(shè)置命令,位置在編譯目錄(STM32F103C8)的Exe下,集成ISP軟件便
于脫離仿真器的串口調(diào)試STMISP.exe。
由于注釋寫的太多,還加入自己編程以來的許多格式習(xí)慣,所以許多人會覺得混亂不堪,在
此聲明,此程序庫僅僅為個人學(xué)習(xí)之用!
STM32學(xué)習(xí)筆記之十六——題外話,自己做塊工程板
一、我的學(xué)習(xí)計劃將STM32單片機的硬件設(shè)計工作:
第一步——用STM32F103CBT6的48腳芯片,為光電平臺的簡單控制為目標,實現(xiàn)基本外圍硬件、PWM、串口、I/O。將SPI、I2C留插針。
第二步——為集成傳感器應(yīng)用為目標,在第一步硬件基礎(chǔ)上制作功能性的套版,兩板連接實現(xiàn)AD、SPI、I2C、RTC等等功能。
二、硬件規(guī)劃
選用STM32F103CBT6,面積7×7mm,128K flash,16K RAM,4個16bit PWM,12個12bit PWM或CAP,2個SPI,2個I2C,3個串口,1個CAN,1個USB,),12ADC。
管腳分配目標1如圖,之后的功能包括:4個AD,3個串口(1個與I2C復(fù)用),1個SPI,8個(兩組)PWM輸入輸出,1個USB,1個I/O,1個MCO。
三、管腳分配:
下載 (32.83 KB)
2009-4-26 16:14
四、ALTIUM DESIGNER 6(Protel的第六個版本)操作筆記
之所以選擇這個軟件三個理由:1、界面習(xí)慣兼容Protel。2、操作習(xí)慣于Windows類似方便。3、可輸出igs用于結(jié)構(gòu)設(shè)計。
軟件使用筆記如下:
a) 流程:新建工程,添加原理圖,添加SCH庫,畫原理圖,添加PCB庫,設(shè)定封裝,添加PCB,布線,檢查,導(dǎo)出生產(chǎn)文件。
b) 新建工程:最好使用自己以前的同版本文檔設(shè)置,會包含各種庫省去大量工作
c) 添加器件到SCH,可使用復(fù)制粘貼的辦法,注意管腳,有些需要外殼接地的器件把外殼的焊點畫出來。完成后點擊放置,改動后再器件名稱點擊右鍵更改。
d) 畫原理圖:操作類似其他windows軟件,會自動檢查錯誤連接和重復(fù)硬件。
e) 添加器件到PCB庫,最好使用拷貝粘貼的辦法,最好有官方的焊點圖。沒有的話可以按照封裝的型號直接去http://www.***search.com/搜索封裝型號(不是器件型號),也有封裝的相關(guān)尺寸和焊點圖。
f) 雙擊原理圖的器件,在右下角改封裝名稱。
g) 添加新的PCB到工程:
“設(shè)計/規(guī)則”改線寬、線距、器件距離……;
“設(shè)計/板子形狀/重新定義板子形狀”改工作區(qū)域大小,然后左鍵點擊前置Keepout層,畫電路板外形;
“設(shè)計/板參數(shù)選項”改網(wǎng)格大小,器件和走線中鼠標捕捉的間隔大小……;
“設(shè)計/Import changes From……”引入原理圖的器件和連接方式,包括改動(出現(xiàn)對match提示選擇繼續(xù)就可以了);
“查看/切換單位”改公制和英制;
“工具/取消布線”取消已經(jīng)布好的線;
“自動布線”計算機自動布線,功能比Protel增強不少;
“報告/測量距離”測量實際距離;
在層標簽單擊,前置這個層。右鍵有隱藏層和顯示層比較常用。
屏幕中點擊右鍵菜單中“設(shè)計/規(guī)則”、“選項/板參數(shù)選項”、 “選項/層疊管理”(添加和刪除層)、“選項/顯示掩藏”(針對各種類型進行顯示和隱藏,查找未布的線就使用此功能后在操作框中點擊“所有最終”然后點擊“Apply”,再手工點擊所有的選項為“隱藏的”再點“Apply”就能看到未布線的連線了)
快捷鍵:空格鍵旋轉(zhuǎn)器件,TAB鍵切換線寬和放置過孔。左鍵單擊選擇,左鍵按住移動器件(多個重疊會有列表選擇,未松開時右鍵取消操作),左鍵雙擊改器件屬性(所在層、位置……),右鍵按住移動鼠標平移視野,滾輪上下移動,滾輪按住移動鼠標放大縮小
五、基本電路原理設(shè)計
拋棄復(fù)雜設(shè)計,專注于可獨立調(diào)式的CPU板設(shè)計。計劃設(shè)計模塊包括:供電、JTAG、晶振、RTC(電池引出)。
注:未使用標準JTAG設(shè)計,原因有三:
1、原設(shè)計太占管腳,這個尺寸實在難實現(xiàn)
2、這只是CPU板具體應(yīng)用會再做功能套版,上面可以連接標準JTAG
3、有可能向USB燒寫和SW雙線調(diào)式方向轉(zhuǎn)變,所以以后不一定會使用標準JTAG
|
|