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

QQ登錄

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

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

基于時(shí)間觸發(fā)混合式多任務(wù)調(diào)度器設(shè)計(jì)

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
ID:99624 發(fā)表于 2015-12-20 03:09 | 只看該作者 回帖獎(jiǎng)勵(lì) |倒序?yàn)g覽 |閱讀模式
       幾個(gè)星期了,一直被UC/OS-III搞得焦頭爛額;UC/OS-III與II不同之處很多。真正搞懂內(nèi)核原理確實(shí)不易,是塊硬骨頭。但是本人認(rèn)為那就是筋頭巴腦的醬牛肉,越嚼越有味!學(xué)習(xí)之余竟然收獲了時(shí)間觸發(fā)混合式多任務(wù)調(diào)度器設(shè)計(jì)的方法。臥槽,爽!

       操作系統(tǒng)固然好,但是在對(duì)穩(wěn)定性,安全,可靠性要求較高的工程中就不見(jiàn)得好用了。由于嵌入了操作系統(tǒng)導(dǎo)致工程代碼復(fù)雜,調(diào)試程序就要花很長(zhǎng)時(shí)間,搞不好BUG就會(huì)跳出來(lái)害人。本人堅(jiān)信操作系統(tǒng)只能在迫不得已的情況下使用,比如手機(jī),平板電腦等消費(fèi)電子產(chǎn)品。下面的這個(gè)基于時(shí)間觸發(fā)混合式多任務(wù)調(diào)度器已經(jīng)能完成較多任務(wù)的可靠調(diào)度了。

      核心代碼“多任務(wù)”.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]; /*建立的任務(wù)數(shù)*/
/*
*********************************************************************************************************
* 函 數(shù) 名: hSCH_Update(void)
* 功能說(shuō)明: 調(diào)度器的刷新函數(shù),每個(gè)時(shí)標(biāo)中斷執(zhí)行一次。在嘀嗒定時(shí)器中斷里面執(zhí)行。
 當(dāng)刷新函數(shù)確定某個(gè)任務(wù)要執(zhí)行的時(shí)候,將RunMe加1,要注意的是刷新任務(wù)
 不執(zhí)行任何函數(shù),需要運(yùn)行的任務(wù)有調(diào)度函數(shù)激活。
 搶占式任務(wù)需要執(zhí)行的話,立即就會(huì)得到執(zhí)行。
* 形    參:無(wú)
* 返 回 值: 無(wú)
*********************************************************************************************************
*/
void hSCH_Update(void)
{
tByte index;
/*注意計(jì)數(shù)單位是時(shí)標(biāo),不是毫秒*/
for(index = 0; index < hSCH_MAX_TASKS; index++)
{
if(hSCH_task_G[index].pTask)   /*檢測(cè)這里是否有任務(wù)*/
{
if(hSCH_task_G[index].Delay == 0)
{
if(hSCH_task_G[index].Co_op)    /*混合式調(diào)度和合作式調(diào)度的區(qū)分 合作式1 搶占式0*/
{
hSCH_task_G[index].RunMe += 1;  /*合作式任務(wù)需要運(yùn)行 將RunMe置1*/
}
else
{
//注意:“(*hSCH_task_G[index].pTask)”是函數(shù)人口地址
(*hSCH_task_G[index].pTask)();   /*搶占式任務(wù)需要立即運(yùn)行 將RunMe減1*/
//hSCH_task_G[index].RunMe -= 1;
if(hSCH_task_G[index].Period == 0)
{       /*單次執(zhí)行的任務(wù) 則將其清除*/
hSCH_task_G[index].pTask = 0;
}
}
if(hSCH_task_G[index].Period)
{           /*調(diào)度周期性的任務(wù)再次執(zhí)行*/
hSCH_task_G[index].Delay = hSCH_task_G[index].Period;
}
}
else
{              /*還有準(zhǔn)備好運(yùn)行*/
hSCH_task_G[index].Delay -= 1;
}
}
}
}

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


