Timer1 Question

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

I can't seem to get my timer1 to enable on compare match to drive two motors. One at PD5 and one on PD6. It is driving me crazy. Please help.

 

ISR(TIMER1_COMPA_vect)

{

PORTD ^= (1<<PIND5);

}

 

ISR(TIMER1_COMPB_vect)

{

PORTD ^= (1<<PIND6);

}

 

// All initializations

void initialize_all()

{

sei();

 

DDRD = 0b11110100; //set the output pins to control the motors

DDRB = 0b00100001; //more motor control

PORTB = !(1<<PINB5); //onboard led off

PORTD |= (1<<PIND2); // SPIN FORWARD

PORTB |= (1<<PINB0); //SPIN FORWARD

 

TCCR1A = (1<<COM1A1) | (1 << COM1B1) | (1 << WGM13) | (0 << WGM12) | (0 << WGM11);

TCCR1B = (1 << WGM13) | (1 << WGM12) | (0 << CS11);

TCNT1 = 20000;

ICR1 = 20000;

OCR1A = 10000;

OCR1B = 10000;

TIMSK1 |= (1<<OCIE1A);

TIMSK1 |= (1<<OCIE1B);

}

This topic has a solution.
Last Edited: Tue. Dec 5, 2017 - 10:27 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

The way you have it set up, it will toggle a port pin once every timer cycle, and that will give you a fixed 50% duty cycle square wave at 1/2 of the timer's overflow frequency.

 

Assuming that you REALLY want PWM, use the hardware capability to set a port pin on overflow and clear it on compare. You do not  even need interrupts to do that. Hardware takes care of all of it for you. That MIGHT not be  on the pins you have chosen.

 

By the way, the EASY way to toggle a port pin by software is to do PIND |= (1<<PIND5); or similar. Setting a bit in the PIN register of a port will toggle it with newer AVRs (say, approximately Mega328 or newer).

 

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

Last Edited: Tue. Dec 5, 2017 - 08:49 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Moving. Nothing to do with Studio.

John Samperi

Ampertronics Pty. Ltd.

www.ampertronics.com.au

* Electronic Design * Custom Products * Contract Assembly

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

Thanks Jim, So im pretty new to this. How is using the hardware different from using the timer the way I have set up?

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

Just a caution:

I suggest that you get in the habit of NOT enabling interrupts (sei) until all of your initializations are complete.

Eventually, you may run into a situation that the interrupts occur before you are totally ready for them...

 

In this particular (simple) case, it is not necessary...

David (aka frog_jr)

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

 

How to properly post source code: http://www.avrfreaks.net/comment...

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include <string.h>
#include "uart.h"
#include "lcd_lib.h"
#include <asf.h>
#include <avr/interrupt.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <stdio.h>
#include <avr/sleep.h>
#include <inttypes.h>
#include <math.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>

volatile uint16_t dutyCycleA;
volatile uint16_t dutyCycleB;
volatile uint16_t freqCycle;

// ADC variables
volatile unsigned int Ain;
volatile int AinLow;
volatile int voltageLeft;
volatile int voltageCenter;
volatile int voltageRight;
volatile float Voltage;
char VoltageBuffer[10];
uint8_t data;

volatile int sensorL = 0;
volatile int sensorC = 0;
volatile int sensorR = 0;

volatile int lapCounter = 0;

#define ON 1
#define OFF 0

char lcdBuffer[17]; // LCD display buffer

// File stream for UART. Used for Transmission to demonstrate the fprintf function.
//FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

void convertADC()
{
	// Convert A to D
	ADCSRA |= (1<<ADSC);
	// Wait until this conversion is completed
	while((ADCSRA & (1<<ADSC)));
}

void readSensors()
{
	ADMUX = 0b10000010;
	convertADC();
	Ain = (1<<ADCL); // First read lower byte
	Ain |= (ADCH<<8); // Then read upper byte
	voltageLeft = Ain;
	if (voltageLeft >= 769) sensorL = ON;
	if (voltageLeft < 769) sensorL = OFF;
	
	ADMUX = 0b10000011;
	convertADC();
	Ain = (1<<ADCL); // First read lower byte
	Ain |= (ADCH<<8); // Then read upper byte
	voltageCenter = Ain;
	if (voltageCenter >= 769) sensorC = ON;
	if (voltageCenter < 769) sensorC = OFF;
	
	ADMUX = 0b10000110;
	convertADC();
	Ain = (1<<ADCL); // First read lower byte
	Ain |= (ADCH<<8); // Then read upper byte
	voltageRight = Ain;
	if (voltageRight >= 769) sensorR = ON;
	if (voltageRight < 769) sensorR = OFF;
	 
}
void printSensorValues()
{
	dtostrf(voltageLeft, 3, 0, lcdBuffer);
	printf(lcdBuffer);
	printf(" \n");

	dtostrf(voltageCenter, 3, 0, lcdBuffer);
	printf(lcdBuffer);
	printf(" \n");
	
	dtostrf(voltageRight, 3, 0, lcdBuffer);
	printf(lcdBuffer);
	printf(" \n");
	
		dtostrf(sensorL, 1, 0, lcdBuffer);
		printf(lcdBuffer);
		dtostrf(sensorC, 1, 0, lcdBuffer);
		printf(lcdBuffer);
		dtostrf(sensorR, 1, 0, lcdBuffer);
		printf(lcdBuffer);
	printf(" \n");
}

