Port Manipulation - Pulse Counter

I am trying to count digital pulses coming from a external source. Since the pulses are coming too fast I can not use digitalWrite. For other reasos I can not use interrup either. As such, I am planning to use port manipulation. I am using arduino ATmega 2560. The code I have so far is written below:

volatile unsigned int pulses = 0;
void count() {
 // This function is called 
 pulses++;
}

void setup() {
 
  DDRD &= ~(1<

Thanks in advence, Derlone

if pulse is coming too fast, then more so you must use interrupt. are you saying you cannot use interrupt because you need to do serial.println?

f pulse is coming too fast, then more so you must use interrupt. are you saying you cannot use interrupt because you need to do serial.println?

The pulses I am getting are not periodic. But doing some mesurement I would say the average period is about 80 micro seconds. And I can not use interrupt because I planing to have two or more external sources of pulses in the same arduino. Also I need other functions running while I do the counting.

That's exactly why you do need interrupts, so that it can all run at once.

pin change interupts monitor an 8-bit port, there are 3 such interrupts so you can monitor 24 pins if necessary. You have to work out what changed and you get to mask out which bits of the port the interrupt (s) respond to.

I'm still not sure why you think you cannot use interrupt. non periodic pulse? that itself is reason why you must only use interrupt. I use interrupt on multiple lines and main loop runs a full blown webserver and it works just fine. You need to read the atmega2560 manual, multiple times, as you will need to access timer interrupt registers directly.

The code down bellow works just fine. The problem is: What do I have to do if instead of getting one external source of pulses I will get 3? (in three different input pins).

int pin = 2;
unsigned long duration;
// Initialize the counter
volatile unsigned int pulses = 0;
void count() {
  // This function is called by the interrupt
  pulses++;
}
void setup() {
  Serial.begin(9600);
  pinMode(pin, INPUT);
  attachInterrupt(0, count, RISING); 
}
void loop() {
  duration = pulseIn(pin, HIGH);
  Serial.println("duration in us");
  Serial.println(duration);
  Serial.println("");
  Serial.println("pulses");
  Serial.println(pulses);
  Serial.println(""); 
 }

There are plenty of sample codes that does exactly this, as this is a very common application, you just need to look for it.

you store the pin state and xor it next time you get an interrupt to a new port in register read, then you know which pin the interrupt is for.

derlone: The code down bellow works just fine. The problem is: What do I have to do if instead of getting one external source of pulses I will get 3? (in three different input pins).

You need to use a pinChange interrupt. They can work on several pins but they are a little more complex. See Nick Gammon's interrupt tutorial.

Note that you should be reading the value of pulses into another variable like this

noInterrupts();
 currPulseCount = pulses;
interrupts();

and then use currPulseCount elsewhere in your code. Because pulses is 2 bytes one of the could change while the data is being read.

...R

Here's the typical code in a pin change interrupt, an outline at least:

ISR (PCINT0_vect)
{
  byte new_pinch0 = PINB ;
  byte diff = (new_pinch0 & ~ prev_pinch0) & PCMSK0 ;  // catch rising edges on relevant pins only
  prev_pinch0 = new_pinch0 ;
  for (byte i = 0 ; i < 8 ; i++)
  {
    if (diff & 1)
      handle(i) ;
    diff >>= 1 ;
  }
}

Nick’s page does not give much detail on pin change interrupt implementation.

A simple implementation on detecting the pin that caused the interrupt is as follows:

assuming all 8 bits of a port are enabled for pin change interrupt.

in the isr you define a static variable

static uint8_t last_state=0; //initial state of all pins is 0.

when isr is called, one of the 8 pins changed, so you read from port in register and xor to last_state

uint8_t state = PIND; //assuming port D
uint8_t mask = state^last_state;
last_state=state;

the xor operation will leave the bit set to 1 on any bit that is a different state than the last state.
0 xor 0 = 0, 1 xor 1 = 0, 1 xor 0 = 1, 0 xor 1 =1

Then from what is set high on mask, you can determine if that particular pin is high or low then do whatever you need.

Maybe get into the habit of saving the status register before turning off interrupts. Return the status to where it was afterwards.

uint8_t oldSREG = SREG; // save status register
  noInterrupts();
  currPulseCount = pulses;
  interrupts();
  SREG = oldSREG;       // return the status register

Do you guys think the following code would work ? Again, I need to count pulses SEPARATELY coming from these pins. I have to have three different variables. I might be wrong but I cant see how I would use three interrupts in the same code, since I can lose pulse if I interrupt an interrupt.

int pin = 2; //external interrupt number 0
int pin = 3; // external interrupt 1
int pin = 21; // external interrupt 2

unsigned long duration;
// Initialize the counter
volatile unsigned int pulses2 = 0;
volatile unsigned int pulses3 = 0;
volatile unsigned int pulses21 = 0;
void count2() {
  // This function is called by the interrupt
  pulses2++;
}
void count3() {
  // This function is called by the interrupt
  pulses3++;
}
void coun21t() {
  // This function is called by the interrupt
  pulses21++;
}
void setup() {
  Serial.begin(9600);
  pinMode(pin, INPUT);
  attachInterrupt(0, count, RISING);
  attachInterrupt(1, count, RISING); 
  attachInterrupt(2, count, RISING);  
}

derlone:
Do you guys think the following code would work

Try it, and then you can tell us.

The Arduino is a great system for learning-by-doing

…R

LarryD: Maybe get into the habit of saving the status register before turning off interrupts. Return the status to where it was afterwards.

Good point - but this isn't always appropriate - with top-level setup code like this you know interrupts to be enabled except inside a critical section like this.

In an interrupt routine the interrupts are disabled and re-enabled for you, but in a function that is called both at top level and from an interrupt then your use of SREG is the correct approach. interrupts() / noInterrupts() are more portable than SREG, so their use is generally encouraged where appropriate.

You'll note in the sources for digitalWrite () and pinMode() that the SREG method is employed since these functions are called from any context. We can assume that setup() code runs at top level though and you definitely want them to be enabled after configuring your pin-change interrupts or you'll never see any interrupts at all.

Problem solved. Like I said, I could not use interrupts and I did not. I actually used hardware counter:

volatile unsigned int pulse = 0;
volatile unsigned int pulses = 0;
volatile unsigned long timerCounts;
 unsigned int timer5CounterValue;



void startCounting (){

  TCCR5A = 0;             
  TCCR5B = 0; 

  TCNT5 = 0;
  timer5CounterValue = 0;
  

  GTCCR = bit (PSRASY);        // reset prescaler now
  // External clock source on T4 pin (D47). Clock on rising edge.
  TCCR5B =  bit (CS50) | bit (CS51) | bit (CS52);
    
} // end of startCounting

void stopCounting (){
 TCCR5A = 0;             
  TCCR5B = 0; 

  
}

void readCounter (){
   timer5CounterValue=TCNT5;
}

void setup () {
  Serial.begin(9600);
  
}

void loop (){
  startCounting();
 delay(1000);
 stopCounting();
 readCounter();
    Serial.println(timer5CounterValue);
}