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

 找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 9411|回復(fù): 0
打印 上一主題 下一主題
收起左側(cè)

STM32學(xué)習(xí)筆記6:TIM模塊定時(shí)器

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:85109 發(fā)表于 2015-7-9 00:27 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
                        TIM模塊定時(shí)器向上溢出 & 輸出比較
首先我們必須肯定ST公司的實(shí)力,也承認(rèn)STM32的確是一款非常不錯(cuò)的Cortex-M3核單片機(jī),但是,他的手冊(cè)實(shí)在是讓人覺(jué)得無(wú)法理解,尤其是其中的TIM模塊,沒(méi)有條理可言,看了兩天幾乎還是不知所云,讓人很是郁悶。同時(shí)配套的固件庫(kù)的說(shuō)明也很難和手冊(cè)上的寄存器對(duì)應(yīng)起來(lái),研究起來(lái)非常費(fèi)勁!功能強(qiáng)大倒是真的,但至少也應(yīng)該配套一個(gè)讓人看的明白的說(shuō)明吧~~
兩天時(shí)間研究了STM32定時(shí)器的最最基礎(chǔ)的部分,把定時(shí)器最基礎(chǔ)的兩個(gè)功能實(shí)現(xiàn)了,余下的功能有待繼續(xù)學(xué)習(xí)。
首先有一點(diǎn)需要注意:FWLib固件庫(kù)目前的最新版應(yīng)該是V2.0.x,V1.0.x版本固件庫(kù)中,TIM1模塊被獨(dú)立出來(lái),調(diào)用的函數(shù)與其他定時(shí)器不同;在V2.0系列版本中,取消了TIM1.h,所有的TIM模塊統(tǒng)一調(diào)用TIM.h即可。網(wǎng)絡(luò)上流傳的各種代碼有許多是基于v1版本的固件庫(kù),在移植到v2版本固件庫(kù)時(shí),需要做些修改。本文的所有程序都是基于V2.0固件庫(kù)。
以下是定時(shí)器向上溢出示例代碼:
C語(yǔ)言: TIM1模塊產(chǎn)生向上溢出事件
//Step1.時(shí)鐘設(shè)置:?jiǎn)?dòng)TIM1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
//Step2.中斷NVIC設(shè)置:允許中斷,設(shè)置優(yōu)先級(jí)
NVIC_InitStructure.NVIC_IRQChannel =TIM1_UP_IRQChannel;    //更新事件
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0;   //搶占優(yōu)先級(jí)0
NVIC_InitStructure.NVIC_IRQChannelSubPriority =1;          //響應(yīng)優(yōu)先級(jí)1
NVIC_InitStructure.NVIC_IRQChannelCmd =ENABLE;             //允許中斷
NVIC_Init(&NVIC_InitStructure);                             //寫入設(shè)置
//Step3.TIM1模塊設(shè)置
void TIM_Configuration(void)
{
TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;

//TIM1 使用內(nèi)部時(shí)鐘
//TIM_InternalClockConfig(TIM1);
//TIM1基本設(shè)置
//設(shè)置預(yù)分頻器分頻系數(shù)71,即APB2=72M, TIM1_CLK=72/72=1MHz
//TIM_Period(TIM1_ARR)=1000,計(jì)數(shù)器向上計(jì)數(shù)到1000后產(chǎn)生更新事件,計(jì)數(shù)值歸零
//向上計(jì)數(shù)模式
//TIM_RepetitionCounter(TIM1_RCR)=0,每次向上溢出都產(chǎn)生更新事件
TIM_BaseInitStructure.TIM_Period = 1000;
TIM_BaseInitStructure.TIM_Prescaler = 71;
TIM_BaseInitStructure.TIM_ClockDivision = 0;
TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_BaseInitStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);
//清中斷,以免一啟用中斷后立即產(chǎn)生中斷
TIM_ClearFlag(TIM1, TIM_FLAG_Update);
//使能TIM1中斷源
TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);
//TIM1總開(kāi)關(guān):開(kāi)啟
TIM_Cmd(TIM1, ENABLE);
}
//Step4.中斷服務(wù)子程序:
void TIM1_UP_IRQHandler(void)
{
GPIOC->ODR ^=(1<<4);                         //閃燈
TIM_ClearITPendingBit(TIM1, TIM_FLAG_Update); //清中斷
}
下面是輸出比較功能實(shí)現(xiàn)TIM1_CH1管腳輸出指定頻率的脈沖:
C語(yǔ)言: TIM1模塊實(shí)現(xiàn)輸出比較,自動(dòng)翻轉(zhuǎn)并觸發(fā)中斷
//Step1.啟動(dòng)TIM1,同時(shí)還要注意給相應(yīng)功能管腳啟動(dòng)時(shí)鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
//Step2. PA.8口設(shè)置為TIM1的OC1輸出口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//Step3.使能TIM1的輸出比較匹配中斷
NVIC_InitStructure.NVIC_IRQChannel = TIM1_CC_IRQChannel;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
//Step4. TIM模塊設(shè)置
void TIM_Configuration(void)
{
    TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;

    //TIM1基本計(jì)數(shù)器設(shè)置
    TIM_BaseInitStructure.TIM_Period =0xffff;                      //這里必須是65535
    TIM_BaseInitStructure.TIM_Prescaler =71;                       //預(yù)分頻71,即72分頻,得1M
    TIM_BaseInitStructure.TIM_ClockDivision = 0;
    TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_BaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM1, &TIM_BaseInitStructure);
    //TIM1_OC1模塊設(shè)置
    TIM_OCStructInit(& TIM_OCInitStructure);
    TIM_OCInitStructure.TIM_OCMode =TIM_OCMode_Toggle;             //管腳輸出模式:翻轉(zhuǎn)
    TIM_OCInitStructure.TIM_Pulse =2000;                           //翻轉(zhuǎn)周期:2000個(gè)脈沖
    TIM_OCInitStructure.TIM_OutputState =TIM_OutputState_Enable;   //使能TIM1_CH1通道
    TIM_OCInitStructure.TIM_OCPolarity =TIM_OCPolarity_High;       //輸出為正邏輯
    TIM_OC1Init(TIM1,&TIM_OCInitStructure);                        //寫入配置
    //清中斷
    TIM_ClearFlag(TIM1, TIM_FLAG_CC1);
    //TIM1中斷源設(shè)置,開(kāi)啟相應(yīng)通道的捕捉比較中斷
    TIM_ITConfig(TIM1, TIM_IT_CC1, ENABLE);
    //TIM1開(kāi)啟
    TIM_Cmd(TIM1, ENABLE);
    //通道輸出使能
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
}
Step5.中斷服務(wù)子程序
void TIM1_CC_IRQHandler(void)
{
    u16 capture;
    if(TIM_GetITStatus(TIM1, TIM_IT_CC1) == SET)
    {
        TIM_ClearITPendingBit(TIM1, TIM_IT_CC1 );
        capture = TIM_GetCapture1(TIM1);
        TIM_SetCompare1(TIM1, capture + 2000);
        //這里解釋下:
        //將TIM1_CCR1的值增加2000,使得下一個(gè)TIM事件也需要2000個(gè)脈沖,
        //另一種方式是清零脈沖計(jì)數(shù)器
        //TIM_SetCounter(TIM2,0x0000);
    }
}
關(guān)于TIM的操作,要注意的是STM32處理器因?yàn)榈凸牡男枰髂K需要分別獨(dú)立開(kāi)啟時(shí)鐘,所以,一定不要忘記給用到的模塊和管腳使能時(shí)鐘,因?yàn)檫@個(gè)原因,浪費(fèi)了我好多時(shí)間阿~~!