ISR(TIMER0_COMPA_vect)
{
	//PORTD ^= (1<<PIND5);
}

ISR(TIMER0_COMPB_vect)
{
	//PORTD ^= (1<<PIND6);
}

// All initializations
void initialize_all()
{
	sei();
	// Initialize UART
	//uart_init();                         // Initialize UART
	//stdout = stdin = stderr = &uart_str; // Set File outputs to point to UART stream
	//printf("Hello! \n");

	DDRD = 0b11110100; //set the output pins to control the motors
	DDRB = 0b00100001; //more motor control
	PORTB = !(1<<PINB5); //onboard led off
	PORTD |= (1<<PIND2); // SPIN FORWARD
	PORTB |= (1<<PINB0); //SPIN FORWARD
			
	// ADC Setup
	ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Set ADC prescaler to 128
	ADCSRA |= (1<<ADEN); // Enable ADC circuit
	
	TCCR0A =  (1 << COM0A1) | (1<<COM0B1);// | (1 << WGM11);
	TCCR0B = (1 << WGM01)  |(1 << WGM00)|(1<<CS01);
	TCNT0 = 0;
	OCR0A = 254;
	OCR0B = 254;
	TIMSK0 |= (1<<OCIE0A);
	TIMSK0 |= (1<<OCIE0B);
	TIFR0 |= (1<<OCF0B) | (1<<OCF0A);
	
}

int main(void)
{	
	initialize_all(); //initialize all
	while(1)
	{
		readSensors();
		//printSensorValues();
		
		if (sensorL == 0 && sensorC == 1 && sensorR == 0)
		{
			OCR0A = 254;
			OCR0B = 254;
		}
		if (sensorL == 0 && sensorC == 0 && voltageRight >= 765)
		{
			OCR0A = 254;
			OCR0B = 1;
		}
		if (sensorL == 1 && sensorC == 0 && sensorR == 0)
		{
			OCR0A = 1;
			OCR0B = 254;

		}
		if (sensorL == 1 && sensorC == 1 && sensorR == 1)
		{
			PORTB &= ~(1<<PINB5);
		}
	}
}

Ok. So I am trying to use Timer 0 to PWM my motors for a redbot but I can't get it to work. The data sheet says PD5 and PD6 are OCOB and OCOA respectively.

This reply has been marked as the solution. 
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Got it!

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <inttypes.h>
#include <string.h>
#include "uart.h"
#include "lcd_lib.h"
#include <asf.h>
#include <avr/interrupt.h>
#include <ctype.h>
#include <stdio.h>
#include <time.h>
#include <stdio.h>
#include <avr/sleep.h>
#include <inttypes.h>
#include <math.h>
#include <avr/wdt.h>
#include <avr/eeprom.h>

volatile uint16_t dutyCycleA;
volatile uint16_t dutyCycleB;
volatile uint16_t freqCycle;

// ADC variables
volatile unsigned int Ain;
volatile int AinLow;
volatile int voltageLeft;
volatile int voltageCenter;
volatile int voltageRight;
volatile float Voltage;
char VoltageBuffer[10];
uint8_t data;

volatile int sensorL = 0;
volatile int sensorC = 0;
volatile int sensorR = 0;

volatile int lapCounter = 0;

#define ON 1
#define OFF 0

char lcdBuffer[17]; // LCD display buffer

// File stream for UART. Used for Transmission to demonstrate the fprintf function.
FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW);

void convertADC()
{
	// Convert A to D
	ADCSRA |= (1<<ADSC);
	// Wait until this conversion is completed
	while((ADCSRA & (1<<ADSC)));
}

