PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : PWM mit ATMega8



Spurius
10.09.2004, 20:18
Hallo,
könnt ihr mir vielleicht sagen wie ich in Bascom ein PWM Signal erzeugen kann? Ich hab schon gesucht, aber nichts gefunden, was mir weiterhilft.
Es gibt ja auch Hard- und Software-PWM...
Gruß
Spurius

Frank
10.09.2004, 22:10
Hi,

wenn du unter Bascom programmierst geht das unter fast allen Atmel Controllern gleich. Du kannst dir also auch andere Beispiele anschaun. Hier z.B. das Programm zum Mega 16 (rn-control)
Schau dir darin mal die Motorroutine an




'################################################# ##
'rncontroltest.BAS
'für
'RoboterNetz Board RN-CONTROL 1.1
'Das neue preiswerte Controllerboard zum experimentieren
'
'Aufgabe:
' Dieses testprogramm testet gleich mehrere Eigenschaften auf dem Board
' Den verschiedenen Tasten sind bestimmte Funktionen zugeordnet
' Taste 1: Zeigt Batteriespannung über RS232 an
' Taste 2: Angeschlossene Motoren beschleunigen und abbremsen
' Taste 3: Einige male Lauflicht über LED´s anzeigen. Am I2C-Bus
' darf in diesem Moment nichts angeschlossen sein
' Taste 4: Zeigt analoge Messwerte an allen Port A PIN´s über RS232 an
''Taste 5: Zeigt digitalen I/O Zustand von PA0 bis PA5 an


' Ser gut kann man aus dem Demo auch entnehmen wie Sound ausgegeben wird,
' wie Tasten abgefragt werden und wie Subroutinen und Funktionen angelegt werden

'Autor: Frank
'Weitere Beispiele und Beschreibung der Hardware
'unter http://www.Roboternetz.de oder robotikhardware.de
'################################################# ######


Declare Sub Batteriespannung()
Declare Sub Motortest()
Declare Sub Lauflicht()
Declare Sub Showporta()
Declare Sub Showdigitalporta()
Declare Function Tastenabfrage() As Byte


$regfile = "m16def.dat"

Dim I As Integer
Dim N As Integer
dim Ton As Integer


$crystal = 16000000 'Quarzfrequenz
$baud = 9600

Config Adc = Single , Prescaler = Auto 'Für Tastenabfrage und Spannungsmessung

Config Pina.7 = Input 'Für Tastenabfrage
Porta.7 = 1 'Pullup Widerstand ein


Const Ref = 5 / 1023 'Für Batteriespannungsberechnung

Dim Taste As Byte
Dim Volt As Single

' Für Motorentest
'Ports für linken Motor
Config Pinc.6 = Output 'Linker Motor Kanal 1
Config Pinc.7 = Output 'Linker Motor Kanal 2
Config Pind.4 = Output 'Linker Motor PWM
'Ports für rechten Motor
Config Pinb.0 = Output 'Rechter Motor Kanal 1
Config Pinb.1 = Output 'Rechter Motor Kanal 2
Config Pind.5 = Output 'Rechter Motor PWM
Config Timer1 = Pwm , Pwm = 10 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down
Pwm1a = 0
Pwm1b = 0
Tccr1b = Tccr1b Or &H02 'Prescaler = 8





I = 0
Sound Portd.7 , 400 , 450 'BEEP
Sound Portd.7 , 400 , 250 'BEEP
Sound Portd.7 , 400 , 450 'BEEP
Print
Print "**** RN-CONTROL 1.1 *****"
Print "Das neue Experimentier- und Roboterboard"
Print
Do




Taste = Tastenabfrage()
If Taste <> 0 Then

Select Case Taste
Case 1
Call Batteriespannung 'Taste 1 Zeigt Bateriespannung über RS232 an
Case 2
Call Motortest 'Taste 2 Motoren beschleunigen und abbremsen
Case 3
Call Lauflicht 'Einige male Lauflicht über LED´s anzeigen. Am I2C-Port darf in diesem Moment nichts angeschlossen sein
Case 4
Call Showporta 'Zeigt Messwerte an allen Port A PIN´s
Case 5
Call Showdigitalporta 'Zeigt digitalen I/O Zustand von PA0 bis PA5 an



