2017-11-03 27 views
1

우리는 2 개의 센서로부터 데이터를 판독해야합니다. 온도 센서와 광 센서. Atmel 328P 프로세서와 함께 arduino uno를 사용하고 있습니다. 그것은 arduino Sketch가 아닌 일반 C로 코딩되어야합니다. 목표는 USB를 통해 센서에서 판독 값을 PC로 전송하는 것입니다. 이 코드입니다 :두 센서를 동시에 사용하면 잘못된 데이터가 PC로 전송되는 이유는 무엇입니까?

을 main.c :

#include "AVR_TTC_scheduler.h" 
#include <avr/io.h> 
#include <avr/delay.h> 
#include <avr/interrupt.h> 
#include <stdlib.h> 
#include <avr/sfr_defs.h> 
#include <util/delay.h> 
#define F_CPU 16E6 
#define UBBRVAL 51 
#include "CFile1.c" 
#include "CFile2.c" 
// The array of tasks 
sTask SCH_tasks_G[SCH_MAX_TASKS]; 


/*------------------------------------------------------------------*- 

    SCH_Dispatch_Tasks() 

    This is the 'dispatcher' function. When a task (function) 
    is due to run, SCH_Dispatch_Tasks() will run it. 
    This function must be called (repeatedly) from the main loop. 

-*------------------------------------------------------------------*/ 

void SCH_Dispatch_Tasks(void) 
{ 
    unsigned char Index; 

    // Dispatches (runs) the next task (if one is ready) 
    for(Index = 0; Index < SCH_MAX_TASKS; Index++) 
    { 
     if((SCH_tasks_G[Index].RunMe > 0) && (SCH_tasks_G[Index].pTask != 0)) 
     { 
     (*SCH_tasks_G[Index].pTask)(); // Run the task 
     SCH_tasks_G[Index].RunMe -= 1; // Reset/reduce RunMe flag 

     // Periodic tasks will automatically run again 
     // - if this is a 'one shot' task, remove it from the array 
     if(SCH_tasks_G[Index].Period == 0) 
     { 
      SCH_Delete_Task(Index); 
     } 
     } 
    } 
} 

/*------------------------------------------------------------------*- 

    SCH_Add_Task() 

    Causes a task (function) to be executed at regular intervals 
    or after a user-defined delay 

    pFunction - The name of the function which is to be scheduled. 
       NOTE: All scheduled functions must be 'void, void' - 
       that is, they must take no parameters, and have 
       a void return type. 

    DELAY  - The interval (TICKS) before the task is first executed 

    PERIOD - If 'PERIOD' is 0, the function is only called once, 
       at the time determined by 'DELAY'. If PERIOD is non-zero, 
       then the function is called repeatedly at an interval 
       determined by the value of PERIOD (see below for examples 
       which should help clarify this). 


    RETURN VALUE: 

    Returns the position in the task array at which the task has been 
    added. If the return value is SCH_MAX_TASKS then the task could 
    not be added to the array (there was insufficient space). If the 
    return value is < SCH_MAX_TASKS, then the task was added 
    successfully. 

    Note: this return value may be required, if a task is 
    to be subsequently deleted - see SCH_Delete_Task(). 

    EXAMPLES: 

    Task_ID = SCH_Add_Task(Do_X,1000,0); 
    Causes the function Do_X() to be executed once after 1000 sch ticks.    

    Task_ID = SCH_Add_Task(Do_X,0,1000); 
    Causes the function Do_X() to be executed regularly, every 1000 sch ticks.    

    Task_ID = SCH_Add_Task(Do_X,300,1000); 
    Causes the function Do_X() to be executed regularly, every 1000 ticks. 
    Task will be first executed at T = 300 ticks, then 1300, 2300, etc.    

-*------------------------------------------------------------------*/ 

unsigned char SCH_Add_Task(void (*pFunction)(), const unsigned int DELAY, const unsigned int PERIOD) 
{ 
    unsigned char Index = 0; 

    // First find a gap in the array (if there is one) 
    while((SCH_tasks_G[Index].pTask != 0) && (Index < SCH_MAX_TASKS)) 
    { 
     Index++; 
    } 

    // Have we reached the end of the list? 
    if(Index == SCH_MAX_TASKS) 
    { 
     // Task list is full, return an error code 
     return SCH_MAX_TASKS; 
    } 

    // If we're here, there is a space in the task array 
    SCH_tasks_G[Index].pTask = pFunction; 
    SCH_tasks_G[Index].Delay =DELAY; 
    SCH_tasks_G[Index].Period = PERIOD; 
    SCH_tasks_G[Index].RunMe = 0; 

    // return position of task (to allow later deletion) 
    return Index; 
} 

