I have problems with interrupts to read the encoder 2 motors and display on hyperterminal.
20MHz ATmega168 use and engines EMG30 (approx. 170RPM).
The algorithm is simple, has the position to 90 degrees and then returns
the problem is after a while, shows erroneous data transmission.
We would appreciate to help me. (attached code and picture)
// atmega168
#define F_CPU 20000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <stdlib.h> //strtol atoi abs labs
#include <stdio.h> //printf()
#define sbi(var, mask) ((var) |= (uint8_t)(1 << mask))
#define cbi(var, mask) ((var) &= (uint8_t)~(1 << mask))
#define FORWARD1() cbi(PORTD, 3); sbi(PORTD, 2)
#define BACKWARD1() cbi(PORTD, 2); sbi(PORTD, 3)
#define FORWARD2() cbi(PORTD, 7); sbi(PORTD, 4)
#define BACKWARD2() cbi(PORTD, 4); sbi(PORTD, 7)
void init_usart0(unsigned int baud)
{
UBRR0 = (unsigned int)(F_CPU/16/baud-1); // Set Baudrate
UCSR0C = 3 << UCSZ00; // Character Size 8 bit
UCSR0B |= _BV(RXEN0) | _BV(TXEN0); // Receiver and Transmitter Enable
}
static int uart_putchar(char c, FILE *stream)
{
if (c == '\n') uart_putchar('\r', stream);
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
return 0;
}
static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL,_FDEV_SETUP_WRITE);
volatile int count_m1 = 0; //contador de Motor1
volatile int count_m2 = 0; //contador de Motor1
volatile unsigned char last_cha1; //ultimo estado del CHA
volatile unsigned char last_chb1; //ultimo estado del CHB
volatile unsigned char last_cha2; //ultimo estado del CHA
volatile unsigned char last_chb2; //ultimo estado del CHB
void config_init(void)
{
init_usart0(9600); // Inicio del USART0
stdout = &mystdout; // Configura printf con usart_putchar
DDRB |= 1 << DDB5; // Led Green placa Down
// Encoder de M1 y M2
DDRC &= ~( 1 << DDC0 | 1 << DDC1 ); // INPUT CHB1:A1
DDRC &= ~( 1 << DDC2 | 1 << DDC3 ); // INPUT CHB2:A2
PORTC |= 1 << PC0 | 1 << PC1; // Res Pull-Up CHB1:A1
PORTC |= 1 << PC2 | 1 << PC3; // Res Pull-Up CHB2:A2
// Control de Motores M1 M2
DDRD |= 1 << DDD2 | 1 << DDD3; // OUTPUT SM11:12
DDRD |= 1 << DDD4 | 1 << DDD7; // OUTPUT SM21:22
// PWM M1(OCR0A) y M2(OCR0B)
DDRD |= 1 << DDD6 | 1 << DDD5; // OUTPUT OCR0A:B D6:5
// Tipo de onda
TCCR0A |= 1 << WGM01 | 1 << WGM00; // Mode Fast PWM
TCCR0B |= 0 << WGM02; // Mode Fast PWM
// Compare Match Output A:B Mode
TCCR0A |= 1 << COM0A1 | 0 << COM0A0; // Set OC0A on Compare Match (normal)
TCCR0A |= 1 << COM0B1 | 0 << COM0B0; // Set OC0B on Compare Match (normal)
// Pre-Escaler Clk_pwm = F_CPU/pre-escaler = 0.305 KHz
TCCR0B |= 1 << CS02 | 0 << CS01 | 0 << CS00; // pre-escaler = 256
// Duty de PMW M1 y M2
OCR0A = 0;
OCR0B = 0;
DDRB |= 0 << DDB0; // INPUT Start Down
PORTB |= 1 << PB0; // Res Pull-Up Start Down
// PCINT para encoder CHA1:B1 PCINT8:9 CHA2:B2 PCINT10:11
PCICR |= 1 << PCIE1; // Habilita PCINT1_vect -> PCINT14:8 (PC6:0)
PCMSK1 |= 0x0F; // Habilita cada PCINT11:8
last_cha1 = (PINC >> 1) & 1; //PC1
last_chb1 = (PINC >> 0) & 1; //PC0
last_cha2 = (PINC >> 3) & 1; //PC3
last_chb2 = (PINC >> 2) & 1; //PC2
// Borra los Flag de los PCINTx, en caso fueran
// antepuestas por cualquier razon
PCIFR |= 1 << PCIF1;
sei();
}
ISR(PCINT1_vect)
{
unsigned char cha1 = (PINC >> 1) & 1; //PC1
unsigned char chb1 = (PINC >> 0) & 1; //PC0
unsigned char cha2 = (PINC >> 3) & 1; //PC3
unsigned char chb2 = (PINC >> 2) & 1; //PC2
// CHA = 0 and CHB = 1
// MOTOR 1
if (cha1 != last_cha1)
{
last_cha1 = cha1;
if ((last_cha1 == last_chb1) ^ 0) count_m1 -=1;
else count_m1 +=1;
}
if (chb1 != last_chb1)
{
last_chb1 = chb1;
if ((last_cha1 == last_chb1) ^ 1) count_m1 -=1;
else count_m1 +=1;
}
// MOTOR 2
if (cha2 != last_cha2)
{
last_cha2 = cha2;
if ((last_cha2 == last_chb2) ^ 0) count_m2 -=1;
else count_m2 +=1;
}
if (chb2 != last_chb2)
{
last_chb2 = chb2;
if ((last_cha2 == last_chb2) ^ 1) count_m2 -=1;
else count_m2 +=1;
}
}
int main (void)
{
config_init(); // Configuracion de puertos
while(PINB & (1<<PINB0)) {_delay_ms(10);} // Button
OCR0A = 80;
OCR0B = 80;
FORWARD1();
FORWARD2();
sei();
PORTB = (1 << PB5); // Led green On
while (1) {
if (count_m1 < -90)
{
FORWARD1();
}
else if (count_m1 > 90)
{
BACKWARD1();
}
// Motor 2
if (count_m2 < -90)
{
FORWARD2();
}
else if (count_m2 > 90)
{
BACKWARD2();
}
printf("\n%d, %d",count_m1, count_m2);
_delay_ms(10);
}
return 0;
}
Imagen: