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

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 7166|回復: 1
收起左側

基于時間觸發混合式多任務調度器設計

[復制鏈接]
ID:99624 發表于 2015-12-20 03:09 | 顯示全部樓層 |閱讀模式
       幾個星期了,一直被UC/OS-III搞得焦頭爛額;UC/OS-III與II不同之處很多。真正搞懂內核原理確實不易,是塊硬骨頭。但是本人認為那就是筋頭巴腦的醬牛肉,越嚼越有味!學習之余竟然收獲了時間觸發混合式多任務調度器設計的方法。臥槽,爽!

       操作系統固然好,但是在對穩定性,安全,可靠性要求較高的工程中就不見得好用了。由于嵌入了操作系統導致工程代碼復雜,調試程序就要花很長時間,搞不好BUG就會跳出來害人。本人堅信操作系統只能在迫不得已的情況下使用,比如手機,平板電腦等消費電子產品。下面的這個基于時間觸發混合式多任務調度器已經能完成較多任務的可靠調度了。

      核心代碼“多任務”.c源碼部分:

#include "Time_Triggered.h"
#include "stm32f10x.h"
#include "GUI.h"
#include "gui_time.h"
#include "wave.h"

#define  RETURN_ERROR                 0x00;
#define  RETURN_NORMOL                0x01;
#define  ERROR_SCH_CANOT_DELETE_TASK  0x02;
#define  ERROR_SCH_TOO_MANY_TASKS  0x03;

tByte Error_code_G;

sTask hSCH_task_G[hSCH_MAX_TASKS]; /*建立的任務數*/
/*
*********************************************************************************************************
* 函 數 名: hSCH_Update(void)
* 功能說明: 調度器的刷新函數,每個時標中斷執行一次。在嘀嗒定時器中斷里面執行。
 當刷新函數確定某個任務要執行的時候,將RunMe加1,要注意的是刷新任務
 不執行任何函數,需要運行的任務有調度函數激活。
 搶占式任務需要執行的話,立即就會得到執行。
* 形    參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void hSCH_Update(void)
{
tByte index;
/*注意計數單位是時標,不是毫秒*/
for(index = 0; index < hSCH_MAX_TASKS; index++)
{
if(hSCH_task_G[index].pTask)   /*檢測這里是否有任務*/
{
if(hSCH_task_G[index].Delay == 0)
{
if(hSCH_task_G[index].Co_op)    /*混合式調度和合作式調度的區分 合作式1 搶占式0*/
{
hSCH_task_G[index].RunMe += 1;  /*合作式任務需要運行 將RunMe置1*/
}
else
{
//注意:“(*hSCH_task_G[index].pTask)”是函數人口地址
(*hSCH_task_G[index].pTask)();   /*搶占式任務需要立即運行 將RunMe減1*/
//hSCH_task_G[index].RunMe -= 1;
if(hSCH_task_G[index].Period == 0)
{       /*單次執行的任務 則將其清除*/
hSCH_task_G[index].pTask = 0;
}
}
if(hSCH_task_G[index].Period)
{           /*調度周期性的任務再次執行*/
hSCH_task_G[index].Delay = hSCH_task_G[index].Period;
}
}
else
{              /*還有準備好運行*/
hSCH_task_G[index].Delay -= 1;
}
}
}
}

