在Timer ISR中使用FreeRTOS中的全局值

时间:2015-06-30 12:46:30

标签: c++ arduino arduino-ide freertos isr

使用:

  • Arduino Mega 2560
  • Arduino IDE
  • 定时器2

代码:

#include "FreeRTOS_AVR.h"
#include "basic_io_avr.h"

/*** 
* HITEC servo ranges from 0.9 to 2.4 ms
* values in usec 
***/

const int firstPulse = 0.7 * 1000;
const int centerPulse = 1.5 * 1000;
const int lastPulse = 2.4 * 1000;
const int cycleLength = 20 * 1000;
const int degree = (lastPulse - firstPulse) / 180 * 1.0; //9.44
const int SERVO_PIN = 29;
const int ULTRASOON_PIN = 43;

void servoTask(void* p);
void ultrasoonTask(void* p);
void receiveTask(void* p);

QueueHandle_t xQueueDistance, xQueueDegrees;

void setup() {
    // put your setup code here, to run once:
    cli();
    USART_init();
    Timer2_init();
    Timer3_init();
    sei();
    pinMode(SERVO_PIN, OUTPUT);

    xQueueDistance = xQueueCreate(1, sizeof(uint8_t));
    xQueueDegrees = xQueueCreate(1, sizeof(int));

    xTaskCreate(servoTask, "Servo task", 200, NULL, 1, NULL);
    xTaskCreate(ultrasoonTask, "Ultrasoon task", 200, NULL, 1, NULL);
    xTaskCreate(receiveTask, "Receive task", 200, NULL, 1, NULL); 
    vTaskStartScheduler();

    while(1) {writeString("DEAD LOOP\n");};
}

volatile int pulse=0;
ISR (TIMER2_COMPA_vect) {
  static int x=0;

  x++;
  if(x%2) {
   //vPrintStringAndNumber("ServoPos= ", pulse);
   //moveServo(pulse);
  }
}

ISR( TIMER3_COMPA_vect){}