void sTsak_Init(void)
{
/*
由于ST固件庫(kù)的啟動(dòng)文件已經(jīng)執(zhí)行了CPU系統(tǒng)時(shí)鐘的初始化,所以不必再次重復(fù)配置系統(tǒng)時(shí)鐘。
啟動(dòng)文件配置了CPU主時(shí)鐘頻率、內(nèi)部Flash訪問(wèn)速度和可選的外部SRAM FSMC初始化。
系統(tǒng)時(shí)鐘缺省配置為168MHz,如果需要更改,可以修改 system_stm32f4xx.c 文件
*/
// bsp_InitLed(); /* 初始LED指示燈端口 */
//    bsp_InitUart(); /* 初始化串口 */
// bsp_InitKey();      /* 初始化按鍵 */
/*混合式調(diào)度和合作式調(diào)度的區(qū)分 合作式1 搶占式0*/
/* 添加三個(gè)任務(wù) */
hSCH_Add_Task(LedTest, 0, 500, 1);           /* 合作式 周期10ms */
hSCH_Add_Task( Touch_MainTask, 5000, 0, 0);        /* 搶占式 周期0ms 即只運(yùn)行一次*/
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);   
}

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




*/
“多任務(wù)”相應(yīng)的.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)();    /*指向任務(wù)的指針必須是一個(gè)*void(void)*函數(shù);*/
tWord Delay;      /*延時(shí)(時(shí)標(biāo))知道下一個(gè)函數(shù)的運(yùn)行*/
tWord Period;    /*連續(xù)運(yùn)行之間的間隔*/
tByte RunMe;   /*當(dāng)任務(wù)需要運(yùn)行的時(shí)候由調(diào)度器加1*/

    tByte Co_op;   /*混合式調(diào)度和合作式調(diào)度的區(qū)分 合作式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];  /*建立的任務(wù)數(shù)*/ 

#endif


/*****************************  (END OF FILE) *********************************/
下面是軟件定時(shí)器部分.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"
/*
定義用于硬件定時(shí)器的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個(gè)全局變量轉(zhuǎn)用于 bsp_DelayMS() 函數(shù) */
static volatile uint32_t s_uiDelayCount = 0;
static volatile uint8_t s_ucTimeOutFlag = 0;

/* 定于軟件定時(shí)器結(jié)構(gòu)體變量 */
static SOFT_TMR s_tTmr[TMR_COUNT];

/*
全局運(yùn)行時(shí)間,單位1ms
最長(zhǎng)可以表示 24.85天,如果你的產(chǎn)品連續(xù)運(yùn)行時(shí)間超過(guò)這個(gè)數(shù),則必須考慮溢出問(wèn)題
*/
__IO int32_t g_iRunTime = 0;

static void bsp_SoftTimerDec(SOFT_TMR *_tmr);

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

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

/* 清零所有的軟件定時(shí)器 */
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,并啟動(dòng)systick中斷。

    SystemCoreClock 是固件中定義的系統(tǒng)內(nèi)核時(shí)鐘,對(duì)于STM32F4XX,一般為 168MHz

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

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

bsp_InitHardTimer(); /* 開(kāi)啟硬件定時(shí)中斷 */
}
/*
*********************************************************************************************************
* 函 數(shù) 名: bsp_RunPer10ms
* 功能說(shuō)明: 該函數(shù)每隔10ms被Systick中斷調(diào)用1次。詳見(jiàn) bsp_timer.c的定時(shí)中斷服務(wù)程序。一些需要周期性處理
* 的事務(wù)可以放在此函數(shù)。比如:按鍵掃描、蜂鳴器鳴叫控制等。
* 形    參:無(wú)
* 返 回 值: 無(wú)
*********************************************************************************************************
*/
//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();
}

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

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

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

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

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

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

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

