I am currently working on a project where I am designing an embedded AVR system using ATmega88 as the controller.
I am trying to output a PWM signal and I want to control its duty cycle with a rotary encoder (using interrupts).
The PWM signal is outputting as intended, however the encoder inputs don't seem to be doing anything despite the functions added. So, assuming that my AVR and encoder boards are working correctly, what is wrong with my C code?
I am using PC4 and PC5 (PCINT12 and PCINT13) as my encoder inputs and I am trying to control a PWM signal at PD7. The IDE I am using is Microchip studio.
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <stdbool.h>
#include <stdio.h>
// headers
//#include "LEDs.h"
//#include "PWM.h"
//#include "Encoder.h"
unsigned char duty;
bool up;
int main(void) {
up = true;
duty = 0;
OCR0A = duty;
pin_init();
PWM_init();
interrupt_init();
PD7_on();
while(1) {
OCR0A = duty;
}
}
int pin_init() {
DDRD = 0xFF;
DDRC = 0x00;
return 1;
}
int PWM_init() {
//setting correct bits for the pwm waveform
TCCR0A |= (1<<COM0A1) | (1<<COM0A0) | (1<<COM0B1)| (1<<COM0B0) | (1<<WGM01)| (1<<WGM00);
//setting prescaler to 8
TCCR0B |= (1<< CS01);
return 1;
}
int interrupt_init() {
PCICR = (1 << PCIE1); //enabling pin change interrupts for group
PCMSK1 |= (1 << PCINT12) | (1 << PCINT13);
sei(); //setting global interrupts
return 1;
}
int PD7_on() {
PORTD = (1<<PD7);
return 1;
}
int PD7_swich() {
if(PORTD == (1<<PD7)) {
PORTD = (0 << PD7);
}else{
PORTD = (1 << PD7);
}
return 1;
}
int inc_duty() {
if(duty == 255) {
up = false;
}else if(duty == 0) {
up = true;
}
if(up) {
duty++;
}else {
duty--;
}
return 1;
}
ISR(PCINT1_vect, ISR_BLOCK) {
PD7_swich();
inc_duty();
}
Initialization code for the pin-change interrupt looks legit. Considering, this is a some test code, and you're not expecting it to handle the encoder rotations properly.
But it is not clear how electrical connections are made? Do you use external pull-up resistors? Because they are not enabled in the code.
Variable
dutyis being used in themain()and also being changed from the interrupt routine. Therefore it has to be markedvolatile. Otherwise the compiler probably will reuse the same value in the loop (inmain()) without reading actual value from memory.Probably, usage of pin-change interrupts is not the best way to handle encoders, because encoders are tend to bounce. You may have to implement some kind of debounce approach.