久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 5532|回復: 1
打印 上一主題 下一主題
收起左側

深入淺出STM32系列ARM_Cortex-M3(共87頁pdf下載)

[復制鏈接]
跳轉到指定樓層
樓主
ID:412306 發表于 2018-10-19 15:46 | 只看該作者 回帖獎勵 |倒序瀏覽 |閱讀模式
一份比較通俗易懂的學習資料
深入淺出    STM32系列
--ARM    Cortex-M3
學習共享電子書 整理: 劉君華(石家莊)

STM32學前班教程之一:為什么是它
經過幾天的學習,基本掌握了 STM32的調試環境和一些基本知識。想拿出來與大家共享,笨教程本著最大限度簡化刪減 STM32入門的過程的思想,會把我的整個入門前的工作推薦給大家。就算是給網上的眾多教程、筆記的一種補充吧,所 以叫學前班教程。其中涉及產品一律隱去來源和品牌,以防廣告之嫌。全部漢字內容為個人筆記。所有相關參考資料也 全部列出。:lol
教程會分幾篇,因為太長啦。今天先來說說為什么是它——我選擇 STM32的原因。 我對未來的規劃是以功能性為主的,在功能和面積之間做以平衡是我的首要選擇,而把運算放在第二位,這根我的專業
有關系。里面的運算其實并不復雜,在入門階段想盡量減少所接觸的東西。
不過說實話,對 DSP 的外設并和開發環境不滿意,這是為什么 STM32一出就轉向的原因。下面是我自己做過的兩塊 DSP28 的全功能最小系統板,在做這兩塊板子的過程中發現要想盡力縮小 DSP 的面積實在不容易(目前只能達到50mm×45mm, 這還是沒有其他器件的情況下),尤其是雙電源的供電方式和1.9V 的電源讓人很頭疼。
后來因為一個項目,接觸了 LPC2148并做了一塊板子,發現小型的 ARM7在外設夠用的情況下其實很不錯,于是開始搜 集相關芯片資料,也同時對小面積的 AVR 和51都進行了大致的比較,這個時候發現了 CortexM3的 STM32,比2148擁有 更豐富和靈活的外設,性能幾乎是2148兩倍(按照 MIPS 值計算)。正好2148我還沒上手,就直接轉了這款 STM32F103。
與2811相比較(核心1.8V 供電情況下),135MHz×1MIPS。現在用 STM32F103,72MHz×1.25MIPS,性能是 DSP 的66%, STM32F103R 型(64管腳)芯片面積只有2811的51%,STM32F103C 型(48管腳)面積是2811的25%,最大功耗是  DSP 的20%,單片價格是 DSP 的30%。且有更多的串口,CAP 和 PWM,這是有用的。高端型號有 SDIO,理論上比 SPI 速度 快。
由以上比較,準備將未來的擁有操作系統的高端應用交給 DSP 的新型浮點型單片機28335,而將所有緊湊型小型、 微型應用交給 STM32。
的 STM32學前班教程:怎么開發
sw 笨笨的 STM32學前班教程之二:怎么開發目前手頭的入門階段使用的開發器概述 該產品為簡易 STM32調試器和 DEMO 板一體化的調試學習設備,價格在一百多塊。
2、硬件配置
仿真部分:USB 口,reset,指示燈,JTAG
DEMO 部分:4按鍵(IO),4LED(IO),一個串口,啟動方式跳線,所有引腳的焊盤(可自行焊接插針進行擴展)
DEMO 芯片:STM32F103C8T6(程序空間64K) 參數和擴展:
注:學習的目標芯片是 STM32F103CBT6(7×7mm,128K flash,16K RAM)以及 STM32F103RET6(10×10mm,512K flash,
64K RAM)。
STM32-SK 的硬件連接方法(用板載調試器調試板載 DEMO):
JP3、JP5  須全部短接
USB 通過電纜連接至 PC 的 USB
串口連接至 PC 的串口或者通過 USB 轉串口電纜連接(力特 Z-TEC,USB2.0與 RS232轉接電纜)
WindowsXP 自動安裝驅動
安裝完成后如果 DEMO 板里面有程序就會自動運行了。這是 ST-Link-II 的通用連接方法 以上是學習階段比較方便的仿真器,進入工程階段后準備換 J-Link V7的仿真器進行開發。目前比較滿意的產品:JLink
v7+USB 轉串口:
購買后所需的改造:打開殼體,將 USB 的+5V 供電跟 JTAG20針的第二腳 Vsupply 飛線,提供目標板5V500mA 的供電。 看中的特點:集成串口,擁有20針 JTAG 可以改造 Vspply 為供電接口,小巧好帶,便宜。
常見的用于 STM32單片機的仿真器分類
a) Ulink2:之前常用的仿真器。Keil 公司產品,之前專用于 ARM7,現擴展到 CortexM3,調試接口支持 JTAG 和 SWD, 連接到 PC 主機的 USB。現在這種調試器已經用的越來越少了。
b) ST-Link-II:ST 公司的仿真接口,支持 IAR EWARM,USB 1.1全速,USB 電源供電,自適應目標系統  JTAG 電平3.3V-5V, 可向目標系統提供不大于5V/200mA 電源。這種調試器不多見,但是許多調試器與目標板一體設計的學習板上常見。
c) J-Link V6/V7:SEGGER 公司產品,調試接口支持 JTAG 和 SWV(V7速度是 V6的12倍),USB 2.0接口,通過 USB 供 電,下載速度達到720k byte/s, 與 IAR WEARM 無縫集成,寬目標板電壓范圍:1.2V-3.3V(V7支持5V),多核調試,給 目標板提供3.3V50mA 電源。這種調試器現在出現的越來越多,兼容性比較好(主要是指能夠與  IAR WEARM 無縫集成 這點),國內山寨貨和各種變種也很多。
6、目標板主要分為一體化設計(與調試器、供電整合)和單獨設計兩類,詳細產品比較見豆皮的《如何選擇 STM32開 發板》。

STM32學前班教程之三:讓 PC 工作

開發軟件的選擇
1、 軟件與版本的選擇
需求:支持 STLink2或未來的 Jlink V7調試接口(因為 STM32-SK 使用這個接口),能夠找到去除軟件限制的方法,最好 具有中文版幫助和界面,最好帶有純軟件仿真
選擇:RealView MDK 3.23RPC 或者 IAR EWARM 4.42A(5版本觀望一下)。
2、 RealView MDK 3.23RPC(中國版)安裝與去除限制 第一步:執行安裝程序完成基本安裝,最后選項選擇加入虛擬硬件,便于純軟件調試。
第二步:執行軟件,點擊 File-->Licence Manager,復制 CID 的數據到破解器的 CID,其他選項如下圖,然后點擊 Generate。
第三步:復制 LIC0的數據到軟件的 LIC 框里面,點擊 Add LIC。注意添加序列號后 Licence Manager 會算出這個號對應 的有效期,如果到期會顯示為紅色,需要重新點擊破解軟件的 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 設置的 Debug 選項中選擇 ST LINKII Debugger,同時在 Utilities 的選項中選擇 ST LINKII Debugger。
完成以上步驟,就完成了 ST-LINKII 的相關配置,可以作為調試器開始使用。注意:目前 ST-LINKII 不支持 Flash 菜單中 的 Download 和 Erase 命令,程序在使用 Start/Stop Debug Session 時自動載入 flash 中供調試。
3、 IAR EWARM 4.42A 安裝與破解
第一步:開始/運行…/CMD 顯示 DOS 界面,執行 iarid.exe>>ID.TXT 得到本機 ID 碼,復制這個 ID 碼,再執行 iarkg.exe ID
碼>>Lic422A.TXT,得到一組注冊碼。
第二步:使用 EWARM-EV-WEB-442A.exe(30天限制版,其他版本無法使用第一步中的注冊碼 ),執行安裝程序完成基 本安裝,過程中需要添入第一步里面算出來的注冊碼,可以取消時間限制,但是那一組當中只有一個有效,需要實驗。
4、 鏈接硬件調試程序

RealView MDK:找到一個 STM32-SK 的基礎程序,最好是只關于 IO 的且與當前板子程序不同,這樣在板上就可以看到 結果,點擊 Project/open project。例如 GPIO、TIMER(另兩個例程是關于串口的,需要連接串口才能夠看到運行結果)。
使用“Open Project”打開,然后設置 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。使用調試欄里面的“go”等等運行程序。 注:由于目前版本 MDK 與我手頭的 ST-LINK-II 編程器不兼容,所以后面的所有工作均改用 IAR。

STM32學前班教程之四:打好基礎建立模板
1、 新建目錄 Project_IAR4,按照自己的順序重新組織 dll(驅動);inc、src 函數庫;settings,其他所有文件全部放這個 新建的目錄下。
2、 雙擊打開 Project.eww,繼續更改內部設置。
3、 需更改的內容列表: 位置和項目 目標 說明
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 里面調試程序,VECT_TAB_RAM 是在
RAM 里調試程序
Project\Option\ C/C++ Compiler\Optimizations\Size  最終編譯一般選擇 High

調試可選 None None,Low,Medium,High 是不同的代碼優化等級
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 調試程序,如果需要使用 RAM 調試則改為 lnkarm_RAM.xcl
Project\Option\ Debugger\Setup\Driver    Third-Party Driver  使用第三方驅動連接單片機
Project\Option\ Debugger\ Download Use flash loader  下載到 flash 所需的設置
Project\Option\ Debugger\ Third-Party Driver\ Third-Party Driver\IAR debugger driver $PROJ_DIR$\ddl\STM32Driver.dll  驅動 文件路徑
注1:所有跟路徑相關的設置需要根據實際情況編寫,相對路徑的編寫——“$PROJ_DIR$”代表 eww 文件所在文件夾,“..”
代表向上一層。 注2:其他設置使用庫函數里面的工程文件的默認選項即可,初學不用了解太多。
4、 需要重新刪除并重新添加 Project 下“FWLib”和“User”的所有文件,為了刪減外設模塊方便需要在“USER”額外添加
“stm32f10x_conf.h”(不添加也可以,需要展開 main.c 找到它)。然后執行 Project\Rebuid All,通過則設置完畢。
5、 完成以上步驟,第一個自己習慣的程序庫就建立完畢了,以后可以從 “stm32f10x_conf.h”中刪減各種庫文件,從 “stm32f10x_it.c”編輯中斷,從“main.c”編寫得到自己的程序。最后需要將這個庫打包封存,每次解壓縮并修改主目錄名稱 即可。
6、 我的程序庫特點:
a)  默認兼容 ST-LINK-II,IAR EWARM 4.42A,Flash 調試,其他有可能需要更改設置
b) 為操作方便減少了目錄的層次
c) 為學習方便使用網友漢化版2.0.2固件,主要是庫函數中 c 代碼的注釋。 后面隨著學習深入將在我的模板里面加入如下內容:
d) 加入必用的 flash(讀取優化),lib(debug),nvic(中斷位置判斷、開中斷模板),rcc(時鐘管理模板,開啟外設時鐘 模板),gpio(管腳定義模板)的初始化代碼,所有模板代碼用到的時候只要去掉前面的注釋“//”,根據需求填入相應值 就可以了。
e)  因為自己記性不好,所以 main 函數中的代碼做到每行注釋,便于自己以后使用。

f) 集成 Print_U 函數簡單串口收發函數代碼,便于調試,改變使用 Printf 函數的調試習慣。
g) 集成使用 systick 的精確延時函數 delay。
h) 集成時鐘故障處理代碼。
i) 集成電壓監控代碼。
j) 集成片上溫度檢測代碼。
k) 逐步加入所有外設的初始化模塊 一、編寫程序所需的步驟
1、解壓縮,改目錄名稱,和 eww 文件名,以便跟其他程序區分。
2、更改設置:在“stm32f10x_conf.h”關閉不用的外設(在其聲明函數前面加注釋符號“//”)。并根據外部晶振速度更改其中
“HSE_Value”的數值,其單位是 Hz。
3、完成各種頭文件的包含(#i nclude "xxx.h";),公共變量的聲明(static  數據類型 變量名稱;),子程序聲明(void 函 數名稱(參數);)……C 語言必須的前置工作。
4、改寫我的程序庫里面所預設的模板,再進行其他模塊的初始化子程序代碼的編寫,并在程序代碼的開始部分調用。注 意:必須記住所有外設的使用需要考慮4個問題:
a)     開時鐘 RCC(在 RCC 初始化中);
b)    自身初始化;
c)    相關管腳配置(在 GPIO 初始化中);
d)    是否使用中斷(在 NVIC 初始化中)
5、編寫 main.c 中的主要代碼和各種子函數。
6、在“stm32f10x_it.c”填寫各種中斷所需的執行代碼,如果用不到中斷的簡單程序則不用編寫此文件。
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 燒寫并按鈕調試程序。注意,ST-Link-II 是直接將程序燒寫進 Flash 進行調試,而不是使用 RAM
的方式。

STM32學前班教程之五:給等待入門的人一點點建議

入門必須閱讀的相關文檔
1、 幾個重要官方文檔的功能:
a) Datasheet——芯片基本數據,功能參數封裝管腳定義和性能規范。
b) 固件函數庫用戶手冊——函數庫功能,庫函數的定義、功能和用法。 c) 參考手冊——各種功能的具體描述,使用方法,原理,相關寄存器。 d) STM32F10xxx 硬件開發:使用入門——相關基礎硬件設計
e) STM32F10XXX  的使用限制:芯片內部未解決的硬件設計 bug,開發需要注意繞開。
f) 一本簡單的 C 語言書,相信我,不用太復雜。
2、 其他的有用文檔,對初學幫助很大
a)  如何使用 STM32的軟件庫在 IAR 的 EWARM 下進行應用開發——IAR 基礎設置。
b) 輕松進入 STM32+Cortex-M3世界.ppt——開發板和最小系統設計需求。
c) 如何選擇 STM32開發板.pdf——各種開發板介紹和功能比較。
d) MXCHIP 的系列視頻教程——全部芯片基礎及其外設的教程,使用函數庫編程的話就不用看每個視頻后半段的關于寄 存器的介紹了。
e) STM32_Technical_Slide(常見問題)——一些優化設計方案。
3、 關于參考書,買了兩本但是基本對學習沒什么幫助,如果湊齊以上資料,建議慎重買書,不如留著那 n 個幾十塊錢, 攢到一起買開發板。
我自己的學習過程
1、 一共24個庫,不可能都學,都學也沒用。按照我的工作需求必須學的有16個,這16個也不是全學。主要學習來源是

