Задачи Arduino uno freertos перестали работать

Я работаю над проектом с Arduino UNO, я использую freertos для многозадачности, у меня две задачи: 1-TaskLedBlink. и 2-TaskSerialP6008. первая задача. используется для двукратного мигания светодиода через каждый заданный период времени, а второй используется для получения кадра из последовательного порта и последующей его отправки. кадр должен начинаться с 0x02 и заканчиваться на 0x0D. при получении 0x02 я начинаю добавлять входящие байты в массив с именем asciiFrame до тех пор, пока не будет получен 0x0D, после чего я отправляю кадр отверстия . До этого момента программа работала нормально. затем я решил добавить блок кода, который отвечает за декодирование asciiFrame, результат сохраняется в массиве под названием binaryFrame. Вот тут программа начала странно себя вести. светодиод перестает мигать, иногда горит, иногда не горит, последовательные данные теряются (не принимаются). в худшем случае программа больше не отвечает, пока я не перезагружу ардуино. Когда я начал искать решение проблемы, я обнаружил, что когда я удаляю эту строку binaryFrame [m] = (asciiFrame [k] & 15) + ((asciiFrame [k + 1] & 15) ‹‹ 4); программа работает нормально. Помогите пожалуйста решить эту проблему ... вот код

#include <Arduino_FreeRTOS.h>
#include <semphr.h>  // add the FreeRTOS functions for Semaphores (or Flags).

byte inByte = 0;                    // incoming serial byte
bool startByte = false;
byte asciiFrame[18];                //array to save ascci frame p6008 02 xx xx....0d max 18 bytes including 0x02 and 0x0D
byte binaryFrame[8];                //array to save binary frame p6008 (max 7 bytes + CHECKSUM)
byte i=0;                           //index used to select case in array
byte j=0;                             //index used to select byte in array to send it over serial

byte k=0;                             //index used to convert from ascii to binary
byte m=0;                             //to save data in binary frame
bool asciiFrameComplete = false;    //to indicate that a complete frame(ascii mode) hs been recieved
bool binaryFrameComplete = false;
bool asciiP6008Enabled = true;      //true(ascii mode) false(binary mode)

// Declare a mutex Semaphore Handle which we will use to manage the Serial Port.
// It will be used to ensure only only one Task is accessing this resource at any time.
SemaphoreHandle_t xSerialSemaphore;

// define two Tasks for DigitalRead & AnalogRead
void TaskLedBlink( void *pvParameters );
void TaskSerialP6008( void *pvParameters );

// the setup function runs once when you press reset or power the board
void setup() {

  // initialize serial communication at 9600 bits per second:
  pinMode(13, OUTPUT);
  Serial.begin(9600);
  // Semaphores are useful to stop a Task proceeding, where it should be paused to wait,
  // because it is sharing a resource, such as the Serial port.
  // Semaphores should only be used whilst the scheduler is running, but we can set it up here.
  if ( xSerialSemaphore == NULL )  // Check to confirm that the Serial Semaphore has not already been created.
  {
    xSerialSemaphore = xSemaphoreCreateMutex();  // Create a mutex semaphore we will use to manage the Serial Port
    if ( ( xSerialSemaphore ) != NULL )
      xSemaphoreGive( ( xSerialSemaphore ) );  // Make the Serial Port available for use, by "Giving" the Semaphore.
  }

  // Now set up two Tasks to run independently.
  xTaskCreate(
    TaskLedBlink
    ,  (const portCHAR *)"LedBlink"  // A name just for humans
    ,  128  // This stack size can be checked & adjusted by reading the Stack Highwater
    ,  NULL
    ,  2  // Priority, with 1 being the highest, and 4 being the lowest.
    ,  NULL );

  xTaskCreate(
    TaskSerialP6008
    ,  (const portCHAR *) "AnalogRead"
    ,  256  // Stack size
    ,  NULL
    ,  1  // Priority
    ,  NULL );

  // Now the Task scheduler, which takes over control of scheduling individual Tasks, is automatically started.
  //vTaskStartScheduler();
}

void loop(){
  // Empty. Things are done in Tasks.
}

/*--------------------------------------------------*/
/*---------------------- Tasks ---------------------*/
/*--------------------------------------------------*/

void TaskLedBlink( void *pvParameters __attribute__((unused)) )  // This is a Task.
{
  for (;;) // A Task shall never return or exit.
  {
      digitalWrite(13, HIGH);
      vTaskDelay(1);
      digitalWrite(13, LOW);
      vTaskDelay(6);
      digitalWrite(13, HIGH);
      vTaskDelay(1);
      digitalWrite(13, LOW);
      vTaskDelay(17);
   }
}


