发新帖我要提问
12
返回列表
打印

RTX51的任务会切换不了吗?

[复制链接]
楼主: ningling_21
手机看帖
扫描二维码
随时随地手机跟帖
21
刘前辈| | 2011-12-27 21:52 | 只看该作者 回帖奖励 |倒序浏览
需要看看串口中断程序干了些什么。


、、

使用特权

评论回复
22
highgear| | 2011-12-27 23:51 | 只看该作者
这么简单的一个东西,被你们搞得复杂无比。51下的串口这种简单的东西,就应该直接裸奔,用 os 不会简化结构,反而复杂化了。

即便用 os, 如果这两个任务联系如此紧密而且互斥,那么应该合并为一个任务,而不是分割开。

                if(flag_uart==1)                //串口收到数据
                {
                        os_send_signal(2);        //给任务2发信号
                }

os_send_signal(2) 应改为直接调用任务2中的发送。

使用特权

评论回复
23
ayb_ice| | 2011-12-28 08:27 | 只看该作者
这么简单的一个东西,被你们搞得复杂无比。51下的串口这种简单的东西,就应该直接裸奔,用 os 不会简化结构,反而复杂化了。

即便用 os, 如果这两个任务联系如此紧密而且互斥,那么应该合并为一个任务,而不是分割 ...
highgear 发表于 2011-12-27 23:51

由裸奔刚转RTOS的人一般都喜欢这么做

使用特权

评论回复
评分
参与人数 1威望 +1 收起 理由
刘前辈 + 1
24
刘前辈| | 2011-12-28 12:51 | 只看该作者
本帖最后由 刘前辈 于 2011-12-28 13:01 编辑

有点想明白了,LZ的主从轮询协议大致是这样:……   因此可以完善一下程序,只要上位机**重发协议,那么即使从站开机执行若干时间升级程序(错过了接收主站协议数据帧),但升级完毕后,最终会收到主站的重发协议数据。

void main_task _task_ 1
{
        while(1)
        {
                ......
                ......
                if(flag_uart==1)                //串口收到数据
                {
                     flag_uart=0;                                   

                 os_send_signal(2);        //给任务2发信号
                }
           os_switch_task( );
        }
}
//串口数据处理任务
void rece_task _task_ 2
{
        while(1)
        {              
                .......
               os_wait1(K_SIG);         // 等待信号

                send_char(0x0d);                // 串口发送数据
                .......
                flag_uart=0;
               
           //     os_wait1(K_SIG);                //退出该任务,等待信号
        }
}
//串口发送数据
void send_char(uchar g)            //串口发送数据                        
{                                                                        

       //  while(flag_send==1)                        //等待发送完成
    //    {
    //            os_wait1(K_SIG);                //退出该任务,等待信号
    //    }
    //    os_wait2(K_TMO,2);                        //延时

         TI=0;     // 发送早已完成,否则不会收到上位机信号,除非全双工。
        SBUF0=g;                                //发送数据
        jyhe0+=g;                                
        flag_send=1;
}


、、

使用特权

评论回复
25
ningling_21|  楼主 | 2011-12-28 15:48 | 只看该作者
22# 刘前辈
串口中断处理是这样的:
void uart_int(void) interrupt 4
{
   if(RI0)
{
    RI0=0;
    sbuf=SBUF0;    //保存收到的数据
}

  if(TI0)
{
    TI0=0;
    flag_send=0;   //发送完成
}
}

使用特权

评论回复
26
highgear| | 2011-12-28 21:30 | 只看该作者
这个问题本不是个问题。楼主既然使用了串口中断,而且发送协议如此简单,那么就完全不必开一个任务来做。把强耦合的任务分割成若干块,用变量联络,这不是一种好的设计方法。

串口中断本身就可以看作是一个任务,把所有接收和发送都放入在这个中断中,楼主你会发现整个程序会很简单:

if(RI0)
{
    RI0=0;
    ParseInputCommand();   //解析输入
     TI = 0;
    SBUF0 = firstOutputCommand; //发送第一个字节命令, 发送完毕会产生中断以便发送下一个字节
    //sbuf=SBUF0;    //保存收到的数据
}

  if(TI0)
{
    TI0=0; //发送完成

//   flag_send=0;   
}

使用特权

