I've done some basic AVR programming before, but I'm not super savvy... that's why I need some help from the community with UNO.
I have a little project where I need to capture PWM signal ranging from 0Hz to 240Hz and convert it to 0Hz to 150Hz. Separately I'm able to capture PWM using TCCR1 and ICR1 and to create 1Hz to 150Hz PWM using TCCR1 but I don't know how to combine these two routines. It seems that I cannot capture input using any other timers and I'm having issues producing low frequency PWM using anything besides timer counter 1 as well:(
Is there a trick that I could use? I will be very grateful for any help!
Interesting puzzle as for both you need the same timer. Should be easy with the Atmega328PB, as it has 2 extra 16 bit timers, but you have to do it with one.
Thinking out loud:
Is that input frequency changing slowly, like the tachometer of an engine or a odometer?
In that case the input what you capture will most likely fit within one cycle that you generate, as you are generating a lower frequency than what your input is. And since you know what frequency you generate, I suspect you could still calculate the pulsewidth of the incoming pulse.
I I were in your situation I would define a pin change interrupt connected to the rising edge of your incoming pulse signal.
In the pinchange ISR you would have to take a snapshot of the timer value and store that for the next time you ener the ISR.
When in the ISR again calculate the amount of timer ticks that have passed since the last time you were in the ISR.
Two possibilities
a) previous snapshot < current timer value (timer did not restart) period = "timer value" - "previous snapshot"
b) previous snapshot > current timer value (timer restarted inbetween) period = "timer value" + TOP - "previous snapshot"
where TOP is the timer top that you change to generate your desired output frequency.
Hey! Actually it is for a speedometer, instead of buying Kph to Mph converter I first want to try to make own. So yes, good guess
That sounds interesting! I'm not that proficient in programming so it will take me some time to figure that out, but thanks for the idea! I will try to implement it!
I moved your topic to an appropriate forum category @mech314.
In the future, please take some time to pick the forum category that best suits the subject of your topic. There is an "About the _____ category" topic at the top of each category that explains its purpose.
Here are the code snippets that've used to read or produce PWM.
Read:
int Hz;
void setupTimer() { // timer1
TCCR1A = 0; //
TCCR1B = 132; // (10000100) Falling edge trigger, Timer = CPU Clock/256, noise cancellation on
TCCR1C = 0; //
TIMSK1 = 33; // (00100001) Input capture and overflow interupts enabled
TCNT1 = 0; // start from 0
}
ISR(TIMER1_CAPT_vect) { // Interupt when pulse is detecte
revTick = ICR1; // save duration
TCNT1 = 0; // restart timer
}
ISR(TIMER1_OVF_vect) { // counter overflow/timeout
revTick = 0; // Ticks per second = 0
}
void setup() {
pinMode(9, OUTPUT); // Set digital pin 9 (D9) to an output
TCCR1A = _BV(COM1A1) | _BV(WGM11); // Enable the PWM output OC1A on digital pins 9
TCCR1B = _BV(WGM13) | _BV(WGM12) | _BV(CS12); // Set fast PWM and prescaler of 256 on timer 1
ICR1 = 62499; // Set the PWM frequency to 1Hz: 16MHz/(256 * 1Hz) - 1 = 62499
OCR1A = 31249; // Set the duty-cycle to 50%: 62499 / 2 = 31249
}
void loop() {}
If you don't want to mess around with floats, you can use 64 miles = 103 km (very close, correct to within 7 feet in the 64 miles) to convert. So, just multiply the kilometers by 64, and then divide by 103 to get miles. Important: you don't want your analog read multiplied by 64 to exceed the capacity of an int (an int will only go up to 32767), so multiply by 64U to get an unsigned int (which can go up to 65535) instead of an int. Or multiply by 64UL to get an unsigned long (which can go up to 4 billion).
Your code works! Thank you very much!
Interestingly, initially when I was determining the frequency for each speed on the speedometer I used Atmega168 to output 50% PWM at different HZ and this is where I found 0 - 240 Hz, however - today I quickly used NE555 timer, which I don't trust as much and I found much lower frequency resulting in the same speed reading.
I found that at lower speeds the conversion is perfect, 60 Kph = 40 Mph, however 160 Kph = 108 Mph. It is not entirely clear who is at fault - converter or speedometer error when I set 160 Kph - this needed to be tested using GPS (probably not going to do that, way to fast to do on normal roads).
The website with timer visualization is amazing, thanks for showing it! I will definitely use in future projects!
I'm reading other replies in the thread, I will adjust accordingly later when I check what is the actual frequency coming from the speed sensor. I will post later when I install new speedometer on my car, that probably won't happen in the nearest couple of weeks but I will post the results!
Guys, you are the best! I am very grateful!!
P.s. Now I need to read it carefully and figure out how it works