/*------------------------------------------------------------------*- 

    SCH_Delete_Task() 

    Removes a task from the scheduler. Note that this does 
    *not* delete the associated function from memory: 
    it simply means that it is no longer called by the scheduler. 

    TASK_INDEX - The task index. Provided by SCH_Add_Task(). 

    RETURN VALUE: RETURN_ERROR or RETURN_NORMAL 

-*------------------------------------------------------------------*/ 

unsigned char SCH_Delete_Task(const unsigned char TASK_INDEX) 
{ 
    // Return_code can be used for error reporting, NOT USED HERE THOUGH! 
    unsigned char Return_code = 0; 

    SCH_tasks_G[TASK_INDEX].pTask = 0; 
    SCH_tasks_G[TASK_INDEX].Delay = 0; 
    SCH_tasks_G[TASK_INDEX].Period = 0; 
    SCH_tasks_G[TASK_INDEX].RunMe = 0; 

    return Return_code; 
} 

/*------------------------------------------------------------------*- 

    SCH_Init_T1() 

    Scheduler initialisation function. Prepares scheduler 
    data structures and sets up timer interrupts at required rate. 
    You must call this function before using the scheduler. 

-*------------------------------------------------------------------*/ 

void SCH_Init_T1(void) 
{ 
    unsigned char i; 

    for(i = 0; i < SCH_MAX_TASKS; i++) 
    { 
     SCH_Delete_Task(i); 
    } 

    // Set up Timer 1 
    // Values for 1ms and 10ms ticks are provided for various crystals 

    // Hier moet de timer periode worden aangepast ....! 
    OCR1A = (uint16_t)625;    // 10ms = (256/16.000.000) * 625 
    TCCR1B = (1 << CS12) | (1 << WGM12); // prescale op 64, top counter = value OCR1A (CTC mode) 
    TIMSK1 = 1 << OCIE1A;    // Timer 1 Output Compare A Match Interrupt Enable 
} 

/*------------------------------------------------------------------*- 

    SCH_Start() 

    Starts the scheduler, by enabling interrupts. 

    NOTE: Usually called after all regular tasks are added, 
    to keep the tasks synchronised. 

    NOTE: ONLY THE SCHEDULER INTERRUPT SHOULD BE ENABLED!!! 

-*------------------------------------------------------------------*/ 

void SCH_Start(void) 
{ 
     sei(); 
} 

/*------------------------------------------------------------------*- 

    SCH_Update 

    This is the scheduler ISR. It is called at a rate 
    determined by the timer settings in SCH_Init_T1(). 

-*------------------------------------------------------------------*/ 

ISR(TIMER1_COMPA_vect) 
{ 
    unsigned char Index; 
    for(Index = 0; Index < SCH_MAX_TASKS; Index++) 
    { 
     // Check if there is a task at this location 
     if(SCH_tasks_G[Index].pTask) 
     { 
     if(SCH_tasks_G[Index].Delay == 0) 
     { 
      // The task is due to run, Inc. the 'RunMe' flag 
      SCH_tasks_G[Index].RunMe += 1; 

      if(SCH_tasks_G[Index].Period) 
      { 
       // Schedule periodic tasks to run again 
       SCH_tasks_G[Index].Delay = SCH_tasks_G[Index].Period; 
       SCH_tasks_G[Index].Delay -= 1; 
      } 
     } 
     else 
     { 
      // Not yet ready to run: just decrement the delay 
      SCH_tasks_G[Index].Delay -= 1; 
     } 
     } 
    } 
} 

// ------------------------------------------------------------------ 


int main() 
{ 
    DDRB = 0xff; 
    DDRD = 0xff; 
    PORTD = 0xff; 
    setup(); 
    setup2(); 
    SCH_Init_T1(); 

    SCH_Add_Task(commando, 0, 1); 
    SCH_Add_Task(send_lux, 0, 100); 
    SCH_Add_Task(send_temp, 0, 100); 

    SCH_Start(); 

    while (1) { 
     SCH_Dispatch_Tasks(); 
    } 
    return 0; 
} 