/*
*********************************************************************************************************
* 函 數 名: hSCH_Add_Task
* 功能說明: 添加或者說創建一個任務。
* 形    參:void (*pFuntion)(void) tWord DELAY tWord PERIOD
* 返 回 值: 返回任務的ID號
*   使用說明:   0 表示是搶占式任務  1 表示是合作式任務
* (1)SCH_Add_Task(DOTASK,1000,0,1) DOTASK是函數的運行地址,1000是1000個時標以后開始運行,
       只運行一次;
* (2)Task_ID = SCH_Add_Task(DOTASK,1000,0,1); 將任務標示符保存 以便以后刪除任務 
* (3)SCH_Add_Task(DOTASK,0,1000,1); 每個1000個時標周期性的運行一次;
*********************************************************************************************************
*/
tByte hSCH_Add_Task(void (*pFuntion)(void),
tWord DELAY,
tWord PERIOD,
tByte Co_op)  /*任務合作式和搶占式的區分*/
{
tByte index = 0; /*首先在隊列中找到一個空隙,(如果有的話)*/
while((hSCH_task_G[index].pTask != 0) && (index <hSCH_MAX_TASKS))
{
index ++;
}
if(index == hSCH_MAX_TASKS)/*超過最大的任務數目 則返錯誤信息*/
{
Error_code_G = ERROR_SCH_TOO_MANY_TASKS;/*設置全局錯誤變量*/
return hSCH_MAX_TASKS;
}
hSCH_task_G[index].pTask = pFuntion; /*運行到這里說明申請的任務塊成功*/
hSCH_task_G[index].Delay = DELAY;
hSCH_task_G[index].Period = PERIOD;
hSCH_task_G[index].RunMe = 0;
hSCH_task_G[index].Co_op = Co_op;
return index;   /*返回任務的位置,以便于以后刪除*/
}
/*
*********************************************************************************************************
* 函 數 名: hSCH_Task_Delete
* 功能說明: 刪除任務。就是將任務結構體各個成員全部賦值為0
* 形    參:tByte index
* 返 回 值: 是否刪除成功
*********************************************************************************************************
*/
tByte hSCH_Task_Delete(tByte index)
{
tByte Return_code;
if(hSCH_task_G[index].pTask == 0)   /*這里沒有任務*/
{
Error_code_G = ERROR_SCH_CANOT_DELETE_TASK;/*設置全局錯誤變量*/
Return_code  = RETURN_ERROR;
}
else
{
Return_code  = RETURN_NORMOL;
}
hSCH_task_G[index].pTask = 0x0000;
hSCH_task_G[index].Delay = 0;
hSCH_task_G[index].Period = 0;
hSCH_task_G[index].RunMe =0;
return Return_code; /*返回狀態*/
}
/*
*********************************************************************************************************
* 函 數 名: hSCH_Dispatch_Tasks
* 功能說明: 在主任務里面執行的調度函數。
* 形    參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void hSCH_Dispatch_Tasks(void)
{
tByte index;
/*運行下一個任務,如果下一個任務準備就緒的話*/
for(index = 0; index < hSCH_MAX_TASKS; index++)
{
if((hSCH_task_G[index].RunMe >0) && (hSCH_task_G[index].Co_op)) /*只調度合作式任務*/
{
(*hSCH_task_G[index].pTask)();     /*執行任務 */
hSCH_task_G[index].RunMe -= 1;   /*執行任務完成后,將RunMe減一 ,實際上就是恢復為0 */
if(hSCH_task_G[index].Period == 0) /*如果是單次任務的話,則將任務刪除 */
{
hSCH_Task_Delete(index);
}
}
}
}
/*
*********************************************************************************************************
* 函 數 名: bsp_Init
* 功能說明: 初始化所有的硬件設備。該函數配置CPU寄存器和外設的寄存器并初始化一些全局變量。只需要調用一次
* 形    參:無
* 返 回 值: 無
*********************************************************************************************************
*/
extern void  LedTest(void);
extern void KeyTest(void);
extern void display(void);
extern void display1(void);
extern void Gui_test(void);
// GUI_TOUCH_Exec(); //定時掃描觸摸屏


void sTsak_Init(void)
{
/*
由于ST固件庫的啟動文件已經執行了CPU系統時鐘的初始化,所以不必再次重復配置系統時鐘。
啟動文件配置了CPU主時鐘頻率、內部Flash訪問速度和可選的外部SRAM FSMC初始化。
系統時鐘缺省配置為168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
*/
// bsp_InitLed(); /* 初始LED指示燈端口 */
//    bsp_InitUart(); /* 初始化串口 */
// bsp_InitKey();      /* 初始化按鍵 */
/*混合式調度和合作式調度的區分 合作式1 搶占式0*/
/* 添加三個任務 */
hSCH_Add_Task(LedTest, 0, 500, 1);           /* 合作式 周期10ms */
hSCH_Add_Task( Touch_MainTask, 5000, 0, 0);        /* 搶占式 周期0ms 即只運行一次*/
hSCH_Add_Task( Multi_MainTask, 20000, 0, 0);    /* 搶占式 周期200ms */
hSCH_Add_Task(Gui_test, 0, 1000, 1);    /* 合作式1 周期500ms */
hSCH_Add_Task( KeyTest, 100, 10, 1);        /* 合作式 周期4ms */
hSCH_Add_Task(display, 0, 3000, 1);   
}

/*
    時間觸發混合式任務調度器使用注意:
 1,任務執行時間較長的或者當前任務在循環體執行期間別的任務就無法執行,可以通過改變中斷優先級的方法
    來設計;
 2,本工程中,原子delay延時函數不能用,否則會死機!
 3,可以和軟件定時器配合設計出復雜的多任務調度器;嘗試在回調函數中運用軟件定時器進行任務調度和通信;
 4,時鐘滴答定時器默認優先級15;
 5, 實驗證明,當程序進入循環體時,滴答定時器停止工作,所以基于滴答定時器的如計數,計時等等任務相當于
    休眠,等待程序走出循環體,滴答定時器才開始工作;這就是滴答定時器中斷優先級最低的好處!
 6,本工程中使用的中斷資源:uart1,TIM3_IRQHandler,SysTick,Timer5




*/
“多任務”相應的.H 頭文件:

 
#ifndef __TIME_TRIGGERED_H
#define __TIME_TRIGGERED_H


