Arduino Uno低内存可用

时间:2019-01-12 22:15:12

标签: arduino arduino-uno

我正在尝试使用ENC28J60和Arduino Uno通过以太网进行通信,并运行3 task。我的arduino代码有点问题。我的代码正在编译,但是出现以下错误:“可用内存不足,可能会出现稳定性问题。”并且板上的LED闪烁得非常快。我想董事会正在尝试分配内存,但他失败了。知道我该怎么办吗?

#include <Arduino_FreeRTOS.h>
#include "HX711.h"
#include <PID_v1.h>
#include <string.h>
//#include <SPI.h>
#include <UIPEthernet.h>

#define configUSE_IDLE_HOOK 0

// FreeRTOS tasks
void TaskPrimaryControlLoop(void *pvParameters);
void TaskConcentrationControlLoop(void *pvParameters);
void TaskIdle(void *pvParameters);

/* Weigth Cells */
#define hx_pf_dout 3
#define hx_pf_clk  2
#define hx_c_dout 5
#define hx_c_clk  4
HX711 pf_scale(hx_pf_dout, hx_pf_clk);
HX711 c_scale(hx_c_dout, hx_c_clk);
float pf_factor = -236000;
float c_factor = -203000;
float p_weigth   = 0; // (kg, 0.000) primary liquid weigth
float p_l_weigth = 0; // (kg, 0.000) primary liquid last weigth
float c_weigth   = 0; // (kg, 0.000) concentrate liquid weigth
float c_l_weight = 0; // (kg, 0.000) concentrate liquid last weigth

/* h bridge config */
#define speed_p     9
#define forward_p   7
#define backward_p  8
#define speed_c     6
#define forward_c   A0
#define backward_c  A1
double p_pump = 0; // 0-255 pwm pump output
double c_pump = 0; // 0-255 pwm pump output

//// PID parameters 
// Primary Control Loop
#define p_kp 250.0
#define p_ki 25.0
// Concentration Control Loop
#define c_kp 250.0
#define c_ki 25.0
double p_pv   = 0; // (%) primary flow value
double c_pv   = 0; // (%) concentration flow value
double p_sp = 0; // (l/min) primary flow setpoint
double c_sp_proc = 0; // % concentration
double c_sp  = 0; // (l/min) concentration setpoint
PID pid_pcl(&p_pv, &p_pump, &p_sp, p_kp,p_ki,0.0, DIRECT);
PID pid_ccl(&c_pv, &c_pump, &c_sp, c_kp,c_ki,0.0, DIRECT);


/* Communication Ethernet */
#define MAX_STRING_LEN  32
const byte numChars = 32;
char receivedChars[numChars];
boolean newData = false;

byte mac[] = {
  0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};
IPAddress ip(192, 168, 1, 2);
IPAddress myDns(192,168,1, 1);
IPAddress gateway(192, 168, 1, 1);
IPAddress subnet(255, 255, 255, 0);

// telnet defaults to port 23
EthernetServer server(23);
//EthernetClient client;
boolean alreadyConnected = false; // whether or not the client was connected previously


void setup() {

  Serial.begin(9600);

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB, on LEONARDO, MICRO, YUN, and other 32u4 based boards.
  }

  pinMode(forward_p, OUTPUT);
  pinMode(backward_p, OUTPUT);
  pinMode(forward_c, OUTPUT);
  pinMode(backward_c, OUTPUT);
  pinMode(speed_p, OUTPUT);
  pinMode(speed_c, OUTPUT);

  digitalWrite(backward_p, HIGH);
  digitalWrite(backward_c, HIGH);
  digitalWrite(forward_p, LOW);
  digitalWrite(forward_c, LOW);

  pf_scale.set_scale(pf_factor);
  c_scale.set_scale(c_factor);
  //pf_scale.tare();
  //c_scale.tare();

  pid_ccl.SetMode(AUTOMATIC);
  pid_pcl.SetMode(AUTOMATIC);


  xTaskCreate(
      TaskPrimaryControlLoop
      ,  (const portCHAR *)"PrimaryControlLoop"   // A name just for humans
      ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
      ,  NULL
      ,  2  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
      ,  NULL );
  xTaskCreate(
    TaskConcentrationControlLoop
    ,  (const portCHAR *)"ConcentrationControlLoop"   // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  2  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL );
  xTaskCreate(
    TaskIdle
    ,  (const portCHAR *)"Idle"   // A name just for humans
    ,  512  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  0  // Priority, with 3 (configMAX_PRIORITIES - 1) being the highest, and 0 being the lowest.
    ,  NULL );
}

