Forum: Compiler & IDEs Veränderbare Spannung per PWM @ Atmega16 und dazugehöriges.


von Basti (Gast)


Lesenswert?

So, jetzt habe ich mich doch schon etwas mit meinem nun funktionierenden 
Atmega16 auseinandergesetzt.
Was ich jetzt gerne als Endprodukt hätte ist folgendes:

Der µC soll in der Lage sein eine konkrete Spannung zwischen 0 und 5V 
auszugeben. Also soll man zB. am PC sagen können "Lass ma 3V 
rüberwachsen", per Nullmodemkabel wird der für den µC passende Befehl an 
diesen weitergegeben und dieser setzt per PWM einen Pin auf eben die 
gewünschten 3V.

Das ganze 2 mal, und zwar sollten auch verschiedene Spannungen möglich 
sein ("Pin X bitte 3V, Pin Y bitte 2,5V").




Gegebenenfalls bitte erst die Posts weiter unten lesen bevor man sich 
durch meine langen Texte wühlt, wenn dort schon über andere Fragen 
diskutiert wird, wurden die früher beschriebenen Probleme vermutlich 
schon gelöst ;-)







Wie ich mich bisher an diese Aufgabe herantaste:

Hab mir alles was ich hier an PWM-Tutorials finden konnte durchgelesen 
und denk dass ich die Funktionsweise von PWM soweit verstanden habe. 
Allerdings bin ich auch im Umgang mit C nicht gerade geübt, weshalb noch 
ein paar Fragen auftauchen.
Ich möchte jetzt erst einmal Versuchen dass ich die Spannungen 
herbekomme die ich gerne hätte, aber irgendwie bekomm ich das noch nich 
so ganz hin...

Ich hab mir aus gefundenen Programmstücken bzw. nach den verschiedenen 
Tutorials folgende Grundversion zusammengeschrieben:
1
#include "avr/io.h"
2
#include <avr/pgmspace.h>
3
#define F_CPU 11059200
4
#include <util/delay.h>
5
6
void init(void)
7
{
8
DDRD=0b00110000;    //Pin 18 und 19 als Ausgang
9
ICR1=0xFFFF;      //Top-Wert
10
TCCR1A=0b10100010;  //fast PWM, mode 14, non-inverting
11
TCCR1B=0b00011001;  //fast PWM, no clock division
12
OCR1A=0x8000;      //Compare-Wert A
13
OCR1B=0x8000;      //Compare-Wert B
14
}
15
16
int main(void)
17
{
18
init();
19
20
return 0;
21
}


Läuft soweit alles, ich hab als Comment mal die "Auswirkungen" der 
Einstellungen angefügt, hoffe doch das das soweit Korrekt ist, wenn 
nicht bitte bescheid geben =)

Achja, delay.h hab ich noch drin weil ich vorher mit nachfolgendem 
Pausieren in der Main-Schleife gespielt hab, will das aber erstmal 
rauslassen.


Habe nun an Pin 18 und 19 je einen 100k Ohm Widerstand und nen 22nF 
Kondensator angelötet, wie hier halt:
http://www.mikrocontroller.net/articles/Bild:Pwm_filter_1.png


Wie gesagt, das Progrämmchen läuft, aber wenn ich jetzt die 
Ausgangsspannung messen möchte bekomme ich bei Pin 18 die zu erwartenden 
2,5V, an Pin 19 allerdings steigt die Spannung in ca. 7 Sekunden von 0 
auf 5V an, fällt wieder auf 0 usw.
Ich dachte ich hätte die beiden Ausgänge identisch programmiert, hab ich 
mir da doch irgendwelche Programmteile falsch "zusammengeklaut" bzw. was 
in der Programmierung falsch Verstanden?
Wäre schön wenn ihr mir dabei weiterhelfen könntet =)

Tja und nun das zweite Problem:

Nach diesem Tutorial:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#PWM_.28Pulsweitenmodulation.29
steht so schön "Durch Verändern des OCR1A Wertes werden die 
unterschidelichen PWM Werte eingestellt"
Wenn ich da allerdings was ändere passiert gar nix: Pin 18 behält seine 
2,5V bei, Pin 19 sein (aus meiner Sicht) komisches Verhalten.

Wiederum bin ich Dankbar wenn mir jemand Aufklärung verschafft, entweder 
stimmt was nich oder ich hab was falsch aufgefasst.