#define hSCH_MAX_TASKS     10


typedef unsigned char    tByte;
typedef unsigned int     tWord; 

typedef  struct
{
void (*pTask)();    /*指向任務的指針必須是一個*void(void)*函數;*/
tWord Delay;      /*延時(時標)知道下一個函數的運行*/
tWord Period;    /*連續運行之間的間隔*/
tByte RunMe;   /*當任務需要運行的時候由調度器加1*/

    tByte Co_op;   /*混合式調度和合作式調度的區分 合作式1 搶占式0*/
}sTask;

void   hSCH_Update(void);
tByte  hSCH_Add_Task(void (*pFuntion)(void),
 tWord DELAY,
 tWord PERIOD,
 tByte Co_op);
tByte  hSCH_Task_Delete(tByte TASK_INDEX);
void   hSCH_Dispatch_Tasks(void);  
void sTsak_Init(void);
extern sTask hSCH_task_G[hSCH_MAX_TASKS];  /*建立的任務數*/ 

#endif


/*****************************  (END OF FILE) *********************************/
下面是軟件定時器部分.C 源碼:

#include "Time_Triggered.h"
#include "ILI9341.h"
#include "key.h"
#include "bsp_timer.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_rcc.h"
#include "led.h"
/*
定義用于硬件定時器的TIM, 可以使 TIM2 - TIM5
TIM3 和TIM4 是16位
TIM2 和TIM5 是32位
*/
#define TIM_HARD TIM5
#define TIM_HARD_IRQn TIM5_IRQn
#define TIM_HARD_RCC RCC_APB1Periph_TIM5

/* 這2個全局變量轉用于 bsp_DelayMS() 函數 */
static volatile uint32_t s_uiDelayCount = 0;
static volatile uint8_t s_ucTimeOutFlag = 0;

/* 定于軟件定時器結構體變量 */
static SOFT_TMR s_tTmr[TMR_COUNT];

/*
全局運行時間,單位1ms
最長可以表示 24.85天,如果你的產品連續運行時間超過這個數,則必須考慮溢出問題
*/
__IO int32_t g_iRunTime = 0;

static void bsp_SoftTimerDec(SOFT_TMR *_tmr);

/* 保存 TIM定時中斷到后執行的回調函數指針 */
static void (*s_TIM_CallBack1)(void);
static void (*s_TIM_CallBack2)(void);
static void (*s_TIM_CallBack3)(void);
static void (*s_TIM_CallBack4)(void);

/*
*********************************************************************************************************
* 函 數 名: bsp_InitTimer
* 功能說明: 配置systick中斷,并初始化軟件定時器變量
* 形    參:  無
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_InitTimer(void)
{
uint8_t i;

/* 清零所有的軟件定時器 */
for (i = 0; i < TMR_COUNT; i++)
{
s_tTmr[i].Count = 0;
s_tTmr[i].PreLoad = 0;
s_tTmr[i].Flag = 0;
s_tTmr[i].Mode = TMR_ONCE_MODE; /* 缺省是1次性工作模式 */
}

/*
配置systic中斷周期為1ms,并啟動systick中斷。

    SystemCoreClock 是固件中定義的系統內核時鐘,對于STM32F4XX,一般為 168MHz

    SysTick_Config() 函數的形參表示內核時鐘多少個周期后觸發一次Systick定時中斷.
    -- SystemCoreClock / 1000  表示定時頻率為 1000Hz, 也就是定時周期為  1ms
    -- SystemCoreClock / 500   表示定時頻率為 500Hz,  也就是定時周期為  2ms
    -- SystemCoreClock / 2000  表示定時頻率為 2000Hz, 也就是定時周期為  500us

    對于常規的應用,我們一般取定時周期1ms。對于低速CPU或者低功耗應用,可以設置定時周期為 10ms
    */
SysTick_Config(SystemCoreClock / 1000);

