Forum: Mikrocontroller und Digitale Elektronik PWM über serielle Schnittstelle


von Leon (Gast)


Lesenswert?

Hallo,
Ich möchte über die serielle Schnittstelle auf meiner Platine die 
Pulsbreite meiner PWM ädern. Ich benutze einen Atmega8 mit 
entsprechendem max232 pegelwandler.
Die PWM habe ich meinem Microcontroller beigebracht und kann über die 
entsprechende Variable im Programm die Breite meines Pulses ändern.
Da ich den Puls on the flight ändern möchte, ohne den Controller jedes 
mal neu zu programmieren, würde ich gerne über die serielle 
Schnittstelle an die Variable herankommen.  Geht das?
Muss ich sie dafür in irgendeinen Speicher schreiben? Oder ist es 
einfacher bei jedem Signal die Variable zu verändern (größer, kleiner) 
anstatt die neue Variable direkt zu übertragen?
Mein erster Ansatz war, dass ich die entsprechenden Pins am Controller 
auf Eingang setze...

Wäre schön, wenn mir jemand da Tipps/Anregungen geben könnte.

Ich muss natürlich noch sagen, dass ich im ganzen 
microcontroller-programmieren noch recht unerfahren bin. grundsätzlich 
sind C kenntnisse vorhanden.

Danke im Voraus :)

von Alex S. (thor368)


Lesenswert?

Tach Leon,

grundsätzlich ist deine Idee den neunen Sollwert vom USART Modul an die 
entsprechende Stelle im Speicher zu schreiben richtig. Aber du denkst zu 
kompliziert. Du hast deinen code nicht gepostet, von daher kann ich nur 
sehr abstrackt reden.

Damit das Timermodul ein PWM Signal erzeugen kann benötigt es einen 
Sollwert in OCRxx. Außerdem hast du ein USART Modul, dass in der Lage 
ist Daten von einem PC zu empfangen. Im Prinzip musst du nun nur noch 
die vom PC gesendeten bytes in das entsprechende OCR kopieren. Die mega 
AVRs haben noch kein DMA, sodass für jedes eintreffende byte die CPU 
aktiv werden muss. Am einfachsten geht das, indem du den RX interrupt 
auf dem USART aktivierst und in der ISR einfach ein OCRxx = UDR machst. 
Komplizierter wird es natürlich, wenn du ein 16bit timer verwendest.

Thor

von kopfkratzer (Gast)


Lesenswert?

Lies Dir erstmal das hier durch:
http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART
Du brauchst auch eine passene Kalibrierung Deines internen Taktes bzw. 
besser einen passenden Baudratenquarz als externen Taktgeber.
Vielleicht wäre auch USB was für Dich ?

von Troll (Gast)


Lesenswert?

Dein Programm braucht dann wohl noch eine Empfangsroutine für die 
serielle Schnittstelle. Je nachdem, welches Zeichen da ankommt (also 
welches Zeichen Du in Deinem Terminal-Programm tippst), sollte die 
entsprechend reagieren.
Ganz grob:
Wenn z.B. das Zeichen '+' kommt, kannst Du Deine Variable um 1 erhöhen, 
wenn ein '-' kommt, verringern, und wenn eine Ziffer kommt, kannst Du 
die Dir merken, mit 10 multiplizieren und die weitere addieren, wenn 
eine weitere kommt, und die Zahl als Wert setzen, wenn ein '\n' 
(Enter-Taste) kommt.

Dafür musst Du die serielle Schnittstelle entsprechend dem Artikel 
initialisieren und eine ISR für "Zeichen empfangen" schreiben.
Das könnte ganz grob in der einfachsten implementierung so aussehen:
1
...
2
3
volatile uint16_t tmp_Zahl;
4
volatile uint16_t pwm_Wert;
5
6
main()
7
{
8
  ...
9
10
  tmp_Zahl = 0;
11
  pwm_Wert = PWM_STARTWERT;
12
13
  // UART init:
14
  ...
15
  UCSRB = (1<<RXEN) | ...;
16
17
  while(1);
18
}
19
20
...
21
22
ISR(USART_RXC_vect)
23
{
24
  char c = UDR;
25
  switch (c)
26
  {
27
  case '-':
28
    if (pwm_Wert > 0)
29
    {
30
      --pwm_Wert;
31
      OCwasauchimmer = pwm_wert;
32
    }
33
    break:
34
  case '+':
35
    if (pwm_Wert < DEIN_MAX_PWM_WERT)
36
    {
37
      ++pwm_Wert;
38
      OCwasauchimmer = pwm_wert;
39
    }
40
    break:
41
  case 10: // Linefeed
42
    if (tmp_Zahl != -1)
43
    {
44
      pwm_Wert = tmp_Zahl;
45
      OCwasauchimmer = pwm_Wert;
46
    }
47
    break;
48
  default:
49
    if ((c => '0') && (c <= '9'))
50
    {
51
      if (tmp_Zahl == -1)
52
      {
53
        tmp_Zahl = 0;
54
      }
55
      tmp_Zahl *= 10;
56
      tmp_Zahl += (c - '0');
57
    }
58
    else
59
    {
60
      // falsches Zeichen bricht aktuelle Eingabe ab:
61
      tmp_Zahl = -1;
62
    }
63
  }
64
}
65
66
...

