用于线上 NEC 信号输出的 Arduino 时序编程

Arduino timing programming for NEC signal output on wire

对于包含 led-strip 控制器的项目,我想用 Arduino nano 替换红外遥控器。现在在做了一些研究(http://blog.allgaiershops.com/2012/05/10/reversing-an-rgb-led-remote/)和测量后,我发现 led-strip 控制器使用 NEC 协议。

现在我尝试创建一个程序来模拟在 IR_receiver 上测量的按钮按下事件之一。但是,当测量数字引脚 2 上的输出(支持 PWM)时,时序并不接近所需。

但是,如果我在主循环的函数(high/low 输出)中使用 for 循环,则可以创建 500us 的高输出。

我想知道您是否可以给我一些支持以使代码正常运行,或者您能否给我一些关于如何有效处理 Arduino 时序的提示。

/*
Timer2_Counter_display_time_elapsed.ino
Timer2 Counter Basic Example - Demonstrates use of my Timer2_Counter, which is a timer function with 0.5us precision, 
rather than 4us precision like the built-in Arduino micros() function has.
By Gabriel Staples
Visit my blog at http://electricrcaircraftguy.blogspot.com/
-My contact info is available by clicking the "Contact Me" tab at the top of my blog.
-Please support my work & contributions by buying something here: https://sites.google.com/site/ercaguystore1/
My original post containing this code can be found here: http://electricrcaircraftguy.blogspot.com/2014/02/Timer2Counter-more-precise-Arduino-micros-function.html
Written: 17 May 2014
Updated: 30 May 2014
*/

//CODE DESCRIPTION:
//This code demonstrates the use of my Timer2, which provides a more precise timer than micros().  
//micros() has a precision of only 4us.  However, Timer2 keeps track of time to a precision of 0.5us.
//This is especially important in my code which reads an RC receiver PWM signal, which varies from 900~2100us. 
//Though this code demonstrates the use of the Timer_2 functions I have written, it does not adequately demonstrate the 
//real utility of the code, so I will state the following:
//By using my Timer2 timer to measure the PWM high time interval on an RC receiver, in place of using micros(), I can get repeatable 
//pulse width reads with a fluctuation of ~1us, rather than having a read-in range fluctuating by as much as +/- 4~8 us when I use micros().
//This is an increase in precision of ~8x.

//include the library
#include <eRCaGuy_Timer2_Counter.h>
#define pin_output 2
#include <time.h>

//Note: an object of this class was already pre-instantiated in the .cpp file of this library, so you can simply access its methods (functions)
//      directly now through the object name "timer2"
//eRCaGuy_Timer2_Counter timer2;  //this is what the pre-instantiation line from the .cpp file looks like

boolean on=false;
int values[24][32]={0};
int  one_output =1680;
int  zero_output= 560;

void low_output(int );
void high_output(int );
void start_protocol(int);
void end_protocol(int);


void setup() {
    //configure Timer2
    timer2.setup(); //this MUST be done before the other Timer2_Counter functions work; Note: since this messes up PWM outputs on pins 3 & 11, as well as 
    //interferes with the tone() library (http://arduino.cc/en/reference/tone), you can always revert Timer2 back to normal by calling 
    //timer2.unsetup()
    //values[0]={8,4,1,5,8,6};
    //prepare serial
    Serial.begin(115200);  
    pinMode(pin_output, OUTPUT);   
    digitalWrite(pin_output, HIGH);
    //Output a header of info:
    /*Serial.println(F("Notes:"));
    Serial.println(F("micros() has a precision of 4us"));
    Serial.println(F("get_count() with unsigned long final data type has a final precision of 1us, and is fast"));
    Serial.println(F("get_count() with float final data type has a final precision of 0.5us, and is not quite as fast"));
    Serial.println(F("get_micros() has a precision of 0.5us, and is slower than the above 2 methods, so one of the above 2 methods is preferred"));
    Serial.println(F("=============================================="));*/
}


void loop() {
    //declare local variables
    delay(2000);
    start_protocol();
    low_output(8);
    high_output(4);
    low_output(1);
    high_output(5);
    low_output(8);
    high_output(6);
    end_protocol();
    static unsigned long t_start = timer2.get_count(); 
    // unsigned long t_micros = micros();
    unsigned long t_T2_count = timer2.get_count();
    //float t_T2_micros = timer2.get_micros();
    if ((t_T2_count - t_start)/2 >= 2000003)
    {
        digitalWrite(pin_output, HIGH);   
    }
} //end of loop()


void low_output(int xtimes)
{
    for (int i =0 ; i<xtimes ; i++){
        static unsigned long t_start = timer2.get_count(); //units of 0.5us; the count accumulated by Timer2_Counter

        //acquire time stamps

        unsigned long t_T2_count = timer2.get_count(); //units of 0.5us; the count accumulated by Timer2_Counter

        //See if 1.000003 seconds has elapsed.  If so, print out the time stamps. Note: I am using this elapsed time because I want it to NOT be divisible by 4, so that 
        //you can hopefully see the extra precision provided by the Timer2_Counter library, which the default Arduino micros() function does not have
        if ((t_T2_count - t_start)/2 >= zero_output)//1000003) //if 1.000003 seconds has elapsed
        {
            t_start = t_T2_count; //update start time
            if(on==false) {
                digitalWrite(pin_output, LOW);
                on=true;
            }else {
                digitalWrite(pin_output, HIGH);
                on=false;
            }

        }
    }
    return;
}


void high_output(int xtimes)
{
    for (int i =0 ; i<xtimes ; i++){
        static unsigned long t_start = timer2.get_count(); 

        //acquire time stamps

        unsigned long t_T2_count = timer2.get_count(); 


        if ((t_T2_count - t_start)/2 >= one_output)
        {
            t_start = t_T2_count; //update start time
            if(on==false) {
                digitalWrite(pin_output, LOW);
                on=true;
            }else {
                digitalWrite(pin_output, HIGH);
                on=false;
            }

        }
    }
    return;
}


void start_protocol(){

    static unsigned long t_start = timer2.get_count(); 
    unsigned long t_T2_count = timer2.get_count(); 
    digitalWrite(pin_output, LOW);    


    t_start = timer2.get_count();
    t_T2_count = timer2.get_count(); 
    if ((t_T2_count - t_start)/2 >= 9000)
    {
        digitalWrite(pin_output, HIGH);
    } 

}


void end_protocol(){

    static unsigned long t_start = timer2.get_count();
    unsigned long t_T2_count = timer2.get_count();
    if ((t_T2_count - t_start)/2 >= zero_output)
    {
        digitalWrite(pin_output, LOW);
    }

    t_start = timer2.get_count();
    t_T2_count = timer2.get_count(); 
    if ((t_T2_count - t_start)/2 >= 40000)
        digitalWrite(pin_output, HIGH); 

    t_start = timer2.get_count();
    t_T2_count = timer2.get_count();
    if ((t_T2_count - t_start)/2 >= 9000)
    {
        digitalWrite(pin_output, LOW); 
    }  
    t_start = timer2.get_count();
    t_T2_count = timer2.get_count();
    if ((t_T2_count - t_start)/2 >= 2100)
    {
        digitalWrite(pin_output, HIGH); 
    }
    t_start = timer2.get_count();
    t_T2_count = timer2.get_count(); 
    if ((t_T2_count - t_start)/2 >= zero_output)
    {
        digitalWrite(pin_output, LOW); 
    }
    digitalWrite(pin_output, HIGH);
}

对于这段代码,我使用了 Gabriel Staples 制作的时序库。

[更新] 在遵循@Gmodjackass 的提示后,以下代码在引脚 2 的输出端获得了 NEC 信号。注意:可以通过添加对直接引脚端口操作的支持来优化代码。

#define pin_output 2
#include <time.h>

boolean on=false;
int values[24][32]={0};
int  one_output =1680;
int  zero_output= 560;
int sb=-1;
void low_output(int );
void high_output(int );
void start_protocol();
void end_protocol();
void selection_protocol(String);
void setup() {

    Serial.begin(115200);  
    pinMode(pin_output, OUTPUT);   
    digitalWrite(pin_output, HIGH);
    Serial.print("user_inpu: on(1) / off(0)");
    delayMicroseconds(400);
}

void loop() {
    //declare local variables
    if (Serial.available()) 
    {

        char sb = Serial.read();
        Serial.print(sb);
        switch (sb){
        case '0':
            selection_protocol("off");
            break;
        case '1':
            selection_protocol("on");
            break; 

        }
        sb=-1;
    }
} //end of loop()

void low_output(int xtimes)
{
    for (int i =0 ; i<xtimes*2 ; i++){          
        if(on==false) {
            digitalWrite(pin_output, LOW);
            on=true;
        }else {
            digitalWrite(pin_output, HIGH);
            on=false;
        }
        delayMicroseconds(zero_output);
        //}
    }
    return;
}
void high_output(int xtimes)
{
    for (int i =0 ; i<xtimes*2 ; i++){       
        if(on==false) {
            digitalWrite(pin_output, LOW);
            on=true;
            delayMicroseconds(zero_output);
        }else {
            digitalWrite(pin_output, HIGH);
            on=false;
            delayMicroseconds(one_output);
        }
        //}
    }
    return;
}
void start_protocol(){
    digitalWrite(pin_output, LOW);    
    delayMicroseconds(9000);
    digitalWrite(pin_output, HIGH);
    delayMicroseconds(4400);


    return;
}
void end_protocol(){

    digitalWrite(pin_output, LOW);
    delayMicroseconds(zero_output);        
    digitalWrite(pin_output, HIGH); 
    delay(40);        
    digitalWrite(pin_output, LOW); 
    delayMicroseconds(9000);       
    digitalWrite(pin_output, HIGH); 
    delayMicroseconds(2100);       
    digitalWrite(pin_output, LOW);
    delayMicroseconds(zero_output);
    digitalWrite(pin_output, HIGH);
    return;
}
void selection_protocol(String user_input){

    if(user_input == "on"){
        Serial.print("on selected");
        start_protocol();
        low_output(8);
        high_output(4);
        low_output(1);
        high_output(5);
        low_output(8);
        high_output(6);
        end_protocol();
    }
    if(user_input == "off"){
        Serial.print("off selected");
        start_protocol();
        low_output(8);
        high_output(4);
        low_output(1);
        high_output(3);
        low_output(1);
        high_output(1);
        low_output(6);
        high_output(1);
        low_output(1);
        high_output(6);
        end_protocol();

    }
    return;
}

您的一些时间差异可能是由于 arduino 的 digitalWrite 的速度非常慢造成的,也许考虑使用 direct port manipulation. Also consider using this delay function,因为它可能会导致更多的时间问题。

(已编辑拼写错误)