Hallo,
ich hab ein Problem mit einer Augenscheinlich einfachen Aufgabe. Ich
möchte gern zwei Frequenzen mit dem µC ausgeben lassen (ATMega8). Diese
möchte ich auch einstellen können. Von 1 (besser 0Hz) bis 300 oder
500Hz.
Wie ich es versucht hab:
Ich hab ein Display welches mir in Zeile1 Freuenz1 anzeigt und in Zeile2
Frquenz2. Mit 6 Pins an Port-C stell ich die Frquenz ein. + und - 100,
10 oder 1 ...
An dem PortB Pin 5 kann ich zwischen den beiden Kanälen zum einstellen
wechseln. Ich berechne die Zeit Zwischen den Tackten und gebe dann ein
kurzes HIGH auf PINB1 oder 2 aus.
Meine Probleme:
Ich kann keine PullUps einschalten sonnst kann ich nicht über 17Hz
kommen da das auslesen lange dauert. --> ok mach ich das halt mit der
Hardware. Gehts auch Eleganter?
Die Frequenzen werden nicht genau eingestellt, durch rundungsfehler, das
kann man noch verbessern und nach messen aber damit muss ich so wohl
leben. Oder?
Wenn ich auf dem MyAVR MK2 USB Bord die Verbindungen ziehe und auch das
Display dran hab kann ich nicht mehr den µC Brennen. Er wird dann nicht
mehr erkannt.
Alles im allen ist es es ne doofe baustelle und ich glaub das kann man
auch eleganter lösen. Hab alle Freiheitsgrade ... kann mehr als einen µC
Verwenden, kann, noch schalter hinzufügen oder was auch immer. Wie
würdet ihr die Sache angehen.
Aufgabe: zwei Simulta verdenete Frquenzen einstellen und ausgeben. +
Display.
Hat jemand eine Lösung?
Gruß Liloba
Hier mein Code:
1
/*
2
* Display.c
3
*
4
* Created: 12.09.2011 15:49:44
5
* Author: *****
6
*/
7
#define F_CPU 16000000ul
8
#include<avr/io.h>
9
//#include <stdlib.h>
10
#include<string.h>
11
//#include <avr/interrupt.h>
12
#include"lcd.h"
13
//#include <util/delay.h>
14
15
typedefenum{FALSE,TRUE}logic;
16
17
voidStart_Screen(void);
18
voidupDate_Diplay(intFrequenz1,intFrequenz2);
19
voidToggelChannel(logic*ChannelToggle);
20
voiddelay_42P_8xXus(unsignedlongTime);
21
voidout_H(charPinNr);
22
voidout_L(charPinNr);
23
voidinit(void);
24
25
unsignedlongFrequenzUpDate(int*frequenz);
26
unsignedintcalc_delay(int*frequenz);
27
28
voidStart_Screen(void){
29
lcd_clrscr();// clear display and home cursor
30
lcd_puts("Hallo \n");// put string to display (line 1) with linefeed
31
lcd_puts("Line2");
32
delay_42P_8xXus(55500);
33
}
34
unsignedlongFrequenzUpDate(int*frequenz){
35
unsignedintdelay=0;
36
if((PINC&(1<<PINC0)))*frequenz=(*frequenz)+1;
37
if((PINC&(1<<PINC1)))*frequenz=(*frequenz)-1;
38
if((PINC&(1<<PINC2)))*frequenz=(*frequenz)+10;
39
if((PINC&(1<<PINC3)))*frequenz=(*frequenz)-10;
40
if((PINC&(1<<PINC4)))*frequenz=(*frequenz)+100;
41
if((PINC&(1<<PINC5)))*frequenz=(*frequenz)-100;
42
43
if(*frequenz<1)//abfangen bei Bereichsüberscheitung der Frequenz
44
{*frequenz=1;}
45
if(*frequenz>500)*frequenz=500;
46
47
delay=calc_delay(frequenz);
48
returndelay;
49
}
50
51
voidToggelChannel(logic*ChannelToggle){
52
*ChannelToggle=~(*ChannelToggle);
53
if(*ChannelToggle)
54
{lcd_gotoxy(10,1);lcd_puts("*");}
55
else
56
{lcd_gotoxy(10,0);lcd_puts("*");}
57
delay_42P_8xXus(44400);//33300 = ca. 300ms
58
}
59
voidout_H(charPinNr){
60
PORTB|=(1<<PinNr);
61
}
62
voidout_L(charPinNr){
63
PORTB&=~(1<<PinNr);
64
}
65
voiddualOUT_H(charPinNr){
66
PORTB|=(11<<PinNr);
67
}
68
voiddualOUT_L(charPinNr){
69
PORTB&=~(11<<PinNr);
70
}
71
72
unsignedintcalc_delay(int*frequenz){
73
unsignedintdelay;
74
delay=((10000000/(*frequenz))-133)/88;//wegen der genauigkeit wird mit 0,1µs gerechnet
Liloba schrieb:> Wie> würdet ihr die Sache angehen.
Wie immer, wenn es darum geht irgendwelche 'extern abzugebende Timings'
möglichst gut einzuhalten:
Mit einem Timer.
> delay = ((10000000/(*frequenz))-133)/88;
wenn du das so naiv dahinrechnest, darfst du dich über Rundungsfehler
nicht wundern!
Formel umformen! Die Divisionen so weit wie möglich im Rechengang nach
rechts schieben! Dabei aber aufpassen, dass nicht Zwischenergebnisse
überzulaufen drohen.
Das hier
> void delay_42P_8xXus(unsigned long Time){for (int i=0;i<=Time;i++){ }}
ist Müll. Jeder halbwegs brauchbare Compiler, der in den letzten 30
Jahren entwickelt wurde, wird dir die Funktion zu einer 0-Operation
zusammenstreichen, sobald man ihm die Erlaubnis im Sinne von
'Optimierung einschalten' dazu gibt.
Karl Heinz Buchegger schrieb:> Jeder halbwegs brauchbare Compiler, der in den letzten 30> Jahren entwickelt wurde,
Naja, GCC hat noch recht lange (bis Version 2.x, glaub' ich), explizite
Delay-Schleifen erkannt und sie nicht wegoptimiert in der Annahme, dass
der Entwickler sich was dabei gedacht hat. Aber selbst dort war das
wohl dann mal irgendwann einer verbesserten Optimierungsstrategie
im Weg und ist auf den Müllhaufen der Compilergeschichte geflogen.
Hallo ihr beiden,
nun ich wollte das mit zuerst mit einem Timer machen aber die 2(+1) die
ich im ATmega8 zur Verfügung hab benutzen den selben gemeinsamen
Zählwert oder nicht? ich mein ich kann ihnen sagen das sie bis 100
zählen sollen und dann den einen bei 10 und den andern bei 40 schalten
lassen. aber was ich brauch sind zwei die immer bei 1 schalten und
unterschiedlich lang sind... außerdem ist der Bereich von 1 bis 500Hz
nicht so leicht mit 8Bit zu machen. aber ich würde mich freuen wenn mir
jemand zeigt wie es geht. ich kann auch einen anderen µC nehmen aber
dann hab ich nicht mal mehr ein Experimentierboard.
Das mit dem optimieren der Rechnung ist gut. Das werde ich mal versuchen
aber lieber währe es mir wenn ich die Timer nutzen kann ...
wie sollte da die Initialisierung aussehen?
Wie kann man den Timer abschalten wenn man auch 0 Hz also keine Ausgabe
haben will?
ich hatte auch schon mal mit dem delay_µs gearbeitet aber dann wird der
Code zu lang und geht nicht mehr in den Speicher. Darum diese Schleife.
...
Gruß
Liloba
Es reicht T1, der hat 2 Compare-Interrupts und 2 Pins, die zyklusgenau
vom Comparewert gesetzt oder gelöscht werden können.
Damit kannst Du 2 verschiedene Frequenzen erzeugen.
Und im Interrupt zählst Du die höherwertigen Byte(s) über den 16Bit des
Timers.
Peter
Liloba schrieb:> (besser 0Hz)
0Hz geht nicht, dann müßtest Du unendlich lange warten.
Denk Dir eine sinnvolle untere Grenze aus.
Die Schrittweite kann natürlich kleiner sein.
Peter
Liloba schrieb:> ich hatte auch schon mal mit dem delay_µs gearbeitet aber dann wird der> Code zu lang und geht nicht mehr in den Speicher.
Weil du eine der Randbedingungen der delay-Routinen missachtet hast:
sie funktionieren nur mit einem zur Compilezeit konstanten
Argument.
Anyway, delays sind keine sinnvolle Lösung zur Erzeugung einer halbwegs
genau einzustellenden Frequenz, das geht nur mit Hardware, also im
Rahmen eines Controllers mit einem Timer.
Wenn dein Controller davon wirklich nicht die für die Lösung der
Aufgabe notwendige Anzahl hat, dann solltest du dich nach einem anderen
umsehen. Allerdings glaube ich das im vorliegenden Fall nicht. Mir
ist deine Aufgabenstellung jedoch zu konfus formuliert, als dass ich
mir jetzt freiwillig eine Lösung für dein Problem ausdenken würde,
sorry.
Hallo Jörg,
die aufgabe: mit einem ATmega8 zwei Frequenzen ausgeben. Einstellbar von
1 bis 300Hz. Dauer des HighLevels ca 4-60µs.
Hallo Peter,
ich kann dem was du schreibst nicht folgen. Da ich zu wenig Anung hab...
was bedeutet Compare-Interrupts?
Sind es wirklich 2 Frequenzen die man nach deiner Methode einstellen
kann oder sind es zwei Leistungsmodulationen?
Kann Einer von euch mal ein paar Zeilen Code hier zum Besten geben dann
kann ich das mit dem Timer Testen.
Danke für die Geduld.
Liloba
Liloba schrieb:> mit einem ATmega8 zwei Frequenzen ausgeben. Einstellbar von> 1 bis 300Hz. Dauer des HighLevels ca 4-60µs.
Klingt wie 'ne Hausaufgabe ... da wollte wohl jemand, dass du dich
mit dem Datenblatt eingehend beschäftigst.
> Da ich zu wenig Anung hab...> was bedeutet Compare-Interrupts?
Schau dir doch einfach mal die Beschreibung der compare match unit
im Kapitel zu den Timern im Datenblatt an. Du hast 3 Timer im
ATmega8, also kannst du 3 voneinander unabhängige Frequenzen damit
erzeugen. Über irgendwelche Auflösungs- und Genauigkeitsforderungen
schreibst du nichts, insofern genügen für die Aufgabe durchaus auch
die 8-bit-Timer.
Und ja, all diese Parameter (sowohl Frequenz auch als Impulsbreite)
kann man dabei (mit endlicher Genauigkeit natürlich) voneinander
unabhängig rein durch die Timerhardware erzeugen lassen. Damit ist
man vollständig unabhängig vom Zeitverhalten irgendwelcher Interrupts
oder dergleichen, und die Software kann sich rein auf die Bedienung
der Timerhardware konzentrieren.
Hallo schön das ich noch immer Infos bekomme! Ich versuch mich jetzt
hier wirklich durchzubeißen und es handelt sich nicht um eine
Hausaufgabe! Bin eigentlich Themen fremd. Danke für den Link!
zu Euren und meinen Fragen:
Die Auflösung soll 1Hz betragen ich dachte das Inkrement sein klar da
die Einstellungen in 1Hz Schritten vorgenommen werden. - bitte um
Entschuldigung. Die Genauigkeit ist mir recht egal wenn 300Hz nur 295
oder aber auch 305Hz sind reicht das (1,5%).
Nun ehe ich aus diesen Infos des Datenblattes Fragen zusammenschuster
hab ich mal versucht was zu schreiben. Aber es geht nur eine LED an.
(Ich hab an Port B Pin 0, 1 und 2 je eine LED angeschlossen)
Kann mir jemand sagen wie ich während der Laufzeit die Timer werte
ändere kann und welche es sind?
Ich ging jetzt davon aus das TCNT1/0 die Endwerte der Timer sind. Und
TCCR1A/B die dazugehörigen Compare Wert?
Ist das Prinzip mit den Interruptus so richtig und sollten dies so
Funktionieren?
1
/*
2
* Frequenz.c
3
*
4
* Created: 27.09.2011 11:43:22
5
* Author: ******
6
*/
7
8
#include<avr/io.h>
9
#include<avr/interrupt.h>
10
11
voidInit(void){
12
DDRB=0xff;//PortB ist Ausgang
13
14
//Timer Settings
15
TCNT1=0b11111111;//The Timer/Counter (TCNT1),
16
TCNT0=0b11111111;
17
18
TIMSK=(1<<OCIE1A)|(1<<OCIE1B);//Output Compare A/B Match Interrupt Enable
19
TIMSK=(1<<TOV0)|(1<<TOV1);//Timer Over Flow Interrupt Enable
> //Timer Settings> TCNT1 = 0b11111111; //The Timer/Counter (TCNT1),> TCNT0 = 0b11111111;
Die TCNT Register gehen dich herzlich wenig an. Das sind die Register in
denen der Timer zählt.
> ICR1 = 0b00111111; //TOP Wert //Ist der hier erforderlich da ...>> OCR1A = 0b00011111; //verglichswert für Timer (Abschaltungszeitpunkt)> OCR1B = 0b00011111;
Noch ungünstigere Schreibweisen als die binäre Schreibweisen für Zahlen
sind dir nicht eingefallen?
Schreib doch einfach
ICR1 = 63;
bzw
OCR1A = 31;
OCR1B = 31;
dann kann man das auch lesen.
Den Link hast du dir angesehen?
Mein Rat: bring erst mal mittels Timer EINE LED zum blinken. Zuerst 1Hz,
dann 2Hz, dann 3Hz. Dann wirst du auch verstehen, wie die Dinge
zusammenhängen und wenn du für diese kleinen Frequenzen die jeweiligen
Registerwerte berechnen musst.
Du machst den Fehler schlechthin, den Anfänger machen. Sie haben nur
Augen für ihr endgültiges Projekt und können noch nicht (für erste Tests
und um ein Teilgebiet das sie bei ihrem Endprojekt brauchen werden)
zunächst unwichtiges weglassen. Für dich ist momentan unwichtig: alles
was mit Einstellung zu tun hat, alles was mit Ausgabe zu tun hat, alles
was mit verändern der Frequenz zu tun hat. Für dich ist JETZT erst mal
wichtig, dass du mit einem Timer überhaupt eine Frequenz zustande
bringst und zwar so, dass du die Frequenz unter Kontrolle hast
(Berechnung auf Papier und Bleistift) und dass du das einfach
kontrollieren kannst. Daher die LED und 1Hz.
Hi,
ich hab jetzt was versucht was sich an den link Text anlehnt! Aber es
geht nicht! Ich kann keinen unterschied mehr sehen aber der interrupt
geht nicht.
1
/*
2
* Frequenz.c
3
*
4
* Created: 27.09.2011 11:43:22
5
* Author: ******
6
*/
7
8
#define F_CPU 4000000UL
9
#include<avr/io.h>
10
#include<avr/interrupt.h>
11
12
uint8_tswTeiler=0;
13
14
voidInit(void){
15
DDRB=0xff;//PortB ist Ausgang
16
17
//Timer Settings
18
TIMSK=(1<<OCIE1A);//Output Compare A Match Interrupt Enable
19
OCR1A=250-1;//verglichswert für Timer, im CTC wird hier die oberGrenze eingestellt
Liloba schrieb:> Hi,> ich hab jetzt was versucht was sich an den link Text anlehnt! Aber es> geht nicht! Ich kann keinen unterschied mehr sehen aber der interrupt> geht nicht.
Du hast keinen sei()
Hallo Karl Heinz Buchegger,
ich hab es selber raus bekommen jetzt frag ich mich aber wofür TCCR1A
bzw TCCR1B sind.
In B kann man scheinbar den Timer Modi und den Prescaler einstellen und
was macht man mit TCCR1A ?
Danke
Liloba schrieb:> Hallo Karl Heinz Buchegger,> ich hab es selber raus bekommen jetzt frag ich mich aber wofür TCCR1A> bzw TCCR1B sind.> In B kann man scheinbar den Timer Modi und den Prescaler einstellen und> was macht man mit TCCR1A ?
Schau ins Datenblatt.
Beides zusammen sind die Konfigurationsregister des Timers.
Da kann man noch jede Menge mehr einstellen.
An dieser Stelle kann ich dir nur raten: Schau ins Datenblatt. Das ist
deine Bibel. Ohne geht gar nichts.
Der für die praktische Arbeit wichtigste Teil ist bei jeder
Hadrware-Komponente immer der letzte Abschnitt im jeweiligen Kapitel
"Register Summary". Dort sind alle Konfigurationsregister aufgeführt,
zusammen mit allen Bits und was sie bewirken. Die Abschnitte davor sind
immer die ausführliche Erläuterung, wie die Funktionalität funktioniert.
Wenn du also in der Register Summary etwas nicht verstehst, dann findet
sich in den Abschnitten davor die Erklärung dazu.
Aber ohne Datenblatt bist du genauso aufgeschmissen, wie du es bei der
Progammierung eines Videorekorders ohne Handbuch bist.
Hallo, Ich hab mich jetzt die letzten stunden mit diesen Timer befasst.
Ich glaub das ein CTC Mode mit nur 8 Bit gut für mein vorhaben ist darum
wollte ich den Timer2 für den Anfang verwenden. (Bei den anderen hab ich
das eine oder andern hinbekommen)
Um erstmal was zu Testen dacht eich an eine normale PWM.
Der Compare-Wert in OCR2 steht auf 50 und soll den TIMER2_COMP_vect
Interrupt auslösen welche für kurze zeit (11,1µs) alle Pins an PortB auf
1 setzt. Der Pin3 sollte davon nicht betroffen sein da er von der PWM
gesteuert wird.
Kurz um: Ich dachte ich hätte es jetzt begriffen aber es geht so nicht.
Was ist jetzt der Fehler?
PS: Das Datenblatt bringt mir hier jetzt nichts. Aber es war bis hierher
sehr Sinnvoll und Nützlich.
Gruß Liloba
1
voidInit(void){
2
DDRB=0xff;//PortB ist Ausgang
3
4
//Timer2 Settings
5
TIMSK=(1<<TOV2)|(1<<TOIE2);
6
OCR2=50;
7
TCCR2=1<<CS00;
8
TCCR2=(1<<WGM20);
9
//TCCR2 = (1<<WGM21); //Modus CTC Obergrenze in OCR2
Liloba schrieb:> Der Compare-Wert in OCR2 steht auf 50 und soll den TIMER2_COMP_vect> Interrupt auslösen welche für kurze zeit (11,1µs) alle Pins an PortB auf> 1 setzt.
Woraus schlussfolgerst du, dass dies gerade 11,1 µs lang wäre?
Pins setzen und wieder löschen wäre übrigens:
1
PORTB=0xff;
2
PORTB=0;
Das müsste einen Impuls ergeben, der (bei eingeschalteter Optimierung)
genau einen CPU-Takt lang ist, also 1 µs beim Default-Takt.
Du toggelst sie stattdessen, was ein wenig langsamer ist, weil du
die CPU zwingst, jeweils die alten Werte erstmal einzulesen.
> TCCR2 = 1<<CS00;> TCCR2 = (1<<WGM20);
Das macht die CS00-Einstellung der vorherigen Zeile wieder zunichte,
damit hat dein Timer keinen Takt. Entweder so:
1
TCCR2=1<<CS00;
2
TCCR2|=1<<WGM20;
besser jedoch gleich in einer Zeile, denn es gibt keinen Grund, das
aufzutrennen:
Hi,
die 11.1µs hab ich gemessen mit dem Ossi.
das toggeln war nur zur Anschauung und sollte nicht die Endvariante
sein. Ich versuch einfach nur die beiden Interruptus zu nutzen ... aber
es geht nicht.
Wie kann ich denn die Optimierung eingeschaltet? Ich nutze Studio5 ...
ist noch ein andere Schnitzer im Code so das der Timer nicht arbeite?
Gruß
Liloba
Liloba schrieb:> die 11.1µs hab ich gemessen mit dem Ossi.
Dann hast du keine Optimierung eingeschaltet. So eine Operation
sollte schneller gehen.
Hat übrigens nichts mit den östlichen Deutschen zu tun ;-), sondern das
Teil heißt "Oszi(lloskop)".
> Ich versuch einfach nur die beiden Interruptus zu nutzen ... aber> es geht nicht.
Wofür willst du denn die Interrupts noch haben? Für mehr als eine
Demonstration brauchst du die nicht, denn die PWM (und damit die
Ausgabe der Impulse) wird komplett von der Timer-Hardware
erledigt — und das ist das Beste, was dir in dieser Hinsicht
passieren kann. Beim Erreichen des OCRx-Wertes wird der Ausgang
in die eine Lage gesetzt, beim Erreichen des Zählerüberlaufs wird
er wieder rückgesetzt (zum Beispiel; dies wäre ein "fast PWM mode").
> Wie kann ich denn die Optimierung eingeschaltet? Ich nutze Studio5 ...
Keine Ahnung, ich nicht. :)
> ist noch ein andere Schnitzer im Code so das der Timer nicht arbeite?
Hast du das kaputte TCCR2 denn korrigiert?
Liloba
Bitte gewöhn dir an:
Wenn du Fragen hast, zeige deinen Code. Und zwar alles!
Wenn in deinem Code Fehler moniert wurden und du daher deinen Code
geändert hast, zeig bei weiteren Fragen wieder deinen Code.
Auf dieser Seite deines Monitors sehen wir dein Programm nicht in seiner
jetzigen Form und wir wissen auch nicht welche Änderungen du alle
gemacht hast.
Die Forensoftware macht dir das einfach. Du brauchst nur auf "Datei
auswählen" bei Dateianhang klicken und dein C-File, so wie es ist,
auswählen. Das ist für dich kaum Arbeit und hier muss keiner im Nebel
stochern und raten.
dr.prof.schlau schrieb:> Was zum Teufel ist ein Videorekorder?? :-))
Ein Gerät, um die Privaten ansehen zu können, ohne von der Werbung zu
verblöden (Timeshift-Funktion).
Peter
Hi,
also hier mein neuer Code ... ;)
ich habe gehofft das ich 2 Timer genau gleich konfigurieren kann aber
seht selber.
Timer1 Mode 1
Timer2 Mode 1
Damit die Interruptus sich nicht in die quere kommen hab ich die
Timerzeiten um 127 Zähler versetzt.
Komplett gleich bekomme ich die nicht.
Das Problem besteht noch immer. Wie kann ich 2 Frequenzen in 1Hz
schritten von 1 bis 300Hz ausgeben? Das Gittern sollte nur wenige (<30)
µs sein.
Wie kann ich die Code-Optimierung einschalten?
Gruß Liloba
Liloba schrieb:> Das Problem besteht noch immer.
Ja. Weil du immer noch nicht begriffen hast, dass man derartige Dinge
von der Timer-Hardware erledigen lässt und nicht irgendwo in den
Interrupt-Routinen.
Bitte versuche als erstes zu verstehen, wie der Timer eine PWM
erzeugt. Du brauchst dafür keinen Interrupt. Für eine konstante
Frequenz (als ersten Schritt) kannst du nach dem Konfigurieren der
Ports und der Timer-Hardware die CPU schlafen legen (aber natürlich
nicht den IO-clock, also sleep mode "idle"), die hat dann nichts
mehr zu tun.
Dann jittert da auch rein gar nichts.
Wenn du deine beiden Timer dann soweit hast, dass sie jeder ihr
PWM-Signal ausgeben, dann denkst du das nächste Mal drüber nach,
wie du die Frequenz eines Timers änderst. Bis dahin ist dieses
Thema erstmal tabu.
Guten Morgen,
also ich hab mir auf die Zunge gebissen und weiter gemacht! Danke, dass
ihr mir noch immer schreibt! ;)
also mein neuer Code:
1
#include<avr/io.h>
2
3
voidInit(void);
4
5
intmain(void)
6
{
7
DDRB=0xff;//PortB ist Ausgang
8
TCCR1A=(1<<COM1A1)|(1<<WGM11);
9
TCCR1B=(1<<WGM13)|(1<<WGM12)|(1<<CS11);
10
ICR1=123;//TOP Wert
11
OCR1A=0;//Verglichswert
12
13
do{}while(1);
14
}
Die kleinste Frequenz liegt hier bei ca. 2Hz. mit ICR1=65535.
Mit dem Prescale kann ich da noch was machen aber dann wird der Puls
länger, aber bis 64µs ist schon noch OK.
Wie kann ich jetzt aber die zweite Frequenz erzeugen wenn ich keinen 16
Bit Timer mehr habe. Wo doch schon 65535 grenzwertig ist.
Das mit dem idle hab ich nicht überlesen aber ich brauch die CPU später
noch für andere Dinge.
Gruß
Liloba
Liloba schrieb:> Die kleinste Frequenz liegt hier bei ca. 2Hz. mit ICR1=65535.> Mit dem Prescale kann ich da noch was machen aber dann wird der Puls> länger
Jetzt hast du es.
> aber bis 64µs ist schon noch OK.
Uff
> Wie kann ich jetzt aber die zweite Frequenz erzeugen wenn ich keinen 16> Bit Timer mehr habe. Wo doch schon 65535 grenzwertig ist.
Das Problem:
In deinem Eröffnungsposting war von einer Pulslänge noch nicht die Rede.
Als du 300Hz gesagt hast, ist wohl jeder davon ausgegangen, dass es sich
da um eine symetrische Rechteckschwingung handelt. Das wäre kein Problem
gewesen.
Ich frag mich gerade, ob du nicht die Pulslänge mit einem extern
flankengetriggerten Monoflop machen solltest. Einen kurzen Puls kriegst
du mit dem Mega8 hin. Aber 2 wird schwer. Zumindest wüsste ich jetzt auf
Anhieb nicht, wie da das mit einem 8 Bit Timer machen könntest.
Karl Heinz Buchegger schrieb:> Zumindest wüsste ich jetzt auf> Anhieb nicht, wie da das mit einem 8 Bit Timer machen könntest.
Ja, ich auch nicht so recht. Naja, man hat natürlich alle Zeit der
Welt, den Timer zwischen normalem Zählen (für einen Umlauf) und
PWM-Modus (nach dem Overflow) umzuschalten ... aber optimal fände
ich das nicht.
Eine Chance, auf einen moderneren Controller umzuschwenken (insbe-
sondere einen, der zwei 16-bit-Timer hat), gibt's wohl nicht, oder?
Jörg Wunsch schrieb:> Karl Heinz Buchegger schrieb:>> Zumindest wüsste ich jetzt auf>> Anhieb nicht, wie da das mit einem 8 Bit Timer machen könntest.>> Ja, ich auch nicht so recht. Naja, man hat natürlich alle Zeit der> Welt, den Timer zwischen normalem Zählen (für einen Umlauf) und> PWM-Modus (nach dem Overflow) umzuschalten ... aber optimal fände> ich das nicht.
Was ist schon optimal?
Ich finde die Idee jetzt gar nicht mal so schlecht. PeDa macht in seiner
genauen Sekunde im Grunde ja auch nichts anderes. Nur das hier halt ein
Modus-Wechsel des Timers noch mit inkludiert ist. Ich denke, das wäre
machbar, zumal die zu erzeugenden Frequenzen ja jetzt so hoch auch
wieder nicht sind. Interruptmässig sollte da noch alles im grünen
Bereich sein. Ohne ISR wirds sowieso nicht gehen, weil man mit dem
Prescaler nicht weit genug hochkommt für die kleinen Frequenzen.
Wurde das eigentlich schon mal gefragt oder gabs dazu eine Erklärung?
Warum eigentlich so kurze Pulse? Ich finde das schon ungewöhnlich: 150Hz
mit einer Pulslänge im µs Bereich.
hallo,
den kurzen Impuls brauch ich für einen andere aperatur welche nur 2µs
bis 60µs (da würde ich mit 64µ schon drüber kommen) verträgt.
Weil ich ja schon wusste das es so nicht geht hab ich doch die Sache mit
dem Interrupts versucht. Das ging mit dem Timer2 recht gut und auch
jitter stabil.
1
ISR(TIMER2_COMP_vect){
2
if(swTeiler2>=0){
3
PORTB=1<<PB2;
4
TCNT2=0;
5
swTeiler2=0;
6
PORTB&=~(1<<PB2);
7
}
8
elseswTeiler2++;
9
}
Mit dem Code sollte der µC nicht viel zu tun haben und jetzt da der eine
Takt vom Timer gemacht wird sollten die Interrupts auch nicht zum
jittern führen. Oder?
Ich könnte auch andere µC verwenden. Dieser hat sich nur angeboten da er
auf dem Einsteiger Board sitzt. Ich könnte auch 2 µC verwenden nur weiß
ich nicht wie ich die Infos welche Frequenz einstellt werden soll von
einem µC zu dem anderen bekomme.
Liloba schrieb:> Mit dem Code sollte der µC nicht viel zu tun haben und jetzt da der eine> Takt vom Timer gemacht wird sollten die Interrupts auch nicht zum> jittern führen. Oder?
Ein wenig Jitter hast du trotzdem, da die Interruptannahmezeiten nicht
völlig konstant sind. Ein Programmfluss kann immer nur unterbrochen
werden, nachdem ein Befehl vollständig abgearbeitet ist, und die
Befehle können unterschiedlich lange für die Abarbeitung benötigen.
Außerdem wird es spätestens dann brenzlig, wenn du für dein Bedien-
programm auch noch Interrupts brauchst (und sei es nur für einen
weiteren Timer, bspw. für eine Tastaturentprellung).
Ich würde dann eher die skizzierte Hardwarelösung implementieren.
Die braucht zwar auch Interrupts, aber das Interrupt-Timing hat
(sofern die Interrupts überhaupt brauchbar schnell bedient werden)
dann keinen Einfluss mehr auf die Genauigkeit der Impulsgenerierung.
Nochmal die Gedanken:
. du lässt den Timer "eine Runde" im CTC-Modus laufen; beim
Erreichen des compare match wird er einerseits durch die Hardware
neu gestartet, andererseits wird ein Interrupt ausgelöst
. die ISR programmiert den laufenden Timer um auf PWM-Betrieb,
die Zählweite wird damit für diesen Umlauf 256 (8 bit), das
OCR2 wird umprogrammiert, sodass es kurz vor Erreichen des
Überlaufs den nötigen kurzen Impuls generiert; beim Überlauf
wird dann ein Overflow-Interrupt ausgelöst
. die ISR für den Overflow programmiert alles wieder auf den
CTC-Modus zurück.
Damit ergibt sich die Frequenz als f_IO ÷ prescaler ÷ (OCR2 + 256).
Prinzipiell sind auch mehrere Umläufe im Normalmodus denkbar,
bevor man auf PWM schaltet. Damit sollte man selbst bei etwas
kleineren Prescaler-Werten (zur Erreichung kurzer Impulse im
PWM-Modus) noch auf niedrige Frequenzen kommen.
> Ich könnte auch andere µC verwenden.
Das wäre zumindest meine Vorzugsvariante. Ein ATmega1284P hat
zwei 16-bit-Timer, oder aber halt die "Klassiker"-Linie ATmega128
bzw. der modernere Nachfolger ATmega1281.
Ich würde es noch etwas anders machen:
Timer im PWM-Modus laufen lassen, mit ICR als Top. Duty-Cycle
entsprechend der gewünschten Pulslänge, Frequenz ein ganzzahliger Teiler
der gewünschten Frequenzen. Im Interrupt dann Mitzählen für die gewählte
Frequenz und den OC-Pin nur für einen PWM-Zyklus lang mit dem Timer
verbinden.
Jörg Wunsch schrieb:> Stefan Ernst schrieb:>> Timer im PWM-Modus laufen lassen, mit ICR als Top.>> Kann der Timer 2 im ATmega8 nicht.
Man kann mit der beschriebenen Methode doch beide Signale mit Timer 1
machen.
Stefan Ernst schrieb:> Man kann mit der beschriebenen Methode doch beide Signale mit Timer 1> machen.
Ich verstehe nicht ganz, wie du deren Frequenzen dann voneinander
unabhängig in 1-Hz-Schritten zwischen 1 Hz und 300 Hz einstellen
willst.
ich glaub ich hab so was gemacht wie Stefan Ernst meint.
aber zusammen mit dem Display kommen die Probleme die oben beschrieben
werden ... der µC ist beschäftigt der Interrupt kommt und dann wandert
der Displaytext. Oder ligt es an was anderem?
der ATmega1284P scheint ganz gut zu sein ... ich hab zur Display
Ansteuerung von einem Kollegen eine lcd.c unc lcd.h bekommen.
wahrscheinlich muss ich da mit dem andern µc Änderungen vornehmen oder?
das Display ist das "Displaytech162". Denn da jetzt die Zeichen
stillstehen würde mir es reichen! Sicher die Zeiteinstellungen müsste
ich dann noch machen.
Gruß und danke
Liloba
Liloba schrieb:> ich glaub ich hab so was gemacht wie Stefan Ernst meint.>> aber zusammen mit dem Display kommen die Probleme die oben beschrieben> werden ... der µC ist beschäftigt der Interrupt kommt und dann wandert> der Displaytext. Oder ligt es an was anderem?
An lcd.c. ;-)
Das hier:
1
if((PINC&(111111<<PINC0))){
wird wohl nicht das tun, was du willst. 111111 ist eine ziemlich
große Zahl. Vermutlich meinst du 0b111111, aber dann kannst du
das auch gleich als 0x3F hinschreiben. Noch besser, sowas packt
man in ein #define obendrüber und gibt ihm damit einen sinnvollen
Namen:
1
#define BUTTONMASK 0x3f /* mask of button input pins on port C */
2
...
3
if((PINC&BUTTONMASK)!=0){
4
...
> wahrscheinlich muss ich da mit dem andern µc Änderungen vornehmen oder?
Irgendwo vermutlich schon, hängt davon ab, an welchen Portpins das
Display hängt.
> Denn da jetzt die Zeichen> stillstehen würde mir es reichen!
Dazu müsste man erstmal wissen, warum sie dies nicht tun.
Liloba schrieb:> ich glaub ich hab so was gemacht wie Stefan Ernst meint.>> aber zusammen mit dem Display kommen die Probleme die oben beschrieben> werden ... der µC ist beschäftigt der Interrupt kommt und dann wandert> der Displaytext.
?
Wie muss man sich das vorstellen?
Das hier
void upDate_Diplay(int Frequenz1, int Frequenz2){
char lcd_freque_str0 [6];
char lcd_freque_str1 [6];
itoa((Frequenz1),lcd_freque_str0,10);
itoa((Frequenz2),lcd_freque_str1,10);
lcd_clrscr();
lcd_gotoxy(11,0);lcd_puts(lcd_freque_str0);lcd_puts("Hz");
lcd_gotoxy(11,1);lcd_puts(lcd_freque_str1);lcd_puts("Hz");
}
ist nicht so prickelnd.
Durch den lcd_clrscr wird dir die Anzeige flimmern, wenn upDate_Diplay
in schneller Folge aufgerufen wird.
Zumindest mich würde es auch enorm stören, wenn die Zahl ständig hin und
her wandert, nur eil ich von 99 auf 100 weitergeschaltet habe. Besser
ist es wenn man
* die Anzeige so einrichtet, dass alle Teile immer an der gleichen
Stelle auftauchen und man ganz einfach überschreiben kann anstelle
dass man das LCD dauernd löschen muss. Wird ein Text mit dem gleichen
Text überschrieben, merkt das kein Mensch. Wird aber das LCD
gelöscht, so hat man kurzzeitig ein leeres LCD vor sich, auf welches
dann wieder neue Ausgaben kommmen. Das ist nicht zu übersehen
und wird, wenn es oft genug in der Sekunde passiert als Flimmern
wahrgenommen.
* Zahlenausgaben so einrichtet, dass die Einerstelle immer an der
gleichen Anzeigeposition auftaucht. Das ergibt ein angenehmeres
Ablesen, als wie wenn man das Gefühl hat, die Zahl wandert einem
während des Ablesens ständig links und rechts davon.
Jörg Wunsch schrieb:> Stefan Ernst schrieb:>> Man kann mit der beschriebenen Methode doch beide Signale mit Timer 1>> machen.>> Ich verstehe nicht ganz, wie du deren Frequenzen dann voneinander> unabhängig in 1-Hz-Schritten zwischen 1 Hz und 300 Hz einstellen> willst.
Ja, Denkfehler von mir. :-(
Ich dachte eigentlich daran die PWM-Frequenz entsprechend hoch
anzusetzen, und dann mit zwei Zählern im Interrupt zu arbeiten. Aber das
gemeinsame Vielfache der 300 möglichen Frequenzen ist halt doch verdammt
hoch. ;-)
Karl Heinz Buchegger schrieb:> die Anzeige so einrichtet, dass alle Teile immer an der gleichen> Stelle auftauchen und man ganz einfach überschreiben kann anstelle> dass man das LCD dauernd löschen muss.
Das eigentliche schreiben passiet auch immer an der selben Stelle. Aber
die Dargestellten Frequenzen (zahlen) sind halt mal einstellig und mal 3
stellig, ... beim normalen überschreiben werden immer nur die neuen
Digits überschrieben und so bleiben die Nullen der 100 stehen auch wenn
nur noch 9Hz eingestellt sind... durch die Angehängte Einheit "Hz"
werden dann die Nullen überschreiben aber dann Steht 9HzHz auf dem
Display.
ich Müsste die String länge die geschrieben werden soll Definieren. Oder
nur Teilbereiche des nachträglich löschen.
Kann das PullUp ein Problem sein?
Da die Pins abgefragt werden und diese Abfrage durch den Interrupt
unterbrochen wird ... kann so was sein?
@Jörg Wunsch, danke für den hinweiß hab die sache übernommen!
Gruß
Liloba
Liloba schrieb:> beim normalen überschreiben werden immer nur die neuen> Digits überschrieben und so bleiben die Nullen der 100 stehen auch wenn> nur noch 9Hz eingestellt sind
Rechtsbündig schreiben. Hast du vielleicht noch Platz für ein
sprintf() (statt des itoa())? Da wäre sowas ganz einfach.
> Kann das PullUp ein Problem sein?
Welcher Pullup?
Ein LCD wird einfach nur direkt, Pin für Pin mit dem µC verbunden. Kein
Pullup, kein Pulldown, gar nichts.
Der Rest ist Software.
> Da die Pins abgefragt werden und diese Abfrage> durch den Interrupt unterbrochen wird ... kann so was sein?
Am LCD?
Nein. LCD sind insofern zeitkritisch, als man ein Mindesttiming
einhalten muss. Ein Interrupt an der falschen Stelle macht dir das
Timing aber höchstens länger. Das ist alles nicht kritisch.
Hallo alle zusammen,
solangsam siehts schon gut aus.
Diese stelle hier macht Probleme:
1
if((PINB&(0<<PINB5))){...}
Ursprünglich stand da
1
if((PINB&(1<<PINB5))){...}
jedoch macht der PullUP ja automatisch die 1 und ich möcht mit einem
Taster den Pin auf Low ziehen worauf der µC dann reagiert.
Dasselbe ist bei den andern Pins.
Die Frequenz bei den selbst gebastelten Timer ist nicht richtig aber das
schau ich mir gleich an. Die Pin Abfrage ist jetzt mein Problem.
Liloba
Liloba schrieb:> Hallo alle zusammen,> solangsam siehts schon gut aus.>> Diese stelle hier macht Probleme:>
1
>if((PINB&(0<<PINB5))){...}
2
>
Das geht nicht.
Nach Auswertung der Verschiebung steht da
if (( PINB & 0 ) )
und das ist ziemlich sicher nicht das was du willst.
Eine 0 kannst du schieben sooft und so weit du willst. Das Ergebnis
bleibt trotzdem immer 0.
> Ursprünglich stand da>
1
>if((PINB&(1<<PINB5))){...}
2
>
das ist schon richtig
> jedoch macht der PullUP ja automatisch die 1 und ich möcht mit einem> Taster den Pin auf Low ziehen worauf der µC dann reagiert.
dann musst du die Bedingung umdrehen
if( !( PINB & ( 1<<PINB5 ) )
Die Maskierung mit & sorgt ja nur dafür, dass das interessierende Bit
übrig bleibt. Und das kann entweder 0 oder nicht 0 sein.
Im Original wurde abgefragt ob es nicht 0 ist. Jetzt drehst du die
Bedingung um und fragst ab ob es 0 ist.
(aber hüte dich an dieser Stelle vor Vergleichen mit == oder !=
Einfacher ist es, die C Regel anzuwenden, dass jedes Ergebnis ungleich
0 automatisch als logisch WAHR gewertet wird. Dein originales
if ((PINB & (1<<PINB5)))
benutzt das, um die Langform
if ( (PINB & (1<<PINB5)) != 0 )
zu vermeiden.
Erstens ist das kürzer, zweitens ist es weniger fehleranfällig in der
Schreibweise.
ok, das hab ich. ... uns sogar verstande ;)
warum kann ich OCR2 welches nach der Init auf 72 steht nicht mehr in der
laufzeit verändern? Dardurch ist mein ganzer Timer2 fast nutzlos.
Also ich hab das jetzt mal ne ein bisschen durchgetestet und es muss mit
der Pin abfrage in der Main zusammen hängen. Sobald ich diese ausschalte
steht die Anzeige still.
Kann ich irgendwie die Timer oder auch nur die Interrupts
unterbrechen/anhalten solang eine Änderung der Einstellungen
durchgeführt wird?
Schönes Wochenende euch allen und danke für die Hilfe!
Liloba
naja, da die Bedienung noch nicht geht ... hab ich das nur simuliert
aber dabei ging es nicht !
Nun denn, ... ich mach am Dienstag weiter.
Danke noch mal.
Liloba schrieb:> hab ich das nur simuliert> aber dabei ging es nicht !
Simulatoren sind Schall und Rauch. Nur die Praxis zählt.
Wenn du statt des ältlichen ATmega8 wenigstens einen ATmega88
benutzen würdest, hättest du einige Vorteile:
. Upgrade-Pfad auf ATmega168 oder gar ATmega328 möglich, sodass
du bspw. auf jeden Fall Platz für sprintf() und damit eine
ordentlich formatierte Ausgabe ohne weitere Verrenkungen.
. Online-Debug-Möglichkeit via debugWIRE (bspw. mit einem AVR
Dragon).
. Im AVR Studio meines Wissens dann den "Simulator V2", bei dem
prinzipbedingt sichergestellt ist, dass der Digitalteil des
Controllers auch genau so simuliert wird, wie er sich im IC
verhält. Beim alten Simulator (meines Wissens ist das beim
ATmega8 die einzige Möglichkeit) ist das nämlich keinesfalls
so sicher.