九九的STM32筆記(二)TIM模塊產(chǎn)生PWM
這個(gè)是STM32的PWM輸出模式,STM32的TIM1模塊是增強(qiáng)型的定時(shí)器模塊,天生就是為電機(jī)控制而生,可以產(chǎn)生3組6路PWM,同時(shí)每組2路PWM為互補(bǔ),并可以帶有死區(qū),可以用來(lái)驅(qū)動(dòng)H橋。
下面的代碼,是利用TIM1模塊的1、2通道產(chǎn)生一共4路PWM的代碼例子,類似代碼也可以參考ST的固件庫(kù)中相應(yīng)example
C語(yǔ)言: TIM1模塊產(chǎn)生PWM,帶死區(qū)
   
//Step1.開(kāi)啟TIM和相應(yīng)端口時(shí)鐘
//啟動(dòng)GPIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB| \
                       RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\
                       ENABLE);
//啟動(dòng)AFIO
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//啟動(dòng)TIM1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
//Step2. GPIO做相應(yīng)設(shè)置,為AF輸出
//PA.8/9口設(shè)置為TIM1的OC1輸出口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PB.13/14口設(shè)置為TIM1_CH1N和TIM1_CH2N輸出口
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//Step3. TIM模塊初始化
void TIM_Configuration(void)
{
    TIM_TimeBaseInitTypeDef TIM_BaseInitStructure;
    TIM_OCInitTypeDef TIM_OCInitStructure;
    TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
    //TIM1基本計(jì)數(shù)器設(shè)置(設(shè)置PWM頻率)
    //頻率=TIM1_CLK/(ARR+1)
    TIM_BaseInitStructure.TIM_Period = 1000-1;
    TIM_BaseInitStructure.TIM_Prescaler = 72-1;
    TIM_BaseInitStructure.TIM_ClockDivision = 0;
    TIM_BaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;
    TIM_BaseInitStructure.TIM_RepetitionCounter = 0;
    TIM_TimeBaseInit(TIM1,&TIM_BaseInitStructure);
    //啟用ARR的影子寄存器(直到產(chǎn)生更新事件才更改設(shè)置)
    TIM_ARRPreloadConfig(TIM1, ENABLE);

    //TIM1_OC1模塊設(shè)置(設(shè)置1通道占空比)
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState =TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
    TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;
    TIM_OCInitStructure.TIM_Pulse = 120;
    TIM_OC1Init(TIM1, &TIM_OCInitStructure);
    //啟用CCR1寄存器的影子寄存器(直到產(chǎn)生更新事件才更改設(shè)置)
    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
    //TIM2_OC2模塊設(shè)置(設(shè)置2通道占空比)
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
    TIM_OCInitStructure.TIM_OutputNState =TIM_OutputNState_Enable;
    TIM_OCInitStructure.TIM_Pulse = 680;
    TIM_OC2Init(TIM1, &TIM_OCInitStructure);
    //啟用CCR2寄存器的影子寄存器(直到產(chǎn)生更新事件才更改設(shè)置)
    TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
  
    //死區(qū)設(shè)置
    TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable;
    TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable;
    TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_OFF;
    TIM_BDTRInitStructure.TIM_DeadTime =0x90;   //這里調(diào)整死區(qū)大小0-0xff
    TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;
    TIM_BDTRInitStructure.TIM_BreakPolarity =TIM_BreakPolarity_High;
    TIM_BDTRInitStructure.TIM_AutomaticOutput =TIM_AutomaticOutput_Enable;
    TIM_BDTRConfig(TIM1, &TIM_BDTRInitStructure);
  
    //TIM1開(kāi)啟
    TIM_Cmd(TIM1, ENABLE);
    //TIM1_OC通道輸出PWM(一定要加)
    TIM_CtrlPWMOutputs(TIM1, ENABLE);
}

