PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : RC-Empfängers an PCINT1/2 bei ATMEGA88



therealosram
15.08.2013, 23:21
Hallo an das Forum,

bin neu hier und komme bei der Programmierung eines ATMEGA88 nicht weiter.

Ich möchte an Pin 15 u. 16 die Signale eines RC-Empfängers in einer ISR einlesen lassen und diese dann im Hauptprogramm weiterverarbeiten. Die INT0/1 pins habe ich schon mit anderen Dingen belegt, so dass ich auf die PCINT1/2 zurückgreifen muss.
In meinen Büchern und im Internet habe ich noch nicht die passenden Passagen gefunden, die mir bei meinem Problem weiterhelfen würden.


'Autosteuerung
$regfile = "m88def.dat"
$crystal = 16000000
$hwstack = 40
$swstack = 40
$framesize = 40

Dim I As Integer
On Timer1 Fehler

Config Portc.3 = Output
Config Pinb.1 = Input

Sreg.7 = 1 'Globale Interrupts einschalten
Pcicr.0 = 1 'PCInterrupt einschalten
Pcifr.0 = 1
Pcmsk0 = &B00000010 'Einschalten pcint1
Pinb.1 = 0

On Pcint1 Lesen

Config Timer1 = Counter , Prescale = 1 , Compare A = Toggle , Clear Timer = 1
Enable Timer1
Enable Interrupts

'Display Einrichten
Config Lcdpin = Pin , Db4 = Portb.0 , Db5 = Portd.7 , Db6 = Portd.1 , Db7 = Portd.0 , E = Portb.4 , Rs = Portb.5
Config Lcd = 16 * 2
Cursor Off
Cls

Upperline : Lcd " Los gehts:"

Do
Lowerline : Lcd " Puls: " ; I ; " ms "
Toggle Portc.3
Loop


Lesen:
If Pinb.1 = 1 Then
Pulsein I , Pinb , 1 , 1
End If
Return

Fehler:
Timer1 = 0
Return
end

Nun zu meinen Fragen:
- Was mache ich falsch, denn die ISR scheint nicht zu starten?
- Wie messe ich mit dem TIMER1 die genaue Länge der Signale um sie dann für Berechnungen weiter zu verwenden?
- Ich möchte weg von den Assembler-ähnlichen Eingaben, weil ich sie nicht verstehe. Im Datenblatt stehen nur Beispiele für C und Assembler. Wie muss der Code für Bascom aussehen, dass das richtig funktioniert?

Sauerbruch
16.08.2013, 14:43
Moin-moin!

Das sieht schon ziemlich gut aus, und zu Deinen Fragen gibt´s auch Antworten!
Erstmal gibt´s aber noch ein paar Anmerkungen zu Deinem bisherigen Code (von oben nach unten):

SREG.7=1 ist korrekt - genau das gleiche macht aber auch der Befehl "Enable Interrupts". Das ist also quasi doppelt gemoppelt.
PCICR.0=1 aktiviert den PCINT0 - auf "Bascom" könnte man aber analog dazu "Enable PCINT0" schreiben (liest sich einfacher).

Das Bit PCIFR.0 dient dem Controller dagegen als sogenanntes "Flag" (so ´ne Art Signal) - es wird gesetzt wenn die Interrupt-Bedingung eintritt, und gelöscht wenn die dazugehörige Interrupt-Routine ausgeführt wurde. Der Controller macht das ganz alleine; dieses Bit solltest Du also erstmal in Ruhe lassen :-)

PINB.1=0: Die PIN-Register enthalten die logischen Zustände die an einem Anschluss anliegen, der als Eingang konfiguriert ist. Man fragt sie also ab wenn man wissen möchte, ob ein Anschluss High oder Low ist. Vermutlich wolltest Du den PullUp-Widerstand des Eingangs B.1 aktivieren - das ginge dann mit PORTB.1=1.

Compare A = Toggle, Clear Timer = 1: Diese Befehle braucht man nur für PWM-Anwendungen - in diesem Fall sind sie unnötig.


Und diese Sequenz

Do:
Lowerline : LCD " Puls: " ; I ; " ms"
Toggle PORT.3
Loop

