組み込み一般アルゴリズム:時間トリガでの組み込みソフトウェア設計モード


組み込みソフトウェア開発では、システム全体のアーキテクチャを設計することが第一歩となることが多い.OSベースのものもあれば、裸のものもあります.まず裸機についてお話ししますが、多くの人がモノリシック機の裸機開発(OSベース)をしている間に頭の中にアーキテクチャを設計する考えがなく、while(1)サイクルが最後まで続き、ステータスマシンを書くことができるのは基礎がしっかりしている人物だと思います.では、問題は、while(1)は何ですか.「C埋め込みプログラミングデザインモード」という本では、while(1)を「超循環モード」、すなわち埋め込み式の入門バカモードと呼ぶ.このモードではフロントの傍受があってもシステムのリアルタイム性が馬鹿になるに違いない.ハードウェアからの分析:while(1)の高いCPU占有率も消費電力を大幅に向上させた.もちろん、合理的であり、スーパーサイクルモードは安全性と信頼性において非常に優れている.構造が簡単で理解しやすいが、これは安全性の要求が高いシステムにとって魅力的ではない.
このように多くのコードに言及して本当につまらないで、具体的な本を読むようにしましょう、強烈に《C埋め込み式のプログラミングの設計のモード》を推薦して、ここでも1つの小さい広告をします:友达が2年編纂する埋め込み式の設計の構造の書籍に没頭します(飛思カールのシリーズMCUに基づいて)も来年初めに清華大学の出版社から出版して、飛思カールが好きな学友は関心を持つことができます.
/**
  ******************************************************************************
  * @file    cx_sch.c
  * @author  CX
  * @version V1.0.0.1
  * @date    2016-7-26
  * @brief   1.0.0.1
	             ,        
	       RunNum     ,            
	     1.0.0.0 
	             
  ******************************************************************************
  * @attention
  *
  *      :None
  *      : None
  *     :None
  ******************************************************************************
  */


#include "cx_sch.h"



sTask_Typedef SCH_tasks_G[SCH_MAX_TASKS];



/**
  * @brief       
  * @param   pFunction     , Delay     , Peroid       , RunNum       , ModeEnum     
  * @retval        
  * @notice  None
*/
uint8_t SCH_Add_Task(void(*pFunction)(), uint32_t Delay, uint32_t Peroid, uint8_t RunNum, TaskMode_Enum ModeEnum)
{
	uint8_t Index = 0;
	while((SCH_tasks_G[Index].pTask != 0) && (Index < SCH_MAX_TASKS))	
	{
		Index++;                                                             
	}
	if(Index == SCH_MAX_TASKS)
	{
		return SCH_MAX_TASKS;
	}
	SCH_tasks_G[Index].pTask = pFunction;
	SCH_tasks_G[Index].Delay = Delay;
	SCH_tasks_G[Index].Peroid = Peroid;
	SCH_tasks_G[Index].RunMe = 0;
#if RunNum_ON
	SCH_tasks_G[Index].RunNum = RunNum;
#endif
	SCH_tasks_G[Index].ModeEnum = ModeEnum;
	return Index;
}



/**
  * @brief       
  * @param   Index,       
  * @retval  None
  * @notice  None
*/
void SCH_Delete_Tasks(uint8_t Index)
{
	SCH_tasks_G[Index].pTask = 0;
	SCH_tasks_G[Index].Delay = 0;
	SCH_tasks_G[Index].Peroid = 0;
	SCH_tasks_G[Index].RunMe = 0;
#if RunNum_ON
	SCH_tasks_G[Index].RunNum = 0;
#endif
}



/**
  * @brief       
  * @param   None
  * @retval  None
  * @notice        ,                     
*/
void SCH_Update_Tasks(void)
{
	u8 Index;
	for(Index = 0;Index < SCH_MAX_TASKS;Index++)
	{
		if(SCH_tasks_G[Index].pTask)
		{
			if(SCH_tasks_G[Index].Delay == 0)   
			{
				switch(SCH_tasks_G[Index].ModeEnum)
				{
					case SEIZ_Enum:                         //        
						SCH_tasks_G[Index].pTask();
						if(SCH_tasks_G[Index].RunMe > 0)
						{
							SCH_tasks_G[Index].RunMe--;
#if RunNum_ON
							if(SCH_tasks_G[Index].RunNum > 0)
							{
								SCH_tasks_G[Index].RunNum--;
								if(SCH_tasks_G[Index].RunNum == 0)
								{
									SCH_Delete_Tasks(Index);
								}	
							}
#endif
						}
						break;
					case COOP_Enum:
						SCH_tasks_G[Index].RunMe++;     
						break;
					default:break;
				}				
				if(SCH_tasks_G[Index].Peroid)
				{
					SCH_tasks_G[Index].Delay = SCH_tasks_G[Index].Peroid;
				}
			}
			else
			{
				SCH_tasks_G[Index].Delay--;     
			}
		}
	}
}



