Källkod, microprocessorn (C)

/*****************************************************
Project : SpinLED
Version : 1.0
Date    : 2008-06-01
Author  : Sara Hedfors, Niclas Evestedt & Simon Berthilsson

Chip type           : ATmega16
Clock frequency     : 16.000 000 MHz
*****************************************************/

    #include <mega16.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <spi.h>

/******* funktioner, makron och konstanter *************************/

    // definera alternativ putcharfunktion:
    #define _ALTERNATE_PUTCHAR_

    // definera diverse hårdvaruberoende värden:
    #define LED_PER_KOLUMN 56
    #define BYTE_PER_KOLUMN (LED_PER_KOLUMN/8)
    #define KOLUMNS_PER_LAP 145 // VALBART (måste vara delbart med 5)
    #define IMAGE_SIZE_PX (LED_PER_KOLUMN*KOLUMNS_PER_LAP)
    #define IMAGE_SIZE_BYTE (IMAGE_SIZE_PX/8)
    #define CHAR_WIDTH 5
    #define NUM_PACKETS (IMAGE_SIZE_BYTE+2)     // håller reda på hur många data packets som vi ska
    #define NUM_TEXT_PACKETS (KOLUMNS_PER_LAP/CHAR_WIDTH+2+1)
    #define CLKSPEED 16000000
    #define BAUD 9600
    #define UBAUD (CLKSPEED/(16*BAUD) - 1)

    #define TEMPPOS 0 // plats i minnet där temp alltid läggs

    // definera specifika pinnar:
    #define SPI_MOSI PORTB.5
    #define SPI_SS PORTB.4
    #define SPI_CLK_MINNE PORTB.7
    #define SPI_CLK_LED PORTB.0
    #define LED_OUTPUT_DISABLE PORTD.6

    // definera tillstånd:
    #define IMAGE 0
    #define TEMP 1
    #define TEXT 2

    // metoder:
    void initHardware();       // Initierar processorn: Sätter in- respektive utportar,
                               // initialiserar timer 1 och 2, initialiserar interrupt-hanteringen,
                               // initialiserar UART-hanteringen samt initialiserar AD konverteraren
    void nextByte();           // Hanterar inkommande paket från UART-kommunikationen, med hjälp av
                               // metoden getchar, avkodar dem och sätter rätt tillsånd samt
                               // rotation. Om data är del i en bild anropas metoden putByte och om
                                 // del i en text anropas putchar. Metoden håller också koll på hur
                               // många paket som kommit.
    void putByte(unsigned int pos, unsigned char byte); // Med hjälp av metoden spi_writebyte skrivs
                               // datat i parametern byte till adressen pos i det externa minnet
    void putchar(char c);      // Med hjälp av metoden spi_writebyte skrivs tecknet i parametern c
                               // till det externa minnet (som text). En global variabel posPutchar
                               // håller koll på vilken adress tecknet ska skrivas till.
    void putTemp(int temp);    // Gör om parametern temp till en sträng, och skriver sedan med hjälp
                               // av putchar tecknen i strängen till det externa minnet. Dessutom
                               // läggs ett specialtecken, °C, till sist i strängen.
    int readTemp();            // Hämtar aktuell information från AD-omvandlaren och räkar om den
                               // till temperatur
    void spi_writebyte(unsigned char byte); // Tar parametern byte, delar upp den i bitar och
                              // skickar dessa bitar en och
                              // en till det externa minnet, samtidigt som metoden genererar
                              // klockpulser till minnet.

    // interrupts:
    interrupt [USART_RXC] void usart_rx_isr(void); // Mjukvaruinterrupt från den inbyggda UART-
                              // mottagaren när nytt paket anländer. Sätter variabeln newByte till
                              // 1 för att markera att nytt paket anlänt, samt spara data i uartData
    interrupt [EXT_INT0] void newLap(void); // Hårdvaruinterrupt från hallgivaren. Räknar ut
                              // föregående varvtid med hjälpa av timer 1, samt hur ofta en ny
                              // kolumn av bilden ska skiftas ut. Nollställer timer 2 och sätter
                              // dess compare match till den uträknade tiden. Här hanteras också
                              // eventuell rotation av bilden genom att flytta en pekare till
                              // bildens startposition framåt eller bakåt.
    interrupt [TIM2_COMP] void updateImage(void); // Mjukvaruinterrupt från timer 2. Hanterar
                              // utskiftningen av en kolumn med hjälp av metoden spi_writebyte.
                              // Generering av klockpulser till minnet och till skiftregisterna
                              // talar om hur många bitar som ska skiftas ut.

    // globala variabler:
    unsigned char state = TEMP;           // state anger vilket tillstånd
    unsigned char lapsPerRotation = 0x00; // vrider 1 px vart lapsPerRotation varv
    unsigned int posPutchar = 0;          // position  putchar använder (absolut plats i minnet där
                                          // putchar skriver för tillfället)
    unsigned int readPackets = 0;         // håller reda på hur många packets som vi redan läst in.
    unsigned int pointerWrite = 0;        // plats i minnet som det skrivs till för tillfället
                                          // (pekar på början av bilden)
    unsigned int pointerRead = 0;         // plats i minnet som det läses från för tillfället (pekar
                                          // på början av bilden)
    unsigned int pointer = 0;             // plats i minnet som det läses från för tillfället (pekar
                                          // på var exakt vi befinner oss i bilden)
    unsigned int counter = 0;             // håller koll på var vi befinner oss på varvet (fysiskt)
    unsigned char num_interrupts = 3;     // antalet interrupts som 8bitars timern måste cirkulera
                                          // genom innan dax att uppdatera (räknas ned varje
                                          //interrupt)
    unsigned char fix_num_interrupts = 3; //antalet interrupts som 8bitars timern måste cirkulera
                                          // genom innan dax att uppdatera (sätts 1 ggr/varv)
    unsigned char remainder;              // detta plus fix_num_interrupts*0xff motsvarar hur lång
                                          // tid en pixel i sidled varar
    unsigned char uartData;               // används för att spara det som hämtas från UART
    bit newByte = 0;                      // flagga om nytt UART-paket anlänt
    unsigned int error = 0;               // räknar antalet paket som anlänt utan att hunnit tagits
                                          // om hand om

    // globala konstanter:
    const unsigned int asciiToLEDConverter[94][5] = // asci-tabell som putchar använder sig av
   {{0x0000,0x0000,0x0000,0x0000,0},{0x0000,0x03fb,0x0000,0x0000,0},{0x0000,0x0300,0x0000,0x0300,0},
    {0x0048,0x03fe,0x0048,0x03fe,0},{0x0300,0x0300,0x00fe,0x0101,0x00c6},
    {0x0187,0x0198,0x0066,0x0386,0},{0x0019,0x0025,0x0025,0x0019,0},{0x0000,0x0380,0x0000,0,0},
    {0x0000,0x00fc,0x0102,0x0201,0},{0x0000,0x0201,0x0102,0x00fc,0},{0x0140,0x0080,0x0140,0x0000,0},
    {0x0020,0x0070,0x0020,0x0000,0},{0x0000,0x0003,0x0000,0x0000,0},{0x0020,0x0020,0x0020,0x0000,0},
    {0x0000,0x0003,0x0003,0x0000,0},{0x0003,0x001c,0x00e0,0x0300,0},{0x01fe,0x0201,0x0201,0x01fe,0},
    {0x0081,0x0101,0x03ff,0x0001,0},{0x0187,0x0219,0x0261,0x0181,0},{0x0102,0x0221,0x0251,0x018e,0},
    {0x03e0,0x0020,0x0020,0x03ff,0},{0x03c6,0x0221,0x0221,0x021e,0},{0x01fe,0x0211,0x0211,0x010e,0},
    {0x0300,0x0207,0x0238,0x03c0,0},{0x01de,0x0221,0x0221,0x01de,0},{0x01c2,0x0221,0x0221,0x01fe,0},
    {0x0000,0x0022,0x0000,0x0000,0},{0x0000,0x0023,0x0000,0x0000,0},{0x0010,0x0028,0x0044,0x0082,0},
    {0x0028,0x0028,0x0028,0x0028,0},{0x0082,0x0044,0x0028,0x0010,0},{0x0180,0x020d,0x0230,0x01c0,0},
    {0x003e,0x0041,0x005d,0x003d,0},{0x01ff,0x0210,0x0210,0x01ff,0},{0x03ff,0x0211,0x0211,0x01ee,0},
    {0x00fc,0x0102,0x0201,0x0201,0},{0x03ff,0x0201,0x0102,0x00fc,0},{0x03ff,0x0221,0x0221,0x0221,0},
    {0x03ff,0x0220,0x0220,0x0220,0},{0x01fc,0x0202,0x0211,0x021f,0},{0x03ff,0x0020,0x0020,0x03ff,0},
    {0x0201,0x03ff,0x0201,0x0000,0},{0x0206,0x0201,0x0201,0x03fe,0},{0x03ff,0x0030,0x00c8,0x0307,0},
    {0x03ff,0x0001,0x0001,0x0001,0},{0x03ff,0x01c0,0x01c0,0x03ff,0},{0x03ff,0x00e0,0x001c,0x03ff,0},
    {0x01fe,0x0201,0x0201,0x01fe,0},{0x03ff,0x0220,0x0220,0x01c0,0},{0x01fc,0x0202,0x0207,0x01fd,0},
    {0x01ff,0x0230,0x0228,0x01c7,0},{0x01ce,0x0221,0x0221,0x011e,0},{0x0200,0x03ff,0x0200,0x0200,0},
    {0x03fe,0x0001,0x0001,0x03fe,0},{0x03fc,0x0003,0x000c,0x03f0,0},{0x03fc,0x0007,0x000f,0x03fc,0},
    {0x03cf,0x0030,0x0030,0x03cf,0},{0x03e2,0x0021,0x0021,0x03fe,0},{0x0207,0x0219,0x0261,0x0381,0},
    {0x007f,0x0290,0x0090,0x007f,0},{0x027f,0x0090,0x0090,0x027f,0},{0x027e,0x0081,0x0081,0x027e,0},
    {0x0080,0x0100,0x0200,0x0180,0},{0x0001,0x0001,0x0001,0x0001,0},{0x0200,0x0100,0x0080,0x0000,0},
    {0x0012,0x0025,0x0025,0x001f,0},{0x03ff,0x0021,0x0021,0x001e,0},{0x001e,0x0021,0x0021,0x0012,0},
    {0x001f,0x0021,0x0021,0x03ff,0},{0x001e,0x0029,0x0029,0x001a,0},{0x0010,0x00ff,0x0110,0x0080,0},
    {0x0011,0x0029,0x0029,0x001e,0},{0x03ff,0x0010,0x0020,0x001f,0},{0x0020,0x00bf,0x0001,0x0000,0},
    {0x0002,0x0001,0x00bf,0x0000,0},{0x03ff,0x0008,0x0014,0x0023,0},{0x0200,0x03fe,0x0001,0x0000,0},
    {0x003f,0x0018,0x0008,0x001f,0},{0x003f,0x0010,0x0020,0x001f,0},{0x001e,0x0021,0x0021,0x001e,0},
    {0x001f,0x0028,0x0028,0x0010,0},{0x0010,0x0028,0x0028,0x001f,0},{0x0021,0x003f,0x0021,0x0010,0},
    {0x0012,0x0029,0x0025,0x0013,0},{0x0020,0x01ff,0x0021,0x0002,0},{0x003e,0x0001,0x0001,0x003f,0},
    {0x003f,0x0001,0x0006,0x0038,0},{0x003e,0x0003,0x0007,0x003e,0},{0x0033,0x000c,0x000c,0x0033,0},
    {0x0032,0x0009,0x0009,0x003e,0},{0x0023,0x0025,0x0029,0x0031,0},{0x0012,0x0025,0x00a5,0x001f,0},
    {0x0012,0x00a5,0x0025,0x009f,0},{0x001e,0x00a1,0x0021,0x009e,0}
    }; // specialtecken: $ är utbytt mot grader Celcius
       //                [ är utbytt mot Å
       //                \ är utbytt mot Ä
       //                ] är utbytt mot Ö
       //                { är utbytt mot å
       //                | är utbytt mot ä
       //                } är utbytt mot ö

