Search code examples
carduinoavrdude

C Blink and Interrupt project


I am stuck and do not know where to start.

Modify the sample code you were given to make it function just like the assembly code written previously.

The LED on B0 should flash continuously. Whenever you press the switch, the other 3 LEDs shoul d display the next number in the counting sequence 0 -> 7 and then wrap back around to 0.

-Sample code that needs to be modified C Blink and interrupt code

#include <avr/io.h>
#define F_CPU 1000000UL  // 1 MHz
#include <util/delay.h>
#include <avr/interrupt.h>

ISR(PCINT2_vect) { /* Run every time there is a change on button */
        if (PIND & (1 << PIND0)) {    
            PORTD |= (1<<PORTD1);
            PORTD |= (1<<PORTD2);
            PORTD |= (1<<PORTD3);
            _delay_ms(250);
            PORTD &= ~ (1<<PORTD1);
            PORTD &= ~ (1<<PORTD2);
            PORTD &= ~ (1<<PORTD3);
        }
            }

void initInterrupt0(void) {
    PCICR |= (1 << PCIE2); /* set pin-change interrupt for D pins */
    PCMSK2 |= (1 << PCINT16); /* set mask to look for PCINT18 / PD2 */
    sei(); /* set (global) interrupt enable bit */
}

int main(void)
{
    // -------- Inits --------- //
    DDRB |= (1<<DDB0);
    DDRD |= (1<<DDD1);
    DDRD |= (1<<DDD2);
    DDRD |= (1<<DDD3); 
    initInterrupt0();
    /* Blink code */
    while (1) 
    {
        _delay_ms(200);
        PORTB |= (1<<PORTB0);
        _delay_ms(1000);
        PORTB &= ~ (1<<PORTB0);
        _delay_ms(1000);
    }
}

code from assembly

.include "m328pdef.inc"

    .def mask = r16 ; mask register
.def ledR = r17 ; led register
.def oLoopR = r18 ; outer loop register
.def iLoopRl = r24 ; inner loop register low
.def iLoopRh = r25 ; inner loop register high

.equ oVal = 71 ; outer loop value
.equ iVal = 2048 ; inner loop value

    .org 0x0000
    rjmp start
.org 0x000A
rjmp Interupt
   

;start of blinking

start:
sbi DDRD, 1
sbi DDRD, 2
sbi DDRD, 3
cbi DDRD, 0


; interupt requirments
   sei
   lds r16, PCMSK2
   ori r16, (1<<PCINT16)
   sts PCMSK2, r16
   lds r16, PCICR
   ori r16, (1<<PCIE2)
   sts PCICR, r16

   clr r20
 
    clr ledR ; clear led register
ldi mask,(1<<PINB0) ; load 00000001 into mask register
out DDRB,mask ; set PINB0 to output

 blink:
eor ledR,mask ; toggle PINB0 in led register
out PORTB,ledR ; write led register to PORTB

ldi oLoopR,oVal ; initialize outer loop count

oLoop: ldi iLoopRl,LOW(iVal) ; intialize inner loop count in inner
ldi iLoopRh,HIGH(iVal) ; loop high and low registers

iLoop: sbiw iLoopRl,1 ; decrement inner loop registers
brne iLoop ; branch to iLoop if iLoop registers != 0

dec oLoopR ; decrement outer loop register
brne oLoop ; branch to oLoop if outer loop register != 0

rjmp blink ; jump back to start

;interupt code

Interupt :
sbic   PIND, 0
rjmp   skip       ; if interupt has just happened skip everything under this
inc    r20
andi   r20, 0b00000111
mov    r19, r20
lsl    r19
in     r18, PIND
cbr    r18, 0b00001110
or     r18, r19
out    PortD, r18
skip:
reti
    

Solution

  • General problems:

    • All switches must be debounced. If not done in hardware with an RC filter, then it must be done in software.
    • Enabling an interrupt on a GPIO input connected to a switch is a major mistake for the above reason. You can do so if you know what you are doing, but it's probably not a task for a beginner. See https://stackoverflow.com/a/23559522/584518.
    • You cannot have 250ms busy-delays inside an ISR, that's completely senseless. In this case it will screw up the blinking frequency of the LED and block the button from triggering.