其實(shí),PWM模塊還可以有很多花樣可以玩,比方在異常時(shí)(如CPU時(shí)鐘有問(wèn)題),可以緊急關(guān)閉輸出,以免發(fā)生電路燒毀等嚴(yán)重事故


《九九的STM32筆記》整理(2)


這是一個(gè)綜合的例子,演示了ADC模塊、DMA模塊和USART模塊的基本使用。
我們?cè)谶@里設(shè)置ADC為連續(xù)轉(zhuǎn)換模式,常規(guī)轉(zhuǎn)換序列中有兩路轉(zhuǎn)換通道,分別是ADC_CH10(PC0)和ADC_CH16(片內(nèi)溫度傳感器)。因?yàn)槭褂昧俗詣?dòng)多通道轉(zhuǎn)換,數(shù)據(jù)的取出工作最適合使用DMA方式取出,so,我們?cè)趦?nèi)存里開(kāi)辟了一個(gè)u16AD_Value[2]數(shù)組,并設(shè)置了相應(yīng)的DMA模塊,使ADC在每個(gè)通道轉(zhuǎn)換結(jié)束后啟動(dòng)DMA傳輸,其緩沖區(qū)數(shù)據(jù)量為2個(gè)HalfWord,使兩路通道的轉(zhuǎn)換結(jié)果自動(dòng)的分別落到AD_Value[0]和AD_Value[1]中。
然后,在主函數(shù)里,就無(wú)需手動(dòng)啟動(dòng)AD轉(zhuǎn)換,等待轉(zhuǎn)換結(jié)束,再取結(jié)果了。我們可以在主函數(shù)里隨時(shí)取AD_Value中的數(shù)值,那里永遠(yuǎn)都是最新的AD轉(zhuǎn)換結(jié)果。
如果我們定義一個(gè)更大的AD_Value數(shù)組,并調(diào)整DMA的傳輸數(shù)據(jù)量(BufferSize)可以實(shí)現(xiàn)AD結(jié)果的循環(huán)隊(duì)列存儲(chǔ),從而可以進(jìn)行各種數(shù)字濾波算法。
接著,取到轉(zhuǎn)換結(jié)果后,根據(jù)V=(AD_Value/4096)*Vref+的公式可以算出相應(yīng)通道的電壓值,也可以根據(jù) T(℃) =(1.43 - Vad)/34*10^(-6) + 25的算法,得到片內(nèi)溫度傳感器的測(cè)量溫度值了。
通過(guò)重新定義putchar函數(shù),及包含"stdio.h"頭文件,我們可以方便的使用標(biāo)準(zhǔn)C的庫(kù)函數(shù)printf(),實(shí)現(xiàn)串口通信。
相關(guān)的官方例程,可以參考FWLib V2.0的ADC\ADC1_DMA和USART\printf兩個(gè)目錄下的代碼。
本代碼例子是基于萬(wàn)利199的開(kāi)發(fā)板EK-STM32F實(shí)現(xiàn),CPU=STM32F103VBT6


#i nclude "stm32f10x_lib.h"
#i nclude "stdio.h"


#defineADC1_DR_Address   ((u32)0x4001244C)


vu16 AD_Value[2];
vu16 i=0;
s16 Temp;
u16 Volt;

void RCC_Configuration(void);
void GPIO_Configuration(void);
void NVIC_Configuration(void);
void USART1_Configuration(void);
void ADC1_Configuration(void);
void DMA_Configuration(void);
int fputc(int ch, FILE *f);
void Delay(void);
u16 GetTemp(u16 advalue);
u16 GetVolt(u16 advalue);


