Forum: Mikrocontroller und Digitale Elektronik Rechteckgenerator Warteschleife


von Tmelle (Gast)


Lesenswert?

Hallo,

ich möchte einen Rechteckgenerator mit dem Controller Atmega8 bauen.
Es sollen Frequenzen von 1 Hz bis 1MHz ausgewählt werden.

Die Menüsteuerung mit einlesen der Werte (Frequenzbereich, 
Tastverhältnis und Frequenz) funktioniert bereits.

Ein Problem was ich habe ist die Gestalltung der Warteschleife für die 
Impulszeit und die Pausenzeit.

In etwa habe ich mir das so vorgestellt:
Bsp 1Hz und Tastverhältnis 50%:

Do

PORTB.0=1
warteschleife für Impuls (0,5s)
PORTB.0=0
warteschleife für Pause (0,5s)

Loop

Mein Problem ist die Durchführung der Takte (z.B. 0,5s)

Weil meine Prozessortaktung 3,686411Mhz beträgt müssen für 1s Wartezeit
3686411 Takte durchgeführt werden.

Für 0,5s also 1823405,5 Takte (die Hälfte).

Jetzt zu meinem Problem:
i=0

Do
i=i+1
Loop  XX

Wenn ich das jetzt richtig verstehe besteht diese Schleife aus 3 Takten
also muss Sie 1823405,5/3=607802 mal Wiederhohlt werden.

Ist das Richtig so?

MfG Tmelle

von Kannnix (Gast)


Lesenswert?

Die Schleife besteht aus erheblich mehr als 3 Takten, schau Dir mal den 
generierten Assemblercode an. Da siehst Du genau, was passiert.

Grob geschätzt: Mit einem Takt von 3MHz kannst Du 1MHz max. Frequenz 
vergessen (siehe oben).

von Michael (Gast)


Lesenswert?

Mit Atmegas hab ich keine Erfahrung aber nur mal so als Tip: Bei einem 
PIC ist der Systemtakt nur ein viertel des Oszilatortaktes, d.h.u.a. es 
müssen vier Ozilatortakte vergehen bis sich überhaupt ein Portpin ändern 
kann bzw. eine Änderung im PIC ankommt. Beim Atmega könnte ich mir 
vorstellen ist es ähnlich und dann wird es aber eng mit ca. 3 Mhz 
Oszilatortakt 1 Mhz Takt an den Pins zu generieren.

von Ste N. (steno)


Lesenswert?

Hallo Tmelle,

also ich kann dich beruhigen, der Atmega macht pro Oszilatortakt ein 
Prozessortakt. Allerdings kommen mir für ein 1MHz Rechtecksignal 3,6Mhz 
Prozessortakt recht wenig vor. Ich würde höher gehen und vor allem einen 
Timer inkl. Interrupt und Timercompareregister benutzen. Damit erfolgt 
das Pintoggeln automatisch und Du brauchst dich überhaupt nicht mehr um 
irgendwelche Warteschleifen zu kümmern. Im Hauptprogramm werden die 
Werte eingelesen und nur die entsprechenden Register des Timers gesetzt.

Siehe auch: http://www.mikrocontroller.net/articles/AVR-Tutorial:_Timer

Gruß, Steffen

von Tobias Korrmann (Gast)


Lesenswert?

Gibt es bi dem Atmega8 keine Timer die man nutzen kann?

von Tmelle (Gast)


Lesenswert?

Hallo,

danke für eure Antworten, ich werde das Mal mit den Timern Probieren.

Mein Problem ist, dass bei dem Generator das Tastverhältnis, also das 
Verhältnis Pausenzeit/Impulszeit einstellbar sein soll.

Das Hauptprogramm ließt die gewünschte Frequenz und das Tastverhältnis 
ein.
(bereits Fertig).

Der Prozessortakt wird beim fertigen Gerät dann auf 16MHz erhöht. Zum 
Entwickeln werde ich erstmal einen Frequenzbereich von 1-100Hz benutzen.

Es wäre nett wenn ihr mir helfen könntet.

von Tmelle (Gast)


Lesenswert?

Sry für Tripplepost aber der Timer funktioniert jetzt auch mit der 
Einstellung des Tastverhältnisses.

Jetzt fehlt mir die Möglichkeit den Prescaler des Timers umzuändern bzw. 
zu senken, damit höhere Frequenzen möglich sind.

Ich habe das wiefolgt versucht:

Disable
         Reset Timer1
         If Presc = 8 Then Config Timer1 = Timer , Prescale = 8
         If Presc = 64 Then Config Timer1 = Timer , Prescale = 64