/******* slut funktioner, makron, konstanter ***********************/

/******* funktioner ************************************************/

    void initHardware(void) // Initiera hårdvaran
    {
        #asm("cli")
        // Input/Output Ports initialization
        // Port A initialization
        // Func7=In | Func6=In | Func5=In | Func4=In | Func3=In | Func2=In | Func1=In | Func0=In ADC
        PORTA=0x00;
        DDRA=0x00;

        // Port B initialization
        // Func7=Out SPI CLK MINNE| Func6=In SPI MISO| Func5=Out SPI MOSI| Func4=Out SPI ~SS|
        // Func3=In | Func2=In | Func1=In | Func0=Out SPI LED
        PORTB=0x10;       // PORTB.4 = 1 => ~SS initialt 1
        DDRB=0xB1;

        // Port C initialization
        // Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out
        PORTC=0x00;
        DDRC=0xFF;

        // Port D initialization
        // Func7=Out | Func6=Out LED Output disable | Func5=Out | Func4=Out | Func3=Out |
        // Func2=In Hallmätare | Func1=Out UART transmit | Func0=In UART recieve
        PORTD=0x44;       // PORTD.2 = 1 => pullup-motstånd aktiverat
        DDRD=0xFA;

        // Timer/Counter 0 initialization
        // Clock source: System Clock
        // Clock value: Timer 0 Stopped
        // Mode: Normal top=FFh
        // OC0 output: Disconnected
        TCCR0=0x00;
        TCNT0=0x00;
        OCR0=0x00;

        // Timer/Counter 1 initialization
        // Clock source: System Clock/1024
        // Clock value: Timer 1 running
        // Mode: Normal top=FFFFh
        // OC1A output: Discon.
        // OC1B output: Discon.
        // Noise Canceler: Off
        // Input Capture on Falling Edge
        // Timer 1 Overflow Interrupt: Off
        // Input Capture Interrupt: Off
        // Compare A Match Interrupt: Off
        // Compare B Match Interrupt: Off
        TCCR1A=0x00;
        TCCR1B=0x05;  //divide clock by 1024 for timer1
        TCNT1H=0x00;
        TCNT1L=0x00;
        ICR1H=0x00;
        ICR1L=0x00;
        OCR1AH=0x00;
        OCR1AL=0x00;
        OCR1BH=0x00;
        OCR1BL=0x00;

        // Timer/Counter 2 initialization
        // Clock source: System Clock/1024
        // Clock value: Timer 2 running
        // Mode: clear OCR2 on compare match, TOP=OCR2
        // OC2 output: Disconnected
        ASSR=0x00;
        TCCR2=0x0F;
        TCNT2=0x00;
        OCR2=0xFF;

        // Timer(s)/Counter(s) Interrupt(s) initialization
        TIMSK=0x80;

        // External Interrupt(s) initialization
        // INT0: interrupt on falling edge
        // INT1: off
        // INT2: Off
        MCUCR=0x02;

        //General Interrupt Control Register set to
        //detect interrupt requests on PIN INT0
        GICR=0x40;

        // USART initialization
        // Communication Parameters: 8 Data, 1 Stop, No Parity
        // USART Receiver: On
        // USART Transmitter: On
        // USART Mode: Asynchronous
        // USART Baud rate: clk/16/baud-1
        // USART set to enable interrupt on recieve complete
        UCSRA=0x80;
        UCSRB=0x98;
        UCSRC=0x86;
        UBRRH = (unsigned char)(UBAUD>>8);
        UBRRL = (unsigned char)(UBAUD);

        // Analog Comparator initialization
        // Analog Comparator: Off
        // Analog Comparator Input Capture by Timer/Counter 1: Off
        ACSR=0x80;
        SFIOR=0x00;

        // ADC initialization
        // ADC Voltage Reference: AREF pin
        // ADC0 as single ended input
        // ADC frequency = XTAL / 2
        // ADC interrupt disabled
        // ADC Auto Trigger Source: None
        ADMUX=0x00;
        ADCSRA=0x80;

        //enable interrupts
        #asm("sei")

    } // end initHardware

    void nextByte() // läser byte från UART-bufferten
    {
        unsigned char rotation;

        if(readPackets==0)
        {       // paket nr 0:
                // bit 7:6 - state
                // bit 5:0 - rotationsinformation:
                //           bit5=1 => moturs, bit5=0 => medurs
                //           bit4:0 => rotationsfrekvens

                rotation = (uartData & 0x3F); // bitmask för att ta fram lapsperrotation
                state = uartData >> 6; // bitmask för att ta fram state

                if(state == TEMP){ lapsPerRotation = rotation; }
                else { readPackets++; }
        }
        else if(readPackets==1)
        {   // paket nr 1:
            // bit 7   - 0 => lägga ut befintlig bild som redan finns i minnet
            //           1 => skriva in ny bild i minnet
            // bit 6:0 - bildnummer

            if(!(uartData & 0x80)) // om bara lägga ut bild som redan finns i minnet
            {
                 readPackets = 0;
                 pointerRead = (uartData & 0x7F)*IMAGE_SIZE_BYTE; // hämtar bildnummer,
                                                  // konverterar till absolut adress i minnet
                 lapsPerRotation = rotation;
            }
            else // om vi bara ska skriva in ny bild i minnet
            {
                 pointerWrite = (uartData & 0x7F)*IMAGE_SIZE_BYTE; // hämtar bildnummer,
                                                  // konverterar till absolut adress i minnet
                 posPutchar = pointerWrite; // sätter posPutchar till absolut adress i minnet
            }
        }
        else if(state == IMAGE && readPackets < NUM_PACKETS)
        {
                putByte(pointerWrite + (readPackets-2), uartData);
                readPackets++;
        }
        else if(state==TEXT && readPackets < NUM_TEXT_PACKETS)
        {
                putchar(uartData);
                readPackets++;
        }
        else
        {
              readPackets = 0; // nytt set med data, nollställ readPackets och anropa metoden igen
              nextByte();
        }
    }

    void putByte(unsigned int pos, unsigned char byte) // skriver byte via SPI till minne
    {
        #asm("cli")
        SPI_SS = 0;             // initiatiera kommunikation genom att sätta ~SS låg

        spi_writebyte(0x06);    // op-kod för aktivera skriva till minne
        SPI_SS = 1;

          #asm("nop")

        SPI_SS = 0;
        spi_writebyte(0x02);
        spi_writebyte((unsigned char)(pos >> 8)); // skriv första delen av adressen
        spi_writebyte((unsigned char)(pos));      // skriv andra delen av aderssen
        spi_writebyte(byte);

          SPI_SS = 1;             // avsluta kommunikation genom att sätta ~SS hög
          #asm("sei")
    }

    void putchar(char c) // skriver tecken via SPI till minne
    {
        int i;
        int j;
        if (!(c < 0x7E && c > 0x1f)){ c = 0x20; } // om ogiltigt tecken, skriv space = 0x20

        for (i=0; i<CHAR_WIDTH; i++)
        {
             #asm("cli")
               SPI_SS = 0;                // initiatiera kommunikation genom att sätta ~SS låg

             spi_writebyte(0x06);       // op-kod för aktivera skriva till minne
             SPI_SS = 1;
             #asm("nop")
             SPI_SS = 0;

             spi_writebyte(0x02);                             // op-kod för skriva till minne
             spi_writebyte((unsigned char)(posPutchar >> 8)); // skriv första delen av adressen
             spi_writebyte((unsigned char)(posPutchar));      // skriv andra delen av adressen

               for (j=0; j<3; j++){ spi_writebyte(0x00); }      // skicka 3 byte nollor
               spi_writebyte((unsigned char)(asciiToLEDConverter[c-0x20][i] >> 8));// skicka översta
                                                                                 // delen av tecknet
               spi_writebyte((unsigned char)(asciiToLEDConverter[c-0x20][i]));     // skicka understa
                                                                                 // delen av tecknet
               for (j=0; j<2; j++){ spi_writebyte(0x00); }      // skicka 2 byte nollor

               SPI_SS = 1;             // avsluta kommunikation genom att sätta ~SS hög
               #asm("sei")
               posPutchar = posPutchar + BYTE_PER_KOLUMN;
        }
    }

    int readTemp() // hämtar aktuell temperatur
    {
        int temp;
        int temphel;
        int temprest;
        ADCSRA|=0x40;                   // Starta ADC genom att sätta bit 6 i ADCSRA till 1
        while ((ADCSRA & 0x10) == 0);   // Vänta på resultat
        ADCSRA|=0x10;                   // Cleara genom att sätta bit 4 i ADCSRA till 1
        temp = (ADCW)*11-2975;          // (ger 125 ggr temperaturen)
        temphel = temp/125;
        temprest = temp%125;
        if(temprest > 62){ return (temphel + 1); }
        return temphel;
    }

    void putTemp(int temp) // skriver temp till utenhet
    {
        unsigned int pos;
        char tempstr[4];
        itoa(temp, tempstr);

        posPutchar = TEMPPOS;

        for(pos=0; pos<13; pos++){ putchar(' '); } // lägg 13 tecken tomt

        if(tempstr[1] == 0) // ensiffrig temperatur
        {
               putchar(tempstr[0]); // lägg ut temperatur
               putchar(0x24);       // lägg till grader C
               for(pos=0; pos<(KOLUMNS_PER_LAP/CHAR_WIDTH-15); pos++){ putchar(' '); } // fyll på med
                                                                                     // tomt
        }
        else // tvåsiffrig temperatur
        {
               putchar(tempstr[0]); // lägg ut temperatur siffra 1
               putchar(tempstr[1]); // lägg ut temperatur siffra 2
               putchar(0x24);       // lägg till grader C
               for(pos=0; pos<(KOLUMNS_PER_LAP/CHAR_WIDTH-16); pos++){ putchar(' '); } // fyll på med
                                                                                     // tomt
        }
    }

    void spi_writebyte(unsigned char byte)
    {
        int i;
        for(i=7; i>=0; i--)
        {
            SPI_MOSI = (byte & ( (unsigned char)(1<<i) ));
            #asm("nop")
            SPI_CLK_MINNE = 1;    // skicka
            #asm("nop")
            SPI_CLK_MINNE = 0;
        }
    }


    void main(void)
    {
        int temp;
        int lasttemp = -1;
        unsigned int lasterror = 0;
        unsigned int lastReadPackets = 0;
        initHardware();

        while (1)
        {
                 while(error > lasterror)     // felhantering om ej hunnit läsa alla paket från UART
                {
                        if(readPackets == lastReadPackets && state == TEXT)
                        {
                                if(lastReadPackets == NUM_TEXT_PACKETS)
                                {
                                        readPackets = 0;
                                        lastReadPackets = 0;
                                }
                                else
                                {
                                        readPackets++;
                                        lastReadPackets++;
                                }
                        }
                        lasterror++;

                        if(error == 0xffff)
                        {
                                error = 0xffff - lasterror;
                                lasterror = 0;
                        }
                        newByte = 0;
                }
                if(newByte) // om UART:en skickat ny byte
                {
                        nextByte();
                        #asm("cli")
                        lastReadPackets = readPackets;
                        newByte = 0;
                        #asm("sei")
                }
                if(state == TEMP)
                {
                        temp = readTemp();
                        if (temp != lasttemp)
                        {
                                putTemp(temp);
                                lasttemp = temp;
                        }
                }

        } //end while(1)
    } // end main