CFile1.C :

void setup() 
{ 
    UBRR0H = 0; 
    UBRR0L = UBBRVAL; 
    UCSR0A = 0; 
    UCSR0B = _BV(TXEN0) | _BV(RXEN0); 
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); 

    ADMUX=(1<<REFS0);// For Aref=AVcc; 
    ADCSRA=(1<<ADEN)|(1<<ADPS0); 
} 


uint16_t read(uint8_t ch) { 
    //Select ADC Channel ch must be 0-7 
    //ch=ch&0b00000111; 
    ADMUX|=ch; 

    //Start Single conversion 

    ADCSRA|=(1<<ADSC); 

    //Wait for conversion to complete 
    while(!(ADCSRA & (1<<ADIF))); 

    //Clear ADIF by writing one to it 
    ADCSRA|=(1<<ADIF); 

    return(ADC); 
} 

void transmit(uint8_t lux) 
{ 
    loop_until_bit_is_set(UCSR0A, UDRE0); 
    UDR0 = lux; 
} 

void send_lux() 
{ 
    float lux; 
    lux = read(0b0000); 
    lux = lux/10; 
    transmit(lux); 


    } 

void commando() 
{ 
    if bit_is_set(UCSR0A,RXC0) 
    { 
     PORTB = UDR0; 
    } 
} 

CFile2.c :

void setup2() 
{ 
    UBRR0H = 0; 
    UBRR0L = UBBRVAL; 
    UCSR0A = 0; 
    UCSR0B = _BV(TXEN0) | _BV(RXEN0); 
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); 

    ADMUX=(1<<REFS0);// For Aref=AVcc; 
    ADCSRA=(1<<ADEN)|(1<<ADPS0); 
} 


uint16_t read2(uint8_t ch) { 
    //Select ADC Channel ch must be 0-7 
    //ch=ch&0b00000111; 
    ADMUX|=ch; 

    //Start Single conversion 

    ADCSRA|=(1<<ADSC); 

    //Wait for conversion to complete 
    while(!(ADCSRA & (1<<ADIF))); 

    //Clear ADIF by writing one to it 
    ADCSRA|=(1<<ADIF); 

    return(ADC); 
} 

void transmit2(uint8_t temp) 
{ 
    loop_until_bit_is_set(UCSR0A, UDRE0); 
    UDR0 = temp; 
} 

void send_temp() 
{ 
    float temp; 
    temp = read2(0b0001); 
    temp = (temp * 5)/1024; 
    temp = ((temp -0.5) *100); 
    transmit2(temp); 

} 

편집 :

#include "AVR_TTC_scheduler.h" 
#include <avr/io.h> 
#include <avr/delay.h> 
#include <avr/interrupt.h> 
#include <stdlib.h> 
#include <avr/sfr_defs.h> 
#include <util/delay.h> 
//#define F_CPU 16E6 
#define UBBRVAL 51 
//#include "CFile1.c" 
//#include "CFile2.c" 
// The array of tasks 
sTask SCH_tasks_G[SCH_MAX_TASKS]; 


/*------------------------------------------------------------------*- 

    SCH_Dispatch_Tasks() 

    This is the 'dispatcher' function. When a task (function) 
    is due to run, SCH_Dispatch_Tasks() will run it. 
    This function must be called (repeatedly) from the main loop. 

-*------------------------------------------------------------------*/ 

void SCH_Dispatch_Tasks(void) 
{ 
    unsigned char Index; 

    // Dispatches (runs) the next task (if one is ready) 
    for(Index = 0; Index < SCH_MAX_TASKS; Index++) 
    { 
     if((SCH_tasks_G[Index].RunMe > 0) && (SCH_tasks_G[Index].pTask != 0)) 
     { 
     (*SCH_tasks_G[Index].pTask)(); // Run the task 
     SCH_tasks_G[Index].RunMe -= 1; // Reset/reduce RunMe flag 

     // Periodic tasks will automatically run again 
     // - if this is a 'one shot' task, remove it from the array 
     if(SCH_tasks_G[Index].Period == 0) 
     { 
      SCH_Delete_Task(Index); 
     } 
     } 
    } 
} 