/*
*********************************************************************************************************
* 函 數(shù) 名: bsp_SoftTimerDec
* 功能說(shuō)明: 每隔1ms對(duì)所有定時(shí)器變量減1。必須被SysTick_ISR周期性調(diào)用。
* 形    參:  _tmr : 定時(shí)器變量指針
* 返 回 值: 無(wú)
*********************************************************************************************************
*/
static void bsp_SoftTimerDec(SOFT_TMR *_tmr)
{
if (_tmr->Count > 0)
{
/* 如果定時(shí)器變量減到1則設(shè)置定時(shí)器到達(dá)標(biāo)志 */
if (--_tmr->Count == 0)
{
_tmr->Flag = 1;

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

/*
*********************************************************************************************************
* 函 數(shù) 名: bsp_DelayMS
* 功能說(shuō)明: ms級(jí)延遲,延遲精度為正負(fù)1ms
* 形    參:  n : 延遲長(zhǎng)度,單位1 ms。 n 應(yīng)大于2
* 返 回 值: 無(wú)
*********************************************************************************************************
*/
void bsp_DelayMS(uint32_t n)
{
if (n == 0)
{
return;
}
else if (n == 1)
{
n = 2;
}

DISABLE_INT();   /* 關(guān)中斷 */

s_uiDelayCount = n;
s_ucTimeOutFlag = 0;

ENABLE_INT();   /* 開(kāi)中斷 */

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

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

/*
*********************************************************************************************************
*    函 數(shù) 名: bsp_DelayUS
*    功能說(shuō)明: us級(jí)延遲。 必須在systick定時(shí)器啟動(dòng)后才能調(diào)用此函數(shù)。
*    形    參:  n : 延遲長(zhǎng)度,單位1 us
*    返 回 值: 無(wú)
*********************************************************************************************************
*/
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); /* 需要的節(jié)拍數(shù) */

    tcnt = 0;
    told = SysTick->VAL;             /* 剛進(jìn)入時(shí)的計(jì)數(shù)器值 */

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

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


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

DISABLE_INT();   /* 關(guān)中斷 */

s_tTmr[_id].Count = _period; /* 實(shí)時(shí)計(jì)數(shù)器初值 */
s_tTmr[_id].PreLoad = _period; /* 計(jì)數(shù)器自動(dòng)重裝值,僅自動(dòng)模式起作用 */
s_tTmr[_id].Flag = 0; /* 定時(shí)時(shí)間到標(biāo)志 */
s_tTmr[_id].Mode = TMR_ONCE_MODE; /* 1次性工作模式 */

ENABLE_INT();   /* 開(kāi)中斷 */
}

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

DISABLE_INT();   /* 關(guān)中斷 */

s_tTmr[_id].Count = _period; /* 實(shí)時(shí)計(jì)數(shù)器初值 */
s_tTmr[_id].PreLoad = _period; /* 計(jì)數(shù)器自動(dòng)重裝值,僅自動(dòng)模式起作用 */
s_tTmr[_id].Flag = 0; /* 定時(shí)時(shí)間到標(biāo)志 */
s_tTmr[_id].Mode = TMR_AUTO_MODE; /* 自動(dòng)工作模式 */

ENABLE_INT();   /* 開(kāi)中斷 */
}

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

DISABLE_INT();   /* 關(guān)中斷 */

s_tTmr[_id].Count = 0; /* 實(shí)時(shí)計(jì)數(shù)器初值 */
s_tTmr[_id].Flag = 0; /* 定時(shí)時(shí)間到標(biāo)志 */
s_tTmr[_id].Mode = TMR_ONCE_MODE; /* 自動(dòng)工作模式 */

ENABLE_INT();   /* 開(kāi)中斷 */
}

/*
*********************************************************************************************************
* 函 數(shù) 名: bsp_CheckTimer
* 功能說(shuō)明: 檢測(cè)定時(shí)器是否超時(shí)
* 形    參:   _id     : 定時(shí)器ID,值域【0,TMR_COUNT-1】。用戶必須自行維護(hù)定時(shí)器ID,以避免定時(shí)器ID沖突。
* _period : 定時(shí)周期,單位1ms
* 返 回 值: 返回 0 表示定時(shí)未到, 1表示定時(shí)到
*********************************************************************************************************
*/
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;
}
}

/*
*********************************************************************************************************
* 函 數(shù) 名: bsp_GetRunTime
* 功能說(shuō)明: 獲取CPU運(yùn)行時(shí)間,單位1ms。最長(zhǎng)可以表示 24.85天,如果你的產(chǎn)品連續(xù)運(yùn)行時(shí)間超過(guò)這個(gè)數(shù),則必須考慮溢出問(wèn)題
* 形    參:  無(wú)
* 返 回 值: CPU運(yùn)行時(shí)間,單位1ms
*********************************************************************************************************
*/
int32_t bsp_GetRunTime(void)
{
int32_t runtime;

DISABLE_INT();   /* 關(guān)中斷 */

runtime = g_iRunTime; /* 這個(gè)變量在Systick中斷中被改寫(xiě),因此需要關(guān)中斷進(jìn)行保護(hù) */

ENABLE_INT();   /* 開(kāi)中斷 */

return runtime;
}

