OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 2917|回复: 7

stm8并行多任务

[复制链接]

5

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
124
金钱
124
注册时间
2016-9-22
在线时间
36 小时
发表于 2016-11-24 15:35:19 | 显示全部楼层 |阅读模式
1金钱
      现在手头有个小项目,遇到了些问题,请大神赐教!使用的芯片是stm8s207s8   整个系统包括:1、软件模拟的iic通讯,与触摸ic通讯,判断按键。2、与595通讯,控制按键灯。3、用uart1与语音ic通讯,实时控制播报语音。4、用uart3与指纹模块通讯,以一定频率采集指纹头上的指纹。5、使用一个io口与射频ic通讯,软件解码。     整个系统,需要实时扫描的就只有三个,即:扫描指纹、扫描射频卡、扫描按键。这三个封装函数我都有写好,因为这三个函数里面都涉及语音播报,语音播报是这样一个流程:发送一段指令码,控制语音ic播报指定的一段语音,语音ic成功接收到信号,会返回“ok”,播放完毕会返回“stop”。大家都知道语音播放需要一定时间,我现在写的语音通讯函数,直接用的while((UART1_SR&0X20)==0);这样写有一个坏处,接收这段语音如果有20s,单片机就只能在这等20s,什么别的事都做不了。
     另外,这个项目我启用了3个定时器,设置了相同的频率,把三个扫描函数分别放入一个定时器中断函数中,但我发现他们之间还是会有相互干扰,因为指纹扫描不需要很快1s扫描3次左右足够了,每当指纹通讯时,指纹模块的灯亮,此时如果你要是按密码键盘,根本没有任何反应,后来我就想,设置不同的指纹扫描频率,毕竟你在输入密码的时候,不可能同时输入指纹,只要有按键被按下,在一定时间内,指纹以5s一次扫描,过了这个设定的时间就以1s 3次的速度扫描。这样改良后,效果是比开始好了,但还是感觉有时候,会和扫描射频卡的函数,相冲突。
     其实自己的开发经验挺少的,刚毕业,一直都是裸奔,后来我就在网上查找,单片机跑小系统,并行多任务。大致了解了下ROTS_52,也就4个文件,挺小巧的,但我有些疑问,如果移植到我的项目中,在每个task中有延时该怎么处理,像语音通讯这种几秒中的等待该怎么处理。求大神指教!!!!
     /********************************
*FileName:         MAIN_C
*Author         :   JZHG1992
*Versions:         V1.0
*********************************/

#include "OS.h"


/************************************
*                 主函数
*************************************/

void main( void )
{
        uchar i;

        OS_Timer0_Init();         // 系统定时器时钟初始化
        EA = 1;                                          // 开总中断
        while(1)
        {
                for ( i=0; i<TASK_MAX; i++ )
                {
                        if ( Task_Delay == 0 )
                        {
                                OS_Task_Run( task );
                                break;
                        }
                }
        }                                                               
}


/********************************
*FileName:         OS_C
*Author         :   JZHG1992
*Versions:         V1.0
*********************************/

#include "OS.H"

/************************************
*                 系统任务执行频度参数
*************************************/

uchar Task_Delay[TASK_MAX];

/************************************
*                 系统定时器时钟初始化
*************************************/

void OS_Timer0_Init( void )
{
        uchar i;

        for ( i=0; i<TASK_MAX; i++ )
        {
                Task_Delay = 0;   // 复位系统任务执行频度参数               
        }
        TMOD = (TMOD&0xf0)|0x01; // 设置定时器0方式1
        TH0 = 256-(OS_CLOCK/TASK_CLOCK)/12/256; // 赋初值200Hz
        TL0 = 256-(OS_CLOCK/TASK_CLOCK)/12%256;
        TR0 = 1;  // 使能定时器0
        ET0 = 1;  // 使能定时器0中断
}

/************************************
*                 系统任务调度函数
*************************************/

void OS_Task_Run( void (*ptask)() )
{
        (*ptask)();
}

/************************************
*                 系统中断服务函数
*************************************/