各種例程代碼、“固件函數庫用戶手冊”和“參考手冊”。
具體學習方法是通讀不同來源的程序,在程序中找到相關的函數庫的應用,然后再閱讀相關文檔,有條件的實驗。對于 內容的選擇方面,根據入門內容和未來應用,將所涉及的范圍精簡到最低,但是對所選擇的部分的學習則力求明確。以 下是我按照自己的需求對程序庫函數排列的學習順序:
a)  絕大部分程序都要涉及到的庫——flash,lib,nvic,rcc,只學基礎的跟最簡單應用相關必用的部分,其他部分后期再 返回頭學。
b) 各種程序通用但不必用的庫——exti,MDA,systic,只通讀理解其作用。
c) DEMO 板擁有的外設庫——gpio,usart,編寫代碼實驗。
d) 未來需要用到的外設的庫——tim,tim1,adc,i2c,spi,先理解等待有條件后實驗。
e)  開發可靠性相關庫——bkp,iwdg,wwdg,pwr,參考其他例程的做法。
f) 其他,根據興趣來學。


STM32學前班教程之六:這些代碼大家都用得到
2、 閱讀 flash:  芯片內部存儲器 flash 操作函數
我的理解——對芯片內部 flash 進行操作的函數,包括讀取,狀態,擦除,寫入等等,可以允許程序去操作 flash 上的數 據。
基礎應用1,FLASH 時序延遲幾個周期,等待總線同步操作。推薦按照單片機系統運行頻率,0—24MHz 時,取 Latency=0;
24—48MHz 時,取 Latency=1;48~72MHz 時,取 Latency=2。所有程序中必須的 用法:FLASH_SetLatency(FLASH_Latency_2);
位置:RCC 初始化子函數里面,時鐘起振之后。
基礎應用2,開啟 FLASH 預讀緩沖功能,加速 FLASH 的讀取。所有程序中必須的 用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
位置:RCC 初始化子函數里面,時鐘起振之后。

3、 閱讀 lib:調試所有外設初始化的函數。
我的理解——不理解,也不需要理解。只要知道所有外設在調試的時候,EWRAM 需要從這個函數里面獲得調試所需信 息的地址或者指針之類的信息。
基礎應用1,只有一個函數 debug。所有程序中必須的。 用法: #ifdef DEBUG
debug();
#endif
位置:main 函數開頭,聲明變量之后。
4、 閱讀 nvic:系統中斷管理。 我的理解——管理系統內部的中斷,負責打開和關閉中斷。 基礎應用1,中斷的初始化函數,包括設置中斷向量表位置,和開啟所需的中斷兩部分。所有程序中必須的。 用法: void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;//中斷管理恢復默認參數
#ifdef   VECT_TAB_RAM
//如果 C/C++ Compiler\Preprocessor\Defined symbols 中的定義了 VECT_TAB_RAM(見程序庫更改內容的表格)
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //則在 RAM 調試
#else    //如果沒有定義 VECT_TAB_RAM NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//則在 Flash 里調試
#endif    //結束判斷語句
//以下為中斷的開啟過程,不是所有程序必須的。
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//設置 NVIC 優先級分組,方式。

//注:一共16個優先級,分為搶占式和響應式。兩種優先級所占的數量由此代碼確定,NVIC_PriorityGroup_x 可以是0、1、
2、3、4,分別代表搶占優先級有1、2、4、8、16個和響應優先級有16、8、4、2、1個。規定兩種優先級的數量后,所有 的中斷級別必須在其中選擇,搶占級別高的會打斷其他中斷優先執行,而響應級別高的會在其他中斷執行完優先執行。
//NVIC_InitStructure.NVIC_IRQChannel = 中斷通道名;
//開中斷,中斷名稱見函數庫
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
//搶占優先級
//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
//響應優先級
//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//啟動此通道的中斷
//NVIC_Init(&NVIC_InitStructure);    //中斷初始化
}
5、 閱讀 rcc:單片機時鐘管理。 我的理解——管理外部、內部和外設的時鐘,設置、打開和關閉這些時鐘。 基礎應用1:時鐘的初始化函數過程——
用法:void RCC_Configuration(void)    //時鐘初始化函數
{
ErrorStatus HSEStartUpStatus;     //等待時鐘的穩定 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 使用系統時鐘 RCC_PCLK2Config(RCC_HCLK_Div2);    //APB2(高速)為 HCLK 的一半 RCC_PCLK1Config(RCC_HCLK_Div2);    //APB1(低速)為 HCLK 的一半
//注:AHB 主要負責外部存儲器時鐘。PB2負責 AD,I/O,高級 TIM,串口1。APB1負責 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 設置為系統時鐘源
while (RCC_GetSYSCLKSource() != 0x08){}
//等待系統時鐘源的啟動
}
//RCC_AHBPeriphClockCmd(ABP2設備1 | ABP2設備2  |, ENABLE);
//啟動 AHP 設備
//RCC_APB2PeriphClockCmd(ABP2設備1 | ABP2設備2  |, ENABLE);

//啟動 ABP2設備
//RCC_APB1PeriphClockCmd(ABP2設備1 | ABP2設備2  |, ENABLE);
//啟動 ABP1設備
}
1、閱讀 exti:外部設備中斷函數 我的理解——外部設備通過引腳給出的硬件中斷,也可以產生軟件中斷,19個上升、下降或都觸發。EXTI0~EXTI15連
接到管腳,EXTI 線16連接到 PVD(VDD 監視),EXTI 線17連接到 RTC(鬧鐘),EXTI 線18連接到 USB(喚醒)。 基礎應用1,設定外部中斷初始化函數。按需求,不是必須代碼。
用法: void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure; //外部設備中斷恢復默認參數
EXTI_InitStructure.EXTI_Line = 通道1|通道2;
//設定所需產生外部中斷的通道,一共19個。
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //產生中斷
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
//上升下降沿都觸發
EXTI_InitStructure.EXTI_LineCmd = ENABLE; //啟動中斷的接收
EXTI_Init(&EXTI_InitStructure);    //外部設備中斷啟動
}

2、閱讀 dma:通過總線而越過 CPU 讀取外設數據
我的理解——通過 DMA 應用可以加速單片機外設、存儲器之間的數據傳輸,并在傳輸期間不影響 CPU 進行其他事情。 這對于入門開發基本功能來說沒有太大必要,這個內容先行跳過。

3、閱讀 systic:系統定時器
我的理解——可以輸出和利用系統時鐘的計數、狀態。 基礎應用1,精確計時的延時子函數。推薦使用的代碼。
用法:
static vu32 TimingDelay;//全局變量聲明
void SysTick_Config(void)//systick 初始化函數
{
SysTick_CounterCmd(SysTick_Counter_Disable);//停止系統定時器
SysTick_ITConfig(DISABLE);    //停止 systick 中斷
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
//systick 使用 HCLK 作為時鐘源,頻率值除以8。 SysTick_SetReload(9000);//重置時間1毫秒(以72MHz 為基礎計算) SysTick_ITConfig(ENABLE);//開啟 systic 中斷
}
void Delay (u32 nTime) //延遲一毫秒的函數
{
SysTick_CounterCmd(SysTick_Counter_Enable);    //systic 開始計時

TimingDelay = nTime;    //計時長度賦值給遞減變量
while(TimingDelay != 0);    //檢測是否計時完成

SysTick_CounterCmd(SysTick_Counter_Disable);    //關閉計數器

SysTick_CounterCmd(SysTick_Counter_Clear);    //清除計數值
}
void TimingDelay_Decrement(void)
//遞減變量函數,函數名由“stm32f10x_it.c”中的中斷響應函數定義好了。
{
if (TimingDelay != 0x00)    //檢測計數變量是否達到0
{
TimingDelay--;    //計數變量遞減
}
}
注:建議熟練后使用,所涉及知識和設備太多,新手出錯的可能性比較大。新手可用簡化的延時函數代替:
void Delay(vu32 nCount)//簡單延時函數
{
for(; nCount != 0; nCount--);(循環變量遞減計數)
}
當延時較長,又不需要精確計時的時候可以使用嵌套循環:
void Delay(vu32 nCount)    //簡單的長時間延時函數
{int i;     //聲明內部遞減變量
for(; nCount != 0; nCount--)  //遞減變量計數
{for (i=0; i<0xffff; i++)}    //內部循環遞減變量計數
}
4、閱讀 gpio:I/O 設置函數

我的理解——所有輸入輸出管腳模式設置,可以是上下拉、浮空、開漏、模擬、推挽模式,頻率特性為2M,10M,50M。 也可以向該管腳直接寫入數據和讀取數據。
基礎應用1,gpio 初始化函數。所有程序必須。 用法:void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;    //GPIO 狀態恢復默認參數
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 參數為:ALL,2MHz,FLATING。如果其中任意 一行與前一組相應設置相同,那么那一行可以省略,由此推論如果前面已經將此行參數設定為默認參數(包括使 用 GPIO_InitTypeDef GPIO_InitStructure 代碼),本組應用也是默認參數的話,那么也可以省略。以下重復這個過程直到所有 應用的管腳全部被定義完畢。
……
}
基礎應用2,向管腳寫入0或1
用法:GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);//寫入1

STM32筆記之七:讓它跑起來,基本硬件功能的建立

0、             實驗之前的準備
a)                接通串口轉接器

b)    下載 IO 與串口的原廠程序,編譯通過保證調試所需硬件正常。
1、    flash,lib,nvic,rcc 和 GPIO,基礎程序庫編寫
a) 這幾個庫函數中有一些函數是關于芯片的初始化的,每個程序中必用。為保障程序品質,初學階段要求嚴格 遵守官方習慣。注意,官方程序庫例程中有個 platform_config.h 文件,是專門用來指定同類外設中第幾號外設被使用, 就是說在 main.c 里面所有外設序號用 x 代替,比如 USARTx,程序會到這個頭文件中去查找到底是用那些外設,初學的 時候參考例程別被這個所迷惑住。
b)    全部必用代碼取自庫函數所帶例程,并增加逐句注釋。
c)    習慣順序——Lib(debug),RCC(包括 Flash 優化),NVIC,GPIO
d)    必用模塊初始化函數的定義:
void RCC_Configuration(void);    //定義時鐘初始化函數
void GPIO_Configuration(void);    //定義管腳初始化函數
void NVIC_Configuration(void);              //定義中斷管理初始化函數 void Delay(vu32 nCount);                                         //定義延遲函數 e)                Main 中的初始化函數調用:
RCC_Configuration();        //時鐘初始化函數調用 NVIC_Configuration();     //中斷初始化函數調用 GPIO_Configuration();    //管腳初始化函數調用
f)     Lib 注意事項:
屬于 Lib 的 Debug 函數的調用,應該放在 main 函數最開始,不要改變其位置。
g)    RCC 注意事項:
Flash 優化處理可以不做,但是兩句也不難也不用改參數…… 根據需要開啟設備時鐘可以節省電能 時鐘頻率需要根據實際情況設置參數

h)    NVIC 注意事項
注意理解占先優先級和響應優先級的分組的概念 i)    GPIO 注意事項 注意以后的過程中收集不同管腳應用對應的頻率和模式的設置。 作為高低電平的 I/O,所需設置:RCC 初始化里面打開 RCC_APB2
PeriphClockCmd(RCC_APB2Periph_GPIOA);GPIO 里面管腳設定:IO 輸出(50MHz,Out_PP);IO 輸入(50MHz,IPU);
j)     GPIO 應用
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 函數
void Delay(vu32 nCount)//簡單延時函數
{for(; nCount != 0; nCount--);}
實驗步驟:
RCC 初 始 化 函 數 里 添 加 : RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1  |   RCC_APB2Periph_GPIOA  | RCC_APB2Periph_GPIOB , ENABLE);
不用其他中斷,NVIC 初始化函數不用改
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);    //初始化 簡單的延遲函數:
void Delay(vu32 nCount)    //簡單延時函數
{ for (; nCount != 0; nCount--);}    //循環計數延時 完成之后再在 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)     目的:在基礎實驗成功的基礎上,對串口的調試方法進行實踐。硬件代碼順利完成之后,對日后調試需要用 到的 printf 重定義進行調試,固定在自己的庫函數中。
b)    初始化函數定義:
void USART_Configuration(void);    //定義串口初始化函數
c)    初始化函數調用:
void UART_Configuration(void);    //串口初始化函數調用 初始化代碼:
void USART_Configuration(void)    //串口初始化函數
{

//串口參數初始化
USART_InitTypeDef USART_InitStructure;    //串口設置恢復默認參數
//初始化參數設置
USART_InitStructure.USART_BaudRate = 9600;    //波特率9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b;     //字長8位 USART_InitStructure.USART_StopBits = USART_StopBits_1;        //1位停止字節 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 發送功能
USART_Init(USART1, &USART_InitStructure);    //初始化
USART_Cmd(USART1, ENABLE);    //啟動串口
}
RCC 中打開相應串口
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE); GPIO 里面設定相應串口管腳模式
//串口1的管腳初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;    //管腳9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //復用推挽輸出 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)    簡單應用:
發送一位字符
USART_SendData(USART1, 數據);    //發送一位數據
while(USART_GetFlagStatus(USART1,    USART_FLAG_TXE)     ==    RESET){}
//等待發送完畢 接收一位字符
while(USART_GetFlagStatus(USART1,    USART_FLAG_RXNE)     ==    RESET){}
//等待接收完畢
變量= (USART_ReceiveData(USART1));    //接受一個字節 發送一個字符串
先定義字符串:char rx_data[250];
然后在需要發送的地方添加如下代碼
int i;     //定義循環變量
while(rx_data!='\0')    //循環逐字輸出,到結束字'\0'
{USART_SendData(USART1,  rx_data);    //發送字符
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符發送完畢
i++;}
e)    USART 注意事項: 發動和接受都需要配合標志等待。 只能對一個字節操作,對字符串等大量數據操作需要寫函數 使用串口所需設置:RCC 初始化里面打開 RCC_APB2PeriphClockCmd
(RCC_APB2Periph_USARTx);GPIO 里面管腳設定:串口 RX(50Hz,IN_FLOATING);串口 TX(50Hz,AF_PP);
f)     printf 函數重定義(不必理解,調試通過以備后用)