/*
*********************************************************************************************************
* 函 數(shù) 名: SysTick_Handler
* 功能說(shuō)明: 系統(tǒng)嘀嗒定時(shí)器中斷服務(wù)程序。啟動(dòng)文件中引用了該函數(shù)。
* 形    參:  無(wú)
* 返 回 值: 無(wú)
*********************************************************************************************************
*/
void SysTick_Handler(void)
{
SysTick_ISR();
}

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

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

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

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

因?yàn)锳PB1 prescaler != 1, 所以 APB1上的TIMxCLK = PCLK1 x 2 = SystemCoreClock / 2;
因?yàn)锳PB2 prescaler != 1, 所以 APB2上的TIMxCLK = PCLK2 x 2 = SystemCoreClock;

APB1 定時(shí)器有 TIM2, TIM3 ,TIM4, TIM5, TIM6, TIM7, TIM12, TIM13,TIM14
APB2 定時(shí)器有 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定時(shí)中斷 (Update) */
{
NVIC_InitTypeDef NVIC_InitStructure; /* 中斷結(jié)構(gòu)體在 misc.h 中定義 */

NVIC_InitStructure.NVIC_IRQChannel = TIM_HARD_IRQn;

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

/*
*********************************************************************************************************
* 函 數(shù) 名: bsp_StartHardTimer
* 功能說(shuō)明: 使用TIM2-5做單次定時(shí)器使用, 定時(shí)時(shí)間到后執(zhí)行回調(diào)函數(shù)?梢酝瑫r(shí)啟動(dòng)4個(gè)定時(shí)器,互不干擾。
*             定時(shí)精度正負(fù)10us (主要耗費(fèi)在調(diào)用本函數(shù)的執(zhí)行時(shí)間,函數(shù)內(nèi)部進(jìn)行了補(bǔ)償減小誤差)
* TIM2和TIM5 是32位定時(shí)器。定時(shí)范圍很大
* TIM3和TIM4 是16位定時(shí)器。
* 形    參: _CC : 捕獲通道幾,1,2,3, 4
*             _uiTimeOut : 超時(shí)時(shí)間, 單位 1us.       對(duì)于16位定時(shí)器,最大 65.5ms; 對(duì)于32位定時(shí)器,最大 4294秒
*             _pCallBack : 定時(shí)時(shí)間到后,被執(zhí)行的函數(shù)
* 返 回 值: 無(wú)
*********************************************************************************************************
*/
void bsp_StartHardTimer(uint8_t _CC, uint32_t _uiTimeOut, void * _pCallBack)
{
    uint32_t cnt_now;
    uint32_t cnt_tar;

    /*
        執(zhí)行下面這個(gè)語(yǔ)句,時(shí)長(zhǎng) = 18us (通過(guò)邏輯分析儀測(cè)量IO翻轉(zhuǎn))
        bsp_StartTimer2(3, 500, (void *)test1);
    */
    if (_uiTimeOut < 5)
    {
        ;
    }
    else
    {
        _uiTimeOut -= 5;
    }

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

        TIM_SetCompare1(TIM_HARD, cnt_tar);       /* 設(shè)置捕獲比較計(jì)數(shù)器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);       /* 設(shè)置捕獲比較計(jì)數(shù)器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);       /* 設(shè)置捕獲比較計(jì)數(shù)器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);       /* 設(shè)置捕獲比較計(jì)數(shù)器CC4 */
TIM_ClearITPendingBit(TIM_HARD, TIM_IT_CC4);
TIM_ITConfig(TIM_HARD, TIM_IT_CC4, ENABLE); /* 使能CC4中斷 */
    }
else
    {
        return;
    }
}