void OS_ISR( void ) interrupt 1
{
        uchar i;

           TH0 = 256-(OS_CLOCK/TASK_CLOCK)/12/256; // 赋初值200Hz
        TL0 = 256-(OS_CLOCK/TASK_CLOCK)/12%256;
        for ( i=0; i<TASK_MAX; i++ )
        {
                if ( Task_Delay )Task_Delay --;
        }
}




/********************************
*FileName:         OS_H
*Author         :   JZHG1992
*Versions:         V1.0
*********************************/
/********************************
*系统原理:单片机定时器延时中断来产
*               生系统任务调度节拍,设置
*               各个任务的执行频度,来调
*               度各任务。以实现系统多线
*                   操作。
*********************************/
#ifndef _OS_H_
#define _OS_H_
#include<reg52.h>

/************************************
*                定义变量类型
*************************************/

#define uchar unsigned char         // 宏定义uchar
#define uint unsigned int         // 宏定义uint

/************************************
*                配置系统参数
*这里你可以根据你的需要修改
*************************************/

#define OS_CLOCK  12000000   // 系统晶振频率,单位Hz
#define TASK_CLOCK 200       // 任务中断节拍,单位Hz
#define TASK_MAX   2         // 任务数目

/************************************
*        系统任务外调函数与参数
*************************************/

extern uchar Task_Delay[TASK_MAX];        // 系统任务执行频度参数
extern void OS_Timer0_Init( void );       // 系统定时器时钟初始化
extern void OS_Task_Run( void(*ptask)()); // 系统任务调度函数
extern void ( *const task[] )();          // 获得任务指针

//-------------
#endif



/********************************
*FileName:         TASK_C
*Author         :   JZHG1992
*Versions:         V1.0
*********************************/

#include "OS.H"

/************************************
*                 设置系统任务执行频度
*************************************/

#define TASK_DELAY0 TASK_CLOCK/3   // 任务0的执行频度
#define TASK_DELAY1 TASK_CLOCK/1    // 任务1的执行频度

//--------------------------
// 演示用的端口

sbit LED0 = P1^0;
sbit LED1 = P1^1;

/************************************
*                 任务0函数
*************************************/

void task0( void )
{
        Task_Delay[0] = TASK_DELAY0;  // 设置任务执行度

        /* 你的任务 */
        LED0 = !LED0;
               
}

/************************************
*                 任务1函数
*************************************/

void task1( void )
{
        Task_Delay[1] = TASK_DELAY1;  // 设置任务执行度

        /* 你的任务 */
        LED1 = !LED1;
               
}

/************************************
*                 获得任务指针
*        添加你的任务指针
*************************************/

void ( *const task[] )() = { task0, task1 };





正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

17

主题

344

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1280
金钱
1280
注册时间
2013-12-14
在线时间
567 小时
发表于 2016-11-24 16:15:30 | 显示全部楼层
没用过楼主说的那个OS,但是感觉楼主的需求,还是可以用状态机来解决的,毕竟你的声音播放不是阻塞的,对于那个while((UART1_SR&0X20)==0)等待串口接收标志,可以用if来替代,大致估算一下你的串口标志位被置位的时间,然后每隔一段时间扫描一次。

感觉楼主只需要一个定时器就可以了,作为节拍,然后将扫描都放到主函数的while( 1 )里面就行了。

我也是刚毕业,也在研究单片机多任务并行的问题,我们可以多多讨论。
半导体->模拟电路->数字电路->单片机->汇编->C->操作系统->java
回复

使用道具 举报

17

主题

344

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1280
金钱
1280
注册时间
2013-12-14
在线时间
567 小时
发表于 2016-11-24 16:27:12 | 显示全部楼层
本帖最后由 东北小辉辉 于 2016-11-24 16:38 编辑

