Fel i serialkomm. mellan Arduino och PC

PIC, AVR, Arduino, Raspberry Pi, Basic Stamp, PLC mm.
Corpze
Inlägg: 256
Blev medlem: 29 januari 2013, 17:31:27

Fel i serialkomm. mellan Arduino och PC

Inlägg av Corpze »

Hej, jag har ett problem med mitt lilla projekt gällande att styra en fokusmotor från pc-programmet fokusMax och insticksprogrammet till det.
Jag har moddat orginalkoden så att jag även har en DHT22-sensor inkopplad men det verkar antingen som att utläsningen av den är antingen för seg, eller att den interfererar med någonting annat, vad det skulle vara vet jag inte, men jag vet att när jag sätter min "DHT-kod" på ca 15 rader inom /* */ så fungerar den övriga koden utmärkt. Sensorn är ju inte den snabbaste utan tar ju upp till 250ms på sig, kan det vara nåt med det? Tror att float'erna kanske har nåt att göra med det... för övriga lcd-koderna i koden fungerar utmärkt!

Det är i mitten av koden som DHT-sensorn är inlagd. Lägger även upp en bild på hur felmeddelandena ser ut (det är bara read fail som är själva felmeddelandet, de andra värdena står även där när koden fungerar perfekt.
prt2.jpg

Kod: Markera allt

#include <MsTimer2.h>
#include <DHT.h>
#include <LiquidCrystal.h>
#include <SPI.h>




LiquidCrystal lcd (12, 11, 10, 9, 7, 6);

//START OF FOCUS CONTROL INITIALISE
// include the library code:
#include <EEPROM.h>
#include <eepromRW.h>

#define MAX_COMMAND_LEN             (5)
#define MAX_PARAMETER_LEN           (6)
#define COMMAND_TABLE_SIZE          (11)
#define TO_UPPER(x) (((x >= 'a') && (x <= 'z')) ? ((x) - ('a' - 'A')) : (x))

#define DHTPIN A3
#define DHTTYPE DHT22

// initialize the library with the numbers of the interface pins
int dirPin = 2; // Easy Driver Direction Output Pin
int stepperPin = 3; // EasyDriver Stepper Step Output Pin
int powerPin = 4; //Sets the output used to power the Driver board
unsigned long powerMillis = 0; // used to remember when EasyDriver power was enabled
int motorSteps =200; //number if steps for the motor to turn 1 revolution

// MY OWN BUTTONCODE

int buttonIN = A0;
int buttonOUT = A1;
int val = 0;

// END OF MY OWN BUTTONCODE

// MY OWN DHT TO LCD-CODE

DHT dht(DHTPIN, DHTTYPE);

// END OF MY OWN DHT TO LCD-CODE

// MY OWN STEPS TO LCD-CODE

volatile long manualNoOfSteps;


// END OF MY OWN STEPS TO LCD-CODE

volatile long NoOfSteps = 1000; //required number of steps to make
volatile long Position = 0; //used to keep track of the current motorposition
volatile long MaxStep = 200000; //define maximum no. of steps, max travel
volatile int SPEED = 500;
volatile byte MotorType = 0; // Motortypes, default is 0, Stepper motor, 1=Servo, 2=DC motor                           
volatile int BoardType = 0; // Boardtypes, default is 0, EasyDriver, 1=L293 chip, 2=LadyAda AFmotor board                           

boolean Direction = true;//True is one way false is other.Change to false if motor is moving in the wrong direction
boolean IsMoving = false;
boolean Absolute = true;
volatile long MaxIncrement=16384;//not yet used
//END OF FOCUS CONTROL INITIALISE

//Serial comms setup
char incomingByte = 0; // serial in data byte
byte serialValue = 0;
boolean usingSerial = true; // set to false to have the buttons control everything
char gCommandBuffer[MAX_COMMAND_LEN + 1];
char gParamBuffer[MAX_PARAMETER_LEN + 1];
long gParamValue;
volatile boolean UPDATE = true;

struct config_t //Memory Structure for Parking, Unparking the Focuser and other config settings 
{
    long parkposition;
    boolean parked;
    boolean stepperdirection;
    long controlboardtype;
} configuration;


typedef struct {
  char const    *name;
  void          (*function)(void);
} 
command_t;

//Set up a command table. when the command "IN" is sent from the PC and this table points it to the subroutine to run
command_t const gCommandTable[COMMAND_TABLE_SIZE] = {
  {
    "IN1",     FocusINFun,  }
  ,
  {
    "OUT",    FocusOUTFun,   }
  ,
  {
    "STP",  FocusSTEPSFun,   }
  ,
  {
    "SPD",  FocusSPEEDFun,   }
  ,
  {
    "LMT",  FocusSLimitFun,   }
  ,
  {
    "POS",    FocusSPositionFun,   }
  ,  
  {
    "MDE",   FocusSModeFun,   }
  ,
  {
    "TYP",   FocusSTypeFun,   }
  ,  
  {
    "PRK",   ParkFocuserFun,   }
  ,  
  {
    "BRD",   FocusBoardTypeFun,   }
  ,  
  {
    NULL,      NULL   }
};

//Serial Comms setup end

void setup() {

  EEPROM_readAnything(0, configuration); //PARKING:- Read the Position and Parked info
    if (configuration.parked == true) { //If the Focuser was Parked then load the Position information
    
     Position = configuration.parkposition; //Load the Position information
     Direction = configuration.stepperdirection;
     BoardType = configuration.controlboardtype;
  }

  pinMode(dirPin, OUTPUT); //Initialise Easydriver output
  pinMode(stepperPin, OUTPUT); //Initialise easy driver output
  //START OF FOCUS CONTROL SETUP
   //END OF FOCUS CONTROL SETUP
  Serial.begin(19200);// start the serial
  NoOfSteps=1000;
  pinMode(13,OUTPUT); 
  pinMode(powerPin,OUTPUT); //Easydriver Sleep mode or power off
  digitalWrite(powerPin, LOW); //Easydriver Pwer off (Low = powered down)
  
  // MY OWN BUTTONCODE
  pinMode(dirPin, OUTPUT);
  pinMode(stepperPin, OUTPUT);
  pinMode(buttonIN, INPUT);
  digitalWrite(buttonIN, HIGH);
  pinMode(buttonOUT, INPUT);
  digitalWrite(buttonOUT, HIGH);
  // END OF MY OWN BUTTONCODE
  
  // MY OWN DHT TO LCD-CODE
  lcd.begin(16,2);
  dht.begin();
  // END OF MY OWN DHT TO LCD-CODE
 
  
  
  
}

void printStep(){
lcd.setCursor(6,0);
char s[7];
sprintf(s, "%7ld", manualNoOfSteps);
lcd.print(s);

MsTimer2::set(200, printStep);
MsTimer2::start();
}
void loop() {

 
  int bCommandReady = false;
  
  //FocuserControl Power off command
  if (millis() > (powerMillis + 20000)) // check if power has been on for more than 20 seconds
  {
      digitalWrite(powerPin, LOW); // if yes, then disable power
  }
  
  //If There is information in the Serial buffer read it in and start the Build command subroutine
  if (usingSerial && Serial.available() >= 1) {
    // read the incoming byte:
    incomingByte = Serial.read();
    delay(5);
    if (incomingByte == '#') {
    // Build a new command. //
    bCommandReady = cliBuildCommand(incomingByte);
    }
  }
  else
  {
    incomingByte=0;
    //Serial.flush();
  }

  //If there is a command in the buffer then run the process command subroutine
  if (bCommandReady == true) {
    bCommandReady = false; // reset the command ready flag
    cliProcessCommand(); // run the command
  }
 if ((Position != configuration.parkposition)) {
  configuration.parked = 0;
  EEPROM_writeAnything(0, configuration);
 }
  if (UPDATE){
    UPDATE=false;
    SerialDATAFun();  // Used to send the current state of the focuser to the PC over serial comms
  }
  
//MY OWN BUTTONCODE

//IN

lcd.setCursor(0,0);
        lcd.print("Steps:");

delayMicroseconds(200);
val = digitalRead(buttonIN);
  if (val == LOW)
  {
    digitalWrite(powerPin, HIGH);
    digitalWrite(dirPin, HIGH);
    MsTimer2::set(500, printStep);
    MsTimer2::start();
    while (val == LOW) {
      digitalWrite(stepperPin, HIGH);
      delayMicroseconds(200);
      digitalWrite(stepperPin, LOW);
      delayMicroseconds(200);
      manualNoOfSteps  = manualNoOfSteps + 1;
      
      val = digitalRead(buttonIN);
    }
    MsTimer2::stop();
    
  }

  
//OUT

delayMicroseconds(200);
  val = digitalRead(buttonOUT);
  if (val == LOW)
  {
    digitalWrite(powerPin, HIGH);
    digitalWrite(dirPin, LOW);
    MsTimer2::set(500, printStep);
    MsTimer2::start();
    while (val == LOW) {
      digitalWrite(stepperPin, HIGH);
      delayMicroseconds(200);
      digitalWrite(stepperPin, LOW);
      delayMicroseconds(200);
      manualNoOfSteps = manualNoOfSteps - 1;
      
      val = digitalRead(buttonOUT);
    }
    MsTimer2::stop();
   
  }
  
 // END OF MY OWN BUTTONCODE
 
 // MY OWN DHT TO LCD-CODE
 
 // Reading temperature or humidity takes about 250 milliseconds!
 // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
/* float h = dht.readHumidity();
 float t = dht.readTemperature();

 // check if returns are valid, if they are NaN (not a number) then something went wrong!
 if (isnan(t) || isnan(h)) {
 lcd.setCursor(1,1);
 lcd.println("Failed to read from DHT");
 } else {
  lcd.setCursor(9,1);
  lcd.print(h);
  lcd.print(" %");
  lcd.setCursor(0,1);
  lcd.print(t);
  lcd.print((char)223);
  lcd.print("C");*/
  }

 // END OF MY OWN DHT TO LCD-CODE



//***************************************************
//*****Start of User defined Functions **************
//***************************************************

//START OF FOCUS CONTROL FUNCTIONS
void EasyDriverStep(boolean dir,long steps){
  digitalWrite(powerPin, HIGH); // enable power to the EasyDriver
  powerMillis = millis(); // remember when power was switched on
  delayMicroseconds(10); // wait a bit after switching on power
  digitalWrite(dirPin,dir);
  delay(100);
  for(int i=0;i<steps;i++){
    digitalWrite(stepperPin, HIGH);
    delayMicroseconds(SPEED);
    digitalWrite(stepperPin, LOW);
    delayMicroseconds(SPEED);
  }
}

void ParkFocuserFun (void) {//Park the focuser by setting the Park bit to 1 and the current Focuser Position in Configuration

 if (configuration.parked == false){
 configuration.parkposition = Position;
 configuration.stepperdirection = Direction;
 configuration.parked = true;
 configuration.controlboardtype = BoardType;
 
 EEPROM_writeAnything(0, configuration);
 }
  UPDATE=true; //Update even if the focuser was already parked
}

void FocusINFun (void) {//Move the Stepper IN.
  long Steps = 0;

  if (Absolute == false) {  //If not Absolute move the number of steps
    if ((Position-NoOfSteps)>=0) {
    switch (BoardType) {
    case 0:
      EasyDriverStep(Direction,NoOfSteps);
      break;
      default: 
      // if nothing else matches, do the default
      // default is optional
      break;
      }
       Position=Position-NoOfSteps;
      }
  }
  else if (NoOfSteps < MaxStep) //Absolute :- work out the number of steps to take based on current position
  {
    if (NoOfSteps<Position){
    
       Steps=(Position-NoOfSteps);
       switch (BoardType) {
        case 0:
         EasyDriverStep(Direction,Steps);
        break;
        default: 
      // if nothing else matches, do the default
      // default is optional
      break;
      }
     Position=NoOfSteps;
    }
    else
    {
    Steps=(NoOfSteps-Position);
    switch (BoardType) {
        case 0:
         EasyDriverStep(!Direction,Steps);
        break;
        default:
        break; 
      }
    Position=NoOfSteps;  
    }
  }
  // set the update flag so that the new position is displayed
  IsMoving=true;
  UPDATE=true;
}

void FocusOUTFun (void) {//Move the Stepper OUT.
 long Steps = 0;

  if (Absolute == false) {  //If not Absolute move the number of steps
    if ((Position+NoOfSteps)<=MaxStep) {
       switch (BoardType) {
        case 0:
         EasyDriverStep(!Direction,NoOfSteps);
        break;
        default: 
      // if nothing else matches, do the default
      // default is optional
       break;
      }
      Position=Position+NoOfSteps;
    }
  }
  else if (NoOfSteps < MaxStep) //Absolute :- work out the number of steps to take based on current position
  {
    if (NoOfSteps>Position){
    
    Steps=(NoOfSteps-Position);
    switch (BoardType) {
        case 0:
         EasyDriverStep(!Direction,Steps);
        break;
        default: 
      // if nothing else matches, do the default
      // default is optional
       break;
      }
    Position=NoOfSteps;
    }
    else
    {
    Steps=(Position-NoOfSteps);
    switch (BoardType) {
        case 0:
         EasyDriverStep(Direction,Steps);
        break;
        default: 
      // if nothing else matches, do the default
      // default is optional
       break;
      }
    Position=NoOfSteps;  
    }
  }
  // set the update flag so that the new position is displayed
  IsMoving=true;
  UPDATE=true;
}

void FocusSTEPSFun (void) {//Set the number of Steps.
  NoOfSteps = gParamValue;
  // set the update flag so that the new position is displayed
  UPDATE=true;
}

// function to set the RPM of the stepper motor
// user sends :speed:500:
void FocusSPEEDFun (void) {
  SPEED = gParamValue;
  UPDATE=true;
}

// Set max limit for focus travel, for absolute positioning focusers
void FocusSLimitFun (void) {
  MaxStep = gParamValue;
  UPDATE=true;
}

// set current focuser position, used for calibrating absolute positioning focusers
void FocusSPositionFun (void) {
  Position = gParamValue;
  UPDATE=true;
}

// set the focuser mode to relative 0 or absolute positioning 1
void FocusSModeFun (void) {
  switch (gParamValue){
  case 0:
    Absolute=false;
    //Serial.println("Relative Mode"); // debug only
    break;
  case 1:
    Absolute=true;
    //Serial.println("Absolute Mode"); // debug only
    break;
  default:
    //Serial.println("0 or 1 for relative or absolute, try again"); // debug only
    break;  
  }
  UPDATE=true;
}
// to add different motor types, stepper, servo or DC
void FocusSTypeFun(void){
  MotorType=gParamValue;
  UPDATE=true;
}

// to add different motor types, stepper, servo or DC
void FocusBoardTypeFun(void){
  BoardType=gParamValue;
  UPDATE=true;
}
//END OF FOCUS CONTROL FUNCTIONS

//Start of serial control functions

void SerialDATAFun (void) {//Update All information over comms if there has been any change in the state of the focuser
   Serial.print("#POS:");  
  Serial.print(Position);
  Serial.println(";");
  Serial.print("#STP:" );
  Serial.print(NoOfSteps);
  Serial.println(";");
  Serial.print("#MDE:");
  if (Absolute){
  Serial.print("1");
  }
  else{  
  Serial.print("0");
  }
  Serial.println(";");
  Serial.print("#LMT:");
  Serial.print(MaxStep);
  Serial.println(";");
   Serial.print("#SPD:");
 if (SPEED==0){
  Serial.print(char(SPEED));
  }
  else{  
  Serial.print(SPEED);
  }
  Serial.println(";");
  if (IsMoving==true) {
    Serial.print("#MOV:");
    Serial.print("1");
    Serial.println(";");
    IsMoving=false;
  }
  Serial.print("#BRD:0");  
  Serial.print(BoardType);
  Serial.println(";");
  Serial.print("#PRK:");  
  if (configuration.parked == 1) Serial.print("01"); else Serial.print("00");
  Serial.println(";");
}


//Process Command. This searches the command table to see if the command exits if it does then the required subroutine is run
void cliProcessCommand(void)
{
  int bCommandFound = false;
  int idx;

  /* Convert the parameter to an integer value. 
   * If the parameter is emplty, gParamValue becomes 0. */
  gParamValue = strtol(gParamBuffer, NULL, 0);

  /* Search for the command in the command table until it is found or
   * the end of the table is reached. If the command is found, break
   * out of the loop. */
  for (idx = 0; gCommandTable[idx].name != NULL; idx++) {
    if (strcmp(gCommandTable[idx].name, gCommandBuffer) == 0) {
      bCommandFound = true;
      break;
    }
  }

  /* If the command was found, call the command function. Otherwise,
   * output an error message. */
  if (bCommandFound == true) {
    (*gCommandTable[idx].function)();
  }
}


//When data is in the Serial buffer this subroutine is run and the information put into a command buffer.
// The character : is used to define the end of a Command string and the start of the parameter string
// The character ; is used to define the end of the Parameter string
int cliBuildCommand(char nextChar) {
  static uint8_t idx = 0; //index for command buffer
  static uint8_t idx2 = 0; //index for parameter buffer
  int loopchk = 0;

  nextChar = Serial.read();
  do
  {

    gCommandBuffer[idx] = TO_UPPER(nextChar);
    idx++;
    nextChar = Serial.read();
    loopchk=loopchk+1;
  } 
  while ((nextChar != ':') && (loopchk < 100));

  loopchk=0;

  nextChar = Serial.read();

  do
  {

    gParamBuffer[idx2] = nextChar;
    idx2++;
    nextChar = Serial.read();
  } 
  while ((nextChar != ';')&& (idx2 < 100));



  gCommandBuffer[idx] = '\0';
  gParamBuffer[idx2] = '\0';
  idx = 0;
  idx2 = 0;

  return true;
}

//END of serial control functions


Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Senast redigerad av Corpze 14 mars 2013, 11:07:36, redigerad totalt 1 gång.
eqlazer
Inlägg: 923
Blev medlem: 22 september 2007, 13:53:45
Ort: Göteborg

Re: Fel i serialkomm. mellan Arduino och PC

Inlägg av eqlazer »

Bra, då har du lärt dig att float kan ställa till med mycket på en liten µC :)
Corpze
Inlägg: 256
Blev medlem: 29 januari 2013, 17:31:27

