單芯片解決方案,開啟全新體驗——W55MH32 高性能以太網單片機
W55MH32是WIZnet重磅推出的高性能以太網單片機,它為用戶帶來前所未有的集成化體驗。這顆芯片將強大的組件集于一身,具體來說,一顆W55MH32內置高性能Arm? Cortex-M3核心,其主頻最高可達216MHz;配備1024KB FLASH與96KB SRAM,滿足存儲與數據處理需求;集成TOE引擎,包含WIZnet全硬件TCP/IP協議棧、內置MAC以及PHY,擁有獨立的32KB以太網收發緩存,可供8個獨立硬件socket使用。如此配置,真正實現了All-in-One解決方案,為開發者提供極大便利。
在封裝規格上,W55MH32 提供了兩種選擇:QFN100和QFN68。
W55MH32L采用QFN100封裝版本,尺寸為12x12mm,其資源豐富,專為各種復雜工控場景設計。它擁有66個GPIO、3個ADC、12通道DMA、17個定時器、2個I2C、5個串口、2個SPI接口(其中1個帶I2S接口復用)、1個CAN、1個USB2.0以及1個SDIO接口。如此豐富的外設資源,能夠輕松應對工業控制中多樣化的連接需求,無論是與各類傳感器、執行器的通信,還是對復雜工業協議的支持,都能游刃有余,成為復雜工控領域的理想選擇。 同系列還有QFN68封裝的W55MH32Q版本,該版本體積更小,僅為8x8mm,成本低,適合集成度高的網關模組等場景,軟件使用方法一致。更多信息和資料請進入http://www.w5500.com/網站或者私信獲取。
此外,本W55MH32支持硬件加密算法單元,WIZnet還推出TOE+SSL應用,涵蓋TCP SSL、HTTP SSL以及 MQTT SSL等,為網絡通信安全再添保障。
為助力開發者快速上手與深入開發,基于W55MH32L這顆芯片,WIZnet精心打造了配套開發板。開發板集成WIZ-Link芯片,借助一根USB C口數據線,就能輕松實現調試、下載以及串口打印日志等功能。開發板將所有外設全部引出,拓展功能也大幅提升,便于開發者全面評估芯片性能。
若您想獲取芯片和開發板的更多詳細信息,包括產品特性、技術參數以及價格等,歡迎訪問官方網頁:http://www.w5500.com/,我們期待與您共同探索W55MH32的無限可能。
第十二章 SysTick——系統定時器
本章參考資料《Cortex-M3內核編程手冊》-4.5 章節SysTick Timer(STK),和4.48章節SHPRx, 其中STK這個章節有SysTick的簡介和寄存器的詳細描述。因為SysTick是屬于CM3內核的外設, 有關寄存器的定義和部分庫函數都在core_CM3.h這個頭文件中實現。所以學習SysTick的時候可以參考這兩個資料,一個是文檔,一個是源碼。
1 SysTick簡介
SysTick—系統定時器是屬于CM3內核中的一個外設,內嵌在NVIC中。系統定時器是一個24bit的向下遞減的計數器, 計數器每計數一次的時間為1/SYSCLK,一般我們設置系統時鐘SYSCLK等于72M。當重裝載數值寄存器的值遞減到0的時候,系統定時器就產生一次中斷,以此循環往復。
因為SysTick是屬于CM3內核的外設,所以所有基于CM3內核的單片機都具有這個系統定時器,使得軟件在CM3單片機中可以很容易的移植。 系統定時器一般用于操作系統,用于產生時基,維持操作系統的心跳。
2 SysTick寄存器介紹
SysTick—系統定時器有4個寄存器,簡要介紹如下。在使用SysTick產生定時的時候,只需要配置前三個寄存器,最后一個校準寄存器不需要使用。
寄存器名稱 | 寄存器描述 |
CTRL | SysTick 控制及狀態寄存器 |
LOAD | SysTick 重裝載數值寄存器 |
VAL | SysTick 當前數值寄存器 |
CALIB | SysTick 校準數值寄存器 |
位段 | 名稱 | 類型 | 復位值 | 描述 |
16 | COUNTFLAG | R/W | 0 | 如果在上次讀取本寄存器后,SysTick 已經計到了 0,則該位為 1。 |
2 | CLKSOURCE | R/W | 0 | 時鐘源選擇位,0=AHB/8,1 = 處理器時鐘 AHB |
1 | TICKINT | R/W | 0 | 1=SysTick 倒數計數到 0 時產生 SysTick 異常請求,0 = 數到 0 時無動作。也可通過讀取 COUNTFLAG 標志位確定計數器是否遞減到 0 |
0 | ENABLE | R/W | 0 | SysTick 定時器的使能位 |
位段 | 名稱 | 類型 | 復位值 | 描述 |
23:0 | RELOAD | R/W | 0 | 當倒數計數至零時,將被重裝載的值 |
位段 | 名稱 | 類型 | 復位值 | 描述 |
23:0 | CURRENT | R/W | 0 | 讀取時返回當前倒計數的值,寫它則使之清零,同時還會清除在 SysTick 控制及狀態寄存器中的 COUNTFLAG 標志 |
位段 | 名稱 | 類型 | 復位值 | 描述 |
31 | NOREF | R | 0 |
NOREF flag. Reads as zero. Indicates that a separate reference clock is provided. The frequency of this clock is HCLK/8 |
30 | SKEW | R | 1 | Reads as one. Calibration value for the 1 ms inexact timing is not known because TENMS is not known. This can affect the suitability of SysTick as a software real time clock |
23:0 | TENMS | R | 0 |
Indicates the calibration value when the SysTick counter runs on HCLK max/8 as external clock. The value is product dependent, refer to the Product Reference Manual, SysTick Calibration Value section. When HCLK is at max frequency, SysTick period is 1ms. If calibration info unknown, calculate from processor/external clock frequency. |
系統定時器的校準數值寄存器在定時實驗中不需要用到。有關各個位的描述這里引用手冊里面的英文版本,比較晦澀難懂, 暫時不知道這個寄存器用來干什么。有研究過的朋友可以交流,起個拋磚引玉的作用。
3 SysTick定時介紹
3.1 代碼分析
SysTick 屬于內核的外設,有關的寄存器定義和庫函數都在內核相關的庫文件core_cm3.h中。
SysTick配置庫函數
代碼清單:SysTick-1SysTick配置庫函數
__STATIC_INLINE uint32_t SysTick_Config(uint32_t ticks) { // 不可能的重裝載值,超出范圍 if ((ticks - 1UL) > SysTick_LOAD_RELOAD_Msk) { return (1UL); } // 設置重裝載寄存器 SysTick->LOAD = (uint32_t)(ticks - 1UL); // 設置中斷優先級 NVIC_SetPriority (SysTick_IRQn, (1UL < __NVIC_PRIO_BITS) - 1UL); // 設置當前數值寄存器 SysTick-?>VAL = 0UL; // 設置系統定時器的時鐘源為AHBCLK=72M // 使能系統定時器中斷 // 使能定時器 SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; return (0UL); }
用固件庫編程的時候我們只需要調用庫函數SysTick_Config()即可,形參ticks用來設置重裝載寄存器的值, 最大不能超過重裝載寄存器的值224,當重裝載寄存器的值遞減到0的時候產生中斷,然后重裝載寄存器的值又重新裝載往下遞減計數, 以此循環往復。緊隨其后設置好中斷優先級,最后配置系統定時器的時鐘等于AHBCLK=72M,使能定時器和定時器中斷,這樣系統定時器就配置好了,一個庫函數搞定。
SysTick_Config()庫函數主要配置了SysTick中的三個寄存器:LOAD、VAL和CTRL,有關具體的部分看代碼注釋即可。
配置SysTick中斷優先級
在SysTick_Config()庫函數還調用了固件庫函數NVIC_SetPriority()來配置系統定時器的中斷優先級,該庫函數也在core_m3.h中定義,原型如下:
__STATIC_INLINE void NVIC_SetPriority(IRQn_Type IRQn, uint32_t priority) { if ((int32_t)IRQn < 0) { SCB-?>SHP[(((uint32_t)(int32_t)IRQn) & 0xFUL)-4UL] = (uint8_t)((priority < (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } else { NVIC-?>IP[((uint32_t)(int32_t)IRQn)] = (uint8_t)((priority < (8 - __NVIC_PRIO_BITS)) & (uint32_t)0xFFUL); } }
函數首先先判斷形參IRQn的大小,如果是小于0,則表示這個是系統異常,系統異常的優先級由內核外設SCB的寄存器SHPRx控制, 如果大于0則是外部中斷,外部中斷的優先級由內核外設NVIC中的IPx寄存器控制。
因為SysTick屬于內核外設,跟普通外設的中斷優先級有些區別,并沒有搶占優先級和子優先級的說法。在W55MH32中, 內核外設的中斷優先級由內核SCB這個外設的寄存器:SHPRx(x=1.2.3)來配置。有關SHPRx寄存器的詳細描述可參考《Cortex-M3內核編程手冊》4.4.8章節。 下面我們簡單介紹下這個寄存器。
SPRH1-SPRH3是一個32位的寄存器,但是只能通過字節訪問,每8個字段控制著一個內核外設的中斷優先級的配置。在W55MH32中, 只有位7:4這高四位有效,低四位沒有用到,所以內核外設的中斷優先級可編程為:0~15,只有16個可編程優先級,數值越小,優先級越高。 如果軟件優先級配置相同,那就根據他們在中斷向量表里面的位置編號來決定優先級大小,編號越小,優先級越高。
異常 | 字段 | 寄存器描述 |
Memory management fault | PRI_4 | SHPR1 |
Bus fault | PRI_5 | SHPR1 |
Usage fault | PRI_6 | SHPR1 |
SVCall | PRI_11 | SHPR2 |
PendSV | PRI_14 | SHPR3 |
SysTick | PRI_15 | SHPR3 |
如果要修改內核外設的優先級,只需要修改下面三個寄存器對應的某個字段即可:
在系統定時器中,配置優先級為(1UL << __NVIC_PRIO_BITS) - 1UL), 其中宏__NVIC_PRIO_BITS為4,那計算結果就等于15, 可以看出系統定時器此時設置的優先級在內核外設中是最低的,如果要修改優先級則修改這個值即可,范圍為:0~15。
// 設置系統定時器中斷優先級 NVIC_SetPriority (SysTick_IRQn, (1UL < __NVIC_PRIO_BITS) - 1UL);
但是,問題來了,剛剛我們只是學習了內核的外設的優先級配置。如果我同時使用了systick和片上外設呢?而且片上外設也剛好需要使用中斷, 那systick的中斷優先級跟外設的中斷優先級怎么設置?會不會因為systick是內核里面的外設,所以它的中斷優先級就一定比內核之外的外設的優先級高?
從《W55MH32中斷應用概覽》這章我們知道,外設在設置中斷優先級的時候,首先要分組,然后設置搶占優先級和子優先級。 而systick這類內核的外設在配置的時候,只需要配置一個寄存器即可,取值范圍為0~15。既然配置方法不同,那如何區分兩者的優先級?下面舉例說明。
比如配置一個外設的中斷優先級分組為2,搶占優先級為1,子優先級也為1,systick的優先級為固件庫默認配置的15。 當我們比較內核外設和片上外設的中斷優先級的時候,我們只需要抓住NVIC的中斷優先級分組不僅對片上外設有效,同樣對內核的外設也有效。 我們把systick的優先級15轉換成二進制值就是1111(0b),又因為NVIC的優先級分組2,那么前兩位的11(0b)就是3,后兩位的11(0b)也是3。 無論從搶占還是子優先級都比我們設定的外設的優先級低。如果當兩個的軟件優先級都配置成一樣,那么就比較他們在中斷向量表中的硬件編號,編號越小,優先級越高。
SysTick初始化函數
代碼清單:SysTick-2 SysTick初始化函數
/** * @brief 啟動系統滴答定時器 SysTick * @param 無 * @retval 無 */ void SysTick_Init(void) { /* SystemFrequency / 1000 1ms中斷一次 * SystemFrequency / 100000 10us中斷一次 * SystemFrequency / 1000000 1us中斷一次 */ if (SysTick_Config(SystemCoreClock / 100000)) { /* Capture error */ while (1); } }
SysTick初始化函數由用戶編寫,里面調用了SysTick_Config()這個固件庫函數, 通過設置該固件庫函數的形參,就決定了系統定時器經過多少時間就產生一次中斷。
SysTick中斷時間的計算
SysTick定時器的計數器是向下遞減計數的,計數一次的時間TDEC=1/CLKAHB, 當重裝載寄存器中的值VALUELOAD減到0的時候,產生中斷, 可知中斷一次的時間TINT=VALUELOAD * TDEC= VALUELOAD/CLKAHB, 其中CLKAHB =72MHZ。如果設置VALUELOAD為72, 那中斷一次的時間TINT=72/72M=1us。 不過1us的中斷沒啥意義,整個程序的重心都花在進出中斷上了,根本沒有時間處理其他的任務。
SysTick_Config(SystemCoreClock / 100000)
SysTick_Config()的形我們配置為SystemCoreClock / 100000=72M/100000=720, 從剛剛分析我們知道這個形參的值最終是寫到重裝載寄存器LOAD中的, 從而可知我們現在把SysTick定時器中斷一次的時間TINT=720/72M=10us。
SysTick定時時間的計算
當設置好中斷時間TINT后,我們可以設置一個變量t,用來記錄進入中斷的次數, 那么變量t乘以中斷的時間TINT就可以計算出需要定時的時間。
SysTick定時函數
當設置好中斷時間TINT后,我們可以設置一個變量t,用來記錄進入中斷的次數, 那么變量t乘以中斷的時間TINT就可以計算出需要定時的時間。
SysTick定時函數
現在我們定義一個微秒級別的延時函數,形參為nTime,當用這個形參乘以中斷時間TINT就得出我們需要的延時時間, 其中TINT我們已經設置好為10us。關于這個函數的具體調用看注釋即可。
/** * @brief us延時程序,10us為一個單位 * @param * @arg nTime: Delay_us( 1 ) 則實現的延時為 1 * 10us = 10us * @retval 無 */ void Delay_us(__IO u32 nTime) { TimingDelay = nTime; while (TimingDelay != 0); }
函數Delay_us()中我們等待TimingDelay為0,當TimingDelay為0的時候表示延時時間到。變量TimingDelay在中斷函數中遞減, 即SysTick每進一次中斷即10us的時間TimingDelay遞減一次。
SysTick中斷服務函數
void SysTick_Handler(void) { TimingDelay_Decrement(); }
中斷復位函數調用了另外一個函數TimingDelay_Decrement(),原型如下:
/** * @brief 獲取節拍程序 * @param 無 * @retval 無 * @attention 在 SysTick 中斷函數 SysTick_Handler()調用 */ void TimingDelay_Decrement(void) { if (TimingDelay != 0x00) { TimingDelay--; } }
TimingDelay的值等于延時函數中傳進去的nTime的值,比如nTime=100000,則延時的時間等于100000*10us=1s。
我們知道,systick的counter從reload值往下遞減到0的時候,CTRL寄存器的位16:countflag會置1,且讀取該位的值可清0, 所有我們可以使用軟件查詢的方法來實現延時。具體代碼見 代碼清單:SysTick-3 和 代碼清單:SysTick-4 ,我敢肯定這樣的寫法, 初學者肯定會更喜歡,因為它直接,套路淺。
代碼清單:SysTick-3 systick 微秒級延時
void SysTick_Delay_Us( __IO uint32_t us) { uint32_t i; SysTick_Config(SystemCoreClock/1000000); for (i=0; iCTRL)&(1<16)) ); } // 關閉SysTick定時器 SysTick-?>CTRL &=~SysTick_CTRL_ENABLE_Msk; }
代碼清單:SysTick-4 systick 毫秒級延時
void SysTick_Delay_Ms( __IO uint32_t ms) { uint32_t i; SysTick_Config(SystemCoreClock/1000); for (i=0; iCTRL)&(1<16)) ); } // 關閉SysTick定時器 SysTick-?>CTRL &=~ SysTick_CTRL_ENABLE_Msk; }
在這兩個微秒和毫秒級別的延時函數中,我們還是調用了SysTick_Config這個固件庫函數,有關這個函數的說明具體見 代碼清單:SysTick-5 。 配套代碼注釋理解即可。其中SystemCoreClock是一個宏,大小為72000000,如果不想使用這個宏,也可以直接改成數字。
代碼清單:SysTick-5 systick 配置函數
// 這個 固件庫函數 在 core_cm3.h中 static __INLINE uint32_t SysTick_Config(uint32_t ticks) { // reload 寄存器為24bit,最大值為2^24 if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); // 配置 reload 寄存器的初始值 SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; // 配置中斷優先級為 1<4 -1 = 15,優先級為最低 NVIC_SetPriority (SysTick_IRQn, (1<__NVIC_PRIO_BITS) - 1); // 配置 counter 計數器的值 SysTick-?>VAL = 0; // 配置systick 的時鐘為 72M // 使能中斷 // 使能systick SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_TICKINT_Msk | SysTick_CTRL_ENABLE_Msk; return (0); }
WIZnet 是一家無晶圓廠半導體公司,成立于 1998 年。產品包括互聯網處理器 iMCU?,它采用 TOE(TCP/IP 卸載引擎)技術,基于獨特的專利全硬連線 TCP/IP。iMCU? 面向各種應用中的嵌入式互聯網設備。
WIZnet 在全球擁有 70 多家分銷商,在香港、韓國、美國設有辦事處,提供技術支持和產品營銷。
香港辦事處管理的區域包括:澳大利亞、印度、土耳其、亞洲(韓國和日本除外)。
審核編輯 黃宇
-
單片機
+關注
關注
6061文章
44866瀏覽量
646005 -
定時器
+關注
關注
23文章
3284瀏覽量
117020 -
WIZnet
+關注
關注
3文章
21瀏覽量
42362
發布評論請先 登錄
STM32 SYSTICK定時器常見問題
明德揚視頻分享點撥FPGA課程---第十二章??學習自檢方法
「正點原子STM32Mini板資料連載」第十二章 定時器中斷實驗
SysTick定時器的相關資料推薦
SysTick—系統定時器
【正點原子Linux連載】第十二章官方SDK移植試驗-摘自【正點原子】I.MX6U嵌入式Linux驅動開發指南V1.0

STM32 Systick系統定時器

SysTick 定時器

systick定時器 延時計時

【STM32】SysTick滴答定時器(delay延時函數講解)

評論