ist auch etwas problematisch: Dein LCD hämmert alle paar Millisekunden seine Buchstaben in die untere Zeile - und zwar hintereinander. Das heißt, schneller als Du sehen kannst ist die untere Zeile vollgeschrieben, und alles was danach kommt geht in´s "Nirvana".
Abhilfe würde hier der Befehl "Locate 2,1" vor dem LCD-Befehl schaffen: Damit startet jeder Ausdruck an der ersten Stelle der zweiten Zeile.


Und zu den PCINTs muss man auch ein paar Dinge wissen, um die Wirrnis zu verstehen:

Es gibt 24 Anschlüsse, die einen Pinchange-Interrupt auslösen können: PCINT0, PCINT1,...PCINT23. Es gibt aber keine 24 unterschiedlichen Pinchange-Interrupts, sondern nur drei: PCINT0, PCINT1 und PCINT2 (vergleichbar mit den beiden "normalen" Interrupts INT0 und INT1). Dass diese drei Interrupts genauso heißen wie die ersten drei Anschlüsse, ist sehr verwirrend. Die Interrupt Anschlüsse sind nun in 8er-Gruppen zusammengefasst, von denen jeder Anschluss den selben Interrupt auslöst:

Anschlüsse PCINT0-PCINT7 -> PCINT0
Anschlüsse PCINT8-PCINT15 -> PCINT1
Anschlüsse PCINT16-PCINT23 -> PCINT2

Wenn Du also über den Pin 15 den Interrupt auslösen möchtest, ist das der Anschluss PCINT1, und somit die Interrupt-Routine PCINT0 ! (verwirrend, aber wahr)
Das PCMSK-Register hast Du also korrekt gesetzt mit &B00000010. Und PCICR.0=1 ist auch korrekt, schließlich möchtest Du ja die Gruppe "PCINT0" aktivieren (man könnte auch in Bascom direkt schreiben "Enable PCINT0).
Aber Du musst dann "On PCINT0 Lesen" schreiben!

Und die Messung von RC-Impulsen habe ich immer so gemacht:

Lesen:
If PINB.1=1 then
Timer1=0
Else
I=Timer1
End if
Return

Heißt also, dass der Timer zurückgesetzt wird wenn der Impuls beginnt (Flanke und PINB.1=1), und sein aktueller Wert auf die Variable I überschrieben wird, wenn der Impuls endet (Flanke und PINB.1=0). Wenn Du einen Prescaler von 64 nimmst, läuft der Timer erst nach 200 ms über - in dieser Zeit sollten mindestens 10 Impulse aufgelaufen sein. Und wenn nicht, springt der Controller berechtigterweise in die ISR "Fehler".

Wenn Du dann noch ein "Flag" setzt wenn das Impulsende erkannt wurde, kannst Du in der Hauptschleife das Flag abfragen und den LCD-Befehl nur ausführen lassen, wenn auch tatsächlich ein neuer Impuls gemessen wurde. Aber das wäre vielleicht was für die nächste Runde :-)

Ich hoffe, das waren nicht zu viele & verwirrende Informationen - ansonsten einfach nachfragen!

HeXPloreR
16.08.2013, 15:41
Hallo,

Du könntest auch einfach auf den Bascombefehl "pulsein" ausweichen. Der PCINT muss dann ein einfacher Eingang sein(+PullUp an), an dem das RC-Signal anliegt. Da ist dann zwar kein Timer mehr händisch programmiert, aber man sieht eh nicht wozu Du den unbedingt brauchst ;)

Ein RC-Empfänger gibt soweit ich es burteilen kann immer ein Signal aus solange der Empfänger Spannung hat und der Sender am Empfänger ankommt. Kommt eine "0" an, ist die Verbindung weg ( das habe ich allerdings ganz sicher nur mit Spannungsunterbrechung probiert - also Reichweitentest steht noch aus.)

Wichtig ist auch das die 16mega Crystal-Frequenz vom Mikrocontroller bereitgestellt wird und nicht nur im Code geschrieben wurde.
Pulsein funktioniert nach meiner Erfahrung ab 4Mhz erst zufriedenstellend.
Damit habe ich mit meiner Funke einen Neutralwert von ca. 150 (mit Trimmer) eingestellt. Auch auf LCD Display...da ich das aber nur zum üben dran hatte habe ich später wieder auf Terminalausgaben gewechselt.

