<acronym id="xonnx"></acronym>
      <td id="xonnx"></td>
    1. <pre id="xonnx"></pre>

      1. 專注電子技術學習與研究
        當前位置:單片機教程網 >> STM32 >> 瀏覽文章

        STM32學習之通用定時器的使用

        作者:竹葉聽箏   來源:竹葉聽箏   點擊數:  更新時間:2014年06月19日   【字體:

        1、STM32F103內部定時器有哪些?

            STM32一共有8個通用16Timer,其中TIMER1TIMER8是高級定時器,其它的TIMER2~TIMER7是普通定時器。
           
        此外還有一個Systick(系統滴答定時器),這個定時器通常在操作系統中作為系統的任務切換周期。
           
        還有一個RTC,是一個毫秒定時器,支持秒級中斷,用來做實時時鐘計數器。

            看門狗定時器 也可以算一個。

            8個定時器中,Timer1 Timer8是由APB2(輸出最高頻率為72MHZ)預分頻后,再通過一個倍頻器得到時鐘頻率,最高為72MHz。Timer2~Timer7則是由APB1(輸出最高頻率為36MHZ)預分頻后,再通過一個倍頻器得到時鐘頻率,最高為36MHz。

         

        2、如何進行程序編寫     

          這里我通過定時器來控制一個LED0.5s 0.5s ,交替閃爍。當然要讓定時器正常工作起來,還要配置中斷NVIC。定時器計數到某個數,產生中斷,從而進入中斷服務程序,點亮LED燈。

        main函數分析:

        #include "stm32f10x.h"

         

        void GPIO_Config(void)//GPIO配置

        {

           GPIO_InitTypeDef GPIO_InitStructure;

           RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能gpioc的時    

           GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;                 //選擇管腳PC.13LED

           GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;   //管腳速度為50M

         

                GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;          //設置輸出模式為推挽輸出

           GPIO_Init(GPIOC, &GPIO_InitStructure);             //將上述設置寫入到GPIOC里去

        }

         

              void NVIC_Config(void)                                           //中斷控制器的配置

        {

        NVIC_InitTypeDef NVIC_InitStructure;

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);                   //優先組設置

        NVIC_InitStructure.NVIC_IRQChannel =TIM2_IRQn ;           //TIM2中斷選通

        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;      //搶占優先級

        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;           //子優先級

        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;         //使能中斷控制

        NVIC_Init(&NVIC_InitStructure);

        }

        void Timer_Config(void)         //定時器的配置

        {

               TIM_TimeBaseInitTypeDef   TIM_TimeBaseStructure;   

        RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2 , ENABLE);  //Timer2 時鐘使能

        TIM_DeInit(TIM2);                              //復位TIM2定時器      

        TIM_TimeBaseStructure.TIM_Period=1000;          //定時器周期

        TIM_TimeBaseStructure.TIM_Prescaler=36000-1;     //預分頻數

        TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;   //TIM2時鐘分頻,1表示不分頻

        TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//定時器計數為向上計數模式

        TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);     

        TIM_ClearFlag(TIM2, TIM_FLAG_Update);           //清除定時器2的溢出標志位

        TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE);      //使能定時器2溢出中斷

        TIM_Cmd(TIM2, ENABLE);                       //定時器2使能

        }

         

         

        int main(void)

        {

          SystemInit();//初始化時鐘,配置為72MHz,我試過將這句注釋掉,好像不影響結果。查            

                      了一下,在配置

                       //main函數之前的啟動代碼有這樣一句  LDR R0, =SystemInit,我疑惑的是難               

                     道啟動的時候就配成72Mhz? 

            GPIO_Config();

               NVIC_Config();

               Timer_Config();

          while(1)

               { 

            ;     

          }

        }

         

         


        中斷服務函數

        void TIM2_IRQHandler(void)

        {

        static int flag_bit=0;//定義一個標志位

              

        if ( TIM_GetITStatus(TIM2 , TIM_IT_Update) != RESET ) //判斷中斷溢出標志為是否為1

               {

           TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update); //清除溢出中斷標志位

                       flag_bit = !flag_bit;

                       if(flag_bit == 1)

                  GPIO_SetBits(GPIOC, GPIO_Pin_13);             //熄滅LED

                       if(flag_bit == 0)

             GPIO_ResetBits(GPIOC, GPIO_Pin_13);           //點亮LED

                }

         

           這個函數是寫在stm32f10x_it.c 里面的,我對TIM2_IRQHandler()函數的理解應該是這樣的:

            首先由定時器定時,定時好了產生中斷溢出標志位,發送中斷

            然后進入中斷服務函數TIM2_IRQHandler(),進入函數之后要做的就是清除中斷溢出 

            標志位。

            最后再執行函數里的其他內容。

        定時器定時時間計算是這兩句:

                           TIM_TimeBaseStructure.TIM_Period=1000;          //定時器周期

                           TIM_TimeBaseStructure.TIM_Prescaler=36000-1;     //預分頻數

           Prescaler可以理解為定時器的基數是72M  /  Prescaler+1  = 2000k,也就是500us ,Period 可以理解為要計數多少次,這里是1000次。 所以就是每500us記一次,計數1000次,就是500ms。

        公式為:

           Period / (72M / (Prescaler+1) )=____

            1000 / (72 M/ (35999+1) )  =  0.5

         

         

        我有的一些疑問:1、進入中斷函數之后,定時器要干些什么,是不是就停止計數了?

                        2、計數記到1000發生中斷,計數值是不是有自動清零

          問題先放到這兒,邊學習,邊解決。             

                       

         

         

        3仿真結果觀察

        前面第三章已經過如何仿真波形的步驟,可以參看前面。點擊setup 按鈕 會彈出一個窗口,在窗口的右上邊,有個new的按鈕,點擊后輸入 PORTC.13

         

        仿真運行結果如下:


        可以從仿真結果中觀察到,方波的周期為一秒。占空比為0.5 ,跟預期一致。

         

        4對第四章串口的補充

          第四章介紹了串口的打印函數printf 是如何調用實現的。但要使用keil自帶的微庫microLIB ,那能不能不使用這個微庫呢。我參照野火的教程,修改了程序,自己編寫usart_printf()函數來實現打印的功能。

         

           USRT1的配置不改變,主要的就是添加打印函數實現串口輸出功能。代碼感覺可能很長,但無非就是一些判斷,看看字符串最后一位是不是\0 ,不是的話,遇到轉義字符,/n /r 怎么做,以及將數字轉換成字符這些。

        這些很多時候我都沒注意:

          1、  這一句while ( *Data != 0)     // 判斷是否到達字符串結束符

        我們平時不是都用 \0 嗎? 0開始我還沒反應過來。 其實ASCII的十六進制的0 就是\0

         如果要使用\0,while ( *Data !='\0') ,主要要加單引號表字符串,上面沒有加就是十六進制,后面的也就能明白了。

          2、stdarg.h這個函數,以前都沒見過,但學習就是要學習新知識。 知識改變命運,我一直都相信這句!

          3、char *itoa(int value, char *string, int radix)  是指針函數,返回值是一個地址

          4、其他的都是涉及指針的操作,所以C指針一定要學好,沒學好,不要緊,趁這個機會把它弄明白,當我看懂了下面這些,也就明白了。

         

        #ifndef __usart_debug_H

        #define    __usart_debug_H

         

        #include "stm32f10x.h"

        #include   //stdarg.hC語言中C標準函數庫的頭文件,目的為讓函數能夠接收可變參數。

         

        extern void usart_debug_config(void);  //提供給外部函數調用usart_debug_config()函數。

        //

        //  函數名:itoa

        //  描述  :將整形數據轉換成字符串

        // 輸入  -radix =10 表示10進制,其他結果為0

        //         -value 要轉換的整形數

         //       -buf 轉換后的字符串

         //       -radix = 10

         * 輸出  :無

         * 返回  :無

         * 調用  :被USART1_printf()調用

         *

        static char *itoa(int value, char *string, int radix)

        {

            int     i, d;

            int     flag = 0;

            char    *ptr = string;

         

            //This implementation only works for decimal numbers.  

            if (radix != 10)

            {

                *ptr = 0;

                return string;

            }

         

           if (!value)

            {

                *ptr++ = 0x30;

                *ptr = 0;

                return string;

            }

         

            //if this is a negative value insert the minus sign.

            if (value < 0)

            {

                *ptr++ = '-';

         

                // Make the value positive.

                value *= -1;

            }

         

            for (i = 10000; i > 0; i /= 10)

            {

                d = value / i;

         

                if (d || flag)

                {

                    *ptr++ = (char)(d + 0x30);

                    value -= (d * i);

                    flag = 1;

                }

            }

         

            // Null terminate the string. 

            *ptr = 0;

         

            return string;

         

        } //NCL_Itoa

         

         

         // 函數名:USART1_printf

         //描述  :格式化輸出,類似于C庫中的printf,但這里沒有用到C

         //輸入  -USARTx 串口通道,這里只用到了串口1,即USART1

         //                -Data   要發送到串口的內容的指針

        //                     -...    其他參數

        // 輸出  :無

         // 返回  :無

         //調用  :外部調用

        //         典型應用USART1_printf( USART1, "\r\n this is a demo \r\n" );

        //                        USART1_printf( USART1, "\r\n %d \r\n", i );

        //                        USART1_printf( USART1, "\r\n %s \r\n", j );

        //

        static   void USART1_printf(USART_TypeDef* USARTx, uint8_t *Data,...)

        {

               const char *s;

          int d;  

          char buf[16];

         

          va_list ap;        // va_list ap  va_start(ap, Data)以及后面的va_arg() 都來自 stdarg.h

          va_start(ap, Data);//具體用法請參照相關資料。

         

               while ( *Data != 0)     // 判斷是否到達字符串結束符

               {                                                   

                      if ( *Data == 0x5c )  // '\'  ASCII 0x5c就是轉義字符'\'

                      {                                                              

                             switch ( *++Data )

                             {

                                    case 'r':                                                        //回車符

                                           USART_ClearFlag(USART2,USART_FLAG_TC);

                                           USART_SendData(USARTx, 0x0d);

                                      while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );

                                           Data ++;

                                           break;

         

                                    case 'n':                                                        //換行符

                                           USART_ClearFlag(USART2,USART_FLAG_TC);

                                           USART_SendData(USARTx, 0x0a);    

                                    while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );

                                           Data ++;

                                           break;

                                   

                                    default:

                                           Data ++;

                                        break;

                             }                  

                      }

                      else if ( *Data == '%')

                      {                                                               //

                             switch ( *++Data )

                             {                         

                                    case 's':                                                                     //字符串

                                           s = va_arg(ap, const char *);

                  for ( ; *s; s++)

                                           {

                                                  USART_ClearFlag(USART2,USART_FLAG_TC);

                                                  USART_SendData(USARTx,*s);

                                                  while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );

                  }

                                           Data++;

                  break;

         

                case 'd':                                                                   //十進制

                  d = va_arg(ap, int);

                  itoa(d, buf, 10);

                  for (s = buf; *s; s++)

                                           {

                                             USART_ClearFlag(USART2,USART_FLAG_TC);

                                                  USART_SendData(USARTx,*s);

                                                  while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );

                  }

                                           Data++;

                  break;

                                     default:

                                                  Data++;

                                        break;

                             }           

                      } //end of else if 

                      else  {

                                  USART_ClearFlag(USART2,USART_FLAG_TC);

                                  USART_SendData(USARTx, *Data++);

                                  while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );

                            }      

                             while( USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET );

               }

        }

         

        #endif // __USART1_H 

         

        軟件仿真中的效果圖:

         波形圖 IO口狀態 串口輸出 都在下面圖里了

         



        5工程代碼   

          定時器中斷                    百度云盤:http://pan.baidu.com/s/1mzOIE

          定時器中斷帶串口          百度云盤:http://pan.baidu.com/s/1dD06Olb

          野火串口工程                 百度云盤:http://pan.baidu.com/s/1o6pzjZ0

          word文檔教程                 百度文庫: 

        關閉窗口

        相關文章

        欧美性色欧美精品视频,99热这里只有精品mp4,日韩高清亚洲日韩精品一区二区,2020国自产拍精品高潮