(1)    需要 c 標準函數:
#i nclude "stdio.h"
(2)    粘貼函數定義代碼
#define PUTCHAR_PROTOTYPE int   io_putchar(int ch)   //定義為 putchar 應用
(3)    RCC 中打開相應串口
(4)    GPIO 里面設定相應串口管腳模式
(6)    增加為 putchar 函數。
int putchar(int c)    //putchar 函數
{
if (c == '\n'){putchar('\r');}    //將 printf 的\n 變成\r USART_SendData(USART1, c);            //發送字符 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發送結束 return c;        //返回值
}
(8)    通過,試驗成功。printf 使用變量輸出:%c 字符,%d 整數,%f 浮點數,%s 字符串,/n 或/r 為換行。注意: 只能用于 main.c 中。
3、    NVIC 串口中斷的應用
a)     目的:利用前面調通的硬件基礎,和幾個函數的代碼,進行串口的中斷輸入練習。因為在實際應用中,不使 用中斷進行的輸入是效率非常低的,這種用法很少見,大部分串口的輸入都離不開中斷。
b)    初始化函數定義及函數調用:不用添加和調用初始化函數,在指定調試地址的時候已經調用過,在那 個
NVIC_Configuration 里面添加相應開中斷代碼就行了。
c)    過程:
i.     在串口初始化中 USART_Cmd 之前加入中斷設置:

USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE 發送中斷,TC 傳輸完成中斷,RXNE 接收中斷,PE 奇偶 錯誤中斷,可以是多個。
ii.     RCC、GPIO 里面打開串口相應的基本時鐘、管腳設置
iii.     NVIC 里面加入串口中斷打開代碼: NVIC_InitTypeDef NVIC_InitStructure;//中斷默認參數 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道設置為串口1中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;    //中斷占先等級0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    //中斷響應優先級0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    //打開中斷
NVIC_Init(&NVIC_InitStructure);    //初始化
iv.    在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數,在其中添入執行代碼。一般最少三個步驟:先 使用 if 語句判斷是發生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。
void USART1_IRQHandler(void)    //串口1中斷
{
char RX_dat;     //定義字符變量

if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)    //判斷發生接收中斷
{USART_ClearITPendingBit(USART1,    USART_IT_RXNE);     //清除中斷標志

GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01);    //開始傳輸 RX_dat=USART_ReceiveData(USART1) & 0x7F;        //接收數據,整理除去前兩位 USART_SendData(USART1, RX_dat);             //發送數據 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待發送結束

}
}
d)    中斷注意事項:
可以隨時在程序中使用 USART_ITConfig(USART1, USART_IT_TXE, DISABLE);來關閉中斷響應。
NVIC_InitTypeDef NVIC_InitStructure 定義一定要加在 NVIC 初始化模塊的第一句。
全局變量與函數的定義:在任意.c 文件中定義的變量或函數,在其它.c 文件中使用 extern+定義代碼再次定義就可以直接 調用了。

STM32筆記之九:打斷它來為我辦事,EXIT (外部 I/O 中斷)應用
a)     目的:跟串口輸入類似,不使用中斷進行的 IO 輸入效率也很低,而且可以通過 EXTI 插入按鈕事件,本節聯 系 EXTI 中斷。
b)    初始化函數定義:
void EXTI_Configuration(void); //定義 IO 中斷初始化函數
c)    初始化函數調用:
EXTI_Configuration();//IO 中斷初始化函數調用簡單應用:
d)    初始化函數:
void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;    //EXTI 初始化結構定義

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;//觸發模式 EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //線路選擇 EXTI_InitStructure.EXTI_LineCmd = ENABLE;//啟動中斷 EXTI_Init(&EXTI_InitStructure);//初始化
}

e)    RCC 初始化函數中開啟 I/O 時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE);

GPIO 初始化函數中定義輸入 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 的初始化函數里面增加以下代碼打開相關中斷: NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel;    //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;        //響應級

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    //啟動
NVIC_Init(&NVIC_InitStructure);    //初始化

g)    在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數,在其中添入執行代碼。一般最少三個步驟:先 使用 if 語句判斷是發生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。
if(EXTI_GetITStatus(EXTI_Line3) != RESET)     //判斷中斷發生來源
{ EXTI_ClearITPendingBit(EXTI_Line3);    //清除中斷標志 USART_SendData(USART1, 0x41);     //發送字符“a” GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED 發 生 明 暗
交替
}
h)    中斷注意事項: 中斷發生后必須清除中斷位,否則會出現死循環不斷發生這個中斷。然后需要對中斷類型進行判斷再執行代碼。
使用 EXTI 的 I/O 中斷,在完成 RCC 與 GPIO 硬件設置之后需要做三件事:初始化 EXTI、NVIC 開中斷、編寫中斷執行 代碼。

STM32筆記之十:工作工作,PWM 輸出
a)     目的:基礎 PWM 輸出,以及中斷配合應用。輸出選用 PB1,配置為 TIM3_CH4,是目標板的 LED6控制腳。
b)    對于簡單的 PWM 輸出應用,暫時無需考慮 TIM1的高級功能之區別。
c)    初始化函數定義:
void TIM_Configuration(void);    //定義 TIM 初始化函數
d)    初始化函數調用:

TIM_Configuration();    //TIM 初始化函數調用
e)     初始化函數,不同于前面模塊,TIM 的初始化分為兩部分——基本初始化和通道初始化:
void TIM_Configuration(void)//TIM 初始化函數
{
TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;//定時器初始化結構
TIM_OCInitTypeDef    TIM_OCInitStructure;//通道輸出初始化結構

//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);            //默認參數 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;        //工作狀態 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    //設定為輸出,需要 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 初始化函數中加入 TIM 時鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g)    GPIO 里面將輸入和輸出管腳模式進行設置。信號:AF_PP,50MHz。
h)    使用中斷的話在 NVIC 里添加如下代碼:

//打開 TIM2中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;    //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;     //響應級 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);    //獲取捕捉數值
}
}

i)     簡單應用:
//改變占空比
TIM_SetCompare4(TIM3,  變量);

j)     注意事項:
管腳的 IO 輸出模式是根據應用來定,比如如果用 PWM 輸出驅動 LED 則應該將相應管腳設為 AF_PP,否則單片機沒有 輸出。

STM32筆記之十一:捕捉精彩瞬間,脈沖方波長度捕獲
a)     目的:基礎 PWM 輸入也叫捕獲,以及中斷配合應用。使用前一章的輸出管腳 PB1(19腳),直接使用跳線連 接輸入的 PA3(13腳),配置為 TIM2_CH4,進行實驗。
b)    對于簡單的 PWM 輸入應用,暫時無需考慮 TIM1的高級功能之區別,按照目前我的應用目標其實只需要采集 高電平寬度,而不必知道周期,所以并不采用 PWM 輸入模式,而是普通脈寬捕獲模式。
c)    初始化函數定義:
void TIM_Configuration(void);    //定義 TIM 初始化函數
d)    初始化函數調用:
TIM_Configuration();    //TIM 初始化函數調用

e)     初始化函數,不同于前面模塊,TIM 的 CAP 初始化分為三部分——計時器基本初始化、通道初始化和時鐘啟 動初始化:
void TIM_Configuration(void)//TIM2的 CAP 初始化函數
{
TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;//定時器初始化結構
TIM_ICInitTypeDef TIM_ICInitStructure;    //通道輸入初始化結構

//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;//管腳與寄存器對應關系 TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;//分頻器
TIM_ICInitStructure.TIM_ICFilter = 0x4;    //濾波設置,經歷幾個周期跳變認定波形穩定0x0~0xF TIM_ICInit(TIM2, &TIM_ICInitStructure);       //初始化
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2);    //選擇時鐘觸發源

TIM_SelectSlaveMode(TIM2, TIM_SlaveMode_Reset);//觸發方式
TIM_SelectMasterSlaveMode(TIM2, TIM_MasterSlaveMode_Enable); //啟動定時器的被動觸發
TIM_ITConfig(TIM2, TIM_IT_CC4, ENABLE);    //打開中斷

TIM_Cmd(TIM2, ENABLE);    //啟動 TIM2
}

f)     RCC 初始化函數中加入 TIM 時鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g)    GPIO 里面將輸入和輸出管腳模式進行設置。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)     簡單應用:
變量 = TIM_GetCapture4(TIM2);

j)     注意事項:

i.     由于我的需求只跟高電平寬度有關,所以避免了使用 PWM 輸入模式,這樣可以每個管腳捕捉一路信號。如果
使用 PWM 模式,每一路需要占用兩個寄存器,所以一個定時器只能同時使用兩路 PWM 輸入。
ii.     由于捕捉需要觸發啟動定時器,所以 PWM 輸出與捕捉不容易在同一個 TIM 通道上實現。如果必須的話只能 增加計數溢出的相關代碼。
iii.     有些程序省略了捕捉通道的初始化代碼,這是不對的
iv.    在基本計時器初始化代碼里面注意選擇適當的計數器長度,最好讓波形長度不要長于一個計數周期,否則需 要增加溢出代碼很麻煩。一個計數周期的長度計算跟如下幾個參數有關:
(1)    RCC 初始化代碼里面的  RCC_PCLKxConfig,這是 TIM 的基礎時鐘源與系統時鐘的關系。
(2)    TIM 初始化的 TIM_Period,這是計數周期的值
(3)    TIM 初始化的 TIM_Prescaler,這是計數周期的倍頻計數器,相當于調節計數周期,可以使 TIM_Period 盡 量大,提高計數精度。


STM32筆記之十二:時鐘不息工作不止,systic 時鐘應用
a)     目的:使用系統時鐘來進行兩項實驗——周期執行代碼與精確定時延遲。
b)    初始化函數定義:
void SysTick_Configuration(void);
c)    初始化函數調用:
SysTick_Configuration();
d)    初始化函數:
void SysTick_Configuration(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//時鐘除8
SysTick_SetReload(250000);    //計數周期長度

SysTick_CounterCmd(SysTick_Counter_Enable);    //啟動計時器
SysTick_ITConfig(ENABLE);    //打開中斷
}
e)      在 NVIC 的初始化函數里面增加以下代碼打開相關中斷: NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中斷等級設置,一般設置的高一些會少受其他影響 f)     在 stm32f10x_it.c 文件中找到 void SysTickHandler  函數
void SysTickHandler(void)
{
執行代碼
}
g)              簡單應用:精確延遲函數,因為 systic 中斷往往被用來執行周期循環代碼,所以一些例程中使用其中斷的啟動 和禁止來編寫的精確延時函數實際上不實用,我自己編寫了精確計時函數反而代碼更精簡,思路更簡單。思路是調用后, 變量清零,然后使用時鐘來的曾變量,不斷比較變量與延遲的數值,相等則退出函數。代碼和步驟如下:
i.     定義通用變量:u16 Tic_Val=0; //變量用于精確計時
ii.     在 stm32f10x_it.c 文件中相應定義:
extern u16 Tic_Val;//在本文件引用 MAIN.c 定義的精確計時變量
iii.     定義函數名稱:void Tic_Delay(u16 Tic_Count);//精確延遲函數
iv.    精確延時函數:
void Tic_Delay(u16 Tic_Count)    //精確延時函數
{    Tic_Val=0;    //變量清零
while(Tic_Val != Tic_Count){printf("");}//計時
}
v.     在 stm32f10x_it.c 文件中 void SysTickHandler  函數里面添加

Tic_Val++;//變量遞增
vi.     調用代碼:Tic_Delay(10);    //精確延時
vii.     疑問:如果去掉計時行那個沒用的 printf("");函數將停止工作,這個現象很奇怪
STM32筆記之十三:惡搞,兩只看門狗 a)    目的: 了解兩種看門狗(我叫它:系統運行故障探測器和獨立系統故障探測器,新手往往被這個并不形象的象形名稱搞糊涂)
之間的區別和基本用法。
b)    相同: 都是用來探測系統故障,通過編寫代碼定時發送故障清零信號(高手們都管這個代碼叫做“喂狗”),告訴它系統運行正常。
一旦系統故障,程序清零代碼(“喂狗”)無法執行,其計數器就會計數不止,直到記到零并發生故障中斷(狗餓了開始 叫喚),控制 CPU 重啟整個系統(不行啦,開始咬人了,快跑……)。
c)    區別:
獨立看門狗 Iwdg——我的理解是獨立于系統之外,因為有獨立時鐘,所以不受系統影響的系統故障探測器。(這條狗是 借來的,見誰偷懶它都咬!)主要用于監視硬件錯誤。
窗口看門狗 wwdg——我的理解是系統內部的故障探測器,時鐘與系統相同。如果系統時鐘不走了,這個狗也就失去作 用了。(這條狗是老板娘養的,老板不干活兒他不管!)主要用于監視軟件錯誤。
d)    初始化函數定義:鑒于兩只狗作用差不多,使用過程也差不多初始化函數栓一起了,用的時候根據情況刪減。

void WDG_Configuration(void);
e)     初始化函數調用:
WDG_Configuration();
f)     初始化函數
void WDG_Configuration()    //看門狗初始化
{
//軟件看門狗初始化

WWDG_SetPrescaler(WWDG_Prescaler_8); //時鐘8分頻4ms
// (PCLK1/4096)/8= 244 Hz (~4 ms)
WWDG_SetWindowValue(65);    //計數器數值
WWDG_Enable(127);    //啟動計數器,設置喂狗時間
// 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);    //計數器數值 IWDG_ReloadCounter();    //重啟計數器 IWDG_Enable();        //啟動看門狗
}
g)    RCC 初始化:只有軟件看門狗需要時鐘初始化,獨立看門狗有自己的時鐘不需要但是需要 systic 工作相關設 置。
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;    //響應中斷優先級 NVIC_Init(&NVIC_InitStructure);     //打開中斷

