Hallo zusammen, ich versuche gerade ein bzw. mehrere Zeichen über die rs232 zu senden und das im Interruptmodus. Das funktioniert auch schon mehr oder weniger gut. Ich verwende dazu CooCox und die HAL library. Controller: stm32f429ni Was ich aber nicht verstehe ist folgender Befehl: HAL_UART_Receive_IT(&UartHandle, rx_data, 1); Muss der "Befehl" in der while(1) schleife stehen?? Dann ist das ja kein richtiger Interrupt oder?? Außerdem muss man vorher die Anzahl der Zeichen angeben, die weiß ich ja vorher noch nicht. Wie wäre denn das zu lösen. Vielen Dank schonmal und schöne Grüße
So viele Fragen auf einmal :-) Fangen wir mal an... Stell erst mal bitte den Code vor. Also deine Routine + HAL_UART_Receive_IT. Dann kann man schon mal sagen, wie diese zusammenarbeiten. "Normal" wäre: uC bekommt ein Zeichen per UART-Rx - Interrupt wird ausgelöst - im INT_Handler wird das empfangene Byte "weggeschrieben" (z.B. in ein Struct oder Buffer oder was auch immer)- in der Haupschleife verarbeitet man das Byte Thema String empfangen: entweder per DMA (einfache Lösung, wenn die Länge des Strings vorher bekannt ist) oder Interruptgesteuert (dann muss man die Routinen dafür aber selbst schreiben). Schau dir mal als erstes das hier an, damit du mal eine Idee bekommst wie man sowas macht: https://www.mikrocontroller.net/articles/FIFO
Danke schonmal für die rasche Antwort. Also mein Code sieht wie folgt aus: #include "stm32f4xx_hal.h" #include "stm32f4xx_hal_rcc.h" #include "stm32f4xx_hal_gpio.h" #include "stm32f4xx_hal_uart.h" #include "stm32f4xx_hal_cortex.h" #include <stdio.h> #include <stdlib.h> #include <string.h> UART_HandleTypeDef uart_config; int x=0; char data[10]; char rx_byte[1]; int main(void) { int i=0; HAL_Init(); SystemInit(); //************ UART CONFIG *****************************// __USART1_CLK_ENABLE(); uart_config.Instance=USART1; uart_config.Init.BaudRate=115200; uart_config.Init.WordLength=UART_WORDLENGTH_8B; uart_config.Init.StopBits=UART_STOPBITS_1; uart_config.Init.Parity=UART_PARITY_NONE; uart_config.Init.Mode=UART_MODE_TX_RX; uart_config.Init.HwFlowCtl=UART_HWCONTROL_NONE; uart_config.Init.OverSampling=UART_OVERSAMPLING_8; HAL_UART_Init(&uart_config); HAL_NVIC_SetPriority(USART1_IRQn,0,1); HAL_NVIC_EnableIRQ(USART1_IRQn); //**********************************************************// //************ UART GPIO CONFIG *********************// GPIO_InitTypeDef uart_gpio; __GPIOA_CLK_ENABLE(); uart_gpio.Pin=GPIO_PIN_9 | GPIO_PIN_10; uart_gpio.Mode=GPIO_MODE_AF_PP; uart_gpio.Pull=GPIO_NOPULL; uart_gpio.Speed=GPIO_SPEED_FAST; uart_gpio.Alternate=GPIO_AF7_USART1; HAL_GPIO_Init(GPIOA, &uart_gpio); //******************************************************// //************ LED ****************************// GPIO_InitTypeDef gpio_led; __GPIOG_CLK_ENABLE(); gpio_led.Pin=GPIO_PIN_12; gpio_led.Mode=GPIO_MODE_OUTPUT_PP; gpio_led.Pull=GPIO_NOPULL; gpio_led.Speed=GPIO_SPEED_FAST; HAL_GPIO_Init(GPIOG, &gpio_led); //***********************************************// while(1) { HAL_UART_Receive_IT(&uart_config, rx_byte, 1); HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, 0); for (i=0; i<=500000; i++); //delay für LED HAL_GPIO_WritePin(GPIOG, GPIO_PIN_12, 1); for (i=0; i<=500000; i++); //delay für LED } } void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle) { data[x]=rx_byte[0]; if (data[x] =='\r') { HAL_UART_Transmit_IT (&uart_config, data, x); x=0; } else { x++; } } void USART1_IRQHandler(void) { HAL_UART_IRQHandler(&uart_config); } Wäre meine Überlegung so prinzipiell richtig?? An der Ausführung muss natürlich noch gearbeitet werden :)
Hab mal etwas gesucht, und im Jahr 2014 war das auch schon ein Problem: https://my.st.com/public/STe2ecommunities/mcu/Lists/STM32Java/Flat.aspx?RootFolder=https%3a%2f%2fmy.st.com%2fpublic%2fSTe2ecommunities%2fmcu%2fLists%2fSTM32Java%2fSTM32Cube%20%20UART%20Receive%20Interrupt&FolderCTID=0x01200200770978C69A1141439FE559EB459D758000F9A0E3A95BA69146A17C2E80209ADC21¤tviews=4114 Ich habe mich nie richtig mit den ganzen Cube von ST beschäftigt, aber du könntest z.B den USART1_IRQHandler anpassen:
1 | void USART1_IRQHandler(void) |
2 | {
|
3 | // HAL_UART_IRQHandler(&uart_config);
|
4 | data[x]=rx_byte[0]; |
5 | |
6 | if (data[x] =='\r') |
7 | {
|
8 | HAL_UART_Transmit_IT (&uart_config, data, x); |
9 | x=0; |
10 | }
|
11 | else
|
12 | {
|
13 | if(x < 10) |
14 | {
|
15 | x++; |
16 | }
|
17 | else
|
18 | {
|
19 | // Error
|
20 | }
|
21 | }
|
22 | }
|
Die Funktion HAL_UART_Receive_IT sieht für mich aus, als ob hier eine grosse und definierte Anzahl an Bytes empfangen werden soll. Der Interrupt selber wird erst ausgeführt, wenn die x Bytes auch wirklich empfangen wurden. Also Timeout und solches Zeugs müsstest du selber handhaben. Wenn du aber nicht weisst, wieviel Übertragen wird, dann würde ich wieder "altmodisch" direkt den IRQ-Hanlder verwenden. Da hast du die volle Kontrolle.
:
Bearbeitet durch User
Vielen Dank für die Antworten aber leider bekomme ich das Ding nicht richtig zu laufen. Was ich immer noch nicht verstehe folgender Befehl: HAL_UART_Receive_IT(&uart_config, rx_byte, 1); Der muss scheinbar in der Hauptschleife stehen, sonst funktioniert nichts. Das ist aber meiner Meinung nach dann keine Interruptsteuerung, wenn ich das jedes mal aufrufen muss, oder?? Kann mir das jemand erklären?? Hat vielleicht jemand ein simples Beispielprogramm mit der HAL library, welches er posten kann!? Danke schonmal.
Mein Tipp: Use the source, Luke! Schau halt selber im Source der Hal Lib nach was die da so treibt.
elektro01 schrieb: > Was ich immer noch nicht verstehe folgender Befehl: > HAL_UART_Receive_IT(&uart_config, rx_byte, 1); > > Der muss scheinbar in der Hauptschleife stehen, sonst funktioniert > nichts. Das ist aber meiner Meinung nach dann keine Interruptsteuerung, > wenn ich das jedes mal aufrufen muss, oder?? Kann mir das jemand > erklären?? Der Thread ist zwar schon alt, wurde aber gerade in Beitrag "Re: STM32 HAL Tutorial" referenziert und da passt die Antwort besser hierhin. Die Funktion HAL_UART_Receive_IT(&uart_config, rx_byte, 1); liefert einen Status zurück der ausgwertet werden sollte. Wenn ein Receive gestartet und noch nichts empfangen wurde wird die beim erneuten Aufruf Busy zurückliefern. Im HAL_UART_RxCpltCallback() kann man ein Flag setzen wenn der Empfang fertig ist (weil z.B. ein Endezeichen empfangen wurde) und im Hauptprogramm kann man andere Sachen erledigen und gelegentlich das Empfangsflag abfragen. Aus dem anderen Thread: technikus schrieb: > HAL_UART_Receive_IT(&UartHandle, rx_data, 10); > > Füllt fleißig den Puffer bis 10 Bytes empfangen wurden und beginnt dann > wieder von vorne - alles Interrupt gesteuert. > > Was ist aber, wenn ich in der Hauptschleife auslese ob schon was da ist > und dann den Startzeiger vom Puffer neu initialisieren möchte? > Qick and dirty kriege ich das hin, geht aber irgendwie am HAL Gedanken > vorbei... Das halte ich für keine gute Strategie, das behandelt man besser in einer Statemachine. Wenn das Protokoll über die Schnittstelle z.B. mit fixem Header+Daten aufgebaut ist startest du einen Receive mit Anzahl Headergrösse und setzt den Status auf 'STATE_RECEIVE_HEADER'. Im RxCpltCallback wird dann nur der Status auf Header empfangen gesetzt. Wenn das Hauptprogramm diesen Status erkennt startet es dann den Receive mit der nötigen Anzahl Daten.
Danke für den konstruktiven Beitrag! Nur was mache ich, wenn der Empfangspuffer mit z.B. 10 Zeichen definiert ist, 9 empfangen werden und das Endzeichen nicht empfangen wird? Dann müsste die Funktion ja nach einem Timeout den Puffer von vorne füllen ?!
ja, timeout ist das Stichwort nachdem ich auch suchen würde. Im User Manual ist ein Kapitel 'Timeout and error management'. Das wird für mehrere Funktionen benutzt ist damit übergeordnet. Im Kapitel UART ist noch ein 'how to use' da findest du schonmal eine kurze Erklärung zum nötigen Ablauf. Und die Interrupt und DMA (non-blocking) Funktionen können mit den Abort Funktionen abgebrochen werden, damit muss man dann etwas spielen. Wenn man ein Protokoll ohne Endezeichen hat kann man auch Blockweise mit Timeout lesen, solche Protokolle finde ich aber weniger gut. Ansonsten ist die Nutzung von Timeouts sehr zu empfehlen. Weil das mehr Aufwand ist spart man sich das gerne, aber wenn der HAL das schon bietet sollte man das auch mitnehmen. Für mich macht das den Unterschied zwischen funktionierenden und robusten Programmen aus: es gibt viele die tun was sie sollen, aber einmal Stecker raus-rein und das Programm hängt und muss neugestartet werden. Programmiere industrielle Steuerungen und du weisst was das kostet...
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.