int main(void)
{
   RCC_Configuration();
   GPIO_Configuration();
   NVIC_Configuration();
   USART1_Configuration();
   DMA_Configuration();
   ADC1_Configuration();
  
   //啟動(dòng)第一次AD轉(zhuǎn)換
   ADC_SoftwareStartConvCmd(ADC1, ENABLE);
   //因?yàn)橐呀?jīng)配置好了DMA,接下來(lái)AD自動(dòng)連續(xù)轉(zhuǎn)換,結(jié)果自動(dòng)保存在AD_Value處
  
    while(1)
    {
       Delay();
       Temp = GetTemp(AD_Value[1]);
       Volt = GetVolt(AD_Value[0]);
       USART_SendData(USART1,0x0c);      //清屏
       //注意,USART_SendData函數(shù)不檢查是否發(fā)送完成
       //等待發(fā)送完成
       while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
       printf("電壓:%d.%d\t溫度:%d.%d℃\r\n", \
           Volt/100, Volt0, Temp/100, Temp0);
      
    }
}

int fputc(int ch, FILE *f)
{
   //USART_SendData(USART1, (u8) ch);
   USART1->DR = (u8) ch;
  
   
   while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
    {
    }
    returnch;
}

void Delay(void)
{
    u32 i;
   for(i=0;i<0x4f0000;i++);
   return;
}                          

u16 GetTemp(u16 advalue)
{
    u32Vtemp_sensor;
    s32Current_Temp;
  
//   ADC轉(zhuǎn)換結(jié)束以后,讀取ADC_DR寄存器中的結(jié)果,轉(zhuǎn)換溫度值計(jì)算公式如下:
//         V25 - VSENSE
// T(℃) = ------------ + 25
//          Avg_Slope
//   V25: 溫度傳感器在25℃時(shí)的輸出電壓,典型值1.43 V。
// VSENSE:溫度傳感器的當(dāng)前輸出電壓,與ADC_DR寄存器中的結(jié)果ADC_ConvertedValue之間的轉(zhuǎn)換關(guān)系為:
//           ADC_ConvertedValue * Vdd
// VSENSE = --------------------------
//           Vdd_convert_value(0xFFF)
// Avg_Slope:溫度傳感器輸出電壓和溫度的關(guān)聯(lián)參數(shù),典型值4.3 mV/℃。
   Vtemp_sensor = advalue * 330 / 4096;
    Current_Temp= (s32)(143 - Vtemp_sensor)*10000/43 + 2500;
    return(s16)Current_Temp;
}


u16 GetVolt(u16 advalue)
{
    return(u16)(advalue * 330 / 4096);
}
                        

void RCC_Configuration(void)
{
    ErrorStatusHSEStartUpStatus;
   //使能外部晶振
   RCC_HSEConfig(RCC_HSE_ON);
   //等待外部晶振穩(wěn)定
   HSEStartUpStatus = RCC_WaitForHSEStartUp();
   //如果外部晶振啟動(dòng)成功,則進(jìn)行下一步操作
   if(HSEStartUpStatus==SUCCESS)
    {
       //設(shè)置HCLK(AHB時(shí)鐘)=SYSCLK
       RCC_HCLKConfig(RCC_SYSCLK_Div1);
       //PCLK1(APB1) = HCLK/2
       RCC_PCLK1Config(RCC_HCLK_Div2);
       //PCLK2(APB2) = HCLK
       RCC_PCLK2Config(RCC_HCLK_Div1);
      
       //設(shè)置ADC時(shí)鐘頻率
       RCC_ADCCLKConfig(RCC_PCLK2_Div2);
       //FLASH時(shí)序控制
       //推薦值:SYSCLK = 0~24MHz  Latency=0
       //       SYSCLK = 24~48MHz Latency=1
       //       SYSCLK = 48~72MHz Latency=2
       FLASH_SetLatency(FLASH_Latency_2);
       //開(kāi)啟FLASH預(yù)取指功能
       FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
       //PLL設(shè)置 SYSCLK/1 * 9 = 8*1*9 = 72MHz
       RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
       //啟動(dòng)PLL
       RCC_PLLCmd(ENABLE);
       //等待PLL穩(wěn)定
       while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
       //系統(tǒng)時(shí)鐘SYSCLK來(lái)自PLL輸出
       RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
       //切換時(shí)鐘后等待系統(tǒng)時(shí)鐘穩(wěn)定
       while(RCC_GetSYSCLKSource()!=0x08);
      
    }
   //下面是給各模塊開(kāi)啟時(shí)鐘
   //啟動(dòng)GPIO
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB| \
                          RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD,\
                          ENABLE);
   //啟動(dòng)AFIO
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
   //啟動(dòng)USART1
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
   //啟動(dòng)DMA時(shí)鐘
   RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
   //啟動(dòng)ADC1時(shí)鐘
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
}


