In this post, I will talk about how to count pulses in Arduino without using any interrupts or loops. This method can come in handy when the controller is handling a lot of task which can either cause it to miss some counts or introduce some unnecessary delays if some checks are included.
Even when using interrupts, it will have to interrupt a program in execution in order to increment a count. This will obviously cause delays for the rest of the program.
In this blog, I will be using the built in timer/counter module of Arduino for the purpose. More details about this module can be found in the atmega328p datasheet (link) (in chapter 14,15 and 16). I will provide a basic introduction, mainly the three registers (TCCR0A, TCCR0B and TCNT0) that will be of use to us.
Introduction
A basic function of the timer counter is to (as the name suggests) "count". It increments the counter (the value in the TCNT0 register) whenever it encounters a clock. The clock frequency and source can be selected using the values in the TCCR0B register.
TCCR0A register
The TCCR0A register (or timer counter control register 0 A) decides the mode of the timer counter. its values are :
Bits 5 to 7 are compare output bits that are used for driving PWM signals, we don't need them for this particular project, so they will be set to zero. The first two bits WGM0 and WGM1 along with the WGM2 bit in TCCR0B register are used for setting the mode of the timer module.
In mode 0 (normal mode) it behaves like a simple counter counting from 0 to 0xFF (255) and then reset back to zero. In CTC mode, it counts from 0 to the value in 0CR0A register. In phase corrected mode, it counts from 0 to 0xFF then back to 0 (symmetrical triangular wave). In fast PWM, the counter behaves similar to the normal mode (there are a few differences w.r.t. the PWM signal which will be discussed in another post).
For this post, the we want the counter to be in normal mode, thus we will set TCC0A to zero.
TCCR0B register
The TCCR0B register will be used to select the clock source. The FOC0A and F0C0B bits are used for force compare for PWM outputs. WGM2 is described in the earlier section. The CS00 to CS02 bits are clock select bits. That are used for selecting the clock source and frequency.
for counting pulses, we will need to use the external clock source on pin T0. To count on each rising edge we need to set the value to 111. This the TCCR0B register will be set to 0x07.
Arduino Code
I am using an Arduino UNO board, which has the atmega328p controller. The Arduino code for this program would simply be :
void setup() {
// put your setup code here, to run once:
TCCR0A = 0x00;
TCCR0B = 0x07;
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
Serial.println(TCNT0);
}
In order to generate external pulses I will be using another board. I have the
evive board which I am using as anther arduino (it is powered by arduino Mega).
The code on this is :
void setup() {
// put your setup code here, to run once:
pinMode(2, OUTPUT);
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite(2, LOW);
delay(1000);
digitalWrite(2, HIGH);
delay(100);
}
This will generate pulses of 1 sec time frame.
Uploading both the codes on the specific boards and check the output on the serial terminal.
The video attached shows the the counter increasing every 2 seconds.
Benefits of this approach
The major benefit is that counter is implemented directly by the hardware, there does not need to be any add instruction in the program to keep count. The major drawback is that only specific pins can be used for the counter (atmega328p has 3 counters , only 3 pins can be used for them.
One second disadvantage is, it reduces the number of pins available for pwm. As one counter module is now used for counting here, it cannot be used for PWM's.
Comments
Post a Comment