i)     中斷程序,軟件看門狗在自己的中斷中喂狗,獨立看門狗需要使用 systic 的定時中斷來喂狗。以下兩個程序都
在 stm32f10x_it.c 文件中。
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(0x7F);     //更新計數值
WWDG_ClearFlag();    //清除標志位
}
void SysTickHandler(void)
{  IWDG_ReloadCounter();    //重啟計數器(喂狗)
}
j)     注意事項:
i.     有狗平常沒事情可以不理,但是千萬別忘了喂它,否則死都不知道怎么死的!
ii.     初始化程序的調用一定要在 systic 的初始化之后。
iii.     獨立看門狗需要 systic 中斷來喂,但是 systic 做別的用處不能只做這件事,所以我寫了如下幾句代碼,可以 不影響 systic 的其他應用,其他 systic 周期代碼也可參考:
第一步:在 stm32f10x_it.c 中定義變量
int Tic_IWDG;    //喂狗循環程序的頻率判斷變量 第二步:將 SysTickHandler 中喂狗代碼改為下面: Tic_IWDG++;          //變量遞增 if(Tic_IWDG>=100)        //每100個 systic 周期喂狗
{  IWDG_ReloadCounter();//重啟計數器(喂狗)
Tic_IWDG=0;    //變量清零
}

STM32筆記之十四:基本問題,來討論一下軟件架構
網上大家都在討論和學習,但是對于架構這個基本問題卻沒幾個人討論。個人認為有個好的架構是寫好代碼的基礎,可 以使后期的調式工作事半功倍!!
1、        架構組成:我的程序代碼分為四種結構 a)     順序執行代碼 定義:按照順序逐行執行的代碼 優點:是思路簡單,代碼可靠不易被干擾。 缺點:占用資源
用途:只用來各種變量、函數的定義,硬件的初始化程序 位置:main.c 的開始一直到 main 函數的 while 函數之前
b)    空閑執行代碼
定義:在 CPU 空閑的時候才執行的代碼 優點:不占用資源 缺點:執行的實時性不能保證
用途:非實時任務,調試信息輸出,不重要的狀態指示 位置:main.c 的 main 函數的 while 函數內部
c)    中斷執行代碼 定義:由軟硬件事件打斷整個程序而執行的代碼 優點:可以保證實時性,各種中斷可以安排優先順序 缺點:關系相對復雜,互相之間容易干擾 用途:觸發性的代碼,比如接收數據,響應外部設備,按鈕的相應 位置:stm32f10x_it.c 內部

d)    循環執行代碼
定義:按照時間周期執行的代碼 優點:定期自動執行 缺點:實時性不好
用途:需要周期執行的任務,狀態檢查及相關信息輸出,數據記錄 位置:stm32f10x_it.c 的 SysTickHandler 內部
e)     DMA 自動代碼 定義:不需要主程序干預,外設自動執行 優點:自動刷新數據,不占用 CPU 資源 缺點:不能控制 用途:數據通信存儲,AD 轉換 位置:不需要
2、架構執行順序圖 下載 (51.33 KB)

深入淺出 STM32(2)
STM32學習筆記之十五——IAR4的最后瘋狂,笨笨的開發模板下載 準備大換血了,包括開發環境升級和固件升級,那個需要一定過程,吧之前完成的模板跟大家共享一下。 我的程序庫特點:
a)     默認兼容 ST-LINK-II,IAR EWARM 4.42A,Flash 調試,使用串口1,GPIOA 的3、4、
5、6腳輸入,GPIOB 的1、2、10、11腳輸出,其他有可能需要更改設置
b)    為操作方便減少了目錄的層次
c)    為學習方便使用網友漢化版2.0.2固件,主要是庫函數中 c 代碼的注釋。
d)        加入必用的 flash(讀取優化),nvic(RAM 與 Flash 調試選擇),rcc(時鐘管理模 板,開啟外設時鐘模板),gpio(管腳定義模板)的初始化代碼,所有模板代碼用到的 時候只要去掉前面的注釋"//",根據需求填入相應值就可以了。
e)     因為自己記性不好,所以 main 函數中的代碼做到每行注釋,便于自己以后使用。
f)     列出常見應用代碼模板與 ASCII 常用列表。
g)    集成 putchar 字符輸出和 Printf 的重定義到串口的代碼,便于調試。
h)    集成 NVIC 中斷管理模板,EXTI 外部 I/O 中斷模板
i)     針對自己情況集成 PWM 輸出模板和 CAP 脈寬捕捉模板,并全部注釋。
j)     集成系統循環時鐘的初始化函數模板
k)    集成自己編寫精確延時代碼,不會影響 systic 的周期代碼的執行。
l)     集成兩種看門狗的使用代碼,小心使用
M)         集成 hex 生成設置命令,位置在編譯目錄(STM32F103C8)的 Exe 下,集成 ISP 軟件便 于脫離仿真器的串口調試 STMISP.exe。
由于注釋寫的太多,還加入自己編程以來的許多格式習慣,所以許多人會覺得混亂不堪,在

此聲明,此程序庫僅僅為個人學習之用!

STM32學習筆記之十六——題外話,自己做塊工程板 一、我的學習計劃將 STM32單片機的硬件設計工作:
第一步——用 STM32F103CBT6的48腳芯片,為光電平臺的簡單控制為目標,實現基本外圍硬件、PWM、串口、I/O。 將 SPI、I2C 留插針。
第二步——為集成傳感器應用為目標,在第一步硬件基礎上制作功能性的套版,兩板連接實現 AD、SPI、I2C、RTC 等 等功能。
二、硬件規劃
選用 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 復用),1個 SPI,8個(兩組)PWM 輸入輸出,1
個 USB,1個 I/O,1個 MCO。 三、管腳分配:
下載 (32.83 KB)
2009-4-26 16:14

四、ALTIUM DESIGNER 6(Protel 的第六個版本)操作筆記
之所以選擇這個軟件三個理由:1、界面習慣兼容 Protel。2、操作習慣于 Windows 類似方便。3、可輸出 igs 用于結構設 計。
軟件使用筆記如下:
a)     流程:新建工程,添加原理圖,添加 SCH 庫,畫原理圖,添加 PCB 庫,設定封裝,添加 PCB,布線,檢查, 導出生產文件。
b)    新建工程:最好使用自己以前的同版本文檔設置,會包含各種庫省去大量工作
c)    添加器件到 SCH,可使用復制粘貼的辦法,注意管腳,有些需要外殼接地的器件把外殼的焊點畫出來。完成 后點擊放置,改動后再器件名稱點擊右鍵更改。

d)    畫原理圖:操作類似其他 windows 軟件,會自動檢查錯誤連接和重復硬件。
e)     添加器件到 PCB 庫,最好使用拷貝粘貼的辦法,最好有官方的焊點圖。沒有的話可以按照封裝的型號直接去
http://www.***search.com/搜索封裝型號(不是器件型號),也有封裝的相關尺寸和焊點圖。
f)     雙擊原理圖的器件,在右下角改封裝名稱。 g)     添加新的 PCB 到工程: “設計/規則”改線寬、線距、器件距離……;
“設計/板子形狀/重新定義板子形狀”改工作區域大小,然后左鍵點擊前置 Keepout 層,畫電路板外形;
“設計/板參數選項”改網格大小,器件和走線中鼠標捕捉的間隔大小……;
“設計/Import changes From……”引入原理圖的器件和連接方式,包括改動(出現對 match 提示選擇繼續就可以了);
“查看/切換單位”改公制和英制; “工具/取消布線”取消已經布好的線; “自動布線”計算機自動布線,功能比 Protel 增強不少; “報告/測量距離”測量實際距離; 在層標簽單擊,前置這個層。右鍵有隱藏層和顯示層比較常用。
屏幕中點擊右鍵菜單中“設計/規則”、“選項/板參數選項”、 “選項/層疊管理”(添加和刪除層)、“選項/顯示掩藏”(針對 各種類型進行顯示和隱藏,查找未布的線就使用此功能后在操作框中點擊“所有最終”然后點擊“Apply”,再手工點擊所有 的選項為“隱藏的”再點“Apply”就能看到未布線的連線了)
快捷鍵:空格鍵旋轉器件,TAB 鍵切換線寬和放置過孔。左鍵單擊選擇,左鍵按住移動器件(多個重疊會有列表選擇, 未松開時右鍵取消操作),左鍵雙擊改器件屬性(所在層、位置……),右鍵按住移動鼠標平移視野,滾輪上下移動,滾 輪按住移動鼠標放大縮小
五、基本電路原理設計
拋棄復雜設計,專注于可獨立調式的 CPU 板設計。計劃設計模塊包括:供電、JTAG、晶振、RTC(電池引出)。 注:未使用標準 JTAG 設計,原因有三:
1、原設計太占管腳,這個尺寸實在難實現

2、這只是 CPU 板具體應用會再做功能套版,上面可以連接標準 JTAG
3、有可能向 USB 燒寫和 SW 雙線調式方向轉變,所以以后不一定會使用標準 JTAG
本文來自 CSDN 博客,轉載請標明出處:http://blog.csdn.net/feiniao_lql/archive/2010/06/21/5684074.aspx

STM32 GPIO 應用筆記
1                   STM32的輸入輸出管腳有下面8種可能的配置:(4輸入+2輸出+2復用輸出)
① 浮空輸入_IN_FLOATING
② 帶上拉輸入_IPU
③ 帶下拉輸入_IPD
④ 模擬輸入_AIN
⑤ 開漏輸出_OUT_OD
⑥ 推挽輸出_OUT_PP
⑦ 復用功能的推挽輸出_AF_PP
⑧ 復用功能的開漏輸出_AF_OD
1.1               I/O 口的輸出模式下,有3種輸出速度可選(2MHz、10MHz 和50MHz),這個速度是指 I/O 口驅動電路的響應 速度而不是輸出信號的速度,輸出信號的速度與程序有關(芯片內部在 I/O 口的輸出部分安排了多個響應速度不同的輸 出驅動電路,用戶可以根據自己的需要選擇合適的驅動電路)。通過選擇速度來選擇不同的輸出驅動模塊,達到最佳的噪 聲控制和降低功耗的目的。高頻的驅動電路,噪聲也高,當不需要高的輸出頻率時,請選用低頻驅動電路,這樣非常有 利于提高系統的 EMI 性能。當然如果要輸出較高頻率的信號,但卻選用了較低頻率的驅動模塊,很可能會得到失真的輸 出信號。
關鍵是 GPIO 的引腳速度跟應用匹配(推薦10倍以上?)。比如:
1.1.1           對于串口,假如最大波特率只需115.2k,那么用2M 的 GPIO 的引腳速度就夠了,既省電也噪聲小。
1.1.2    對于 I2C 接口,假如使用400k 波特率,若想把余量留大些,那么用2M 的 GPIO 的引腳速度或許不夠,這時 可以選用10M 的 GPIO 引腳速度。
1.1.3           對于 SPI 接口,假如使用18M 或9M 波特率,用10M 的 GPIO 的引腳速度顯然不夠了,需要選用50M 的 GPIO

的引腳速度。
1.2    GPIO 口設為輸入時,輸出驅動電路與端口是斷開,所以輸出速度配置無意義。
1.3    在復位期間和剛復位后,復用功能未開啟,I/O 端口被配置成浮空輸入模式。
1.4    所有端口都有外部中斷能力。為了使用外部中斷線,端口必須配置成輸入模式。
1.5    GPIO 口的配置具有上鎖功能,當配置好 GPIO 口后,可以通過程序鎖住配置組合,直到下次芯片復位才能 解鎖。

2    在 STM32中如何配置片內外設使用的 IO 端口
首先,一個外設經過 ①配置輸入的時鐘和 ②初始化后即被激活(開啟);③如果使用該外設的輸入輸出管腳,則需要配 置相應的 GPIO 端口(否則該外設對應的輸入輸出管腳可以做普通 GPIO 管腳使用);④再對外設進行詳細配置。
對應到外設的輸入輸出功能有下述三種情況: 一、外設對應的管腳為輸出:需要根據外圍電路的配置選擇對應的管腳為復用功能的推挽輸出或復用功能的開漏輸出。 二、外設對應的管腳為輸入:則根據外圍電路的配置可以選擇浮空輸入、帶上拉輸入或帶下拉輸入。
三、ADC 對應的管腳:配置管腳為模擬輸入。
如果把端口配置成復用輸出功能,則引腳和輸出寄存器斷開,并和片上外設的輸出信號連接。將管腳配置成復用輸出功 能后,如果外設沒有被激活,那么它的輸出將不確定。

3    通用 IO 端口(GPIO)初始化:
3.1    GPIO 初始化
3.1.1    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | B | C, ENABLE):使能 APB2總線外設時鐘
3.1.2    RCC_ APB2PeriphResetCmd (RCC_APB2Periph_GPIOA | B | C, DISABLE):釋放 GPIO 復位
3.2    配置各個 PIN 端口(模擬輸入_AIN、輸入浮空_IN_FLOATING、輸入上拉_IPU、輸入下拉_IPD、開漏 輸出_OUT_OD、推挽式輸出_OUT_PP、推挽式復用輸出_AF_PP、開漏復用輸出_AF_OD)
3.3    GPIO 初始化完成

