stm32 HAL UART Receive_IT(.) sendet nur 1 Byte

Gast #5699639
Lesenswert?

Servus zusammen,

ich versuche gerade auf meinem Nucleo F767ZI Daten über die 
HAL_UART_Receive_IT() Funktion zu empfangen. Leider kommt im Speicher 
nur das erste Bit an welches versende. Hier der Quellcode:


In der main.c:

uint8_t a = 0;
char docklight[10];

int main(void){
   while(1){
    HAL_UART_Receive_IT(&huart3,&docklight,strlen(docklight));
    if(a == 1){
      a = 0;
      ptr = strtok(docklight,",");
      while(ptr != NULL){
        HAL_UART_Transmit(&huart3,(uint8_t*)ptr,strlen(ptr),10);
        ptr = strtok(NULL,",");
      }
    }
}
}

In der stm32f7xx_it.c:

extern a;

void USART3_IRQHandler(void)
{
  a = 1;
  HAL_UART_IRQHandler(&huart3);
}

Die Variable a soll nur den Transmit Code aus der main auslösen. Ich 
wollte den Interrupt so kurz wie möglich halten, die Daten werden in der 
main später noch weiterverarbeitet.

Wenn ich mit dem Debugger durchgehe wird nur das erste Zeichen meines 
gesendeten Strings gespeichert obwohl ich mehrere versende. Wenn ich das 
Programm ohne Breakpoints ausführe, sendet er mir den gesamten String 
zurück was ich ja möchte. Ich hab keine Ahnung warum er das im Debug 
Modus nicht macht. Ich kann so den String nicht weiterverarbeiten weil 
er immer nur das erste Zeichen des gesendeten Strings speichert. Ich 
verwende zum Senden und zum Anzeigen der Daten Docklight.
#5699649
Lesenswert?

Marco D. schrieb:
> Wenn ich mit dem Debugger durchgehe wird nur das erste Zeichen meines
> gesendeten Strings gespeichert obwohl ich mehrere versende.

Wenn der STM direkt beim ersten Zeichen, das er empfängt anhält, dann 
kann der Interrupt auf alle weiteren Zeichen nicht mehr reagieren. Dein 
PC sendet ja den restlichen String, auch wenn der STM sich im Breakpoint 
befindet.

Gruß, Stefan
Gast #5699793
Lesenswert?

In der _*_it.c brauchst du nichts zu ändern.
Füge im die main.c die Funktion HAL_UART_RxCpltCallback ein.
In dieser kommt jedes Zeichen einzeln an und du kannst auf Zeilenende 
auswerten oder einen Puffer mit einer Anzahl Zeichen füllen.
#5699945
Lesenswert?

Marco D. schrieb:
> Inwiefern muss die Callback Funktion in der main eingebaut werden ? Ich
> werde aus der Funktion nicht wirklich schlau.

In welcher Datei du diese Funktion implementierst ist letztendlich egal. 
Entscheidend ist, daß der Linker die findet.
Es gibt im HAL bereits eine leere Funktion mit diesem Namen, die als 
"weak" deklariert ist, und die überschreibst du so.
#5699959
Lesenswert?

Marco D. schrieb:
> Die Funktion macht scheinbar nicht wirklich was. Ich weiß daher
> nicht
> was ich mit genau dieser soll wenn ich sie sowiso überschreiben soll.

Die Funktion wird aus der Interrupt-Routine heraus aufgerufen und 
bekommt das Handle der Schnittstelle übergeben.
So kommst du an die empfangenen Daten.

Weiter verarbeiten mußt du diese Daten natürlich selber.
#5699967
Lesenswert?

Marco D. schrieb:
> Kann es sein das es eher an Docklight liegt und ich, wenn ich eine
> Sequenz sende nur einzelne chars mit entsprechendem Nullterminator nach
> jedem Zeichen versende ?

Nein!
Wenn du die Interrupt-gestützten Funktionen nutzen willst, brauchst du 
zwingend die zugehörige Callback-Funktion.

Woher willst du sonst wissen, daß etwas empfangen wurde?
Gast #5699971
Lesenswert?

1
char docklight[10];
2