void GPIO_Configuration(void)
{
   GPIO_InitTypeDef GPIO_InitStructure;
   //PC口4567腳設(shè)置GPIO輸出,推挽 2M
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6| GPIO_Pin_7;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
   GPIO_Init(GPIOC, &GPIO_InitStructure);
    //KEY2KEY3 JOYKEY
    //位于PD口的3 411-15腳,使能設(shè)置為輸入
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_11| GPIO_Pin_12 |\
       GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
   GPIO_Init(GPIOD, &GPIO_InitStructure);
   //USART1_TX
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
  
   //USART1_RX
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
   GPIO_Init(GPIOA, &GPIO_InitStructure);
  
   //ADC_CH10--> PC0
   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
   GPIO_Init(GPIOC, &GPIO_InitStructure);
}

void NVIC_Configuration(void)
{
   NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
    // Set theVector Table base location at 0x20000000
   NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
    // Set theVector Table base location at 0x08000000
   NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
   //設(shè)置NVIC優(yōu)先級(jí)分組為Group2:0-3搶占式優(yōu)先級(jí),0-3的響應(yīng)式優(yōu)先級(jí)
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
   //串口中斷打開(kāi)
   NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQChannel;
   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&NVIC_InitStructure);
}


void USART1_Configuration(void)
{
   USART_InitTypeDef USART_InitStructure;
  
   USART_InitStructure.USART_BaudRate = 19200;
   USART_InitStructure.USART_WordLength = USART_WordLength_8b;
   USART_InitStructure.USART_StopBits = USART_StopBits_1;
   USART_InitStructure.USART_Parity = USART_Parity_No;
   USART_InitStructure.USART_HardwareFlowControl =USART_HardwareFlowControl_None;
   USART_InitStructure.USART_Mode = USART_Mode_Tx |USART_Mode_Rx;
   USART_Init(USART1, &USART_InitStructure);
  
   USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  
   USART_Cmd(USART1, ENABLE);
}

void ADC1_Configuration(void)
{
   ADC_InitTypeDef ADC_InitStructure;
   ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
   ADC_InitStructure.ADC_ScanConvMode = ENABLE;
   ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //連續(xù)轉(zhuǎn)換開(kāi)啟
   ADC_InitStructure.ADC_ExternalTrigConv =ADC_ExternalTrigConv_None;
   ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
   ADC_InitStructure.ADC_NbrOfChannel =2;    //設(shè)置轉(zhuǎn)換序列長(zhǎng)度為2
   ADC_Init(ADC1, &ADC_InitStructure);
  
   //ADC內(nèi)置溫度傳感器使能(要使用片內(nèi)溫度傳感器,切忌要開(kāi)啟它)
   ADC_TempSensorVrefintCmd(ENABLE);
  
   //常規(guī)轉(zhuǎn)換序列1:通道10
   ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1,ADC_SampleTime_13Cycles5);
   //常規(guī)轉(zhuǎn)換序列2:通道16(內(nèi)部溫度傳感器),采樣時(shí)間>2.2us,(239cycles)
   ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 2,ADC_SampleTime_239Cycles5);
  
    // EnableADC1
   ADC_Cmd(ADC1, ENABLE);
    //開(kāi)啟ADC的DMA支持(要實(shí)現(xiàn)DMA功能,還需獨(dú)立配置DMA通道等參數(shù))
   ADC_DMACmd(ADC1, ENABLE);
  
    //下面是ADC自動(dòng)校準(zhǔn),開(kāi)機(jī)后需執(zhí)行一次,保證精度
    // EnableADC1 reset calibaration register
   ADC_ResetCalibration(ADC1);
    // Check theend of ADC1 reset calibration register
   while(ADC_GetResetCalibrationStatus(ADC1));
    // StartADC1 calibaration
   ADC_StartCalibration(ADC1);
    // Check theend of ADC1 calibration
   while(ADC_GetCalibrationStatus(ADC1));
    //ADC自動(dòng)校準(zhǔn)結(jié)束---------------
  
}

void DMA_Configuration(void)
{
   DMA_InitTypeDef DMA_InitStructure;
  
   DMA_DeInit(DMA1_Channel1);
   DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;
   DMA_InitStructure.DMA_MemoryBaseAddr =(u32)&AD_Value;
   DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
   //BufferSize=2,因?yàn)锳DC轉(zhuǎn)換序列有2個(gè)通道
   //如此設(shè)置,使序列1結(jié)果放在AD_Value[0],序列2結(jié)果放在AD_Value[1]
   DMA_InitStructure.DMA_BufferSize = 2;
   DMA_InitStructure.DMA_PeripheralInc =DMA_PeripheralInc_Disable;
   DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
   DMA_InitStructure.DMA_PeripheralDataSize =DMA_PeripheralDataSize_HalfWord;
   DMA_InitStructure.DMA_MemoryDataSize =DMA_MemoryDataSize_HalfWord;
   //循環(huán)模式開(kāi)啟,Buffer寫滿后,自動(dòng)回到初始地址開(kāi)始傳輸
   DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
   DMA_InitStructure.DMA_Priority = DMA_Priority_High;
   DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
   DMA_Init(DMA1_Channel1, &DMA_InitStructure);
   //配置完成后,啟動(dòng)DMA通道
   DMA_Cmd(DMA1_Channel1, ENABLE);
}