下面我就在做個拋磚引玉,根據 ST 手冊上的內容,簡單地綜述一下 GPIO 的功能:
一、共有8種模式,可以通過編程選擇:
1. 浮空輸入
2. 帶上拉輸入
3. 帶下拉輸入
4. 模擬輸入
5. 開漏輸出——(此模式可實現 hotpower 說的真雙向 IO)
6. 推挽輸出
7. 復用功能的推挽輸出
8. 復用功能的開漏輸出 模式7和模式8需根據具體的復用功能決定。
二、專門的寄存器(GPIOx_BSRR 和 GPIOx_BRR)實現對 GPIO 口的原子操作,即回避了設置或清除 I/O 端口時的“讀-修 改-寫”操作,使得設置或清除 I/O 端口的操作不會被中斷處理打斷而造成誤動作。
三、每個 GPIO 口都可以作為外部中斷的輸入,便于系統靈活設計。
四、I/O 口的輸出模式下,有3種輸出速度可選(2MHz、10MHz 和50MHz),這有利于噪聲控制。 五、所有 I/O 口兼容 CMOS 和 TTL,多數 I/O 口兼容5V 電平。
六、大電流驅動能力:GPIO 口在高低電平分別為0.4V 和 VDD-0.4V 時,可以提供或吸收8mA 電流;如果把輸入輸出電 平分別放寬到1.3V 和 VDD-1.3V 時,可以提供或吸收20mA 電流。
七、具有獨立的喚醒 I/O 口。
八、很多 I/O 口的復用功能可以重新映射。
九、GPIO 口的配置具有上鎖功能,當配置好 GPIO 口后,可以通過程序鎖住配置組合,直到下次芯片復位才能解鎖。此 功能非常有利于在程序跑飛的情況下保護系統中其他的設備,不會因為某些 I/O 口的配置被改變而損壞——如一個輸入 口變成輸出口并輸出電流。
STM32第一個例子
//**********************************************************************
// 作者:YYYtech
// 時間:2007/12/14
//***********************************************************************
/***********************************************************************
main 文件,GPIO 操作,完成最簡單的 IO 操作實驗,就是控制 LED 燈
4個 LED 分別對應 PC 的6、7、8、9引腳。4個 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 的庫函數,所以必須把這兩個函數加入工程。
關于固件庫函數在文件夾:C:\Keil\ARM\RV31\LIB\ST\STM32F10x
為 了 不 在 操 作 過 程 中 避 免 改 變 KEIL  文 件 夾 下 的 庫 函 數 , 可 以 固 件 函 數 庫 放 到 其 他 文 件 夾 下 , 如 :
E:\jy\work\STM\WxlStm32\LAB\library
其中 stm32f10x_lib.c 文件是整個庫的一些定義,是必須要的。 加入后的工程為:
GPIO 庫函數簡單說明: 函數名稱 功能描述
GPIO_DeInit  重新初始化外圍設備 GPIOx 相關寄存器到它的默認復位值 GPIO_AFIODeInit  初始化交錯功能(remap, event control 和 EXTI 配置) 寄存器 GPIO_Init  根據 GPIO_初始化結構指定的元素初始化外圍設備 GPIOx GPIO_StructInit  填充 GPIO_初始化結構(GPIO_InitStruct)內的元素為復位值 GPIO_ReadInputDataBit  讀指定端口引腳輸入數據
GPIO_ReadInputData  讀指定端口輸入數據 GPIO_ReadOtputDataBit  讀指定端口引腳輸出數據 GPIO_ReadOtputData  讀指定端口輸出數據 GPIO_SetBits  置1指定的端口引腳
GPIO_ResetBits  清0指定的端口引腳 GPIO_WriteBit  設置或清除選擇的數據端口引腳 GPIO_Write  寫指定數據到 GPIOx 端口寄存器 GPIO_ANAPinConfig  允許或禁止 GPIO 4 模擬輸入模式 GPIO_PinLockConfig  鎖定 GPIO 引腳寄存器 GPIO_EventOutputConfig  選擇 GPIO 引腳作為事件輸出 GPIO_EventOutputCmd  允許或禁止事件輸出 GPIO_PinRemapConfig  改變指定引腳的影射 GPIO_EMIConfig  允許或禁止 GPIO 8 和 9 的 EMI 模式 拓展實驗:
在上面 LED 燈流水顯示的基礎之上加上按鍵程序,首先來看看按鍵的原理圖:
當然這個原理圖也是相當之簡單的,不用讀解釋了,唯一注意的是 OK 鍵與其他三個鍵的區別是按下為高電平,其余三 個按下為低電平。
加入后的完整清單如下:
//**********************************************************************
// 作者:JingYong

// 時間:2008/4/24
//***********************************************************************
/*********************************************************************** GPIO 操作,完成最簡單的 IO 操作實驗,用按鍵控制 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);
}
//延遲函數
void Delay(vu32 nCount)
{
for(; nCount != 0; nCount--);
}
//主函數
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);
}
}
}

該例子是按下不同的按鍵,閃爍對應的 LED 燈。 推挽輸出與開漏輸出的區別:
>>推挽輸出:可以輸出高,低電平,連接數字器件

STM32的 GPIO 口的輸出:開漏輸出和推挽輸出 收藏

>>開漏輸出:輸出端相當于三極管的集電極. 要得到高電平狀態需要上拉電阻才行. 適合于做電流型的驅動,其吸收電流
的能力相對強(一般20ma 以內).

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////    三極管的開漏輸出 有什么特性,和推挽是不是一回事,
問題:
很多芯片的供電電壓不一樣,有3.3v 和5.0v,需要把幾種 IC 的不同口連接在一起,是不是直接連接就可以了?實際 上系統是應用在 I2C 上面。
簡答:
1、部分3.3V 器件有5V 兼容性,可以利用這種容性直接連接
2、應用電壓轉換器件,如 TPS76733就是5V 輸入,轉換成3.3V、1A 輸出。
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
開漏電路特點及應用
在電路設計時我們常常遇到開漏(open drain)和開集(open collector)的概念。所謂開漏電路概念中提到的“漏”就 是指 MOSFET 的漏極。同理,開集電路中的“集”就是指三極管的集電極。開漏電路就是指以 MOSFET 的漏極為輸出的 電路。一般的用法是會在漏極外部的電路添加上拉電阻。完整的開漏電路應該由開漏器件和開漏上拉電阻組成。
組成開漏形式的電路有以下幾個特點:
1. 利用 外部電路的驅動能力,減少 IC 內部的驅動。當 IC 內部 MOSFET 導通時,驅動電流是從外部的 VCC 流經 R
pull-up ,MOSFET 到 GND。IC 內部僅需很下的柵極驅動電流。如圖1。
2. 可以將多個開漏輸出的 Pin,連接到一條線上。形成  “與邏輯”  關系。如圖1,當 PIN_A、PIN_B、PIN_C 任意一個變 低后,開漏線上的邏輯就為0了。這也是 I2C,SMBus 等總線判斷總線占用狀態的原理。
3. 可以利用改變上拉電源的電壓,改變傳輸電平。如圖2, IC 的邏輯電平由電源 Vcc1決定,而輸出高電平則由 Vcc2決定。 這樣我們就可以用低電平邏輯控制輸出高電平邏輯了。
4. 開漏 Pin 不連接外部的上拉電阻,則只能輸出低電平(因此對于經典的51單片機的 P0口而言,要想做輸入輸出功能必 須加外部上拉電阻,否則無法輸出高電平邏輯)。
5. 標準的開漏腳一般只有輸出的能力。添加其它的判斷電路,才能具備雙向輸入、輸出的能力。
應用中需注意:
1.    開漏和開集的原理類似,在許多應用中我們利用開集電路代替開漏電路。例如,某輸入 Pin 要求由開漏電路驅動。 則我們常見的驅動方式是利用一個三極管組成開集電路來驅動它,即方便又節省成本。如圖3。
2. 上拉電阻 R pull-up 的 阻值 決定了 邏輯電平轉換的沿的速度 。阻值越大,速度越低功耗越小。反之亦然。
Push-Pull 輸出就是一般所說的推挽輸出,在 CMOS 電路里面應該較 CMOS 輸出更合適,應為在 CMOS 里面的 push
-pull 輸出能力不可能做得雙極那么大。輸出能力看 IC 內部輸出極 N 管 P 管的面積。和開漏輸出相比,push-pull 的高 低電平由 IC 的電源低定,不能簡單的做邏輯操作等。 push-pull 是現在 CMOS 電路里面用得最多的輸出級設計方式。
at91rm9200 GPIO  模擬 I2C 接口時注意!! 一.什么是 OC、OD
集電極開路門(集電極開路 OC 或源極開路 OD)
open-drain 是漏極開路輸出的意思,相當于集電極開路(open-collector)輸出,即 ttl 中的集電極開路(oc)輸出。一般用于 線或、線與,也有的用于電流驅動。
open-drain 是對 mos 管而言,open-collector 是對雙極型管而言,在用法上沒啥區別。

開漏形式的電路有以下幾個特點:
1.利用外部電路的驅動能力,減少 IC 內部的驅動。 或驅動比芯片電源電壓高的負載.
2. 可以將多個開漏輸出的 Pin,連接到一條線上。通過一只上拉電阻,在不增加任何器件的情況下,形成“與邏輯”關系。 這也是 I2C,SMBus 等總線判斷總線占用狀態的原理。如果作為圖騰輸出必須接上拉電阻。接容性負載時,下降延是芯 片內的晶體管,是有源驅動,速度較快;上升延是無源的外接電阻,速度慢。如果要求速度高電阻選擇要小,功耗會大。 所以負載電阻的選擇要兼顧功耗和速度。
3.可以利用改變上拉電源的電壓,改變傳輸電平。例如加上上拉電阻就可以提供 TTL/CMOS 電平輸出等。
4.開漏 Pin 不連接外部的上拉電阻,則只能輸出低電平。一般來說,開漏是用來連接不同電平的器件,匹配電平用的。
5.正常的 CMOS 輸出級是上、下兩個管子,把上面的管子去掉就是 OPEN-DRAIN 了。這種輸出的主要目的有兩個:電 平轉換和線與。
6.由于漏級開路,所以后級電路必須接一上拉電阻,上拉電阻的電源電壓就可以決定輸出電平。這樣你就可以進行任意 電平的轉換了。
7. 線 與 功 能 主 要 用 于 有 多 個 電 路 對 同 一 信 號 進 行 拉 低 操 作 的 場 合 , 如 果 本 電 路 不 想 拉 低 , 就 輸 出 高 電 平 , 因為 OPEN-DRAIN 上面的管子被拿掉,高電平是靠外接的上拉電阻實現的。(而正常的 CMOS 輸出級,如果出現一個輸出為 高另外一個為低時,等于電源短路。)
8.OPEN-DRAIN 提供了靈活的輸出方式,但是也有其弱點,就是帶來上升沿的延時。因為上升沿是通過外接上拉無源電 阻對負載充電,所以當電阻選擇小時延時就小,但功耗大;反之延時大功耗小。所以如果對延時有要求,則建議用下降 沿輸出。
二.什么是線或邏輯與線與邏輯?
在一個結點(線)上, 連接一個上拉電阻到電源 VCC 或 VDD 和 n 個 NPN  或 NMOS  晶體管的集電極 C 或漏極 D, 這些晶體管的發射極 E 或源極 S  都接到地線上, 只要有一個晶體管飽和, 這個結點(線)就被拉到地線電平上. 因為這些晶體管的基極注入電流(NPN)或柵極加上高電平(NMOS),  晶體管就會飽和, 所以這些基極或柵極對這個結點 (線)的關系是或非 NOR 邏輯. 如果這個結點后面加一個反相器, 就是或 OR 邏輯.
注:個人理解:線與,接上拉電阻至電源。(~A)&(~B)=~(A+B),由公式較容易理解線與此概念的由來 ; 如果用下拉電阻和 PNP 或 PMOS  管就可以構成與非 NAND 邏輯, 或用負邏輯關系轉換與/或邏輯. 注:線或,接下拉電阻至地。(~A)+(~B)=~(AB);
這些晶體管常常是一些邏輯電路的集電極開路 OC 或源極開路 OD 輸出端. 這種邏輯通常稱為線與/線或邏輯, 當你看
到一些芯片的 OC 或 OD 輸出端連在一起, 而有一個上拉電阻時, 這就是線或/線與了, 但有時上拉電阻做在芯片的輸 入端內.
順便提示如果不是 OC 或 OD 芯片的輸出端是不可以連在一起的, 總線 BUS  上的雙向輸出端連在一起是有管理的,
同時只能有一個作輸出, 而其他是高阻態只能輸入.
三.什么是推挽結構 一般是指兩個三極管分別受兩互補信號的控制,總是在一個三極管導通的時候另一個截止.要實現線與需要用 OC(open collector)門電路  .如果輸出級的有兩個三極管,始終處于一個導通、一個截止的狀態,也就是兩個三級管推挽相連,這 樣的電路結構稱為推拉式電路或圖騰柱(Totem- pole)輸出電路(可惜,圖無法貼上)。當輸出低電平時,也就是下級負 載門輸入低電平時,輸出端的電流將是下級門灌入 T4;當輸出高電平時,也就是下級負載門輸入高電平時,輸出端的電

流將是下級門從本級電源經 T3、D1 拉出。這樣一來,輸出高低電平時,T3 一路和 T4 一路將交替工作,從而減低了 功耗,提高了每個管的承受能力。又由于不論走哪一路,管子導通電阻都很小,使 RC 常數很小,轉變速度很快。因此, 推拉式輸出級既提高電路的負載能力,又提高開關速度。供你參考。
推挽電路是兩個參數相同的三極管或 MOSFET,以推挽方式存在于電路中,各負責正負半周的波形放大任務,電路工作時, 兩只對稱的功率開關管每次只有一個導通,所以導通損耗小效率高。
輸出既可以向負載灌電流,也可以從負載抽取電流

本文來自 CSDN 博客,轉載請標明出處:http://blog.csdn.net/feiniao_lql/archive/2010/06/13/5668585.aspx


STM32時鐘控制 RCC

對于單片機系統來說,CPU 和總線以及外設的時鐘設置是非常重要的,因為沒有時鐘就沒有時序,組合電路能干什么想 必各位心里都清楚。其實時鐘的學習這部分應該提前一些,但由于一開始時間比較短,有些急于求成,所以直接使用了 萬利給的例程,姑且跳過了這一步。介于下面我計劃要學習的任務都涉及到兆級的高速傳輸,例如全速 USB,DMA 等 等,所以不能再忽略時鐘啦,必須要仔細研究一下。
我學習 RCC 的參考資料:
技術文檔0427及其中文翻譯版 STM32F10xxx_Library_Manual_ChineseV2的第十五章和 RM0008_CH 參考手冊。
準備知識:
片上總線標準種類繁多,而由 ARM 公司推出的 AMBA 片上總線受到了廣大 IP 開發商和 SoC 系統集成者的青睞,已成 為 一 種 流 行 的 工 業 標 準 片 上 結 構 。 AMBA  規 范 主 要 包 括 了 AHB(Advanced High performance  Bus) 系 統 總 線 和 APB(Advanced Peripheral Bus)外圍總線。二者分別適用于高速與相對低速設備的連接。
由于時鐘是一個由內而外的東西,具體設置要從寄存器開始。
RCC 寄存器結構,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 語言的開發可以不和他們直接打交道,當然如果 能夠加以理解和記憶,無疑是百利而無一害。
相信細心的朋友早就發現板子上只有8Mhz 的晶振,而增強型最高工作頻率為72Mhz,顯然需要用 PLL 倍頻9倍,這些設 置都需要在初始化階段完成。為了方便說明,我借用一下例程的 RCC 設置函數,并用中文注釋的形式加以說明:
/*******************************************************************************
*  Name : Set_System
* Deion    : Configures Main system clocks & power
* Input    : None.
* Return     : None.
*******************************************************************************/
//在此指出上面的注釋頭應該是復制過來的,寫錯了...不過沒關系,反正沒參數需要說明,重要的是函數體。
static void RCC_Config(void)
{
/* 這里是重置了 RCC 的設置,類似寄存器復位 */ RCC_DeInit();
/* 使能外部高速晶振 */ RCC_HSEConfig(RCC_HSE_ON);
/* 等待高速晶振穩定 */
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if (HSEStartUpStatus == SUCCESS)
{
/* 使能 flash 預讀取緩沖區 */ FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
/* 令 Flash 處于等待狀態,2是針對高頻時鐘的,這兩句跟 RCC 沒直接關系,可以暫且略過 */ FLASH_SetLatency(FLASH_Latency_2);
/* HCLK = SYSCLK 設置高速總線時鐘=系統時鐘*/ RCC_HCLKConfig(RCC_SYSCLK_Div1);

/* PCLK2 = HCLK 設置低速總線2時鐘=高速總線時鐘*/ RCC_PCLK2Config(RCC_HCLK_Div1);
/* PCLK1 = HCLK/2 設置低速總線1的時鐘=高速時鐘的二分頻*/ RCC_PCLK1Config(RCC_HCLK_Div2);
/* ADCCLK = PCLK2/6 設置 ADC 外設時鐘=低速總線2時鐘的六分頻*/ RCC_ADCCLKConfig(RCC_PCLK2_Div6);
/* Set PLL clock output to 72MHz using HSE (8MHz) as entry clock */
//上面這句例程中缺失了,但卻很關鍵
/* 利用鎖相環講外部8Mhz 晶振9倍頻到72Mhz */ RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
/* 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 FSMC, GPIOD, GPIOE, GPIOF, GPIOG and AFIO clocks */
//使能外圍接口總線時鐘,注意各外設的隸屬情況,不同芯片的分配不同,到時候查手冊就可以
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE | RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG | RCC_APB2Periph_AFIO, ENABLE);
}
由上述程序可以看出系統時鐘的設定是比較復雜的,外設越多,需要考慮的因素就越多。同時這種設定也是有規律可循 的,設定參數也是有順序規范的,這是應用中應當注意的,例如 PLL 的設定需要在使能之前,一旦 PLL 使能后參數不 可更改。