bsp_InitHardTimer(); /* 開啟硬件定時中斷 */
}
/*
*********************************************************************************************************
* 函 數 名: bsp_RunPer10ms
* 功能說明: 該函數每隔10ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程序。一些需要周期性處理
* 的事務可以放在此函數。比如:按鍵掃描、蜂鳴器鳴叫控制等。
* 形    參:無
* 返 回 值: 無
*********************************************************************************************************
*/
//void LedTest()
//{
// LED0=0;
// LED1=0;
//   bsp_DelayMS(50);
// LED0=1;
// LED1=1;
//}
void bsp_RunPer30ms(void)
{
   if(key0()==0)
{
LCD_ShowString(16 ,66,240,240,24,"hello!");
   
 
}
if(key1()==1)
    {
  LCD_Clear(WHITE);
}

// bsp_DelayMS(50);
// GUI_Clear();
}

/*
*********************************************************************************************************
* 函 數 名: bsp_RunPer1ms
* 功能說明: 該函數每隔1ms被Systick中斷調用1次。詳見 bsp_timer.c的定時中斷服務程序。一些需要周期性處理的
* 事務可以放在此函數。比如:觸摸坐標掃描。
* 形    參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_RunPer1ms(void)
{
 
}

/*
*********************************************************************************************************
* 函 數 名: SysTick_ISR
* 功能說明: SysTick中斷服務程序,每隔1ms進入1次
* 形    參:  無
* 返 回 值: 無
*********************************************************************************************************
*/
//extern void bsp_RunPer1ms(void);
//extern void bsp_RunPer10ms(void);
void SysTick_ISR(void)
{
static uint8_t s_count = 0;
uint8_t i;

/* 每隔1ms進來1次 (僅用于 bsp_DelayMS) */
if (s_uiDelayCount > 0)
{
if (--s_uiDelayCount == 0)
{
s_ucTimeOutFlag = 1;
}
}

/* 每隔1ms,對軟件定時器的計數器進行減一操作 */
for (i = 0; i < TMR_COUNT; i++)
{
bsp_SoftTimerDec(&s_tTmr[i]);
}
   hSCH_Update();
/* 全局運行時間每1ms增1 */
g_iRunTime++;
// if (g_iRunTime == 0x7FFFFFFF) /* 這個變量是 int32_t 類型,最大數為 0x7FFFFFFF */
// {
// g_iRunTime = 0;
// }

// bsp_RunPer1ms(); /* 每隔1ms調用一次此函數,此函數在 bsp.c */

// if (++s_count >= 30)
// {
// s_count = 0;

// bsp_RunPer30ms(); /* 每隔10ms調用一次此函數,此函數在 bsp.c */
// }
}

/*
*********************************************************************************************************
* 函 數 名: bsp_SoftTimerDec
* 功能說明: 每隔1ms對所有定時器變量減1。必須被SysTick_ISR周期性調用。
* 形    參:  _tmr : 定時器變量指針
* 返 回 值: 無
*********************************************************************************************************
*/
static void bsp_SoftTimerDec(SOFT_TMR *_tmr)
{
if (_tmr->Count > 0)
{
/* 如果定時器變量減到1則設置定時器到達標志 */
if (--_tmr->Count == 0)
{
_tmr->Flag = 1;

/* 如果是自動模式,則自動重裝計數器 */
if(_tmr->Mode == TMR_AUTO_MODE)
{
_tmr->Count = _tmr->PreLoad;
}
}
}
}

/*
*********************************************************************************************************
* 函 數 名: bsp_DelayMS
* 功能說明: ms級延遲,延遲精度為正負1ms
* 形    參:  n : 延遲長度,單位1 ms。 n 應大于2
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_DelayMS(uint32_t n)
{
if (n == 0)
{
return;
}
else if (n == 1)
{
n = 2;
}

DISABLE_INT();   /* 關中斷 */

s_uiDelayCount = n;
s_ucTimeOutFlag = 0;

ENABLE_INT();   /* 開中斷 */

while (1)
{
//bsp_Idle(); /* CPU空閑執行的操作, 見 bsp.c 和 bsp.h 文件 */

/*
等待延遲時間到
注意:編譯器認為 s_ucTimeOutFlag = 0,所以可能優化錯誤,因此 s_ucTimeOutFlag 變量必須申明為 volatile
*/
if (s_ucTimeOutFlag == 1)
{
break;
}
}
}

