OpenEdv-开源电子网

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

485方式modbus协议发送命令后回数据慢

[复制链接]

12

主题

53

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
284
金钱
284
注册时间
2013-9-24
在线时间
52 小时
发表于 2015-3-20 16:09:42 | 显示全部楼层 |阅读模式
5金钱
用串口调试助手调试的,发送命令后返回数据到串口助手上。裸机时,发送命令01 04 00 00 00 06 70 08,回01 04 0C 00 A2 00 A3 00 A2 00 A1 21 3D 14 D0 DB 85。发完立马回完。但是加入了UCOSII后,能够返回,但是回数据有一卡一卡的感觉,一帧数据分几次回完,好像发生了任务切换,但是我看了我的代码,不应该会这个时候任务切换啊,请大家帮忙看看。下面是部分代码:

//设置任务优先级
#define START_TASK_PRIO         10 //开始任务的优先级设置为最低
//设置任务堆栈大小
#define START_STK_SIZE      64
//任务堆栈 
OS_STK START_TASK_STK[START_STK_SIZE];
//任务函数
void start_task(void *pdata);

//Modebus任务
//设置任务优先级
#define MODBUS_TASK_PRIO           5
//设置任务堆栈大小
#define MODBUS_STK_SIZE      64
//任务堆栈 
OS_STK MODBUS_TASK_STK[MODBUS_STK_SIZE];
//任务函数
void modbus_task(void *pdata);

//数据采集任务
//设置任务优先级
#define COLLECT_TASK_PRIO          3
//设置任务堆栈大小
#define COLLECT_STK_SIZE       64
//任务堆栈 
OS_STK COLLECT_TASK_STK[COLLECT_STK_SIZE];
//任务函数
void collect_task(void *pdata);

OS_EVENT * msg_collect;   //消息邮箱事件块指针

int main(void)
{
  SystemInit();
 delay_init();      //延时初始化
 NVIC_Configuration();
  uart_init(9600);
 Ctrl_EN = 1;
  LED_Init();
 FM24CLXX_Init();
 SPI1_ADS1220_Init();
 EXTI4_Init();   //ADS1220的数据准备脚配置成下降沿中断触发,屏蔽该句可变为管脚电平检测判断
 IOPort_Init();
 SPI2_CC2520_Init();
 CC2520_VREG_EN = 1;
 CC2520_Init();
 CC2520_SetRxMode();

 //FCF帧控制域(2字节) + DSN(1字节) + ADDR最大地址(20字节) + FP帧负载(n) + FCS(2个字节)
 CC2520_PSDU[0] = 23+12+2;
 while(FM24CLXX_Check())//检测不到24CL64
 {

 }
 FM24CLXX_Write(0,(u8*)TEXT_Buffer,SIZE);
 FM24CLXX_Read(0,datatemp,SIZE);
 printf("datatemp = %s",datatemp);
 
 OSInit();       //初始化UCOSII
   OSTaskCreate(start_task,(void *)0,(OS_STK *)&START_TASK_STK[START_STK_SIZE-1],START_TASK_PRIO );//创建起始任务
 OSStart();   
}

void start_task(void *pdata)
{
 u8 indication = 0;
    OS_CPU_SR cpu_sr=0;  //采用的是方法三来开关中断的,cpu_sr用来存放CPU状态寄存器用的
 pdata = pdata;    
 msg_collect=OSMboxCreate((void*)0); //创建消息邮箱
// sem_modbus=OSSemCreate(0); //创建消息量
 if(PowerSelect_Indication) //判断供电方式
 {
  delay_ms(5);
  if(PowerSelect_Indication) indication = 1;
 }         
  OS_ENTER_CRITICAL();   //进入临界区(无法被中断打断) 
      
  OSTaskCreate(modbus_task,(void *)0,(OS_STK*)&MODBUS_TASK_STK[MODBUS_STK_SIZE-1],MODBUS_TASK_PRIO);
          
  OSTaskCreate(collect_task,(void *)0,(OS_STK*)&COLLECT_TASK_STK[COLLECT_STK_SIZE-1],COLLECT_TASK_PRIO);                 
  OSTaskSuspend(START_TASK_PRIO); //挂起起始任务.
 OS_EXIT_CRITICAL();    //退出临界区(可以被中断打断)
}