Hier mal ein Beispiel wie man es nutzen könnte:
https://www.roboternetz.de/community/threads/62201-Servoansteuerung-%C3%BCber-Funkfernsteuerung/page2?highlight=pulsein

therealosram
17.08.2013, 08:04
Jippy, ich habs endlich kapiert.

[code]
'Autosteuerung
$regfile = "m88def.dat"
$crystal = 256000
$hwstack = 40
$swstack = 40
$framesize = 40

Dim I As Integer
Dim I2 As Integer

Config Portc.3 = Output
Config Portc.2 = Output

Enable Interrupts
Enable Pcint0

Pcmsk0.pcint1 = 1


On Pcint0 Lesen:

Do
Portc.3 = 1
Waitms 100
Portc.3 = 0
Waitms 100
Loop

Lesen:
Toggle Portc.2
Return


End
[code]

so funktioniert erstmal das was ich wollte.

vielen, vielen Dank
Weiteres folgt

therealosram
18.08.2013, 09:24
Genau das wollte ich:


'Autosteuerung
$regfile = "m88def.dat"
$crystal = 512000
$hwstack = 40
$swstack = 40
$framesize = 40
Dim I As Integer
Dim I2 As Integer

Config Portd.3 = Output
Config Portd.2 = Output
Config Portd.1 = Output

Config Timer1 = Counter , Prescale = 1
Enable Timer1

'Display Einrichten
Config Lcdpin = Pin , Db4 = Portb.0 , Db5 = Portd.7 , Db6 = Portd.1 , Db7 = Portd.0 , E = Portb.4 , Rs = Portb.5
Config Lcd = 16 * 2
Cursor Off
Cls

Enable Interrupts
Enable Pcint0
Enable Pcint1

Pcmsk0 = &B00000010
Pcmsk1 = &B00001000

On Pcint0 Lesen1
On Pcint1 Lesen2

Do
Portd.1 = 1
Upperline : Lcd " " ; I ; " "
Lowerline : Lcd " " ; I2 ; " "
Portd.1 = 0

Loop

Lesen1:
If Pinb.1 = 1 Then
Timer1 = 0
Else
I = Timer1
End If

Toggle Portd.3
Return

Lesen2:
If Pinc.3 = 1 Then
Timer1 = 0
Else
I2 = Timer1
End If

Toggle Portd.2
Return

End

beide Kanäle werden getrennt erkannt mit:
high 29500
middle 22600
low 15300

und das Programm läuft mit ca 3,5 khz durch für die Berechnungen und Ausgaben. Genau das wollte ich:

- - - Aktualisiert - - -

Eine Frage hab ich ab aber noch


... Wichtig ist auch das die 16mega Crystal-Frequenz vom Mikrocontroller bereitgestellt wird und nicht nur im Code geschrieben wurde...

Ich dachte, es reicht wenn das im Code steht. Ich hab einen externen Quarz dran mit 16 Mhz. Wie sag ich ihm, dass er den nutzen soll? Welche Auswirkungen hat es, wenn es noch im Code anders steht?

HeXPloreR
18.08.2013, 10:28
Genau das wollte ich:



$crystal = 512000


und das Programm läuft mit ca 3,5 khz durch für die Berechnungen und Ausgaben. Genau das wollte ich:


naja, das Du jetzt genau das wolltest bezweifel ich etwas, denn dann würde in Deinem Code die 16Mhz drin stehen...
Der Compiler berechnet aus der Angabe im Code die Timer und Waits usw usw. Die Quarzfrequenz im Atmega bleibt davon aber unbeeindruckt, der läuft möglicherweise noch auf 1Mhz.
Ein einfacher Hardwaretest, wäre eine LED im Sekundentakt blinken zu lassen...


Man setzt die Fuses dafür auf 16Mhz- ich nutze den mySmartUSB MKII und meistens das ProgTool dazu, deswegen kann ich keine qualifizierte Aussage darüber machen wie es ganz genau in Bascom geht, aber es geht auch dort im manuellen Brennmodus einzustellen. Aber erstmal würde ich schauen womit er grade läuft.
(!!!!!VORSICHT: FALSCHE FUSES MACHEN DEN CHIP MÖGLICHERWEISE VORERST ODER DAUERHAFT UNBRAUCHBAR!!!!!!)