Das Funktioniert leider nicht weil (ich denke), der Compiler (in diesem 
Falle Bascom) sich die ganzen Configzeilen am Anfang raussucht und diese 
zuerst in hexcode umwandelt.

Gibt es eine möglichkeit den Prescaler innerhalb des Programms zu 
ändern?

MfG Tmelle

von Falk B. (falk)


Lesenswert?

@  Tmelle (Gast)

>Gibt es eine möglichkeit den Prescaler innerhalb des Programms zu
>ändern?

Sicher. Einfach das Register TCCR1B direkt beschreiben. Siehe 
Datenblatt.

MFG
Falk

von thcamper (Gast)


Lesenswert?

Also ich habe das bei meinem ersten Projekt so gemacht, dass ich nen 
kleinen prescaler verwendet habe.
Dann wird mit jedem Interrupt des Timers einfach ein Register 
Decrementiert. Ist ein bestimmter Wert erreicht, von mir aus EA, war 
meine Periode zu Ende und der Wert wurde wieder auf 00 gesetzt.
Das gleiche Register habe ich benutzt um das Tastverhältnis einzustellen 
also wird z.b. bei FA einfach der Portpin invertiert und bei 00 noch 
einmal.

Du brauchst quasi 3 Register: Zähler, Wert-Tastverhältniss und 
Wert-Frequenz.

Ich gebe aber zu bedenken, dass diese Methode wohl nicht die effektivste 
ist, da du nur 255 stufen hast - man könnte ggf. 2 register zum Zählen 
nehmen. Das mit den die vergehen bis der Portpin invertiert wird Takten 
sollte sich aber ausgleichen, bzw. minimal sein vllt. 2 takte, da er 
immer die gleiche schleife fährt.

Anfänger-Idee halt.

von Tmelle (Gast)


Lesenswert?

Hallo,

eure Beträge haben mich schonmal weiter gebracht. Aber leider muss ich 
euch mit einem weiteren Problem nerven:


Frequenzbereich 1: 1Hz-100Hz    Prescaler=64
Frequenzbereich 2: 100Hz-1kHz   Prescaler=8

Die Einstellung der Frequenz (F bzw 2f), des Tastverhältnisses (Tv) und 
des Prescalers (Presc) werden durch das Hauptprogramm eingelesen bzw. 
festgelegt (funktioniert so wie es soll).

Der Frequenzbereich 1Hz-100Hz funktioniert auch so wie er soll (Toleranz 
ca 0.4 Hz)

Nur der Frequenzbereich 100Hz - 1kHz Funktioniert nicht so wie er soll, 
die Werte für die Warteschleifen berechnen sich jedoch korekt. Ich weiss 
nicht woran das liegt, sitze hier jetzt schon 2 Std. und suche den 
Fehler.

Ich hoffe ihr als erfahrenen Mikrocontroller-Programmierer/innen könnt 
mir auch hier weiterhelfen.

Hier noch der Code des Programmteils welche für den Betrieb zuständig 
ist:
1
Locate 1 , 14                                      'Anzeige "Betrieb"
2
         Lcd "BET"
3
4
5
         2f = F                                             'Variablenumwandlung in Word
6
         T = 36864.11 / Presc                               'Prozessortakt/Vorteiler
7
         T = T / 2f                                         'Warteimpulse pro Periode
8
9
         Impuls = T * Tv                                    'Warteimpulse pro Impuls (Tv=Tastverhältnis)
10
11
         Pause = 100 - Tv
12
13
         Pause = T * Pause                                  'Warteimpulse pro Pause
14
15
16
         Config Timer1 = Timer                              'Konfiguration Timer1 als Timer
17
18
         If Presc = 8 Then                                  'Prescaler für Frequenzbereiche einstellen
19
         Tccr1b = 2
20
         Elseif Presc = 64 Then
21
         Tccr1b = 3
22
         End If
23
24
         Waitms 500
25
26
         Enable Timer1                                      'Start Timer1
27
         Do
28
29
30
         Portc.3 = 0                                        'Ausgang auf Low
31
         Timer1 = 0                                         'Reset Timer1
32
         Do                                                 'Warteschleige Pause
33
         Loop Until Timer1 = Pause
34
35
         Portc.3 = 1                                        'Ausgang auf High
36
         Timer1 = 0                                         'Reset Timer1
37
         Do                                                 'Warteschleife Impuls
38
         Loop Until Timer1 = Impuls
39
40
41
42
43
         Loop Until Pinc.5 = 0
44
45
46
         Portc.3 = 0
47
         Disable Timer1
48
         Goto Auswahl

von avr (Gast)


Lesenswert?