void collect_task(void *pdata)
{
        

while(1)   //进行一遍六路热电阻PT100的巡回检测
 {
  Channelcnt = 1;
  while(Channelcnt<7)
  {      
   Switch_ChannelSelect(on, Channelcnt);  //选择通道开关
   delay_ms(2);
   ADS1220_Start ();  

   while(ADS1220_Dataready);
   ADS1220_Dataready = 1;

   ADS1220_Get_RTD_Conversion_Data_Calibrated ((unsigned char *)tempData);//得到校准后数据
   RTD_code = (((long)tempData[0] << 16) + ((long)tempData[1] << 8) + (long)tempData[2]);
   RTD_Temperature = interpolateRTDTemperatureValue (RTD_code);      
   RTD_float[Channelcnt-1] = RTD_Temperature;
   Channelcnt++;  
  }
  for (Channelcnt=1;Channelcnt<7;Channelcnt++)
  {
   RTD_u16[Channelcnt-1] = RTD_float[Channelcnt-1]*10;
   CC2520_PSDU[23+Channelcnt] = RTD_u16[Channelcnt-1]>>8;
   CC2520_PSDU[24+Channelcnt] = RTD_u16[Channelcnt-1]&0X00FF;
  }
  OSMboxPost(msg_collect,RTD_u16);   //采集并处理好六路数据后,以消息邮箱的方式传递地址给任务modbus_task
  delay_ms(5);        
 }
}

  

void modbus_task(void *pdata)
{
 u8 err;

 while(1)
 {
  Ctrl_EN = 0;  //接受模式
  Mbox_u16 = OSMboxPend(msg_collect,0,&err); //请求消息邮箱
  
  ComprehensiveTreatment();    //485串口数据接收发送处理
 } 
}

 

void ComprehensiveTreatment(void)
{
 u8 i = 0;
 u16 CRCdata = 0;
 OS_CPU_SR cpu_sr=0;  //采用的是方法三来开关中断的,cpu_sr用来存放CPU状态寄存器用的

 delay_ms(50);
  
 if( read_done==0 || ReceiveBuf[0]!=0X01 ) return;   //接收完成并地址匹配判断
  
 CRCdata = crc16(ReceiveBuf,6);   
  
 if(CRCdata != (u16)ReceiveBuf[7]*0x100 + ReceiveBuf[6]) //这是串口助手的写法,如果是Modbus调试精灵,则校验码高位在后,低位前
// if(CRCdata!=((u16)ReceiveBuf[6]*0x100 + ReceiveBuf[7])) //校验成功判断
 { 
  return;
 }
                                                           
 switch(ReceiveBuf[1])     //解读功能码
 {
  case 1: 
    //Read_Coils();
   break;
  case 2: 
   //Read_InputDiscrete();
   break;
   case 3: 
    ReadHoldingRegisters();
   break;
   case 4: 
    ReadInputRegisters();  
   break;
   case 5: 
    WriteSingleCoil();
   break;
   case 6: 
    WriteSingleRegister();
   break;
  case 0X10: 
    WriteDoubleRegister();
   break;
   default: 
    TransportError(0x01);
   break;
 }
  
 
 Ctrl_EN = 1;      // 启动发送
 for(i=0;i<RevMaxLength;i++)
 {
  while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //对USART_DR的写操作,将该位清零
  USART_SendData(USART1,ReceiveBuf);
  while(USART_GetFlagStatus(USART1, USART_FLAG_TC)!=SET);  //先对USART_SR进行读操作,然后对USART_DR进行写操作可清零该位
 }

 Ctrl_EN = 0;
 for(i=0;i<RevMaxLength;i++)
 {
  ReceiveBuf = 0;
 }
 read_done = 0;  
}

 就好像在紫色代码的地方切换到别的任务一样,而我给紫色代码加上临界段,回数据就一次性回完了,没有卡的现象。望各位大神给予指点啊!

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

使用道具 举报

70

主题

6763

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
13131
金钱
13131
注册时间
2012-11-26
在线时间
3814 小时
发表于 2015-3-20 16:38:06 | 显示全部楼层
在执行紫色代码的时候   有中断?
没中断的话,此任务没有主动交出CPU,是不会切换任务的,可能产生中断去执行中断了
学无止境
回复

使用道具 举报

12

主题

53

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
284
金钱
284
注册时间
2013-9-24
在线时间
52 小时
 楼主| 发表于 2015-3-20 17:06:06 | 显示全部楼层
回复【2楼】jermy_z:
---------------------------------
发送的时候没有中断,串口只开了一个接受中断。
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-24 19:36

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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