Hallo Ich versuche seit Tagen den LTC1290 an einem ATmega 32 zu betreiben, leider ohne wesentlichen Erfolg. Ich hab dazu ein C-Code hier aus dem Forum benutzt und leicht umgewandelt. Leider wird dieser Code nur mit der Fertigbausatzplatine von Conrad benutzt. Ich hab den Code etwas geändert, da in dem Bausatz keine CS Leitung benutzt wird. Das Datenblatt hab ich nun dutzende mal gelesen und glaube, daß ich es auch richtig gemacht habe. Ich bekomme nur immer wieder den Wert 1535 oder 2047 angezeigt, ohne irgendeine Systematik. Hin und wieder erscheint auch mal 1023. Das einzige im Code, was von mir stammt ist eigentlich die Impementierung der CS Leitung und die Pins wurde auf mein Layout geändert. Den ACLK erzeuge ich mit einem 3,27 MHZ Oszillator (hatte ich noch rumliegen). SCLK, DIN,DOUT und CS sind an PIN D3-PinD6 am Atmega 32 angeschlossen. Die Funktion LTC1290 Read wird aus einem Main Programm einmal pro Sekunde aufgerufen. Schneller brauche ich auch gar nicht. Aber ich brauche die 12 Bit weil es sonst zu ungenau wird. Kann mal jemand über den Code drüberschauen, ich hab nämlich keine Idee mehr wo ich suchen muß., oder hat jemand einen lauffähigen Code für den LTC1290. Danke Dirk
Hallo Dirk, Ohne jetzt genauer auf Deinen Code geschaut zu haben, aber hast Du an das Folgende gedacht? Das hat mich auch schon das ein oder andere Mal geärgert. [...] The Slave Select (SS) pin plays a central role in the SPI configuration. Depending on the mode the part is running in and the configuration of this pin, it can be used to activate or deactivate the devices. The SS pin can be compared with a chip select pin which has some extra features. In master mode, the SS pin must be held high to ensure master SPI operation if this pin is configured as an input pin. A low level will switch the SPI into slave mode and the hardware of the SPI will perform the following actions:[...] Ist übrigens ein Auszug aus der Application Note AVR151 Gruss bela
Ach, Du nutzt gar kein SPI so wie ich das sehe. Dann kannst Du mein letztes Posting auch vergessen. Ich dachte Du liest Ihn via SPI aus. Gruß bela
Hi Ist richtig, ich versuche die "SPI" selber zu programmieren. Damit ich verstehe, was da geschieht. Aber scheinbar hab ich´s noch nicht verstanden. Bin auch nicht der Weltmeister in diesen Dingen und gehöre eher in die Anfängerecke. Grüße Dirk
Dann probier es doch erstmal mit SPI. Damit Du ein funktionierendes Grundsystem hast. Danach kannst Du dann immer noch ein software SPI realisieren. bela
Hallo Dirk, ich hatte mal was mit LTC1090/1093 gemacht. Beitrag "3fach Sapnnunsg und Strom Anzeige auf LCD für Labornetztei" Ist PSI zu Fuss sozusagen. 8051 Assembler. Vielleicht hift Dir das. Gruß Stephan
#define LTC1290_DIN PIND4 //Pin für RTS = DIN #define LTC1290_DOUT PIND5 //Pin für CTS = DOUT #define LTC1290_CS PIND6 //Pin für Chip select = CS muß das nicht PORTD heißen für die Ausgänge?
Hallo bela: Ich hab im Moment aber erstmal keine AHnung, wie ich das mit richitger SPI Anbindung mache und welche Befehle ich da benutze. Deshalb erstmal die Lösung zu Fuß. Das steht ja im Datenblat auch nicht so kompliziert beschrieben. Ich hab mich mit dem setzen der Signale an das Schema auf Seite 9 gehalten. Danach sollte es gar nicht so schwer sein. Richtig viel hab ich beim Googeln nicht gefunden. Alles was im Netz zu finden ist benutz den Bausatz (halt ohne CS Leitung am Prozessor). Einen Assemblercode hab ich gefunden, wo der LTC1290 direkt (glaube an einem PIC) angeschlossen war. Alles andere ist in Basic. Soweit ich die Basic Programme versteh machen die das alle ähnlich wie bei mir. Nur bei mir klappt es nicht!!! Leider bin ich des Assemblers auch nicht mächtig. Wie gesagt, komme eher aus der ANfängerecke. Christoph: Stehe ein wenig auf dem Schlauch, wo meinst du genau? Ich hab schon mal ne MAil geschrieben. Wie hast du das denn in deinem Aufbau gelöst? Grüße Dirk
Ich habe auch schon den 1290 angesteuert, finde aber hier nur mein Programm in Assembler für den 1286:
1 | cbi DDRB,SDat ; (2) SDat = input |
2 | cbi PortD,CsAdc ; (2) ADC-/Enable ~\_ |
3 | rcall ADClk ; (3) zwei ungültige Bit am Anfang |
4 | rcall ADClk ; (3) |
5 | clr ADDat ; (1) |
6 | ldi Cnt,6 ; (1) Zähler, nur 6 Bit werden weiterverwendet |
7 | Loop6: |
8 | rcall ADClk ; (3) |
9 | clc ; (1) |
10 | sbic PinB,SDat ; (2) nächste Zeile überspringen wenn SDat= 0 |
11 | sec ; (1) SDat=1 also Cy=1 |
12 | rol ADDat ; (1) SDat ins unterste Bit von ADDat schieben |
13 | dec Cnt ; (1) Zähler weiterschieben |
14 | brne Loop6 ; (1+1) |
15 | ldi Cnt,6 ; (1) Zähler für nicht benötigte 6 Bits |
16 | Rest6: |
17 | rcall ADClk ; (3) |
18 | dec Cnt ; (2) Zähler weiterschieben |
19 | brne Rest6 ; (4) |
20 | sbi PortD,CsAdc ; (2) ADC-/Enable _/~ |
21 | sbi DDRB,SDat ; (2) SDat = output |
22 | |
23 | inc ADDat ; (1) Meßergebnis inkrementieren, |
24 | com ADDat ; (1) invertieren und |
25 | andi ADDat,$3F ; (2) auf 6 Bit begrenzen |
also je nach Datenrichtung muß es mal Port und mal Pin heißen
Hallo Vielen Dank für Assemblerbeispiele, nur kann ich leider nix damit anfangen, da ich mich mit Assembler nicht auskenne. Hat vielleicht jemand was lauffähiges in C damit ich mal schauen kann wie es richtig funktioniert?? Grüße Dirk
Hab aus Neugierde was zusammengetippt, auch wenn ich es nicht (richtig) ausprobieren kann (Hab weder den ltc noch einen mega32) - Fuer AVR-GCC/AVR-Studio (Optimierung und F_CPU notwendig) - Atmega32 - alles in einer Datei, einfach an den entsprechenden Kommentaren trennen hth. Jörg (sieht AFAIK besser aus als das, was du oben gepostet hast ;) )
Schau mal bei http://home.arcor.de/bernd_kunze/ad_tricks.htm nach, dort wird der LTC mit Basic angesteuert und prüfe mal ob Deine "Ansteuerungssequenz" gleich ist.
Hi Sven: die Beispiele hab ich mir angeschaut. Soweit ich das in Basic nachvollziehen kann sieht das ähnlich aus - kenne mich aber auch nicht viel in Basic aus. Jörg X.: Vielen Dank. Ich werde mich morgen hinsetzen und mal schaun ob ich dein C-Code zum laufen bekomme. Ich werde mal überprüfen, was bei dir anders ist als in meinem Code. Danke Dirk
Hier meine Schaltung mit dem LTC1290, mit 4 MHz Wandlertakt, der Schiebetakt wird vom Mikrocontroller erzeugt. Das dazugehörige Stück Programm:
1 | .def DatL = r19 ; AD-Wandler-Daten low |
2 | .def DatH = r20 ; AD-Wandler-Daten high |
3 | ;*..................................... |
4 | .equ SClk = 4 ; PortD Bit4 = Serial clock-Ausgang |
5 | .equ Din = 2 ; PortB Bit2 = data input ADC = output AVR |
6 | .equ Dout = 5 ; PortD Bit5 = data output ADC = input AVR |
7 | .equ CS = 1 ; PortB Bit1 = /chip select |
8 | .equ AD1 = $06 ; Steuerwort AD-Kanal 1 |
9 | .equ AD2 = $16 ; Steuerwort AD-Kanal 2 |
10 | ;*..................................... |
11 | ;* Hauptprogramm |
12 | Haupt: |
13 | cbi PortB,CS ; AD-Wandler ChipSelect ~\_ , bis Dout |
14 | ; min 2 AClk-Cycles = 1,08 µSec warten |
15 | ldi DatH,AD2 ; (1) AD-Kanal 2 anfordern, und |
16 | rcall ADCin ; (3) vorherigen AD-Wert1 lesen |
17 | |
18 | ldi Temp,100 ; 52 AClk-cycles warten = 113 4MHz-Takte |
19 | Warte: |
20 | dec Temp ; (1) |
21 | brne Warte ; (2/1) |
22 | ldi Temp,$80 ; Zweierkomplement in unsigned Wert umwandeln |
23 | eor DatH,Temp |
24 | ;*..................................... |
25 | ldi Temp,100 ; 52 AClk-cycles warten = 113 4MHz-Takte |
26 | Wart1: |
27 | dec Temp ; (1) |
28 | brne Wart1 ; (2/1) |
29 | |
30 | cbi PortB,CS ; AD-Wandler ChipSelect ~\_ , bis Dout |
31 | ; min 2 AClk-Cycles = 1,08 µSec warten |
32 | ldi DatH,AD1 ; (1) AD-Kanal 1 anfordern, und |
33 | rcall ADCin ; (3) vorherigen AD-Wert2 lesen |
34 | ldi Temp,$80 ; Zweierkomplement in unsigned Wert umwandeln |
35 | eor DatH,Temp |
36 | ;*..................................... |
37 | rjmp Haupt ; |
38 | |
39 | ;* Unterprogramm liest vom AD-Wandler LTC1290 12 Bit seriell aus |
40 | ;* gleichzeitig serielle Anforderung des nächsten AD-Wertes |
41 | ;* beide Werte stehen im gleichen Registerpaar DatH/DatL |
42 | |
43 | ADCin: |
44 | ldi Temp,10 ; |
45 | Warte2: |
46 | dec Temp ; (1) |
47 | brne Warte2 ; (2/1) |
48 | clr DatL ; (1) DatL=0 |
49 | sec ; (1) Cy=1 |
50 | rol DatL ; (1) Cy=0, DatL=01h - Zähler für 8 Datenbits |
51 | Loop8: |
52 | sbic PinD,Dout ; nächste Zeile überspringen wenn Dout= 0 |
53 | sec ; Dout=1 also Cy=1 |
54 | rol DatH ; Dout ins unterste Bit schieben |
55 | brcc low ; oberstes Bit via Cy zum ADC-Din |
56 | sbi PortB,Din ; Din=H |
57 | brcs high |
58 | low: |
59 | cbi PortB,Din ; Din=L |
60 | high: |
61 | sbi PortD,SClk ; ADC-Clock _/~ |
62 | cbi PortD,SClk ; ADC-Clock ~\_ |
63 | lsl DatL ; Zähler weiterschieben |
64 | brcc Loop8 ; 8 Bit erreicht ? |
65 | |
66 | rol DatL ; (vorher Cy=1, DatL=00h) Cy=0, DatL=01h |
67 | swap DatL ; DatL=10h, Doppelfunktion: Zähler und Daten |
68 | Loop4: |
69 | sbic PinD,Dout ; nächste Zeile überspringen wenn Dout= 0 |
70 | sec ; Dout=1 also Cy=1 |
71 | rol DatL ; Dout ins unterste Bit schieben |
72 | sbi PortD,SClk ; ADC-Clock _/~ |
73 | cbi PortD,SClk ; ADC-Clock ~\_ |
74 | brcc Loop4 ; 4 Bit erreicht ? |
75 | swap DatL ; DatL=0000xxxx --> xxxx0000 |
76 | sbi PortB,CS ; AD-Wandler ChipSelect _/~ |
77 | ret |
@Dirk (Gast) in der main() hab ich die Wartezeit zwischen den Wandlungen vergessen :( Da musst du also noch was #ndern:
1 | //ltc1290.h -- irgendwo einfügen
|
2 | #define F_ACLK 3686400L //ACLK in Hertz, "~L" bei mehr als 32767Hz
|
3 | #define CONV_DELAY() _delay_us(52.0/F_ACLK)
|
4 | |
5 | //in der Main...
|
6 | //zwischen die Aufrufe von ltc1290_read()
|
7 | CONV_DELAY(); |
hth. Jörg
Hallo Jörg Ich hab nun dein Programm mal ein wenig geändert und eine Headerdatei draus gemacht, die dann in meine main eingebunden wird. Deine letzten Änderungen hab ich auch noch mit rein genommen. Mein main. Das Programm macht nichts anderes als eine Uhr aud einem Display auszugeben. Das wirst du wahrscheinlich mit einem Blick sehen. Jede Sekunde will ich nichts anderes machen, als den Kanal 1 des LTC1290 auszulesen.Unipolar, MSBF, WLT1. Die ganze Sache ist also ziemlich Zeit unkritisch. Ich hab einen externen Uhrenquarz am Atmega32. Wenn ich im Hauptprogramm (die 3 maskierten Zeilen ) reinnehme passiert folgendes. Ich bekomme Werte von -(minus) 1660 bis ca -1792 angezeigt. Gleichzeitig spinnt die Uhr. In der Stundenanzeige steht immer eine Zahl zwischen 48 und 53. Die Sekunden zählen hoch, bei 59 gehen sie wieder auf null, die Minutenanzeige wird um eins erhöht (ist ja auch richtig) und wird in der nächsten Sekunde wieder auf null gesetzt. Ich hab noch eine Sache ergänzt. Nachdem CS auf Hihg gezogen wird braucht der LTC ca.175us zur Wnadlung. deshalb hab ich da noch ein delay eingebaut. Den ACLK TAkt erzeuge ich direkt amACLK Pin des LTC mit einem 3,276 MHZ Quarzoszillator. VCC ist 5 Volt, Vref ist 4,90 Volt. An DIN, DOUT, CS und SLCK hab ich nochmal 10 K WIderstände nach VCC (hab ich aus einem SChaltplan aus dem www) Vielleicht hast du eine Idee woran es liegt. Wäre gut, wenn wir das Teil zum Laufen bekämen, weil ich wirklich die 12 Bit brauche, sonst kann ich mein Projekt eigentlich vergessen bzw. die Sache wird mit 10 Bit nur ein Schätzeisen. Grüße Dirk
Wow... - wirf ruhig noch mal einen Blick ins AVR-GCC-Tutorial, bitte! - itoa () ist beim GCC in der <stdlib.h> definiert - Eigentlich gehört KEIN C-Code in die .h-Dateien (nur bei "__attribute__((inline))" -Funktionen lässt es sich nicht vermeiden), beim AVR-Studio kann man .c-Dateien über <rechtsklick auf "Source-Files"> -> "add existing source file" hinzufügen (sonst unter SRC im Makefile) - die wait() funktion ist ziemlich witzlos, es gibt ja schließlich "util/delay.h", mit _delay_us(), und _delay_ms() - das "#define ACLK" solltest du natürlich an deinen ACLK anpassen - Ich würde sagen du brauchst nur den Pull-Up an CS, damit der ltc keinen Unfug macht, wenn der AVR im reset ist. - für das unipolare messen muss die read_ltc1290() auf unsigned umgebaut werden:
1 | uint16_t ltc1290_read(uint8_t ctrl_word) |
2 | {
|
3 | /*Software-SPI:*/
|
4 | uint8_t i, mask; |
5 | uint16_t adc_val=0; |
6 | CLR_CS();CLR_SCLK(); |
7 | for(i = 12, mask = 0x80; i > 0; i--, mask >>= 1) |
8 | {
|
9 | |
10 | if(ctrl_word & mask) |
11 | SET_D_IN(); |
12 | else
|
13 | CLR_D_IN(); |
14 | SPI_WAIT_A(); |
15 | SET_SCLK(); |
16 | adc_val <<= 1; |
17 | if(LTC_PIN & (1<<D_OUT)) |
18 | adc_val |=1; |
19 | SPI_WAIT_B(); |
20 | CLR_SCLK(); |
21 | |
22 | }
|
23 | SET_CS(); |
24 | |
25 | return adc_val; |
26 | }
|
- wenn du eine Zahl mit 4 Stellen ("4095", bzw. 5 stellig "-2048") in
ein char[] schreiben willst, brauchst du mindestens 4+1 Felder
('4','0','9','5','\0')
- bei der Timer initialisierung:
>> while( (ASSR & (1<<TCN2UB)) || (ASSR & (1<<OCR2UB)) || (ASSR & (1<<TCR2UB)) );
beachte (jetzt) die "||" statt "|"
ok. laaanger Post, sry for klugscheißing ;)
hth. Jörg
Hallo Jörg ich hab mit dem Klugscheißing kein Problem. Bin in meinem Job ja auch einer. Dazu noch Pedant und Kleinkrämer (aber nur wenn ich will und mich jemand geärgert hat). Im Anhang die aktuelle amin, unten die Header-Datei. Nun mal die Punkte aus deinem letzten Posting: 1. itoa gilt für signed utoa für unsigned, deshalb hab in utoa geändert. Richtig??? 2.Header Datei ist gekürzt worde, siehe unten. 3.wait funktion hab ich eliminiert, bin noch nicht soweit in das Tutorial vorgestossen. Deshalb wuste ich nicht, daß es da schon fertige Funktionen für gibt. 4.define ACLK hab ich auf 3,2768 Mhz eingestellt. Kannst mir nochmal erklären was du mit dem ~L meinst. 5.die read_LTC1290 hab ich auf unsigned geändert. 6. Hab mir das Tutorial auf´s Nachtischchen gelegt (werde natürlich auch drin lesen). Momentaner Status: Die Uhr läuft immer noch nicht richtig. Ind der Stundenanzeige kommen Zahlen zwischen 49 und 55 per Zufalsprinzip (zumindest erkenne ich keine Regelmäßigkeit). Jetzt bekomme ich Zahlen Zwischen 63800 und 63900 angezeigt. Der momentane Header /********** ltc1290.h *********/ #define LTC_PORT PORTD #define LTC_PIN PIND #define LTC_DDR DDRD #define D_IN PD4 #define D_OUT PD5 #define SCLK PD3 #define CS PD6 #define F_ACLK 3276800 //ACLK in Hertz, "~L" bei mehr als 32767Hz #define CONV_DELAY() _delay_us(52.0/F_ACLK) #define SET_CS() LTC_PORT |= (1<<CS) #define CLR_CS() LTC_PORT &= ~(1<<CS) #define SET_SCLK() LTC_PORT |= (1<<SCLK) #define CLR_SCLK() LTC_PORT &= ~(1<<SCLK) #define SET_D_IN() LTC_PORT |= (1<<D_IN) #define CLR_D_IN() LTC_PORT &= ~(1<<D_IN) /* most probably not necessary - SCLK frequency up to 2Mhz is allowed */ #define SPI_WAIT_A() _delay_us(0.5) #define SPI_WAIT_B() _delay_us(0.5) // Bits in the 'Input Data Word' #define LTC_SGL 0x80 #define LTC_ODD 0x40 #define LTC_SEL1 0x20 #define LTC_SEL0 0x10 #define LTC_UNI 0x08 #define LTC_MSBF 0x04 #define LTC_WL1 0x02 #define LTC_WL0 0x01 // Prototypes uint16_t ltc1290_read(uint8_t ctrl_word); void init_ltc1290(void); //void provide_aclck(uint16_t times); So. ich mach aber jetzt Schluß und muß in Bett weil ich morgen Dienst hab. Grüße Dirk
>> #define F_ACLK 3276800 //ACLK in Hertz, "~L" bei mehr als 32767Hz das ~L ist so gemeint: >#define F_ACLK 3276800L //<<<<-- damit der AVR-GCC die Zahl als "long int" (32 Bit)Wert behandelt - ohne L sind die Zahlen/int (d.h. die ohne '.' und 'e') nur 16Bit breit. Die Variablen > volatile uint8_t sek,min,stu brauchen kein volatile (fällt dir beim Tutoriallesen wahrscheinlich selber auf ;) ) > char text[4]; Muss größer werden, du brauchst mind. 5 Elemente (s. <C-Buch-deiner-Wahl> Kapitel "strings") "char* utoa (int zahl, char *string, int radix );" ist auch UNNÖTIG!! #include<stdlib.h> reicht! uint16_t adc_val; hast du doppelt (einmal VOR main(), einmal IN ltc1290_read() ) -- in meinem Code ist das eine lokale Variable, die brauchst du nicht nochmal global. hth. Jörg ps.: woher ist denn die lcd-Lib? pps.: Code-Zeilen sind billig, du kannst ruhig für jede Anweisung eine neue nehmen ;)
Hallo Jörg Leider läuft es immer noch nicht. morgen abend werde ich mich weiter mit dem Thema beschäftigen. Ich danke aber für jede Verbesserung meines Programmes. Ich hab aus deinen Postings schon wieder ein paar Dinge gelernt, die ich hoffentlich nicht wieder falsch mache. Außerdem versuche ich mich mal in die Assemblerbeispiele einzulesen, möglicherweise versteh ich ja doch was und ergleiche das mal mit meinem Code. Irgendwo muß ja der Fehler zu finden sein. Die LCD-Lib gehört zu einem Grafikdisplay mit SED1530 Treiber. Das Display gibt es bei Reichelt. Ich brauche genau dieses Display, da ich mit der nummerischen Variante schon was gebaut habe und auf GLCD umsteigen wollte. Das Gehäuse war sehr aufwendig, deshalb genau das Display mit gleicher Baugröße. So, jetzt mache ich mal ein Päuschen und lese ein wenig im Tutorial. Grüße Dirk
Hallo Jörg Positive Nachricht: Der LTC läuft. AN dieser Zeile lag es (und an den kleinen Änderungen deinerseits): // turn value read in usable twos-complement, if negative //if(adc_val & 0x0800) // {adc_val |= 0xF000;} Ich messe ja gar keine negativen Spannungen, deshalb brauche ich diesen PArt nicht. Ich hab mir dann einen Spannungteiler aufgebaut und mit ein paar MEßwerten die Ausgabe kontrolliert - passt sehr gut. Leider kann mein MEßgerät nicht aufs Millivolt genau messen, aber das sieht schon sehr gut aus was der LTC da anzeigt. Ich bedanke mich vielmals für die Hilfe, da ich wieder ein paar Dinge dazu gelernt habe, auch in Richtung "ordentliches Programmieren". Sollten wir uns mal treffen geb ich ein Pils aus! Grüße Dirk
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.