/*------------------------------------------------------------------*- 

    SCH_Add_Task() 

    Causes a task (function) to be executed at regular intervals 
    or after a user-defined delay 

    pFunction - The name of the function which is to be scheduled. 
       NOTE: All scheduled functions must be 'void, void' - 
       that is, they must take no parameters, and have 
       a void return type. 

    DELAY  - The interval (TICKS) before the task is first executed 

    PERIOD - If 'PERIOD' is 0, the function is only called once, 
       at the time determined by 'DELAY'. If PERIOD is non-zero, 
       then the function is called repeatedly at an interval 
       determined by the value of PERIOD (see below for examples 
       which should help clarify this). 


    RETURN VALUE: 

    Returns the position in the task array at which the task has been 
    added. If the return value is SCH_MAX_TASKS then the task could 
    not be added to the array (there was insufficient space). If the 
    return value is < SCH_MAX_TASKS, then the task was added 
    successfully. 

    Note: this return value may be required, if a task is 
    to be subsequently deleted - see SCH_Delete_Task(). 

    EXAMPLES: 

    Task_ID = SCH_Add_Task(Do_X,1000,0); 
    Causes the function Do_X() to be executed once after 1000 sch ticks.    

    Task_ID = SCH_Add_Task(Do_X,0,1000); 
    Causes the function Do_X() to be executed regularly, every 1000 sch ticks.    

    Task_ID = SCH_Add_Task(Do_X,300,1000); 
    Causes the function Do_X() to be executed regularly, every 1000 ticks. 
    Task will be first executed at T = 300 ticks, then 1300, 2300, etc.    

-*------------------------------------------------------------------*/ 

unsigned char SCH_Add_Task(void (*pFunction)(), const unsigned int DELAY, const unsigned int PERIOD) 
{ 
    unsigned char Index = 0; 

    // First find a gap in the array (if there is one) 
    while((SCH_tasks_G[Index].pTask != 0) && (Index < SCH_MAX_TASKS)) 
    { 
     Index++; 
    } 

    // Have we reached the end of the list? 
    if(Index == SCH_MAX_TASKS) 
    { 
     // Task list is full, return an error code 
     return SCH_MAX_TASKS; 
    } 

    // If we're here, there is a space in the task array 
    SCH_tasks_G[Index].pTask = pFunction; 
    SCH_tasks_G[Index].Delay =DELAY; 
    SCH_tasks_G[Index].Period = PERIOD; 
    SCH_tasks_G[Index].RunMe = 0; 

    // return position of task (to allow later deletion) 
    return Index; 
} 

/*------------------------------------------------------------------*- 

    SCH_Delete_Task() 

    Removes a task from the scheduler. Note that this does 
    *not* delete the associated function from memory: 
    it simply means that it is no longer called by the scheduler. 

    TASK_INDEX - The task index. Provided by SCH_Add_Task(). 

    RETURN VALUE: RETURN_ERROR or RETURN_NORMAL 

-*------------------------------------------------------------------*/ 

unsigned char SCH_Delete_Task(const unsigned char TASK_INDEX) 
{ 
    // Return_code can be used for error reporting, NOT USED HERE THOUGH! 
    unsigned char Return_code = 0; 

    SCH_tasks_G[TASK_INDEX].pTask = 0; 
    SCH_tasks_G[TASK_INDEX].Delay = 0; 
    SCH_tasks_G[TASK_INDEX].Period = 0; 
    SCH_tasks_G[TASK_INDEX].RunMe = 0; 

    return Return_code; 
} 

/*------------------------------------------------------------------*- 

    SCH_Init_T1() 

    Scheduler initialisation function. Prepares scheduler 
    data structures and sets up timer interrupts at required rate. 
    You must call this function before using the scheduler. 

-*------------------------------------------------------------------*/ 

void SCH_Init_T1(void) 
{ 
    unsigned char i; 

    for(i = 0; i < SCH_MAX_TASKS; i++) 
    { 
     SCH_Delete_Task(i); 
    } 

    // Set up Timer 1 
    // Values for 1ms and 10ms ticks are provided for various crystals 

    // Hier moet de timer periode worden aangepast ....! 
    OCR1A = (uint16_t)625;    // 10ms = (256/16.000.000) * 625 
    TCCR1B = (1 << CS12) | (1 << WGM12); // prescale op 64, top counter = value OCR1A (CTC mode) 
    TIMSK1 = 1 << OCIE1A;    // Timer 1 Output Compare A Match Interrupt Enable 
} 