Kann der Atmega die 16MHz auch vertragen?

Du bist übrigens mit Deiner I und I2 Variable vom Type Integer ziemlich nah am Limit, viellicht macht es Sinn dort einen Word zu nehmen, da es vermutlich eh nur positive Werte annehmen wird?
Hier ein kleines Tutorial i (http://halvar.at/elektronik/kleiner_bascom_avr_kurs/variablen/)n Bas-com.

therealosram
19.08.2013, 09:53
Hallo,

ich nutze einen "mySmart USB light" und die Demoversion von Bascom-AVR.
Das mit dem "Verfusen" von ATmegas hab ich schon durch bei der Einstellung des Quarzes. Zwei davon hab ich schon auf externen Quarz gesetzt und muss sie erstmal wieder recovern. "Nächstes Projekt"
Mittlerweile nutze ich die Einstellung: "111111: Ext. Crystal Osc." Eine Frequenz steht da leider nicht dabei. Ich hoffe, das sind 16 Mhz.

Hier nun mein Projekt.

Doppelte H-Brücke für zwei 24V/250 W Motoren.
ATMEGA88, 4xIR2104 als FET-Treiber, 16x IRF1404 FET's, 8x MBR1645 als FET-Schutz

26246

Hauptprogramm läuft mit Berechnungen bei ca. 5,6 Khz durch. Das reicht meiner Meinung nach.Bei Signalverslust läuft das Programm direkt in die Fehlerroutine und schaltet die Treiber aus.Jeder, der mit "alten" Modellbaufernbedienungen Erfahrungen hat, weiß wie fatal ein Signalverlust an den Servos/Fahrtregler ist. Da "stirbt" meistens was. (Modell, Motor, ....)

Hier noch der Code. Sicherlich gibts da Dinge, die man noch besser gestalten könnte, aber so läufts sauber und ich weiß auch wie.
Vielen Dank für Eure Hilfe.;););)

p.s.: Wo bekomm ich eine bezahlbare Vollversion von BASCOM-AVR her?



'Autosteuerung
$regfile = "m88def.dat"
$crystal = 512000
$hwstack = 40
$swstack = 40
$framesize = 40

'** Ports/Pins ************************************************** *******************************
Config Portd.5 = Output '11 PWM_L_Low
Config Portd.6 = Output '12 PWM_L_High
Config Portb.3 = Output '17 PWM_R_High
Config Portd.3 = Output '05 PWM_R_low
Config Portb.2 = Output '16 Enable links
Config Portc.3 = Output '26 Status_LED
Config Portb.1 = Output '15 enable Rechts

Config Pinc.4 = Input '27 correction Left
Config Pinc.1 = Input '24 corrention Right
Config Pind.2 = Input '04 Taster
Config Pinc.0 = Input '23 rechte Eingabe Poti
Config Pinc.5 = Input '28 Linke Eingabe Poti

'** Ports benennen ************************************************** ***************************
Correct_l Alias Pinc.4 'pin 27
Correct_r Alias Pinc.1 'pin 24
Taster Alias Pind.2 'pin 04
Led Alias Portc.3 'pin 26
Enable_l Alias Portb.2 'pin 16
Enable_r Alias Portb.1 'pin 15
R_poti Alias Portc.0 'pin 23
L_poti Alias Portc.5 'pin 28
'RC_L_in Pin 06
'RC_R_in Pin 25

'** Variablen ************************************************** ********************************
Dim In_l As Integer 'Eingabevariablen Signal
Dim In_r As Integer
Dim In_type As Bit 'Art der Eingabe
Dim L_high As Word 'Ausmaße Links
Dim L_mid As Word
Dim L_low As Word
Dim R_high As Word 'Ausmaße Rechts
Dim R_mid As Word
Dim R_low As Word
Dim L_quotient As Single 'Runterrechnen auf Bytewert
Dim R_quotient As Single
Dim L_verschiebung As Word 'Verschieben des Mittelwertes
Dim R_verschiebung As Word
Dim L_korrekt As Single 'Anpassen unterschiedlicher Motoren
Dim R_korrekt As Single
Dim Calc_l As Single 'Berechnung PWM
Dim Calc_r As Single
Dim Pwm_l As Byte 'Ausgabe PWM
Dim Pwm_r As Byte
Dim I As Word 'allgemeine Variable

