Split from: ATTINY13 timer and interrupts for reading RC receiver signal

Go To Last Post
25 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi i am working on attin13 to detect the square pulse of 3 Khz to 5 Khz frequency. So my Attiny13 should give result only when i have a square input signal of this frequency otherwise no output. I am using Timer and Pin change interrupt like yours. Can you please help me. I find it quite similar to mine but couldnot figured it out. I am new to programming.

Thank you

george

Last Edited: Sat. Jul 27, 2019 - 10:34 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you know if your incoming pulse will always be a square wave (50% hi, 50% low)?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes my input pulse is alwz 50% high 50% low

george

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The way things usually work here is that you post the code you have tried so far (together with details of circuit/wiring - preferably a schematic) and then folks here will point out anything you appear to have misunderstood or have done wrong.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

here the code i have tried. I just took some reference and put up and sorry i am in learning phase

Attachment(s): 

george

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For the benefit of others:

/*
 * PWM input.c
 *
 * Created: 22.07.2019 10:48:39
 * Author : GXG0223A
 */ 
#define F_CPU 9600000
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/atomic.h>
volatile uint8_t pwm_ready = 0;
volatile uint8_t timer_ovf = 0;
volatile uint8_t count = 0;
volatile uint16_t pulses = 0;
 
void Init_PORT(void) 
{
	 DDRB |= (1 << PB1);
	 // PORTB – Port B Data Register
	 //  (set PB1 to HIGH=5V)
	 PORTB |= (1 << PB1);

	 // set  pin as input (PB0, pin 5)
	 DDRB &= ~(1<< PB2);   // set logical 0
}

void Init_INTERRUPTS()
{
	 GIMSK |= (1 << PCIE);   // generally enable pin change interrupt
	 // Pin Change Mask Register
	 PCMSK |= (1 << PCINT0);   // enable pin change interrupt on PB0 (pin 5)
	 // Timer/Counter Interrupt Mask 
	  sei();
}
 
 
 int main(void)
 {
	 Init_PORT();
	// Init_INTERRUPTS();
	 while(1)
	 {
	
    	if ( pwm_ready ) {
    		
    		 pulses =  timer_ovf * 256 + count;			// multiply them by 256 (if we have an 8-bit counter)
    													 // add the timer counts from beginning of last overflow
    		 if ( PINB &(1<<PB2)) {
    			 PORTB |=(1<<PB1);
    		 }
    		 else {
    			 PORTB &=~(1<<PB1);
    		 }
    
    		 GIMSK |= (1 << PCIE);            // Pin Change Interrupt Enable
    		  
    		  pwm_ready = 0;
    	}
		 
     }
 }
  
ISR(PCINT0_vect)
{

	// here we check the level of our pin of interest
	// if it is HIGH, a rising edge interrupt has happened
	// if it is LOW, a falling edge interrupt has happened
	if (PINB & (1<<PB0)) 
		{	
			timer_ovf = 0;							// reset timer overflow counter at rising edge pin change interrupt
			TCNT0 = 0;								// initialize counter register at rising edge pin change interrupt
			TIFR0 = (1<<TOV0);						// clear timer overflow
			 TIMSK0 |= (1 << TOIE0);   // Timer/Counter0 Overflow Interrupt Enable
		
			 GTCCR &= ~(1 << TSM);   // start timer
		}
		 
		
	
	else if ( !(PINB & (1<<PB0)) ) 
		{
			 TIMSK0 &=~(1 << TOIE0);					// Timer/Counter0 Overflow Interrupt disable
			 GTCCR |= (1 << TSM) | (1 << PSR10);   // halt timer
			
			  GIMSK &= ~(1 << PCIE);                   // disable Pin Change Interrupt

			  TIFR0 = (1 << TOV0);
			count = TCNT0;			 // use counter register at falling edge pin change interrupt
									// time between rising and falling edge (pulse width)
									// count number of timer overflows
			pwm_ready = 1;	
		
		
		}
		
		
					
}

