STM32的RCC(Reset and Clock Control)時鍾控制
stm32f103c8的時鍾是72MHz, stm32f401ccu6的時鍾是80M, 開發板板載兩個晶振, 一個高速一個低速
時鍾源
STM32時鍾的走向, 從時鍾源一步步分配給系統和外設, stm32系統一共有四個時鍾源, 依次是
- 高速內部時鍾(HSI): 以內部RC振盪器產生, 頻率為8Mhz,但相較於外部時鍾不穩定.
- 高速外部時鍾(HSE): 以外部晶振作為時鍾源, 晶振頻率可取范圍為4 - 16Mhz,一般采用8Mhz的晶振.
- 低速內部時鍾(LSI): 從內部RC振盪器產生, 頻率為40khz, 也是主要提供給實時時鍾模塊.
- 低速外部時鍾(LSE): 以外部晶振作為時鍾源, 主要是提供給實時時鍾模塊, 所以一般選用32.768khz,該頻率下定時器方便取整.
時鍾分倍頻路徑
以最常用的高速外部時鍾為例, 從時鍾源往下游的每一個環節:
- 最左端的OSC_OUT和OSC_IN 這兩個引腳分別連接到外部晶振的兩端
這個晶振一般為8Mhz - 第一個分頻器PLLXTPRE
在這個分頻器中, 可以選擇設置二分頻, 或者不分頻. 這里選擇不分頻 - 開關PLLSRC
這個開關可以選擇HSE或者HSI作為其時鍾輸出, 這里選擇HSE - 鎖相環/倍頻器 PLL
可以設定2到16的倍頻因子(PLLMUL), 經過PLL的時鍾稱為PLLCLK. 這里設置倍頻因子為9, 產生的PLLCLK為72Mhz- USB預分頻器, PLLCLK在輸入到SW前流向這里, 這個PLLCLK也作為USB的時鍾
- 開關SW
通過這個開關, 可以切換SYSCLK的時鍾源, 有HSI,PLLCLK,HSE三個選擇. 經過這個開關之后就是STM32的系統時鍾(SYSCLK)了. 選擇PLLCLK時鍾則SYSCLK就為72Mhz - AHB預分頻器, SYSCLK經過AHB預分頻后輸入到其他外設. 本例中AHB不分頻, 直接輸入到HCLK, FCLK或者SDIOCLK等時鍾
- AHB總線、內核、內存和DMA使用的HCLK時鍾
- 8分頻后送給Cortex系統定時器時鍾,即SysTick
- 自由運行時鍾FCLK
- APB1分頻器, PCLK1,最大頻率36MHz, 供APB1外設使用. 另一路送給定時器Timer, 1倍頻或2倍頻
- APB2分頻器, PCLK2,最大頻率72MHz, 供APB2外設使用. GPIO外設是掛載在APB2總線上的
- ADC分頻器。ADC分頻器經過2、4、6、8分頻后送給ADC1/2/3使用,ADC最大頻率為14M
- 二分頻, SDIO使用
與代碼相關的時鍾
- SYSCLK: 系統時鍾, 是STM32大部分器件的時鍾來源, 主要由AHB預分頻器分配到各個部件
- HCLK: 由AHB預分頻器直接輸出得到, 它是高速總線AHB的時鍾信號, 提供給存儲器, DMA及Cortex內核, 是Cortex內核運行的時鍾, CPU主頻就是這個信號
- FCLK: 也是由AHB輸出得到, 是內核的“自由運行時鍾”. “自由”表現在它不來自時鍾HCLK. 因此在HCLK停止時FCLK也可以繼續運行. 也就是說, 即使CPU休眠了, 也能夠采樣到外部中斷和跟蹤休眠事件. 低功耗模式下使用
- PCLK1: 外設時鍾, 由APB1分頻得到, 最大可為36Mhz, 提供給APB1總線上的外設使用
- PCLK2: 外設時鍾, 由APB2預分頻輸出得到, 最大為72Mhz, 提供給APB2總線上的外設
時鍾源使能和配置
在配置好時鍾系統之后, 如果要使用某些外設, 例如GPIO, ADC, 還要使能這些外設時鍾. 如果在使用外設之前沒有使能外設時鍾, 這個外設不能正常運行.
STM32時鍾系統的配置代碼分為兩部分, 一部分在 CMSIS 目錄下的 system_stm32f10x.c 中的SystemInit()函數, 用於初始化. 另一部分在 FWLib 目錄下的 stm32f10x_rcc.c 中, 用於操作時鍾系統. 對於系統時鍾來說, 默認情況下是在SystemInit函數的SetSysClock函數中判斷的, SetSysClock 函數的定義如下
static void SetSysClock(void)
{
#ifdef SYSCLK_FREQ_HSE
SetSysClockToHSE();
#elif defined SYSCLK_FREQ_24MHz
SetSysClockTo24();
#elif defined SYSCLK_FREQ_36MHz
SetSysClockTo36();
#elif defined SYSCLK_FREQ_48MHz
SetSysClockTo48();
#elif defined SYSCLK_FREQ_56MHz
SetSysClockTo56();
#elif defined SYSCLK_FREQ_72MHz
SetSysClockTo72();
#endif
}
這段代碼設置系統時鍾的頻率為72MHz,其宏定義為:
#define SYSCLK_FREQ_72MHz 72000000
如果想設置系統時鍾頻率為36MHz,只需注釋掉上面的宏定義,並加入如下定義即可:
#define SYSCLK_FREQ_36MHz 36000000
設置完系統時鍾后可以通過變量 SystemCoreClock 獲得系統時鍾的值,在 system_stm32f10x.c 中該變量的定義為:
#ifdef SYSCLK_FREQ_HSE
uint32_t SystemCoreClock = SYSCLK_FREQ_HSE;
#elif defined SYSCLK_FREQ_24MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_24MHz;
#elif defined SYSCLK_FREQ_36MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_36MHz;
#elif defined SYSCLK_FREQ_48MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_48MHz;
#elif defined SYSCLK_FREQ_56MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_56MHz;
#elif defined SYSCLK_FREQ_72MHz
uint32_t SystemCoreClock = SYSCLK_FREQ_72MHz;
#else /*!< HSI Selected as System Clock source */
uint32_t SystemCoreClock = HSI_VALUE;
#endif
當系統時鍾頻率設置為72MHz大小時:
- PLL時鍾:72MHz
- SYSCLK時鍾:72MHz
- AHB總線時鍾(使用SYSCLK為時鍾源):72MHz
- APB1總線時鍾:36MHz
- APB2總線時鍾:72MHz
時鍾源使能中AHB, APB1, APB2的區別
這三個對應了各自總線上的外設時鍾的開啟和關閉, 在STM32F10x中
AHB總線 RCC_AHBPeriphClockCmd
void RCC_AHBPeriphClockCmd ( uint32_t RCC_AHBPeriph, FunctionalState NewState)
RCC_AHBPeriph 可用的參數(可以是組合)
- STM32_Connectivity_line_devices
RCC_AHBPeriph_DMA1
RCC_AHBPeriph_DMA2
RCC_AHBPeriph_SRAM
RCC_AHBPeriph_FLITF
RCC_AHBPeriph_CRC
RCC_AHBPeriph_OTG_FS
RCC_AHBPeriph_ETH_MAC
RCC_AHBPeriph_ETH_MAC_Tx
RCC_AHBPeriph_ETH_MAC_Rx
- other_STM32_devices
RCC_AHBPeriph_DMA1
RCC_AHBPeriph_DMA2
RCC_AHBPeriph_SRAM
RCC_AHBPeriph_FLITF
RCC_AHBPeriph_CRC
RCC_AHBPeriph_FSMC
RCC_AHBPeriph_SDIO
Note:
SRAM and FLITF clock can be disabled only during sleep mode.
APB1總線 RCC_APB1PeriphClockCmd
void RCC_APB1PeriphClockCmd ( uint32_t RCC_APB1Periph, FunctionalState NewState)
可用參數(可以是組合)
RCC_APB1Periph_TIM2,
RCC_APB1Periph_TIM3,
RCC_APB1Periph_TIM4,
RCC_APB1Periph_TIM5,
RCC_APB1Periph_TIM6,
RCC_APB1Periph_TIM7,
RCC_APB1Periph_TIM12,
RCC_APB1Periph_TIM13,
RCC_APB1Periph_TIM14
RCC_APB1Periph_SPI2,
RCC_APB1Periph_SPI3,
RCC_APB1Periph_USART2,
RCC_APB1Periph_USART3,
RCC_APB1Periph_USART4,
RCC_APB1Periph_USART5,
RCC_APB1Periph_I2C1,
RCC_APB1Periph_I2C2,
RCC_APB1Periph_USB,
RCC_APB1Periph_CAN1,
RCC_APB1Periph_BKP,
RCC_APB1Periph_PWR,
RCC_APB1Periph_DAC,
RCC_APB1Periph_CEC,
RCC_APB1Periph_WWDG,
- USART: 除了1都是
- I2C: 都是
- SPI: 除了1都是
APB2總線 RCC_APB2PeriphClockCmd
void RCC_APB2PeriphClockCmd ( uint32_t RCC_APB2Periph, FunctionalState NewState)
可用參數(可以是組合)
RCC_APB2Periph_AFIO,
RCC_APB2Periph_GPIOA,
RCC_APB2Periph_GPIOB,
RCC_APB2Periph_GPIOC,
RCC_APB2Periph_GPIOD,
RCC_APB2Periph_GPIOE,
RCC_APB2Periph_GPIOF,
RCC_APB2Periph_GPIOG,
RCC_APB2Periph_ADC1,
RCC_APB2Periph_ADC2,
RCC_APB2Periph_ADC3,
RCC_APB2Periph_SPI1,
RCC_APB2Periph_USART1,
RCC_APB2Periph_TIM1,
RCC_APB2Periph_TIM8,
RCC_APB2Periph_TIM9,
RCC_APB2Periph_TIM10,
RCC_APB2Periph_TIM11
RCC_APB2Periph_TIM15,
RCC_APB2Periph_TIM16,
RCC_APB2Periph_TIM17,
- 所有的GPIO都是
- 所有的ADC
系統時鍾 SysTick系統定時器
STK(SysTick Timer)系統定時器
STK(SysTick Timer)系統定時器是CM3內核的外設, 內嵌在 NVIC. 系統定時器 是一個24bit的向下遞減的計數器, 計數器每計數一次的時間為 1/SYSCLK, 一般我們設置系統時鍾 SYSCLK 等於 72M. 當重裝載數值寄存器的值遞減到 0 的時候, 系統定時器就產生一次中斷, 以此循環往復. 因為 SysTick 是屬於 CM3 內核的外設, 所以所有基於 CM3 內核的單片機都具有這個 系統定時器, 使得軟件在 CM3 單片機中可以很容易的移植. 系統定時器一般用於操作系統, 用於產生時基, 維持操作系統的心跳.
SysTick Register 系統定時寄存器
SysTick—系統定時器有4個寄存器, 在使用 SysTick 產生定時的時候, 只需要配置前三個寄存器, 最后一個校准寄存器不需要使用
寄存器名稱 寄存器描述
CTRL SysTick 控制及狀態寄存器
LOAD SysTick 重裝載數值寄存器
VAL SysTick 當前數值寄存器
CALIB SysTick 校准數值寄存器
- STK_CSR控制寄存器, 寄存器低4位含義
- 第0位:ENABLE,Systick 使能位 (0:關閉Systick功能;1:開啟Systick功能)
- 第1位:TICKINT,Systick 中斷使能位(0:關閉Systick中斷;1:開啟Systick中斷)
- 第2位:CLKSOURCE,Systick時鍾源選擇 (0:使用HCLK/8 作為Systick時鍾;1:使用HCLK作為Systick時鍾)
- 第3位:COUNTFLAG,Systick計數比較標志,如果在上次讀取本寄存器后,SysTick 已經數到了0, 則該位為1, 如果讀取該位, 該位將自動清零
- STK_LOAD 重載寄存器
- Systick是一個遞減的定時器, 當定時器遞減至0時, 重載寄存器中的值就會被重裝載, 繼續開始遞減. STK_LOAD寄存器是個24位的寄存器, 最大計數0xFFFFFF
- STK_VAL當前值寄存器
也是個24位的寄存器, 讀取時返回當前倒計數的值, 寫它則使之清零, 同時還會清除在SysTick 控制及狀態寄存器中的COUNTFLAG 標志
用SysTick產生1s的時間基准, 控制LED每隔1s閃一次
流程說明
- 調用內建函數 SysTick_Config(SystemCoreClock / 100000), 就是10us產生一次SysTick中斷,
- 然后系統會去調用內建的中斷處理函數 SysTick_Handler(void), 這個函數里對 TimingDelay--,
- 在 Dealy_us() 里用while循環阻塞進程, 直到 TimingDelay 減為0才跳出阻塞
所以將 TimingDelay 變量設為多少, 就會產生多少毫秒的延遲. 在調用 Delay_us() 函數時, 傳入的數值就是要延遲的10us數
- 設置重載寄存器的值
uint32_t TimingDelay = 0;
/**
* @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);
}
}
/**
* @brief us 延時程序,10us 為一個單位
* @param
* @arg nTime: Delay_us( 1 ) 則實現的延時為 1 * 10us = 10us
* @retval 無
*/
void Delay_us(__IO uint32_t nTime)
{
TimingDelay = nTime;
while (TimingDelay != 0);
}
/**
* @brief 獲取節拍程序
* @param 無
* @retval 無
* @attention 在 SysTick 中斷函數 SysTick_Handler()調用
*/
void TimingDelay_Decrement(void)
{
if (TimingDelay != 0x00) {
TimingDelay--;
}
}
- 實現中斷服務函數 SysTick_Handler
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
TimingDelay_Decrement();
}
- 在main函數中實現LED延時亮滅
/* LED 端口初始化 */
LED_GPIO_Config();
/* 配置 SysTick 為 10us 中斷一次,時間到后觸發定時中斷,
*進入 stm32fxx_it.c 文件的 SysTick_Handler 處理,通過數中斷次數計時
*/
SysTick_Init();
while (1) {
LED1_ON;
Delay_us(100000); // 100000 * 10us = 1000ms
LED1_OFF;
LED2_ON;
Delay_us(100000); // 100000 * 10us = 1000ms
LED2_OFF;
LED3_ON;
Delay_us(100000); // 100000 * 10us = 1000ms
LED3_OFF;
}
外設時鍾 TIM1 - TIM8
STM32中一共有11個定時器
- 2個高級控制定時器: TIM1, TIM8
- 能夠產生3對PWM互補輸出的高級定時器, 常用於三相電機的驅動, 時鍾由APB2的輸出產生.
- 4個普通定時器: TIM2 - TIM5
- 16位自動重裝載計數器
- 向上計數模式: 從0開始計數, 計到 LOAD寄存器 TIMx_ARR 中的數值時, 清0, 依次循環
- 2個基本定時器: TIM6, TIM7
- 時鍾由APB1輸出產生
- 2個看門狗定時器
- 1個系統嘀嗒定時器
使用方法(TIM2時鍾)
第一步:配置系統時鍾
除此之外,還需將GPIO和TIM2外設時鍾打開。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM2是掛在APB1上的, 調用RCC_APB1PeriphClockCmd函數, 而不是RCC_APB2PeriphClockCmd
第二步:配置中斷
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
第三步:配置GPIO的模式, 輸入模式還是輸出模式
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
第四步:定時器配置
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//重新將Timer設置為缺省值
TIM_DeInit(TIM2);
//采用內部時鍾給TIM2提供時鍾源
TIM_InternalClockConfig(TIM2);
//預分頻系數為36000-1,這樣計數器時鍾為72MHz/36000 = 2kHz
TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;
//設置周期數,每計2000個數就產生一次中斷
TIM_TimeBaseStructure.TIM_Period = 2000;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
//禁止ARR預裝載緩沖器
TIM_ARRPreloadConfig(TIM2, DISABLE); //預裝載寄存器的內容被立即傳送到影子寄存器
//開啟TIM2的中斷
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
}
該函數完成兩個功能
- 設定預分頻系數TIM_Prescaler = 36000 - 1
- 設定自動重裝載值TIM_Period = 2000
注意:上述只是配置好了TIM2,但還沒有開啟TIM2。
下面是完整代碼
#include “stm32f10x_lib.h”
void RCC_Configuration(void);
void NVIC_Configuration(void);
void GPIO_Configuration(void);
void TIM2_Configuration(void);
void Delay(vu32 nCount);
int main(void)
{
#ifdef DEBUG
debug();
#endif
RCC_Configuration();
NVIC_Configuration();
GPIO_Configuration();
TIM2_Configuration();
TIM_Cmd(TIM2, ENABLE); //開啟定時器2
while (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_SetLatency(FLASH_Latency_2);
RCC_HCLKConfig(RCC_SYSCLK_Div1);
RCC_PCLK2Config(RCC_HCLK_Div1);
RCC_PCLK1Config(RCC_HCLK_Div2);
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET) {}
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08) {}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}
void NVIC_Configuration(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 4;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void TIM2_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
//重新將Timer設置為缺省值
TIM_DeInit(TIM2);
//采用內部時鍾給TIM2提供時鍾源
TIM_InternalClockConfig(TIM2);
//預分頻系數為36000-1,這樣計數器時鍾為72MHz/36000 = 2kHz
TIM_TimeBaseStructure.TIM_Prescaler = 36000 - 1;
TIM_TimeBaseStructure.TIM_Period = 2000;
//設置時鍾分割
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
//禁止ARR預裝載緩沖器
TIM_ARRPreloadConfig(TIM2, DISABLE); //預裝載寄存器的內容被立即傳送到影子寄存器
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
}
使用方法 TIM2延時
這段放在timer.c里, 將接口放到頭文件, 就可以在main中調用delay方法延時了.
void TIM2_Init(void)
{
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_DeInit(TIM2);
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_TimeBaseStructure.TIM_Prescaler = (SystemCoreClock / 2000000) - 1; // 降頻到2MHz
TIM_TimeBaseStructure.TIM_Period = 20 - 1; // (1/2M)*20 = 1/100K = 10 us
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructure);
TIM_ClearFlag(TIM2, TIM_FLAG_Update);
TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//TIM_Cmd(TIM2, ENABLE); // 開啟TIM2
printf("## TIM2 Initialized ##\r\n");
}
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) {
if(TIM2_TimingDelay != 0x00) {
TIM2_TimingDelay--;
}
}
TIM_ClearITPendingBit(TIM2, TIM_IT_Update);
}
void TIM2_Delay_10us(__IO uint32_t count)
{
TIM_Cmd(TIM2, ENABLE);
TIM2_TimingDelay = count;
while(TIM2_TimingDelay != 0);
TIM_Cmd(TIM2, DISABLE);
}
void TIM2_Delay_ms(__IO uint32_t count)
{
TIM_Cmd(TIM2, ENABLE);
TIM2_TimingDelay = count * 100;
while(TIM2_TimingDelay != 0);
TIM_Cmd(TIM2, DISABLE);
}