'** Configs ************************************************** **********************************
Config Timer0 = Pwm , Compare A Pwm = Clear Up , Compare B Pwm = Clear Down , Prescale = 256
Config Timer1 = Counter , Prescale = 8 , Noise Cancel = 1
Config Timer2 = Pwm , Compare A Pwm = Clear Up , Compare B Pwm = Clear Down , Prescale = 256
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Enable Timer0
Enable Timer1
Enable Timer2
Start Adc
Enable Interrupts
Enable Pcint1
Enable Pcint2
Pcmsk1 = &B00000000
Pcmsk2 = &B00000000
Pcmsk1.pcint10 = 1
Pcmsk2.pcint20 = 1


On Pcint1 Rc_in_r
On Pcint2 Rc_in_l

'** Display Einrichten ************************************************** ***********************
'Config Lcdpin = Pin , _
' Db4 = Portb.0 , Db5 = Portd.7 , Db6 = Portd.1 , Db7 = Portd.0 , E = Portb.4 , Rs = Portb.5
'Config Lcd = 16 * 2
'Cursor Off
'Cls

'** Variablen zuweisen ************************************************** ***********************
Taster = 1
Enable_l = 0
Enable_r = 0
L_quotient = 6.867
R_quotient = 6.621
L_verschiebung = 277
R_verschiebung = 293

'** Initialisierung ************************************************** **************************



Do
Loop Until Taster = 0

'** Hauptschleife ************************************************** ****************************
Go:
Do

Led = 1 'Frequenzmessung möglich

'Locate 1 , 1 : Lcd " " ; In_l ; " "
'Locate 2 , 1 : Lcd " " ; In_r ; " "

Led = 0
If In_l > 4000 Or In_l < 1500 Or In_r > 4000 Or In_r < 1500 Then Goto Fehler

Calc_l = In_l
Calc_r = In_r

'Linearregelung ************************************************** ****************************
Calc_l = Calc_l / 6.867
Calc_l = Calc_l - 277

Calc_r = Calc_r / 6.621
Calc_r = Calc_r - 300

If Calc_l > 254 Then Calc_l = 254
If Calc_l < 1 Then Calc_l = 1

If Calc_r > 254 Then Calc_r = 254
If Calc_r < 1 Then Calc_r = 1

'** Variablenübergabe ************************************************** **********************

Pwm_l = Calc_l
Pwm_r = Calc_r

'** PWM umsetzen ************************************************** ***************************
If Pwm_l > 148 Or Pwm_l < 108 Then
Enable_l = 1
Else
Enable_l = 0
End If

If Pwm_r > 148 Or Pwm_r < 108 Then
Enable_r = 1
Else
Enable_r = 0
End If

Pwm0a = Pwm_l
Pwm0b = Pwm_l
Pwm2a = Pwm_r
Pwm2b = Pwm_r

Loop

'** Empfängerdaten auslesen ************************************************** ******************
Rc_in_r:
If Pinc.2 = 1 Then
Timer1 = 0
Else
In_r = Timer1
End If
Return

Rc_in_l:
If Pind.4 = 1 Then
Timer1 = 0
Else
In_l = Timer1
End If
Return


'** Fehlerroutine ************************************************** ****************************
Fehler:
Enable_l = 0
Enable_r = 0
Pwm0a = 128
Pwm0b = 128
Pwm2a = 128
Pwm2b = 128

Do
Led = 1
Waitms 3000
Led = 0
Waitms 3000
Loop

HeXPloreR
19.08.2013, 11:55
naja, das Du jetzt genau das wolltest bezweifel ich etwas, denn dann würde in Deinem Code die 16Mhz drin stehen...
Der Compiler berechnet aus der Angabe im Code die Timer und Waits usw usw. Die Quarzfrequenz im Atmega bleibt davon aber unbeeindruckt, der läuft möglicherweise noch auf 1Mhz.
Ein einfacher Hardwaretest, wäre eine LED im Sekundentakt blinken zu lassen...