ISR(TIM0_OVF_vect)					// called when a timer overflow occurs
{
	timer_ovf++;								// count timer overflows since reset in rising edge pin change interrupt											// end ISR timer overflow
}

The call to enable in the interrupts is commented? What were you expect to happen?

 

BTW you appear to be using PCINTs there - surely for measuring input period/frequency is it is the input capture on one of the timers that would be the preferred way to read it? You over complicate things by triggering timers with PCINTs.

Last Edited: Mon. Jul 29, 2019 - 10:03 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

// on interrupts is just a mistake. I removed it. I donot have input capture feature in Attiny13.

george

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

George Babu wrote:
 I donot have input capture feature in Attiny13.
If you are programming an application that clearly cries out for input capture then do you think it might have been a mistake to pick an AVR that does not have the feature you require?

 

For example TCB in a tiny202/402 has input capture in an 8 pin AVR and the chips are considerably cheaper than tiny13

Last Edited: Mon. Jul 29, 2019 - 12:17 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Likewise Tiny25/45/85 (from my distant memory)

Last Edited: Mon. Jul 29, 2019 - 12:28 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I have a code attached and think the process is correct and if we go step calculation should give me the pulse width and compare it. Just any recommendation on this program. I cant change attiny13 because i have already solved the output part. I just need to get my output when i have the pulse input as described. Plz i think some errror on pulse calculation. implementing this attach code always give me high on output and doesnot consider input

Attachment(s): 

george

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

david.prentice wrote:

Likewise Tiny25/45/85 (from my distant memory)

No input capture.

 

ATtiny4/5/9/10 have it, but don't go there!

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0


George Babu wrote:

Attachment(s): 

Filemain.c

 

 

/*
 * struggle.c
 *
 * Created: 29.07.2019 12:49:33
 * Author : GXG0223A
 */ 
#define F_CPU 9600000
#include <avr/io.h>
#include <avr/interrupt.h>
volatile uint8_t timer_ovf = 0;
volatile uint8_t count = 0;
volatile uint16_t pulses = 0;

ISR (TIM0_OVF_vect)
{
	 timer_ovf++;		// count timer overflows since reset in rising edge pin change interrupt
}
ISR(PCINT0_vect){
	// here we check the level of our pin of interest
	// if it is HIGH, a rising edge interrupt has happened
	// if it is LOW, a falling edge interrupt has happened

	// PINB – Port B Input Pins Address (page 57)
	// check if PB0 (receiver) bit is 1 (HIGH)
	if (PINB & (1<<PB0)) {
		timer_ovf = 0;   // reset timer overflow counter at rising edge pin change interrupt
		// TCNT0 – Timer/Counter Register (page 73)
		TIFR0 = (1<<TOV0);
		TCNT0 = 0;   // initialize counter register at rising edge pin change interrupt
	}
	// otherwise PB0 (receiver) bit is 0 (LOW)
	// can also be checked like: if ( !(PINB & (1<<PB0)) ) {...}
	else if ( !(PINB & (1<<PB0)) ) {
		// TCNT0 – Timer/Counter Register (page 73)
		count = TCNT0;   // use counter register at falling edge pin change interrupt
		// time between rising and falling edge (pulse width)
		// count number of timer overflows
		// multiply them by 256 (if we have an 8-bit counter)
		// add the timer counts from beginning of last overflow
		pulses = timer_ovf * 256 + count;
	}
} // end ISR pin change interrupt
void setup() 
{
	cli();   // disable global interrupts

	// General Interrupt Mask Register (page 46)
	GIMSK |= (1 << PCIE);   // generally enable pin change interrupt
	// Pin Change Mask Register (page 47)
	PCMSK |= (1 << PCINT0);   // enable pin change interrupt on PB0 (pin 5)
	// Timer/Counter Interrupt Mask Register (page 74)
	TIMSK0 |= (1 << TOIE0);   // Timer/Counter0 Overflow Interrupt Enable
	 // GTCCR – General Timer/Counter Control Register (page 77)
	 GTCCR |= (1 << TSM) | (1 << PSR10);   // halt timer
	 // set prescaler for timer (page 73)
	 TCCR0B |= ((1 << CS00)|(1<<CS02));   // select internal system clock (clkI/O) and set prescaler to 1024
	 GTCCR &= ~(1 << TSM);   // start timer
	  // PCMSK – Pin Change Mask Register
	  PCMSK |= (1 << PCINT0); // pin change interrupt enabled for pin 5
	  // DDRB – Port B Data Direction Register
	  // set position_lights as output (PB1, pin 6)
	  DDRB |= (1 << PB1);
	  // PORTB – Port B Data Register
	  // switch on position_lights (set PB1 to HIGH=5V)
	  PORTB |= (1 << PB1);

	  // set receiver pin as input (PB0, pin 5)
	  DDRB &= ~(1 << PB0);   // set logical 0
	   sei();

   } // end setup