评论回复
27
刘前辈| | 2011-12-28 21:54 | 只看该作者
明白。试试看下面:
void main_task _task_ 1
{
        while(1)
        {
                ......
                ......
                if(flag_uart==1)                //串口收到数据
                {
                     flag_uart=0;                                   

                 os_send_signal(2);        //给任务2发信号
                }
           os_switch_task( );
        }
}

//串口数据处理任务
void rece_task _task_ 2
{
        while(1)
        {     
            os_wait1(K_SIG);         // 等待信号
          // 数据处理     .......
              send_char(0x0d);      // 串口发送响应数据
                .......
                flag_uart=0;
          }
}
//串口发送响应数据
void send_char(uchar g)            //串口发送数据                        
{                                                                            //    os_wait2(K_TMO,2);       //延时

         TI=0;     //强制发送。 发送早已完成,否则不会收到上位机信号,除非全双工。
        SBUF0=g;             //发送数据
        jyhe0+=g;                                
        flag_send=1;
}

.

使用特权

评论回复
28
刘前辈| | 2011-12-28 22:05 | 只看该作者
如果上述修改无效。再试试下面:

还有重要的一点,既然电源上不能实行主站后开机,那么让主站开机后延迟一个(从站)升级程序+复位时间,之后再投入以前的程序运行。(从站不作任何修改;这样完全模拟以前的通信时序了。)


使用特权

评论回复
29
highgear| | 2011-12-28 22:09 | 只看该作者
把接收处理放在一个 os 任务中的方法,很可能会出现接收不到的情况,因为 os 是用定时来不断的切换任务,os 任务的实时性相对较弱,当有若干个同优先级的任务时,串行接收任务中的 sbuf = SBUF0 可能会因为没能及时处理而被覆盖。

所以,把接收任务全部放入中断中而不是使用 os task 是最好的方法。

使用特权

评论回复
30
刘前辈| | 2011-12-28 22:57 | 只看该作者
本帖最后由 刘前辈 于 2011-12-28 23:25 编辑

计算一下:9600 bps/12M 时接收一帧数据需要大约1ms ,RTX51_TINY 系统节拍默认10ms ;时间片默认50ms ;也就是每50ms 进行一次切换 。而切换开销更是忽略不计。——50ms 一个数据处理任务,至少1万条指令,够不够???

串口中断和内核节拍中断是2个独立不相关的ISR。串口中断可以设置最高优先级,——实际没必要。

——串口属于最慢的外部设备,和最慢的OS比较,也是老牛比奔驰。如若连串口都要丢数据,那么,SPI、I2C、高速A/D采集 还有printf ( ),还怎么玩??


、、

30楼多虑了。


、、

使用特权

评论回复
31
highgear| | 2011-12-29 00:00 | 只看该作者
刘公公啊,你没有多少实际的经验,也没有做过实际的串口程序,对吧?

SPI、I2C、高速A/D采集这些都是很简单的东西,只要结构设计合理。

串口接收放在os任务中,如果只有一个任务,那么没有问题,如果有多个任务,那么串口接收任务会被其他的任务打断几十 ms, 而楼主并没有使用接收缓冲,因此,在串口接收任务被切换出去后可能会丢失数据。

串口的慢是相对的,9600的速率对于 os 任务的切换频率来说是极快的。

使用特权

评论回复
32
ayb_ice| | 2011-12-29 08:37 | 只看该作者
像LZ这种程序结构,基本就是垃圾

使用特权

评论回复
33
刘前辈| | 2011-12-29 09:28 | 只看该作者
串口接收放在os任务中,如果只有一个任务,那么没有问题,如果有多个任务,那么串口接收任务会被其他的任务打断几十 ms, 而楼主并没有使用接收缓冲,因此,在串口接收任务被切换出去后可能会丢失数据。


highgear 大师搞笑了,你玩了那么多年串口,不知道现在的串口都是带至少2级缓冲的?例如51。

你自己做了一个抢占式OS,每个节拍一切换,—— 在LZ的系统上相当于10ms 一次切换,假若一个任务运行开销大于10ms的话,内核将强行中止正在运行的任务切换到其他就绪任务。

哈哈,你自己做了一个抢占式OS,就以为所有OS都是抢占式OS啦?LZ用的是RTX51_tiny !

知道什么叫协程吗?不知道上网查查。学好了再来。  ayb_ice 在二楼就告诉你,tiny 是任务自我管理的,当时间片关闭时,一个任务独占CPU裸奔。
当时间片打开时,它在一个时间片内如果运行完毕,自我切换到其他任务。知道LZ的时间片是多长周期?——50ms!——有什么接收数据处理任务需要开销50ms !? 以致触发内核时间片启动来强制中止其继续完成而切换到其他就绪任务?

    回家算好了再来吧!