void TaskSerialP6008( void *pvParameters __attribute__((unused)) )  // This is a Task.
{
  for (;;)
  {
    // read the input on analog pin 0:
    //int sensorValue = analogRead(A0);
    if (Serial.available()>0)
    {
      inByte = Serial.read();
      if ((inByte == 2 || startByte)&&asciiP6008Enabled)                     //if 2 was received or already has been(startByte), and ascii mode is enabled
      {
        startByte = true;                               //start byte came
        asciiFrame[i] = inByte;                           //save bytes in frame array
        i++;                                            //increment to the next case in frame array
        if (inByte == 13)                               //end byte came
        {
          asciiFrameComplete = true;
          startByte = false;
          i=0;
          if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
          {
            for (j=0;j<18&&asciiFrame[j]!=0;j++)                  //send frame back
              Serial.write(asciiFrame[j]);
            memset(asciiFrame, 0, sizeof(asciiFrame));            //then clear it
          }
          xSemaphoreGive( xSerialSemaphore );                     // Now free or "Give" the Serial Port for others.
          for(k=1 ; k<sizeof(asciiFrame) ; k++)
          {
            if(asciiFrame[k]==13)
            {
              binaryFrameComplete=true;
              m=0;
              break;
            } 
            if(k%2!=0)
            {
              binaryFrame[m]=(asciiFrame[k]&15)+((asciiFrame[k+1]&15)<<4);
              m++;
            }             
          }
//          if ( xSemaphoreTake( xSerialSemaphore, ( TickType_t ) 5 ) == pdTRUE )
//          {
//            for (j=0;j<8;j++)                  //send frame back
//              Serial.write(binaryFrame[j]);
//            memset(asciiFrame, 0, sizeof(asciiFrame));            //then clear it
//            memset(binaryFrame, 0, sizeof(asciiFrame));            //then clear it
//          }
//          xSemaphoreGive( xSerialSemaphore );                     // Now free or "Give" the Serial Port for others.
        }
        if (i==sizeof(asciiFrame))                                                 //if array is full ecrase received data, frame length should not exceed 18 bytes
        {
          memset(asciiFrame, 0, sizeof(asciiFrame));              //clear array
          i=0;                                                    //init i
          startByte = false;
        }
      }
      else if(!asciiP6008Enabled)                                 //binary enabled
      {
        Serial.println("binary enabled");
      }
    }
    //vTaskDelay(1);  // one tick delay (15ms) in between reads for stability
  }
}

person Madon    schedule 07.08.2016    source источник


Ответы (2)


Я думаю, проблема заключалась в объявлении переменных как глобальных, я объявил их внутри задачи, и они работают очень хорошо.

person Madon    schedule 07.08.2016

кажется, вы приближаетесь к пределам RAM ...
или ваш m превышает пределы binaryFrame ...

Быстро посмотрев, я оцениваю, что m составляет примерно половину k, и вы определили

byte asciiFrame[18];  
byte binaryFrame[8]; 

а если нет 0x0D, вы не сбросите m ...

С локальными переменными вы получаете другое поведение при подделке памяти.

person datafiddler    schedule 08.08.2016
comment
если вы присмотритесь, я не начну работать с m, пока не будет получено 0x0D, поэтому m всегда сбрасывается. но проблема не в этом - person Madon; 09.08.2016
comment
Я не думаю, что сброс ** m ** помешает переключению или остановке задач. Говоря об оперативной памяти, при компиляции скетча с помощью Arduino IDE говорится, что Sketch использует 10 080 байт (31%) пространства для хранения программ. Максимум 32 256 байт. Глобальные переменные используют 422 байта (20%) динамической памяти, оставляя 1626 байтов для локальных переменных. Максимум 2048 байт. - person Madon; 09.08.2016
comment
При более внимательном рассмотрении я согласен ...;) ‹br› Не будем надеяться, что Arduino_FreeRTOS использует внешнюю память. Вы, конечно, знаете, что просто для того, чтобы моргать независимо, вам не нужна такая сложная многозадачность. а просто BlinkWithoutDelay. - person datafiddler; 09.08.2016
comment
да, для этого мне не нужна многозадачность, но я добавлю больше задач в будущем, я просто иду шаг за шагом .. - person Madon; 09.08.2016