Man setzt die Fuses dafür auf 16Mhz- ich nutze den mySmartUSB MKII und meistens das ProgTool dazu, deswegen kann ich keine qualifizierte Aussage darüber machen wie es ganz genau in Bascom geht, aber es geht auch dort im manuellen Brennmodus einzustellen. Aber erstmal würde ich schauen womit er grade läuft.
(!!!!!VORSICHT: FALSCHE FUSES MACHEN DEN CHIP MÖGLICHERWEISE VORERST ODER DAUERHAFT UNBRAUCHBAR!!!!!!)

Kann der Atmega die 16MHz auch vertragen?

Du bist übrigens mit Deiner I und I2 Variable vom Type Integer ziemlich nah am Limit, viellicht macht es Sinn dort einen Word zu nehmen, da es vermutlich eh nur positive Werte annehmen wird?
Hier ein kleines Tutorial i (http://halvar.at/elektronik/kleiner_bascom_avr_kurs/variablen/)n Bas-com.

10 Zeichen

therealosram
19.08.2013, 12:45
Der Binärcode hat in der Auswahlliste nur 6 Stellen.

Rone
19.08.2013, 13:32
Hallo,

Du verwendest also einen 512KHz Quarz?
Klick mich. (http://www.engbedded.com/fusecalc/)

MfG

HeXPloreR
19.08.2013, 13:49
...wollte eigentlich auch im vorletzten Beitrag schon mit rein geschrieben haben, dass ich das ProgTool (http://shop.myavr.de/index.php?404;http://www.myavr.de:80/download.php?suchwort=progtool) aus einem bestimmten Grund zum Fusen vorziehe: Dort steht nämlich die Frequenz dabei ;) Könnte ja helfen das Problem zu lösen, wenn man nicht weiß was 111111 oder so bedeuten soll.
Ich weiß das nämlich auch nicht, aber ich weiß wo es steht.

Wie kann es sein das Dein Chip auf 16Mhz läuft aber du es dem Programm nicht mitteilst? - ich hatte Dich drauf hingewiesen, jetzt also nochmal die konkrete Frage.
Meinst Du es bringt Dir und dem Chip etwas wenn Du das Timing selbst durch einen (nicht kaufbaren/unmöglichen) Quarz manipulierst? - ich meine nicht.
Hast Du denn auch einen 16Mhz Quarz angeschlossen? - sieht eher so aus als wenn Du nur schreibst Du hast es eingestellt.

Bascom gibt es vom Hersteller.

EDIT: ProgTool hyperlinked

therealosram
19.08.2013, 14:53
Nein. es hängt ein 16 Mhz dran. Spreizung der Timerergebnisse erhöhte sich aber, umso geringer die Frequenz war. ich weiß nicht wieso.

HeXPloreR
19.08.2013, 15:14
Deinem Programm nutzt es aber nichts wenn der Quarz zwar dran ist, sogar eingestellt in den Fuses - was bleibt jetzt noch zu tun?

Tipp: $crystal = 512000 ' ist sicher falsch wenn eine 16000000Hz Quarzangabe auch vom Compiler benutzt werden soll ;)

EDIT:Leider habe ich mich entweder vertan mit der Quarzangabe oder es wurde in den neueren Versionen etwas verändert in der Ansicht beim ProgTool...ich bin mir sicher man konnte dort direkt z.B. einen 16Mhz Quarz sehen. Schade das war irgendwie immer sehr einfach.

therealosram
20.08.2013, 11:33
Nein, ich verwende verwende einen 16 Mhz Quarz und habe in den Fuses auch, meiner Meinung nach, 16 Mhz eingestellt.
Und ja ich habe trotzdem 512 Khz eingestellt. Einfach, weil die Differenz der Werte des Timers zwischen bei 512khz am größten ist. Die Umrechnungsvariablen sind jetzt auf diese Spreizung angepasst. Solange ich kein Display an dieser Schaltung habe und die Werte vernünftig auslesen kann, lasse ich es jetzt dabei.

Mir ist beim Testen aufgefallen, dass ich wohl einen Denkfehler, was die High/Low- und enable-Beschaltung angeht. Ich gebe den FET-Treibern jetzt einfach ein 1 für die eine und ein 254 für die andere Richtung. (keine 0/255 weil die Bootstrap-Schaltung der Teiber den oberen Fet nicht auslösen würde) Über den Enable-Eingang gebe ich jetzt das PWM-Signal für die Geschwindigkeit.

Ich weiß nicht genau, ob man so eine H-Brücke treibt, aber das funktioniert noch besser und ich hab keine Verslustleistung in Neutral-Stellung. Weitere Anregungen nehme ich gern entgegen.

Wen's interessiert, hier der geänderte Code

'Autosteuerung
$regfile = "m88def.dat"
$crystal = 512000
$hwstack = 40
$swstack = 40
$framesize = 40

'** Ports/Pins ************************************************** *******************************
Config Portd.5 = Output '11 PWM_L_vor/zurück
Config Portd.6 = Output '12 PWM_L_enable (PWM)
Config Portb.3 = Output '17 PWM_R_enable (PWM)
Config Portd.3 = Output '05 PWM_R_vor/zurück
Config Portc.3 = Output '26 Status_LED

Config Pinc.4 = Input '27 correction Left
Config Pinc.1 = Input '24 corrention Right
Config Pind.2 = Input '04 Taster
Config Pinc.0 = Input '23 rechte Eingabe Poti
Config Pinc.5 = Input '28 Linke Eingabe Poti

'** Ports benennen ************************************************** ***************************
Correct_l Alias Pinc.4 'pin 27
Correct_r Alias Pinc.1 'pin 24
Taster Alias Pind.2 'pin 04
Led Alias Portc.3 'pin 26
R_poti Alias Portc.0 'pin 23
L_poti Alias Portc.5 'pin 28
'RC_L_in Pin 06
'RC_R_in Pin 25

'** Variablen ************************************************** ********************************
Dim In_l As Integer 'Eingabevariablen Signal
Dim In_r As Integer
Dim L_direction As Bit 'Richtung der Kanäle festlegen
Dim R_direction As Bit
Dim L_quotient As Single 'Runterrechnen auf Bytewert
Dim R_quotient As Single
Dim L_verschiebung As Word 'Verschieben des Mittelwertes
Dim R_verschiebung As Word
Dim L_korrekt As Single 'Anpassen unterschiedlicher Motoren
Dim R_korrekt As Single
Dim Calc_l As Single 'Berechnung PWM
Dim Calc_r As Single
Dim Pwm_l As Integer 'Ausgabe PWM
Dim Pwm_r As Integer
Dim I As Word 'allgemeine Variable

'** Configs ************************************************** **********************************
Config Timer0 = Pwm , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down , Prescale = 256
Config Timer1 = Counter , Prescale = 8 , Noise Cancel = 1
Config Timer2 = Pwm , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down , Prescale = 256
Config Adc = Single , Prescaler = Auto , Reference = Avcc
Enable Timer0
Enable Timer1
Enable Timer2
Start Adc
Enable Interrupts
Enable Pcint1
Enable Pcint2
Pcmsk1 = &B00000000
Pcmsk2 = &B00000000
Pcmsk1.pcint10 = 1
Pcmsk2.pcint20 = 1

On Pcint1 Rc_in_r
On Pcint2 Rc_in_l

'** Display Einrichten ************************************************** ***********************
'Config Lcdpin = Pin , _
' Db4 = Portb.0 , Db5 = Portd.7 , Db6 = Portd.1 , Db7 = Portd.0 , E = Portb.4 , Rs = Portb.5
'Config Lcd = 16 * 2
'Cursor Off
'Cls

'** Variablen zuweisen ************************************************** ***********************
Taster = 1
L_quotient = 6.867
R_quotient = 6.621
L_verschiebung = 277
R_verschiebung = 293

'** Initialisierung ************************************************** **************************

Pwm0a = 0 'Enable Aus
Pwm2a = 0

Do 'Programm freigeben
Loop Until Taster = 0

'** Hauptschleife ************************************************** ****************************
Go:
Do

Led = 1 'Frequenzmessung möglich

'Locate 1 , 1 : Lcd " " ; In_l ; " "
'Locate 2 , 1 : Lcd " " ; In_r ; " "


If In_l > 4000 Or In_l < 1500 Or In_r > 4000 Or In_r < 1500 Then Goto Fehler

Calc_l = In_l
Calc_r = In_r

'Linearregelung ************************************************** ****************************
Calc_l = Calc_l / 6.867
Calc_l = Calc_l - 277

Calc_r = Calc_r / 6.621
Calc_r = Calc_r - 300

Led = 0

'** Variablenübergabe ************************************************** **********************

Pwm_l = Calc_l 'Linker Kanal

Pwm_l = Pwm_l * 2
Pwm_l = Pwm_l - 256

If Pwm_l > 0 Then
L_direction = 1
Else
L_direction = 0
Pwm_l = -pwm_l
End If

If Pwm_l > 254 Then Pwm_l = 254
If Pwm_l < 1 Then Pwm_l = 1

Pwm_r = Calc_r 'rechter Kanal

Pwm_r = Pwm_r * 2
Pwm_r = Pwm_r - 256

If Pwm_r > 0 Then
R_direction = 1
Else
R_direction = 0
Pwm_r = -pwm_r
End If

If Pwm_r > 254 Then Pwm_r = 254
If Pwm_r < 1 Then Pwm_r = 1

'** PWM umsetzen ************************************************** ***************************

If L_direction = 1 And Pwm_l > 7 Then 'links vorwärts
Pwm0a = Pwm_l
Pwm0b = 1
End If

If L_direction = 0 And Pwm_l > 7 Then 'links rückwärts
Pwm0a = Pwm_l
Pwm0b = 254
End If

If Pwm_l <= 7 Then 'links neutral
Pwm0a = 0
Pwm0b = 128
End If

If R_direction = 1 And Pwm_r > 7 Then 'rechts vorwärts
Pwm2a = Pwm_r
Pwm2b = 1
End If

If R_direction = 0 And Pwm_r > 7 Then 'rehts vorwärts
Pwm2a = Pwm_r
Pwm2b = 254
End If

If Pwm_r <= 7 Then 'rechts vorwärts
Pwm2a = 0
Pwm2b = 128
End If

Loop

'** Empfängerdaten auslesen ************************************************** ******************
Rc_in_r: 'rechten RC-Kanal einlesen
If Pinc.2 = 1 Then
Timer1 = 0
Else
In_r = Timer1
End If
Return

Rc_in_l: 'linken RC-Kanal einlesen
If Pind.4 = 1 Then
Timer1 = 0
Else
In_l = Timer1
End If
Return


'** Fehlerroutine ************************************************** ****************************
Fehler:
Pwm0a = 0
Pwm0b = 128
Pwm2a = 0
Pwm2b = 128

Do
Led = 1
Waitms 3000
Led = 0
Waitms 3000
Loop

for_ro
20.08.2013, 12:30
Hallo,
auf die Timer hat die abweichende Frequenzangabe überhaupt keinen Einfluß. Also wofür diese Tricks?
Bei dem ADC wird es aber bestimmt Probleme geben, weil du über Prescaler=Auto eine Abtastfrequenz gewählt hast, die bei 16MHz auf das 32-fache hoch geht.

Deine Waitms 3000 am Ende werden auch nur 100ms dauern.

Noch etwas, was ich ändern würde:
Taster=1 wird durch den Alias zu Pind.2=1, was keinen Sinn macht. Du willst ja wahrscheinlich den PullUp einschalten. Da wäre Portd.2=1 richtig.
Durch eine Besonderheit der Register funktioniert deine Version evtl beim M88, bei anderen Controllern sicher nicht.

Die Variablen ln_r und ln_l würde ich zu Word Typen machen. Durch die Integer bekommst du evtl. negative Werte, falls der Timer in den ISRs mal einen Wert>=2^15 hat. Müsste man mal ausprobieren. Und solange du nicht an negativen Werten interessiert bist, würde ich auch nur positive Typen verwenden. Dadurch kann man Programme viel robuster und stabiler machen.
Gleiches gilt für pwm_l und pwm_r.

Edit: Ich sehe gerade, dass du die neg. Werte im Programm behandelst, evtl ist es dann doch ok.