End Select
Sound Portd.7 , 400 , 500 'BEEP
End If

Waitms 100
Loop

End




'Diese Unterfunktion fragt die Tastatur am analogen Port ab
Function Tastenabfrage() As Byte
Local Ws As Word

Tastenabfrage = 0
Ton = 600
Start Adc
Ws = Getadc(7)
If Ws < 1010 Then
Select Case Ws
Case 410 To 450
Tastenabfrage = 1
Ton = 550
Case 340 To 380
Tastenabfrage = 2
Ton = 500
Case 265 To 305
Tastenabfrage = 3
Ton = 450
Case 180 To 220
Tastenabfrage = 4
Ton = 400
Case 100 To 130
Tastenabfrage = 5
Ton = 350
End Select
Sound Portd.7 , 400 , Ton 'BEEP
End If

End Function



'Diese Unterfunktion zeigt Bateriespannung an
Sub Batteriespannung()
Local W As Word
Start Adc
W = Getadc(6)
Volt = W * Ref
Volt = Volt * 5.2941
Print "Die aktuelle Spannung beträgt: " ; Volt ; " Volt"

End Sub


'Testet Motoren und Geschwindigkeitsreglung
Sub Motortest()
'Linker Motor ein
Portc.6 = 1 'bestimmt Richtung
Portc.7 = 0 'bestimmt Richtung
Portd.4 = 1 'Linker Motor EIN

'Rechter Motor ein
Portb.0 = 1 'bestimmt Richtung rechter Motor
Portb.1 = 0 'bestimmt Richtung rechter Motor
Portd.5 = 1 'rechter Motor EIN


I = 0
Do
Pwm1a = I
Pwm1b = I
Waitms 40
I = I + 5
Loop Until I > 1023

Wait 1
Do
Pwm1a = I
Pwm1b = I
Waitms 40
I = I - 5
Loop Until I < 1
Pwm1a = 0 'Linker Motor aus
Pwm1b = 0 'rechter Motor aus
End Sub


'Einige male Lauflicht über LED´s anzeigen. Am I2C-Port darf in diesem Moment nichts angeschlossen sein
Sub Lauflicht()

Config Portc = Output
Portd = 0
For N = 1 To 10
For I = 0 To 7
Portc.i = 0
Waitms 100
Portc.i = 1
Next I
Next N
Config Portc = Input
End Sub


'Zeigt Die Analogen Messwerte An Port A An
Sub Showporta()
Local Ws As Word

Config Porta = Input
For I = 0 To 5 ' Alle internen Pullup Widerständ ein,bis auf Batteriespannungsmessungsport
Porta.i = 1
Next I

Print
Print "Ermittelte Messwerte an Port A:"
For I = 0 To 7 ' Alle Eingäne inkl.messen
Start Adc
Ws = Getadc(i)
Volt = Ws * Ref
Print "Pin " ; I ; " ADC-Wert= " ; Ws ; " bei 5V REF waeren das " ; Volt ; " Volt"
Next I
End Sub


'Zeigt den Zustand einiger freier I/OI/O von Die Analogen Messwerte An Port A An
Sub Showdigitalporta()
Local Zustand As String
Config Porta = Input
For I = 0 To 5 ' Alle internen Pullup Widerständ ein,bis auf Batteriespannungsmessungsport
Porta.i = 1
Next I

Print
Print "Ermittelter I/O Zustand Port A:"
For I = 0 To 5 ' Alle Eingäne inkl.messen
If Pina.i = 1 Then
Zustand = "High"
Else
Zustand = "Low"
End If
Print "Pin " ; I ; " I/O Zustand= " ; Pina.i ; " " ; Zustand
Next I
End Sub



Entscheident sind dabei folgende Zeilen:


Config Pind.4 = Output 'Linker Motor PWM
Config Pind.5 = Output 'Rechter Motor PWM
Config Timer1 = Pwm , Pwm = 10 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down
Pwm1a = 0
Pwm1b = 0
Tccr1b = Tccr1b Or &H02 'Prescaler = 8


Nach der oberen Konfigurationsphase kannst du also einfach PWM regeln mit:

Pwm1a = Geschwindigkeit 0 bis 1023
Pwm1b = Geschwindigkeit 0 bis 1023

