搜索
bottom↓
回复: 55

移植于atmega16、gcc上的时间调度器程序(多任务处理)

[复制链接]

出0入0汤圆

发表于 2005-8-5 23:06:22 | 显示全部楼层 |阅读模式
首先感谢sunhorse和原作者,思想什么的可以参考《时间触发嵌入式系统设计模式》(pattern for time-triggered edmedded system ,building reliable applications with the 8051 family of microcontrollers)或者http://www.21icbbs.com/club/bbs/bbsView.asp?boardid=11



时间调度器说明:我感觉是按照一定的时间间隔(比如1ms)扫描所有现有,执行该执行的,其他任务做删除或等待处理。和合作机制(就像排队等车),不是抢占的。



声明,对原作者的感谢和代码的所有权等问题同sunhorse所说。以下程序中不再另注。

还有,我是头一次发个比较正规的贴,希望大家多提意见。:P



说明:移植的sunhorse提供的所有代码,并将闪灯例子加入方便实际应用。



代码结构:

MySch.h   调度器公用头文件。

SCH.c     调度器内核程序。

MySch.c   实际应用主程序

LED_FLASH.c LED_FLASH.h 闪灯例子用户代码



硬件连接: PB0接一个灯



功能: 暂实现一个任务--灯1s间隔闪烁,用户可以自己加任务。(每一个任务消耗 7 bytes RAM)



点击此处下载armok0162266.rar






-----此内容被greatsnows于2005-08-10,17:48:40编辑过

阿莫论坛20周年了!感谢大家的支持与爱护!!

月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!

出0入0汤圆

 楼主| 发表于 2005-8-5 23:06:48 | 显示全部楼层
//MySch.h : header file for the MySch project

//



#ifndef _SCH51_H_

#define _SCH51_H_



#ifndef __AVR_ATmega16__

#define __AVR_ATmega16__

#endif



#define OSC_FREQ                 (8000000UL)

//#define __MCU_CLOCK_FREQUENCY__ _8.0000_MHz



#include <io.h>

#include <wdt.h>

#include <sleep.h>

#include <Interrupt.h>

#include <sig-avr.h>

#include <inttypes.h>



/////////////////////////////////////////////////////////////////////////////

//MySch





// Misc #defines

#ifndef     TRUE



#define     FALSE         0

#define     TRUE         (!FALSE)



#endif



#define RETURN_NORMAL             0

#define RETURN_ERROR              1

///////////////////////////////////////////////////

//函数声明和任务结构体定义



// 定义调度器数据结构

// 每一个任务消耗 7 bytes RAM

typedef struct data

{

   //定义函数类型指针,const关键字意思是这是一个指向flash的指针

   const void (*pTask)(void);  



   

   uint16_t Delay;      // 任务第一次被执行前的延迟时间,如果为0则立即执行

   

   

   uint16_t Period;     // 任务的执行间隔时间,如果为0,则只执行一次



   



   uint8_t RunMe;          // 任务执行标志为,1 等待执行,0 不需要执行

     

} sTask;                 //sTask是结构体变量





#endif







// 调度器内核

// 本文件所有函数

//*****************************************************

void SCH_Init_T0(void);

void SCH_Start(void);

void SCH_Manual_Timer0_Reload(void);

// 调度器对外部接口

void SCH_RUN_Tasks(void);

uint8_t SCH_Add_Task(const void (*pFunction)(void),

                   uint16_t DELAY,

                   uint16_t PERIOD);

uint8_t SCH_Delete_Task(uint8_t TASK_INDEX);









// 调度器支持的任务个数,用户在调用调度器的时候必须设置

#define SCH_MAX_TASKS               1

出0入0汤圆

 楼主| 发表于 2005-8-5 23:07:24 | 显示全部楼层
#include "MySch.h"



/////////////////////////////////////////////////////////////////////////////

//SCH.c 调度器内核函数





//   任务调度器数组

sTask SCH_tasks_G[SCH_MAX_TASKS];





/*

***********************************************

*  void SCH_Init_T0(void)

***********************************************

*/



void SCH_Init_T0(void)

{

      

    TCCR0 = (1<<CS01)|(1<<CS00);        //1024分频

    uint8_t i;

    for (i = 0; i < SCH_MAX_TASKS; i++)

    {

        SCH_Delete_Task(i);                //删除不必要的任务

    }



    // 定时器0,8位定时,手动重装

    TIMSK &= 0xFD;         // Clear all T0 bits (T1,2 left unchanged)



    // 设置定时器0的初志

    SCH_Manual_Timer0_Reload();         //填装函数



    //  Interrupt Timer 0 enabled

    TIMSK |= 0x01;

}







