PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM Frage und Interrupt mit Tasten?



Enterprise
28.03.2008, 17:48
Hallo Forum,

Bin schon den ganzen Tag am basteln.
Jetzt ist es so weit euch mal zu fragen.
Ich habe ein Board USC08 mit dem Atmega8 mit 14,7456 MHZ und ein SN754410.
Der Port PB1 ist der PWM OC1A geht auf den SN754410,
Die Ports PD5 und PD6 gehen auch an den SN754410.

Nun wollte ich erst einmal anfangen, ganz klein.
Es sollte über einen Interrupt drei Tasten abgefragt werden.
Taste1 "PB3" soll den Motor mit 50% nach links laufen lassen.
Taste2 "PB4" soll den Motor mit 50% nach rechts laufen lassen.
Taste3 "PB5" soll den Moter auf 100% beschleunigen.

Hier mein Script.
Der Motor läuft nicht.




#include <avr/io.h>
#include <stdint.h>

void pwminit()
{
DDRD = (1<<PD5);
TCCR1A = (1<<COM1B1)|(1<<WGM10)|(1<<WGM12);
TCCR1B = (1<<CS10);
OCR1B = 128;
}


void main (void)
{
DDRB=0x38; // Port B als Eingang
PORTB=0x38; // Pull-ups auf Port B ein
DDRB = 0b11111111;


while(1);

if ( PINB & ( 1<<PINB3 ) )
{
PORTD |= (1<<PD5);
pwminit();
for( ; ; ){};
}

}




Vom vielen testen weiß ich nicht mehr aus noch ein.
Wäre jemand so nett mir dabei zu helfen.

mfg
Enterprise

askazo
28.03.2008, 18:11
Ich habe jetzt nicht alles überprüft, aber der entscheidene Fehler ist auf jeden Fall der hier:

while(1);
Wenn Du hinter dem while(1) direkt ein Semikolon hast, ist die while-Schleife leer. Und da Du eine 1 als Laufbedingung hast, bleibt der Controller auf Ewig in dieser leeren Schleife gefangen.

Richtig wäre:

while(1)
{
if (...)
}


Gruß,
askazo


Ich sehe gerade noch was ganz schlimmes...
[code]for( ; ; ){};[code]
Ich habe noch nie eine leere for-Schleife verwendet, aber das dürfte auch in einer Endlosschleife resultieren. D.h. hier würde Dein Controller schon wieder stecken bleiben. Was wolltest Du damit bezwecken?

Und noch was: Interrupts hast Du hier bisher noch nicht verwendet... aber das solltest Du auch erst mal ohne machen.

Enterprise
28.03.2008, 18:13
Danke für das schnelle Antworten.

Hat nicht funktioniert.

mfg
Enterprise

askazo
28.03.2008, 18:18
Oh, jetzt warst Du aber sehr schnell mit antworten...
Siehe edit im letzten Posting...

Enterprise
28.03.2008, 18:25
Sorry habe das Edit zu spät gesehen.

Habe die Interrupts erstmal weggelassen. da es erstmal mit Tasten drücken funktionieren soll.

Die Endlos schleife kam vom kopieren.

Danach hat es auch nicht funktioniert.

Hier jetzt der code ohne ; und ohne For schleife.



#include <avr/io.h>
#include <stdint.h>

void pwminit()
{
DDRD = (1<<PD5);
TCCR1A = (1<<COM1B1)|(1<<WGM10)|(1<<WGM12);
TCCR1B = (1<<CS10);
OCR1B = 128;
}


void main (void)
{
DDRB=0x38; // Port B als Eingang
PORTB=0x38; // Pull-ups auf Port B ein
DDRB = 0b11111111;


while(1)

if ( PINB & ( 1<<PINB3 ) )
{
PORTD |= (1<<PD5);
pwminit();
}

}



mfg
Enterprise

izaseba
28.03.2008, 18:58
Hallo,


DDRB=0x38; // Port B als Eingang
PORTB=0x38; // Pull-ups auf Port B ein
DDRB = 0b11111111;

Hast Du schon überlegt was in den 3 Zeilen passiert ?