So, das wars erstmal, ich werde vermutlich dieses Thema für im weiteren 
Verlauf auftretende Fragen mitbenutzen.

Schonmal vielen Dank für eure hoffentlich zahl- oder lieber hilfreichen 
Antworten ;-)

Basti

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Das Programm ist nicht sonderlich hübsch, aber es funktioniert.
Die Registerbits solltest du besser mit symbolischen Namen
benennen, also:
1
TCCR1A=_BV(COM1A1) | _BV(COM1B1) | _BV(WGM11);
2
TCCR1B=_BV(WGM12) | _BV(WGM13) | _BV(CS10);

Ich habe es bei mir auf einen herumliegenden ATmega16 geflasht,
und bekomme zwei saubere 1:1-Rechtecksignale an PD4 und PD5.
Dein Fehler muss also irgendwo anders liegen.

Hier das Hexfile:
1
:100000000C942A000C9447000C9447000C94470071
2
:100010000C9447000C9447000C9447000C94470044
3
:100020000C9447000C9447000C9447000C94470034
4
:100030000C9447000C9447000C9447000C94470024
5
:100040000C9447000C9447000C9447000C94470014
6
:100050000C94470011241FBECFE5D4E0DEBFCDBF16
7
:1000600010E0A0E6B0E0EAECF0E002C005900D92EE
8
:10007000A036B107D9F710E0A0E6B0E001C01D92AC
9
:10008000A036B107E1F70E945A000C9464000C946A
10
:10009000000080E381BB8FEF9FEF97BD86BD82EAB2
11
:1000A0008FBD89E18EBD80E090E89BBD8ABD99BD82
12
:1000B00088BD0895CFE5D4E0DEBFCDBF0E944900E2
13
:0A00C00080E090E00C946400FFCF94
14
:00000001FF

von Basti (Gast)


Lesenswert?

Hmm, ich glaub ich spinn -.-

Hab jetzt nochmal das gepostete Programm genommen und in hex umgewandelt 
(compiliert, oder?), sowie das gepostete Programm mit deiner Änderung 
versehen und umgewandelt, stimmt aber einfach nicht mit dem von dir 
erzeugten Hexfile überein :S

Ich bekomm folgende Hex-Datei raus:
1
:100000000C942A000C9447000C9447000C94470071
2
:100010000C9447000C9447000C9447000C94470044
3
:100020000C9447000C9447000C9447000C94470034
4
:100030000C9447000C9447000C9447000C94470024
5
:100040000C9447000C9447000C9447000C94470014
6
:100050000C94470011241FBECFE5D4E0DEBFCDBF16
7
:1000600010E0A0E6B0E0EEEDF0E002C005900D92E9
8
:10007000A036B107D9F710E0A0E6B0E001C01D92AC
9
:10008000A036B107E1F70E945A000C946D000C9461
10
:10009000000080E381BB8FEF9FEF97BD86BD82EAB2
11
:1000A0008FBD89E18EBD80E090E89BBD8ABD99BD82
12
:1000B00088BD089580E381BB8FEF9FEF97BD86BD1C
13
:1000C00082EA8FBD89E18EBD80E090E89BBD8ABD4C
14
:0E00D00099BD88BD80E090E00895F894FFCFC0
15
:00000001FF


Mit deiner hexfile funktioniert es richtig, beide Pins liefern 2,5V. Bei 
mir hauts eben nicht hin. Was für ein Programm bzw. was für einen 
Compiler benutzt du denn?
Ich hatte jetzt mit AVR Studio und dazu installiertem WinAVR gearbeitet.

Hoffe das ich die Lösung find, wenn bei mir was falsch compiliert wird 
kanns ja nich laufen >.<

von Sebastian L. (boaschti)


Lesenswert?

Achja: könntest du vielleicht einfach das komplette Programm so posten 
wie dus compiliert hast, vielleicht is ja doch was anders :S

Ansonsten: was kann ich probieren um zu sehen woran es liegt?

von Simon K. (simon) Benutzerseite


Lesenswert?

Ich vermute mal, dass du irgendwo eine falsche Einstellung zum Prozessor 
gemacht hast. Welche Software benutzt du zum Programmieren?

von Sebastian L. (boaschti)


Lesenswert?

Wie gesagt AVR Studio 4.15, build 623 mit installiertem WinAVR 
(1.0.0.10).