/*

************************************************

*  void SCH_Start(void)

***********************************************

*/

void SCH_Start(void)

{

   sei();                            //开启全局中断

}



/*

************************************************************

*  

* void SCH_Update(void) interrupt INTERRUPT_Timer_0_Overflow

*

*************************************************************

*/

SIGNAL(SIG_OVERFLOW0)

{

    uint8_t Index;



    SCH_Manual_Timer0_Reload();



    for ( Index = 0;  Index < SCH_MAX_TASKS;  Index++ )

    {

        if (SCH_tasks_G[Index].pTask)

        {

            //**********************************************************

           if (SCH_tasks_G[Index].Delay == 0)

           {

                  // 给可以被调度的任务设置标志位

                // 说明:任务运行标志位不具有存储功能,也就是说,如果在规定的

                //       间隔内没有被运行,则机会丧失

                SCH_tasks_G[Index].RunMe += 1;  // Inc. the 'Run Me' flag



                   if (SCH_tasks_G[Index].Period)//将任务需要的延时装入

                   {

                       SCH_tasks_G[Index].Delay = SCH_tasks_G[Index].Period;

                }

             }

            //************************************************************

            else

             {

                    SCH_tasks_G[Index].Delay -= 1;//延时-1

             }

            //************************************************************

        }         

    }

}



/*

************************************************************

*  

* void SCH_Manual_Timer0_Reload()

*

*************************************************************

*/

void SCH_Manual_Timer0_Reload()

{

   // Stop timer

   TCNT0=0X83;                        //64分频下1ms

}



/*

********************************************************************************************************

*     

*                             任务调度器内核

*

********************************************************************************************************

*/





/*

************************************************************

*  

* void SCH_RUN_Tasks(void)

*

************************************************************

*/

void SCH_RUN_Tasks(void)

{

   uint8_t Index;



   // 调度器调度任务

   for (Index = 0; Index < SCH_MAX_TASKS; Index++)

   {

      if (SCH_tasks_G[Index].RunMe > 0)

      {

         (*SCH_tasks_G[Index].pTask)();  // 运行任务



         SCH_tasks_G[Index].RunMe -= 1;  // 清除任务标志位



         // 如果任务只要求运行一次,则删除任务

         if (SCH_tasks_G[Index].Period == 0)

         {

            SCH_Delete_Task(Index);

         }

      }

   }

}



/*

************************************************************

*  

*     uchar SCH_Add_Task

*

*************************************************************

*/

uint8_t SCH_Add_Task( const void (*pFunction)(void),

                    uint16_t DELAY,

                    uint16_t PERIOD)   

{

   uint8_t Index = 0;

   

   while ((SCH_tasks_G[Index].pTask != 0) && (Index < SCH_MAX_TASKS))

   {

      Index++;                    

   }

   

   // Have we reached the end of the list?   

   if (Index == SCH_MAX_TASKS)

   {

      // Task list is full

      

      return SCH_MAX_TASKS;  

    }

      

   // If we're here, there is a space in the task array

   SCH_tasks_G[Index].pTask  = pFunction;

     

   SCH_tasks_G[Index].Delay  = DELAY;

   SCH_tasks_G[Index].Period = PERIOD;



   SCH_tasks_G[Index].RunMe  = 0;



   return Index; // return position of task (to allow later deletion)

}



/*

************************************************************

*  

*     uint8_t SCH_Delete_Task(const uchar TASK_INDEX)

*

*************************************************************

*/

uint8_t SCH_Delete_Task( uint8_t TASK_INDEX)

{

   SCH_tasks_G[TASK_INDEX].pTask   = 0x0000;

   SCH_tasks_G[TASK_INDEX].Delay   = 0;

   SCH_tasks_G[TASK_INDEX].Period  = 0;



   SCH_tasks_G[TASK_INDEX].RunMe   = 0;



   return 0;       // return status

}

出0入0汤圆

 楼主| 发表于 2005-8-5 23:07:47 | 显示全部楼层
//MySch.c : source file for the MySch project

//



#include "MySch.h"



/////////////////////////////////////////////////////////////////////////////

//MySch     主程序

extern const void LED_Flash_Update(void);        //用于闪灯,实际中可代替