經過此番設置后,由于我的電路板上是8Mhz 晶振,所以系統時鐘為72Mhz,高速總線和低速總線2都為72Mhz,低速總 線1為36Mhz,ADC 時鐘為12Mhz,USB 時鐘經過1.5分頻設置就可以實現48Mhz 的數據傳輸。
一般性的時鐘設置需要先考慮系統時鐘的來源,是內部 RC 還是外部晶振還是外部的振蕩器,是否需要 PLL。然后考慮 內部總線和外部總線,最后考慮外設的時鐘信號。遵從先倍頻作為 CPU 時鐘,然后在由內向外分頻,下級遷就上級的原 則有點兒類似 PCB 制圖的規范化要求,在這里也一樣。

(原文件名:STM32系統時鐘框圖.gif)
引用圖片

STM32的時鐘系統分析

在 STM32中,有五個時鐘源,為 HSI、HSE、LSI、LSE、PLL。
①、HSI 是高速內部時鐘,RC 振蕩器,頻率為8MHz。
②、HSE 是高速外部時鐘,可接石英/陶瓷諧振器,或者接外部時鐘源,頻率范圍為4MHz~16MHz。
③、LSI 是低速內部時鐘,RC 振蕩器,頻率為40kHz。
④、LSE 是低速外部時鐘,接頻率為32.768kHz 的石英晶體。
⑤、PLL 為鎖相環倍頻輸出,其時鐘輸入源可選擇為 HSI/2、HSE 或者 HSE/2。倍頻可選擇為2~16倍,但是其輸出 頻率最大不得超過72MHz。
其中40kHz 的 LSI 供獨立看門狗 IWDG 使用,另外它還可以被選擇為實時時鐘  RTC 的時鐘源。另外,實時時鐘 RTC
的時鐘源還可以選擇 LSE,或者是 HSE 的128分頻。RTC 的時鐘源通過 RTCSEL[1:0]來選擇。
STM32中有一個全速功能的 USB 模塊,其串行接口引擎需要一個頻率為48MHz  的時鐘源。該時鐘源只能從 PLL 輸 出端獲取,可以選擇為1.5分頻或者1分頻,也就是,當需要使用  USB 模塊時,PLL 必須使能,并且時鐘頻率配置為48MHz 或72MHz。
另外,STM32還可以選擇一個時鐘信號輸出到 MCO 腳(PA8)上,可以選擇為 PLL 輸出的2分頻、HSI、HSE、或者系 統時鐘。
系統時鐘 SYSCLK,它是供 STM32中絕大部分部件工作的時鐘源。系統時鐘可選擇為  PLL 輸出、HSI 或者 HSE。 系統時鐘最大頻率為72MHz,它通過 AHB 分頻器分頻后送給各模塊使用,AHB 分頻器可選擇1、2、4、8、16、64、128、

256、512分頻。其中 AHB 分頻器輸出的時鐘送給5大模塊使用:
①、送給 AHB 總線、內核、內存和 DMA 使用的 HCLK 時鐘。
②、通過8分頻后送給 Cortex 的系統定時器時鐘。
③、直接送給 Cortex 的空閑運行時鐘 FCLK。
④、送給 APB1分頻器。APB1分頻器可選擇1、2、4、8、16分頻,其輸出一路供 APB1外設使用(PCLK1,最大頻率
36MHz),另一路送給定時器(Timer)2、3、4倍頻器使用。該倍頻器可選擇1或者2倍頻,時鐘輸出供定時器2、3、4使用。
⑤、送給 APB2分頻器。APB2分頻器可選擇1、2、4、8、16分頻,其輸出一路供 APB2外設使用(PCLK2,最大頻率
72MHz),另一路送給定時器(Timer)1倍頻器使用。該倍頻器可選擇1或者2倍頻,時鐘輸出供定時器1使用。另外,APB2
分頻器還有一路輸出供 ADC 分頻器使用,分頻后送給 ADC 模塊使用。ADC 分頻器可選擇為2、4、6、8分頻。
在以上的時鐘輸出中,有很多是帶使能控制的,例如 AHB 總線時鐘、內核時鐘、各種 APB1外設、APB2外設等等。 當需要使用某模塊時,記得一定要先使能對應的時鐘。
需要注意的是定時器的倍頻器,當 APB 的分頻為1時,它的倍頻值為1,否則它的倍頻值就為2。
連接在 APB1(低速外設)上的設備有:電源接口、備份接口、CAN、USB、I2C1、I2C2、UART2、UART3、SPI2、 窗口看門狗、Timer2、Timer3、Timer4。注意 USB 模塊雖然需要一個單獨的48MHz 時鐘信號,但它應該不是供 USB 模 塊工作的時鐘,而只是提供給串行接口引擎(SIE)使用的時鐘。USB 模塊工作的時鐘應該是由 APB1提供的。
連接在 APB2(高速外設)上的設備有: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 在最后設置
/* 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);
}


基本的配置定時器的基本設置

STM32的學習心得之 TIMx(通用定時器)

1、TIM_TimeBaseStructure.TIM_Prescaler = 0x0;//時鐘預分頻數 例如:時鐘頻率=72/(時鐘預分頻+1)
2、TIM_TimeBaseStructure.TIM_CounterMode = TIM1_CounterMode_Up; //定時器模式 向上計數
3、TIM_TimeBaseStructure.TIM_Period = 0xFFFF; // 自動重裝載寄存器周期的值(定時時間) 累計 0xFFFF 個頻率后產生 個更新或者中斷(也是說定時時間到)
4、TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //時間分割值
5、TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);//初始化定時器2
6、TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //打開中斷 溢出中斷
7、TIM_Cmd(TIM2, ENABLE);//打開定時器 此外要記住一定要打開定時器的時鐘(RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);),定時器的頻率的
可以編程的,有對應的模式設置和中斷處理。
STM32學習筆記之 串口通訊 主要功能是把 PC 機發送的數據接收后再返回給 PC 機參數9600,8,1,N。
/************************************************************************ Copyright (c) 2008 wormchen
All rights reserved
文 件 名: main.c
說    明: 串口發送接收數據 將 PC 端發來的數據返回給 PC
主要硬件: EMSTM32V1+miniSTMV100(外部8MRC)
編譯環境: MDK3.10
當前版本: 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 請發送數據_\r\n");
while(1)
{
while(1)
{
if(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == SET)
{
USART_SendData(USART2, USART_ReceiveData(USART2));
}
}
}
}
/*************************************************
函數: void RCC_Config(void)
功能: 配置系統時鐘 參數: 無
返回: 無
**************************************************/
void RCC_Config(void)
{
ErrorStatus HSEStartUpStatus;//定義外部高速晶體啟動狀態枚舉變量 RCC_DeInit();//復位 RCC 外部設備寄存器到默認值 RCC_HSEConfig(RCC_HSE_ON); //打開外部高速晶振
HSEStartUpStatus = RCC_WaitForHSEStartUp();//等待外部高速時鐘準備好
if(HSEStartUpStatus == SUCCESS)//外部高速時鐘已經準別好
{
RCC_HCLKConfig(RCC_SYSCLK_Div1);//配置 AHB(HCLK)時鐘等于==SYSCLK RCC_PCLK2Config(RCC_HCLK_Div1); //配置 APB2(PCLK2)鐘==AHB 時鐘

RCC_PCLK1Config(RCC_HCLK_Div2);//配置 APB1(PCLK1)鐘==AHB1/2時鐘

RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//配置 PLL 時鐘 == 外部高速晶體時鐘*9
RCC_PLLCmd(ENABLE);//使能 PLL 時鐘
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) //等待 PLL 時鐘就緒
{
}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);//配置系統時鐘  = PLL 時鐘
while(RCC_GetSYSCLKSource() != 0x08) //檢查 PLL 時鐘是否作為系統時鐘
{
}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_AFIO, ENABLE);
//打開 GPIOD 和 AFIO 時鐘
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//使能串口2時鐘
}
/*************************************************
函數: void GPIO_Config(void) 功能: GPIO 配置
參數: 無 返回: 無
**************************************************/
void GPIO_Config(void)
{
//設置 RTS(PD.04),Tx(PD.05)為推拉輸出模式
GPIO_InitTypeDef GPIO_InitStructure; //定義 GPIO 初始化結構體
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;//引腳設置推拉輸出 GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化 GPIOD
//配置 CTS (PD.03),USART2 Rx (PD.06)為浮點輸入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_6; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOD, &GPIO_InitStructure);
}
/*************************************************
函數: void USART_Config(void)
功能: USART 配置

參數: 無 返回: 無
**************************************************/
void USART_Config(void)
{
USART_InitTypeDef USART_InitStructure; //定義串口初始化結構體
USART_InitStructure.USART_BaudRate = 9600;//波特率9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位數據 USART_InitStructure.USART_StopBits = USART_StopBits_1;//1個停止位 USART_InitStructure.USART_Parity = USART_Parity_No ; //無校驗位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
//禁用 RTSCTS 硬件流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//使能發送接收 USART_InitStructure.USART_Clock = USART_Clock_Disable; //串口時鐘禁止 USART_InitStructure.USART_CPOL = USART_CPOL_Low; //時鐘下降沿有效 USART_InitStructure.USART_CPHA = USART_CPHA_2Edge;//數據在第二個時鐘沿捕捉
USART_InitStructure.USART_LastBit = USART_LastBit_Disable;
//最后數據位的時鐘脈沖不輸出到 SCLK 引腳
USART_Init(USART2, &USART_InitStructure);//初始化串口2
USART_Cmd(USART2, ENABLE);//串口2使能
}
/*************************************************
函數: void Put_String(void) 功能: 向串口輸出字符串 參數: 無
返回: 無
**************************************************/
void Put_String(u8 *p)
{
while(*p)
{
USART_SendData(USART2, *p++);
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
{
}
}
}

基于 STM32的 PWM 輸出

) 初始化函數定義:
void TIM_Configuration(void);    //定義 TIM 初始化函數
d) 初始化函數調用:
TIM_Configuration();    //TIM 初始化函數調用
e)  初始化函數,不同于前面模塊,TIM 的初始化分為兩部分——基本初始化和通道初始化:
void TIM_Configuration(void)//TIM 初始化函數
{
TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;//定時器初始化結構
TIM_OCInitTypeDef    TIM_OCInitStructure;//通道輸出初始化結構
//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);            //默認參數 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;        //工作狀態 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    //設定為輸出,需要 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 初始化函數中加入  TIM 時鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g) GPIO 里面將輸入和輸出管腳模式進行設置。信號:AF_PP,50MHz。
h) 使用中斷的話在 NVIC 里添加如下代碼:
//打開 TIM2中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;    //通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;    //響應級   
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);    //獲取捕捉數值
}
}
i) 簡單應用:
//改變占空比
TIM_SetCompare4(TIM3,  變量);
j) 注意事項:
管腳的 IO 輸出模式是根據應用來定,比如如果用 PWM 輸出驅動 LED 則應該將相應管腳設為 AF_PP,否則單片機沒有 輸出。



STM32資料一(轉載)


注:下面是一些常用的代碼,網上很多但是大多注釋不全。高手看沒問題,對于我們這些新手就費勁了……所以我把這 些代碼集中,進行了逐句注釋,希望對新手們有價值。
flash:  芯片內部存儲器 flash 操作函數
我的理解——對芯片內部 flash 進行操作的函數,包括讀取,狀態,擦除,寫入等等,可以允許程序去操作 flash 上的數 據。
基礎應用1,FLASH 時序延遲幾個周期,等待總線同步操作。推薦按照單片機系統運行頻率,0—24MHz 時,取 Latency=0;
24—48MHz 時,取 Latency=1;48~72MHz 時,取 Latency=2。所有程序中必須的