Spurius
10.09.2004, 23:35
Hallo,
kannst du mit das nochmal genauer erklären? Vor allem den 2ten Code.
Es reicht schon ein Pin oder? Und wird das dann hardwaremäßig derzeugt?

Frank
10.09.2004, 23:55
PWM ist immer ein gepulstes Signal das an einer Portleitung ausgegeben wird.
In dem Beispiel wurden zwei unabhängige PWM-Signal generiert um zwei Motoren in der Geschwindigkeit steuern zu können.
An den Port muß in dem Fall natürlich noch eine Endstufe (im einfachsten Falle Transistor) angeschlossen werden.
Das PWM-Signal wird über einen Timer generiert, das meinst du vermutlich mit "Hardware Pwm".
Man könnte auch einen Interrupt erzeugen und darin einen Port ein und ausschalten. Das würdest du dann vermutlich als "Software-PWM"
bezeichnen. Im Grunde ist beides das gleiche. Die Generierung mit Timer ist nur etwas genauer und benötigt weniger Rechenleistung.
Was PWM genau ist, dazu findest du hier im Forum schon edliche Beiträge die versuchen dies zu erklären. Nimm am besten mal die Suchfunktion.

Kurze Erläuterung zu den Zeilen
Diese Beiden Zeilen schalten die entsprechend duch die Hardware vorgegebene Ports auf Ausgang um

Config Pind.4 = Output 'Linker Motor PWM
Config Pind.5 = Output 'Rechter Motor PWM

Hier wird der PWM-Modus konfiguriert (Syntax der Anweisung findest du in Bascom Helpdatei)
Dabei wird 10 Bit PWM genutzt, daher kann man später Werte von 0 bis 1023 einstellen. Oft wird auch der 8 Bit Modus benutzt, dann halt nur zwischen 0 und 255

Config Timer1 = Pwm , Pwm = 10 , Compare A Pwm = Clear Down , Compare B Pwm = Clear Down
Ein Register das die PWM-Bitzahl festlegt
Tccr1b = Tccr1b Or &H02

Ausgang wird erst mal ganz runtergeregelt

Pwm1a = 0
Pwm1b = 0

Spurius
11.09.2004, 10:42
Hallo,
sry wenn ich mich dumm anstelle, aber ich finde zu PWM keine Hilfe bei Bascom. Und ich hab leider noch nicht verstanden, wie ich ein bestimmtes Signal wie z.b. 10, 15 khz etc. erzeugen kann.
Trotzdem Danke für die Hilfe
Gruß
Spurius

Frank
11.09.2004, 12:29
Die PWM-Frequenz hat bei der normalen Steuerung von Motoren eine untergeordnete Rolle. Sie wird bestimmt durch den Teiler (Prescaler) und die Auflösung des Timers.
Dazu musst du unbedingt das Datenblatt des Mega8 heranziehen (die Register sind bei den Megas aber fast identisch).

Vielleicht sollten wir doch noch einen Artikel über PWM bei den Megas schreiben. Leide rfehlt mir ein wenig die Zeit zu, aber vielleicht hat jemand anders Lust.

Ich kopiere mir als Erinnerung gerne Bitbeschreibungen der Registe rin den Sourcecode, dann wird´s übersichtlicher.
Zum Beispiel so:



'PWM Frequenz Initialisieren
Tccr1a = &B10100010 '9 Bit PWM
' Bit 7/6 = 00 COM1A1/COM1A0 Pin OC1A nicht mit T/C1 verbunden
' Bit 7/6 = 01 COM1A1/COM1A0 Pin OC1A nicht mit T/C1 verbunden (wenn WGM13=0)
' Bit 7/6 = 10 COM1A1/COM1A0 bei Übereinstimmung OC1A LO beim Aufwärtszählen und Hi beim Abwärtszählen
' Bit 7/6 = 11 COM1A1/COM1A0 bei Übereinstimmung OC1A Hi beim Aufwärtszählen und Lo beim Abwärtszählen
' Bit 5/4 = 00 COM1B1/COM1B0 Pin OC1B nicht mit T/C1 verbunden
' Bit 5/4 = 01 COM1B1/COM1B0 Pin OC1B nicht mit T/C1 verbunden (wenn WGM13=0)
' Bit 5/4 = 10 COM1B1/COM1B0 bei Übereinstimmung OC1B LO beim Aufwärtszählen und Hi beim Abwärtszählen
' Bit 5/4 = 11 COM1B1/COM1B0 bei Übereinstimmung OC1B Hi beim Aufwärtszählen und Lo beim Abwärtszählen
' Bit 3/2 = FOC1A/FOC1B Neue Mega Bits - Bedeutung?
' Bit 1/0 = 00 WGM11/WGM10 PWM nicht aktiv
' Bit 1/0 = 01 WGM11/WGM10 8 Bit PWM
' Bit 1/0 = 10 WGM11/WGM10 9 Bit PWM
' Bit 1/0 = 11 WGM11/WGM10 10 Bit PWM

