AVR-GCC. Software (bit banging) SPI (SPI με λογισμικό).

Είδαμε την δυνατότητα επικοινωνίας των AVR μέσω του διαύλου SPI που υλοποιείται εσωτερικά στο chip. Τι γίνεται όμως αν το chip μας δεν διαθέτει SPI ή αν χρειαζόμαστε έναν δεύτερο δίαυλο SPI; Ευτυχώς ο δίαυλος SPI είναι τόσο απλός που μπορούμε με σχετική ευκολία να τον υλοποιήσουμε εξ ολοκλήρου στο πρόγραμμά μας. Η μέθοδος αυτή ονομάζεται και Bit Banging

Σελίδα της Wikipedia για τον SPI.
Bit Banging.
Τεκμηρίωση του ATmega8.
Τεκμηρίωση του MCP4922.

Στο παρακάτω κύκλωμα ελέγχουμε έναν DAC (MCP4922) μέσω SPI ώστε να βγάζει στην έξοδο του διαδοχικά τάση 0,1,2,3 και 4 Volts.

Πρέπει να σημειώσουμε πως η ταχύτητα επικοινωνίας του διαύλου μας θα είναι αρκετά μικρότερη από αυτή του επιτυγχάνουμε με την χρήση του ενσωματωμένου διαύλου. Έτσι αν θέλουμε υψηλή ταχύτητα πρέπει να επιλέξουμε τον εσωτερικό δίαυλο του AVR.

#include <avr/io.h>
#include <util/delay.h>

/*Η παρακάτω δήλωση ελέγχει αν στον compiler έχουμε βάλει την παράμετρο F_CPU.
  Αν όχι, την περνά. */

#ifndef F_CPU
    #warning "H F_CPU den exei oristei 8a parei thn timh 4000000"
    #define F_CPU 4000000UL  //  Use unsigned long
#endif

#define LOW  0
#define HIGH 1

#define SPI_SCLK  PD5
#define SPI_DATA  PD6
#define SPI_CS    PD7

#define SPI_PORT  PORTD


#define SCLK_Toggle SPI_PORT |= (1<<SPI_SCLK); SPI_PORT &= ~(1<<SPI_SCLK);


void SPI_send(uint8_t value);


void SPI_send(uint8_t value){


    uint8_t i=0b10000000;  //128 Δεκαδικό.

    while(i!=0){

        // Σύγκριση του κάθε bit της value.
        if (value&i){

            SPI_PORT |= 1<<SPI_DATA;

        } else {

            SPI_PORT &= ~(1<<SPI_DATA);
        };

        SCLK_Toggle

            i=i>>1;  // Στο 1ο πέρασμα το i θα γίνει
                     // 0b01000000 στο 2ο 0b00100000
                     // κ.τ.λ. Μέχρι το 0b000000001
    };


}


/*
    Από την σελίδα 16 του MCP4922 ξέρουμε πως
    η τάση εξόδου είναι Vout = (DAC*G*Vref)/(2^n).
    Στην περίπτωση μας G=1 και n=12. DAC είναι η τιμή
    των 12 bit που στέλνουμε στο MCP4922. Αν θέλουμε
    για παράδειγμα 1 volt (1000 mV) στην έξοδο η τιμή
    του DAC θα είναι DAC = (4096*Vout)/Vref. Η τάση
    αναφορά μας Vref είναι 5 (5000 mV) volts. Οπότε
    DAC=820.
*/

int main(void){

    DDRD |= (1<<SPI_CS)|(1<<SPI_SCLK)|(1<<SPI_DATA);

    uint16_t dac;
    uint8_t i=0;

/*
    Στον παρακάτω βρόχο αυξάνουμε την
    τάση εξόδου κατά 1 volt σε κάθε πέρασμα
    όταν φτάσει στα 4 volt την μηδενίζουμε
    και αρχίζουμε πάλι.
*/
    while(1){

        dac=i*820;  // Υπολογισμένη τιμή για 1000 mVolts.

        SPI_PORT &= ~(1<<SPI_SCLK);   // Set SCLK low. CPOL=0.
        PORTD &= ~(1<<SPI_CS);        // Set the DAC chip select LOW

        SPI_send(0b01110000|((dac>>8)&0b00001111)); // Μάσκα για 4 πρώτα
                                                    // bit ελέγχου.
        SPI_send(dac);

        SPI_PORT |= (1<<SPI_CS);      // Sets the DAC chip select pin HIGH
                                      // and latches the new output data.

        i++;

        if (i==5) i=0;

        _delay_ms(3000);

    };

    return 0;
}

Advertisements
This entry was posted in AVR, Electronics and tagged , , , , , , . Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s