in der etsten Zeile machst Du PINB3 PINB4 und PINB5 zum Ausgang.
in der zweiten Zeile Schaltest Du sie alle HIGH
in der dritten Zeile machst Du dann den ganzen Port zum Ausgang.

War das so gedacht ? Scheinbar nicht, sonst würdest Du PINB3 nicht abfragen wollen ;-)
Schlimmer noch, soltest Du den Taster auf PB3 gegen GND schalten, baust Du Dir immer einen Kurzschluß...

Mach das bitte so:


...
DDRB &=~(1<<PB3);
PORTB |=(1<<PB3);

while(1) {
if ( ~PINB & ( 1<<PINB3 ) )
{
PORTD |= (1<<PD5);
pwminit();
}
...

Gruß Sebastian

Enterprise
28.03.2008, 19:14
Danke Sebastian,

Ja die dritte Zeile war Mumpitz, auch nicht gewollt.

Nun habe ich es geändert und eine Kontroll LED eingebaut.

Die LED geht an aber der Motr will nicht laufen.



#include <avr/io.h>
#include <stdint.h>

void pwminit()
{
// DDRD = (1<<PD5);
TCCR1A = (1<<COM1B1)|(1<<WGM10)|(1<<WGM12);
TCCR1B = (1<<CS10);
OCR1B = 128;
}


void main (void)
{
DDRD=0x0c; // Port PD2 u. PD3 auf Port D als Ausgang
PORTD=0x0c; // Pins PD2 u. PD3 auf Port D auf low

DDRB &=~(1<<PB3);
PORTB |=(1<<PB3);

// DDRB=0x38; // Port B als Eingang
// PORTB=0x38; // Pull-ups auf Port B ein
// DDRB = 0b11111111;


while(1)

if ( PINB & ( 1<<PINB3 ) )
{
PORTD |= (1<<PD5);
PORTD |= (1<<PD2); // LED ein "Test"
pwminit();
}
else
{
PORTD &= ~(1<<PD2); // LED aus "Test"
}

}





mfg
Enterprise

McJenso
28.03.2008, 19:20
Hallo,



DDRB=0x38; // Port B als Eingang
PORTB=0x38; // Pull-ups auf Port B ein
DDRB = 0b11111111;


Was möchtest du damit erreichen?



Der Port PB1 ist der PWM OC1A geht auf den SN754410, ...

OCR1B = 128;

Hm,..

while ohne Klammer


Von den Ungereimtheiten im Code mal abgesehen. Du weißt, dass pwminit wieder und wieder durchlaufen wird, bis PB3 auf GND gezogen wird?

Schreib doch einmal genau, was du mit dem Programm erreichen möchtest. Sonst ist es sehr schwer Vorschläge zu machen.

Gruß

Jens

Edit: Na da bin ich ja mal richtig lahm gewesen
Edit: Wenn die Led leuchtet, wird die init immer angesprungen. Es liegt in der Natur einer anständigen Init, das diese nur einmal initalisieren sollte. Daher darf die LED nicht anbleiben.

Enterprise
28.03.2008, 19:28
Hallo McJenson,

Es sollte über einen Interrupt drei Tasten abgefragt werden.
Taste1 "PB3" soll den Motor mit 50% nach links laufen lassen.
Taste2 "PB4" soll den Motor mit 50% nach rechts laufen lassen.
Taste3 "PB5" soll den Moter auf 100% beschleunigen.

Nun das script erst ohne Interrupts, nur mal mit einer Taste.
Die LED geht an aber nder Motor läuft nicht.




#include <avr/io.h>
#include <stdint.h>

void pwminit()
{
// DDRD = (1<<PD5);
TCCR1A = (1<<COM1B1)|(1<<WGM10)|(1<<WGM12);
TCCR1B = (1<<CS10);
OCR1B = 128;
}


void main (void)
{
DDRD=0x0c; // Port PD2 u. PD3 auf Port D als Ausgang
PORTD=0x0c; // Pins PD2 u. PD3 auf Port D auf low

DDRB &=~(1<<PB3);
PORTB |=(1<<PB3);

// DDRB=0x38; // Port B als Eingang
// PORTB=0x38; // Pull-ups auf Port B ein
// DDRB = 0b11111111;


while(1)

if ( PINB & ( 1<<PINB3 ) )
{
PORTD |= (1<<PD5);
PORTD |= (1<<PD2); // LED ein "Test"
pwminit();
}
else
{
PORTD &= ~(1<<PD2); // LED aus "Test"
}

}





mfg
Enterprise

izaseba
28.03.2008, 19:33
Hallo, so wie ich sehe möchtest Du Timer1 in 8 Bit Fast PWM Mode betreiben und Dein Takt auf OC1B ausgeben, den mußt Du aber auch noch als Ausgang konfigurieren.
Der liegt an PB2 also würde ich aus


DDRB &=~(1<<PB3);




DDRB = (1<<PB2);
machen.

Übrigens,


TCCR1B = (1<<CS10);


Damit läuft der Timer mit µC Takt, ist das nicht was schnell ?

Gruß Sebastian

P.S.


Hm,..

while ohne Klammer


@McJenso,
das hab ich mir auch gedacht, aber das dürfte hier sogar funktionieren :-s
trotzdem hab ich in meinem Vorschlag lieber die Klammern drum gemacht \:D/

McJenso
28.03.2008, 20:00
Hallo,

ja habs mal im Simulator versucht. Es geht. Naja hab mich schon bei void main(void) zurückgehalten. ;-)