Hab halt beim Projekt erstellen "AVR GCC" ausgewählt, dann "AVR 
Simulator" und den ATmega16.

Auf 2 Computern probiert, das Ergebnis is immer das Selbe und stimmt mit 
dem Post von Jörg nicht überein.

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


Lesenswert?

Sebastian L. wrote:
> Wie gesagt AVR Studio 4.15, build 623 mit installiertem WinAVR
> (1.0.0.10).

Was auch immer WinAVR 1.0.0.10 sein soll...  WinAVR-Versionsnummern
sind normalerweise in der Form YYYYMMDD.

> Auf 2 Computern probiert, das Ergebnis is immer das Selbe und stimmt mit
> dem Post von Jörg nicht überein.

Meins war mit einem GCC 4.2.2 compiliert.  Der Unterschied ist, dass
bei mir die Funktion init() wirklich gerufen wird, bei dir dagegen
hat der Compiler sie in main() inline erweitert.  Da die Funktion aber
nicht "static" deklariert ist, musste er trotzdem noch eine Kopie
separat anlegen (damit sie als globale Funktion ggf. von anderen
Modulen aufgerufen werden kann -- dass du keine anderen Module weiter
haben wirst, hast du bzw. AVR Studio ihm nicht mitgeteilt).  Kann
aber auch sein, dass es simpel nur eine andere Optimierung war (bei
mir -Os).

Anyway: dein Hexfile läuft bei mir genauso.  Warum auch nicht, der
tatsächlich ausgeführte Code ist der gleiche.

von Sebastian L. (boaschti)


Lesenswert?

In grad mit nem Trojaner am kämpfen, kann die WinAVR Version grad nich 
mehr überprüfen, wenn ich mich richtig erinnere war es aber genau das, 
nur durch Kommas statt Punkte getrennt.

Ich ahbe keine Ahnung wieso, ich habe nichts verändert, aber es läuft 
jetzt. An beiden Pins liegen 2,5V an, die Spannung lässt sich auch 
verändern wenn ich etwas anderes für den Compare-Wert nehme.
Ehrlich gesagt gehts mir so langsam auf die Nerven dass ich irgendwelche 
Probleme habe die dann von alleine verschwinden. Klar is das besser als 
wenn man keine Lösung fidnet, aber trotzdem wüsste ich gerne warum es 
nich funktioniert hat >.<

Ertsmal vielen Dank fürs Antworten, werd jetzt weiter damit rumspielen, 
bis zur nächsten Frage ;-)

Basti

von Sebastian L. (boaschti)


Lesenswert?

So, da kommen auch schon die nächsten Fragen. Bin leider Anfänger sowohl 
in C-Programmierung als auch bzgl. µC, deshalb bin ich bei meinem 
Projekt etwas auf mithilfe angewiesen. Habe zwar schon das 
AVR-GCC-Tutorial durchstöbert, aber noch ist mir die Realisierung zu 
meiner "Aufgabe" nicht über den Weg gelaufen und momentan habe ich weder 
Zeit noch Nerven von Grund auf das gesamte Tutorial durchzuarbeiten, das 
kommt bei Gelegenheit mal. Deshalb wäre ich euch sehr dankbar wenn ihr 
mir in Grundzügen beschreibt wie ich das am besten umsetzten sollte, 
oder mir sagt wo ich die dafür nötigen Informationen finden kann.


Wie oben beschrieben geht es um folgendes:

Der µC soll in der Lage sein eine konkrete Spannung zwischen 0 und 5V
auszugeben. Also soll man zB. am PC sagen können "Lass ma 3V
rüberwachsen", per Nullmodemkabel wird der für den µC passende Befehl an
diesen weitergegeben und dieser setzt per PWM einen Pin auf eben die
gewünschten 3V.

Das ganze 2 mal, und zwar sollten auch verschiedene Spannungen möglich
sein ("Pin X bitte 3V, Pin Y bitte 2,5V").

Diese 0-5V sollen dann per weiterer Gerätschaften die sich über die 
Spannungen Regeln lassen auf 0-300V bzw. 0-2A umgewandelt werden.


Mein PWM-Progrämmchen (siehe oben) läuft soweit, ich kann über eine 
Veränderung des Compare-Wertes die Spannung auch perfekt verändern.

Jetzt habe ich mir mal folgendes ausgerechnet:

Ich setze den Top-Wert auf FFFF, also Dezimal auf 65535.
Die vom µC ausgegebene Spannung wird ja versechzigfacht, diese 
Endspannung sollte in 25V-Schritten veränderbar sein. Das wiederum 
heisst die vom µC ausgegebene Spannung sollte in 25/60, d.h in 5/12 
Volt-Schritten veränderbar sein.
Das wiederum würde bedeuten ich müsste den Compare-Wert in Schritten von 
5461 verändern.


Wie lässt sich das realisieren? Also dass eine Eingabe über die serielle 
Schnittstelle erfolgt, und diese dann vom µC verarbeitet werden kann, so 
dass die beiden Compare-Werte den passenden Wert annehmen?

Das wäre jetzt nur die Umsetzung der Aufgabenstellung die ich mir 
überlege, wenn es auch anders möglich ist eine Ausgangsspannung 
entsprechend einem Befehl vom PC aus zu steuern bin ich auch dafür 
offen.


Wie gesagt, mir fehlt einfach die Zeit alles selbst zu entwickeln, es 
ist auch nicht gerade leicht das zu tun wenn man sowohl in 
C-Programmierung als auch in Sachen µC Angänger ist :S

Insofern hoffe ich einfach dass sich jemand die Zeit nimmt mir dabei ein 
wenig unter die Arme zu greifen, das wäre wirklich sehr freundlich.
Achja: Ich weiss nicht, aber nahc einer wahnsinnig ausgefallenen 
Aufgabenstellung klingt das doch eigentlich nicht? Falls es schon 
irgendwo eine Anleitung oder ein Thema zum umsetzten von "PC lässt den 
µC bestimmte Spannungen asugeben" gibt wäre ich natürlich froh darüber 
mir das ansehen zu können.

Ansonste schon einmal vielen Dank im Voraus, ich weiss das es meist 
nicht sonderlich interessant ist einem Anfänger zu helfen, aber ich wäre 
wirklich froh wenn das trotzdem jemand tun könnte ^^


Basti

von Sebastian L. (boaschti)


Lesenswert?

Bump... wie gesagt, ich bin gewissermassen auf eure Hilfe angewiesen, 
wäre schön wenn sich jemand findet der mir ein paar Hinweise gibt =)

von Peter D. (pdiener) Benutzerseite


Lesenswert?

Hallo Sebastian,

du baust am besten erst mal in die init Funktion das folgende mit ein:
1
UCSRB |= (1<<TXEN);
2
3
UCSRC |=
4
(1<<URSEL)|     /*muss gesetzt sein*/
5
(0<<UMSEL)|     /*Asynchrone Schnittstelle*/
6
(0<<UPM1)|      /*no parity*/
7
(0<<UPM0)|      /*no parity*/
8
(0<<USBS)|      /*one stop bit only*/
9
(1<<UCSZ1)|     /*8-bit mode*/
10
(1<<UCSZ0)|     /*8-bit mode*/
11
(0<<UCPOL);     /*Write this to zero in asynchronous mode*/
12
13
UBRRH = 0;
14
UBRRL = 71;

UBRRL ist für die Baudrate zuständig, die Einstellung sollte mit deinem 
Quarz 9600 Baud ergeben. Die Schnittstelle ist dann konfiguriert und 
kann verwendet werden.

Dann machst du am besten so weiter, wie es im Tutorial steht:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Senden_mit_dem_UART

Dann musst du dir ein Übertragungsprotokoll ausdenken, das die 
übertragenen Daten im Atmega rekonstruieren kann und auf PC Seite 
überhaupt erst mal erzeugt. Das ist im einfachsten Fall eine 
Konsolenanwendung, die nur auf dem Atmega läuft und auf PC Seite ein 
Terminal hat. Dort könnte man die Daten manuell eingeben. Wenn 
irgendwelche Funktionen komplizierterer Art als Spannung ausgegeben 
weden sollen, ist auf PC Seite wohl auch noch ein Stück Software 
notwendig, sei es nur ein VB-Makro, dass irgendwelche Daten von Excel 
zum Mikrocontroller schickt. Du hast irgendwas von einem Webserver 
gesagt, der das steuern soll?

>Habe nun an Pin 18 und 19 je einen 100k Ohm Widerstand und nen
>22nF Kondensator angelötet, wie hier halt:

Ich habe 47k und 22µF eingebaut...
Sonst wäre die Glättung etwas schlecht bei 168Hz.

Grüße,

Peter

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
Noch kein Account? Hier anmelden.