Tccr1b = &B10000001
' Bit 7 = 1 INCNC1 Noise Channel
' Bit 6 = 0 ICES1 Fallende Flanke
' Bit 5 = WGM13
' Bit 4 = WGM12
' Bit 2/1/0 = 000 CS12/CS11/CS10 Stop Timer/Counter 1
' Bit 2/1/0 = 001 CS12/CS11/CS10 Voller Takt
' Bit 2/1/0 = 010 CS12/CS11/CS10 Takt/8
' Bit 2/1/0 = 011 CS12/CS11/CS10 Takt/64
' Bit 2/1/0 = 100 CS12/CS11/CS10 Takt/256
' Bit 2/1/0 = 101 CS12/CS11/CS10 Takt/1024
' Bit 2/1/0 = 110 CS12/CS11/CS10 Externer Takt an Pin T1, fallende Flanke
' Bit 2/1/0 = 111 CS12/CS11/CS10 Externer Takt an Pin T1, steigende Flanke


In der Help-Datei von Bascom findet man schon was, du mußt nach Timer suchen, dann findest du das:



Action
Configure TIMER1.


Syntax
CONFIG TIMER1 = COUNTER | TIMER | PWM ,
EDGE=RISING | FALLING , PRESCALE= 1|8|64|256|1024 ,
NOISE CANCEL=0 |1, CAPTURE EDGE = RISING | FALLING ,
CLEAR TIMER = 1|0,
COMPARE A = CLEAR | SET | TOGGLE I DISCONNECT ,
COMPARE B = CLEAR | SET | TOGGLE I DISCONNECT ,
PWM = 8 | 9 10 ,
COMPARE A PWM = CLEAR UP| CLEAR DOWN | DISCONNECT

COMPARE B PWM = CLEAR UP| CLEAR DOWN | DISCONNECT


Remarks
The TIMER1 is a 16 bit counter. See the hardware description of TIMER1.
It depends on the chip if COMPARE B is available or not.


The syntax shown above must be on one line. Not all the options need to be selected.

Here is the effect of the various options.

EDGE You can select whether the TIMER will count on the falling or rising edge. Only for COUNTER mode.
CAPTURE EDGE You can choose to capture the TIMER registers to the INPUT CAPTURE registers
With the CAPTURE EDGE = FALLING/RISING, you can specify to capture on the falling or rising edge of pin ICP
NOISE CANCELING To allow noise canceling you can provide a value of 1.
PRESCALE The TIMER is connected to the system clock in this case. You can select the division of the system clock with this parameter.
Valid values are 1 , 8, 64, 256 or 1024
The TIMER1 also has two compare registers A and B
When the timer value matches a compare register, an action can be performed

COMPARE A The action can be:
SET will set the OC1X pin
CLEAR will clear the OC1X pin
TOGGLE will toggle the OC1X pin
DISCONNECT will disconnect the TIMER from output pin OC1X
And the TIMER can be used in PWM mode
You have the choice between 8, 9 or 10 bit PWM mode
Also you can specify if the counter must count UP or down after a match
to the compare registers
Note that there are two compare registers A and B


PWM Can be 8, 9 or 10.
COMPARE A PWM PWM compare mode. Can be CLEAR UP or CLEAR DOWN
Using COMPARE A, COMPARE B, COMPARE A PWM or COMPARE B PWM will set the corresponding pin for output. When this is not wanted you can use the alternative NO_OUTPUT version that will not alter the output pin.
For example : COMPARE A NO_OUTPUT , COMPARE A PWM NO_OUTPUT

