2015-06-30 8 views
0

Использование:используя глобальное значение в FreeRTOS внутри таймера ISR

  • Arduino Mega 2560
  • Arduino IDE
  • Timer2

Код:

#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 - глобальная переменная, которую я хочу использовать в ISR Timer2. С receiveTask я получаю значение из очереди и задаю его как значение импульса.

Но каждый раз, когда значение импульса равно 0.

+0

Вы уверены, что переменная 'pulse' фактически обновлена ​​в функции' receiveTask'? –

+0

Да. Если я раскомментирую vPrintStringAndNumber («ServoPos =», m_degrees); он показывает числа. – HieiFCB

ответ

0

, как вы используете функцию xQueueReceive() выглядит правильно, поэтому если предположить, что если (== хСтатус pdPASS) тест на самом деле проходит, то я бы предположить, что проблема в том, что вы отправляете значение в очередь, а не там, где вы получаете значение. Однако вы не показываете этот код. Вы уверены, что на самом деле вы пишете в очередь, и что значение, записываемое в очередь, не всегда равно 0?

+0

Да. Если я раскомментирую vPrintStringAndNumber («ServoPos =», m_degrees); он показывает числа. – HieiFCB

+0

Я редактировал сообщение с полным кодом сейчас. – HieiFCB