Re: Fel i serialkomm. mellan Arduino och PC

Inlägg av Corpze »

Haha :) håller den för mkt siffror för min lilla pic? den blir alltså för seg?

Kan man sätta float'arna som integers istället?

Edit: fann i DHT.cpp att det låg en serial.print som heter Read Fail.. kan det vara spöket som gör att PC-programmet inte svarar? den får en serial-sträng som den inte fattar?

Kod: Markera allt

/* DHT library 

MIT license
written by Adafruit Industries
*/

#include "DHT.h"

DHT::DHT(uint8_t pin, uint8_t type, uint8_t count) {
  _pin = pin;
  _type = type;
  _count = count;
  firstreading = true;
}

void DHT::begin(void) {
  // set up the pins!
  pinMode(_pin, INPUT);
  digitalWrite(_pin, HIGH);
  _lastreadtime = 0;
}

//boolean S == Scale.  True == Farenheit; False == Celcius
float DHT::readTemperature(bool S) {
  float f;

  if (read()) {
    switch (_type) {
    case DHT11:
      f = data[2];
      if(S)
      	f = convertCtoF(f);
      	
      return f;
    case DHT22:
    case DHT21:
      f = data[2] & 0x7F;
      f *= 256;
      f += data[3];
      f /= 10;
      if (data[2] & 0x80)
	f *= -1;
      if(S)
	f = convertCtoF(f);

      return f;
    }
  }
  Serial.print("Read fail");
  return NAN;
}