用法:FLASH_SetLatency(FLASH_Latency_2);
位置:RCC 初始化子函數里面,時鐘起振之后。
基礎應用2,開啟 FLASH 預讀緩沖功能,加速 FLASH 的讀取。所有程序中必須的 用法:FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
位置:RCC 初始化子函數里面,時鐘起振之后。
3、    lib:調試所有外設初始化的函數。 我的理解——不理解,也不需要理解。只要知道所有外設在調試的時候,EWRAM 需要從這個函數里面獲得調試所需信
息的地址或者指針之類的信息。 基礎應用1,只有一個函數 debug。所有程序中必須的。 用法:    #ifdef DEBUG
debug();
#endif
位置:main 函數開頭,聲明變量之后。
4、    nvic:系統中斷管理。 我的理解——管理系統內部的中斷,負責打開和關閉中斷。 基礎應用1,中斷的初始化函數,包括設置中斷向量表位置,和開啟所需的中斷兩部分。所有程序中必須的。 用法:        void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;    //中斷管理恢復默認參數
#ifdef    VECT_TAB_RAM    //如果 C/C++ Compiler\Preprocessor\Defined symbols 中的定義了 VECT_TAB_RAM(見程 序庫更改內容的表格)
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); //則在 RAM 調試
#else    //如果沒有定義 VECT_TAB_RAM

NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);//則在 Flash 里調試
#endif    //結束判斷語句
//以下為中斷的開啟過程,不是所有程序必須的。
//NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//設置 NVIC 優先級分組,方式。
//注:一共16個優先級,分為搶占式和響應式。兩種優先級所占的數量由此代碼確定,NVIC_PriorityGroup_x 可以是0、1、
2、3、4,分別代表搶占優先級有1、2、4、8、16個和響應優先級有16、8、4、2、1個。規定兩種優先級的數量后,所有 的中斷級別必須在其中選擇,搶占級別高的會打斷其他中斷優先執行,而響應級別高的會在其他中斷執行完優先執行。
//NVIC_InitStructure.NVIC_IRQChannel = 中斷通道名; //開中斷,中斷名稱見函數庫
//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //搶占優先級
//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    //響應優先級
//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動此通道的中斷
//NVIC_Init(&NVIC_InitStructure);    //中斷初始化
}
5、    rcc:單片機時鐘管理。 我的理解——管理外部、內部和外設的時鐘,設置、打開和關閉這些時鐘。 基礎應用1:時鐘的初始化函數過程——
用法:void RCC_Configuration(void)    //時鐘初始化函數
{
ErrorStatus HSEStartUpStatus;     //等待時鐘的穩定
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 使用系統時鐘 RCC_PCLK2Config(RCC_HCLK_Div2);            //APB2(高速)為 HCLK 的一半 RCC_PCLK1Config(RCC_HCLK_Div2);            //APB1(低速)為 HCLK 的一半
//注:AHB 主要負責外部存儲器時鐘。PB2負責 AD,I/O,高級 TIM,串口1。APB1負責 DA,USB,SPI,I2C,CAN, 串口2345,普通 TIM。
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); //PLLCLK = 8MHz * 9 = 72 MH RCC_PLLCmd(ENABLE);     //啟動 PLL
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET){}    //等待 PLL 啟動 RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK); //將 PLL 設置為系統時鐘源 while (RCC_GetSYSCLKSource() != 0x08){}    //等待系統時鐘源的啟動
}
//RCC_AHBPeriphClockCmd(ABP2設備1 | ABP2設備2  |, ENABLE); //啟動 AHP 設備
//RCC_APB2PeriphClockCmd(ABP2設備1 | ABP2設備2  |, ENABLE);//啟動 ABP2設備
//RCC_APB1PeriphClockCmd(ABP2設備1 | ABP2設備2  |, ENABLE); //啟動 ABP1設備
}
6、    exti:外部設備中斷函數 我的理解——外部設備通過引腳給出的硬件中斷,也可以產生軟件中斷,19個上升、下降或都觸發。EXTI0~EXTI15連
接到管腳,EXTI 線16連接到 PVD(VDD 監視),EXTI 線17連接到 RTC(鬧鐘),EXTI 線18連接到 USB(喚醒)。

基礎應用1,設定外部中斷初始化函數。按需求,不是必須代碼。 用法: void EXTI_Configuration(void)
{
EXTI_InitTypeDef EXTI_InitStructure;            //外部設備中斷恢復默認參數 EXTI_InitStructure.EXTI_Line = 通道1|通道2; //設定所需產生外部中斷的通道,一共19個。 EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;    //產生中斷 EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //上升下降沿都觸發 EXTI_InitStructure.EXTI_LineCmd = ENABLE;         //啟動中斷的接收 EXTI_Init(&EXTI_InitStructure);    //外部設備中斷啟動
}
7、    dma:通過總線而越過 CPU 讀取外設數據
我的理解——通過 DMA 應用可以加速單片機外設、存儲器之間的數據傳輸,并在傳輸期間不影響 CPU 進行其他事情。 這對于入門開發基本功能來說沒有太大必要,這個內容先行跳過。
8、    systic:系統定時器 我的理解——可以輸出和利用系統時鐘的計數、狀態。 基礎應用1,精確計時的延時子函數。推薦使用的代碼。 用法:
static vu32 TimingDelay;    //全 局變量聲明
void    SysTick_Config(void)
//systick 初始化函數
{
SysTick_CounterCmd(SysTick_Counter_Disable);    //停止系統定時器
SysTick_ITConfig(DISABLE); //停止 systick 中斷

SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //systick 使用 HCLK 作為時鐘源,頻率值除以8。
SysTick_SetReload(9000);    //重置時間1
毫秒(以72MHz 為基礎計算)
SysTick_ITConfig(ENABLE);    //開啟 systic 中 斷
}
void Delay (u32 nTime)    //
延遲一毫秒的函數
{
SysTick_CounterCmd(SysTick_Counter_Enable);    //systic 開始計時
TimingDelay = nTime;    //計時長度賦值給遞減變量
while(TimingDelay != 0); //檢測是否計時完成
SysTick_CounterCmd(SysTick_Counter_Disable);    //關閉計數器
SysTick_CounterCmd(SysTick_Counter_Clear);    //清除計數值
}
void TimingDelay_Decrement(void) //遞減變量函數,函數名由“stm32f10x_it.c”中的中斷響應函數定義好了。
{
if (TimingDelay != 0x00) //檢測計數變量是否達到0
{ TimingDelay--; //計數變量遞減
}
}
注:建議熟練后使用,所涉及知識和設備太多,新手出錯的可能性比較大。新手可用簡化的延時函數代替:
void Delay(vu32 nCount)    //簡 單延時函數

{
for(; nCount != 0; nCount--);    //循 環變量遞減計數
}
當延時較長,又不需要精確計時的時候可以使用嵌套循環:
void Delay(vu32 nCount)    //簡單的長時間延時函數
{int i; //聲明內部遞減變量
for(; nCount != 0; nCount--)    //遞減變量計數
{for (i=0; i<0xffff; i++)}    //
內部循環遞減變量計數
}
9、    gpio:I/O 設置函數 我的理解——所有輸入輸出管腳模式設置,可以是上下拉、浮空、開漏、模擬、推挽模式,頻率特性為2M,10M,50M。
也可以向該管腳直接寫入數據和讀取數據。 基礎應用1,gpio 初始化函數。所有程序必須。 用法:void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;    //GPIO 狀態恢復默認參數
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 參數為:ALL,2MHz,FLATING。如果其中任意 一行與前一組相應設置相同,那么那一行可以省略,由此推論如果前面已經將此行參數設定為默認參數(包括使 用

GPIO_InitTypeDef GPIO_InitStructure 代碼),本組應用也是默認參數的話,那么也可以省略。以下重復這個過程直到所 有應用的管腳全部被定義完畢。
……
}
基礎應用2,向管腳寫入0或1
用法:GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)0x01);      //寫入1
基礎應用3,從管腳讀入0或1
用法:GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_6)

讓它跑起來,基本硬件功能的建立
0、 實驗之前的準備
a)  接通串口轉接器
b) 下載 IO 與串口的原廠程序,編譯通過保證調試所需硬件正常。
1、 flash,lib,nvic,rcc 和 GPIO,基礎程序庫編寫
a) 這幾個庫函數中有一些函數是關于芯片的初始化的,每個程序中必用。為保障程序品質,初學階段要求嚴格遵守官方 習慣。注意,官方程序庫例程中有個 platform_config.h 文件,是專門用來指定同類外設中第幾號外設被使用,就是說在 main.c 里面所有外設序號用 x 代替,比如 USARTx,程序會到這個頭文件中去查找到底是用那些外設,初學的時候參考 例程別被這個所迷惑住。
b) 全部必用代碼取自庫函數所帶例程,并增加逐句注釋。
c) 習慣順序——Lib(debug),RCC(包括 Flash 優化),NVIC,GPIO
d) 必用模塊初始化函數的定義:
void RCC_Configuration(void); //定義時鐘初始化函數
void GPIO_Configuration(void); //定義管腳初始化函數
void NVIC_Configuration(void); //定義中斷管理初始化函數

void Delay(vu32 nCount); //定義延遲函數 e) Main 中的初始化函數調用: RCC_Configuration(); //時鐘初始化函數調用 NVIC_Configuration(); //中斷初始化函數調用 GPIO_Configuration(); //管腳初始化函數調用 f) Lib 注意事項:
屬于 Lib 的 Debug 函數的調用,應該放在 main 函數最開始,不要改變其位置。
g) RCC 注意事項:
Flash 優化處理可以不做,但是兩句也不難也不用改參數…… 根據需要開啟設備時鐘可以節省電能 時鐘頻率需要根據實際情況設置參數
h) NVIC 注意事項 注意理解占先優先級和響應優先級的分組的概念 i) GPIO 注意事項
注意以后的過程中收集不同管腳應用對應的頻率和模式的設置。 作為高低電平的 I/O,所需設置:RCC 初始化里面打開 RCC_APB2
PeriphClockCmd(RCC_APB2Periph_GPIOA);GPIO 里面管腳設定:IO 輸出(50MHz,Out_PP);IO 輸入(50MHz,IPU);
j) GPIO 應用
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 函數
void Delay(vu32 nCount)//簡單延時函數
{for(; nCount != 0; nCount--);}
實驗步驟:
RCC 初 始 化 函 數 里 添 加 : RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1  |   RCC_APB2Periph_GPIOA  | RCC_APB2Periph_GPIOB , ENABLE);
不用其他中斷,NVIC 初始化函數不用改
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);    //初始化
簡單的延遲函數:
void Delay(vu32 nCount)    //簡單延時函數
{ for (; nCount != 0; nCount--);}    //循環計數延時 完成之后再在 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 (3)

STM32筆記之八:來跟 PC 打個招呼,基本串口通訊
a)  目的:在基礎實驗成功的基礎上,對串口的調試方法進行實踐。硬件代碼順利完成之后,對日后調試需要用到的
printf 重定義進行調試,固定在自己的庫函數中。
b) 初始化函數定義:
void USART_Configuration(void);    //定義串口初始化函數
c) 初始化函數調用:
void UART_Configuration(void); //串口初始化函數調用 初始化代碼:
void USART_Configuration(void)    //串口初始化函數
{
//串口參數初始化
USART_InitTypeDef USART_InitStructure;    //串口設置恢復默認參數
//初始化參數設置
USART_InitStructure.USART_BaudRate = 9600;    //波特率9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //字長8位 USART_InitStructure.USART_StopBits = USART_StopBits_1;      //1位停止字節 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 發送功能
USART_Init(USART1, &USART_InitStructure);    //初始化
USART_Cmd(USART1, ENABLE);    //啟動串口
}
RCC 中打開相應串口

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE);
GPIO 里面設定相應串口管腳模式
//串口1的管腳初始化
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;    //管腳9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;    //復用推挽輸出
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) 簡單應用: 發送一位字符
USART_SendData(USART1, 數據); //發送一位數據
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發送完畢 接收一位字符
while(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){} //等待接收完畢 變量= (USART_ReceiveData(USART1)); //接受一個字節
發送一個字符串 先定義字符串:char rx_data[250];
然后在需要發送的地方添加如下代碼
int i;     //定義循環變量
while(rx_data!='\0')    //循環逐字輸出,到結束字'\0'
{USART_SendData(USART1,  rx_data);    //發送字符

while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待字符發送完畢
i++;}
e) USART 注意事項: 發動和接受都需要配合標志等待。 只能對一個字節操作,對字符串等大量數據操作需要寫函數 使用串口所需設置:RCC 初始化里面打開 RCC_APB2PeriphClockCmd
(RCC_APB2Periph_USARTx);GPIO 里面管腳設定:串口 RX(50Hz,IN_FLOATING);串口 TX(50Hz,AF_PP);
f) printf 函數重定義(不必理解,調試通過以備后用)
(1) 需要 c 標準函數:
#i nclude "stdio.h"
(2) 粘貼函數定義代碼
#define PUTCHAR_PROTOTYPE int   io_putchar(int ch)    //定義為 putchar 應用
(3) RCC 中打開相應串口
(4) GPIO 里面設定相應串口管腳模式
(6) 增加為 putchar 函數。
int putchar(int c)    //putchar 函數
{
if (c == '\n'){putchar('\r');}    //將 printf 的\n 變成\r USART_SendData(USART1, c);            //發送字符 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){} //等待發送結束 return c;        //返回值
}