von Karl H. (kbuchegg)


Lesenswert?

Leon schrieb:

> Wäre schön, wenn mir jemand da Tipps/Anregungen geben könnte.

Das ist jetzt ein bischen schwierig, denn eigentlich ist das ziemlich 
simpel, wenn man ein bischen Übung in der Programmierung hat. Speziell 
einen einzelnen 8-Bit Wert per UART zu übertragen ist nicht wirklich 
Raketentechnik. Bei mehr Bytes bzw. wenn es sich jetzt um einen 16-Bit 
Wert handelt, wird das schon ein wenig schwieriger.

Hast du dir denn schon mal die Tutorien hier auf der Web-Site angesehen?
AVR-Tutorial
AVR-GCC-Tutorial


> Mein erster Ansatz war, dass ich die entsprechenden Pins
> am Controller auf Eingang setze...

Wenn du bei UART bleiben willst, dann ist das schon ein wenig 
aufwändiger. Und nein, genau diesen Schritt brauchst du dabei nicht. Das 
macht sich die UART im Mega8 schon selber, wenn du sie einschaltest. Man 
kann jetzt den UART Empfang per Interrupt machen, aber als Anfänger 
würde ich dir erst mal ein Polling (also regelmässiges Nachsehen ob was 
da ist) empfehlen. Ist leichter zu verstehen, wie da die Abläufe sind. 
Die Tutorien sind da deine Freunde.
Das größte Problem beim UART ist allerdings in vielen Fällen die 
Inbetriebnahme. Denn wann da irgendwo etwas nicht stimmt, dann geht erst 
mal gar nichts. Daher nimmt man eine UART meistens auch erst mal so in 
Betrieb, dass man vom µC aus an den PC senden lässt und dort mit einem 
Terminalprogramm kontrolliert, ob alles in Ordnung ist.


Eine andere Idee wäre es, zb mit einem Poti und dem AD-Wandler die 
Vorgabe für die PWM zu erhalten. Auch dazu findet sich in den Tutorien 
was.

von xfr (Gast)


Lesenswert?

Als erstes musst Du den UART zum Laufen bringen. Dazu würde ich erstmal 
versuchen, ein Zeichen vom Mikrocontroller an den PC zu senden und im 
Terminal zu sehen. Wenn das geht, machst Du die andere Richtung, ein 
Zeichen vom UART im Mikrocontroller empfangen.

Du schreibst Dir also eine Funktion:
1
int uart_getchar(void)

Die liefert das empfangene Zeichen vom UART zurück, wenn eins kam oder 
-1, wenn keins kam. Es gibt auch fertige UART-Bibliotheken, die Du 
nutzen kannst, z.B. von Peter Fleury. Der Lerneffekt ist aber größer, 
wenn man es selber schreibt. Ungepuffert sind das nur wenige Zeilen.

So, jetzt kannst Du also einzelne Zeichen empfangen. Dann kannst Du 
Deiner Phantasie freien Lauf lassen und Dir ein Übertragungsprotokoll 
überlegen. Für den Anfang ist es das einfachste, die Variable bei einem 
bestimmten Zeichen zu erhöhen und mit einem anderen zu erniedrigen:
1
while (1) {
2
  int zeichen = uart_getchar();
3
  if (zeichen == 'a' && variable < 255) {
4
    variable++;
5
  } else if (zeichen == 'b' && variable > 0) {
6
    variable--;
7
  }
8
]

Wenn das funktioniert kannst Du etwas weiter gehen und die Zahl dezimal 
als ASCII-Zeichen übertragen (so wie ein Mensch sie in die Tastatur 
eingeben würde) und mit einem <Enter>, also dem Zeichen '\r', 
terminieren.

Das Programm muss dann in einer Schleife die UART-Zeichen empfangen, 
hintereinenader in einen Pufferspeicher legen bis ein '\r' kommt, den 
String in eine Zahl umwandeln und der Variable zuweisen.

von Leo (Gast)


Lesenswert?

Hallo,
danke für die Hilfe. hat mir alles sehr geholfen:) habs anfangs noch 
selber versucht, hab dann aber die uart_getchar() von peter fleury 
verwendet. Leider klappt diese nicht mit einem Interupt, weswegen ich 
nun die ganze zeit eine abfrage senden muss. Aber sie funktioniert.

Nun hab ich das problem, dass ich mit dem uart_getchar() anscheinend nur 
einstellige character senden/empfangen kann. da ich meine PWM-Variable 
aber von 0-100 durchstimmen will, hilft mir das leider nur bedingt.

hat da jemand eine Lösung parat?

von Bronco (Gast)


Lesenswert?

Was hindert Dich denn daran, mehrere Zeichen zu übertragen?

von Leo (Gast)


Lesenswert?

ich dachte, das uart_getc. lag wohl an char/int problematik. jetzt 
klappts auf jeden fall.

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.