Forum: Mikrocontroller und Digitale Elektronik Erfassung PWM Signal und verarbeiten


von gee (Gast)


Angehängte Dateien:

Lesenswert?

Hallo liebe mikrocontroller.net Community,
ich bin noch Neuling im Bereich uC Programmierung deshalb benötige ich 
eure Hilfe :). Natürlich habe ich schon die Tutorials hier auf der Seite 
komplett gelesen und mich auch schon in dem uC Handbuch eingelesen.

Zum Problem: Ich benutze einen ATMega 644 (20Mhz) und habe an meinem PB1 
ein PWM-Signal (1Khz, Tastverhältnis 20-80%) anliegen. Jetzt muss ich 
dieses Signal im uC softwaretechnisch erfassen und das Tastverhältnis 
berechnen. Das Tastverhältnis soll danach der Soll-Wert für ein 
PID-Regler sein der dann später ein Drehstrommotor über ein PWM-Modul 
ansteuert.

Die Platine ist komplett fertig und funktioniert auch, ich benötige eher 
programmiertechnische Hilfe ;).. meine größte Sorge ist wie ich das 
Signal am besten auswerte ??
meine erste Idee war die ansteigende Flanke des Signals zu erfassen und 
meinen Timer0 (Timer1 verwende ich dann für meine PWM) zu starten. Wenn 
die Flanke fällt speichere ich in einer Variablen "an" die Zählerwerte 
und lass weiter laufen bis die nächste steigende Flanke kommt und 
speicher den Timer0 wert (-> komplette Periode)"periode" und Teile den 
ersten Wert "an" / "periode". Das ganze Funktioniert nur leider nicht. 
Mein Code stelle ich dazu ->unten.
Wenn ihr bessere Lösungsverschläge habt bin ich dafür offen z.B abtasten 
des Signals etc etc ...

Schon im vorraus vielen Danke für eure Hilfe
  gee

von Karl H. (kbuchegg)


Lesenswert?

>   if(PINB & 0x02){  // Wenn Signal (1) an PB1

Du willst eine Flanke erkennen und nicht den Code ausführen, wenn PB2 
auf 1 ist.

Flanke!

Dazu musst du erkennen, wann PB2 den Pegel WECHSELT.
1
   OldPegel  =  PINB & 0x02;
2
3
4
   while( 1 ) {
5
6
      ...
7
8
      Pegel = PINB & 0x02;    // welchen Zustand hat der Pin jetzt
9
10
11
      if( Pegel != OldPegel ) {   // hat sich was verändert?
12
                                  // wenn ja, dann war da eine Flanke an diesem Pin
13
14
        if( Pegel ) {             // was war das für eine Flanke ?
15
                                  // nachdem der Pin jetzt auf 1 ist, muss er
16
                                  // vorher auf 0 gewesen sein, und das ganze
17
                                  // war eine Flanke  0-> 1
18
           ....
19
        }
20
        else {                    // No, der Pin ist jetzt 0.
21
                                  // also muss das eine Flanke 1 -> 0 gewesen sein
22
          ...
23
        }
24
25
        OldPegel = Pegel;         // jetzigen Zustand merken, damit im nächsten
26
                                  // Durchgang wieder eine Veränderung festgestellt
27
                                  // werden kann
28
      }
29
   }

von gee (Gast)


Lesenswert?

Danke für deinen Hinweis ich werde das gleich morgen testen :)

gee

von gee (Gast)


Lesenswert?

Ich habe deinen Hinweis ausprobiert und die Flanken erkenne ich, vielen 
Danke dafür noch mal. Das weiter Problem das ich gerade habe ist, dass 
ich sobald eine "High" Flanke kommt ich meinen Timer0 hochzählen lassen 
möchte. Wenn die Flanke abfällt speicher ich meinen Zählerwert des 
Timers in einer Variablen, lass aber alles weiter laufen bis die nächste 
"High"Flanke kommt um einen Zählerwert für die komplette Periode zu 
haben. Das Problem ist nur das mein Timer0 nur bis 255 Zählen kann und 
deshalb mehrmals einen Overflow verursacht, weshalb ich falsche Werte 
erhalte. Habt ihr da einen Tipp oder eine bessere Möglichkeit ?

Freue mich weiterhin sehr über eure Hilfe

Gruß

gee

von Michael A. (Gast)


Lesenswert?

gee schrieb:
> Das Problem ist nur das mein Timer0 nur bis 255 Zählen kann und
> deshalb mehrmals einen Overflow verursacht, weshalb ich falsche Werte
> erhalte.
Du könntest mit dem Overflow einen Interrupt auslösen und per Software 
die Anzahl der Überläufe zählen, so dass du mit Softwarezähler und Timer 
insgesamt 16 Bit zur Verfügung hast.