/*
*********************************************************************************************************
*    函 數 名: bsp_DelayUS
*    功能說明: us級延遲。 必須在systick定時器啟動后才能調用此函數。
*    形    參:  n : 延遲長度,單位1 us
*    返 回 值: 無
*********************************************************************************************************
*/
void bsp_DelayUS(uint32_t n)
{
    uint32_t ticks;
    uint32_t told;
    uint32_t tnow;
    uint32_t tcnt = 0;
    uint32_t reload;

reload = SysTick->LOAD;
    ticks = n * (SystemCoreClock / 1000000); /* 需要的節拍數 */

    tcnt = 0;
    told = SysTick->VAL;             /* 剛進入時的計數器值 */

    while (1)
    {
        tnow = SysTick->VAL;
        if (tnow != told)
        {
            /* SYSTICK是一個遞減的計數器 */
            if (tnow < told)
            {
                tcnt += told - tnow;
            }
            /* 重新裝載遞減 */
            else
            {
                tcnt += reload - tnow + told;
            }
            told = tnow;

            /* 時間超過/等于要延遲的時間,則退出 */
            if (tcnt >= ticks)
            {
            break;
            }
        }
    }
}


/*
*********************************************************************************************************
* 函 數 名: bsp_StartTimer
* 功能說明: 啟動一個定時器,并設置定時周期。
* 形    參:   _id     : 定時器ID,值域【0,TMR_COUNT-1】。用戶必須自行維護定時器ID,以避免定時器ID沖突。
* _period : 定時周期,單位1ms
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_StartTimer(uint8_t _id, uint32_t _period)
{
if (_id >= TMR_COUNT)
{
/* 打印出錯的源代碼文件名、函數名稱 */
BSP_Printf("Error: file %s, function %s()\r\n", __FILE__, __FUNCTION__);
while(1); /* 參數異常,死機等待看門狗復位 */
}

DISABLE_INT();   /* 關中斷 */

s_tTmr[_id].Count = _period; /* 實時計數器初值 */
s_tTmr[_id].PreLoad = _period; /* 計數器自動重裝值,僅自動模式起作用 */
s_tTmr[_id].Flag = 0; /* 定時時間到標志 */
s_tTmr[_id].Mode = TMR_ONCE_MODE; /* 1次性工作模式 */

ENABLE_INT();   /* 開中斷 */
}

/*
*********************************************************************************************************
* 函 數 名: bsp_StartAutoTimer
* 功能說明: 啟動一個自動定時器,并設置定時周期。
* 形    參:   _id     : 定時器ID,值域【0,TMR_COUNT-1】。用戶必須自行維護定時器ID,以避免定時器ID沖突。
* _period : 定時周期,單位10ms
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_StartAutoTimer(uint8_t _id, uint32_t _period)
{
if (_id >= TMR_COUNT)
{
/* 打印出錯的源代碼文件名、函數名稱 */
BSP_Printf("Error: file %s, function %s()\r\n", __FILE__, __FUNCTION__);
while(1); /* 參數異常,死機等待看門狗復位 */
}

DISABLE_INT();   /* 關中斷 */

s_tTmr[_id].Count = _period; /* 實時計數器初值 */
s_tTmr[_id].PreLoad = _period; /* 計數器自動重裝值,僅自動模式起作用 */
s_tTmr[_id].Flag = 0; /* 定時時間到標志 */
s_tTmr[_id].Mode = TMR_AUTO_MODE; /* 自動工作模式 */

ENABLE_INT();   /* 開中斷 */
}

/*
*********************************************************************************************************
* 函 數 名: bsp_StopTimer
* 功能說明: 停止一個定時器
* 形    參:   _id     : 定時器ID,值域【0,TMR_COUNT-1】。用戶必須自行維護定時器ID,以避免定時器ID沖突。
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_StopTimer(uint8_t _id)
{
if (_id >= TMR_COUNT)
{
/* 打印出錯的源代碼文件名、函數名稱 */
BSP_Printf("Error: file %s, function %s()\r\n", __FILE__, __FUNCTION__);
while(1); /* 參數異常,死機等待看門狗復位 */
}

DISABLE_INT();   /* 關中斷 */

s_tTmr[_id].Count = 0; /* 實時計數器初值 */
s_tTmr[_id].Flag = 0; /* 定時時間到標志 */
s_tTmr[_id].Mode = TMR_ONCE_MODE; /* 自動工作模式 */

ENABLE_INT();   /* 開中斷 */
}

/*
*********************************************************************************************************
* 函 數 名: bsp_CheckTimer
* 功能說明: 檢測定時器是否超時
* 形    參:   _id     : 定時器ID,值域【0,TMR_COUNT-1】。用戶必須自行維護定時器ID,以避免定時器ID沖突。
* _period : 定時周期,單位1ms
* 返 回 值: 返回 0 表示定時未到, 1表示定時到
*********************************************************************************************************
*/
uint8_t bsp_CheckTimer(uint8_t _id)
{
if (_id >= TMR_COUNT)
{
return 0;
}

if (s_tTmr[_id].Flag == 1)
{
s_tTmr[_id].Flag = 0;
return 1;
}
else
{
return 0;
}
}