void loop() {
}

void TaskPrimaryControlLoop(void *pvParameters)
{
  //(void) pvParameters;
  for (;;)
    {
      p_weigth = pf_scale.get_units(1);
      p_pv = (p_l_weigth - p_weigth)*100;
      if(p_pv < 0) p_pv = 0;

      pid_pcl.Compute();
      analogWrite(speed_p, p_pump);

      p_l_weigth = p_weigth;
      vTaskDelay(200 / portTICK_PERIOD_MS);  // 200 ms sample time
    }
}

void TaskConcentrationControlLoop(void *pvParameters)
{
  //(void) pvParameters;
  for (;;)
    {
      c_weigth = c_scale.get_units(1);
      c_pv = (c_l_weight - c_weigth)*100;
      if(c_pv < 0) c_pv = 0;

      c_sp = p_sp * (c_sp_proc/100);

      pid_ccl.Compute();
      analogWrite(speed_c, c_pump);

      c_l_weight = c_weigth;
      vTaskDelay(200 / portTICK_PERIOD_MS);  // 200 ms sample time
    }
}


void TaskIdle(void *pvParameters)
{
  //(void) pvParameters;
  for(;;){

    EthernetClient client = server.available();
    // when the client sends the first byte, say hello:
    if (client) {
      if (!alreadyConnected) {
        client.flush();
        //Serial.println("We have a new client");
        //client.println("Hello, client!");
        alreadyConnected = true;
      }
    }

    recvWithStartEndMarkers();
    //showNewData();

    if(receivedChars[0] == 's'){
       p_sp = atof(subStr(receivedChars, ",", 2));
       c_sp_proc = int(subStr(receivedChars, ",", 3));
       newData = false;
       memset(receivedChars, 0, sizeof(receivedChars));
    }

    // send process values to application
    if(receivedChars[0] == 'w'){
      Serial.print(p_pv);
      Serial.print(",");
      Serial.print(p_sp);
      Serial.print(",");
      Serial.print(int(c_pump));
      Serial.print(",");
      Serial.print(c_pv);
      Serial.print(",");
      Serial.print(c_sp);
      Serial.print(",");
      Serial.print(int(p_pump));
      Serial.println();
      newData = false;
      memset(receivedChars, 0, sizeof(receivedChars));
    }



    /*
    // check commands
    while(Serial.available() > 7){
       p_sp  = Serial.parseFloat();
       c_sp_proc = Serial.parseInt();
    }
    newData = false;
    memset(receivedChars, 0, sizeof(receivedChars)

    */
    newData = false;
    memset(receivedChars, 0, sizeof(receivedChars));

    vTaskDelay(1);
  }
}

void recvWithStartEndMarkers() {
    static boolean recvInProgress = false;
    static byte ndx = 0;
    char startMarker = '<';
    char endMarker = '>';
    char rc;
    EthernetClient client = server.available();
    while (client.available() > 0 && newData == false) {
        rc = client.read();

        if (recvInProgress == true) {
            if (rc != endMarker) {
                receivedChars[ndx] = rc;
                ndx++;
                if (ndx >= numChars) {
                    ndx = numChars - 1;
                }
            }
            else {
                receivedChars[ndx] = '\0'; // terminate the string
                recvInProgress = false;
                ndx = 0;
                newData = true;
            }
        }

        else if (rc == startMarker) {
            recvInProgress = true;
        }
    }
}

float mapfloat(float x, float in_min, float in_max, float out_min, float out_max)
{
 return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
}
// Function to return a substring defined by a delimiter at an index
char* subStr (char* str, char *delim, int index) {
  char *act, *sub, *ptr;
  static char copy[MAX_STRING_LEN];
  int i;

  // Since strtok consumes the first arg, make a copy
  strcpy(copy, str);

  for (i = 1, act = copy; i <= index; i++, act = NULL) {
     //Serial.print(".");
     sub = strtok_r(act, delim, &ptr);
     if (sub == NULL) break;
  }
  return sub;

}

1 个答案:

答案 0 :(得分:0)

First thing to do is try to increase the stack depth of your Tasks. You're currently using 128, 128 and 512. You can use "StackHighWaterMark" to get the info about the amount of stack space remaining. Try to use this information to "calibrate" the depth of your task. I recommend using at least 40% of free space.