、、

使用特权

评论回复
34
highgear| | 2011-12-29 09:57 | 只看该作者
刘公公,你的理解能力和水平实在是..................

RTX51 tiny的调度是最简单的 round-robin 协作式,即所有任务轮流坐庄,刘公公你就不必在我面前显摆了。

简单的逻辑: "一个任务独占CPU裸奔", 如果这个任务不是接收任务,会如何?

使用特权

评论回复
35
ningling_21|  楼主 | 2011-12-29 10:08 | 只看该作者
补充:所使用的OS的时间片为700个时钟周期 ,时间应该在1MS以内。贴出的程序只是展现了大体框架,任务1和任务2(包含通信协议处理)却绝非这么简单,因为考虑公司方面不能全贴。

发帖本来为了解决问题的,还请 刘前辈 和 highgear 不要打口水仗了。
由于测试麻烦,故障很难复现,一直等了6天了客户一直没复现,正在找原因...

使用特权

评论回复
36
highgear| | 2011-12-29 10:27 | 只看该作者
好吧,我不知道楼主为何要使用 os,而且分成几个任务+中断,楼主应试试  ayb_ice 所说的队列,即一个简单的缓冲数组。 ayb_ice 前面的回帖技术上都很到位。

使用特权

评论回复
37
刘前辈| | 2011-12-29 12:58 | 只看该作者
任务1和任务2(包含通信协议处理)却绝非这么简单,……


所以,别人本来做的很好的。建议有些人别总以为自己高明,以为别人一个公司都是草包?——你怎么知道别人协议处理任务1里没有数据接收缓冲数组?别人一个公司都是搞通信的。

简单叙述一下LZ的协议(假设可能方案):
1、主站向从站发送数据帧,——假设20字节一个包,以“&”字符封装;——呵呵,那么在没有收到包结束符“&”之前,“数据处理任务2”根本不会启动!它根本没运行,不参与调度切换,何来“影响数据接收”?

2、协议处理任务1负责包封装识别,成帧;一旦接收到中断发来“flag_uart”信号,认为接收到一个完整包结尾字符;随之唤醒“数据处理任务2”进行处理。——呵呵,谁说协议处理任务1没有数据接收缓冲器?没有缓冲器任务1如何进行包识别?别人LZ搞通信的,用不着你H大师教这种常识装聪明,还什么“这么简单的协议,应该在中断中处理……”,——简单你个头!也不好好看看别人“flag_uart”是干什么用的,就在这装聪明。

3、任务2 数据处理完成后,向主站发回响应字节0x0d,表示“数据处理完毕,可接收下一数据包”。
   任务2数据处理期间,主站静默等待从站发回“处理完毕回应信号”字节0X0d ,在未接收到0x0d 之前,根本不会发出任何数据。——覆盖谁?覆盖你个头!连通信协议还搞不清,在这教LZ 应该这样那样?

(附加协议,主站可在等待一段合理时间未收到响应信号后,重发数据。重发N 遍之后,仍然收不到从站信息,认为从站故障。这是后话)

     别人都在搞RTOS了,这位高手说“我不明白LZ为什么要使用OS,这么简单的问题用裸奔处理就行了……”

    现在LZ告诉你了:“像协议处理这样复杂的内容 没必要贴出来,……”

    LZ贴出来的都是简单内容,H 高手你兴奋个啥?还总喜欢装聪明:这个也笨,那个也差劲,你应该这样,他应该那样,“这么多任务应该合并成一个任务,……”哈哈,合并成一个任务之后,关闭系统节拍中断,在RTX51 上玩裸奔!就H 高明?

    如此高明的H,怎么在自己写的抢夺式 RTOS 上关了中断玩裸奔printf( )多任务?——实在是高!然后到处教别人这个“OS奥秘”,谁不学就骂是“萨比”。

        
、、

使用特权

评论回复
38
zf_015820| | 2012-11-16 14:20 | 只看该作者
改得有道理,应该是这样,才行

使用特权

评论回复
39
zf_015820| | 2012-11-16 14:22 | 只看该作者
“刘前辈”同志:最近都没有上BBS了呀?我有一些问题,也想请教下你的,呵呵;我的QQ:858523466;若是有看到,愿意帮忙的话,还请加这个QQ,谢谢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则