Example
'-------------------------------------------------------------------
' TIMER1.BAS for the 8515
'-------------------------------------------------------------------

Dim W As Word

'The TIMER1 is a versatile 16 bit TIMER.
'This example shows how to configure the TIMER

'First like TIMER0 , it can be set to act as a TIMER or COUNTER
'Lets configure it as a TIMER that means that it will count and that
'the input is provided by the internal clock.
'The internal clock can be divided by 1,8,64,256 or 1024
Config Timer1 = Timer , Prescale = 1024


'You can read or write to the timer with the COUNTER1 or TIMER1 variable
W = Timer1
Timer1 = W


'To use it as a COUNTER, you can choose on which edge it is triggered
Config Timer1 = Counter , Edge = Falling, , Prescale = 1024
'Config Timer1 = Counter , Edge = Rising

'Also you can choose to capture the TIMER registers to the INPUT CAPTURE registers
'With the CAPTURE EDGE = , you can specify to capture on the falling or rising edge of pin ICP
Config Timer1 = Counter , Edge = Falling , Capture Edge = Falling , , Prescale = 1024
'Config Timer1 = Counter , Edge = Falling , Capture Edge = Rising

'To allow noise canceling you can also provide :
Config Timer1 = Counter , Edge = Falling , Capture Edge = Falling , Noise Cancel = 1, , Prescale = 1024

'to read the input capture register :
W = Capture1
'to write to the capture register :
Capture1 = W





'The TIMER also has two compare registers A and B
'When the timer value matches a compare register, an action can be performed
Config Timer1 = Counter , Edge = Falling , Compare A = Set , Compare B =
Toggle, , Prescale = 1
'SET , will set the OC1X pin
'CLEAR, will clear the OC1X pin
'TOGGLE, will toggle the OC1X pin
'DISCONNECT, will disconnect the TIMER from output pin OC1X


'To read write the compare registers, you can use the COMPARE1A and COMPARE1B variables
Compare1a = W
W = Compare1a


'And the TIMER can be used in PWM mode
'You have the choice between 8,9 or 10 bit PWM mode
'Also you can specify if the counter must count UP or down after a match
'to the compare registers
'Note that there are two compare registers A and B
Config Timer1 = Pwm , Pwm = 8 , Compare A Pwm = Clear Up , Compare B Pwm = Clear Down

'to set the PWM registers, just assign a value to the compare A and B registers
Compare1a = 100
Compare1b = 200

'Or for better reading :
Pwm1a = 100
Pwm1b = 200

End


Bruachst du überhaupt PWM? Oder verwechselst du das mit dem normalen Timer der auch Frequenzen erzeugen kann?
Lade dir dazu mal das Programm hier runter:

https://www.roboternetz.de/phpBB2/dload.php?action=file&file_id=169

Ich glaub das könnte was für dich sein.

Gruß Frank

Spurius
11.09.2004, 13:40
Hallo,
ich glaub du hast recht, ich brauch kein PWM, sondern einfach eine Timerfrquenz. Vielen Dank für die Hilfe!
Gruß
Spurius

Spurius
11.09.2004, 15:50
Hallo nochmal,
ich hab mir das Programm runtergeladen und auch Code bekommen.
Aber verstehen tu ichs nicht, kannst du mir erklären, wie das funktioniert?
Und was der Timervorgabewert zu bedeuten hat? Ich habe bei 36 khz den Wert 145.

11.09.2004, 17:22
Du mußt nur den Code der im unteren Fenster erzeugt wird in dein Bascom Programm kopieren und compilieren. Der Code ist eigentlich dokumentiert.
Ansonsten empfehle ich Dir auch ein Buch
https://www.roboternetz.de/phpBB2/viewtopic.php?t=2060

Spurius
11.09.2004, 20:54
Das ich den Code kopieren muss ist mir schon klar, nur ich verstehe das mit der Timervorgabe nicht und wüsste gern wie die Berechnung geht.

Frank
11.09.2004, 21:04
Aber das hab ich doch schon versucht zu erklären. Das wird durch die Register bestimmt, schau dir den Quelltext der generiert wird genau an. Lese dir dazu die Beschreibung der genannten register im Datenblatt vom Mega 8 durch.