/******* slut funktioner *******************************************/

/******* interrupts ************************************************/

    // USART mottagarens interrupt
    interrupt [USART_RXC] void usart_rx_isr(void)
    {
        if(newByte == 1) // om föregående byte inte klar
        {
                error++;
        }
        else
        {
                uartData = UDR;
                newByte = 1;
        }
    }


    // hårdvaruinterrupt varje nytt varv från hallmätare
    interrupt [EXT_INT0] void newLap(void)
    {
        static unsigned char lapcounter = 1;
        static unsigned int lastpointer = 0;
        unsigned int lastLapTime;
        unsigned int pixeltime;

        lastLapTime = TCNT1;    // läs varvtimern
        TCNT1 = 0x0000;         // nollställ varvtimern
        TCNT2 = 0x00;           // nollställ pixeluppdateringstimern

        pixeltime = lastLapTime/(KOLUMNS_PER_LAP+5);

        num_interrupts = pixeltime/0xFF; // Hur många gånger ska timern snurra runt innan dax för
                                         // uppdatering
        fix_num_interrupts = num_interrupts;
        remainder = pixeltime%0xFF;
        if(num_interrupts != 0){ OCR2=0xFF; }     // Sätt compare match till rätt sak
        else{ OCR2=remainder; }

        if (1 == (lapsPerRotation & 0x1F)) // om vi ska vrida två px
        {
            if(lapsPerRotation & 0x20) // om bit5=1 => sätt pointer till två "kolumner framåt"
                                       // => vrid motsols
            {
                if(lastpointer == (IMAGE_SIZE_BYTE - BYTE_PER_KOLUMN)){ pointer = BYTE_PER_KOLUMN; }
                else if(lastpointer == (IMAGE_SIZE_BYTE - 2*BYTE_PER_KOLUMN)){ pointer = 0; }
                else { pointer = lastpointer + 2*BYTE_PER_KOLUMN; }
                lastpointer = pointer;    // nollställ counter
            }
            else // om bit5=0 => sätt pointer till en två kolumner "bakåt" => vrid medsols
            {
                if(lastpointer == 0){ pointer = (IMAGE_SIZE_BYTE - 2*BYTE_PER_KOLUMN); }
                else if(lastpointer == BYTE_PER_KOLUMN){ pointer = (IMAGE_SIZE_BYTE -
                                                         BYTE_PER_KOLUMN); }
                else { pointer = lastpointer - 2*BYTE_PER_KOLUMN; }
                lastpointer = pointer;    // nollställ counter
            }
        }
        else if (lapcounter == ((lapsPerRotation-1) & 0x1F)) // om vi ska vrida en px
        {
            lapcounter = 1; // nollställ lapcounter
            if(lapsPerRotation & 0x20) // om bit5=1 => sätt pointer till en "kolumn framåt"
                                       // => vrid motsols
            {
                if(lastpointer == (IMAGE_SIZE_BYTE - BYTE_PER_KOLUMN)){ pointer = 0; }
                else { pointer = lastpointer + BYTE_PER_KOLUMN; }
                lastpointer = pointer;    // nollställ counter
            }
            else // om bit5=0 => sätt pointer till en kolumn "bakåt" => vrid medsols
            {
                 if(lastpointer == 0){ pointer = (IMAGE_SIZE_BYTE - BYTE_PER_KOLUMN); }
                 else { pointer = lastpointer - BYTE_PER_KOLUMN; }
                 lastpointer = pointer;    // nollställ counter
            }
        }
        else // om ingen rotation ska ske
        {
             if(lapsPerRotation & 0x1F != 0){ lapcounter++; }
             pointer = lastpointer;
        }
        counter = 0;            // nollställ kolumnräknaren
    }

    // mjukvaruinterrupt från timer 2
    interrupt [TIM2_COMP] void updateImage(void)
    {
         int i;

         // interrupt från timer 2. Vi ska uppdatera LED vart num_interrupt:e interrupt, eftersom en
         // ny kolumn ska skiftas ut mer sällan än vad timern räknar runt
         if(num_interrupts != 0)
         {
             if(num_interrupts == 1){ OCR2=remainder; }
             num_interrupts--;
         }
         else // om dags att skifta ut
         {
             // hanterar timer 2:s interrupt-återställning:
             TCNT2=0x00;
             num_interrupts = fix_num_interrupts;
             if(num_interrupts != 0){ OCR2=0xFF; }

             if(counter < KOLUMNS_PER_LAP) // om det finns kvar på bilden
             {
                 SPI_SS = 0;             // initiatiera kommunikation genom att sätta ~SS låg
                 spi_writebyte(0x03);    // op-kod för läsa från minne (dvs be minne skicka ut till
                                         // LED)
                 spi_writebyte((unsigned char)((pointerRead + pointer) >> 8)); // skriv första delen
                                                                               // av adressen
                 spi_writebyte((unsigned char)(pointerRead + pointer));        // skriv andra delen
                                                                               // av aderssen

                 LED_OUTPUT_DISABLE = 1;// släck alla LED under utskiftningen
                 for(i=0; i<57; i++)    // vänta 57 klockcykler => klockar ut 56 ggr på LED
                                        // (skiftregister "snor" en klockcykel)
                 {
                     SPI_CLK_MINNE = 1;  // skicka klockpuls till minne
                     SPI_CLK_LED = 1;    // skicka klockpuls LED (skiftregister)
                     #asm("nop")
                     SPI_CLK_MINNE = 0;
                     SPI_CLK_LED = 0;
                 }
                 LED_OUTPUT_DISABLE = 0; // tänd alla LED efter utskiftningen
                 SPI_SS = 1;             // avsluta kommunikation genom att sätta ~SS hög

                 // om bilden ej är slut, räkna upp pointer
                 if (pointer < IMAGE_SIZE_BYTE - BYTE_PER_KOLUMN){ pointer = pointer +
                                                                   BYTE_PER_KOLUMN; }
                 // om bilden är slut, nollställ pointer
                 else { pointer = 0; }
              }
              counter++; // räknar hur många gånger vi kommer hit per varv
         }
    }

/******* slut interrupts *******************************************/
toppen på sidan tillbaka till SpinLED-sidan tillbaka till förstasidan [Teknik och data]

Valid HTML 4.01!