-2

嗨,我正在研究通过串行总线控制电梯的嵌入式系统。每次我发送一条消息(数据包包含地址,数据长度,数据,crc)我都需要等待电梯响应,它由确认包表示。

每次我从电梯收到数据包时都会设置 ACK。接收消息是通过中断完成的。ACK 数据包看起来像:

0xA0,0x00,0x00,0x00,0x00

当它到来时,我将 ACK 设置为true

这是我的发送功能:

bool TransferService::send(char recAddr,char dataLength, char *data){
     pc.putc(startByte);
     pc.putc(recAddr);
     pc.putc(controllerAddress);
     pc.putc(dataLength);
     for (int i = 0; i < dataLength; i++) {
       pc.putc(data[i]);
     }
     pc.putc(getCrc(recAddr,controllerAddress,data, dataLength));
     _messageReceived = false;
     timer.reset();
     timer.start();
     ACK = false;
     do {
       if (ACK) {
         break;
       }
     } while(timer.read_ms()<=15);
     timer.stop();
     if (!ACK) {
       send(recAddr,dataLength,data);
     }
}

这只是尝试,它不起作用。

bool TransferService::send(char recAddr,char dataLength, char *data){
PT_BEGIN();
  timer.reset();
  timer.start();
  do {
    pc.putc(startByte);
    pc.putc(recAddr);
    pc.putc(controllerAddress);
    pc.putc(dataLength);
    for (int i = 0; i < dataLength; i++) {
      pc.putc(data[i]);
    }
    pc.putc(getCrc(recAddr,controllerAddress,data, dataLength));
    _messageReceived = false;
    PT_WAIT_UNTIL(!timer.read_ms() <=10 || ACK);
  } while(timer.read_ms() <=10);
  PT_END();
}

我的问题是如何使用 protothreads 使第一个函数正常工作。

4

1 回答 1

1

Adam Dunkels 的 Protothreads 实现中的线程函数结构非常清晰,您的函数显然不遵循它。

Protothread 线程函数必须返回int并且通常具有签名:

int threadfunction( struct pt* pt ) ;

并且必须使用PT_THREAD宏定义,因此:

PT_THREAD( threadfunction( struct pt* pt ) )
{
    PT_BEGIN(pt) ;
    // thread body here
    PT_END(pt) ;
}

Protothread文档...

protothread 函数必须始终返回一个整数,但绝不能显式返回 - 返回是在 protothread 语句中执行的。

查看 I 的定义,PT_THREAD没有任何东西可以阻止它与 C++ 成员函数一起使用,或者使用除 之外的其他参数pt,在这种情况下,以下内容更接近正确:

PT_THREAD( TransferService::send( struct pt* pt, char recAddr, char dataLength, char *data )
{
    PT_BEGIN( pt );
    timer.reset();
    timer.start();

    pc.putc( startByte );
    pc.putc( recAddr );
    pc.putc( controllerAddress );
    pc.putc( dataLength );
    for( int i = 0; i < dataLength; i++ )
    {
        pc.putc( data[i] );
    }
    pc.putc( getCrc( recAddr, controllerAddress, data, dataLength ) );
    _messageReceived = false;

    PT_WAIT_UNTIL( pt, timer.read_ms() > 10 || ACK );

    PT_END();
}

在您的尝试中,您有一个 do-while 循环和一个PT_WAIT_UNTIL,但是 WAIT 使循环变得不必要。实际上没有必要传递pt参数,所需的struct pt可能是类成员甚至是全局成员(尽管这是不明智的)。

请注意,以上内容遵循问题中明显的模式,但将是一种不寻常的设计模式;大多数情况下,一个线程会无限期地运行,而不是为单个事务运行。在不了解您的整个应用程序的情况下,我建议该线程应该在比单个事务send()函数更高的级别上运行,这样您就有一个“发送者”线程可以重复执行发送操作而不会退出,如下面的大纲所示(即不是完整或“真实”的代码,并且有很多假设):

// Constructor...
TransferService::TransferService()
{
    PT_INIT( &m_pt ) ;  // Where thread state m_pt 
                        // is a member variable of
                        // type struct pt (or just pt 
                        // since this is C++)
    ...
}

// Thread function
PT_THREAD(TransferService::senderThread() )
{
  PT_BEGIN(&m_pt);     
  for(;;)
  {
      PT_WAIT_UNTIL( &m_pt, ready_to_send ) ;

      timer.reset();
      timer.start();
      send( recAddr, dataLength, data ) ;

      PT_WAIT_UNTIL( &m_pt, timer.read_ms() > 10 || ACK );
  }
  PT_END(pt);
}

// Single send transaction function
bool TransferService::send( char recAddr, char dataLength, char *data )
{
    pc.putc( startByte );
    pc.putc( recAddr );
    pc.putc( controllerAddress );
    pc.putc( dataLength );
    for( int i = 0; i < dataLength; i++ )
    {
        pc.putc( data[i] );
    }
    pc.putc( getCrc( recAddr, controllerAddress, data, dataLength ) );
    _messageReceived = false;
}

请注意,由于PT_...API 的工作方式,PT_WAIT_UNTIL必须与 and 位于同一函数中PT_BEGINPT_END因此在上面的代码中移动了计时器等待。

于 2016-12-18T13:47:29.180 回答