Gast
#4142653
Hallo liebe Microcontroller Community, ich sitze nun seit mehreren Tagen an einem Projekt für mein Studium (Elektro-& Informationstechnik) bei dem ich einfach nicht weiter komme. Mit der Suchfunktion habe ich leider nicht das passende gefunden, da es ein eher spezielles Problem ist, welches ich nun genauer erläutern werde. Als Entwicklungsumgebung dient ein modifiziertes Eclipse welches auf einer Virtuellen Maschine unter Linux läuft. Das Programm wurde in C programmiert. Verwendete Hardware: ATmega128, STK500, AVR Dragon In diesem Projekt geht es um die Verwendung des ParallelIO und des ADC. Ich werde nun den Kommentierten Quellcode posten und dann erläutern, an welchen Stellen es Probleme macht. Über Hilfe wäre ich sehr dankbar, da ich momentan nicht weiter weiß woran es liegt und es unter Eclipse mit dem Debuger nicht so einfach ersichtlich ist, wo die Probleme auftauchen. *fett*Quellcode: *fett*Funktionen: /* * adc.c * * Created on: 26.05.15 * Author: ---- * */ //enthält alle Definitionen für den eingestellten Prozessor #include <avr/io.h> #include "adc.h" #include <util/delay.h> //////////////////////////////////////////////////////////// //Implementierung der Funktionen /*Schaltet den ADC ein und konfiguriert ihn mit den folgenden Einstellungen: *fs = 19,12kHz *Uref = 5,00V *Wandler-Ergebnis rechtsbündig *Kanal ADC0, Single Ended * *Paramter: keine *Rückgabe: keine */ void init_ADC(){ ADMUX|=(1<<REFS0); //Das Bit 6 des ADMUX Registers auf 1 setzen (Interne Spannungsreferenz 5V) ADMUX&=~(1<<ADLAR)|(1<<MUX4)|(1<<MUX3)|(1<<MUX2)|(1<<MUX1)|(1<<MUX0); //Die Bit's 5 bis 0 des ADMUX Registers auf 0 setzen (ADC0=>Kanal0 und ADLAR Rechtsbündig) //Eigentlich überflüssig, da Default Wert schon auf 0 ADCSRA|=(1<<ADEN); //ADC Einschalten (Bit 7 des ADCSRA Registers auf 1 setzen) ADCSRA|=(1<<ADPS2); //Prescaler auf 16 setzen ADCSRA&=~(1<<ADPS1)|(1<<ADPS0); //Eigentlich überflüssig, da Default Wert schon auf 0 } /*Setzt den Running-Modus und startet die Wandlung(Konversion) * *Paramter: mode *Rückgabe: keine */ void start_ADC(eADCRUNMODE mode){ if(mode==FREERUN){ //Freerunning-Modus aktivieren und die Konvertion starten ADCSRA|=(1<<ADFR); ADCSRA|=(1<<ADSC); } else if(mode==SINGLESHOT){ //Freerunning-Modus deaktivieren und die Konvertion starten ADCSRA&=~(1<<ADFR); //Single Conversation ADCSRA|=(1<<ADSC); } else{ ADCSRA&=~(1<<ADFR); //Single Conversation ADCSRA|=(1<<ADSC); } } /*Stoppt die Wandlung, indem sie den ADC in den Running-Modus "single shot" schaltet, *ohne eine neue Messung zu starten * *Paramter: keine *Rückgabe: keine */ void stop_ADC(){ ADCSRA&=~(1<<ADFR); //Freerunning-Modus deaktivieren => ADC stoppen } /*Wartet auf das Ende einer Wandlung(Polling des ADIF-Bits) und setzt dann das ADIF-Bit auf 0 durch setzen einer 1 im ADIF-Bit * *Paramter: keine *Rückgabe: keine */ void wait_ADC(){ while((ADCSRA & (1<<ADIF))==0); //Warte solange bis das Ergebnis !=0 ist (Bis Wandlung abgeschlossen) ADCSRA|=(1<<ADIF); //Rücksetzen des ADIF-Bits durch setzen einer 1 } /*Liest den gewandeltetn 10-Bit-Digitalwert aus und liefert ihn in der gewählten Auflösung zurück. * *Paramter: res *Rückgabe: result */ unsigned short read_ADC(eADCRES res){ unsigned short result=0; unsigned short result_low=0; unsigned short result_high=0; if(res==BIT10){ result_low = ADCL; // High- und Low-Teil auslesen result_high = ADCH; // 2 höchstwertige Bits immer als letztes auslesen! result=(result_high<<8)|result_low; // Beides zu 10 Bit Wert zusammenfügen return result; } else if(res==BIT8){ // 8-Bit-Ergebnis (höchstwertige 8 Bit) result_low = ADCL; // High- und Low-Teil auslesen result_high = ADCH; // 2 höchstwertige Bits immer als letztes auslesen! result=(result_high<<8)|result_low; // Beides zu 10 Bit Wert zusammenfügen result=result>>2; // Die zwei niederwertigsten Bits "rausschieben" return result; } else{ return result; //Im falle einer Fehleingabe 0 zurückgeben } } /*Lifert die niederwertigste Ziffer eines Wertes vom Typ unsigned long (z) als ungepackte BCD-Zahl * sowie den durch 10 geteilten Rest des Wertes (r)(über den Zeiger-Parameter value) * *Paramter: unsigned long* value Zeiger auf den zu konvertierenden Wert *Rückgabe: z */ unsigned char ulong2bcd_unpk(unsigned long* value){ if(*value !=0){ //Wenn die Eingabe ungleich 0 ist unsigned char z = *value%10; //Niederwertigstens Teil der Zahl in z speichern unsigned long r = (*value-z)/10; //Höherwertigen Teil der Zahl in r speichern value = &r; //Höherwertigen Teil im Übergabeparameter speichern! return z; //Niederwertigen Teil in Rückgabeparameter z zurückgeben } else{ //Sonderfall, wenn value = 0 return 0; } } /*Wandelt einen zweistelligen Wert(<100) vom Typ unsigned long in eine gepackte BDC-Zahl um * *Paramter: value *Rückgabe: result */ unsigned char ulong2bcd_pk(unsigned long value){ unsigned char low_nibble=0,high_nibble=0,result=0; //Lokale Variablen deklarieren und initialisieren if(value < 100){ //Wert MUSS kleiner als 100 sein! low_nibble=ulong2bcd_unpk(&value); //Bestimmen des niederwertigen Teils der Zahl und speichern in low_nibble, sowie //bestimmen des höherwertigen Teils und speichern in value high_nibble=(value<<4); //Den höherwertigen Teil der Zahl um 4 Stellen nach links verschieben (Max 9 = 00001001 => 10010000) result=high_nibble|low_nibble; //Den höherwertigen Teil ODER-Verknüpfen mit dem niederwertigeren Teil und speichern in Result return result; } else{ return 0xff; //Falls unzulässige Eingabe 0xff zurückgeben } } /*Beispiel: Zahl 83 wird in value übergeben *->low_nibble=ulong2bcd_unpk(&temp); *low_nibble = 3 = 0b00000011 *high_nibble = 8 = 0b00001000 *->high_nibble=(temp<<4); *high_nibble um 4 Bit nach Links verschieben = 0b10000000 *->result=high_nibble|low_nibble; *low_nibble und high_nibble ODER-Verknüpfen = 0b10000011 (1000 0011 = 8 3) */ /*rechnet einen Messwert(digital) in einen Spannungswert in V um und liefert diesen zurück. * Hinweis: Die Umrechnung erfolgt unter Berücksichtigung der Spannungsreferenz uref und der Aufkösung res des übergebenen Messwertes * *Paramter: value - Messwert(digital *Paramter: res - Auflösung des Messwerts *Paramter: uref - Spannungsreferenzwert des ADC (entspricht Spannung bei maximalem Messwert => 5V) *Rückgabe: result */ float ushort2Volt(unsigned short value, eADCRES res, float uref){ float result=0.0; //deklarieren und initialisieren von lokalen Variablen if(res==BIT8){ //Wenn Auflösung = 8Bit result=(float)((value*uref)/255); //Berechnung return result; } else if(res==BIT10){ //Wenn Auflösung = 8Bit result=(float)((value*uref)/1023); //Berechnung return result; } else{ return result; //Sonst 0.0 zurückgeben } } /*Beispiel: Potentiometer wird voll Aufgedreht (100%); res=8Bit * value = 255 * result = (255*5)/255 (result = 5.0 V */ *fett*Hauptprogramm: void main_03(void){ //Programm, dass beim Druck auf beliebige Taste eine Einzelmessung startet //und das Messergebnis (10Bit) in Volt (je eine Stelle vor dem Komma und eine Stelle //nach dem Komma, z.B. 4,3V) auf den LED's anzeigt. eADCRUNMODE mode=FREERUN; eADCRES res=BIT10; float value=0.0; //deklarieren und initialisieren der lokalen Variablen float uref=5.0; init_ADC(); //initialisieren des ADC start_ADC(mode); //Starten des ADC mit eingestelltem mode (hier FREERUN) MIT_initPorts_Ain_Bout(); //Port A wird für die Eingabe und Port B für die Ausgabe initialisiert while(1){ MIT_wait4key_A(); //Wartet auf einen beliebigen Tastendruck wait_ADC(); //Auf Abschluss der Wandlung warten value=ushort2Volt(read_ADC(res),res,uref); //Wandlungsergebnis als Volt zurückgeben value=value*10; //Für die Weiterverarbeitung mit 10 multiplizieren MIT_putByteLED_B(ulong2bcd_pk((long)value)); //Wert als gepackte BCD-Zahl auf Port B ausgeben } } /*Beispiel: read_ADC(res) ergibt einen Wert von 1023 (Regler 100%) * ushort2Volt gibt einen Wert von 5.0 zurück * 5.0 * 10 = 50 * ulong2bcd_pk ruft ulong2bcd_unpk auf um Einer und Zehnerstelle zu ermitteln und liefert dann eine gepackte BCD zahl * von 0101 0000 * Ausgabe dieser Zahl auf Port B *fett*Problemstellung: Leider bekomme ich nicht die richtigen Werte angezeigt. Für das triviale Beispiel bei 5V müssten LED 4 und 6 leuchten. Leider leuchten stattdessen LED 4 und 1, also 1.2V was murks ist. Ich bin schon zu festgefahren in dieser Funktion, dass ich den Fehler nicht erkenne. Die ushort2Volt arbeitet richtig. Es muss war bei der gepackten BCD Zahl konvertierung falsch laufen. Um Hilfe wäre ich sehr dankbar! Mit freundlichen Grüßen Benny