/**
  * @brief        
  * @param   None
  * @retval  None
  * @notice  None
*/
void SCH_Dispatch_Tasks(void)
{
	u8 Index;
	while(1)
	{
		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--;
#if RunNum_ON
				if(SCH_tasks_G[Index].RunNum > 0)
				{
					SCH_tasks_G[Index].RunNum--;
					if(SCH_tasks_G[Index].RunNum == 0)
					{
						SCH_Delete_Tasks(Index);
					}	
				}
#endif
				if(SCH_tasks_G[Index].Peroid == 0)
				{
					SCH_Delete_Tasks(Index);
				}
			}
		}
	}
}



/**
  * @brief        
  * @param   None
  * @retval  None
  * @notice  None
*/
void SCH_Init(void)
{
	TIM2Base_Config(10);
}


/**
  * @brief         
  * @param   None
  * @retval  None
  * @notice  None
*/
void SCH_Start(void)
{
	TIM_Cmd(TIM2, ENABLE);	
}
#ifndef __CX_SCH_H
#define __CX_SCH_H


#include "stm32f10x.h"
#include "cx_timbase.h"


#define      RunNum_ON          0


typedef enum
{
	COOP_Enum = 0x0,
	SEIZ_Enum = 0x1
}TaskMode_Enum;




typedef struct
{
	void (*pTask)(void); 
	uint32_t Delay;			       
	uint32_t Peroid;		     
	uint8_t RunMe;		               //      
#if RunNum_ON
	uint8_t RunNum;                        //        ,       
#endif
	TaskMode_Enum ModeEnum;
}sTask_Typedef;




#define      SCH_MAX_TASKS         10


void SCH_Init(void);
void SCH_Start(void);
uint8_t SCH_Add_Task(void(*pFunction)(), uint32_t Delay, uint32_t Peroid, uint8_t RunNum, TaskMode_Enum ModeEnum);
void SCH_Update_Tasks(void);
void SCH_Dispatch_Tasks(void);
void SCH_Delete_Tasks(uint8_t Index);



#endif

古い規則で、コードを分析しないで、コードを加えても何行もなくて、データの構造も簡単で、心を静めてきっと理解することができます.このコードは51チップマシン(12 MHZ,12 T)で実際に1 msのタイムスケールでテストされ、12個のタスクを満載したCPUの使用率は89%にとどまり、依然として11%の空きがある.国産STC 15シリーズの1 Tチップマシンを使用する場合は正反対と推定される(実際にテストしたことがなく、推測するだけ).
コードを理解した後、ループスケジューリングの下で応答イベントが遅延し、リアルタイム性が低下したと聞かれるかもしれません.では、このような疑問に対して、以下の点をお話ししたいと思います.
1:遅延は相対的であり,ポーリングスケジューリングの応答速度は,スーパーサイクルシステムのwhile(1)+割り込みフラグビット+ブロック遅延よりも十分速い.
2:サイクルスケジューリングは一般的には短いタスクを追加したほうがいいです.長いタスクは無視したほうがいいです.なぜか、自分で考えましょう.
3:このコードはオペレーティングシステムを書いているのではなく、組み込みシステムのコードの一部としてしか使えません.
4:タスクの手ぶれは避けられない.あなたがプリエンプトコアでない限り、CPUの使用権をプリエンプトすることができる.私は菜鳥を編んで、書けません.
5:はっきり言って、このコードはヌード機の開発に限られます.
感謝、感謝...  ...
使用中にバグが発生した場合は、本人のQQ:951253606に連絡し、バグ現象と再現過程を説明してください.
MCUの製品の開発を求めて私の本人のQQ:951253606に連絡してください.