extern void LED_Flash_Init(void);                //用于闪灯,实际中可代替

   

static void io_init(void)

{

    //{{WIZARD_MAP(General)

    //}}WIZARD_MAP(General)



    //{{WIZARD_MAP(I/O Ports)

    // PortA

    PORTA = 0x0;

    DDRA = 0x0;

    // PortB

    PORTB = 0x01;

    DDRB = 0x01;

    // PortC

    PORTC = 0x0;

    DDRC = 0x0;

    // PortD

    PORTD = 0x0;

    DDRD = 0x0;

    //}}WIZARD_MAP(I/O Ports)



    //{{WIZARD_MAP(Watchdog)

    // Watchdog Disabled

    wdt_disable();

    //}}WIZARD_MAP(Watchdog)



    //{{WIZARD_MAP(Analog Comparator)

    // Analog Comparator Disabled

    ACSR = 0x80;

    //}}WIZARD_MAP(Analog Comparator)

}



int main(void)

{

    //{{WIZARD_MAP(Initialization)

    io_init();

    //}}WIZARD_MAP(Initialization)

    // TODO: Add extra initialization here

   

    //{{WIZARD_MAP(Global interrupt)

    //}}WIZARD_MAP(Global interrupt)

   

    SCH_Init_T0();

    LED_Flash_Init();                            //用于闪灯,实际中可代替

    SCH_Add_Task(LED_Flash_Update, 0, 1000);    //用于闪灯,实际中可代替LED_Flash_Update

    SCH_Start();

     

    while(1)  

    {

        SCH_RUN_Tasks();

        // TODO: Add your code here

        

    }

}

出0入0汤圆

 楼主| 发表于 2005-8-5 23:08:01 | 显示全部楼层
//LED_FLASH.h : header file for the MySch project

//

///////////////////////////////////////////////////////

//用于测试闪灯代码



//#ifndef _LED_FLASH_H_

//#define _LED_FLASH_H_



#ifndef __AVR_ATmega16__

#define __AVR_ATmega16__

#endif





#include <io.h>

#include <wdt.h>

#include <sleep.h>

#include <Interrupt.h>

#include <sig-avr.h>

#include <inttypes.h>



/////////////////////////////////////////////////////////////////////////////







// Misc #defines

#define LED_ON sbi(PORTB,0)

#define LED_OFF cbi(PORTB,0)

出0入0汤圆

 楼主| 发表于 2005-8-5 23:08:16 | 显示全部楼层
#include "LED_FLASH.h"

///////////////////////////////////////////////////////

//用于测试闪灯代码



// ------ Private variable definitions -----------------------------



static uint8_t LED_state_G;



/*------------------------------------------------------------------*-



  LED_Flash_Init()



-*------------------------------------------------------------------*/

void LED_Flash_Init(void)

   {

   LED_state_G = 0;

   }



const void LED_Flash_Update(void)

   {

   // Change the LED from OFF to ON (or vice versa)

   if (LED_state_G == 1)

      {

      LED_state_G = 0;

      LED_OFF;

      }

   else

      {

      LED_state_G = 1;

      LED_ON;

      }

   }

出10入210汤圆

发表于 2005-8-6 08:43:33 | 显示全部楼层
先頂一下

出0入0汤圆

发表于 2005-8-6 09:00:15 | 显示全部楼层
楼主很厚道

出0入0汤圆

发表于 2005-8-6 22:40:49 | 显示全部楼层
好贴!



能否做成一个软件包的形式放在网站上作为例子呢?

出0入0汤圆

 楼主| 发表于 2005-8-7 20:42:02 | 显示全部楼层
我回去就加上,呵呵
-----此内容被greatsnows于2005-08-08,20:09:29编辑过

出0入0汤圆

发表于 2006-8-22 21:34:23 | 显示全部楼层
好贴,多学习

出0入4汤圆

发表于 2006-8-23 08:09:46 | 显示全部楼层
《时间触发嵌入式系统设计模式》,我很喜欢这本英国人写的书!

出0入0汤圆

发表于 2006-10-20 22:53:25 | 显示全部楼层
《时间触发嵌入式系统设计模式》,我也很喜欢这本书!!

出0入0汤圆

发表于 2007-2-13 00:13:55 | 显示全部楼层
多学习

出0入0汤圆

发表于 2007-5-3 18:08:33 | 显示全部楼层
菜鸟开眼见了,谢谢楼主!

出0入0汤圆

