Workflow of timers

Hi,
ive had minimal experince with PLCs (functions blocks), and want to learn about micro-controllers. Ive been at it, trying to learn for a couple of weeks (UNO). I have a project for myself thata i thought would be good to get my teeth into..

Below is the outline of my project, the top part gives the details.

If you can help me out, im after feedback if i have the flow correct, and if not why not. More so than code that i can cut and paste into the IDE.

Thanks if you can steer me in the right direction.

Quick note: had to do a refresher on maths to help myself out. found this link help ful for those in the same situation - www then .youtube.com/user/mathbff

/* Notes

the general idea of this program is to create a square wave (50%) pulse generator
thats frequency is modified by an input variable resistor. The frequency will
be from 0 to about 360 Hz. The goal is to use this frequency to simulate an engine
speed (proximity run by disc with 10 slots in it)so a PID controller can be used
to simulate a throttle position sensor attached to an ECU of a deisel engine,
which is setup to be a stationary generator.

unsigned long up to 4,294,967,296 - 1 (2^32)
16 bit counter (0-65535) (int)
MY ABBREVIATIONS

(CoS) - counter setting // used to set the counter overflow value
(OvC) = overflow counter // counts how many times an overflow has occured in increments of 1
(TaCT) = target clock tiks setting // this is hte target that invokes the interrupt to
change the (CoS) value if the clock tiks are under (BaTCT)
(BaTCT) = balance to clock tiks target // this is the value that is used to count the
remainder of tiks until interrupt

100rpm with 10 slot = 479988 tiks = 300Hz
400rpm with 10 slot = 119997 tiks = 66.6Hz
1800rpm with 10 slot = 26666 tiks = 16.6Hz
you may have to double the above amounts depending on the routine

SETUP PROCESS
1 - stop counter (said a good idea while changing settings)
2 - set (BaTCT) to '0'
3 - set (OvC) to '0'
4 - take reading of analog pin 'x' and set the mapped value to (TaCT)

  • TIMER setup (using 16 bit timer 1)
    5 - clear timer registers
    6 - select timer mode
    7 - set timer function
    8 - clear interrupt flag
    9 - set prescaler (TCCRxn)
    10 - set output compare (OCRxn)
    */

// Declare variables

// initial setup

// any function calls

// program to run

welcome

please read the sticky on the top of every forum called how to use this forum, read #7 about code tags

to post really long code, make a txt file and attach it as a document.

joeblogs:
the general idea of this program is to create a square wave (50%) pulse generator
thats frequency is modified by an input variable resistor. The frequency will
be from 0 to about 360 Hz.

That sounds straightforward.

Read the value of the potentiometer using analogRead().

Based on the value from the pot calculate the interval between pulses (the minimum will be 2778 micro secs) and save the value in a variable. Maybe 3 millisecs would be sufficiently accurate.

Use the saved value to generate a succession of HIGH and LOW outputs using digitalWrite().

Have a look at how millis() is used to manage timing in Serial Input Basics. The same thing works for micros()

...R

If you want to dig into timer programming details, start by reading the data sheet section about T1. In CTC mode the timer can be cleared when it reaches the OCRA value, resulting in adjustable frequency. A square wave of half that frequency (50% duty cycle) can be output on the OC1A pin (D9). I think that you figured out all that already.

The timer mode etc. can be initialized once, you only have to update OCRA properly. As long as the OCRA value is not too close to zero, it's sufficient to update it when the counter is cleared, best done in the timer ISR. You also can use OCRA1 and ICR1 alternatively for the timer period, and switch between both on a compare match/timer reset. With the intended low output frequencies it's very unlikely that you ever have to worry about too low OCRA values, if the prescaler is set to a high clock rate.

Alternatively you can use a PWM mode to eliminate the update problem.

In your code you can access all timer registers by the names used in the datasheet. You can #define your own names for these registers, if you like, but this will make your code less readable to others. Better use unsigned variables for all timer related values, if you want to use the full 16 bit range of the registers.

Now you can start writing your code, and come back if you run into any problems.

thanks for the replys folks,

DrDiettrich
that was the road i was heading down i think, i am a bit unsure how to deal with this

at lower rpm the CTC is going to be lower than the actual amount of clk tiks that im counting, so i would have to load the amount of overflows into a variable.
(OvC) = overflow counter
times that by 65536

  • the CTC amount when the pulse of the proxy finally comes
    which gives me the total amount of tiks between pulses

am i better doing all of the above in the ISR, or just updating (OvC), in the ISR, and having the loop process the rest.

As far as ive read the timer still keeps counting away regardless of if an ISR is running, or code is executing - is this correct.

the first attempt is attached, im going to change to completely using CTC, but its a start

practice 1.txt (2.28 KB)

joeblogs:
am i better doing all of the above in the ISR, or just updating (OvC), in the ISR, and having the loop process the rest.

If the minimum pulse duration is about 3 millisecs why on earth are you bothering with the complexity of ISRs and hardware Timers?

You should do as little as possible inside an ISR so that it can complete quickly.

...R

It's a good idea to explore the limitations of ISRs before using them in real projects. In my experiments I couldn't handle interrupts above 100kHz, at least not in C code.

For a wide output frequency range I'd adjust the prescaler instead of fiddling with overflows.

Hi Robin2.
to learn about timers/interrupts in short. my project needs to be able to tell the difference for a .25 rpm change in engine speed, which equates to a difference of 25 clock tiks/rpm at max speed.