Zum Problem. Um Hardwarefehler auszuschließen, würde ich noch eine LED an den PWM Ausgang hängen.
Ansonsten würde ich die Init nur einmal durchlaufen und dann nur noch den Vergleichswert (OCR1B) ändern. Wobei ich zugeben muss, dass es auch das so funktionieren müsste.

Gruß

Jens

Enterprise
28.03.2008, 20:04
Hallo Sebastian,



Hallo, so wie ich sehe möchtest Du Timer1 in 8 Bit Fast PWM Mode betreiben und Dein Takt auf OC1B ausgeben, den musst Du aber auch noch als Ausgang konfigurieren.


Das habe ich bestimmt verwechselt, da der PWM Ausgang am OC1A ist.
Komme nicht so klar mit dem Datenblatt vom Atmega8.

Dann wäre doch das richtiger oder?
DDRB = (1<<PB1);




Damit läuft der Timer mit µC Takt, ist das nicht was schnell ?


Nee , das wollte ich auch nicht.
Da ich ein 14,7456 MHZ Quartz habe.

Wie müßte ich es jetzt verändern.

mfg
Enterprise

izaseba
28.03.2008, 20:40
Naja hab mich schon bei void main(void) zurückgehalten.

8-[ Kannst mal sehen, wie oberflächlich ich manchmal lese...

@Enterprise, ändere Dein Programm bitte so, daß es ein int zurückliefert, auch wenn beim AVR nichts zurückgeliefert wird, es ist halt so und müsste eigentlich eine Warnung beim kompilieren geben...

zu Deinem PWM Kanal



TCCR1A = (1<<COM1B1)|(1<<WGM10)|(1<<WGM12);


8 Bit Fast PWM Modus
OC1B geht LOW bei Compare Match also TCNT1= OCR1B
OC1B geht HIGH bei Bottom also TCNT1 = 0

Wenn Du das auf OC1A ändern willst muß so aussehen:


TCCR1A = (1<<COM1A1)|(1<<WGM10)|(1<<WGM12);


und anstatt OCR1B nimmt man halt OCR1A und ja PB1 muß dann als Ausgang deklariert werden.

Zu der PWM Frequenz, tja was ist sinnvoll für Motoren ? 10 kHz ?
wenn Du den Timer mit µC Takt laufen läßt hast Du eine PWM Frequenz von 14745600 / 256 = 57,6 KHz
bei Prescaller 8 7,2 KHz
bei Prescaller 64 900 Hz

Muß mal schauen, was am besten passt.

Und mach das dann so wie McJenso sagt,
am Anfang Timer Initialisieren, im Programm dann nur OCR1A ändern

0 -> Stopp
255-> Voll
128 -> Halb usw.

Gruß Sebastian

Enterprise
28.03.2008, 21:33
Hallo Sebastian,

Jetzt bin ich wirklich durcheinander.



#include <avr/io.h>
#include <stdint.h>


void pwminit()
{
TCCR1A = (1<<COM1A1)|(1<<WGM10)|(1<<WGM12);
TCCR1B = (1<<CS10);
OCR1A = 128;
}

int main()
{
DDRD=0x0c; // Port PD2 u. PD3 auf Port D als Ausgang
PORTD=0x0c; // Pins PD2 u. PD3 auf Port D auf low

DDRB &=~(1<<PB3);
PORTB |=(1<<PB3);

DDRB |= (1<<DDB1);
DDRD |= (1<<DDD5);

pwminit();

while(1)

if ( PINB & ( 1<<PINB3 ) )
{
PORTD |= (1<<PD5);
PORTD |= (1<<PD2); // LED ein "Test"
// pwminit();
}
else
{
PORTD &= ~(1<<PD2); // LED aus "Test"
}

}


Habe versucht alles zu beachten, was ihr mir geschrieben habt.

mfg
Enterprise

izaseba
28.03.2008, 22:12
Jetzt bin ich wirklich durcheinander

:-s Warum ?
Ich glaube es liegt eher daran, daß Du Anfänger in Sachen C u. µC bist, oder ?

Ich versuche Dein Programm etwas abzuändern:



#include <avr/io.h>
#include <stdint.h>

int main(void) {
DDRD=(1<<PD2)|(1<<PD3)|(1<<PD5);
DDRB = (1<<PB1);
PORTB = (1<<PB3);
TCCR1A = (1<<COM1A1)|(1<<WGM10)|(1<<WGM12);
TCCR1B = (1<<CS10);
while(1) {
if ( PINB & ( 1<<PINB3 ) ) {
PORTD |= (1<<PD2)|(1<<PD5);
OCR1A = 128;
}
else {
PORTD &= ~((1<<PD2)|(1<<PD5)); // LED aus "Test"
OCR1A = 0;
}
}
return 0;
}


Ich sag mal so, das müsste klappen :-k

Gruß Sebastian

Enterprise
28.03.2008, 22:48
Danke Sebastian,

Funktioniert natürlich mit deinem Programm.



Ich glaube es liegt eher daran, daß Du Anfänger in Sachen C u. µC bist, oder ?



Dabei hast du recht mit der Annahme.

Habe festgestellt, es ist für ein Anfänger ziemlich schwer ohne jemanden fragen zu können, der Ahnung hat.
Deshalb habe ich mich erst heute Abend um 19.00 Uhr gemeldet.
Da ich den ganzen Tag versucht habe mich im Forum, RN Wissen, Tutorials, Datenblätter u.s.w durch zu lesen.
Das hatte ja keinen roten Faden.

Danke nochmals für deine Hilfe und deine Geduld.

mfg
Enterprise

izaseba
28.03.2008, 23:20
Funktioniert natürlich mit deinem Programm.

Wieso meinem ? Ich habe nur etwas nachgeholfen.

Wichtig ist aber, daß Du das verstehst, dann ist die Erweiterung auf 3 Tasten nur noch ein kleiner Schritt...

Gruß Sebastian

Enterprise
29.03.2008, 10:09
Hallo zusammen,

Gestern habe ich mit izaseba das Programm zusammen gestellt.



#include <avr/io.h>
#include <stdint.h>

int main(void) {
DDRD=(1<<PD2)|(1<<PD3)|(1<<PD5);
DDRB = (1<<PB1);
PORTB = (1<<PB3);
TCCR1A = (1<<COM1A1)|(1<<WGM10)|(1<<WGM12);
TCCR1B = (1<<CS10);
while(1) {
if ( PINB & ( 1<<PINB3 ) ) {
PORTD |= (1<<PD2)|(1<<PD5);
OCR1A = 128;
}
else {
PORTD &= ~((1<<PD2)|(1<<PD5)); // LED aus "Test"
OCR1A = 0;
}
}
return 0;
}


Ich kann in der IF Schleife den Wert OC1A ändern wie ich möchte.
Das hat keine Auswirkung auf die Geschwindigkeit vom Motor.
Habe auch den Prescale auf CS11 geändert.
Hatte auch keine Auswirkung.

mfg
Enterprise

McJenso
29.03.2008, 15:48
Hallo,

muss man für den Motor nicht noch die Richtung vorgeben? Der Motor dreht sich aber oder bewegt er sich gar nicht? Was hast du für einen Motor? Was passiert, wenn du den Taster/Schalter an PB3 betätigst.
Das Programm sieht gut aus. Würde halt CS11 nehmen.

Gruß

Jens

Enterprise
29.03.2008, 17:19
Hallo,



muss man für den Motor nicht noch die Richtung vorgeben? Der Motor dreht sich aber oder bewegt er sich gar nicht? Was hast du für einen Motor? Was passiert, wenn du den Taster/Schalter an PB3 betätigst.
Das Programm sieht gut aus. Würde halt CS11 nehmen.


Wenn ich die Taste drücke dreht sich der Motor in eine Richtung.
Ich meine PB40 mit Getriebe so ungefähr.

Ich habe festgestellt, wenn der Port PB5 high wird, dann
läuft der Motor.
Dann habe ich den Port PB4 high geschaltet mit der PB3 Taste, dann hat sich der Motor nicht gedreht.
Seltsam ?????
Der müßte ja dann auch in die andere Richtung drehen.

Was meist du dazu !

mfg
Enterprise

izaseba
29.03.2008, 17:43
Hallo Enterprise,


Wenn ich die Taste drücke dreht sich der Motor in eine Richtung.
Ich meine PB40 mit Getriebe so ungefähr.

Ich habe festgestellt, wenn der Port PB5 high wird, dann
läuft der Motor.
Dann habe ich den Port PB4 high geschaltet mit der PB3 Taste, dann hat sich der Motor nicht gedreht.
Seltsam ?????
Der müßte ja dann auch in die andere Richtung drehen.

Was meist du dazu !

Solange wir nicht wissen, wie das alles bei Dir verschaltet ist wird Dir kein Mensch helfen können, hast Du mal einen Schaltplan ?

Was wir nur wissen, an PB1 wird ein PWM Signal erzeugt, normalerweise musste der Motortreiber noch ein Paar Signale für die Richtung erfahren.

Gruß Sebastian

Enterprise
29.03.2008, 22:17
Hallo izaseba,

Habe ein paar Infos von diesem Board gefunden.
In meinen Aufzeichnungen ist ein L293D der soll genau wie der
SN754410 sein.

Habe auch gestern, die Leiterbahnen optisch verfolgt und durch gemessen.

Hier zwei Files von dem Schaltplan.

mfg
Enterprise

McJenso
30.03.2008, 09:28
Hallo,

es ist also ein ganz 'normaler' Motor, also kein Schrittmotor oder etwas Bürstenloses. Der Motor muss an die Anschlüsse X1:3 und 4. Die Versorgung für den Motor gehört an X2:2 und 4. Die 5V Versorgung an X2:1 und 3. Ich denke nicht das hier der Fehler ist, aber schau es dir noch mal an. Ich gehe mal davon aus, dass du keinen zweiten Motor angeschlossen hast. Wenn nur PD4 oder PD5 und ein ausreichendes PWM Signal anliegt muss sich der Motor einmal an die eine oder andere Richtung drehen. Bei nur einem angeschlossenen Motor vermute ich ein ständiges Reseten und Neustarten des Controllers. Wie sieht deine Spannungsversorgung aus. Hast du die gleiche Versorgung für den Motor und die Logik?

Gruß

Jens

Enterprise
30.03.2008, 22:06
Hallo,

Ja ich habe zwei Motoren angeschlossen.
Ich nutze gleiche Versorgung für den Motor und die Logik.

mfg
Enterprise

McJenso
31.03.2008, 17:16
Hallo,

haben die Motorgehäuse kontakt zueinander. Es gibt Motoren bei denen ein Anschluss mit dem Gehäuse verbunden ist. Bitte prüf das einmal mit einem Messgerät und baue die Motoren event. isoliert auf. Ich würde die Motoren aber vorerst durch LED's mit Vorwiderstand ersetzen und die Schaltung damit testen. Musst halt die 'Drehrichtung' an die Polung der LED' anpassen. LED's geben keine Störungen ab wie Motoren und lassen sich mit PWM wunderbar dimmen. Sollte die Schaltung dann funktionieren, musst du halt über eine bessere Entstörung und/oder getrennte Versorgungen nachdenken.


Gruß

Jens