/*
*********************************************************************************************************
* 函 數 名: bsp_GetRunTime
* 功能說明: 獲取CPU運行時間,單位1ms。最長可以表示 24.85天,如果你的產品連續運行時間超過這個數,則必須考慮溢出問題
* 形    參:  無
* 返 回 值: CPU運行時間,單位1ms
*********************************************************************************************************
*/
int32_t bsp_GetRunTime(void)
{
int32_t runtime;

DISABLE_INT();   /* 關中斷 */

runtime = g_iRunTime; /* 這個變量在Systick中斷中被改寫,因此需要關中斷進行保護 */

ENABLE_INT();   /* 開中斷 */

return runtime;
}

/*
*********************************************************************************************************
* 函 數 名: SysTick_Handler
* 功能說明: 系統嘀嗒定時器中斷服務程序。啟動文件中引用了該函數。
* 形    參:  無
* 返 回 值: 無
*********************************************************************************************************
*/
void SysTick_Handler(void)
{
SysTick_ISR();
}

/*
*********************************************************************************************************
* 函 數 名: bsp_InitHardTimer
* 功能說明: 配置 TIM4,用于us級別硬件定時。TIM4將自由運行,永不停止.
* TIM4可以用TIM2 - TIM5 之間的TIM, 這些TIM有4個通道, 掛在 APB1 上,輸入時鐘=SystemCoreClock / 2
* 形    參: 無
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_InitHardTimer(void)
{
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
uint16_t usPeriod;
uint16_t usPrescaler;
uint32_t uiTIMxCLK;

  /* 使能TIM時鐘 */
RCC_APB1PeriphClockCmd(TIM_HARD_RCC, ENABLE);

    /*-----------------------------------------------------------------------
system_stm32f4xx.c 文件中 void SetSysClock(void) 函數對時鐘的配置如下:

HCLK = SYSCLK / 1     (AHB1Periph)
PCLK2 = HCLK / 2      (APB2Periph)
PCLK1 = HCLK / 4      (APB1Periph)

因為APB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
因為APB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;

APB1 定時器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14
APB2 定時器有 TIM1, TIM8 ,TIM9, TIM10, TIM11

----------------------------------------------------------------------- */
uiTIMxCLK = SystemCoreClock / 2;

usPrescaler = uiTIMxCLK / 1000000 ; /* 分頻到周期 1us */
usPeriod = 0xFFFF;

/* Time base configuration */
TIM_TimeBaseStructure.TIM_Period = usPeriod;
TIM_TimeBaseStructure.TIM_Prescaler = usPrescaler;
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

TIM_TimeBaseInit(TIM_HARD, &TIM_TimeBaseStructure);

//TIM_ARRPreloadConfig(TIMx, ENABLE);

/* TIMx enable counter */
TIM_Cmd(TIM_HARD, ENABLE);

/* 配置TIM定時中斷 (Update) */
{
NVIC_InitTypeDef NVIC_InitStructure; /* 中斷結構體在 misc.h 中定義 */

NVIC_InitStructure.NVIC_IRQChannel = TIM_HARD_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; /* 比串口優先級低 */
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
}

/*
*********************************************************************************************************
* 函 數 名: bsp_StartHardTimer
* 功能說明: 使用TIM2-5做單次定時器使用, 定時時間到后執行回調函數。可以同時啟動4個定時器,互不干擾。
*             定時精度正負10us (主要耗費在調用本函數的執行時間,函數內部進行了補償減小誤差)
* TIM2和TIM5 是32位定時器。定時范圍很大
* TIM3和TIM4 是16位定時器。
* 形    參: _CC : 捕獲通道幾,1,2,3, 4
*             _uiTimeOut : 超時時間, 單位 1us.       對于16位定時器,最大 65.5ms; 對于32位定時器,最大 4294秒
*             _pCallBack : 定時時間到后,被執行的函數
* 返 回 值: 無
*********************************************************************************************************
*/
void bsp_StartHardTimer(uint8_t _CC, uint32_t _uiTimeOut, void * _pCallBack)
{
    uint32_t cnt_now;
    uint32_t cnt_tar;

    /*
        執行下面這個語句,時長 = 18us (通過邏輯分析儀測量IO翻轉)
        bsp_StartTimer2(3, 500, (void *)test1);
    */
    if (_uiTimeOut < 5)
    {
        ;
    }
    else
    {
        _uiTimeOut -= 5;
    }

    cnt_now = TIM_GetCounter(TIM_HARD);     /* 讀取當前的計數器值 */
    cnt_tar = cnt_now + _uiTimeOut; /* 計算捕獲的計數器值 */
    if (_CC == 1)
    {
        s_TIM_CallBack1 = (void (*)(void))_pCallBack;

        TIM_SetCompare1(TIM_HARD, cnt_tar);       /* 設置捕獲比較計數器CC1 */
        TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC1);
TIM_ITConfig(TIM_HARD, TIM_IT_CC1, ENABLE); /* 使能CC1中斷 */

    }
    else if (_CC == 2)
    {
s_TIM_CallBack2 = (void (*)(void))_pCallBack;

        TIM_SetCompare2(TIM_HARD, cnt_tar);       /* 設置捕獲比較計數器CC2 */
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC2);
TIM_ITConfig(TIM_HARD, TIM_IT_CC2, ENABLE); /* 使能CC2中斷 */
    }
    else if (_CC == 3)
    {
        s_TIM_CallBack3 = (void (*)(void))_pCallBack;

        TIM_SetCompare3(TIM_HARD, cnt_tar);       /* 設置捕獲比較計數器CC3 */
        TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC3);
