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

using global value in FreeRTOS inside a Timer ISR

本文关键字:全局 FreeRTOS Timer ISR      更新时间:2023-10-16

使用:

  • 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 LOOPn");};
}
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。

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