Das du den Timer einsetzt ist schon OK.
Aber du solltest ihn besser Nutzen, besonderst je näher
deine Ausgabefrequen an die Taktfrequenz heranreicht.

Du willst ein Rechtecksignal mit variabler Frequenz und
einstellbarem Verhältnis.

Das einstellen eines bestimmten Dutys ist eigentlich
eine PWM. Das kann der Timer 1 in Hardware machen und
dabei einen Pin (OSC1A/B) ansteuern.
Einmal gestartet braucht sich das Programm nicht mehr
darum kümmern, kann die Werte jedoch bei Bedarf
ändern (OCR1A/B-Register).

Die variable Frequenz ergibt sich aus dem TOP-Wert des Timers.
Bei einer 8 Bit PWM ist er 255 bei 10 sind es 1023.

Aber der Mega kann (wenn man es ihm sagt ICR1-Register) auch bis
617 Zählen.

Die Frequenz ist immer

Jetzt versuch mal in deinem Programm zuerst ein PWM und dann das
Verändern des TOP-Wertes.

Tutorial und Datenblatt helfen.

Am Ende dann ICR1 aus Frequenzeingabe berechnen und den Duty
OCR1 als Prozentualen Anteil von ICR1.

Möglich sind bei deinem Quarz ca. 3,6 kHz mit 0,1% Schritten.

avr

von Tmelle (Gast)


Lesenswert?

Hallo,

ich bin jetzt schonmal weiter, die PWM funktioniert jetzt. Ich habe nur 
noch keine Idee wie ich den TOPwert des Zählers ändere.

Also die Timer im PWM Modus arbeiten ja wenn ich das richtig aus den 
Tutorials verstanden habe so:

-Zählen (vorwärts)

-Bei ereichen des Comparewertes Port auf High.

-TOPwert ereicht.

-Zählen (rückwärts)

-Bei ereichen des Comparewertes Port wieder auf Low.

-Bei ereichen von 0 wieder von vorne beginnen.

Den Comparewert berechne ich wie du sagtest über das Tastverhältnis. Was 
auch schon gut Funktioniert (100% Prüfen konnte ich das noch nicht weil 
mein Oszilloskop gerade repariert wird).

Jetzt fehlt mir nur noch die Möglichkeit den TOPwert festzulegen (Aus 
dem  Datenblatt bin ich auch nicht sonderlich schlau geworden weil mir 
als Einsteiger in Microcontroller noch der Überblick darin fehlt).

MfG Tmelle

von avr (Gast)


Lesenswert?

Hier ist das eigentlich gut beschrieben:

http://www.mikrocontroller.net/articles/AVR-Tutorial:_PWM

Du brauchst den MODUS 14.

avr

von gast (Gast)


Lesenswert?


von Tmelle (Gast)


Lesenswert?

Hallo,

ich komme mit den ganzen Einstellungen in den Registern irgendwie nicht 
zurecht. Ich bekomme mit meinen Einstellungen zwar Frequenzen heraus 
aber nicht die die ich will. Evtl könnte mir ja jemand eine Timer Config 
erstellen, wäre echt net.

MfG

von Condi (Gast)


Lesenswert?

Hi,

dein Problem sind nicht die Register sondern das Grundverständnis.

Angenommen du hast eine 1Mhz Clock und willst ein 100Hz Signal 
haben(Prescaler 1).

Der Timer muss dazu 100 Mal von 0 nach top und wieder nach 0. Das wird 
dann alle 1000000hz/100Hz = 10000 Taktzyklen passiert sein müssen. Um 
den Top Wert zu erhalten wird das noch durch 2 geteilt. Also müsste das 
Top Register 5000 haben. Für ein Tasverhältnis von 30% muss in das 
Output Compare Register also 1500.

Jetzt musst du nur noch den Prescaler setzen damit die Werte in die 
Register passen.

Condi

von Tmelle (Gast)


Lesenswert?

Genau so habe ich das ja berechnet, also ich denke das Prinzip habe ich 
schon verstanden.

Ich weiss nur noch nicht was der Unterschied von z. B. ICR1L und ICR1H 
ist.

von spess53 (Gast)


Lesenswert?

Hi

>Ich weiss nur noch nicht was der Unterschied von z. B. ICR1L und ICR1H
>ist.

ICR1 ist ein 16 Bit Register. ICR1L sind davon die niederwertigen und 
ICR1H die höherwertigen 8 Bit. Gleiches gilt für die OC-Register. Zu 
beachten ist, das erst das H-Byte und danach das L-Byte geschrieben 
wird. Beim Lesen erst L-Byte, danach H-Byte.

MfG Spess

von Tmelle (Gast)


Lesenswert?