TIM_ITConfig(TIM_HARD, TIM_IT_CC3, ENABLE); /* 使能CC3中斷 */
    }
    else if (_CC == 4)
    {
        s_TIM_CallBack4 = (void (*)(void))_pCallBack;

        TIM_SetCompare4(TIM_HARD, cnt_tar);       /* 設置捕獲比較計數器CC4 */
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC4);
TIM_ITConfig(TIM_HARD, TIM_IT_CC4, ENABLE); /* 使能CC4中斷 */
    }
else
    {
        return;
    }
}

/*
*********************************************************************************************************
* 函 數 名: TIMx_IRQHandler
* 功能說明: TIM 中斷服務程序
* 形    參:無
* 返 回 值: 無
*********************************************************************************************************
*/
//void TIM2_IRQHandler(void)
//void TIM3_IRQHandler(void)
//void TIM4_IRQHandler(void)
void TIM5_IRQHandler(void)
{
    if (TIM_GetITStatus(TIM_HARD, TIM_IT_CC1))
    {
        TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC1);
        TIM_ITConfig(TIM_HARD, TIM_IT_CC1, DISABLE); /* 禁能CC1中斷 */

        /* 先關閉中斷,再執行回調函數。因為回調函數可能需要重啟定時器 */
        s_TIM_CallBack1();
    }

    if (TIM_GetITStatus(TIM_HARD, TIM_IT_CC2))
    {
        TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC2);
        TIM_ITConfig(TIM_HARD, TIM_IT_CC2, DISABLE); /* 禁能CC2中斷 */

        /* 先關閉中斷,再執行回調函數。因為回調函數可能需要重啟定時器 */
        s_TIM_CallBack2();
    }

    if (TIM_GetITStatus(TIM_HARD, TIM_IT_CC3))
    {
        TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC3);
        TIM_ITConfig(TIM_HARD, TIM_IT_CC3, DISABLE); /* 禁能CC3中斷 */

        /* 先關閉中斷,再執行回調函數。因為回調函數可能需要重啟定時器 */
        s_TIM_CallBack3();
    }

    if (TIM_GetITStatus(TIM_HARD, TIM_IT_CC4))
    {
        TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC4);
        TIM_ITConfig(TIM_HARD, TIM_IT_CC4, DISABLE); /* 禁能CC4中斷 */

        /* 先關閉中斷,再執行回調函數。因為回調函數可能需要重啟定時器 */
        s_TIM_CallBack4();
    }
}
//void bsp_Init(void)
//{
// /*
// 由于ST固件庫的啟動文件已經執行了CPU系統時鐘的初始化,所以不必再次重復配置系統時鐘。
// 啟動文件配置了CPU主時鐘頻率、內部Flash訪問速度和可選的外部SRAM FSMC初始化。

// 系統時鐘缺省配置為168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
// */

// //bsp_InitUart(); /* 初始化串口 */
//// bsp_InitTimer(); /* 初始化系統滴答定時器 */

// /* 針對不同的應用程序,添加需要的底層驅動模塊初始化函數 */

// //bsp_InitLed(); /* 初始LED指示燈端口 */
//}


/*
*********************************************************************************************************
* 函 數 名: bsp_Idle
* 功能說明: 空閑時執行的函數。一般主程序在for和while循環程序體中需要插入 CPU_IDLE() 宏來調用本函數。
* 本函數缺省為空操作。用戶可以添加喂狗、設置CPU進入休眠模式的功能。
* 形    參:無
* 返 回 值: 無
*********************************************************************************************************
*/
//void bsp_Idle(void)
//{
// /* --- 喂狗 */