大致看了一下楼主说的那个OS,这也能叫OS?当然,跑个LED还是可以的。
感觉楼主这个项目真正的难点,还是在于任务时间片的划分,对于一个任务中的延时,比如模拟I2C中的延时,如果这个延时足够小(比如,只有几个us),还是可以认为是非阻塞的(但是如果延时多了就变成阻塞的了),如果这个延时比较大(比如几个ms),就需要对这个任务进行分割,在有delay的地方结束,转而去执行其他任务(当然,其他任务也要保证尽可能的短,否则I2C的时序就被破坏了,通讯就会失败),当时间片又轮训到这个任务时,继续进行I2C时序的通讯。当一个任务比较长时,也要进行分割,这就看具体的应用。看楼主的应用中,还有软件解码什么的,估计这个时间片划分够难的了。

楼主也可以去了解一下PT线程,比如之前有一位版主发的这个帖子。
http://www.openedv.com/thread-89015-1-2.html

阿mo上还有一位网友对这个进行了改良,叫小小调度器。这个可以用看似阻塞的编程方式来实现非阻塞编程。这个就比较智能,C语言的特性__LINE__会自动帮你记录下状态。都比楼主发的那个“OS”靠谱。

以上是我的一点心得,有错误的地方,还请各位指出,谢谢。


半导体->模拟电路->数字电路->单片机->汇编->C->操作系统->java
回复

使用道具 举报

34

主题

322

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1821
金钱
1821
注册时间
2014-12-4
在线时间
713 小时
发表于 2016-11-24 16:39:52 | 显示全部楼层
状态机和时间片能解决楼主的问题
回复

使用道具 举报

5

主题

13

帖子

0

精华

初级会员

Rank: 2

积分
124
金钱
124
注册时间
2016-9-22
在线时间
36 小时
 楼主| 发表于 2016-11-24 19:17:18 | 显示全部楼层
东北小辉辉 发表于 2016-11-24 16:27
大致看了一下楼主说的那个OS,这也能叫OS?当然,跑个LED还是可以的。
感觉楼主这个项目真正的难点,还是 ...

方便留个qq吗?或者加个微信,以后多交流!
回复

使用道具 举报

39

主题

599

帖子

2

精华

金牌会员

Rank: 6Rank: 6

积分
2109
金钱
2109
注册时间
2011-9-3
在线时间
119 小时
发表于 2016-11-25 10:41:40 | 显示全部楼层
帮顶。
回复

使用道具 举报

17

主题

344

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1280
金钱
1280
注册时间
2013-12-14
在线时间
567 小时
发表于 2016-11-25 10:46:48 | 显示全部楼层
本帖最后由 东北小辉辉 于 2016-11-25 10:57 编辑

还有,楼主要分清任务的轻重缓急,优先处理死线比较近的硬实时任务。至于非实时任务,可以搞一个缓冲buffer,等到CPU空闲的时候再执行。尽量把单片机的硬件资源榨取干净,通讯协议这些,能用硬件尽量用硬件,你这款单片机应该也有硬件I2C吧?实在不行,再用软件模拟,解码什么的,相信你能解决这个问题,加油。
其实这个问题已经与单片机无关了,是软件架构方面的问题,楼主最好在人多的区发一个帖子,看看大神怎么处理这种问题,我们也跟着学习一下,这个区发帖基本没人理。

半导体->模拟电路->数字电路->单片机->汇编->C->操作系统->java
回复

使用道具 举报

20

主题

158

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
334
金钱
334
注册时间
2012-8-21
在线时间
27 小时
发表于 2016-11-25 11:38:26 | 显示全部楼层
最大的误区就是,同时开3个相同频率的定时器中断,应该只开一个就够了,作为整个系统的TICK,另外对于整个系统里面所需要的操作的东西,你必须清楚,哪些是可以通过定时去处理的,时间的划分又是如何进行的
另外就是对于实时性要求高的任务或者处理,则只需判断相应的标志,就执行处理即可
对于你说的那个OS来说,就看那个TASK_DELAY就知道,这个对于小应用是可以的,但是对于复杂的就完全不行了,各个模块之间执行或者所需要的DELAY是不同的,,,所以你说的这个OS,完全可以丢掉,
正常的逻辑编程思路如下,
TICK+状态机+事件触发,
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-6-28 22:29

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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