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 :)
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
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 ?
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 | ...
|
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.
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.
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?
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.