// /* --- 讓CPU進入休眠,由Systick定時中斷喚醒或者其他中斷喚醒 */

// /* 對于 emWin 圖形庫,可以插入圖形庫需要的輪詢函數 */
// //GUI_Exec();

// /* 對于 uIP 協議實現,可以插入uip輪詢函數 */
//}
 
軟件定時器相應的.H 頭文件:
#ifndef __BSP_TIMER_H
#define __BSP_TIMER_H
#include "bsp_timer.h"

/* 開關全局中斷的宏 */
#define ENABLE_INT() __set_PRIMASK(0) /* 使能全局中斷 */
#define DISABLE_INT() __set_PRIMASK(1) /* 禁止全局中斷 */

/* 這個宏僅用于調試階段排錯 */
#define BSP_Printf printf
//#define BSP_Printf(...)

#include "stm32f10x.h"
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifndef TRUE
#define TRUE  1
#endif

#ifndef FALSE
#define FALSE 0
#endif
/*
在此定義若干個軟件定時器全局變量
注意,必須增加__IO 即 volatile,因為這個變量在中斷和主程序中同時被訪問,有可能造成編譯器錯誤優化。
*/
#define TMR_COUNT 4 /* 軟件定時器的個數 (定時器ID范圍 0 - 3) */

/* 定時器結構體,成員變量必須是 volatile, 否則C編譯器優化時可能有問題 */
typedef enum
{
TMR_ONCE_MODE = 0, /* 一次工作模式 */
TMR_AUTO_MODE = 1 /* 自動定時工作模式 */
}TMR_MODE_E;

/* 定時器結構體,成員變量必須是 volatile, 否則C編譯器優化時可能有問題 */
typedef struct
{
volatile u8 Mode; /* 計數器模式,1次性 */
volatile u8 Flag; /* 定時到達標志  */
volatile u32 Count; /* 計數器 */
volatile u32 PreLoad; /* 計數器預裝值 */
}SOFT_TMR;

/* 提供給其他C文件調用的函數 */
void bsp_InitTimer(void);
void bsp_DelayMS(uint32_t n);
void bsp_DelayUS(uint32_t n);
void bsp_StartTimer(uint8_t _id, uint32_t _period);
void bsp_StartAutoTimer(uint8_t _id, uint32_t _period);
void bsp_StopTimer(uint8_t _id);
uint8_t bsp_CheckTimer(uint8_t _id);
int32_t bsp_GetRunTime(void);

void bsp_InitHardTimer(void);
void bsp_StartHardTimer(uint8_t _CC, uint32_t _uiTimeOut, void * _pCallBack);

#endif



/*
*/


/* 通過取消注釋或者添加注釋的方式控制是否包含底層驅動模塊 */

/*****************************   (END OF FILE) *********************************/


          最后感謝安富萊電子提供的資源。
 ------------------------------GKXW-----2015年12月5日21:35:25---------------------------------------------------- 



 
回復

使用道具 舉報

ID:106794 發表于 2016-6-1 15:21 | 顯示全部樓層
辛苦,感謝分享,贊一個!
回復

使用道具 舉報

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

本版積分規則

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

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 在线天堂免费中文字幕视频 | 国产精品久久久久国产a级 欧美日本韩国一区二区 | 欧美日韩综合 | 在线区| 国产精品自产拍 | 久久久久亚洲精品中文字幕 | 99reav| 日韩成人免费中文字幕 | 亚洲三区在线观看 | 在线视频a | 视频一区在线 | 国产一区二区三区色淫影院 | 人人做人人澡人人爽欧美 | 国产xxxx岁13xxxxhd | 黑人久久 | 国产一区中文字幕 | 国产精品永久免费 | 91豆花视频 | 成年人黄色一级片 | 精品成人在线视频 | 97免费在线观看视频 | av手机在线免费观看 | 成人av电影网 | 欧美成人影院 | 性一交一乱一伦视频免费观看 | 精品国产一区二区三区观看不卡 | 91亚洲国产精品 | 亚洲精品第一 | 亚洲欧美国产精品久久 | 中文字幕在线观看一区 | 色综合国产 | 狠狠久 | 91一区二区三区在线观看 | 美女视频一区 | 日韩一区二区三区在线看 | 亚洲自拍偷拍免费视频 | 91久久爽久久爽爽久久片 | 国久久| 羞羞网站免费观看 | 亚洲一区免费视频 | 一区2区|