Der Quarztakt wird durch den Prescaler-Wert geteilt. Das Ergebnis wird dann noch durch die Auflösung des Timers (zb. 256 oder 1024) geteilt. Daraus gergibt sich die Frequenz. Man kann auch einen bestimmten Timerwert bei jedem Interrupt schon vorgeben (so wird es bei dem generierten Code gemacht), dann kann man quasi fast alle Frequenzen recht genau erzeugen

Schau dazu auch mal in diesen Thread
https://www.roboternetz.de/phpBB2/viewtopic.php?t=3092&highlight=timer

Dem Tool Timer brauchst du ja nur zu sagen was für eine Frequenz du haben möchtest (ganz oben), danach erzeugt es automatisch das Programm das genau diese Frequenz erzeugt. Somit hast du da garkeine Arbeit mehr mit.

Hier hab ich noch ne gute Seite für dich, auch hier wird es recht gut erklärt.
http://www.rowalt.de/mc/avr/avrboard/05/avrb05.htm

Spurius
12.09.2004, 00:49
Ok, ich glaub ich verstehs allmählich.
Ich brauche das Ganze, um eine IR-Sende-Diode mit 36 khz zu betreiben.
Wie gebe ich das Signal an den Port aus? Was muss da in der Routine stehen, wenn der Interrupt ausgelöst wird?

12.09.2004, 12:52
1. Das Tool runter laden: https://www.roboternetz.de/phpBB2/dload.php?action=file&file_id=169

2. Ton erzeugen anklicken

3. Im oberen Feld Frequenz (also 36000) eingeben

4. "Berechnen" klicken und generierten Code in Bascom kopieren

5. Statt dem Piezo-Lautsprecher schließt du nun deine IR-Diode an dem Port an. Alternativ kannst du auch einfach Port ändern, je nachdem welchen du beim Mega 8 nehmen willst. Vergess nicht oben include "m16def" durch "m8def" zu ändern.

Einfacher gehts nu nicht mehr ;-)

Spurius
12.09.2004, 13:04
Wie das mit dem Code erzeugen geht ist mir schon klar, ich wollt nur wissen wie ich das Signal ausgebe.
Also wenn ich das richtig verstehe wird einfach bei jedem Interrupt der High/Low Zustand vertauscht.

12.09.2004, 13:19
Oh Mann, RTFM.
Jeder Form von Timer-PWM ist hardwaremäßig ein Pin zugeordnet (OC1A, ...).

Frank
12.09.2004, 15:26
Er meint kein PWM sondern nur Frequenzausgabe.
Dazu musst du einfach im Interrupt einen Port Toggeln (umschalten). Das hast du richtig erkannt. Dies macht doch schon der generierte Code von dem oben genannten Tool.
In dem Gastposting hatte ich doch eben geschrieben das du dann statt Piezo einfach deine IR-Diode mit Vorwiderstand ran hängen kannst.
Bei Punkt 3 hab ich mich auf die schnelle vertan, du musst dort 72000 eingeben, weil du ja pro interrupt nur einmal umschaltest. Also wenn der Interrupt 72000 mal pro Sekunde aufgerufen wird und du nur einmal den Port im Interrupt umschaltest (was sinnvoll ist), dann ergibt das am Port eine Frequenz von genau 36000 Hz (36 khz). Aber das steht auch in den dokumentierten Zeilen im generierten Code!



1. Das Tool runter laden: https://www.roboternetz.de/phpBB2/dload.php?action=file&file_id=169

2. Ton erzeugen anklicken

3. Im oberen Feld Frequenz (also 36000) eingeben
Fehler, meinte 72000 da Port ja im Interrupt nur einmal umgeschaltet wird - also halbe Periode!

4. "Berechnen" klicken und generierten Code in Bascom kopieren

5. Statt dem Piezo-Lautsprecher schließt du nun deine IR-Diode an dem Port an. Alternativ kannst du auch einfach Port ändern, je nachdem welchen du beim Mega 8 nehmen willst. Vergess nicht oben include "m16def" durch "m8def" zu ändern.

Einfacher gehts nu nicht mehr ;-)

Spurius
12.09.2004, 15:35
Ok, vielen Dank für die Hilfe, sry wenn ich etwas begriffsstutzig war.
Gruß
Spuurius