《九九的STM32筆記》整理
這次是RTC的筆記:)
RTC這東西暈暈的,因?yàn)橐粋(gè)模塊涉及到了RTC,BKP,RCC多個(gè)模塊,之間的關(guān)系讓人有點(diǎn)模糊
入門的知識(shí)請(qǐng)大家看手冊(cè),我來(lái)總結(jié):
總之,RTC只是個(gè)能靠電池維持運(yùn)行的32位定時(shí)器over!
所以,使用時(shí)要注意以下問(wèn)題:
1. 上電后要檢查備份電池有沒(méi)有斷過(guò)電。如何檢查? 恩,RTC的示例代碼中已經(jīng)明示:
  往備份域寄存器中寫一個(gè)特殊的字符,備份域寄存器是和RTC一起在斷電下能保存數(shù)據(jù)的。
  上電后檢查下這個(gè)特殊字符是否還存在,如果存在,ok,RTC的數(shù)據(jù)應(yīng)該也沒(méi)丟,不需要重新配置它
  如果那個(gè)特殊字符丟了,那RTC的定時(shí)器數(shù)據(jù)一定也丟了,那我們要重新來(lái)配置RTC了
  這個(gè)過(guò)程包括時(shí)鐘使能、RTC時(shí)鐘源切換、設(shè)置分頻系數(shù)等等,這個(gè)可以參考FWLib\example\RTC\Calendar的代碼
  在我的這個(gè)實(shí)例里,檢查備份域掉電在Init.c的RTC_Conig()中,函數(shù)內(nèi)若檢測(cè)到BKP掉電,則會(huì)調(diào)用RTC_Configuration()2. 因?yàn)镽TC的一些設(shè)置是保存在后備域中的,so,操作RTC的設(shè)置寄存器前,要打開(kāi)后備域模塊中的寫保護(hù)功能。
3. RTC設(shè)定值寫入前后都要檢查命令有沒(méi)有完成,調(diào)用RTC_WaitForLastTask();

具體的RTC初始化代碼如下:
////////////////////////////////////////////////////////////////////////////////
// RTC時(shí)鐘初始化!
////////////////////////////////////////////////////////////////////////////////

void RTC_Configuration(void)
{
   //啟用PWR和BKP的時(shí)鐘(from APB1)
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
   //后備域解鎖
   PWR_BackupAccessCmd(ENABLE);
   //備份寄存器模塊復(fù)位
   BKP_DeInit();
   //外部32.768K其喲偶那個(gè)
   RCC_LSEConfig(RCC_LSE_ON);
    //等待穩(wěn)定
    while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET);
   //RTC時(shí)鐘源配置成LSE(外部32.768K)
   RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE);
   //RTC開(kāi)啟
   RCC_RTCCLKCmd(ENABLE);
   //開(kāi)啟后需要等待APB1時(shí)鐘與RTC時(shí)鐘同步,才能讀寫寄存器
   RTC_WaitForSynchro();
   //讀寫寄存器前,要確定上一個(gè)操作已經(jīng)結(jié)束
   RTC_WaitForLastTask();
   //設(shè)置RTC分頻器,使RTC時(shí)鐘為1Hz
    //RTC period= RTCCLK/RTC_PR = (32.768 KHz)/(32767+1)
   RTC_SetPrescaler(32767);

   //等待寄存器寫入完成
   RTC_WaitForLastTask();
   //使能秒中斷
   RTC_ITConfig(RTC_IT_SEC,ENABLE);  
   //等待寫入完成
   RTC_WaitForLastTask();
   return;
}

void RTC_Config(void)
{
   //我們?cè)贐KP的后備寄存器1中,存了一個(gè)特殊字符0xA5A5
   //第一次上電或后備電源掉電后,該寄存器數(shù)據(jù)丟失,
   //表明RTC數(shù)據(jù)丟失,需要重新配置
    if(BKP_ReadBackupRegister(BKP_DR1) != 0xA5A5)
    {
       //重新配置RTC
       RTC_Configuration();
       //配置完成后,向后備寄存器中寫特殊字符0xA5A5
       BKP_WriteBackupRegister(BKP_DR1, 0xA5A5);
    }
    else
    {
       //若后備寄存器沒(méi)有掉電,則無(wú)需重新配置RTC
       //這里我們可以利用RCC_GetFlagStatus()函數(shù)查看本次復(fù)位類型
       if (RCC_GetFlagStatus(RCC_FLAG_PORRST) != RESET)
       {
           //這是上電復(fù)位
       }
       else if (RCC_GetFlagStatus(RCC_FLAG_PINRST) != RESET)
       {
           //這是外部RST管腳復(fù)位
       }
       //清除RCC中復(fù)位標(biāo)志
       RCC_ClearFlag();
       //雖然RTC模塊不需要重新配置,且掉電后依靠后備電池依然運(yùn)行
       //但是每次上電后,還是要使能RTCCLK???????
       //RCC_RTCCLKCmd(ENABLE);
       //等待RTC時(shí)鐘與APB1時(shí)鐘同步
       //RTC_WaitForSynchro();
       //使能秒中斷
       RTC_ITConfig(RTC_IT_SEC, ENABLE);
       //等待操作完成
       RTC_WaitForLastTask();
    }
#ifdef RTCClockOutput_Enable
   
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR | RCC_APB1Periph_BKP,ENABLE);
   
   PWR_BackupAccessCmd(ENABLE);
   
   BKP_TamperPinCmd(DISABLE);
   
   BKP_RTCOutputConfig(BKP_RTCOutputSource_CalibClock);