Also wenn ich jetzt zum Beispiel in IRC1 987 schreiben möchte, muss ich 
dann 987 erst in binärcode umwandeln um den Wert in das Register zu 
schreiben, oder wie stelle ich das am besten an?

MfG

Tmelle

von Tmelle (Gast)


Lesenswert?

Sry, war gerade bei 10 Bit. 987 geht natürlich nicht, als Beispiel 
könnte natürlich der Wert 234 sein. Oder ist das Regiter beim 10 Bit 
Modus auch in 2x 5 Bit eingeteilt?

von spess53 (Gast)


Lesenswert?

Hi

>muss ich dann 987 erst in binärcode umwandeln...

987=$03DB=0000001111011011b

Bascom ist egal, wie du einen Wert angibst. Richtig geschrieben versteht 
es dich schon.

>Sry, war gerade bei 10 Bit. 987 geht natürlich nicht,...

Wieso? 10 Bit: 0...1023

>Genau so habe ich das ja berechnet, also ich denke das Prinzip habe ich
>schon verstanden.

Wenn ich deinen letzten Post lese, würde ich das bezweifeln.

MfG Spess

von Tmelle (Gast)


Lesenswert?

Ich habe oben schon von 10 Bit geredet aber im Post davor ging es um 
8bit, deshalb habe ich mich korrigiert.
Ich meinte: Ich war gerade bei 10 Bit, 987 geht natürlich bei 8 Bit 
nicht.
Sry habe mich unverständlich ausgedrückt.

Mein Problem mit in Binär umwandeln war weil ich in zb. ICR1H zB. die 4 
höherwertigen Bits und in ICR1L die 4 niederwertigen Bits 
hineinschreiben muss.

Bascom erkennt aber leider nicht das komplette Register IC1R (wird nicht 
durch Bascom in Großbuchstaben und in andere Farbe geändert) somit muss 
ich ja den umweg über ...H und ...L gehen.

von Tmelle (Gast)


Lesenswert?

Hier nochmal der Programmteil Betrieb für den PWM-Modus umgeschrieben:
Vieleicht kann mir ja einer sagen was hier falsch ist.
1
Config Portb.1 = Output
2
3
4
         'TCCR1A Register
5
         'Bit 7:6= Match Portb.1=1, Bottom Portb.1=0,
6
         'Bit 5:4= - = 00
7
         'Bit 3:2= - = 00 (wird nur bei non-PWM gebraucht)
8
         'Bit 1:0= 10= Modus14
9
10
         Tccr1a = &B11100010
11
12
         'TCCR1B Register
13
         'Bit 7:6= Noise Canceler: Aus
14
         'Bit 5  = Reserviert
15
         'Bit 4:3= 11= Modus14
16
         'Bit 2:0= 101 = Prescaler: 1024
17
18
         Tccr1b = &B00011101
19
20
         'Input Capture Register (TOP-Wert)
21
         'Ich kann mir denken das das falsch ist, aber wie Teile ich am besten die Dezimalzahl?
22
         Icr1l = 1000
23
         Icr1h = 1000
24
25
         'Output Compare Register = TV*TPeriode = 0,5*1000 = 500
26
27
         Compare1a = 500
28
29
         'Warteschleife
30
31
         Do
32
33
         Loop Until Pinc.5 = 0

Hier müsste eine Frequenz von 3686411/(1024*1000)= 3,6Hz herauskommen, 
aber der Ausgang verändert sich nicht, sprich f=0Hz.

Entschuldigung das ich euch mit meinen "einfachen" Problemen nerve, ich 
hoffe ihr helft mir trozdem.

Gruß Tmelle

von spess53 (Gast)


Lesenswert?

Hi

>        'Input Capture Register (TOP-Wert)
>        'Ich kann mir denken das das falsch ist, aber wie Teile ich am
>         besten die Dezimalzahl?
>         Icr1l = 1000
>         Icr1h = 1000

Die 1000 passen nicht in ICR1L oder ICR1H.

In Bascom sollte es etwa so gehen(ohne Gewähr):

DIM i as Word

i=1000
ICR1H= High(i)
ICR1L= Low(i)

MfG Spess

von Condi (Gast)


Lesenswert?


von spess53 (Gast)


Lesenswert?

Hi

>Hm, ähm was sagt denn die Hilfe dazu?

>http://avrhelp.mcselec.com/config_timer1.htm....

Hier wird gerade versucht dem OT etwas 'fortgeschrittenere' 
BASCOM-Programmierung zu vermitteln. Und dann kommst du mit dem 
Urschleim aus der Hilfe.

MfG Spess

von Condi (Gast)


Lesenswert?

Tschuldigung.

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.