float DHT::convertCtoF(float c) {
	return c * 9 / 5 + 32;
}

float DHT::readHumidity(void) {
  float f;
  if (read()) {
    switch (_type) {
    case DHT11:
      f = data[0];
      return f;
    case DHT22:
    case DHT21:
      f = data[0];
      f *= 256;
      f += data[1];
      f /= 10;
      return f;
    }
  }
  Serial.print("Read fail");
  return NAN;
}


boolean DHT::read(void) {
  uint8_t laststate = HIGH;
  uint8_t counter = 0;
  uint8_t j = 0, i;
  unsigned long currenttime;

  // pull the pin high and wait 250 milliseconds
  digitalWrite(_pin, HIGH);
  delay(250);

  currenttime = millis();
  if (currenttime < _lastreadtime) {
    // ie there was a rollover
    _lastreadtime = 0;
  }
  if (!firstreading && ((currenttime - _lastreadtime) < 2000)) {
    return true; // return last correct measurement
    //delay(2000 - (currenttime - _lastreadtime));
  }
  firstreading = false;
  /*
    Serial.print("Currtime: "); Serial.print(currenttime);
    Serial.print(" Lasttime: "); Serial.print(_lastreadtime);
  */
  _lastreadtime = millis();

  data[0] = data[1] = data[2] = data[3] = data[4] = 0;
  
  // now pull it low for ~20 milliseconds
  pinMode(_pin, OUTPUT);
  digitalWrite(_pin, LOW);
  delay(20);
  cli();
  digitalWrite(_pin, HIGH);
  delayMicroseconds(40);
  pinMode(_pin, INPUT);

  // read in timings
  for ( i=0; i< MAXTIMINGS; i++) {
    counter = 0;
    while (digitalRead(_pin) == laststate) {
      counter++;
      delayMicroseconds(1);
      if (counter == 255) {
        break;
      }
    }
    laststate = digitalRead(_pin);

    if (counter == 255) break;

    // ignore first 3 transitions
    if ((i >= 4) && (i%2 == 0)) {
      // shove each bit into the storage bytes
      data[j/8] <<= 1;
      if (counter > _count)
        data[j/8] |= 1;
      j++;
    }

  }

  sei();
  
  /*
  Serial.println(j, DEC);
  Serial.print(data[0], HEX); Serial.print(", ");
  Serial.print(data[1], HEX); Serial.print(", ");
  Serial.print(data[2], HEX); Serial.print(", ");
  Serial.print(data[3], HEX); Serial.print(", ");
  Serial.print(data[4], HEX); Serial.print(" =? ");
  Serial.println(data[0] + data[1] + data[2] + data[3], HEX);
  */

  // check we read 40 bits and that the checksum matches
  if ((j >= 40) && 
      (data[4] == ((data[0] + data[1] + data[2] + data[3]) & 0xFF)) ) {
    return true;
  }
  

  return false;

}
Edit, fann felet, det var i dht.cpp-filen som serial.print spökade, nu fungerar det att köra från datorn!
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Fel i serialkomm. mellan Arduino och PC

