Moin, ich verwende den DAC LTC1257 der über drei Ports angesteuert wird. Mit dem Threads: Beitrag "LTC1257 - Problem mit Ansteuerung (SPI)" Beitrag "LTC1257 Low Level Routinen" habe ich mich bereits auseinandergesetzt. Irgendwie funktioniert das bei mir nicht wirklich. Laut den Threads soll es darum gehen einen Sägezahn zu erzeugen. Das funktioniert nicht wirklich bei mir. Ich verwende den AT90CAN128 der extern über ein 16MHz Quarz getaktet wird. Im Anhang befindet sich eine Ossidarstellung von der derzeitigen Funktion. Hier noch der Auszug vom Quelltext: //---------------------------------------------------------------------- ----------- // Digital Analog Wandler Initialisieren #define DACOUT PORTC #define DACIN PORTC #define DACLOAD(LEVEL) DACOUT = (LEVEL) ? (DACIN & ~_BV(PC0)):(DACIN | _BV(PC0)) #define DACCLK(LEVEL) DACOUT = (LEVEL) ? (DACIN & ~_BV(PC1)):(DACIN | _BV(PC1)) #define DACDATA(LEVEL) DACOUT = (LEVEL) ? (DACIN & ~_BV(PC2)):(DACIN | _BV(PC2)) #define LATCHTIMING 0xFF /* spend some time to the latch */ #define LEV_LOW 0 #define LEV_HIGH 1 inline void DAC_init(void); inline void DAC_send(unsigned int data); /* * Low level initialisation routine for LTC1257. */ inline void DAC_init(void) { /* Initial port/pin state */ DACCLK(LEV_LOW); /* clock pin low -> idle */ DACLOAD(LEV_HIGH); /* load pin high -> idle */ } //---------------------------------------------------------------------- ----------- // Wert an Digital Analog Wandler uebertragen inline void DAC_send(unsigned int data) { volatile unsigned char bitctr = 0; for(bitctr = 0; bitctr < 0x0C; bitctr++) { DACCLK(LEV_LOW); if (data & 0x800) /* output MSB (bits [11..0]!) */ DACDATA(LEV_HIGH); else DACDATA(LEV_LOW); data <<= 1; /* shift next bit to MSB */ DACCLK(LEV_HIGH); /* -> await rising edge */ _delay_us(4); } DACCLK(LEV_LOW); /* clock pin low -> idle */ DACLOAD(LEV_LOW); /* load pulled low -> output */ for (bitctr = 0; bitctr < LATCHTIMING; bitctr++) ; DACLOAD(LEV_HIGH); /* load pulled high -> idle */ } Gruß Mike
- Hast du die Pins alle als Ausgang gschaltet? - Arbeiten die DACLOAD, DAC_CLK etc. -Macros nicht invertiert (d.h. "DACDATA(LEV_LOW)" setzt den Pin)? - Das LATCHTIMING solltest du, laut LTC-Datenblatt, ersetzen können durch
1 | NOP(); |
2 | NOP(); |
3 | NOP(); |
4 | // NOP() ist dabei sowas:
|
5 | #define NOP() asm volatile ("nop\n\t")
|
- Evtl. muss du vor "DACCLOCK(LEV_HIGH)" noch mal warten (_delay_us(0.5), oder so) - Der gepostete Code erzeugt GANZ sicher keinen Sägezahn ;) - Poste noch mal: - was nicht geht - was du erwartest - welche Fehlermeldungen du bekommst hth. Jörg
Hallo, nur als Hinweis: Du kannst den LTC1257 auch an den Hardware-SPI hängen. CPOL=1 war glaube ich passend. Allerdings müssen die Daten dann links bündig liegen, die ersten 4 Bit fallen dann "hinten" raus und mit /LOAD werden am Ende der 2 SPI Ausgaben die richtigen 12Bit übernimmen. Gruß aus Berlin Michael
Moin, schonmal vielen dank für die Info. - was nicht geht wenn ich mir den erzeugten Sägezahn auf dem Ossciloskop anschaue ist dieser wohl erkennbar, wird aber durch zahlreiche nebenschwingungen überlagert. - was du erwartest als Übung möchte ich erstmal das Projekt mit dem Sägezahn vollenden, um den Umgang mit diesem DAC zu lernen, anschließend möchte ich ein über den ADC Wandler eingelesenes Signal über den DAC ausgeben, ebenfalls zur Übung. - welche Fehlermeldungen du bekommst Ich verwende das AVR Studio 4 und zum programmieren einen AVR ISP MKII. Der Compiler gibt keine Fehlermeldung und keine Warnung aus. Die Ports von dem µC (AT90CAN128) habe ich als Ausgang definiert mit DDRC = (1 << PC0) | (1 << PC1) | (1 << PC2); Ich werde das morgen mit NOP() versuchen, habe heute Abend keine Zeit mehr. Ob die Macros invertiert laufen weiß ich nicht, ich werde dieses mal mit einer LED testen. Den LTC1257 kann ich Hardwaretechnisch nicht an den SPI Port hängen, da es sich bereits um eine fertige Platine handelt, die ich derzeitig nicht mehr ändern kann. MFG Mike
Moin, so, habe es hinbekommen, ich kann eine saubere Sägezahnspannung erzeugen. Nur wie muß ich die vom ADC übergebenen Werte an den LTC1257 übergeben, damit das Analog eingelesene Signal wieder dargestellt wird. Bis jetzt habe ich aus dem ADC Wert eine Spannung berechnet mit folgender Formel: Vin= ADC_Wert*Referenzspannung/1023 Gruß Mike
Benutzt du den internen ADC? Dann musst du die Werte 0-1023 auf 0-4095 abbilden (geht wohl am besten mit "ADC * 4" (oder ADC<<2 falls der Compiler das nicht rafft))...
Moin, ja, ich verwende den internen ADC. Die Funktion ist auch gegeben, habe mit einer fixen Spannung getestet. Bei 2,56V ergibt sich ein ADC Wert von 1023, und bei 0 V von 0. Nun habe ich diesen Wert mit 4 multipliziert, aber das Signal am DAC ist nicht annähernd das vom ADC. Vielleicht hilft es weiter. ich möchte ein Audiosignal mit ~10khz Bandbreite übertragen. vor dem ADC habe ich einen dementsprechenden Tiefpassfilter, den selbigen am Ausgang vom DAC. Das Eingangssignal am ADC verschiebe ich noch mit einer angelegten Spannung von 1V in den positiven Wertebereich. Gruß Mike
> Vielleicht hilft es weiter. ich möchte ein Audiosignal mit ~10khz > Bandbreite übertragen. Ich bin nicht so fit in der Theorie, aber das wird schwierig, der interne ADC macht nur max. 15kSpS (200kHz/13.5) bei voller Auflösung. Das Übertragen ist ja nicht so kompliziert: einfach alle 1/10kHz Sekunden (Timer!) einen neuen Wert an den DAC schicken. hth. Jörg
@ Jörg X. (Gast) >Das Übertragen ist ja nicht so kompliziert: einfach alle 1/10kHz >Sekunden (Timer!) einen neuen Wert an den DAC schicken. Oder noch besser per ADC-Complete Interrupt im Free Running mode. MFG Falk
Moin, vielen dank für die prompten Antworten, Der Free Running Modus wird doch mit dem Bit ADCSRB |= (1 << ADTS0); aktiviert, so habe ich es aus dem Datenblatt des AT90CAN128 verstanden. Nur wie greife ich dann auf das Bit zu, bzw. wie erhalte ich die Daten vom Interrupt. Habe soetwas noch nie gemacht. Den ADC spreche ich folgendermaßen an: void ADC_init(void) { // Kanal AD0 gewählt ADMUX = 0; // Interne Referenzspannung verwenden ADMUX |= (1 << REFS0) | (1 << REFS1) | (1 << ADLAR); // ADC aktivieren, Teilungsfaktor auf 128 ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // Free Running Modus aktiviert --> // ADCSRB |= (1 << ADTS0); <-- (richtig ???) ADCSRA |= (1 << ADSC); // Eine ADC Wandlung zum Warmlaufen ohne den Wert zu übergeben while (ADCSRA & (1 << ADSC)) { ; } } unsigned char ADC_read() { ADCSRA |= (1<<ADSC); // eine Wandlung while ( ADCSRA & (1<<ADSC) ) { ; // auf Abschluss der Konvertierung warten } return ADCW; // Wandlungsergebnisse zurückgeben } Gruß Mike Gruß Mike
Hallo, wenn man in einer Funktion auf einem Mikrocontroller was gerechnet hat, und dabei einen wert Analog ausgeben will, denn weist man den Wert dem PORT zu. zb.
1 | DDRC=0xff; |
2 | PORTC=Wert; |
so, und wenn die Bits an den PINS fakeln denn kann man sie anhand einen DAC wieder herstellen Frage: 1-ist das Richtig 2-Soll man beim Testen die Test Schaltung von dem DAC "die im Datenblatt als Test Circuit bezeichnet" aufbauen, reicht das "Erfahrung nach !!" Danke im Voraus mfg
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.