void ultrasoonTask(void* p) {
  uint8_t ultrasoonValue; 
  portBASE_TYPE xStatus;

  while(1) {
    ultrasoonValue = ping();
    //vPrintStringAndNumber("Ping= ", ultrasoonValue);
    xQueueSendToBack(xQueueDistance, &ultrasoonValue, 0);
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

void servoTask(void *p) { 
  uint8_t inValue;
  int m_degrees;
  portBASE_TYPE xStatus;

  while(1) {
    xStatus = xQueueReceive(xQueueDistance, &inValue, 0);
    if(xStatus == pdPASS) {
      //vPrintStringAndNumber("ServoRead= ", inValue);
      m_degrees = changeServoPosition((int)inValue);
      //vPrintStringAndNumber("ServoPos= ", m_degrees);
      xQueueSendToBack(xQueueDegrees, &m_degrees, 0);
    }
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

void receiveTask(void* p) {
  int m_degrees; 
  portBASE_TYPE xStatus;

  while(1) {
    xStatus = xQueueReceive(xQueueDegrees, &m_degrees, 0);
    if(xStatus == pdPASS) {
      //vPrintStringAndNumber("ServoPos= ", m_degrees);
      pulse = m_degrees;
      //vPrintStringAndNumber("ServoPos= ", pulse);
    }
    vTaskDelay(500 / portTICK_PERIOD_MS);
  }
}

long ping() {
  pinMode(ULTRASOON_PIN, OUTPUT); // Switch signalpin to output
  digitalWrite(ULTRASOON_PIN, LOW); // Send low pulse
  delayMicroseconds(2); // Wait for 2 microseconds
  digitalWrite(ULTRASOON_PIN, HIGH); // Send high pulse
  delayMicroseconds(5); // Wait for 5 microseconds
  digitalWrite(ULTRASOON_PIN, LOW); // Holdoff

  pinMode(ULTRASOON_PIN, INPUT); // Switch signalpin to input  
  digitalWrite(ULTRASOON_PIN, HIGH); // Turn on pullup resistor

  long temp = pulseIn(ULTRASOON_PIN, HIGH); //Listen for echo

  //convert to CM: sound speed is 340 m/s. 29microseconds/cm. 
  //                 ping signal travels out and back, take half distance travelled.
  return temp / 29 / 2;
}

void moveServo(int p) {
    digitalWrite(SERVO_PIN, HIGH);
    delayMicroseconds(p);
    digitalWrite(SERVO_PIN, LOW);
    delayMicroseconds(cycleLength - p);
}

int changeServoPosition(int in) {
  int p = in * degree + firstPulse;
  if(p < firstPulse) {
    p = firstPulse;
  } else if(p > lastPulse) {
    p = lastPulse;
  }
  return p;
}

void Timer2_init() {
  TCCR2A = 0;
  TCCR2B = 0;
  //  CTC Mode
  TCCR2B |= (1<<WGM22);
  //
  //  Prescaler mode: 1024
  TCCR2B |= (1<<CS22) | (1<<CS20);

  TIMSK2 = (1<<OCIE2A); //interrupt enable
  TCNT2 = 0;
  OCR2A = 156;
}

/**
  *  Timer3 is 16 bits, max tellen tot 2^16= 65535 
  *  OCR3A = FCPU / prescaler / frequentie
  *  FCPU = 16000000, Prescaler = 1024, FCPU/Prescaler = 15625
  *  Frequentie = 1/(time in seconds), 20ms = 0.02s, 1/s = 50Hz
  *  OCR3A = 312.5
  **/

void Timer3_init() {
  TCCR3A = 0;
  TCCR3B = 0;

  //  CTC Mode
  TCCR3B |= (1<<WGM32);  
  //  Prescaler mode: 1024
  TCCR3B |= (1<<CS32) | (1<<CS30);

  TIMSK3 = (1<<OCIE3A); //interrupt enable
  TCNT3 = 0;
  OCR3A = 313;
}

void USART_init() {
  /* Set baud rate */
  UBRR0H = 0;//UBRR0H = (unsigned char)(ubrr>>8);
  UBRR0L = 16000000/16/9600-1; //FCPU en BAUD. UBRR0L = (unsigned char)ubrr;
  UCSR0A = 0;
  /* Enable receiver and transmitter */
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);
  /* Set frame format: 8data, 2stop bit */
  UCSR0C = (1<<USBS0)|(3<<UCSZ00);  // URSEL: Register select, om op UCSRC te schrijven
                // USBS:  op 2stop bit zetten
                // UCSZ0: 3 erop schuiven, hierdoor UCSZ0 en UCSZ1 op 1 geset. 8 bit
}

void writeChar(char data){
  /* Wait for empty transmit buffer */
  while ( !( UCSR0A & (1<<UDRE0)) );    // UDRE is een flag die wacht totdat data in de buffer gezet mag worden.
    /* Put data into buffer, sends the data */
    UDR0 = (uint8_t)data;
}

void writeString(char* str){
  while(*str)
    writeChar(*str++);
}

void writeInteger(int16_t number, uint8_t base){
  char nmb[3];
  itoa(number, nmb, base);
  writeString(nmb);
}

char readChar(){
  /* Wait for data to be received */
  while ( !(UCSR0A & (1<<RXC0)) );      // RXC is een flag die wacht totdat er data bij de buffer van de ontvanger is.
  /* Get and return received data from buffer */
    return (char)UDR0;
}

void loop(){
}

问题:

volatile int pulse是我想在Timer2的ISR中使用的全局变量。 使用receiveTask,我从队列中获取值并将其设置为脉冲值。

但每次脉冲值为0时。

1 个答案:

答案 0 :(得分:0)

您使用xQueueReceive()函数的方式看起来是正确的,所以假设if(xStatus == pdPASS)测试实际上正在通过,那么我会认为问题实际上是您将值发布到队列,而不是您接收值的位置。但是,您没有显示该代码。您确定要实际写入队列,并且写入队列的值不总是0吗?