/*------------------------------------------------------------------*- 

    SCH_Start() 

    Starts the scheduler, by enabling interrupts. 

    NOTE: Usually called after all regular tasks are added, 
    to keep the tasks synchronised. 

    NOTE: ONLY THE SCHEDULER INTERRUPT SHOULD BE ENABLED!!! 

-*------------------------------------------------------------------*/ 

void SCH_Start(void) 
{ 
     sei(); 
} 

/*------------------------------------------------------------------*- 

    SCH_Update 

    This is the scheduler ISR. It is called at a rate 
    determined by the timer settings in SCH_Init_T1(). 

-*------------------------------------------------------------------*/ 

ISR(TIMER1_COMPA_vect) 
{ 
    unsigned char Index; 
    for(Index = 0; Index < SCH_MAX_TASKS; Index++) 
    { 
     // Check if there is a task at this location 
     if(SCH_tasks_G[Index].pTask) 
     { 
     if(SCH_tasks_G[Index].Delay == 0) 
     { 
      // The task is due to run, Inc. the 'RunMe' flag 
      SCH_tasks_G[Index].RunMe += 1; 

      if(SCH_tasks_G[Index].Period) 
      { 
       // Schedule periodic tasks to run again 
       SCH_tasks_G[Index].Delay = SCH_tasks_G[Index].Period; 
       SCH_tasks_G[Index].Delay -= 1; 
      } 
     } 
     else 
     { 
      // Not yet ready to run: just decrement the delay 
      SCH_tasks_G[Index].Delay -= 1; 
     } 
     } 
    } 
} 

// ------------------------------------------------------------------ 
void setup2() 
{ 
    UBRR0H = 0; 
    UBRR0L = UBBRVAL; 
    UCSR0A = 0; 
    UCSR0B = _BV(TXEN0) | _BV(RXEN0); 
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); 

    ADMUX=(1<<REFS0);// For Aref=AVcc; 
    ADCSRA=(1<<ADEN)|(1<<ADPS0); 
} 


uint16_t read2(uint8_t ch) { 
    //Select ADC Channel ch must be 0-7 
    //ch=ch&0b00000111; 
    ADMUX|=ch; 

    //Start Single conversion 

    ADCSRA|=(1<<ADSC); 

    //Wait for conversion to complete 
    while(!(ADCSRA & (1<<ADIF))); 

    //Clear ADIF by writing one to it 
    ADCSRA|=(1<<ADIF); 

    return(ADC); 
} 

void transmit2(uint8_t send) 
{ 
    loop_until_bit_is_set(UCSR0A, UDRE0); 
    UDR0 = send; 
} 

void send_temp() 
{ 
    float temp; 
    temp = read2(0b0001); 
    temp = (temp * 5)/1024; 
    temp = ((temp -0.5) *100); 
    transmit2(temp);_delay_ms(10); 

} 


void send_lux() 
{ 
    float lux; 
    lux = read2(0b0000); 
    lux = lux/10; 
    transmit2(lux);_delay_ms(10); 

} 

void commando() 
{ 
    if bit_is_set(UCSR0A,RXC0) 
    { 
     PORTB = UDR0; 
    } 
} 


int main() 
{ 
    DDRB = 0xff; 
    DDRD = 0xff; 
    PORTD = 0xff; 
    //setup(); 
    setup2(); 
    SCH_Init_T1(); 

    SCH_Add_Task(commando, 0, 500); 
    SCH_Add_Task(send_lux, 0, 1000); 
    SCH_Add_Task(send_temp, 500, 1000); 

    SCH_Start(); 

    while (1) { 
     SCH_Dispatch_Tasks(); 
    } 
    return 0; 

} 
+0

스케줄러를 사용해야합니까? 너가 복잡하게 끝난 것 같아. 특정 간격으로 보내야하는 경우 타이머를 사용할 수 있습니다. – DigitalNinja

+0

어떤 센서가 잘못된 데이터를 보내고 있습니까? CFile1.c와 CFile2.c가 무엇인지 설명 할 수 있습니까? 더 많은 문맥을 제공하십시오. –

+0

@DigitalNinja 예 우리는 프로젝트를 위해 우리에게 주어진 스케줄러를 사용해야합니다. –

답변

0

ADC 처리에 경쟁 조건이 있습니다. 뮤텍스를 사용하여 한 번에 하나의 작업으로 만 ADC에 대한 액세스를 제한 할 것을 제안하십시오.