2013-06-26 107 views
0

我在使用状态机设置时遇到问题。我知道这些,所以我有一个问题。所以这里有一些方法可以忽略。主要的问题是由于某种原因,它发送一个消息给它接收到的每个字节,但我认为Serial.read()在读取后清除了缓冲区。 因此,这里的大量代码:状态机问题

#include "Arduino_Structures.h" 
#include <SPI.h> 
#include <Ethernet.h> 
#include "Time.h" 

//GLOBAL DECLARATIONS 
enum { STANDBY, SEND, RECEIVE, PROCESS} state = SEND; 
enum { STATUS, CONFIG, CURRENT, TIME, VOLTAGE} messageType = STATUS; 

char lcv; 
char lcv2; //loop control variables 

MESSAGE_STRUCT outgoing; //changing outgoing message 
MESSAGE_STRUCT incoming; //changing incoming message 
OODLES_BLOCK oodles;   //oodles of information from the following 5 blocks 
    STATUS_BLOCK temp_status;  //temporary status block 
    CONFIG_BLOCK temp_config;  //temporary config block 
    CURRENT_BLOCK temp_current; //temporary current block 
    TIME_BLOCK temp_time;    //temporary time block 
    VOLTAGE_BLOCK temp_voltage; //temporary voltage block 


//FUNCATION DECLARATIONS 
void sendMsg(MESSAGE_STRUCT* outgoing); 
void receiveMsg(MESSAGE_STRUCT* incoming); 

//ARDUINO SETUP 
void setup() 
{ 
    delay(TIMEOUT); //wait for the boards to start up 
    Serial.begin(BAUD); //set the arduino to be at the Micro-AT baud rate 
    do 
    { 
     lcv = Ethernet.begin(mac); //start etherent board, get IP 
    }while(!lcv); 

} 

//ARDUINO LOOP 
void loop() 
{ 
    switch(state) 
    { 
    case STANDBY: 
     delay(1000); 
     state = SEND; 
     break; 

    case SEND: 

     switch(messageType) 
     { 
     case STATUS: 
      outgoing.start_byte = 0x00; 
      outgoing.length = 0x00; 
      outgoing.address_1 = 0xFF; 
      outgoing.address_2 = 0xFF; 
      outgoing.code_word = REQUEST_STATUS; 
      outgoing.checksum = 0; 

      sendMsg(&outgoing); 
      state = RECEIVE; 
      break; 

     case CONFIG: 
      outgoing.start_byte = 0x00; 
      outgoing.length = 0x00; 
      outgoing.address_1 = 0xFF; 
      outgoing.address_2 = 0xFF; 
      outgoing.code_word = REQUEST_CONFIG; 
      outgoing.checksum = 0; 

      sendMsg(&outgoing); 
      state = RECEIVE; 
      break; 

     case CURRENT: 
      outgoing.start_byte = 0x00; 
      outgoing.length = 0x00; 
      outgoing.address_1 = 0xFF; 
      outgoing.address_2 = 0xFF; 
      outgoing.code_word = REQUEST_CURRENT; 
      outgoing.checksum = 0; 

      sendMsg(&outgoing); 
      state = RECEIVE; 
      break; 

     case TIME: 
      outgoing.start_byte = 0x00; 
      outgoing.length = 0x00; 
      outgoing.address_1 = 0xFF; 
      outgoing.address_2 = 0xFF; 
      outgoing.code_word = REQUEST_TIME; 
      outgoing.checksum = 0; 

      sendMsg(&outgoing); 
      state = RECEIVE; 
      break; 

     case VOLTAGE: 
      outgoing.start_byte = 0x00; 
      outgoing.length = 0x00; 
      outgoing.address_1 = 0xFF; 
      outgoing.address_2 = 0xFF; 
      outgoing.code_word = REQUEST_VOLTAGE; 
      outgoing.checksum = 0; 

      sendMsg(&outgoing); 
      state = RECEIVE; 
      break; 

     default: 
      break; 
     } 
    break; 
    case RECEIVE: 
     if(Serial.available()) 
     { 
         state = SEND; 
       receiveMsg(&incoming); 
        //NEED TO CHECK TO MAKE SURRE START BYTE AND ADDRESS ARE CORRECT 
        //ALSO THIS IS WHERE I SHOULD CHECK THE CHECKSUM 
        //ONCE INSIDE SWITCHES NEED TO MAKE SURE THE RESPONSE IS CORRECT 
      switch(messageType) 
      { 
      case STATUS: 
       //copy information from incoming's data array to the temp_status block so that it retains its structure 
       memcpy(&temp_status, &incoming.data, sizeof(STATUS_BLOCK)); 

       //these are directly taken from the status block information (Arduino_Structures.h) 
       oodles.left_source = temp_status.left_source; 
       oodles.right_source = temp_status.right_source; 
       oodles.left_overcurrent = temp_status.left_overcurrent; 
       oodles.right_overcurrent = temp_status.right_overcurrent; 
       oodles.automatic_transfer = temp_status.ready; 
       oodles.event_led = temp_status.event; 
       oodles.bus_type = temp_status.bus_type; 
       oodles.preferred = temp_status.preferred; 
       oodles.lockout_installed = temp_status.lockout_installed; 
       oodles.supervisory_control = temp_status.supervisory_control; 

       //put the time into the TimeElement then convert it to unix time 
       TimeElements timeInfo; //will be used (from Time.h library) 
       timeInfo.Year = temp_status.year; 
       timeInfo.Month = temp_status.month; 
       timeInfo.Day = temp_status.day; 
       timeInfo.Hour = temp_status.hour; 
       timeInfo.Minute = temp_status.minute; 
       timeInfo.Second = temp_status.second; 
       oodles.unix_time = makeTime(timeInfo); 

       //might want to wipe incoming and outogoing messages to make sure they get correctly rewritten 
       //messageType = CONFIG; 
       //state = SEND; 
       break; 

      case CONFIG:    
       break; 

      case CURRENT: 
       break; 

      case TIME: 
       break; 

      case VOLTAGE: 
       break; 
      } 
       } 
     break; 

    case PROCESS: 
     break; 
    } 
} 

