i do not unterstand why my code isnt working(doISR). What its supposed to do:
-there is a running light(6 LEDs) and 3 Buttons. I need to press the button at the right time(Button 1, if LED 1 or 2 is on....etc). if its correct: increase the speed, if not: reset.
i bet its a blunder, but i dont get it :)
void wait(void) {
while (!(TIFR1 & (1 << OCF1A))) // wait
;
TIFR1 |= (1 << OCF1A); // delete Interrupt flag
}
volatile bool ISRhasHappend = false;
ISR(PCINT0_vect) {
ISRhasHappend = true;
}
int main(void) {
OCR1A = 3125 - 1; //2 seconds
TCCR1B |= (1 << WGM12); //turn on CTC mode
TCCR1B |= (1 << CS12) | (1 << CS10); //Prescalemode 101 -> 1024 Takt
DDRB = (1 << PCINT5);
DDRC = 0x3f;
PCICR = 0x3f; //Pin Change Interrupt Control Register
PCMSK0 = (1 << PCINT0) | (1 << PCINT2) | (1 << PCINT4);
sei();
doRunningLight();
if (ISRhasHappend == true) {
doISR();
}
}
void doISR() {
//while timee >0
for(int x=3125;x>0;x=x-250){
//if LEDs 0+1 on, and button0 pressed ...etc
if ((PORTC & (0b00000011)) && (PINB & (1 << PINB0)) || (PORTC &
(0b00001100)) && (PINB & (1 << PINB2)) || (PORTC & (0b00110000)) &&
(PINB & (1 << PINB4))) {
//All led lights up
PORTC |= 0x3f;
wait();
//reduce timer if catched the light
OCR1A = x;
}
else {
//turn signal
for (int y = 1; y < 5; y++) {
PORTB ^= (1 << PCINT5);
wait();
}
//back to 3124 if failed
OCR1A = 3125 - 1;
}
}
ISRhasHappend = false;
}
void doRunningLight(){
while(1) {
for (int i = 0; i<6; i++){
PORTC |= (1<<i);
wait();
PORTC &= ~(1<<i);
}
}
}
The function doRunningLight() never returns, so the code that you wrote after it to check ISRhasHappend and call doIsr will never run. You will need to think of a different way to handle your events, probably without using blocking delay loops.
I would also question whether you actually need a pin-change interrupt. Button presses are slow enough that your microcontroller should be able to detect them by reading the pin in the main loop.
Related
I'm testing some things on a Attiny85 and thought about the best way to handle the interrupt rutine. I know it is bad to have a lot of code in the interrupt handler, but I'm uncertain of any other ways to do this. I want my main program to sleep and wake on PCINT, the PCINT comes from multiple pins (rotary encoder A, b & switch and a receiving UART) so I was thinking just having a lot of code in the handler.
The code to determining which pin caused the interrupt, would look like this
#include <avr/io.h>
#include <stdint.h> // has to be added to use uint8_t
#include <avr/interrupt.h> // Needed to use interrupts
volatile uint8_t portbhistory = 0xFF; // default is high because the pull-up
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
/*main program loop here */
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
/* PCINT0 changed */
}
if(changedbits & (1 << PB1))
{
/* PCINT1 changed */
}
if(changedbits & (1 << PB2))
{
/* PCINT2 changed */
}
}
And then ofc inside each of the if-statements in the interrupt handler, there would be code handling something, like this code, turning on the Timer0
TCNT0 = 0; // Set counter to 0
OCR0A = SERIAL_BIT_TIME; // Call timer interrupt in middle of first bit
position = 0; // Reset position and data
TIMSK |= 1 << OCIE0A; // Enable interrupt for compare register A (timer interrupt)
TIFR |= 1 << OCF0A; // Clear timer interrupt flag to prevent it jumping directly there
PCMSK &= ~(1 << SERIAL_RECEIVE); // Disable pin change interrupt
or with the switch input, the code inside the if-statement would be
if (lightState)
{
dali.transmit(ADDRESS, OFF);
lightState = 0;
}
else
{
dali.transmit(ADDRESS, ON);
lightState = 1;
}
Would this be a dumb solution?
volatile uint8_t flag;
int main(void)
{
DDRB &= ~((1 << DDB0) | (1 << DDB1) | (1 << DDB2)); // Clear the PB0, PB1, PB2 pin
// PB0,PB1,PB2 (PCINT0, PCINT1, PCINT2 pin) are now inputs
PORTB |= ((1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2)); // turn On the Pull-up
// PB0, PB1 and PB2 are now inputs with pull-up enabled
PCICR |= (1 << PCIE0); // set PCIE0 to enable PCMSK0 scan
PCMSK0 |= (1 << PCINT0); // set PCINT0 to trigger an interrupt on state change
sei(); // turn on interrupts
while(1)
{
gotosleep();
do
{
switch(flag)
{
case 1:
dosomething1();
break;
case 2:
dosomething2();
break;
case 3:
dosomething3();
break;
}
cli();
flag = 0;
sei();
}while(flag);
}
}
ISR (PCINT0_vect)
{
uint8_t changedbits;
changedbits = PINB ^ portbhistory;
portbhistory = PINB;
if(changedbits & (1 << PB0))
{
flag = 1;
}
if(changedbits & (1 << PB1))
{
flag = 2;
}
if(changedbits & (1 << PB2))
{
flag = 3;
}
}
I am trying to build a drum machine using an Atmega644. The drum machine will have 16 LED's which will show which 16th of the beat it is at. The user should be able to set the BPM and therefore the updating of the LED will be different for different BPM.
I have a 16 MHz Crystal set at XTAL1 and XTAL2. I used a FUSE calculator to write the FUSE bits to a "Full Swing Oscillator" and remove the internal clock divide 8. I then set up the TIMER0 to perform this task
#define F_CPU 16000000UL // 1MHz internal clock
unsigned int tempo = 250; // Default BPM of 120.
volatile unsigned int seq_timer = 0;
//set-up timer for 0.5 ms update
TIMSK0 = (1<<OCIE0A);
TCCR0A = (1 << WGM01) |(1<<WGM00);
TCCR0B = (0 << WGM02) | (0<< CS02) | (1 << CS01) | (1 << CS00); //divide by 64
OCR0A = 125;
ISR (TIMER0_COMPA_vect) {
if (seq_timer>0) {seq_timer--;}
}
//Update which 16th note we are at.
void step(void){
update_led();
step_number = step_number < 15 ? step_number +1 : 0;
}
//Shift the LED such that the LED corresponding to step_number is lit up.
void update_led(void) {
for (int j = 16; j>=0; j--)
{
if ((((1 << step_number))>>j) & 0x01) {
PORTD |= (1 << PD5); //Serial Input
}
else {
PORTD &= ~(1 << PD5);
}
PORTD |= (1 << PD4); //Read clock
PORTD &= ~(1<< PD4);
}
PORTD |= (1 << PD3); //Shift clock
_delay_ms(40);
PORTD &= ~(1 << PD3);
}
while (1)
{
if ((seq_timer == 0)) {
seq_timer = tempo;
step();
}
Step functions calls a "update_led()" function which light up the LED corresponding to the step_number. This should according to my calculations occur (16e6 / (64*250*125)) = 8 updates/sec. But instead it does 4 updates/sec.
Am I missing something crucial?
I am new to AVR C Programming, I am testing a simple PWM using 16-bit timer on Atmega328p Counter/Timers which is suppose to act as a dimmer to an LED.
My Code:
#define F_CPU 16000000UL
void initTimer();
int x = 1;
int n = 1000;
int main(void)
{
initTimer();
DDRB |= (1 << PB1)| (1 << PB2);
while(1)
{
x++;
if(x > 65) {
x = 1;
}
}
}
void initTimer() {
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
// used for TOP, makes for 50 Hz PWM
ICR1 = 40000;
OCR1A = n * x;
}
ISR(TIMER1_OVF_vect)
{
OCR1A = n * x;
}
Problem is that it doesn't display the dimming effect, the brightness of the LED stays constant as to whatever value I set for OCR1A (PB1) output pin initially, its suppose to change value as the interrupt happen but its just not doing this, this is suppose to be simple test what am I doing wrong?
Update:
As advice I enable the interrupts using the TIMSK1 register and SEI(), however still the same issue the LED brightness stays constant as to whatever the original value of OCR1A that was specified in the initTimer().
int main(void)
{
initTimer();
DDRB |= (1 << PB1)| (1 << PB2);
while(1)
{
x++;
if(x > 65) {
x = 1;
}
}
}
void initTimer() {
ICR1 = 40000;
OCR1A = n * x;
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
TIMSK1 |= (1 << ICIE1);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
sei();
}
ISR (TIMER1_COMPA_vect)
{
OCR1A = n * x;
}
Although I tried an alternative approach and that gives me the dimming affect:
int main(void)
{
initTimer();
DDRB |= (1 << PB1)| (1 << PB2);
while(1)
{
_delay_ms(20);
OCR1A = n * 4;
_delay_ms(20);
OCR1A = n * 8;
_delay_ms(20);
OCR1A = n * 15;
_delay_ms(20);
OCR1A = n * 25;
_delay_ms(20);
OCR1A = n * 1;
}
}
void initTimer() {
ICR1 = 40000;
OCR1A = n * x;
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
}
So it seems the problem is with the interrupts since PWM affect works but its just not working with the interrupt handler.
The first thing that jumps out at me is x and n should be volatile. You also should enable the interrupt in TIMSK0 register. Also enable interrupts by calling sei.
If I were you, I'd start with some know good sample code. The page I mentioned has a example that fires an interrupt every 4ms. Take that code and toggle the led on and off.
Another problem is you are changing x without regard to whether or not the isr was called. So in effect you will get a random x each time in the isr. This code is simple enough it might get stuck in a simple pattern. Instead move the setting of x to your isr.
Here is a good intro to avr timers: https://sites.google.com/site/qeewiki/books/avr-guide/timers-on-the-atmega328
ICR1 = 40000;
OCR1A = n * x;
TCCR1A = (1 << COM1A1) | (1 << COM1B1) | (1 << WGM11);
TCCR1B = (1 << WGM13) | (1 << WGM12) | (1 << CS11);
This is wrong, you need to configure TCCR1A and TCCR1B before initializing ICR1 and OCR1A. See this answer for more details.
On ATmega 32u4 I've got two timers. One is for measuring ticks between interrupts and second which counts 1/60 of number of ticks. I'm not sure I'm allowed what I'm doing and if that is correct. If you could tell me what is wrong I would greatfull.
void setup(){
EIMSK |= (1 << INT2); //INT2 enable
EICRA |= (1 << ISC21) | (1 << ISC20); //INT2 RISING EDGE
DDRD &= ~(1 << PD2); //PD0 (INT0)(3) as input
PORTD &= ~(1 << PD2); //PD0 pulldown
TCCR1B |= (1 << CS11); //prescaler 8
//TIMER3 - 1/60
TCCR3A |= (1 << WGM32); //CTC Mode
TCCR3B |= (1 << CS31); //prescaler 8
TIMSK3 |= (1 << OCIE3A); //compate interrupt enable
sei();
}
ISR(INT2_vect) {
TCNT3 = 0;
OCR3A = TCNT1 / 60;
TCNT1 = 0;
degree = 30;
}
ISR(TIMER3_COMPA_vect) {
Color * currentColor = &bColor;
if (degree == 0)
degree = 59;
else degree--;
if (degree == time.second)
currentColor = &sColor;
else if (degree == time.minute)
currentColor = &mColor;
else if (degree % 5 == 0 && degree / 5 == time.hour)
currentColor = &hColor;
//set pwm
RedReg = currentColor->Red;
GreenReg = currentColor->Green;
BlueReg = currentColor->Blue;
}
I am trying to initiate a timer with CTC and external interrupts that will count to 60 seconds and use a function to display the output to LEDs on an ATmega128. The function, as follows, will count all the way to the first iteration of the tens place when debugging, but on the next run-through the tens variable is reset to zero and I cannot understand why it is resetting. Can anyone see where I might have made an error?
#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>
#include <util/delay_basic.h>
volatile uint8_t passval = 0;
void display(uint8_t value);
int main(void)
{
DDRC = 0xFF; //PORTC output for two seven segment displays(tenths and ones place)
DDRD = 0x0F; //PORTD output for one seven segment display(tens place)
EICRA = ((1 << ISC01) | (1 << ISC00) | (1 << ISC11) | (1 << ISC10)); //Interrupt set to trigger on rising edge for PINA1...0
TCCR1B |= (1 << WGM12); //Sets CTC Mode
OCR1A = 24999; //Prescaler as 64 with a count of 25000
TCNT1 = 0; //Clears clock
TIMSK |= (1 << OCIE1A); //Enables interrupt
sei(); //Enable Global Interrupt
while (1)
{
TCCR1B |= ((1 << CS11) | (1 << CS10));
display(passval);
}
return 0;
}
void display(uint8_t value)
{
static uint8_t tenths, ones, tens;
tenths = value;
if (tenths > 0x09) //Rolls Over tenths place at 10
{
passval = 0x00;
tenths = 0x00;
ones++; //Advances ones place
if (ones > 0x09) //Rolls over ones places at 10
{
ones = 0x00;
tens++; //Advances tens place
if (tens > 0x06) //Rolls over tens place at 6
{
tens = 0x00;
}
}
}
PORTC = ((ones << 4) + tenths); //Display Output
PORTD = tens;
}
ISR (TIMER1_COMPA_vect) //Timer ISR
{
passval++; //Advance tenths place
}