发表于 2007-5-3 20:03:00 | 显示全部楼层
多谢楼主分享。Small RTOS移植到ATmega16,有没有人赶兴趣??



《时间触发嵌入式系统设计模式》是英文的,还是有中文翻译版?

出0入0汤圆

发表于 2009-3-5 22:56:10 | 显示全部楼层
写的很多,有时间回去好好读读

出0入0汤圆

发表于 2009-3-6 08:36:57 | 显示全部楼层
Mark一下!

出0入0汤圆

发表于 2009-3-6 09:48:07 | 显示全部楼层
Mark一下!

出0入0汤圆

发表于 2009-3-6 09:53:41 | 显示全部楼层
不错。

出0入0汤圆

发表于 2009-3-6 13:14:42 | 显示全部楼层
学习中..

出0入0汤圆

发表于 2009-3-6 20:31:05 | 显示全部楼层
MARK

出0入0汤圆

发表于 2009-3-6 21:12:23 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-3-6 21:53:16 | 显示全部楼层
已经在M8上采用这个调度器做了两个项目了。很爽

出0入0汤圆

发表于 2009-3-7 08:29:13 | 显示全部楼层
mark!

出0入0汤圆

发表于 2009-12-28 13:56:41 | 显示全部楼层
mark

出0入0汤圆

发表于 2009-12-28 22:00:14 | 显示全部楼层
先MARK一下。有空了再来认真读一下。

出0入0汤圆

发表于 2009-12-28 22:11:14 | 显示全部楼层
用于时间要求不是很高场合确实不错。

出0入0汤圆

发表于 2009-12-30 19:06:22 | 显示全部楼层
关注

出0入0汤圆

发表于 2010-1-12 21:26:35 | 显示全部楼层
学习学习,有点像ucos II啊

出0入0汤圆

发表于 2010-5-29 12:56:32 | 显示全部楼层
mark

出675入8汤圆

发表于 2010-5-29 13:17:35 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-6-3 15:31:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-6-3 17:07:26 | 显示全部楼层
"时间触发“不是银弹。

出0入0汤圆

发表于 2010-6-4 14:29:07 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-7-31 10:32:31 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-7-31 15:52:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-1 00:15:52 | 显示全部楼层
mark!

出0入0汤圆

发表于 2010-8-1 00:21:15 | 显示全部楼层
标记一下

出0入0汤圆

发表于 2010-8-17 22:39:33 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-20 20:30:37 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-8-20 21:18:28 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-9-20 17:20:22 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-1-1 13:40:14 | 显示全部楼层
脚印!

出0入0汤圆

发表于 2011-1-1 19:27:28 | 显示全部楼层
看看,哪天移植到ST上试试

出0入0汤圆

发表于 2011-1-26 09:01:39 | 显示全部楼层
脚印

出0入0汤圆

发表于 2011-8-11 21:57:42 | 显示全部楼层
mark

出0入0汤圆

发表于 2011-8-17 20:49:51 | 显示全部楼层
标记

出0入0汤圆

发表于 2012-7-27 12:51:26 | 显示全部楼层
特意找来学习

出0入8汤圆

发表于 2012-7-28 16:42:59 | 显示全部楼层
时间调度 mark

出0入0汤圆

发表于 2014-7-15 22:39:41 | 显示全部楼层
liuchangyin 发表于 2010-1-12 21:26
学习学习,有点像ucos II啊

哪里像UCOS了。。

出0入0汤圆

发表于 2014-7-15 23:45:16 | 显示全部楼层
好贴呀,收藏中,思想值得学习。

出0入0汤圆

发表于 2014-7-15 23:45:37 | 显示全部楼层
好贴呀,收藏

出0入8汤圆

发表于 2014-7-16 08:46:50 | 显示全部楼层
还好,我试试在128上可以不~

出0入0汤圆

发表于 2016-8-10 21:04:03 | 显示全部楼层
有个问题不太明白,调度代码实际上是一个前后台系统,前台运行的是SCH_RUN_Tasks函数,后台由定时器中断构成SIGNAL(SIG_OVERFLOW0) ,两个函数中共同使用了任务调度数组SCH_tasks_G[],那么就存在共享冲突的问题,这个代码里似乎没有保护。是不是该用临界区(关总中断)保护一下呢?

出0入70汤圆

发表于 2017-3-25 14:59:28 | 显示全部楼层
这不就是在定时回调而已吗?
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-25 19:41

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表