8
本帖最后由 HARRY007 于 2017-12-13 12:50 编辑
一、事情的起因
最近天气不热不冷,晚上睡觉前我特别喜欢在床头用我的USB小风扇吹一会儿。但是睡着了一直吹又不好,所以就很纠结。最近也在学习程序思想框架,看了一些前辈的视频和一些大牛写的书,深受启发,所以就想搞块单片机小板子验证一下程序思想框架,正好借这个风扇的问题,做一个定时开关的板子,一举多得啊~
二、画板、材料购买、投板
三、效果
昨晚板子焊接好了,随便写了一个用的代码先凑合着用着,准备有时间了用学到的新思想框架重新写一下代码,可能的话就跟着这个帖子一起贴出来。最终的使用效果图就是这样的,忽略我的小窝……
四、STM8的资料
【福利】说了这么多放一些我在学习这个单片机中用到的一些资料,我感觉没用的就不上传了。
编译环境软件IAR: http://pan.baidu.com/s/1eSHRfEi 密码:exlf
五、程序
今天先放一个临时为了吹风扇我在以前的工程中改的版本,其中控制继电器的部分都没有创建专门的.c和.h,直接写在了led驱动函数里。代码的程序风格参考了我学生时代的胡老师、论坛的大牛吴坚鸿前辈还有STM8的风驰前辈等等,特此说明。此版本的代码较简单,我接下来的意思是希望在这个简单的例程代码中加入调度器,并且尽量的实现底层单片机外设和应用层代码的隔离,便于移植,小菜自娱自乐,大牛们拍砖要轻点。后续新版本代码写了再更新了~
六、程序V1.1版本—混合式调度器
逛论坛的时候发现很多单片机初学者纠结于任务的执行,抱怨51的执行速度是多么多么的慢,仔细看过他们的代码后发现很多代码是这样写的:
task_one();
delayms(100);
task_two();
delayms(10);
task_three();
很容易发现由于延时代码的存在,导致CPU被严重的霸占了,做了很多无用功。单片机在内核的基础上加了很多服务用的外设,比如最常见的定时器,它可以独立在CPU工作之外并行运行,所以利用定时器可以做很多需要“等待”的任务。
基于合作式或者抢占式的调度器前辈们已经做了大量的实验探究和谈论,单片机实现抢占式难度较大,我们单兵去开发一个要求也是非常高的。相对而言,合作式调度器就容易太多了。之余还不清楚啥叫合作式和抢占式调度器的童鞋们不要着急,接下来我会上传一本非常经典的书:《时间触发嵌入式系统设计模式——8051系列微控制器开发可靠应用》,本次设计也是在该书的作者Michael J. Pont的代码基础上进行了一些增删。同时也参考了刘兵大大的C控件设计思想,不过刘兵大大的代码我是不能随便上传的,所以只是稍微引用了一些,不过思想毕竟是合作式调度器,所以还是会有一些相近的地方,海涵。
[code]/************************ (C) COPYRIGHT HARRY007 *******************************
* 文件名 :Task_Scheduler.c
* 描述 :合作式调度器C文件
* 库版本 :V2.1.0
* 作者 :HARRY007 参考:Michael J. Pont , liubing等人
* 修改时间 :2016-09-11
*******************************************************************************/
/* 包含自定义头文件 */
#include "head.h"
sTaskH hSCH_tasks_G[hSCH_MAX_TASKS];
/*******************************************************************************
* 名称: hSCH_Init
* 功能: 任务初始化
* 形参: 无
* 返回: 无
* 说明: 无
******************************************************************************/
void hSCH_Init(void)
{
u8 i;
for(i = 0;i < hSCH_MAX_TASKS;i ++)
{
hSCH_tasks_G.pTask = NULL;
hSCH_tasks_G.Delay = 0;
hSCH_tasks_G.Period = 0;
hSCH_tasks_G.RunMe = 0;
hSCH_tasks_G.Co_op = 1;
}
}
/*******************************************************************************
* 名称: hSCH_Dispatch_Tasks
* 功能: 任务调度
* 形参: 无
* 返回: 无
* 说明: 需要放在主函数超级大循环中
******************************************************************************/
void hSCH_Dispatch_Tasks(void)
{
u8 Index;
for (Index = 0; Index < hSCH_MAX_TASKS; Index++)//遍历所有任务
{
if ((hSCH_tasks_G[Index].Co_op) && (hSCH_tasks_G[Index].RunMe > 0)) //某任务是否就绪
{
if(hSCH_tasks_G[Index].pTask != NULL)//需要执行任务是否真正存在
{
hSCH_tasks_G[Index].pTask();//执行任务
}
hSCH_tasks_G[Index].RunMe -= 1; //任务执行完成后减1
}
if (hSCH_tasks_G[Index].Period == 0)//如果调度周期为0,则删除任务
{
hSCH_tasks_G[Index].pTask = NULL;//将任务执行
}
}
}
/*******************************************************************************
* 名称: SCH_Add_Task
* 功能: 添加任务
* 形参: 任务函数指针,首次开始执行时间,调度周期,任务类型
* 返回: 结构体指针sTaskH
* 说明: 无
******************************************************************************/
sTaskH *SCH_Add_Task(TASK_SCH *pFunction, u16 DELAY, u16 PERIOD,u8 task_mode)
{
static u8 Index = 0;
if (Index < hSCH_MAX_TASKS)
{
hSCH_tasks_G[Index].pTask = pFunction;//函数指针送过来
hSCH_tasks_G[Index].Delay = DELAY; //延迟DELAY后开始首次执行
hSCH_tasks_G[Index].Period = PERIOD; //调度周期
hSCH_tasks_G[Index].RunMe = 0; //等待不执行
hSCH_tasks_G[Index].Co_op = task_mode; //配置任务类型
Index++;
}
return &hSCH_tasks_G[Index-1];
}
/*******************************************************************************
* 名称: SCH_Delete_Task
* 功能: 任务删除
* 形参: 结构体指针sTaskH
* 返回: 无
* 说明: 代码没有真的删除,只是不执行这个任务而已,指向空指针
******************************************************************************/
void SCH_Delete_Task(sTaskH *task)
{
task->pTask = NULL;
task->Delay = 0;
task->Period = 0;
task->RunMe = 0;
}
/*******************************************************************************
* 名称: SCH_Update
* 功能: 任务调度时间更新
* 形参: 无
* 返回: 无
* 说明: 需要放在定时器中断函数中
******************************************************************************/
void SCH_Update(void)
{
u8 Index_temp;
for (Index_temp = 0; Index_temp < hSCH_MAX_TASKS; Index_temp++)
{
if(hSCH_tasks_G[Index_temp].pTask)
{
if(hSCH_tasks_G[Index_temp].Delay == 0)
{
if(hSCH_tasks_G[Index_temp].Co_op)//合作式
{
hSCH_tasks_G[Index_temp].RunMe += 1;
}
else//抢占式
{
if( hSCH_tasks_G[Index_temp].pTask != NULL )
{
hSCH_tasks_G[Index_temp].pTask(); //执行任务
hSCH_tasks_G[Index_temp].RunMe -= 1; //任务执行完成后减1
}
}
if(hSCH_tasks_G[Index_temp].Period)
{
hSCH_tasks_G[Index_temp].Delay = hSCH_tasks_G[Index_temp].Period;
}
}
else
{
hSCH_tasks_G[Index_temp].Delay -= 1;
}
}
}
}
/************************ (C) COPYRIGHT HARRY007 *****END OF FILE**************/
/************************ (C) COPYRIGHT HARRY007 *******************************
* 文件名 :Task_Scheduler.h
* 描述 :合作式调度器H文件
* 库版本 :V2.1.0
* 作者 :HARRY007 参考:Michael J. Pont , liubing等人
* 修改时间 :2016-09-11
*******************************************************************************/
#ifndef __TASK_SCHEDULER_H
#define __TASK_SCHEDULER_H
#define hSCH_MAX_TASKS 2 //最大允许任务数量
typedef void *TASK_SCH(void);
typedef struct
{
TASK_SCH *pTask;//待执行任务
u16 Delay; //首次执行等待时间
u16 Period; //调度周期
u8 RunMe; //就绪标志
u8 Co_op; //抢占式任务标志 1:合作 0:抢占
}sTaskH;
extern sTaskH hSCH_tasks_G[hSCH_MAX_TASKS];
void hSCH_Init(void);
void hSCH_Dispatch_Tasks(void);
sTaskH *SCH_Add_Task(TASK_SCH *pFunction, u16 DELAY, u16 PERIOD,u8 task_mode);
void SCH_Delete_Task(sTaskH *task);
void SCH_Update(void);
#endif
/************************ (C) COPYRIGHT HARRY007 *****END OF FILE**************/
混合式调度的.c和.h文件就在上面了。应用很简单,在主函数中main.c中:
sTaskH *TASK_ONE;
……
void main(void)
{
system_init();//上电初始化
enableInterrupts();//总中断允许
hSCH_Init();//任务初始化
TASK_ONE = SCH_Add_Task((TASK_SCH *)Led_SystemRun,2000,500,1);//添加LED指示任务
SCH_Add_Task((TASK_SCH *)LED2,0,50,0);//添加LED指示任务
while (1)
{
//IWDG_ReloadCounter();//喂狗
Led_WorkRun();
KEY_Pro();
hSCH_Dispatch_Tasks();//任务调度
}
}
在定时器中断中还需要执行SCH_Update();函数,实现任务的计时和状态等的更新:
INTERRUPT_HANDLER(TIM4_UPD_OVF_IRQHandler, 23)
{//1MS
/* In order to detect unexpected events during development,
it is recommended to set a breakpoint on the following instruction.
*/
KEY_Scan();
SCH_Update();
TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
}
还是那句话,站在巨人的肩膀上才能看的更远。上面的代码昨天刚改的,不合适的地方大家指正。这个混合式调度器的抢占任务我没仔细介绍,大家自己研究吧~书中也有讲到。9月12日,也就是今天其实V1.2版本对这个调度器进行的大改,但是感觉发上来不合适,我再改改,后面更新。
下面我就跟上《时间触发嵌入式系统设计模式——8051系列微控制器开发可靠应用》这本书的PDF文件。
|
|