int main(void)
{
    /* Replace with your application code */
	
    while (1) 
    {
		 if (pulses > 10000) {					//>5khz 
			 PORTB &= ~(1 << PB1);
		 }
		 else
		 {
			 PORTB |= (1 << PB0);
		 }
    }
}

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hi

 Anybody with suggestion and code. I want to do with Attiny13 only. Currently using PCINT and Timer0. Anyone help me if you have any idea

george

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Your code does many things - what works and what doesn’t?

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I just need to detect certain range of frequency input signal and when i have that i need an output. I am using Timer/Counter and Pinchange interrupt to find out the pulse width and compare it with my frequency. my input frequency range is between 3khz to 5khz.  Last comparision of pulses>10000 is just a example. I find out my PCINT interrupt is not working. Can you say why and suggest me the code.

Thanks

george

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

How precise does it need to be ?

Are there always a freq on the pin ?

Are there noise ?

How many periods of the freq. before you change the port.

 

I would probably just make a timer ISR that pull the input pin

 

Lets say you run 9.6MHz and make a ISR for every 96 clk (100kHz), and just count how many ISR's the signal is high, if it's between 10 and 17 you set the port pin (else clear)

(everything can then be 8 bit).

That should be about 10 lines in the ISR for everything, other than the init code for timer and port.

 

As most know here I would probably do it in ASM and run something like 300-400kHz timer ISR's, so the are more resolutions.

 

 

 

If this is all you need then why any ISR, just have a free running timer running slow so it don't overflow at 3kHz.

wait until it goes high

  clr timer

wait until it goes low

  read timer (if you fear timer overflow then check for the overflow ISR bit, if set it took to long(remember to clear it))

 if between the numbers the match 3-5 kHz then set port else clear    

    

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

First, how often do you want to make the decision...the longer the better results.

 

Say every 1/2 second (500ms)....then you will have between 1500 & 2500 counts & even if you are off a few it will be very minor deviation.

 

5000Hz, is still plenty slow (4000 1-cycle instructions at 20MHz) for just polling the input to check the pin (sounds like you are not doing much else).

============

Set your timer so it counts at a reasonable rate (perhaps 1 tick/ms).  You don't even need any irq at all. 

 

Clear the timer & your pin count to zero

 

is time up (500ms)?

 no---check pin & update pin count , can also debounce pin if needed(add later)

 yes--check pin count & make decision (1500 to 2500 counts)

       --clear the timer & your pin count to zero

loop

 

Once this works, you can try fancier options

 

 

 

 

 

 

 

 

 

 

    

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