(8) 通過,試驗成功。printf 使用變量輸出:%c 字符,%d 整數,%f 浮點數,%s 字符串,/n 或/r 為換行。注意:只
能用于 main.c 中。
3、 NVIC 串口中斷的應用
a)  目的:利用前面調通的硬件基礎,和幾個函數的代碼,進行串口的中斷輸入練習。因為在實際應用中,不使用中 斷進行的輸入是效率非常低的,這種用法很少見,大部分串口的輸入都離不開中斷。
b) 初 始 化 函 數 定 義 及 函 數 調 用 : 不 用 添 加 和 調 用 初 始 化 函 數 , 在 指 定 調 試 地 址 的 時 候 已 經 調 用 過 , 在 那 個
NVIC_Configuration 里面添加相應開中斷代碼就行了。
c) 過程:
i. 在串口初始化中 USART_Cmd 之前加入中斷設置:
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);//TXE 發送中斷,TC 傳輸完成中斷,RXNE 接收中斷,PE
奇偶錯誤中斷,可以是多個。
ii. RCC、GPIO 里面打開串口相應的基本時鐘、管腳設置
iii. NVIC 里面加入串口中斷打開代碼: NVIC_InitTypeDef NVIC_InitStructure;//中斷默認參數 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;//通道設置為串口1中斷 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //中斷占先等級0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;    //中斷響應優先級0
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;    //打開中斷
NVIC_Init(&NVIC_InitStructure);    //初始化
iv. 在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數,在其中添入執行代碼。一般最少三個步驟:先使用
if 語句判斷是發生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。
void USART1_IRQHandler(void)    //串口1中斷
{
char RX_dat;     //定義字符變量

if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)     //判斷發生接收中斷
{USART_ClearITPendingBit(USART1,    USART_IT_RXNE);     //清除中斷標志
GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)0x01);    //開始傳輸 RX_dat=USART_ReceiveData(USART1) & 0x7F;        //接收數據,整理除去前兩位 USART_SendData(USART1, RX_dat);             //發送數據 while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET){}//等待發送結束
}
}
d) 中斷注意事項:
可以隨時在程序中使用 USART_ITConfig(USART1, USART_IT_TXE, DISABLE);來關閉中斷響應。 NVIC_InitTypeDef NVIC_InitStructure 定義一定要加在 NVIC 初始化模塊的第一句。 全局變量與函數的定義:在任意.c 文件中定義的變量或函數,在其它.c 文件中使用 extern+定義代碼再次定義就可以
直接調用了。
STM32筆記之九:打斷它來為我辦事,EXIT (外部 I/O 中斷)應用
a)  目的:跟串口輸入類似,不使用中斷進行的 IO 輸入效率也很低,而且可以通過 EXTI 插入按鈕事件,本節聯系
EXTI 中斷。
b) 初始化函數定義:
void EXTI_Configuration(void); //定義 IO 中斷初始化函數
c) 初始化函數調用:
EXTI_Configuration();//IO 中斷初始化函數調用簡單應用:
d) 初始化函數:
void EXTI_Configuration(void)
{ EXTI_InitTypeDef EXTI_InitStructure; //EXTI 初始化結構定義

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;//觸發模式 EXTI_InitStructure.EXTI_Line = EXTI_Line3 | EXTI_Line4; //線路選擇 EXTI_InitStructure.EXTI_LineCmd = ENABLE;//啟動中斷 EXTI_Init(&EXTI_InitStructure);//初始化
}
e) RCC 初始化函數中開啟 I/O 時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); GPIO 初始化函數中定義輸入 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 的初始化函數里面增加以下代碼打開相關中斷: NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQChannel; //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占先級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //響應級

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //啟動
NVIC_Init(&NVIC_InitStructure); //初始化
g) 在 stm32f10x_it.c 文件中找到 void USART1_IRQHandler 函數,在其中添入執行代碼。一般最少三個步驟:先使用
if 語句判斷是發生那個中斷,然后清除中斷標志位,最后給字符串賦值,或做其他事情。
if(EXTI_GetITStatus(EXTI_Line3) != RESET)     //判斷中斷發生來源
{ EXTI_ClearITPendingBit(EXTI_Line3);       //清除中斷標志 USART_SendData(USART1, 0x41);    //發送字符“a” GPIO_WriteBit(GPIOB, GPIO_Pin_2, (BitAction)(1-GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_2)));//LED  發 生 明 暗
交替
}
h) 中斷注意事項: 中斷發生后必須清除中斷位,否則會出現死循環不斷發生這個中斷。然后需要對中斷類型進行判斷再執行代碼。 使用 EXTI 的 I/O 中斷,在完成 RCC 與 GPIO 硬件設置之后需要做三件事:初始化 EXTI、NVIC 開中斷、編寫中斷
執行代碼。
STM32筆記之十:工作工作,PWM 輸出
a)  目的:基礎 PWM 輸出,以及中斷配合應用。輸出選用 PB1,配置為 TIM3_CH4,是目標板的 LED6控制腳。
b) 對于簡單的 PWM 輸出應用,暫時無需考慮 TIM1的高級功能之區別。
c) 初始化函數定義:
void TIM_Configuration(void);    //定義 TIM 初始化函數
d) 初始化函數調用:
TIM_Configuration();    //TIM 初始化函數調用
e)  初始化函數,不同于前面模塊,TIM 的初始化分為兩部分——基本初始化和通道初始化:
void TIM_Configuration(void)//TIM 初始化函數
{

TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;//定時器初始化結構
TIM_OCInitTypeDef    TIM_OCInitStructure;//通道輸出初始化結構
//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);            //默認參數 TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;        //工作狀態 TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    //設定為輸出,需要 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 初始化函數中加入  TIM 時鐘開啟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM3, ENABLE);
g) GPIO 里面將輸入和輸出管腳模式進行設置。信號:AF_PP,50MHz。

h) 使用中斷的話在 NVIC 里添加如下代碼:
//打開 TIM2中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;    //通道 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//占先級 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;        //響應級 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);    //獲取捕捉數值
}
}
i) 簡單應用:
//改變占空比 TIM_SetCompare4(TIM3,  變量); j) 注意事項:

管腳的 IO 輸出模式是根據應用來定,比如如果用 PWM 輸出驅動 LED 則應該將相應管腳設為 AF_PP,否則單片機 沒有輸出
我的測試程序可以發出不斷循環三種波長并捕獲,對比結果如下: 捕捉的穩定性很好,也就是說,同樣的方波捕捉到數值相差在一兩個數值。 捕捉的精度跟你設置的濾波器長度有關,在這里
TIM_ICInitStructure.TIM_ICFilter = 0x4;    //濾波設置,經歷幾個周期跳變認定波形穩定0x0~0xF
這個越長就會捕捉數值越小,但是偏差幾十個數值,下面是0、4、16個周期濾波的比較,out 是輸出的數值,in 是捕 捉到的。
現在有兩個疑問:
1、在 TIM2的捕捉輸入通道初始化里面這句
TIM_SelectInputTrigger(TIM2, TIM_TS_TI2FP2); //選擇時鐘觸發源
按照硬件框圖,4通道應該對應 TI4FP4。可是實際使用 TI1FP1,TI2FP2都行,其他均編譯錯誤未注冊。這是為什么?
2、關閉調試器和 IAR 程序,直接供電跑出來的結果第一個周期很正常,當輸出脈寬第二次循環變小后捕捉的數值就 差的遠了。不知道是為什么


時鐘不息工作不止,systic 時鐘應用
a)  目的:使用系統時鐘來進行兩項實驗——周期執行代碼與精確定時延遲。
b) 初始化函數定義:
void SysTick_Configuration(void);
c) 初始化函數調用:
SysTick_Configuration();
d) 初始化函數:

void SysTick_Configuration(void)
{
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);//時鐘除8
SysTick_SetReload(250000);        //計數周期長度 SysTick_CounterCmd(SysTick_Counter_Enable);    //啟動計時器 SysTick_ITConfig(ENABLE);            //打開中斷
}
e)  在 NVIC 的初始化函數里面增加以下代碼打開相關中斷:
NVIC_SystemHandlerPriorityConfig(SystemHandler_SysTick, 1, 0);//中斷等級設置,一般設置的高一些會少受其他影響
f) 在 stm32f10x_it.c 文件中找到 void SysTickHandler  函數
void SysTickHandler(void)
{
執行代碼
}
g) 簡單應用:精確延遲函數,因為 systic 中斷往往被用來執行周期循環代碼,所以一些例程中使用其中斷的啟動和 禁止來編寫的精確延時函數實際上不實用,我自己編寫了精確計時函數反而代碼更精簡,思路更簡單。思路是調用 后,變量清零,然后使用時鐘來的曾變量,不斷比較變量與延遲的數值,相等則退出函數。代碼和步驟如下:
i. 定義通用變量:u16 Tic_Val=0; //變量用于精確計時
ii.  在 stm32f10x_it.c 文件中相應定義:
extern u16 Tic_Val;//在本文件引用 MAIN.c 定義的精確計時變量
iii.  定義函數名稱:void Tic_Delay(u16 Tic_Count);//精確延遲函數
iv. 精確延時函數:

void Tic_Delay(u16 Tic_Count)    //精確延時函數
{ Tic_Val=0;    //變量清零
while(Tic_Val != Tic_Count){printf("");}//計時
}
v.  在 stm32f10x_it.c 文件中 void SysTickHandler  函數里面添加
Tic_Val++;//變量遞增
vi. 調用代碼:Tic_Delay(10); //精確延時
vii.  疑問:如果去掉計時行那個沒用的 printf("");函數將停止工作,這個現象很奇怪
C 語言功底問題。是的,那個“注意事項”最后的疑問的原因就是這個
Tic_Val 應該改為 vu16
while(Tic_Val != Tic_Count){printf("");}//計時 就可以改為:
while(Tic_Val != Tic_Count);    //檢查變量是否計數到位
STM32筆記之十三:惡搞,兩只看門狗 a)  目的: 了解兩種看門狗(我叫它:系統運行故障探測器和獨立系統故障探測器,新手往往被這個并不形象的象形名稱搞糊
涂)之間的區別和基本用法。
b) 相同: 都是用來探測系統故障,通過編寫代碼定時發送故障清零信號(高手們都管這個代碼叫做“喂狗”),告訴它系統運行
正常。一旦系統故障,程序清零代碼(“喂狗”)無法執行,其計數器就會計數不止,直到記到零并發生故障中斷(狗 餓了開始叫喚),控制 CPU 重啟整個系統(不行啦,開始咬人了,快跑……)。
c) 區別:
獨立看門狗 Iwdg——我的理解是獨立于系統之外,因為有獨立時鐘,所以不受系統影響的系統故障探測器 。(這條 狗是借來的,見誰偷懶它都咬!)主要用于監視硬件錯誤。

窗口看門狗 wwdg——我的理解是系統內部的故障探測器,時鐘與系統相同。如果系統時鐘不走了,這個狗也就失去 作用了。(這條狗是老板娘養的,老板不干活兒他不管!)主要用于監視軟件錯誤。
d) 初始化函數定義:鑒于兩只狗作用差不多,使用過程也差不多初始化函數栓一起了,用的時候根據情況刪減。
void WDG_Configuration(void);
e)  初始化函數調用:
WDG_Configuration();
f) 初始化函數
void WDG_Configuration()    //看門狗初始化
{
//軟件看門狗初始化
WWDG_SetPrescaler(WWDG_Prescaler_8); //時鐘8分頻4ms
// (PCLK1/4096)/8= 244 Hz (~4 ms) WWDG_SetWindowValue(65);    //計數器數值
WWDG_Enable(127);    //啟動計數器,設置喂狗時間
// 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);        //計數器數值 IWDG_ReloadCounter();    //重啟計數器
IWDG_Enable();    //啟動看門狗

}
g) RCC 初始化:只有軟件看門狗需要時鐘初始化,獨立看門狗有自己的時鐘不需要但是需要 systic 工作相關設置。
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;    //響應中斷優先級 NVIC_Init(&NVIC_InitStructure);      //打開中斷
i)  中斷程序,軟件看門狗在自己的中斷中喂狗,獨立看門狗需要使用 systic 的定時中斷來喂狗。以下兩個程序都在
stm32f10x_it.c 文件中。
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(0x7F);     //更新計數值
WWDG_ClearFlag();    //清除標志位
}
void SysTickHandler(void)
{    IWDG_ReloadCounter();    //重啟計數器(喂狗)
}
j) 注意事項:
i. 有狗平常沒事情可以不理,但是千萬別忘了喂它,否則死都不知道怎么死的!
ii.  初始化程序的調用一定要在 systic 的初始化之后。
iii.  獨立看門狗需要 systic 中斷來喂,但是 systic 做別的用處不能只做這件事,所以我寫了如下幾句代碼,可以不影

響 systic 的其他應用,其他 systic 周期代碼也可參考: 第一步:在 stm32f10x_it.c 中定義變量
int Tic_IWDG;      //喂狗循環程序的頻率判斷變量 第二步:將 SysTickHandler 中喂狗代碼改為下面: Tic_IWDG++;    //變量遞增
if(Tic_IWDG>=100)    //每100個 systic 周期喂狗
{    IWDG_ReloadCounter();//重啟計數器(喂狗)
Tic_IWDG=0;    //變量清零
}

完整的pdf格式文檔51黑下載地址(共87頁):
深入淺出STM32系列ARM_Cortex-M3.pdf (408.48 KB, 下載次數: 54)


評分

參與人數 1黑幣 +50 收起 理由
admin + 50 共享資料的黑幣獎勵!

查看全部評分

分享到:  QQ好友和群QQ好友和群 QQ空間QQ空間 騰訊微博騰訊微博 騰訊朋友騰訊朋友
收藏收藏2 分享淘帖 頂 踩
回復

使用道具 舉報

沙發
ID:611159 發表于 2019-9-13 11:55 | 只看該作者
好東西。下不了
回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

手機版|小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 奇米四色影视 | 国产精品久久久久久久7777 | 成人欧美一区二区三区黑人孕妇 | 天天干成人网 | 久久99深爱久久99精品 | 国产成人精品a视频一区www | 国产精品一区二区久久久久 | av天天爽| 国产精品久久久久永久免费观看 | 一级a性色生活片久久毛片 一级特黄a大片 | 午夜影院在线观看 | 精品国产一区二区三区观看不卡 | 欧美天堂在线 | 麻豆久久久久 | 波多野结衣中文视频 | 一级毛片视频在线观看 | 久久1区 | 99精品一区二区 | 精品自拍视频 | 精品国产亚洲一区二区三区大结局 | 91大神xh98xh系列全部 | 国产精品视频一二三区 | 成人国产免费视频 | 国产视频一区二区在线观看 | 国产精品一区一区三区 | 一级做a爰片性色毛片 | 天天操天天干天天爽 | 国产国拍亚洲精品av | a黄毛片| www.一区二区三区.com | 色橹橹欧美在线观看视频高清 | a级毛片国产 | 不卡一区| 一二三区在线 | av在线播放不卡 | 特级特黄特色的免费大片 | 中文字幕成人在线 | 日本午夜视频 | 91国产精品 | 午夜手机在线 | 久久久精品天堂 |