Inlägg av sodjan »

> Kan man sätta float'arna som integers istället?

Det är ju behovet i din applikation som får styra vad som passar.
Men generellt kan man säga att det ofta går att ersätta float med
fixed-point integers, bara de är tillräckligt stora. Det kan en enkel
analys av vilka tolområden det handlar om svara på.
Corpze
Inlägg: 256
Blev medlem: 29 januari 2013, 17:31:27

Re: Fel i serialkomm. mellan Arduino och PC

Inlägg av Corpze »

Ok, som i detta fallet när jag skall läsa ut temp och luftfuktighet, då räcker det med en decimal, men jag antar att det är formlerna i biblioteket som styr, inte resultatet av dessa?
sodjan
EF Sponsor
Inlägg: 43251
Blev medlem: 10 maj 2005, 16:29:20
Ort: Söderköping

Re: Fel i serialkomm. mellan Arduino och PC

Inlägg av sodjan »

Ja, om man använder "rutiner på burk" så måste ju deras
in/ut parametrar styra datatyperna, så klart.
Användarvisningsbild
Icecap
Inlägg: 26650
Blev medlem: 10 januari 2005, 14:52:15
Ort: Starup (Haderslev), Danmark

Re: Fel i serialkomm. mellan Arduino och PC

Inlägg av Icecap »

Jag är ganska säker på att formlerna borde bli ganska rätt om man räknar i t.ex. 1/10-del grad eller procent. Då blir 10,0°C ett värde på 100 - vilket enkelt kan betraktas som ett heltal.

Flyttal kan ibland vara rätt typ att använda - men i min erfarenhet är det mycket sällsynt i µC-världen.
Skriv svar