DrDiettrich
point noted, will do some reading, i now the plcs we use will handle this, but i wanted to learn a bit about C and controllers, what other options are there apart from C.

Cheers

More precise input is required for such small differences. The 10 bit ADC steps in about 1/1000 of the max speed, or 500 ticks of max 500,000.

Fast ISR is said to be possible in assembly, but I never tried that. The assembler should provide some support, e.g. for saving/restoring registers.

joeblogs:
to learn about timers/interrupts in short.

That's fine. I did not realize it was just a learning exercise.

my project needs to be able to tell the difference for a .25 rpm change in engine speed, which equates to a difference of 25 clock tiks/rpm at max speed.

Please provide the maths behind this. It was certainly not obvious from your Original Post which said "from 0 to about 360 Hz"

...R

Hey guys

R

sorry i only posted half of the project at the start

the main end result is having a controller read the pulses from a proxy that is on a shaft
engine max speed 2200 rpm
standard speed 1800rpm
pulses per revolution = 10 (this can be changed but it seemed like a reasonable starting point)

2200rpm with 10 slot = 46636 tiks per pulse
2199rpm with 10 slot = 43656 tiks per pulse

the difference is 19.8 tiks between the 2 readings, i am trying to be able to read the difference of 0.25 rpm. the engine is connected to a 60 kva alternator, and this is the sort of accuracy i want to be able to keep the AC frequency +/-0.3 hz (or half this if possible).

i only got my arduino a week ago, so i have no idea at all of the limitations of the software/controller. Im not sure if this approach is even close to the right way to approach this.

it may be that i have to use a frequency to voltage converter, (i couldnt see the point of converting a digital signal back to analog though) so i thought id give this a crack first seemed like a good way to get the feet wet.

Dr
with the ADC are you refering to the input VR, should i use two boards, one to simulate the pulses and one to read them.

i guess my question really is, is an 8 bit microcontroller capable of consistently reading the difference in speed above. if you assume that the chips job is only to read the pulses and output a simple command to the PID. other boards could be used for other control needs, then they would have to talk to each other. but thats a whole new post.

thanks for your time in responding.

joeblogs:
i guess my question really is, is an 8 bit microcontroller capable of consistently reading the difference in speed above.

im getting the feeling that my expectations are to high for the microcontroller (more likely the way im approaching it) , as DR stated ISRs above 100kHz become unstable.

would a better approach be counting the pulses over a set period set by the timer, rather than trying to count the clk tiks between pulses.

If you (only) want a fake encoder for testing purposes, I'd suggest an independent controller for the pulse generation. This will show what happens on pulses which are not synchronized with the receiver clock. You also can use a second pot or other input, for fine-tuning the encoder frequency.

Once you made this part work, you can continue with the decoder part.

joeblogs:
i guess my question really is, is an 8 bit microcontroller capable of consistently reading the difference in speed above.

Joe, this is an interesting article that might help address your question.

http://www.gammon.com.au/forum/?id=11504

Accuracy

Pumping in a 5 MHz signal from a signal generator, the sketch outputs around 5001204 (give or take a couple of counts). The error (assuming the signal generator is accurate) is therefore 1204/500000 or about 0.02% error.

Trying with a 5 kHz signal, the sketch outputs around 5000 to 5002, an error of 2/5000 or 0.04% error.

So, pretty accurate. Tests on my Arduino clock showed that the clock itself was around 0.2% wrong, so we can't really expect better accuracy than that.

finally its starting to make a bit of sense

last try is attached.

can anyone see some improvments i can make, am i breaking any coding rules.

also im using a multimeter to read the frequency (dont have a scope yet). When i set up OCR1A with a static value (not using the analog input) of 49999, which should have equated to 20Hz on the dot. I was getting a reading of 19.99 (not sure of the accuracy of the meter). To get bang on 20Hz i changed OCR1A to 49967.
Is it safe to assume that the difference of 49999-49967=32 tiks is how long the loop takes to go through a cycle.

thanks for your ideas, some good clues to steer me along.

thanks for the link C2, cant count the pages ive read in the last few nights but its a lot - will have a read.

practice3.txt (2.47 KB)

PS - for anyone with a similar sort of problem to do with timers and direct port manipulation.
On ATMELs website there are a series of videos (getting started with AVR), which were really helpful, and at a nice speed for a fried brain.

If you study the Atmega datasheet I think there is an option for the Timer to change an output pin automatically. That would mean that the pulse frequency has nothing to do with the rest of your code.

Your accuracy will always be at the mercy of the accuracy of the Arduino clock. Maybe you need to build a standalone Atmega 328 with super-accurate crystal clock.

You will have great difficulty with this project if you don't have a measuring instrument in which you have confidence - the "blind leading the blind" comes to mind.

...R

R
there is to i didnt pick that one up, pins 9 and 10. will use that one down the track not ready to part with the blinking LED yet.

As for accuracy, i just ordered the newer version of the Zero, 32 bit timers and a 48MHz clock which ill use on the actual project.

Hah Hah bit like a gold fish trying to eat a shark. Was going to concentrate on the software basics first. When i get closer to building the actual machine ill get a shiny new scope.

C2's link has so much information on it and theres an example which is extremely close to want i think im trying to do.

thanks for your help

joeblogs:
As for accuracy, i just ordered the newer version of the Zero, 32 bit timers and a 48MHz clock which ill use on the actual project.

If I understand your project you need accurate absolute time keeping. That does not automatically come with a higher clock speed. It depends on the stability and accuracy of the oscillator that drives the Arduino.

…R