Forum: Mikrocontroller und Digitale Elektronik STM32 - Mit USART String-Input den CCR (PWM-Timer) setzen


von Nik J. (nikita_j)


Lesenswert?

Hallo zusammen,

Board: STM32F4-Discovery
Bib: STM32
IDE: Atolic Truestudio

Aufgabe:
möchte durch USART-Schnittstelle vom PC an STM32 die Parameter für 
PWM-Signal (Servo-Motoren) senden. Der STM32 soll string auslesen evtl. 
in int umwandeln und CCR1, CCR2, CCRn.. Wert verändern/stellen.

Aktueller Stand:

USART Interrupt
1
void USART2_IRQHandler() {
2
  if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET) {
3
    USART_ClearITPendingBit(USART2, USART_IT_RXNE);
4
    static int cnt = 0;
5
    char input = USART2->DR;
6
7
    if ((input != '\n') && (cnt < MAX_WORDLEN)) {
8
      received_str[cnt++] = input;
9
    } else {
10
      received_str[cnt] = '\0';
11
      cnt = 0;
12
      USART2_Send(USART2, received_str);
13
//      if(received_str){
14
//
15
//      }
16
    }
17
  }
18
19
}

USART string senden
1
void USART2_Send(USART_TypeDef *USARTx, volatile char *str) {
2
  while (*str) {
3
    while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);
4
    USART_SendData(USARTx, *str);
5
    *str++;
6
  }
7
}

Frage:
Wie kann ich "received_str" zerlegen? z.B. ich sende vom Computer 
MP11500
dies soll interpretiert werden als: CCP1 auf Wert 1500 setzen oder 
MP31000: CCP3 auf Wert 1000 setzen.
Wie kann ein Beispielcode dafür aussehen?

Vielen Dank!
Grüß, Nik

von Nop (Gast)


Lesenswert?

Du kannst erstmal gucken, ob der String mit "MP" beginnt. Dann machst Du 
einen switch-case auf das nächste Zeichen, das '1', '2', '3' oder so 
sein kann. Aufgepaßt, '1' ist nicht der integer 1.

Die Zahlenumwandlung kannst Du mit atoi() machen, was einen String 
erwartet. Der Wert kommt ab Positon 3, also value = 
atoi(received_str+3).

Das als Anregungen.

von Nop1 (Gast)


Lesenswert?

sscanf

von pegel (Gast)


Lesenswert?

Nop1 schrieb:
> sscanf

Den finde ich auch gut. ;)
1
#include "stdio.h"
2
#include "string.h"
3
#include "stdint.h"
4
5
uint8_t Zeichenkette [] = {"MP12345"};
6
void main()
7
{
8
  printf("\nZerlegung von: %s \n",Zeichenkette);
9
  uint8_t Laenge = strlen(Zeichenkette);
10
  printf("Laenge der Zeichenkette: %i\n",Laenge);
11
12
13
  if (Zeichenkette[0]=='M' & Zeichenkette[1]=='P'){
14
    printf("MP Stimmt\n");
15
16
    uint8_t  Kanal = Zeichenkette[2]-'0';
17
    printf("Kanal: %d\n",Kanal);
18
19
    uint8_t buffer[10];
20
    int PWM_Wert;
21
22
    for(int i=3,j=0;i<Laenge;i++,j++) {
23
      buffer[j]=Zeichenkette[i];
24
    }
25
26
    sscanf(buffer,"%d",&PWM_Wert);
27
    //printf("buffer: %s\n",buffer);
28
29
    printf("PWM_Wert: %d\n",PWM_Wert);
30
  }
31
}

von Bülent C. (mirki)


Lesenswert?

Diese ganze string Bearbeitung auf einem uC ist doch murks. Sende per 
uart doch gleich die hex Werte der Zahlen. Größere Werte kannst du doch 
zerlegen und zusammen führen.
Will dir damit nur sagen, daß du Dir erstmal grundlegende Gedanken über 
das protokol machen solltest.
Ein Byte als qualifier und dann payload plus am Ende ein Trennzeichen.

von W.S. (Gast)


Lesenswert?

Nikita J. schrieb:
> Aktueller Stand:
>
> USART Interruptvoid USART2_IRQHandler() {
> ...
>     if ((input != '\n') && (cnt < MAX_WORDLEN)) {
>       received_str[cnt++] = input;

Du schreibst Murks.

Trenne doch die logschen Ebenen voneinander, sonst verhedderst du dich 
noch viel mehr.

Wie man sowas richtig macht, kannst du in der Lernbetty nachlesen, 
alternativ in diversen geposteten Quellen von mir.

Sene- und Empfangs-Verfahren:
- der Interrupthandler behandelt die Hardware: er sendet Zeichen aus dem 
Sende-Ringpuffer und empfängt Zeichen, die er in den Empfangs-Ringpuffer 
schreibt. Er bewertet die Inhalte NICHT.

- die von außen sichtbaren Funktionen des seiellen Treibers nehmen zu 
sendende Zeichen entgegen und stopfn sie in den Sende-Ringpuffer und sie 
geben empfangene Zeichen aus dem Empfangs-Ringpuffer an die aufrufenden 
Programmteile. Sie befassen sich NICHT mit der Hardware und sie bewerten 
auch die Inhalte NICHT.

Kommando-Verfahren:
Variante A:
Es gibt ein Kommandoprogramm, das eine Funktion enthält, welche aus der 
Grundschleife zyklisch aufgerufen wird. Diese Funktion fragt den 
seriellen Treiber ab, ob Empfangszeichen vorliegen, sortiert diese in 
einen Kommandopuffer und sendet ein Echo der Zeichen zurück. Sie kann 
auch diverse Editierfunktionen haben. Ist der Puffer voll oder ist ein 
Enter (CR oder LF oder was auch immer) erkannt, dann ruft sie die 
eigentliche Kommandofunktion auf, welche die Kommandozeile analysiert 
und entsprechend ausführt.

Variante B:
Es gibt ein Kommandoprogramm, das eine Funktion enthält, welche aus der 
Grundschleife zyklisch aufgerufen wird. Diese Funktion fragt den 
seriellen Treiber ab, ob Empfangszeichen vorliegen, wertet das aktuelle 
Zeichen aus und führt die zugehörigen Funktionen aus.

Diese Variante B ist nicht für HMI geeignet, aber für schnelle 
Maschinenkommunikation. Mal ein Beispiel für nen Plotter:
120.5X92.0YD200X20YU
macht nen Strich von x=120.5, y=92 nach x=200, y=20

W.S.

von Nik J. (nikita_j)


Lesenswert?

Vielen herzlichen Dank für eure Vorschläge! Ich werde mich an diesen 
Wochenende dies ausprobieren!

Grüße, Nik

von Andreas S. (igel1)


Lesenswert?

Nikita J. schrieb:
> Vielen herzlichen Dank für eure Vorschläge! Ich werde mich an diesen
> Wochenende dies ausprobieren!
>
> Grüße, Nik

Bitte poste einmal Deine Ergebnisse, denn Du fertig bist - ich wollte 
auch schon einmal immer so etwas programmiert haben.

Viele Grüße

Igel1

von pegel (Gast)


Angehängte Dateien:

Lesenswert?

Mit dem sscanf geht es sogar noch eleganter mit einer formatierten 
Zerlegung, wobei der letzte Wert auch eine variable Länge haben kann.

Siehe Anhang.

von pegel (Gast)


Lesenswert?

Mit Leerzeichen zwischen den Werten im String kann man sich auch die 
Längenangabe sparen.

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.