void sendMsg(MESSAGE_STRUCT* message) 
{ 
    //brake up integers from MESSAGE_STRUCT to bytes (see intByte in Arduino_Structures.h) 

    intByte code_word, checksum; 

    code_word.intValue = message->code_word; 
    checksum.intValue = message->checksum; 

    //send byte by byte 
    Serial.write(message->start_byte); 
    Serial.write(message->length); 
    Serial.write(message->address_1); 
    Serial.write(message->address_2); 
    Serial.write(code_word.byte1); 
     Serial.write(code_word.byte2); 

    for(lcv = 0; lcv < message->length; lcv++) 
     Serial.write(message->data[lcv]); 

    Serial.write(checksum.byte1); 
     Serial.write(checksum.byte2); 
} 

void receiveMsg(MESSAGE_STRUCT* message) 
{ 
    //receive bytes and put them back as integers (see intByte in Arduino_Structures.h) 
     intByte code_word, checksum; 

    //receive byte by byte 
    message->start_byte = Serial.read(); 
    message->length = Serial.read(); 
    message->address_1 = Serial.read(); 
    message->address_2 = Serial.read(); 
    code_word.byte1 = Serial.read(); 
     code_word.byte2 = Serial.read(); 
     message->code_word = code_word.intValue; 

    for(lcv = 0; lcv < message->length; lcv++) 
     message->data[lcv] = Serial.read(); 

     checksum.byte1 = Serial.read(); 
     checksum.byte2 = Serial.read(); 
     message->checksum = checksum.intValue; 
} 

这里是显示错误的串行显示器,它应该只响应一次,如果我把它只有一个字节一次响应。如果我下面把它的8个字节的响应,它响应8次(“答案”是指Arduino的笔记本电脑,并“请求”是指笔记本电脑的Arduino):

Answer: 6/26/2013 4:30:59 PM.56364 (+11.3133 seconds) 

00 00 FF FF 00 01 00 00       

Request: 6/26/2013 4:31:00 PM.48564 (+0.9219 seconds) 

00 00 FF FF 01 01 00 00       

Answer: 6/26/2013 4:31:00 PM.51664 (+0.0156 seconds) 

00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00 
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00 
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00 
00 00 FF FF 00 01 00 00 00 00 FF FF 00 01 00 00 
+0

从[Serial.read()](http://arduino.cc/en/Serial/Read)文档:“返回可用的传入串行数据的第一个字节”。它只读取1个字节,并没有说清除缓冲区,我怀疑它只消耗1个字节。你可以使用[Serial.readBytes()](http://arduino.cc/en/Serial/ReadBytes),如果这更接近你正在寻找的行为。 – Macattack

回答

1

它看起来像你检查,看看该Serial.available()不是零,然后读取一堆数据。这可能是因为当你开始你的receiveMsg功能时,你没有完成接收数据。你应该:

  1. 检查以确保您需要的字节,如果
  2. 它们不提供等待,但你期待他们即将

只是作为一个例子:

void receiveMsg(MESSAGE_STRUCT* message) 
{ 
    // receive bytes and put them back as integers 
    intByte code_word, checksum; 

    // receive byte by byte, wait for it if need be 
    while(Serial.available() < 1) {delay(10);} 
    message->start_byte = Serial.read(); 
    while(Serial.available() < 1) {delay(10);} 
    message->length = Serial.read(); 

有更好,更可靠的方法来做到这一点,但这是非常简单和容易实现的测试,以查看输入缓冲区是否没有被填满。