#endif
   return;
}


《九九的STM32筆記》整理3

基于STM32處理器
RTC只是個(gè)能靠電池維持運(yùn)行的32位定時(shí)器over!
并不像實(shí)時(shí)時(shí)鐘芯片,讀出來(lái)就是年月日。。。
看過(guò)些網(wǎng)上的代碼,有利用秒中斷,在內(nèi)存中維持一個(gè)年月日的日歷。
我覺(jué)得,這種方法有很多缺點(diǎn):
1.斷電時(shí)沒(méi)有中斷可用
2.頻繁進(jìn)中斷,消耗資源
3.時(shí)間運(yùn)算復(fù)雜,代碼需要自己寫
4.不與國(guó)際接軌。。。。
so,還是用標(biāo)準(zhǔn)的UNIX時(shí)間戳來(lái)進(jìn)行時(shí)間的操作吧!
什么是UNIX時(shí)間戳?
UNIX時(shí)間戳,是unix下的計(jì)時(shí)方式。。。很廢話
具體點(diǎn):他是一個(gè)32位的整形數(shù)(剛好和STM32的RTC寄存器一樣大),表示從UNIX元年(格林尼治時(shí)間1970-1-10:0:0)開(kāi)始到某時(shí)刻所經(jīng)歷的秒數(shù)
聽(tīng)起來(lái)很玄幻的,計(jì)算下:32位的數(shù)從0-0xFFFFFFFF秒,大概到2038年unix時(shí)間戳將會(huì)溢出!這就是Y2038bug
不過(guò),事實(shí)上的標(biāo)準(zhǔn),我們還是照這個(gè)用吧,還有二十年呢。。。
UNIX時(shí)間戳:1229544206 <==>現(xiàn)實(shí)時(shí)間:2008-12-17 20:03:26
我們要做的,就是把當(dāng)前時(shí)間的UNIX時(shí)間戳放在RTC計(jì)數(shù)器中讓他每秒++,over
然后,設(shè)計(jì)一套接口函數(shù),實(shí)現(xiàn)UNIX時(shí)間戳與年月日的日歷時(shí)間格式轉(zhuǎn)換 這樣就可以了
在RTC中實(shí)現(xiàn)這個(gè)時(shí)間算法,有如下好處:
1. 系統(tǒng)無(wú)需用中斷和程序來(lái)維持時(shí)鐘,斷電后只要RTC在走即可
2. 具體的兩種計(jì)時(shí)的換算、星期數(shù)計(jì)算,有ANSI-C的標(biāo)準(zhǔn)C庫(kù)函數(shù)實(shí)現(xiàn),具體可以看time.h
3. 時(shí)間與時(shí)間的計(jì)算,用UNIX時(shí)間戳運(yùn)算,就變成了兩個(gè)32bit數(shù)的加減法
4. 與國(guó)際接軌。。。

幸好是與國(guó)際接軌,我們有time.h幫忙,在MDK的ARM編輯器下有,IAR下也有
其中已經(jīng)定義了兩種數(shù)據(jù)類型:unix時(shí)間戳和日歷型時(shí)間
time_t:      UNIX時(shí)間戳(從1970-1-1起到某時(shí)間經(jīng)過(guò)的秒數(shù))
    typedef unsigned int time_t;

struct tm:   Calendar格式(年月日形式)
同時(shí)有相關(guān)操作函數(shù)
gmtime,localtime,ctime,mktime等等,方便的實(shí)現(xiàn)各種時(shí)間類型的轉(zhuǎn)換和計(jì)算
于是,基于這個(gè)time.h,折騰了一天,搞出了這個(gè)STM32下的RTC_Time使用的時(shí)間庫(kù)

這是我的RTC_Time.c中的說(shuō)明:
本文件實(shí)現(xiàn)基于RTC的日期功能,提供年月日的讀寫。(基于ANSI-C的time.h)

作者:jjldc (九九)
QQ: 77058617

RTC中保存的時(shí)間格式,是UNIX時(shí)間戳格式的。即一個(gè)32bit的time_t變量(實(shí)為u32)
ANSI-C的標(biāo)準(zhǔn)庫(kù)中,提供了兩種表示時(shí)間的數(shù)據(jù) 型:
time_t:      UNIX時(shí)間戳(從1970-1-1起到某時(shí)間經(jīng)過(guò)的秒數(shù))
    typedef unsigned int time_t;