/*
*********************************************************************************************************
* 函 數(shù) 名: TIMx_IRQHandler
* 功能說(shuō)明: TIM 中斷服務(wù)程序
* 形    參:無(wú)
* 返 回 值: 無(wú)
*********************************************************************************************************
*/
//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中斷 */

        /* 先關(guān)閉中斷,再執(zhí)行回調(diào)函數(shù)。因?yàn)榛卣{(diào)函數(shù)可能需要重啟定時(shí)器 */
        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中斷 */

        /* 先關(guān)閉中斷,再執(zhí)行回調(diào)函數(shù)。因?yàn)榛卣{(diào)函數(shù)可能需要重啟定時(shí)器 */
        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中斷 */

        /* 先關(guān)閉中斷,再執(zhí)行回調(diào)函數(shù)。因?yàn)榛卣{(diào)函數(shù)可能需要重啟定時(shí)器 */
        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中斷 */

        /* 先關(guān)閉中斷,再執(zhí)行回調(diào)函數(shù)。因?yàn)榛卣{(diào)函數(shù)可能需要重啟定時(shí)器 */
        s_TIM_CallBack4();
    }
}
//void bsp_Init(void)
//{
// /*
// 由于ST固件庫(kù)的啟動(dòng)文件已經(jīng)執(zhí)行了CPU系統(tǒng)時(shí)鐘的初始化,所以不必再次重復(fù)配置系統(tǒng)時(shí)鐘。
// 啟動(dòng)文件配置了CPU主時(shí)鐘頻率、內(nèi)部Flash訪問(wèn)速度和可選的外部SRAM FSMC初始化。

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

// //bsp_InitUart(); /* 初始化串口 */
//// bsp_InitTimer(); /* 初始化系統(tǒng)滴答定時(shí)器 */

// /* 針對(duì)不同的應(yīng)用程序,添加需要的底層驅(qū)動(dòng)模塊初始化函數(shù) */

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


/*
*********************************************************************************************************
* 函 數(shù) 名: bsp_Idle
* 功能說(shuō)明: 空閑時(shí)執(zhí)行的函數(shù)。一般主程序在for和while循環(huán)程序體中需要插入 CPU_IDLE() 宏來(lái)調(diào)用本函數(shù)。
* 本函數(shù)缺省為空操作。用戶可以添加喂狗、設(shè)置CPU進(jìn)入休眠模式的功能。
* 形    參:無(wú)
* 返 回 值: 無(wú)
*********************************************************************************************************
*/
//void bsp_Idle(void)
//{
// /* --- 喂狗 */

// /* --- 讓CPU進(jìn)入休眠,由Systick定時(shí)中斷喚醒或者其他中斷喚醒 */

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

// /* 對(duì)于 uIP 協(xié)議實(shí)現(xiàn),可以插入uip輪詢函數(shù) */
//}
 
軟件定時(shí)器相應(yīng)的.H 頭文件:
#ifndef __BSP_TIMER_H
#define __BSP_TIMER_H
#include "bsp_timer.h"

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

/* 這個(gè)宏僅用于調(diào)試階段排錯(cuò) */
#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
/*
在此定義若干個(gè)軟件定時(shí)器全局變量
注意,必須增加__IO 即 volatile,因?yàn)檫@個(gè)變量在中斷和主程序中同時(shí)被訪問(wèn),有可能造成編譯器錯(cuò)誤優(yōu)化。
*/
#define TMR_COUNT 4 /* 軟件定時(shí)器的個(gè)數(shù) (定時(shí)器ID范圍 0 - 3) */

/* 定時(shí)器結(jié)構(gòu)體,成員變量必須是 volatile, 否則C編譯器優(yōu)化時(shí)可能有問(wèn)題 */
typedef enum
{
TMR_ONCE_MODE = 0, /* 一次工作模式 */
TMR_AUTO_MODE = 1 /* 自動(dòng)定時(shí)工作模式 */
}TMR_MODE_E;

/* 定時(shí)器結(jié)構(gòu)體,成員變量必須是 volatile, 否則C編譯器優(yōu)化時(shí)可能有問(wèn)題 */
typedef struct
{
volatile u8 Mode; /* 計(jì)數(shù)器模式,1次性 */
volatile u8 Flag; /* 定時(shí)到達(dá)標(biāo)志  */
volatile u32 Count; /* 計(jì)數(shù)器 */
volatile u32 PreLoad; /* 計(jì)數(shù)器預(yù)裝值 */
}SOFT_TMR;

/* 提供給其他C文件調(diào)用的函數(shù) */
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



/*
*/


/* 通過(guò)取消注釋或者添加注釋的方式控制是否包含底層驅(qū)動(dòng)模塊 */

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


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



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

使用道具 舉報(bào)

沙發(fā)
ID:106794 發(fā)表于 2016-6-1 15:21 | 只看該作者
辛苦,感謝分享,贊一個(gè)!
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

快速回復(fù) 返回頂部 返回列表