3
int main(void){
4
    while(1){
5
        HAL_UART_Receive_IT(&huart3,&docklight,strlen(docklight));

strlen gibt 0 zurueck, da dein Array global ist und damit automatisch 
mit 0 initialisiert wird. Waere das Array nicht global (und nicht 
initialisiert), wuerde strlen zaehlen, bis im Speicher irgendwann mal 
eine 0 steht.
Willst du das? Oder wolltest du eher sizeof nehmen?
1
#include <iostream>
2
#include <string.h>
3

4
using namespace std;
5

6
char docklight[10];
7

8
int main(void)
9
{
10
  cout << "strlen is: " <<  strlen(docklight) << endl;
11
  cout << "sizeof is: " <<  sizeof(docklight) << endl;
12

13
  return 0;
14

15
}
1
$ c++ -Wall -Wextra -o main main.cpp && ./main
2
strlen is: 0
3
sizeof is: 10
Gast #5699974
Lesenswert?

Wenn ich die Funktion HAL_UART_RxCpltCallback(...) in der main aufrufe 
wird doch nicht die ISR dadurch aufgerufen. Ich blicke überhaupt nicht 
mehr durch. Mit Handle meinst du das &huart3 welches ich übergebe ? wie 
soll ich daraus die empfangenen Daten herausbekommen ? Ich müsste ja auf 
die Variable docklight zugreifen können um mit den Daten was anzufangen 
was ich aber nicht kann.
#5699986
Lesenswert?

Marco D. schrieb:
> Wenn ich die Funktion HAL_UART_RxCpltCallback(...) in der main aufrufe
> wird doch nicht die ISR dadurch aufgerufen. Ich blicke überhaupt nicht
> mehr durch. Mit Handle meinst du das &huart3 welches ich übergebe ? wie
> soll ich daraus die empfangenen Daten herausbekommen ? Ich müsste ja auf
> die Variable docklight zugreifen können um mit den Daten was anzufangen
> was ich aber nicht kann.

Du rufst die Callback-Funktion NIEMALS selber auf!

Die wird aufgerufen, sobald 1 Zeichen über die UART empfangen wird.

Und Ja!

huartx ist das Handle.

Die erste Aktion in dem Callback ist es, zu überprüfen ob das Handle zu 
deiner gewünschten UART gehört.
Gast #5699988
Lesenswert?

Also ich hab jetzt nochmal nachgeschaut wie die Interrupt Funktion 
arbeitet. Schein, was ich nicht wusste, wird die Callback Funktion 
aufgerufen, nachdem der Buffer für die empfangenen Dateien leer ist. 
Also muss ich doch nicht die Callback Funktion in der main aufrufen 
sondern sie da nur überschreiben oder ? Mich stört nur das in 
stm32f7xx_hal_uart.c darauf hingewiesen wird, dass 
HAL_UART_RxCpltCallback möglichst nicht verändert werden sollte.
Gast #5700024
Lesenswert?

Ich möchte einfach nur einen String empfangen und, wenn dieser dann 
eingelesen wurde, mit diesem String weiterarbeiten. Es kann doch nicht 
sein, dass das so kompliziert ist. Die Interrupt Funktion habe ich nur 
verwendet weil ich nicht wusste wie ich sonst dafür sorge, dass nach 
einmaligem senden der Daten im main programm der empfangene String 
weiterverarbeitet werden kann. Es geht auch sicherlich dann noch einfach 
ohne, nur weiß ich nicht wie. Ich wäre für jeden Hinweis sehr dankbar. 
Es kann mir aber doch niemand erzählen das ich für so einen Generalfall 
eine eigene Funktion schreiben muss !
Gast #5700028
Lesenswert?

Es war auch mein Plan jetzt nur die reguläre FUnktion ohne Interrupt zu 
verwenden. Nur hab ich da keine Ahnung wie ich in der while(1)-Schleife 
dafür sorge, dass nur einmal etwas versendet wird. Packe ich da die 
Transmit-Funktion in die Callback-Funktion ? Da wiederum kann ich aber 
nicht auf meinen empfangenen String zugreifen weshalb das nicht geht.
#5700043
Lesenswert?

Fang mal hiermit an!
Sonst wird das nix....

STM32Cube basics MOOC with hands-on exercises:
https://www.youtube.com/playlist?list=PLnMKNibPkDnGtuIl5v0CvC81Am7SKpj02

Moving from 8 to 32 bits workshop - first steps in STM32:
https://www.youtube.com/playlist?list=PLnMKNibPkDnHXgWV0h36LQDGrEuT2r5I4


Danach gehts dann hier weiter:
https://www.st.com/content/st_com/en/support/learning/stm32-education/stm32-moocs.html
Gast #5700358
Lesenswert?

Also ich hab jetzt den Code auf folgendes reduziert:

int main(void){

char daten[10] = "Hallo\n";

  while(1){

      HAL_UART_Receive(&huart3,(uint8_t*)daten,strlen(daten),100);
      HAL_UART_Transmit(&huart3,(uint8_t*)daten,strlen(daten),100);
      HAL_Delay(500);
}

Ich bekomme auch mit dem "normalen" Receive nur 1 Bit geladen. D.h. wenn 
ich etwas einlese, dann ändert sich nur das 1. Bit. Ich benutze nur 
default settings und hab ein komplett neues Projekt erstellt. Ich habe 
einzig die Baudrate vom Uart3 auf 9600 gestellt damit ich etwas über 
meinen USB Port versenden kann.

Habe auch schon etliche Tutorials gesehn und die machens auch nicht 
anders.
Gast #5700761
Lesenswert?

Also ich brauche für meinen Zweck definitiv die Interrupt Funktion. Ich 
bekomme es mittlerweile hin Daten mit festgelegter Größe zu empfangen. 
Ich habe aber keine Ahnung wie ich eine Routine schreibe, die mir Daten 
variabler Länge einliest. Ich habe am Schluss der Nachricht einen 
Nullterminator womit ich es schaffen sollte variable Längen einzulesen. 
Hat jemand einen Tipp für mich wie ich da vorgehe ?
Gast #5700968
Lesenswert?

eine callback ist eine "rückruf-funktion " ..
sie wird irgendwo anders aufgerufen ...

frei nach dem motto: wenn was passiert sag mir bescheid!!!
bescheidgesagt wird hier über diese funktion ...


wenn du also deine :
1
volatile uint8_t IstWasPassiert  =  0;
2

3
char rxString[100];
4
uint8_t rxCount;
5

6

7
int main(){
8

9
   uint8_t byte ;
10
   HAL_UART_Receive_IT(&huart3, &byte , 1 );
11

12
   while(1)
13
   {
14
      if( IstWasPassiert == 1 )
15
      {
16
          IstWasPassiert  =  0;
17
          printf( rxString );
18
      }
19
   }
20
}
21

22

23

24
void HAL_UART_RxCpltCallback( uint8_t byte )
25
{
26
   // jedes zeichen was emfangen wird landet hier nacheinander drin !!! 
27
   rxSring[rxCount] = byte;
28
   rxCount++;
29

30
   if( byte == '\n' )
31
   {  
32
       rxCount = 0;
33
       IstWasPassiert  =  1;
34
   }
35

36
   if( rxCount > 100 )
37
       rxCount  = 0;
38

39
}

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren