int outPin = 8; // digital pin 8 as <70uS pulse for Chronos pulse mode
int inPin = 3; // digital pin 3 as NRF clock input
int PulseInPin = 4; // digital pin 4 as pulse width measurement
void setup() {
pinMode(outPin, OUTPUT); // sets the digital pin as output to generator a <70uS pulse
pinMode(inPin, INPUT); // sets the digital pin as input to detect when pulse on start
Serial.begin(115200); // setup for RS232
pinMode(PulseInPin,INPUT); // setup for pulse width measurement
}
void loop() {
int val = digitalRead(inPin);
static int state = 0;
// static int freq = 1000;
static unsigned long PulseOnTime = 500;
const int pulseon = 60;
static int pulseoff = 929;
static int currenttime = 1;
PulseOnTime = pulseIn(PulseInPin, HIGH);
currenttime = millis();
pulseoff = PulseOnTime-pulseon; // calculate pulse off time
// val = (digitalRead(inPin)); // Read NRF clock
if (state == 0 && val == 1) { // When pulse on and state = 0, we would like generator a pulse
digitalWrite(outPin, LOW); // sets the pin off
delayMicroseconds(pulseoff); // pauses for (duty on - pulse time)
digitalWrite(outPin, HIGH); // sets the pin on
delayMicroseconds(pulseon); // pauses for 60 microseconds
digitalWrite(outPin, LOW); // sets the pin off
state = 1;
}
else {
if(val == 0) {
state = 0;
delayMicroseconds(1000);
}
}
Serial.print(currenttime);
Serial.print(">");
Serial.print("PulseOnTime: ");
Serial.print(PulseOnTime);
Serial.print(" _state: ");
Serial.print(state);
Serial.print(" _ In: ");
Serial.print(val);
Serial.print(" _Out: ");
Serial.print(outPin);
Serial.print(" _???: ");
Serial.print(pulseoff);
Serial.print('\n');
}
Based on that scope image: the incoming pulse lasts just over 200 µs, and comes in every 1 ms.
Those print statements take about 4 ms (roughly 11 characters per ms at 115200 bps). That's one major problem already, you will miss pulses completely.
Chingping:
the 60uS does not generate at pulse on.
That is because you ask your code to wait a bit before generating the pulse:
delayMicroseconds(pulseoff); // pauses for (duty on - pulse time)
Now if you want the output pulse to start right when you get your input pulse, and you want it to last for pretty much exactly 60 µs, you have to drastically modify your code.
use an interrupt to detect the incoming pulse for fastest reaction time. Set it to trigger on RISING for rising edge.
use direct port calls to set the output pin, not the much slower digitalWrite() call.
use a timer interrupt for switching off the pulse.
That way you will get 60 µs pulse (give or take a few clock pulses at 62.5 ns each - you can fine tune this a bit by tweaking the exact duration of the timer interrupt), which starts within some 300 ns from the incoming pulse.
Thanks for your input. You are correct. The control loop time is too long due to pulseIn() function. I added a condition to use this function every second instead of every control loop. It work great now. Thanks a lot.
Chingping:
It seems Arduino Uno is not right board to support this project. The pulse is not reliable. I will try Arduino Zero as my next step.
What is "not reliable"?
Unless you didn't give the full picture, I see this as a job the ATmega328p controller is perfectly capable of. The limitation is more likely with your programming skills, and switching to a Zero is not going to solve that.
Thanks for your reply. I do not have Arduino Zero with me. I will try to change the code to utilize interrupt.
When I say not reliable. I mean the pulse has been generate in right place in most case. Every once a while it has been generate in duty off cycle.
The ESP32 has a High Resolution Timer that is good to operate a few bits of code down to 50uS. I would venture that if no other code was ran but the code to cause a ESP32 reset or none at all, would get you your 60uS pulse.
Idahowalker:
I am guessing that the UNO is off a bit due to its 'need' to handle the millisecond interrupt.
The images appear to show a pulse on a falling edge, rather than just on rising edge, as if there's an artifact in the input signal.
The ESP won't improve on this. Also if you think dealing with the millis() and micros() and similar functions in the background is an issue, just think of what the ESP is doing in the background... there's a reason they have the yield() function! For real time, precision timing work the AVR beats the ESP in many situations. Reacting quickly to interrupts is one fo them.
My spec is to generate a pulse less than 70 uS. So 50~70 is fine. I change the code to use interrupt. It's working great. Thanks a lot. It's my first Arduino project. I will use Arduino more going forward. That's very cool small board.
I should note: we normally steer beginners clear from using interrupts, as there are lots of pitfalls. This is one of the rare cases where an interrupt is appropriate (for quick reaction to a rather fast changing signal).