The reason why you can't modify the pulse protocol. Edit - but I think it's becoming clearer that it is because it is defined by the manufacturer. Nowhere did you explain that. It is time to gather that information for us.
Well, I did, and proceeded as requested.
I don't really understand why you seem upset about that.
I also have the original elctronic drawings and firmware from scalextric, but at some point are all these datas necessary to give the perimeter of my need? I did mention scalextric just in case somebody in the future might look after the same informations than I am now. but basically should it be something very different, it would not change my problem's perimeter.
Anyway, just tried the PulseIn() function and it returning weird and unstable numbers.
I am wondering if an arduino can actually measure a 40µs pulse. I guess I have to investigate more about this ability.
Well, I'm still waiting for any details at all really... your question focuses on pulse detection. Don't you think someone would want to have numbers on the pulse timings to help with that?
Obviously you did not follow my advice to read the forum guidelines. For this, you should be posting your code.
The IRremote library counts multiples of 50µs, way too long for your times.
But I don't see a need for a library. Poll the signal and start with a falling edge. Take the start time, wait for the next rising edge and take the time, repeat for the next falling edge.
What 40us pulse? I have to admit, it is frustrating sorting through drips and drabs of information to try and get a clear picture. I'm tired of it, so I'm out. Good luck.
I withdraw my remarks as it appears that i haven't and probably won't see what you're endgame is sorry to all and lve learnt by it.
So roughly, the 'ID' is the time between rising edges. Subtract 130 microseconds and divide by 50 microseconds to get the boundary points. Subtract 105 instead of 130 to round to the nearest ID.
The time that the pulse is HIGH when action is requested seems about 50 uS. What happens if no 'action' is being requested?
I think the InputCapture feature of the ATmega328P and other AVR processors would be a good choice. On an Arduino UNO or Nano that's Pin 8. You can set the hardware to capture the 16-bit Timer1 value when there is a RISING or FALLING edge on Pin 8. That will give you timing to 1/16th of a microsecond.
Here is a sketch I wrote to demonstrate the use of Input Capture:
// Measures the HIGH width, LOW width, frequency, and duty-cycle of a pulse train
// on Arduino UNO/Nano Pin 8 (ICP1 pin).
// Note: Since this uses Timer1, Pin 9 and Pin 10 can't be used for
// analogWrite().
void setup()
{
Serial.begin(115200);
while (!Serial);
// For testing, uncomment one of these lines and connect
// Pin 3 or Pin 5 to Pin 8
// analogWrite(3, 64); // 512.00, 1528.00, 2040.00, 25.10%, 490.20 Hz
// analogWrite(5, 64); // 260.00, 764.00, 1024.00, 25.39%, 976.56 Hz
noInterrupts (); // protected code
// reset Timer 1
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
TIMSK1 = 0;
TIFR1 |= _BV(ICF1); // clear Input Capture Flag so we don't get a bogus interrupt
TIFR1 |= _BV(TOV1); // clear Overflow Flag so we don't get a bogus interrupt
TCCR1B = _BV(CS10) | // start Timer 1, no prescaler
_BV(ICES1); // Input Capture Edge Select (1=Rising, 0=Falling)
TIMSK1 |= _BV(ICIE1); // Enable Timer 1 Input Capture Interrupt
TIMSK1 |= _BV(TOIE1); // Enable Timer 1 Overflow Interrupt
interrupts ();
}
volatile uint32_t PulseHighTime = 0;
volatile uint32_t PulseLowTime = 0;
volatile uint16_t Overflows = 0;
ISR(TIMER1_OVF_vect)
{
Overflows++;
}
ISR(TIMER1_CAPT_vect)
{
static uint32_t firstRisingEdgeTime = 0;
static uint32_t fallingEdgeTime = 0;
static uint32_t secondRisingEdgeTime = 0;
uint16_t overflows = Overflows;
// If an overflow happened but has not been handled yet
// and the timer count was close to zero, count the
// overflow as part of this time.
if ((TIFR1 & _BV(TOV1)) && (ICR1 < 1024))
overflows++;
if (PulseLowTime == 0)
{
if (TCCR1B & _BV(ICES1))
{
// Interrupted on Rising Edge
if (firstRisingEdgeTime) // Already have the first rising edge...
{
// ... so this is the second rising edge, ending the low part
// of the cycle.
secondRisingEdgeTime = overflows; // Upper 16 bits
secondRisingEdgeTime = (secondRisingEdgeTime << 16) | ICR1;
PulseLowTime = secondRisingEdgeTime - fallingEdgeTime;
firstRisingEdgeTime = 0;
}
else
{
firstRisingEdgeTime = overflows; // Upper 16 bits
firstRisingEdgeTime = (firstRisingEdgeTime << 16) | ICR1;
TCCR1B &= ~_BV(ICES1); // Switch to Falling Edge
}
}
else
{
// Interrupted on Falling Edge
fallingEdgeTime = overflows; // Upper 16 bits
fallingEdgeTime = (fallingEdgeTime << 16) | ICR1;
TCCR1B |= _BV(ICES1); // Switch to Rising Edge
PulseHighTime = fallingEdgeTime - firstRisingEdgeTime;
}
}
}
void loop()
{
noInterrupts();
uint32_t pulseHighTime = PulseHighTime;
uint32_t pulseLowTime = PulseLowTime;
interrupts();
// If a sample has been measured
if (pulseLowTime)
{
// Display the pulse length in microseconds
Serial.print("High time (microseconds): ");
Serial.println(pulseHighTime / 16.0, 2);
Serial.print("Low time (microseconds): ");
Serial.println(pulseLowTime / 16.0, 2);
uint32_t cycleTime = pulseHighTime + pulseLowTime;
Serial.print("Cycle time (microseconds): ");
Serial.println(cycleTime / 16.0, 2);
float dutyCycle = pulseHighTime / (float)cycleTime;
Serial.print("Duty cycle (%): ");
Serial.println(dutyCycle * 100.0, 2);
float frequency = (float)F_CPU / cycleTime;
Serial.print("Frequency (Hz): ");
Serial.println(frequency, 2);
Serial.println();
delay(1000); // Slow down output
// Request another sample
noInterrupts();
PulseLowTime = 0;
interrupts();
}
}
John, thank you for your time. i wasn't expecting to get an answer so detailed, and including a so long sketch.
You got it right.
absolutely. I was focusing on the shortest I may have to deal with when writing 40ms.
Pulse is up until 25µs before the next rise, whatever the ID is.
So, for ID1, pulse is 160µs wide, and for ID6 pulse is 400µs.
for the next test, I wanted to get rid of possible light emiting / receiving issues, so, I first emulated an ID1 requestiong action with x1000 values, using a UNO board and a basic blink program with timing values changed so that it sticks to the actual ones.
implemented your sketch in a NANO board, and connected them together.
I have been able to get a stable reading:
This proves me that your sketch works fine, and that if I don't get the expected values, it comes from something else than the sketch (like diagram, IR receiver or Nano hardware limitations)
Please note that the screenshot indicated values are matching values in the modified blink sketch.
Next: I think I'll connect directly the NANO instead of the IR LED emitter to see exactly what values I get, and if they matches what my oscilloscope tells me.
EDIT: I have changed blink to :
// the setup function runs once when you press reset or power the board
void setup() {
// initialize digital pin LED_BUILTIN as an output.
pinMode(5, OUTPUT);
}
// the loop function runs over and over again forever
void loop() {
digitalWrite(5, HIGH); // sets the pin on
delayMicroseconds(47); // pauses for 47 microseconds
digitalWrite(5, LOW); // sets the pin off
delayMicroseconds(140); // pauses for 140 microseconds // wait for a second
}
... which I should have done from the start, and got correct readings from your sketch.
If I can have it correctly, I'll then have to check what's going on with the IR receiver I have in hands. I suspect its integrated circuit is limiting it to longer signals, So I've ordered a few Vishay BP104 and check if I can have it work better.
Thanks for your help, and I will post my results, as somebody else may look after these datas.
Obviously any input or remark is very welcome.
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.