The application is a frequency range detector.  The AVR should change the logic state on an indicator pin if the input frequency is between 3000 and 5000 Hertz.  Since you didn't tell us, I'm going to assume that there is always a frequency on the input pin and the frequency ranges between 0 and 100 KHz.  And a PIN change interrupt is being used to detect a change on the frequency input pin.   Since you also didn't tell us,  I'm going to assume that the AVR is doing nothing else besides monitoring this input frequency.   You'all did mention that the signal is a 0-5V, 50% duty cycle with sharp rising and falling edges.   Since this is a precision timing circuit, it really really helps to know the system clock speed.  Since no one bothered to mention it, I'm going to assume that it is the factory internal RC clock setting of 8 MHz with the DIV8 fuse enabled, giving a system clock of 1MHz.

 

   Set the timer to a prescaler of 8.  When the PCINT pin goes low, set the timer count to 0.  Wait inside the interrupt until the input returns high, using repeated polling of the input pin for logic high.   Check the timer value.  If it is less than 12, then the frequency is too fast (>5KHz).  If it is more than 20 (or so), then the frequency is too slow (<3KHz).  If the timer value is between 12 and 20 inclusive,  then light an LED.  If out of range turn off the LED.  Finally exit the interrupt.   

 

The code spends half of its time inside this PCINT interrupt routine, but that's OK, because as you didn't tell us, the Tiny13 is doing nothing but monitoring the input frequency.

 

I didn't read your code because I assumed that it was doing something like what is described above.  Remove all the code that isn't directly involved with doing what is described above, because the Tiny13 is too small to do anything but one little task.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello  Simonetta 

You are on the right track as you explained above . I will tell you my project about. My input is coming from the switch. if i press the switch i will get a Pulse signal of 3 to 5 Khz frequency. So when i press the switch my output need to be high. I have two outputs where MOSFETs are connected. Donot bother about output i solved that part already.

I didnot understand your part (  Wait inside the interrupt until the input returns high, using repeated polling of the input pin for logic high.   Check the timer value.  If it is less than 12, then the frequency is too fast (>5KHz).  If it is more than 20 (or so), then the frequency is too slow (<3KHz).  If the timer value is between 12 and 20 inclusive,  then light an LED. ) Can you plz give me in form of code. 

I have been stuck on this for more than months and when i couldnot solve myself i am asking for help.

Thank you

george

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Sorry  sparrow2 and  avrcandies  i didnot understand what u really mean to say because i am new to programming. 

 

george

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

 

 i didnot understand what u really mean to say because i am new to programming.

 

You ABSOLUTELY should not try using any interrupts...you seem to be 100% starting at square zero...get something simple to work, then take it from there.

 

If you have trouble with the extremely simple scheme I proposed, you will bury yourself with a billion problems doing anything complex.  Start simple!

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

avrcandies wrote:

 

 i didnot understand what u really mean to say because i am new to programming.

 

You ABSOLUTELY should not try using any interrupts...you seem to be 100% starting at square zero...get something simple to work, then take it from there.

 

If you have trouble with the extremely simple scheme I proposed, you will bury yourself with a billion problems doing anything complex.  Start simple!

 

Maybe a simple blinking LED.

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Yes i have perfect square signal. I already use RC filter convert into voltage equivalent , read it by ADC pin and checked it and it works fine with that. But now i want to use the signal detect its frequency and if my inpu signal is of other freuency i want No output. Do you have any idea and suggesstion how to deal without Interrupts

george

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

George Babu wrote:
square signal
George Babu wrote:
read it by ADC pin
is it just me ?? surprisefrown

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Do you have any idea and suggesstion how to deal without Interrupt

Please see #17 & take it step by step...you may need to study some tutorials, there are many AVR "getting started" tutorials here (tutorials section).

 

Checking the pin would include whether it has toggled since the last check; each time it changes state from 0 to 1 is another count...you are looking for positive edges.  Later on, you can also add debouncing to overcome any noise pulses.

The "decision" is just determining if you got enough counts during the total time window for the desired freq range. 

Keep it simple, after each determination, start everything over.  That's enough to keep you experimenting.

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!