www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Atmega16 und spi bus


Autor: baggio (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo kann jemand mir helfen ich muss mit Atmega 16 spi bus und ADW max 
146 umgehen.
Die Analoge werte eines Kanals des ADW(MAX146)werden uber spi bus mit 
dem ATmega 16 kommuniziert und an PC über RS232 gesendet.Die Analoge 
werte können durch das Poti auf der SPI-Platine des Evaluationsboards 
verändert werden.
 Ich habe folgendes Programm zur Verfügung.


//polli2_max146.c
//Verwendung des MAX146/147 (8 Kanäle, 12 Bit AD-Wandler)
//auf ext. Erweiterungsboard (Polli_V2_spi)
//zum Einlesen von analogen Daten über SPI
//und Ausgabe über RS 232 zum PC
//Taste 1 (int0) unterbricht SPI-Aktivität kurzzeitig, LEDs blinken
//Compiler: CodeVision 1.24.8
//
#include <mega16.h>
#include <stdio.h>
#include <spi.h>
#include <delay.h>


// MAX147 externe Spannungsreferenz [mV]       - nicht für MAX 146 erf.
#define VREF 2500

// MEGA 16    SPI-Leitungen für MAX146/147

#define NCS PORTB.4     // MAX146-Pin 18        ---> 13    CON 1 auf 
Erweiterungsboard
#define DOUT PINB.5     // MAX146-Pin 17        ---> 14
                        // SCLK MAX146 Pin 19   ---> 19
                        // DOUT MAX146 Pin 15   ---> 15


union adcu
          {
          unsigned char byte[2];
          unsigned int word;
          };


interrupt [EXT_INT0] void ext_int0_isr(void)      // Taste 1 auf 
Polliboard
{
        PORTD=0x60;                               //Leds ein-aus
        delay_ms (1000);
        PORTD=0x00;
        delay_ms(1000);
}

void uartinit(void)
{
        UCSRA=0x00;
        UCSRB=0x58;            //TXD enable, 8 Bit              bei 
90S8535 UCR
        UBRRL=0x33;           //9600 Baud bei 8 MHz Quarz       bei 
90S8535 UBRR
}

// Funktion f. eine AD-Wandlung - Wert zurück
unsigned int max147_read(unsigned char kan)
{
        union adcu adc_data;
        unsigned char TB1, RB1,  RB2, RB3;
        //control byte f. Max 147
        //TB1=0x8F;     Kan. 0 ..., externe clock f. AD
        TB1=0x8e;       //Start, Kan. 7, unipolar,
                        //single ended, interne clock für AD
        if      (kan==0)
                TB1=0x8e;
        else if (kan==1)
                TB1=0xce;
        else if (kan==2)
                TB1=0x9e;
        else if (kan==3)
                TB1=0xde;
        else if (kan==4)
                TB1=0xae;
        else if (kan==5)
                TB1=0xee;
        else if (kan==6)
                TB1=0xbe;
        else if (kan==7)
                TB1=0xfe;


        NCS=0;          //Chip Select f. Max 147
        delay_us(100);
        SPDR=TB1;   RB1=spi(0);
        //SPDR=0x00;
        RB2=spi(0);
        //SPDR=0x00;
        RB3=spi(0);
        NCS=1;          //deselect f. MAX147
        delay_us(10);

        adc_data.byte[1]=RB2;
        adc_data.byte[0]=RB3;
        return(adc_data.word>>3)&0xfff;

}

void main(void)
{
unsigned  n1, n2, n3;      // Ergebnis der AD-Wandlung
float mittelw;       // Einstellung f. printf auf float with precision
unsigned char kan;



        // Input/Output Ports initialization
        // Port A
        DDRA=0x00; PORTA=0x00;
        DDRD=0x60;                      //Leds


        // Port B
        // the /SS pin is set as an output
        // with level 1, it's required by
        // the SPI to work in master mode
        //------        mega16     ------
        //
        //PB.7=SCLK     PB.6=MISO       PB.5=MOSI       PB.4=SS
        //
        DDRB=0xB0;      PORTB=0xB0;

        // Port C
        DDRC=0x00;   PORTC=0x00;


        uartinit();


        // SPI initialization des uP 90S8535
        // SPI Type: Master
        // SPI Clock Rate: 921.6 kHz=3.6864 MHz/4
        //
        // SPI Clock Phase: Cycle Half
        // SPI Clock Polarity: Low
        // SPI Data Order: MSB First
        SPCR=0x50;

        //putsf("\rMAX147 Demo\n");
        //putsf("\r***********************************************\n");

        delay_us(100);


        while (1)
        {
        /*
        for (kan=0; kan<8; kan++)
                {
                n=max147_read(kan);
                printf("Kanal= %2u  N=%4u U=%4umV\r\n",kan, n,(unsigned) 
((long) n*VREF/4096));
                }
        */
        kan=0;
        n1=max147_read(kan);
        printf("\r%4u\r", (unsigned) ((long) n1*VREF/4096));

        n2=max147_read(kan);
        printf("%4u\r", (unsigned) ((long) n2*VREF/4096));

        n3=max147_read(kan);
        printf("%4u\r", (unsigned) ((long) n3*VREF/4096));
        mittelw= (float) ((n1+n2+n3)/3);
        printf("------> Mittelw: %f\r",  mittelw*VREF/4096);


        delay_ms(500);
        GICR=0x40;
        MCUCR=0x02;
        #asm("sei")



        };
}

ich muss das Programm ändert so ab,dass die Datenerfassung in Abstand 
von einer Sekunde erfolgt.

Kan jemand mir helfen da ich weiß genau nicht wo ich das programm 
modifizieren muss und die lösung zu haben.

: Gesperrt durch Moderator
Autor: Joachim K. (minifloat)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Entweder du lässt den Contoroller im Mainloop hängen und entfernst die 
For-Schleife mit der Messung. Die For Schleife wird in eine 
void-Funktion ausgelagert. Dann nimmst du einen der 3 Timer wie im 
AVR-GCC-Tutorial als Interruptquelle, der dann die For-Schleife, die in 
die Mess-Funktion ausgelagert wurde, einmal pro Sekunde auführt.

Oder du änderst da delay_ms auf 1000(nicht so schön).

Vorteil der Interrrupt-Methode: Der Prozessor wird durch das Delay nicht 
blockiert und kann noch viele andere schöne Dinge erledigen, an die du 
bis jetzt noch nicht gedacht hast. Vielleicht eine Menüführung und 
Display, wo man die Zeit zwischen 2 Messungen einstellen kann.

Dir ist bewusst, dass das Rechnen mit Floatvariablen auf diesem 
Prozessor nicht in Hardware gegossen ist? Das verschwendet Rechenzeit 
und Flashspeicher. Such mal nach "Festkommaarithmetik".

mfg mf

Autor: baggio (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich bedanke mich sehr für ihre Antwort, es ist wirklich sehr nette von 
Ihnen.
Das problem ist dass ich mich nich gut kennnt mit dem Mikrocontroller, 
da ich Medizintechnik,studiert. Es ist ein projektarbeit, und jede muss 
aussuchen,aber ohne grundkenntnis es ist schwer ich habe schon so viel 
zeit darüber gemacht ohne Fortsetzung.
Please können sie das teile des geänderten Progr. beispielweise 
schreiben.
Es kann mich vielleich helfen.
Noch eine frage was muss ich verstehen und welche unterlagen brauche ich 
und wo muss ich achten.
Noch vielen dank.

Autor: baggio (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Noch eine Frage Minifloat wenn si das Prog verstehen.
Warum werden die variable n1,n2,und n3 initialisiert.
Was macht das Prog im mainloop genau.

vielen dank Minifloat.

Autor: Peter Diener (pdiener) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Warum werden die variable n1,n2,und n3 initialisiert.

>unsigned  n1, n2, n3;      // Ergebnis der AD-Wandlung

Diese Variablen werden nicht initialisiert. Das müssen sie auch nicht, 
da sie bei der ersten Verwendung einen definierten Wert erhalten, 
nämlich den vom AD-Wanlder am Kanal, der in der Variablen kan steht:

>n1=max147_read(kan);

// Auswählen von Kanal 0
        kan=0;
// Einlesen des AD Kanals 0 in n1
        n1=max147_read(kan);
// Wagenrücklauf am Terminal, Ausgeben von der Spannung aus n1 ohne Nachkommastellen als Zahl der Länge 4, Wagenrücklauf im Terminal
        printf("\r%4u\r", (unsigned) ((long) n1*VREF/4096));

// Einlesen des AD Kanals 0 in n2
        n2=max147_read(kan);
// Ausgeben von der Spannung aus n2 ohne Nachkommastellen als Zahl der Länge 4, Wagenrücklauf im Terminal
        printf("%4u\r", (unsigned) ((long) n2*VREF/4096));

// Einlesen des AD Kanals 0 in n3
        n3=max147_read(kan);
// Ausgeben von der Spannung aus n3 ohne Nachkommastellen als Zahl der Länge 4, Wagenrücklauf im Terminal
        printf("%4u\r", (unsigned) ((long) n3*VREF/4096));
// Ausrechnen des Mittelwerts von n1, n2, n3
        mittelw= (float) ((n1+n2+n3)/3);
// Ausgeben der mittleren Spannung der letzten 3 Messungen an AD Kanal 0
        printf("------> Mittelw: %f\r",  mittelw*VREF/4096);

// 500 ms CPU belasten, ohne etwas zu tun
        delay_ms(500);
// Irgendeinen Interrupt einschalten, dazu Datenblatt lesen!
        GICR=0x40;
// Datenblatt lesen!
        MCUCR=0x02;

Interrupts soll man immer so kurz wie möglich halten, das hier ist 
folglich überhaupt keine gute Idee:
interrupt [EXT_INT0] void ext_int0_isr(void)      // Taste 1 auf
Polliboard
{
        PORTD=0x60;                               //Leds ein-aus
        delay_ms (1000);
        PORTD=0x00;
        delay_ms(1000);
}

(Normale) Taster sollte man gar nicht an Interrupts anschließen, das ist 
ganz schlechter Stil. So macht man das besser:
http://www.mikrocontroller.net/articles/AVR-GCC-Tu...

Genauso schlecht ist das:
        GICR=0x40;
        MCUCR=0x02;

Hier weiß niemand, ohne das Datenblatt zu lesen, was da genau passiert. 
Entweder man kommentiert das ordentlich, oder man verwendet die 
aussagekräftigen Bitnamen aus dem Datenblatt statt der Werte als 
Hexzahl.
Nicht nur, dass es unübersichtlich ist, es ist auch noch gefährlich, 
ganze Register zu beschreiben, ohne, dass man den Überblick hat, was die 
einzelnen Bits daraus machen.
Ich bezweifle, dass die Mehrzahl an Programmieren auf Anhieb und ohne 
Datenblatt wissen, welche Funktion die Bits haben, die hier gerade alle 
auf Null gesetzt werden:
MCUCR=0x02;

Ein Programm sollte man immer so schreiben, dass es ein anderer 
Programmierer ohne weiteres verstehen kann, ohne dass er dazu ein 
Datenblatt braucht.

Und wenn man solche Sachen wie mit MCUCR macht, dann sollte man ganz 
genau als Kommentar dazuschreiben, warum das genau so gemacht wird.

Grüße,

Peter

Autor: baggio (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Vielen Dank für Ihre Hilfe PDIENER,wie ich schon vorher gesagt hast ich 
habe keine ahnung wo ich das programm ändert muss um die Aufgabestellung 
zu lösung.
Ich füge einfach mal das Datenblatt von Mega16 bei, die seite 32 erklärt 
was macht der Register  MCUCR und ab seite 14 erklärt für den register 
GICR.
ich muss das Programm ändert so ab,dass die Datenerfassung in Abstand
von einer Sekunde erfolgt.
Ich füge ein auch die datablatt für MAX146.
BITTE HILFE SONST BIN ICH TOD MIT DIESEM PROJETARBEIT.
Noch vielen Dank,dass sie Interess haben.
Noch frage wenn ich das progr-. mit avr compiliere, kommt ssolche 
fehlermeldung:
../ffffm.c:12:20: error: mega16.h: No such file or directory
../ffffm.c:14:17: error: spi.h: No such file or directory
In file included from ../ffffm.c:15:

../ffffm.c:35: error: 'EXT_INT0' undeclared here (not in a function)
../ffffm.c:35: error: expected '=', ',', ';', 'asm' or '__attribute__' 
before 'void'
../ffffm.c: In function 'max147_read':
../ffffm.c:77: error: expected ';' before numeric constant
was solche genau machen um die Fehler zu beheben.
Vielen Dank nochmal für ihre Antwort.

Autor: riki (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> BITTE HILFE SONST BIN ICH TOD MIT DIESEM PROJETARBEIT.
  hui


Na dann geh doch einfach zu Deinem Kollegen oder Kommilitone hin und 
drück ihm nen 100€-Schein in die Hand und sag: Mach mal bitte ;)

... oder Du änderst die 500 von delay_ms(500); in 1000 und guckst dass 
Dus erst mal kompiliert bekommst.

Ansonsten, ruhe bewahren und tief durchatmen. So grau ist die Welt nun 
auch wieder nicht ;-)

Autor: baggio (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Hallo kann jemand mir helfen ich muss mit Atmega 16 spi bus und ADW max
146 umgehen.
Die Analoge werte eines Kanals des ADW(MAX146)werden uber spi bus mit
dem ATmega 16 kommuniziert und an PC über RS232 gesendet.Die Analoge
werte können durch das Poti auf der SPI-Platine des Evaluationsboards
verändert werden.
 Ich habe folgendes Programm zur Verfügung.


//polli2_max146.c
//Verwendung des MAX146/147 (8 Kanäle, 12 Bit AD-Wandler)
//auf ext. Erweiterungsboard (Polli_V2_spi)
//zum Einlesen von analogen Daten über SPI
//und Ausgabe über RS 232 zum PC
//Taste 1 (int0) unterbricht SPI-Aktivität kurzzeitig, LEDs blinken
//Compiler: CodeVision 1.24.8
//
#include <mega16.h>
#include <stdio.h>
#include <spi.h>
#include <delay.h>


// MAX147 externe Spannungsreferenz [mV]       - nicht für MAX 146 erf.
#define VREF 2500

// MEGA 16    SPI-Leitungen für MAX146/147

#define NCS PORTB.4     // MAX146-Pin 18        ---> 13    CON 1 auf
Erweiterungsboard
#define DOUT PINB.5     // MAX146-Pin 17        ---> 14
                        // SCLK MAX146 Pin 19   ---> 19
                        // DOUT MAX146 Pin 15   ---> 15


union adcu
          {
          unsigned char byte[2];
          unsigned int word;
          };


interrupt [EXT_INT0] void ext_int0_isr(void)      // Taste 1 auf
Polliboard
{
        PORTD=0x60;                               //Leds ein-aus
        delay_ms (1000);
        PORTD=0x00;
        delay_ms(1000);
}

void uartinit(void)
{
        UCSRA=0x00;
        UCSRB=0x58;            //TXD enable, 8 Bit              bei
90S8535 UCR
        UBRRL=0x33;           //9600 Baud bei 8 MHz Quarz       bei
90S8535 UBRR
}

// Funktion f. eine AD-Wandlung - Wert zurück
unsigned int max147_read(unsigned char kan)
{
        union adcu adc_data;
        unsigned char TB1, RB1,  RB2, RB3;
        //control byte f. Max 147
        //TB1=0x8F;     Kan. 0 ..., externe clock f. AD
        TB1=0x8e;       //Start, Kan. 7, unipolar,
                        //single ended, interne clock für AD
        if      (kan==0)
                TB1=0x8e;
        else if (kan==1)
                TB1=0xce;
        else if (kan==2)
                TB1=0x9e;
        else if (kan==3)
                TB1=0xde;
        else if (kan==4)
                TB1=0xae;
        else if (kan==5)
                TB1=0xee;
        else if (kan==6)
                TB1=0xbe;
        else if (kan==7)
                TB1=0xfe;


        NCS=0;          //Chip Select f. Max 147
        delay_us(100);
        SPDR=TB1;   RB1=spi(0);
        //SPDR=0x00;
        RB2=spi(0);
        //SPDR=0x00;
        RB3=spi(0);
        NCS=1;          //deselect f. MAX147
        delay_us(10);

        adc_data.byte[1]=RB2;
        adc_data.byte[0]=RB3;
        return(adc_data.word>>3)&0xfff;

}

void main(void)
{
unsigned  n1, n2, n3;      // Ergebnis der AD-Wandlung
float mittelw;       // Einstellung f. printf auf float with precision
unsigned char kan;



        // Input/Output Ports initialization
        // Port A
        DDRA=0x00; PORTA=0x00;
        DDRD=0x60;                      //Leds


        // Port B
        // the /SS pin is set as an output
        // with level 1, it's required by
        // the SPI to work in master mode
        //------        mega16     ------
        //
        //PB.7=SCLK     PB.6=MISO       PB.5=MOSI       PB.4=SS
        //
        DDRB=0xB0;      PORTB=0xB0;

        // Port C
        DDRC=0x00;   PORTC=0x00;


        uartinit();


        // SPI initialization des uP 90S8535
        // SPI Type: Master
        // SPI Clock Rate: 921.6 kHz=3.6864 MHz/4
        //
        // SPI Clock Phase: Cycle Half
        // SPI Clock Polarity: Low
        // SPI Data Order: MSB First
        SPCR=0x50;

        //putsf("\rMAX147 Demo\n");
        //putsf("\r***********************************************\n");

        delay_us(100);


        while (1)
        {
        /*
        for (kan=0; kan<8; kan++)
                {
                n=max147_read(kan);
                printf("Kanal= %2u  N=%4u U=%4umV\r\n",kan, n,(unsigned)
((long) n*VREF/4096));
                }
        */
        kan=0;
        n1=max147_read(kan);
        printf("\r%4u\r", (unsigned) ((long) n1*VREF/4096));

        n2=max147_read(kan);
        printf("%4u\r", (unsigned) ((long) n2*VREF/4096));

        n3=max147_read(kan);
        printf("%4u\r", (unsigned) ((long) n3*VREF/4096));
        mittelw= (float) ((n1+n2+n3)/3);
        printf("------> Mittelw: %f\r",  mittelw*VREF/4096);


        delay_ms(500);
        GICR=0x40;
        MCUCR=0x02;
        #asm("sei")



        };
}

ich muss das Programm ändert so ab,dass die Datenerfassung in Abstand
von einer Sekunde erfolgt.

Kan jemand mir helfen da ich weiß genau nicht wo ich das programm
modifizieren muss und die lösung zu haben.
Die Daten Blatte habe ich beigefügt.
Ich bedanke mich.

Autor: Düsendieb (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
baggio schrieb:
> delay_ms(500);

Da.

Autor: baggio (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke Düsendieb,
was soll ich machen mit dem delay
nur da muss ich das Prog ändern oder gibt noch was.
Danke Düsendieb.

Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.