Hallo ich möchte gerne den ADC 0-2 auslesen und in Variablen speichern
um diese dann in die Register campare1a,compare1b und ocr2 zu schreiben
und damit dann das PWM signal zu steuern.
Ich weiß in meinem Code ist der ADC zur zeit auf 10bit eingestellt das
werde ich aber später noch ändern auf 8bit sodas die Variablen in die
Register passen.
Bis jetzt habe ich einfach erstmal Werte in die 3 Register geschrieben
um nachzuprüfen ob die PWM Signale funktionieren.Das klappt auch.
Dann wollte ich auf dem Display erstmal die Werte von ADC0 ADC1 und ADC2
anzeigen lassen bis jetzt wird aber nur 0 angezeigt.
In der ISR_ADC habe ich die ganzen if then drin, wenn das so nicht geht
dann erklärt mir mal bitte wie man das macht.
Ich poste einfach mal meinen Code bitte erschlagt mich nicht ich bin
noch Anfänger.
$regfile "m8def.dat "
$crystal = 3689400
$baud = 9600
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Start Adc
Enable Interrupts
On Adc Isr_adc
Dim W As Word , Channel As Byte
Dim Adc0 As Word
Dim Adc1 As Word
Dim Adc2 As Word
Channel = 0
Config Portd = Output
Config Portc = Input
Config Timer0 = Timer , Prescale = 1
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Down , Compare B
Pwm = Clear Down , Prescale = 1
Config Timer2 = Pwm , Prescale = 1 , Compare Pwm = Clear Up , Pwm = On
Pwm1a = 0
Pwm1b = 0
Ocr2 = 0
'Die Timer freigeben
Enable Timer0
Enable Timer1
Enable Timer2
'Die Timer starten
Start Timer0
Start Timer1
Start Timer2
'Timer Interrups
On Timer0 Isr_timer0
On Timer1 Isr_timer1
On Timer2 Isr_timer2
Sreg.7 = 1
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 ,
Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 16 * 2
Cls
Do
Locate 1 , 1
Lcd "" ; Adc0
Locate 1 , 7
Lcd "" ; Adc1
Locate 2 , 1
Lcd "" ; Adc2
Loop
End
'-----------------------------------------------------------------------
---
Isr_adc:
W = Getadc(channel)
If Channel = 0 Then Adc0 = W
If Channel = 1 Then Adc1 = W
If Channel = 2 Then Adc2 = W
Incr Channel
If Channel > 2 Then Channel = 0
Return
'-----------------------------------------------------------------------
----
Isr_timer0:
'Mach irgendwas für was auch immer
Return
'-----------------------------------------------------------------------
----
Isr_timer1:
Pwm1a = 50
Pwm1b = 10
Return
'-----------------------------------------------------------------------
----
Isr_timer2:
Ocr2 = 100
Return
'-----------------------------------------------------------------------
----
> W = Getadc(channel)
Wenn du sowieso GETADC benutzt, wozu dann der Interrupt? (ABgesehen
davon, dass das so sowieso nicht geht. Der INterrupt würde aufgerufen
werden, wenn das ADC Ergebnis fertig ist, d.h. man benutzt dann gar
nicht mehr GETADC
Benutze GETADC einfach in der Hauptschleife und gut ists. Du brauchst
dafür keine Interrupts.
1
Config Adc = Single , Prescaler = Auto , Reference = Avcc
2
Start Adc
3
4
5
Do
6
7
Adc0 = GetADC( 0 )
8
Adc1 = GetADC( 1 )
9
Adc2 = GetADC( 2 )
10
11
Locate 1 , 1
12
Lcd "" ; Adc0
13
Locate 1 , 7
14
Lcd "" ; Adc1
15
Locate 2 , 1
16
Lcd "" ; Adc2
17
18
Loop
UNd die ganze INterruptbehandlung im Zusammenhang mit dem ADC wirfst du
raus.
gib das in den Timer0 Interrupt
Isr_timer0:
W = Getadc(channel)
If Channel = 1 Then compare1a = W
If Channel = 2 Then compare1b = W
Incr Channel
If Channel < 2 Then
incr channel
else
channel = 0
endif
return
den ADC Interrupt brauchst du nicht.
Prescale 1 ist warscheinlich zu schnell, habs jetzt nicht nachgerechnet
Basti schrieb:> So ich habe es jetzt so gemacht könnte mir einer genau erklären was> getadc macht
Die BASCOM Hilfe.
Du musst dir angewöhnen, dass die Hilfe des Herstellers deine erste
Anlaufstelle ist.
> ich möchte die register selber schreiben.
Wozu?
Genau aus dem Grund verwendest du doch BASCOM, damit du dich um diesen
Kleinkram eben nicht selber kümmern musst.
GETACD startet eine Wandlung, wartet bis sie fertig ist und holt das
Ergebnis ab.
Ich seh jetzt ehrlich gesagt nicht, warum das in einer Timer ISR
passieren muss, aber seis drum.
Hi,
man macht im Interrupt so wenig wie möglich aber vor allem wird deine
Adc_isr nie aufgerufen weil die dann kommt wenn der ADC fertig ist.
Die Ints für die PWM-Timer sind auch Quatsch. Es ist der Sinn der PWM,
daß man zu beliebiger Zeit Pwm1a usw. setzt und den Rest macht der Timer
alleine im Hintergrund.
Die Timer-Ints kommen beim Überlauf des Timers, die brauchst Du gar
nicht.
Also:
Do
ADCs lesen
PWM setzen
Werte anzeigen
Loop
Fertig, Du brauchst keinen einzigen Int.
Noch eleganter wäre es die drei Punkte jeweils in Gosubs zu machen. Hier
ist das noch übersichtlich aber wenn es mehr wird ist das eleganter.
Ne mir ist klar das ich die ISR nicht brauche die hatte ich nur zum
Testen mal mit eingebaut.Ich würde gerne die Register selber
schreiben,weil ich irgendwann auf C umsteigen möchte.Bascom ist nur der
erste Schritt.Ich habe das ganze jetzt so gemacht.So funktioniert es
$regfile "m8def.dat "
$crystal = 3689400
$baud = 9600
Adcsra = &B11000101
Admux = &B01100000
Dim W As Word , Channel As Byte
Channel = 0
Config Portd = Output
Config Portc = Input
Config Timer0 = Timer , Prescale = 8
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Down , Compare B
Pwm = Clear Down , Prescale = 1
Config Timer2 = Pwm , Prescale = 1 , Compare Pwm = Clear Up , Pwm = On
Pwm1a = 0
Pwm1b = 0
Ocr2 = 0
'Die Timer freigeben
Enable Timer0
Enable Timer1
Enable Timer2
'Die Timer starten
Start Timer0
Start Timer1
Start Timer2
'Timer Interrups
On Timer0 Isr_timer0
Sreg.7 = 1
Config Lcdpin = Pin , Db4 = Portd.4 , Db5 = Portd.5 , Db6 = Portd.6 ,
Db7 = Portd.7 , E = Portd.3 , Rs = Portd.2
Config Lcd = 16 * 2
Cls
Do
Loop
End
'-----------------------------------------------------------------------
----
Isr_timer0:
W = Getadc(channel)
If Channel = 0 Then Pwm1a = Adch
If Channel = 1 Then Pwm1b = Adch
If Channel = 2 Then Ocr2 = Adch
Incr Channel
If Channel > 2 Then Channel = 0
Return
Basti schrieb:> Ne mir ist klar das ich die ISR nicht brauche die hatte ich nur zum> Testen mal mit eingebaut.Ich würde gerne die Register selber> schreiben,weil ich irgendwann auf C umsteigen möchte.
Dann steig auf C um.
> W = Getadc(channel)> If Channel = 0 Then Pwm1a = Adch
Das ist doch Schwachsinn. Getadc macht die ganze Arbeit und du holst dir
dann hinten nach noch einmal das Ergebnis ab. Den ADC auf einen Kanal
konfigurieren, ihn aktivieren, die Wandlung abwarten und das Ergebnis
abholen, das sind 4 Schritte. Alles was du tust ist, du wiederholst den
letzten (den einfachsten) dieser Schritte. Du bist im Brotberuf nicht
zufällig Politiker? Die machen das auch so: andere für sich arbeiten
lassen und dann so tun, als ob sie alles gemacht hätten.
Wenn du an den ADC auf Registerebene rann willst, dann tu das. Aber dann
tu es dann auch wirklich und richtig und schmück dich nicht mit fremden
Federn, indem du GETADC die Arbeit machen lässt und hinten nach das
Ergebnis noch einmal abstaubst.
Ja möchte ich ja selber machen ich habe das jetzt nur so gemacht wenn
ich einfach GETADC benutze habe ich keine 8bit und diese passen dann
auch nicht in den Timer für das PWM Signal oder nicht.Deswegen habe ich
dann nur das Register ADCH nochmal gelesen.Ich würde ja Getadc weglassen
das habe ich vorher versucht aber ich weiß nicht genau wie ich ADMUX und
ADCSRA ansprechen muss.Was ich soweit bis jetzt verstanden habe ist das
ich ja oben (config ADC) die erste Konversation gestartet habe mit ADC0
Dann muss ich warten bis das Ergebnis in den Registern steht.Ich habe
den ADC (left adjust ) das heißt ADCH=0-255.Dann muss ich Admux den
ADC1 wählen und wieder die Konversation starten.Ich hoffe ich habe das
so richtig verstanden.
Was mich jetzt interessieren würde wie ich in Bascom warten kann bis das
Register ADCH ein Ergebnis hat
PS ich hoffe ihr versteht mich!!!!
Basti schrieb:> Ja möchte ich ja selber machen ich habe das jetzt nur so gemacht wenn> ich einfach GETADC benutze habe ich keine 8bit
sondern 10. ALso Werte von 0 bis 1023
> und diese passen dann> auch nicht in den Timer für das PWM Signal oder nicht.
Du willst also Werte von 0 bis 255.
Ist dividieren durch 4 wirklich so schwer (zumal das für den µC ein
Klacks ist, einfach um 2 Bit nach links schieben und ich denke BASCOM
hat sogar explizite Schiebeinstruktionen)
> Was mich jetzt interessieren würde wie ich in Bascom warten kann bis das> Register ADCH ein Ergebnis hat
Wenn du sowieso nach C willst:
AVR-GCC-Tutorial
Auch das
AVR-Tutorial
wird hilfreich sein
In beiden Tutorien gibt es einen Abschnitt über den ADC und wie das
funktioniert. Da sind die Register, die Bits in den Registern und in
welcher Reihenfolge was zu machen ist. Selbst wenn du nicht in C oder
Assembler programmierst sind sie hilfreich, denn die Vorgehensweise ist
absolut identisch. Nur die Schreibweise ist ein wenig anders.
Basti schrieb:> Was mich jetzt interessieren würde wie ich in Bascom warten kann bis das> Register ADCH ein Ergebnis hat
Du startest im Single Mode eine Wandlung mit ADSC = 1 und wartest
solange bis ADSC wieder 0 ist. Dann ist die Wandlung fertig.
Basti schrieb:> Ja das mit dem Devidieren kenne ich dachte sowas sei nicht so gut.Hatte> gedacht wenn ich direkt das ADCH nehme sei besser
Mit Verlaub:
Aber wenn du den letzten Taktzyklus aus dem µC herausholen willst, dann
fang damit an, nicht BASCOM zu benutzen. BASCOM ist zum schnellen
Entwickeln super. Aber so wie in jeder Hochsprache bleibt immer ein
bischen was auf der Strecke. Gott sei Dank, kommt es aber nur selten auf
den letzten einzusparenden Taktzyklus an, so dass man sich ein bischen
Schwund immer leisten kann. Ob dein µC jetzt 95% oder 94.8% seiner Zeit
Däumchen dreht und das LCD vollkleistert, spielt keine wirkliche Rolle.
Wie schon gesagt: wenn du dem Compiler nicht traust, dass er eine
Division durch 4 mittels Schieben realisiert, dann kannst du ja auch die
Schiebebefehle von BASCOM direkt benutzen.
Besser ist immer relativ: Es ist relativ sinnfrei, GETADC ein 10 Bit
Ergebnis fertig herrichten zu lassen, nur um es dann zu verwerfen und
seinen eigenen Zugriff zu machen.
Basti schrieb:> Könnte das ganze dann so aussehen??>
Nein.
Was musst du tun?
Du musst das ADSC Bit (welches Bit 6 ist) auf 1 setzen (Siehe Datenblatt
oder die Tutorien)
dann musst du warten, bis das ADSC Bit wieder auf 0 zurückfällt. (SIehe
Datenblatt oder die Tutorien)
Dann kannst du dir das Ergebnis abholen (Siehe Datenblatt oder die
Tutorien)
ADCSRA.6 = 1 ; bit auf 1
WHILE ADCSRA.6 = 1 ; warten bis es nicht mehr 1 ist
WEND
adc1 = ADCH ; wert abholen
Karl Heinz Buchegger schrieb:> ADCSRA.6 = 1
Karl Heinz,
man kann in Bascom Register zusammen mit Bitnamen verwenden, das erspart
die kryptische Bitabzählerei, also:
ADCSRA.ADSC = 1
Basti schrieb:> Isr_timer0:> Admux = &B01100000
Wurde Dir schon gesagt, dass es keine gute Idee ist, in der ISR zu
wandeln und damit zu warten ?
Wenn ich mich nicht verrechnet hab', dürfte das bei angenommenen 200kHz
ADC-Clock so ca. 35% der verfügbaren Rechenleistung kosten.
1 /(200000 : 13 : 3) = 195µs pro Wandlung bei 3689400 = 719 µC-Clocks
Abstand zwischen den Timer0-Aufrufen: 256 x 8 = 2048 µC-Clocks
Ergibt +35% Auslastung.
Basti schrieb:> Ja danke gut zu wissen geht das auch irgendwie mit den Mux Registern> einfacher
Die Kenntnis darum ist auch in C weiterverwendbar, nur die Syntax ist da
etwas anders.