struct tm:   Calendar格式(年月日形式)
   tm結(jié)構(gòu)如下:
   struct tm {
      int tm_sec;   // 秒 seconds afterthe minute, 0 to 60
                       (0 - 60 allows for the occasional leap second)
      int tm_min;   // 分 minutes afterthe hour, 0 to 59
       int tm_hour; // 時(shí) hours since midnight, 0 to 23
       int tm_mday; // 日 day of the month, 1 to 31
       int tm_mon;   // 月 months sinceJanuary, 0 to 11
       int tm_year; // 年 years since 1900
       int tm_wday; // 星期 days since Sunday, 0 to 6
       int tm_yday; // 從元旦起的天數(shù) days since January 1, 0 to 365
        int tm_isdst; // 夏令時(shí)??Daylight Savings Time flag
        ...
    }
    其中wday,yday可以自動(dòng)產(chǎn)生,軟件直接讀取
    mon的取值為0-11
   ***注意***:
   tm_year:在time.h庫(kù)中定義為1900年起的年份,即2008年應(yīng)表示為2008-1900=108
    這種表示方法對(duì)用戶來(lái)說(shuō)不是十分友好,與現(xiàn)實(shí)有較大差異。
    所以在本文件中,屏蔽了這種差異。
    即外部調(diào)用本文件的函數(shù)時(shí),tm結(jié)構(gòu)體類型的日期,tm_year即為2008
    注意:若要調(diào)用系統(tǒng)庫(kù)time.c中的函數(shù),需要自行將tm_year-=1900

成員函數(shù)說(shuō)明:
struct tm Time_ConvUnixToCalendar(time_t t);
    輸入一個(gè)Unix時(shí)間戳(time_t),返回Calendar格式日期
time_t Time_ConvCalendarToUnix(struct tm t);
    輸入一個(gè)Calendar格式日期,返回Unix時(shí)間戳(time_t)
time_t Time_GetUnixTime(void);
    從RTC取當(dāng)前時(shí)間的Unix時(shí)間戳值
struct tm Time_GetCalendarTime(void);
    從RTC取當(dāng)前時(shí)間的日歷時(shí)間
void Time_SetUnixTime(time_t);
    輸入U(xiǎn)NIX時(shí)間戳格式時(shí)間,設(shè)置為當(dāng)前RTC時(shí)間
void Time_SetCalendarTime(struct tm t);
    輸入Calendar格式時(shí)間,設(shè)置為當(dāng)前RTC時(shí)間

外部調(diào)用實(shí)例:
定義一個(gè)Calendar格式的日期變量:
struct tm now;
now.tm_year = 2008;
now.tm_mon =11;       //12月
now.tm_mday = 20;
now.tm_hour = 20;
now.tm_min = 12;
now.tm_sec = 30;

獲取當(dāng)前日期時(shí)間:
tm_now = Time_GetCalendarTime();
然后可以直接讀tm_now.tm_wday獲取星期數(shù)

設(shè)置時(shí)間:
Step1. tm_now.xxx = xxxxxxxxx;
Step2. Time_SetCalendarTime(tm_now);

計(jì)算兩個(gè)時(shí)間的差
struct tm t1,t2;
t1_t = Time_ConvCalendarToUnix(t1);
t2_t = Time_ConvCalendarToUnix(t2);
dt = t1_t - t2_t;
dt就是兩個(gè)時(shí)間差的秒數(shù)
dt_tm =mktime(dt);   //注意dt的年份匹配,ansi庫(kù)中函數(shù)為相對(duì)年份,注意超限
另可以參考相關(guān)資料,調(diào)用ansi-c庫(kù)的格式化輸出等功能,ctime,strftime等


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

使用道具 舉報(bào)

本版積分規(guī)則

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

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表
主站蜘蛛池模板: 91精品国模一区二区三区 | 亚洲视频第一页 | 精品九九九 | 亚洲视频国产视频 | 久久精品一区 | 国产精品久久久久影院色老大 | 国产激情视频网站 | 99精品国产一区二区青青牛奶 | 视频一区二区中文字幕日韩 | 日韩欧美中文 | 久久久精品 | 国产精品2 | 国产精品一区二区视频 | 亚洲第一成年免费网站 | 国产一级在线 | 国产高清视频在线观看播放 | 成人一区二区三区在线观看 | 污片在线观看 | 亚洲三区在线观看 | 久国产精品 | 久久三区 | 一级黄色片免费在线观看 | 亚洲精品区 | 国产日韩欧美 | 精品免费国产视频 | 亚洲国产精品成人 | 91看片视频 | 日韩精品久久 | 欧美一区二区三区在线播放 | 狠狠操婷婷| 日日摸夜夜添夜夜添精品视频 | 国产成人精品久久 | 日韩日韩日韩日韩日韩日韩日韩 | 精品亚洲一区二区三区 | 欧美xxxx网站 | 免费观看一级毛片 | 欧美一级毛片免费观看 | 狠狠av| 欧美精品一区二区三 | 久久久久电影 | 美女爽到呻吟久久久久 |