von Seb a. (seppelg85)


Lesenswert?

gee schrieb:
> haben. Das Problem ist nur das mein Timer0 nur bis 255 Zählen kann und
> deshalb mehrmals einen Overflow verursacht, weshalb ich falsche Werte
> erhalte. Habt ihr da einen Tipp oder eine bessere Möglichkeit ?

Warum wählst du nicht einfach einen höheren Timer? Entweder per 
definiertem Top Wert oder z.b. 10 Bit statt aktuell 8.

Gruß

von Johannes S. (Gast)


Lesenswert?

Hallo,

Du kannst Dir eine weitere Hilfsvariable definieren, die bei jedem 
Timerüberlauf (Interrupt verwenden) um eins hochgezählt wird. Diese 
zusammen mit dem Timer0-Wert gibt Dir dann die benötigten Zeiten.

von gee (Gast)


Lesenswert?

Danke für eure Tipps ich versuche es.
Eine Frage ich habe gerade als Test einfach mal meinen 16bit Timer1 
genommen und habe nur mal versucht die komplette Periode zu messen. Auch 
hier kommt immer was anderes raus !? .. mhm.. die 20Mhz werden wohl auch 
hier einen OVF verursachen.. egal ob ich jetzt T0 oder T1 verwende die 
von euch oben genannte Systematik mit dem OVF-Interrupt ist ja die 
gleiche ich teste das jetzt. Danke noch mal :)

gee

von Michael A. (Gast)


Lesenswert?

gee schrieb:
> ... mhm.. die 20Mhz werden wohl auch hier einen OVF verursachen..
Eigentlich nicht. Bei 20 MHz Takt und 1 ms Signalperiode sollte der 
Zähler bis 20000 kommen. Ziehst du den Startwert ab bzw. setzt bei der 
ersten Flanke den Zähler auf 0?

von gee (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

ich setze den Startwert mit TCNT0= 0x00 ja eigentlich zurück oder ?
Habe noch mal im Dateianhang meine Quelldatei. Habe versucht alles so 
genau wie möglich zu Kommentieren. Vielen Dank das ihr mir so helft ich 
versuche so viel wie möglich alleine zu programmieren, aber ich bin 
gerade an einer Stelle wo ich ohne Hilfe nicht weiterkomme -.- ..bzw. 
keine Ideen mehr habe -> zu wenig Erfahrung.

gee

von Michael A. (Gast)


Lesenswert?

Bei der Berechnung der Gesamtzeit ist deine Frage im Kommentar 
berechtigt.
Entweder Multiplikation mit 2^8=256 oder 8-mal nach links schieben.

  Gesamt = i+TCNT0;  // Gesamtzeit
      // wenn der Timer0 z.B 68 OVF hatte
      // muss ich dann nicht die Anzahl der OVF ´
      // mit 255 multiplizieren und das ganze
      // mit dem geraden Zählerwert von T0 addieren
      // also (i*255)+TCNT0  ???????????

1. Die Gesamtzahl muß eine 16-Bit Variable sein (char hat nur 8)
2. Gesamt = (i*255)+TCNT0  oder Gesamt = i<<8 + TCNT0 wäre richtig.

von dennis (Gast)


Lesenswert?

Hallo uC-Community,

mein Programm für die PWM-Abtastung lauft soweit ganz gut,vielen Dank 
noch mal an alle Helfer ;), nur leider ist jetzt ein weiteres komplexes 
Problem hinzugekommen.

Und zwar habe ich natürlich seit der Entwicklung der Software weitere 
Softwareteile hinzugefügt. Jetzt habe ich folgendes Problem:
Ich habe meine PWM-Abtastung(die PWM 1kHz aus einem Steuergerät) durch 
den Timer0 realisiert. Dadurch habe ich das Verhaeltnis errechnet dieses 
wiederum für ein normales PWM-Signal für einen BL-Motor verwendet wird. 
Nun bin ich an einer fortgeschrittenen Stelle, in der ich mehrere 
Programmteile zusammengefügt habe. Durch das Gesamtprogramm verändert 
sich nach jedem Zyklus die Zeit meines Programmdurchlaufs. Dadurch 
bekomme ich obwohl ich die PWM am Steuergerät nicht ändere (sagen wir 5% 
DutyCycle) jeden Zyklus anderes PWM-Verhältnis (meist über 100% -.-) 
dadurch wird auch mein Motor extrem belastet, schwingt und quietscht ...

So an dieser Stelle brauche ich eure Hilfe habe keinen besonderen 
Lösungsansatz.

Ideen wären:
2 uC verwenden, den einen für die Berechnung des PWM-Signal aus dem 
Steuergerät, den anderen für die Ausführung des restlichen Programms.
Sonst fällt mir nichts mehr ein, danke für eure Hilfe..

dennis

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.