国家机器问题

时间:2013-06-26 21:43:17

标签: c++ c hex arduino state-machine

我在使用状态机设置时遇到问题。我知道这些,所以我遇到了问题。所以这里有一些方法可以忽略。主要问题是由于某种原因它为它收到的每个字节发送一条消息,但我认为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

1 个答案:

答案 0 :(得分:1)

看起来你正在检查Serial.available()是不是零,然后读取一堆数据。可能是您在开始receiveMsg功能时未收到数据。你应该:

  1. 检查以确保您需要的字节可用等待
  2. 它们不可用,但您希望它们即将推出
  3. 仅作为一个例子:

    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();
    

    有更好,更强大的方法可以做到这一点,但这很简单,很容易实现测试,看看输入缓冲区是否没有被填充。