void readSensors()
{
	ADMUX = 0b10000010;
	convertADC();
	Ain = (1<<ADCL); // First read lower byte
	Ain |= (ADCH<<8); // Then read upper byte
	voltageLeft = Ain;
	if (voltageLeft >= 769) sensorL = ON;
	if (voltageLeft < 769) sensorL = OFF;
	
	ADMUX = 0b10000011;
	convertADC();
	Ain = (1<<ADCL); // First read lower byte
	Ain |= (ADCH<<8); // Then read upper byte
	voltageCenter = Ain;
	if (voltageCenter >= 769) sensorC = ON;
	if (voltageCenter < 769) sensorC = OFF;
	
	ADMUX = 0b10000110;
	convertADC();
	Ain = (1<<ADCL); // First read lower byte
	Ain |= (ADCH<<8); // Then read upper byte
	voltageRight = Ain;
	if (voltageRight >= 769) sensorR = ON;
	if (voltageRight < 769) sensorR = OFF;
	 
}
void printSensorValues()
{
	dtostrf(voltageLeft, 3, 0, lcdBuffer);
	printf(lcdBuffer);
	printf(" \n");

	dtostrf(voltageCenter, 3, 0, lcdBuffer);
	printf(lcdBuffer);
	printf(" \n");
	
	dtostrf(voltageRight, 3, 0, lcdBuffer);
	printf(lcdBuffer);
	printf(" \n");
	
		dtostrf(sensorL, 1, 0, lcdBuffer);
		printf(lcdBuffer);
		dtostrf(sensorC, 1, 0, lcdBuffer);
		printf(lcdBuffer);
		dtostrf(sensorR, 1, 0, lcdBuffer);
		printf(lcdBuffer);
	printf(" \n");
	dtostrf(TCNT0, 3, 0, lcdBuffer);
	printf(lcdBuffer);
	printf(" \n");	
}

ISR(TIMER0_COMPA_vect)
{
	PORTD ^= (1<<PIND5);
}

ISR(TIMER0_COMPB_vect)
{
	PORTD ^= (1<<PIND6);
}

// All initializations
void initialize_all()
{
	sei();
	// Initialize UART
	uart_init();                         // Initialize UART
	stdout = stdin = stderr = &uart_str; // Set File outputs to point to UART stream
	//printf("Hello! \n");

	DDRD = 0b11110100; //set the output pins to control the motors
	DDRB = 0b00100001; //more motor control
	PORTB = !(1<<PINB5); //onboard led off
	PORTD |= (1<<PIND2); // SPIN FORWARD
	PORTB |= (1<<PINB0); //SPIN FORWARD
			
	// ADC Setup
	ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // Set ADC prescaler to 128
	ADCSRA |= (1<<ADEN); // Enable ADC circuit
	
	PORTD |=(1<<DDD5) |(1<<DDD6);
	TCCR0A =  (1 << COM0A1) | (1<<COM0B1)|(1 << WGM00);
	TCCR0B = (1 << WGM01)  | (1<<CS01);
	TCNT0 = 0;
	OCR0A = 128;
	OCR0B = 128;
	TIMSK0 |= (1<<OCIE0A);
	TIMSK0 |= (1<<OCIE0B);
	//TIFR0 |= (1<<OCF0B) | (1<<OCF0A);
	
}

int main(void)
{	
	initialize_all(); //initialize all
	while(1)
	{
		readSensors();
		//printSensorValues();
		//_delay_ms(1000);
		
		if (sensorL == 0 && sensorC == 1 && sensorR == 0)
		{
			OCR0A = 100;
			OCR0B = 100;
		}
		if (sensorL == 0 && sensorC == 1 && sensorR == 1)
		{
			OCR0A = 50;
			OCR0B = 100;
		}
		if (sensorL == 0 && sensorC == 0 && sensorR == 1)
		{
			OCR0A = 20;
			OCR0B = 100;

		}
		if (sensorL == 1 && sensorC == 1 && sensorR == 0)
		{
			OCR0A = 100;
			OCR0B = 50;
		}
		if (sensorL == 1 && sensorC == 0 && sensorR == 0)
		{
			OCR0A = 100;
			OCR0B = 1;
		}
		if (sensorL == 1 && sensorC == 1 && sensorR == 1)
		{
			PORTB &= ~(1<<PINB5);
		}
	}
}

 

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

You can suit yourself on the below...

 

While I don't see where the AVR model is mentioned, I'm guessing some kind of Arduino given the 16MHz clock speed.  Those modern AVR models have a pin-toggle feature by writing to the PIN register, as opposed to the RMW that is in your ISRs.  Perhaps not a problem right now, but it >>will<< cause you head scratching if you start to do port D manipulation in the mainline.

 

But why do the ISR and toggle at all?  Put the output channels on the OC0x pins, and let the timer do the toggling.

You can put lipstick on a pig, but it is still a pig.

I've never met a pig I didn't like, as long as you have some salt and pepper.