搜索
bottom↓
回复: 36

ucos中的modbus 怎么能做到实时响应?

[复制链接]

出0入0汤圆

发表于 2016-6-12 18:36:22 | 显示全部楼层 |阅读模式
做了3个任务, 两个任务采集网口数据  Task_TcpClient1( void * p_arg )    Task_TcpClient2( void * p_arg )
另一个任务采进行MODBUS 通讯,  
把网口的通讯任务优先级设置为5,  MODBUS任务优先级设置为4, 网口的数据可以不用实时响应,
但是MODBUS必须实时响应
函数如下
网口采集1
void  Task_TcpClient1( void * p_arg )
{
    OS_ERR      err;


   (void)p_arg;


    while (DEF_TRUE)
                        {                               //任务体,通常写成一个死循环
                            ucKLTCPFrame[6]=0x01;
                               
                        xMBTCPPortSendResponse( ucKLTCPFrame, 12 );
                               
                       do_tcp_client();   
                 
                                          
                           OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );    //相对性延时1000个时钟节拍(1s)
    }
               
               
}


网口采集2
void  Task_TcpClient2( void * p_arg )
{
    OS_ERR      err;


   (void)p_arg;


    while (DEF_TRUE)
                        {                               //任务体,通常写成一个死循环
                            ucKLTCPFrame[6]=0x02;
                               
                        xMBTCPPortSendResponse( ucKLTCPFrame, 12 );
                               
                       do_tcp_client_1();   
                 
                                          
                           OSTimeDly ( 1000, OS_OPT_TIME_DLY, & err );    //相对性延时1000个时钟节拍(1s)
    }
               
               
}


MODBUS任务
void  Task_Modbus ( void * p_arg )
{
   OS_ERR      err;

   CPU_SR_ALLOC();
   (void)p_arg;
   
   
    while (DEF_TRUE)
                       
                {                                        //任务体,通常写成一个死循环
                         
                       if(Uart2_rev_flag == 0x01)
                       
                     {       
                               
                               
                         Uart2_rev_flag = 0x00;//接收一帧数据标志清零
                       
                                OS_CRITICAL_ENTER();                                   //进入临界段,避免串口打印被打断
                            ParseRecieve();//MOBUS处理函数
                          
                           GPIO_ResetBits(GPIOA,GPIO_Pin_1);//485接收使能,关闭发送使能       
                       
               
                                                                             
                           USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//允许接收中断
                                         
                         OS_CRITICAL_EXIT();          //退出临界段                   
                               
                       
                     }                        
                                
                // OSTimeDlyHMSM(0, 0,0,50,OS_OPT_TIME_HMSM_STRICT,&err);        //延时阻塞50ms
                 // OSSched();   
                  // OSTimeDly ( 10, OS_OPT_TIME_PERIODIC, & err ); //周期性延时5000个时钟节拍(5s)

    }

现在现象 modbus任务中 把延时函数 加上 防止的时候 modbus数据 有时候能采集到, 但是 非常慢,  有时候发送的数据根本没有接收到
如果把延时函数换成   OSSched(); 任务切换,可以实时响应, 但是,网口的数就采集不到了,  请教下各位有啥情况


出0入0汤圆

 楼主| 发表于 2016-6-13 21:38:23 | 显示全部楼层
调试了一天,偶尔一次发送少量的数据,可以事实得到响应,
如果不断发送不同指令的MODBUS指令数据,或一直发送  STM32 偶尔能得到相应 ,有时候完全采集不到功能吗指令
想了一天,不断的发送MODBUS 不就是不断的进入中断, 从而使ucos的其他任务轮询不上, 或执行其他任务时候,本身任务进入临界段, 或不允许打断任务
这时候 ,modbus中断发过来的命令就忽略了,
有什么好的办法,能实时接收到 MODBUS 不同的命令并储存到内存中呢

出0入0汤圆

发表于 2016-6-13 21:58:24 | 显示全部楼层
试试DMA传输数据

出0入0汤圆

发表于 2016-6-13 22:13:06 | 显示全部楼层
感觉写法不是很好,既然用上OS了,怎么用标志位来传送信息,你在串口中断中使用信号量来传递数据收到信息,Modbus任务Pend在此信号量上。
从你贴上的代码来看,当前的写法,Modbus任务如果没有延时函数调用,其它比它优先级低的任务没有运行的机会!

出0入0汤圆

发表于 2016-6-13 22:20:11 | 显示全部楼层
一般的流程是使用中断来接收串口的数据并保存在缓冲区内,等收到完整的一帧数据后通过信号量来通知相应的任务来处理此帧数据。一般中断的接收方式不会轻易丢失数据。

出0入0汤圆

 楼主| 发表于 2016-6-13 22:26:12 | 显示全部楼层
electrlife 发表于 2016-6-13 22:13
感觉写法不是很好,既然用上OS了,怎么用标志位来传送信息,你在串口中断中使用信号量来传递数据收到信息, ...

由于刚用UCOS 不算熟悉, 由于MODBUS 中断有2个, 一个是时间判断3.5t  一个串口中断, 多了有点不会用
就直接移植 自己编写的MODBUS,     modbus中的用红色标志, 是三种方法都试过了, 所以有时间延时, 如果没有掩饰就切换任务了

出0入0汤圆

 楼主| 发表于 2016-6-13 22:37:47 | 显示全部楼层

谢谢,我也想过,关键是modbus中断处理中, 不能丢数据

出0入0汤圆

发表于 2016-6-13 22:42:03 | 显示全部楼层
有OS就要评估调度延时问题

出0入0汤圆

 楼主| 发表于 2016-6-13 22:53:39 | 显示全部楼层
NJ8888 发表于 2016-6-13 22:42
有OS就要评估调度延时问题

因为网络数据平时变化不大, 所以今天调试时候 特意把3个网络的数据延时加长了,  优先级设置小些(与MODBUS 任务命令, 设置大了 ,现象没啥两样)
modbus 读和写的命令    和根据数据处理命令延时时间比较短

出0入0汤圆

发表于 2016-6-13 23:04:09 | 显示全部楼层
既然modbus有实时交互,你可以考虑另外一个辅助单片机裸奔处理这个事

出0入0汤圆

 楼主| 发表于 2016-6-14 08:50:17 | 显示全部楼层
NJ8888 发表于 2016-6-13 23:04
既然modbus有实时交互,你可以考虑另外一个辅助单片机裸奔处理这个事

目前,硬件只能这样了,也不算 MODBUS 也不算什么太实时,触摸屏3秒读一次CUP里的数据,由于地址不连续,所以向CPU发完一次命令 需要2秒 多才能完成(数据实时性不强,因为采集的是温度,湿度数据...)
要控制动作的MODBUS 指令因为是人为控制,有随机性,一定随机响应,,平时这种指令并不是总发的, (由于触摸屏和相关的变量连接 平时总发没用的01 功能码)




出0入0汤圆

发表于 2016-6-14 09:07:03 | 显示全部楼层
串口使用DMA接收和发送,UCOS中开一个任务延迟一定时间间隔读DMA的接收数量,如果和上次读的一致延时增加,直到3.5T后发消息处理数据!

出0入0汤圆

发表于 2016-6-14 09:41:04 | 显示全部楼层
这个就2秒多了,并且modbus中轮询任务间隔时间是很短的。并且有容错重发机制。

出0入0汤圆

 楼主| 发表于 2016-6-14 09:54:17 | 显示全部楼层
shian0551 发表于 2016-6-14 09:41
这个就2秒多了,并且modbus中轮询任务间隔时间是很短的。并且有容错重发机制。 ...

试着把读取的命令用时间间隔开, 发送,可以缩短发送的时间

出0入0汤圆

发表于 2016-6-14 09:56:14 | 显示全部楼层
jiangzhimin 发表于 2016-6-13 22:37
谢谢,我也想过,关键是modbus中断处理中, 不能丢数据

使用DMA并不意味着会丢数据

出0入0汤圆

发表于 2016-6-14 10:13:01 | 显示全部楼层
MODBUS收到数据和处理数据一定要分开,收到的数据先缓冲起来。

出0入0汤圆

 楼主| 发表于 2016-6-14 10:38:30 | 显示全部楼层
netawater 发表于 2016-6-14 10:13
MODBUS收到数据和处理数据一定要分开,收到的数据先缓冲起来。

呵呵做农业喷灌的大侠,正在考虑用楼上的DMA加串口,  有没有想你说的收到的数据和处理的数据分开的示例
关键因为屏连接 着变量,屏空闲时候 不断的发 01没用功能码,不断的串口中断,很麻烦 影响别的任务执行, 如果使用按键发送,一次性发送命令多, 不容易操作

出0入0汤圆

发表于 2016-6-14 13:25:47 | 显示全部楼层
jiangzhimin 发表于 2016-6-14 10:38
呵呵做农业喷灌的大侠,正在考虑用楼上的DMA加串口,  有没有想你说的收到的数据和处理的数据分开的示例
...

表示看不懂说什么。

出0入0汤圆

发表于 2016-6-14 14:26:58 | 显示全部楼层


这是我用UCOS III的串口
实时没问题
你可以参考一下
  1.         while (DEF_TRUE)                                          /* Task body, always written as an infinite loop.       */
  2.         {
  3.                 //

  4.         len = Serial_Rd((SERIAL_IF_NBR   )App_SerTraceIF_Nbr,
  5.                           (void           *)buf,
  6.                           (CPU_SIZE_T      )100,
  7.                           (CPU_INT32U      )10,
  8.                           (SERIAL_ERR     *)&serial_err);
  9.         if(len>0)
  10.         {
  11.             BSP_LED_Toggle(3u);
  12.             MBPoll(buf,&len);
  13.             Serial_Wr((SERIAL_IF_NBR   )App_SerTraceIF_Nbr,
  14.                           (void           *)buf,
  15.                           (CPU_SIZE_T      )len,
  16.                           (CPU_INT32U      )0,
  17.                           (SERIAL_ERR     *)&serial_err);
  18.         }
  19.         }
复制代码

出0入0汤圆

发表于 2016-6-14 14:27:56 | 显示全部楼层
os_mbx_init
_init_box
isr_mbx_receive
os_mbx_wait
os_mbx_send

上了系统,这些系统级的调度不用上,当然没有好的实时性了

出0入0汤圆

 楼主| 发表于 2016-6-14 14:45:57 | 显示全部楼层
ccyhyxt 发表于 2016-6-14 14:26
这是我用UCOS III的串口
实时没问题
你可以参考一下

看的似都非都, 不过还是要谢谢您
没办法只能参考下http://www.cnblogs.com/zjutlitao/p/3917638.html 这篇文章上个消息队列试一试, 不知道能不能成功

出0入0汤圆

 楼主| 发表于 2016-6-14 15:42:45 | 显示全部楼层
jiangzhimin 发表于 2016-6-14 14:45
看的似都非都, 不过还是要谢谢您
没办法只能参考下http://www.cnblogs.com/zjutlitao/p/39176 ...

按照例子没有处理成功, 找遍资料 个别做的 ucos 移植freemodbus 例子, 可是压根就没有啥信号量
只能求助哪个大神把关于消息或信号量的例子发送 参考下了

出0入0汤圆

发表于 2016-6-14 18:36:15 | 显示全部楼层
ucos iii 本就有串口的驱动,所以我上面的程序,直接读写就行了

出0入0汤圆

 楼主| 发表于 2016-6-15 13:46:36 | 显示全部楼层
各位大神, ucos 中断的频率多高,可以不影响别其他任务的执行啊(假如系统时钟节拍是1ms)

出0入0汤圆

发表于 2016-6-15 17:12:35 | 显示全部楼层
Modbus那个线程你如果把延时去掉的话应该一直占用cpu吧?另外两个线程应该是不跑的。

出0入0汤圆

发表于 2016-6-15 21:51:00 | 显示全部楼层
我不用OS,两个串口走两路MODBUS表示无压力。单片机作MODBUS从机,而且是两路一直读,没停止过。

出0入0汤圆

发表于 2016-6-15 22:30:12 来自手机 | 显示全部楼层
electrlife 发表于 2016-6-13 22:20
一般的流程是使用中断来接收串口的数据并保存在缓冲区内,等收到完整的一帧数据后通过信号量来通知相应的任 ...

正解,直接中断缓冲保存数据,帧完成后发信号量给任务,任务再处理后,回复数据,也采用中断方式!

出0入0汤圆

 楼主| 发表于 2016-6-15 22:44:57 | 显示全部楼层
gliet_su 发表于 2016-6-15 21:51
我不用OS,两个串口走两路MODBUS表示无压力。单片机作MODBUS从机,而且是两路一直读,没停止过。 ...

您有的什么型号,stm 系列?我的是F103XXZET6,现在不担心处理modbus  问题, 我担心mcu不断处理modbus 指令, 不停进入中断,
从而别的任务得不到执行。  所以问下各位,ucos 这样频繁进中断,处理modbus指令, 别的任务有机会得到执行吗, 或有啥好办好处理下

出0入4汤圆

发表于 2016-6-15 22:54:00 来自手机 | 显示全部楼层
lingdianhao 发表于 2016-6-15 22:30
正解,直接中断缓冲保存数据,帧完成后发信号量给任务,任务再处理后,回复数据,也采用中断方式! ...

顶,这个问题与OS没什么关系,有没有OS都应该这么处理

出50入0汤圆

发表于 2016-6-15 23:09:49 来自手机 | 显示全部楼层
串口速率必比CPU时钟满很多,不可能处理不了其他任务

出0入0汤圆

发表于 2016-6-15 23:12:53 | 显示全部楼层
jiangzhimin 发表于 2016-6-15 22:44
您有的什么型号,stm 系列?我的是F103XXZET6,现在不担心处理modbus  问题, 我担心mcu不断处理modbus  ...

你不做复杂的算法,简单的数据处理,完全够用。你说你的进入中断次数多,导致任务没有机会执行。这个不可能。串口多少M,cpu主频多少M,你cpu使用率可能不到1%,ucos统计任务可以测cpu使用率,打出来看看,cpu使用率占了多少。

出0入0汤圆

 楼主| 发表于 2016-6-16 09:07:55 | 显示全部楼层
lingdianhao 发表于 2016-6-15 22:30
正解,直接中断缓冲保存数据,帧完成后发信号量给任务,任务再处理后,回复数据,也采用中断方式! ...

如果裸机时候,中断回复采用中断方式  这个方法也不错呵呵,但是ucos 在中断时候可以OSSemPost 信号量, 看资料中断中好像不能用OSSemPend 等待信号量

出0入0汤圆

 楼主| 发表于 2016-6-16 09:25:22 | 显示全部楼层
本帖最后由 jiangzhimin 于 2016-6-16 10:31 编辑

这是自己写的大家帮忙看下 哪有不妥的地方  这段程序是 单个少量的命令可以接受, 不间断的发送 就反应不过来

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2016-6-20 22:55:37 | 显示全部楼层
看了一下楼主自己最后改写的,在处理数据任务中PEND信号,应该是死等,然后里面应该不能有延迟函数,有数据就需要马上处理完,然后等待下一次数据。

出0入0汤圆

 楼主| 发表于 2016-6-21 08:41:52 | 显示全部楼层
mozid7 发表于 2016-6-20 22:55
看了一下楼主自己最后改写的,在处理数据任务中PEND信号,应该是死等,然后里面应该不能有延迟函数,有数据 ...

peng 的后边参数 不是死等待的参数
另外没有延时函数怎么切换任务, 我第一幅图,红色标记 用了三种方法切换任务, 不用延时 是可以响应,但是 切换不了任务

出0入0汤圆

发表于 2016-10-22 10:58:44 | 显示全部楼层
jiangzhimin 发表于 2016-6-21 08:41
peng 的后边参数 不是死等待的参数
另外没有延时函数怎么切换任务, 我第一幅图,红色标记 用了三种方法 ...

如果没记错的话,OSSemPend这个接口也会进行一次任务切换,所以没有特殊需要可以不用使用别的接口进行任务切换,可以翻翻ucos的手册了解一下。

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-4-20 05:22

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

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