Skocz do zawartości
Komentator

Kurs STM32 - #5 - Komunikacja z komputerem, UART

Pomocna odpowiedź

simoon87, OpenSTM32 to nic innego jak gcc - cała reszta to otoczka. Więc źródło problemów to raczej nie kompilator, a IDE już na pewno.

Natomiast co do biblioteki standardowej, to gcc oraz Keil używają oczywiście innych - nie chodzi o StdPeriph, ale o bibliotekę standardową języka C oraz kod uruchamiany przed main().

Na pewno niepotrzebnie wykonujesz w kodzie inicjalizację PLL - w przypadku kodu, który jest dostarczany z OpenSTM32, SystemInit jest wywoływane przed main(), więc nie ma potrzeby ponownej inicjalizacji PLL. To może być przyczyna błędu, ale nie sądzę.

Musiałbyś dokładniej poszukać kiedy ten błąd występuje. O ile rozumiem wywołanie USART_SendChar działa poprawnie, a USART_Puts nie? Dziwna sprawa. Próbowałeś wysłać kilka znaków za pomocą USART_SendChar, np. wywołać funkcję kolejno dla literek z "Hello World!\n"?

Nie wkleiłeś kodu funkcji obsługi przerwania - może tam coś się psuje.

Jest jeszcze jedna możliwość, która tłumaczyłaby dziwne zachowanie - przepełnienie stosu. Domyślnie stos jest bardzo mały (256B o ile dobrze pamiętam, więc można go łatwo przepełnić. Efektem są właśnie programy, które działają, ale po drobnej zmianie przestają.

Udostępnij ten post


Link to post
Share on other sites
Musiałbyś dokładniej poszukać kiedy ten błąd występuje. O ile rozumiem wywołanie USART_SendChar działa poprawnie, a USART_Puts nie? Dziwna sprawa. Próbowałeś wysłać kilka znaków za pomocą USART_SendChar, np. wywołać funkcję kolejno dla literek z "Hello World!\n"?

Nie, to jest tak, że działa tylko funkcja USART_SendData() która jest standardowo w pliku stm32f10x_usart.h ale ona wysyła bajt bez obsługi przerwania.

Nie działa ani USART_SendChar ani USART_Puts które ładują odpowiednio znak lub łańcuch do bufora cyklicznego a następnie wywołują przerwanie. To, że program w ogóle nie wchodzi do przerwania zdiagnozowałem w banalny sposób, na sam początku funkcji obsługi przerwania dodałem zasiedzenie diody. Niestety dioda się nie świeci. Dodatkowo w Debugu widać ze program wykonuje się OK do momentu w którym powinien wejść do przerwania i nagle umiera. Kod przerwanie poniżej:

void USART1_IRQHandler(void)
{
GPIO_WriteBit( LED_GPIO, ERR_LED, 0);  //DEBUG

if( USART_GetITStatus(USART1, USART_IT_TXE) == SET )
{

	// sprawdzamy czy indeksy są różne
	if( Buffer.TxBeg != Buffer.TxEnd )
	{
		Buffer.TxEnd = (Buffer.TxEnd + 1) & TX_BUF_MASK;		// obliczamy i zapamiętujemy nowy indeks konca (może się zrównać z poczatkiem)
		USART1->DR = Buffer.TxBuf[Buffer.TxEnd];				// zwracamy bajt pobrany z bufora  jako rezultat funkcji
	}
	else
	{
		USART_ITConfig(USART1, USART_IT_TXE, DISABLE);  	// wylacz przerwanie = koniec transmisji
	}
}

if( USART_GetITStatus(USART1, USART_IT_TC) == SET )	//gdy bufor nadawczy pusty
{
	SendMode(FALSE);	// odbiornik załaczony && nadajnik wyłaczony
}

if( USART_GetITStatus(USART1, USART_IT_RXNE) == SET )
{
	register uint8_t tmp_head;
    register uint8_t data;

    tmp_head = (Buffer.RxBeg + 1) & RX_BUF_MASK;				// obliczamy nowy indeks poczatku
  	    data = (uint8_t)(USART1->DR);

    if( tmp_head == Buffer.RxEnd )	Buffer.RxBeg = Buffer.RxEnd;	// sprawdzamy nadmisanie

    else
    {
    	switch( data )
    	{
        	case 0:	break;		// ignorujemy bajt = 0
        	case 10: break;			// ignorujemy znak LF
        	case 13: Buffer.ascii_line++;	// sygnalizujemy obecność kolejnej linii w buforze
        	default : Buffer.RxBeg = tmp_head; Buffer.RxBuf[tmp_head] = data;
        }
       }
}
}
Jest jeszcze jedna możliwość, która tłumaczyłaby dziwne zachowanie - przepełnienie stosu.

Co do stosu to jestem sceptycznie nastawiony gdyż ten sam kod działa w Keil oraz ten program robi tylko 2 rzeczy miga diodą oraz wysyła jeden znak. Co miało by przepełniać stos?

plik main:

#include "SystemInit.h"			//Konfiguracja systemu

int main(void)
{
RCC_Config();
GPIO_Config();
RS485_Configuration(9600, USART_Parity_Even);

if( SysTick_Config_Mod(SysTick_CLKSource_HCLK_Div8, 90000ul) ) while(1);
GPIO_WriteBit( LED_GPIO, ERR_LED, 1);	//Wygaszenie diody ERROR

for(;;)
{
	if(!SysTimer.SoftTimer[0])	//100ms
	{
		SysTimer.SoftTimer[0]=10;
		GPIO_WriteBit( LED_GPIO, LIVE_LED, (BitAction)(1-GPIO_ReadOutputDataBit(LED_GPIO, LIVE_LED)) );	// XOR LIVE LED
	}

	if(!SysTimer.SoftTimer[1])	//500ms
	{
		SysTimer.SoftTimer[1]=50;
		SendMode(TRUE);
//			USART_SendData(USART1, 'X');	//Działa ale to jest wyslanie bez obsługi przerwania
//			USART_SendChar(USART1, 'X');	//nie działa
		USART_Puts( USART1, "X" );
	}


}
return 0;
}

Edit: Bez inicjalizacji PLL wszystko bez zmian

Udostępnij ten post


Link to post
Share on other sites

Ciekawe - moim zdaniem pod Keilem ten program też nie powinien działać. Na pewno brakuje wywołania USART_ClearITPendingBit() w przerwaniu - więc po pierwszym wystąpieniu program ma pełne prawo się zapętlić.

[ Dodano: 01-11-2015, 21:42 ]

Podsumowując - OpenSTM32 spokojnie może wykorzystywać komunikację po UART z wykorzystaniem przerwań. Oczywiście pod warunkiem, że napiszemy poprawny program.

A jako ciekawostka, również dla innych osób wersja poprawiona i zmieniona do USART2, żeby można było wykorzystać konwerter wbudowany w Nuceo:

#include "stm32f10x.h"

#define TX_BUF_SIZE 32
#define TX_BUF_MASK (TX_BUF_SIZE-1)
#define RX_BUF_SIZE 32
#define RX_BUF_MASK (RX_BUF_SIZE-1)

struct {
int TxBeg;
int TxEnd;
char TxBuf[TX_BUF_SIZE];
int RxBeg;
int RxEnd;
char RxBuf[TX_BUF_SIZE];
int ascii_line;
}Buffer;

void USART2_IRQHandler(void)
{
   //GPIO_WriteBit( LED_GPIO, ERR_LED, 0);  //DEBUG

   if( USART_GetITStatus(USART2, USART_IT_TXE) == SET )
   {
   	USART_ClearITPendingBit(USART2, USART_IT_TXE);

       // sprawdzamy czy indeksy są różne
       if( Buffer.TxBeg != Buffer.TxEnd )
       {
           Buffer.TxEnd = (Buffer.TxEnd + 1) & TX_BUF_MASK;        // obliczamy i zapamiętujemy nowy indeks konca (może się zrównać z poczatkiem)
           USART2->DR = Buffer.TxBuf[Buffer.TxEnd];                // zwracamy bajt pobrany z bufora  jako rezultat funkcji
       }
       else
       {
           USART_ITConfig(USART2, USART_IT_TXE, DISABLE);      // wylacz przerwanie = koniec transmisji
       }
   }

   if( USART_GetITStatus(USART2, USART_IT_TC) == SET )    //gdy bufor nadawczy pusty
   {
       //SendMode(FALSE);    // odbiornik załaczony && nadajnik wyłaczony
   }

   if( USART_GetITStatus(USART2, USART_IT_RXNE) == SET )
   {
       register uint8_t tmp_head;
       register uint8_t data;

       tmp_head = (Buffer.RxBeg + 1) & RX_BUF_MASK;                // obliczamy nowy indeks poczatku
          data = (uint8_t)(USART2->DR);

       if( tmp_head == Buffer.RxEnd )    Buffer.RxBeg = Buffer.RxEnd;    // sprawdzamy nadmisanie

       else
       {
           switch( data )
           {
               case 0:    break;        // ignorujemy bajt = 0
               case 10: break;            // ignorujemy znak LF
               case 13: Buffer.ascii_line++;    // sygnalizujemy obecność kolejnej linii w buforze
               default : Buffer.RxBeg = tmp_head; Buffer.RxBuf[tmp_head] = data;
           }
       }
   }
}

void USART_SendChar(USART_TypeDef* USARTx, uint8_t Char)
{
   /* Check the parameters */
   assert_param(IS_USART_ALL_PERIPH(USARTx));
   assert_param(IS_USART_DATA(Char));

   /* Fill Tx buffor */
   uint8_t tmp_head;
   tmp_head = (Buffer.TxBeg + 1) & TX_BUF_MASK;
   while (tmp_head == Buffer.TxEnd) {}
   Buffer.TxBuf[tmp_head] = Char;
   Buffer.TxBeg = tmp_head;

   /* Turn On Tx Interrupt / Starting transmit */
   USART_ITConfig(USARTx, USART_IT_TXE, ENABLE);
}

void USART_Puts( USART_TypeDef* USARTx, char *s )
{
   register uint8_t c;
   while (c = *s++) USART_SendChar( USARTx, c );
}


void RCC_Config(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//wlacz taktowanie portu GPIO A    enkoder
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//wlacz taktowanie portu GPIO B    led
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//wlacz taktowanie USART1            uart
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
}

void RS485_Configuration(uint32_t baudrate, uint16_t parity)
{
   GPIO_InitTypeDef gpio;
   USART_InitTypeDef uart;
   NVIC_InitTypeDef nvic;

   /* Enable the USART1 Interrupt */
   nvic.NVIC_IRQChannel = USART2_IRQn; // USART1_IRQn
   nvic.NVIC_IRQChannelPreemptionPriority = 0;
   nvic.NVIC_IRQChannelSubPriority = 0;
   nvic.NVIC_IRQChannelCmd = ENABLE;
   NVIC_Init(&nvic);

   /* Config DE/nRE */
   /* Configure (PA.11) as Output push-pull */
   //GPIO_InitStructure.GPIO_Pin = DO_485;
   gpio.GPIO_Speed = GPIO_Speed_50MHz;
   gpio.GPIO_Mode = GPIO_Mode_Out_PP;
   //GPIO_Init(GPIOA, &GPIO_InitStructure);

   gpio.GPIO_Pin = GPIO_Pin_2;
   gpio.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &gpio);

gpio.GPIO_Pin = GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &gpio);

   /* Configure USART1 Tx (PA.9) as alternate function push-pull */
   gpio.GPIO_Pin = GPIO_Pin_9;
   gpio.GPIO_Mode = GPIO_Mode_AF_PP;
   gpio.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_Init(GPIOA, &gpio);

   /* Configure USART1 Rx (PA.10) as input floating */
   gpio.GPIO_Pin = GPIO_Pin_10;
   gpio.GPIO_Mode = GPIO_Mode_IN_FLOATING;
   GPIO_Init(GPIOA, &gpio);

USART_StructInit(&uart);
   uart.USART_BaudRate = baudrate;
   USART_Init(USART2, &uart);

   /* Enable the USART1 */
   USART_Cmd(USART2, ENABLE);
}


int main(void)
{
volatile long dly;

   RCC_Config();
   RS485_Configuration(9600, USART_Parity_No);

   for(;;)
   {
       USART_Puts(USART2, "Hello world! 1\n");
       USART_Puts(USART2, "Hello world! 2\n");
       for (dly=0;dly<1000000;dly++)
       	;

   }
   return 0;
}
  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Dodanie USART_ClearITPendingBit(USART1, USART_IT_TXE); nic nie zmienia. W dalszym ciągu procesor w ogóle nie wchodzi do USART1_IRQHandler()

Pisząc ten kod posiłkowałem się Książką STM32 Aplikacje i ćwiczenia w języku C. Autor w żadnym z kodów nie używał funkcji USART_ClearITPendingBit.

Mam prośbę mógłbyś udostępnić Twój projekt z OpenSTM32 skoro u Ciebie działa chciałbym zaimportować go do siebie i porównać co robię nie tak.

Udostępnij ten post


Link to post
Share on other sites

A próbowałeś uruchomić program który wkleiłem? Czy też nie chce działać?

Udostępnij ten post


Link to post
Share on other sites
A próbowałeś uruchomić program który wkleiłem? Czy też nie chce działać?

Tak do końca nie mogę zrobić Kopiuj/Wklej wiec założyłem nowy projekt pozamieniałem na USART1 oraz odpowiednie GPIO (nie robię tego na Nuceo). Cały czas nie działa. Jutro przeinstaluje całe to OpenSTM32 bo już nie mam innych pomysłów.

Udostępnij ten post


Link to post
Share on other sites

Faktycznie, flaga TXE jest kasowana przy zapisie do rejestru DR. Więc wywołanie USART_ClearITPendingBit nie jest niezbędne. Ciekawe dlaczego w takim razie nie działa - u mnie działa na USART2, natomiast na USART1 testowałem tylko pod debuggerem, ale wygląda że wszystko jest ok.

Udostępnij ten post


Link to post
Share on other sites

Dzisiaj przeinstalowałem OpenSTM32, założyłem nowy projekt, przekopiowałem wszystkie swoje pliki *.c *.h skompilowałem i dalej nie działa. Nie mam już pomysłów w załączniku przesyłam wyeksportowany projekt. W związku z tym mam prośbę do Ciebie Elvis, jakbyś mógł rzucić na niego okiem może coś zauważysz....

sp_open.zip

Udostępnij ten post


Link to post
Share on other sites

I już wszystko jasne. Użyłeś złego pliku startup - startup_stm32.s.

W nim nie masz zdefiniowanego USART1_IRQHandler w tablicy przerwań. Więc pierwsze wywołanie przerwania robi skok pod adres 0 i wyjątek niepoprawnego dostępu do pamięci.

Jeśli wygenerujesz projekt zgodnie z instrukcją kursu, zamiast startartup_stm32.s będziesz miał dołączony plik startup_stm32f10x_ms.S - nie jest idealny, ale ma chociaż w wektorze przerwań USART1_IRQHandler.

  • Lubię! 2

Udostępnij ten post


Link to post
Share on other sites

Dzięki Tobie rozwikłałem zagadkę! Wielkie dzięki.

Zakładałem projekt tak samo jak w kursie z jedną różnicą....

W kursie wybierana jest płytka Nuceo w oknie MCU Configuration:

Natomiast ja dodałem 2 swoje płytki: ZL27arm, oraz płytkę swojego urządzenia. Gdy wybiore jedną z nich do Startup ładowany jest plik: startup_stm32.s. Jeśli wybiorę Nuceo faktycznie jest plik: startup_stm32f10x_ms.S

Po ręcznej podmianie plików projekt Żyje!!!

Jeszcze raz wielkie dzięki

Udostępnij ten post


Link to post
Share on other sites

Hej, mam problem z komunikacją przez UART na płytce STM32F407 Discovery. Konfiguruję odpowiednio porty oraz sprawdziłem czy jest odpowiednia wartość zegara HSE_VALUE = 8000000. Jednak stale otrzymuję na wyjściu błędne znaki.

Odczyt w terminalu na wysłanie(kilka razy) stringa "hello".

Konfiguracja portu gpio i usart

GPIO_InitTypeDef gpio;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC, ENABLE);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource6,GPIO_AF_USART6);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource7,GPIO_AF_USART6);

gpio.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;;
gpio.GPIO_Mode = GPIO_Mode_AF;
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_PuPd = GPIO_PuPd_UP;
gpio.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_Init(GPIOC, &gpio);

USART_InitTypeDef usart;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART6, ENABLE);

usart.USART_BaudRate = 9600;

usart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
usart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;;
usart.USART_Parity = USART_Parity_No;
usart.USART_StopBits = USART_StopBits_1;
usart.USART_WordLength = USART_WordLength_8b;

USART_Init(USART6, &usart);
USART_Cmd(USART6,ENABLE);

Testowałem na różnych portach i ciągle jest ten sam problem. Macie jakieś pomysły co może być nie tak?

Udostępnij ten post


Link to post
Share on other sites

Dołączam się do podziękowań za kurs.

Zacząłem tydzień temu i idzie mi to bardzo wolniej niż się spodziewałem, jednak to nie jest taka zabaweczka jak Arduino. 🙂

Załączam kod do pracy domowej 5.1-3, bo myślę, że nie ma co tego rozbijać, jak już ostatnie działa. Wprowadziłem pewne niezbędne zmiany, bo pracuję na 303RE.

/**
******************************************************************************
* @file    main.c
* @author  Konrad
* @version V1.0
* @date    11-11-2015
* @brief   UART I/O.
******************************************************************************
*/

#include "stm32f30x.h"
#include <string.h>
#include <stdlib.h>

void send_char(char c) {
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
	;
USART_SendData(USART2, c);
}

void send_string(const char* s) {
while (*s)
	send_char(*s++);
}

int main(void) {
GPIO_InitTypeDef gpio;
USART_InitTypeDef uart;

RCC_AHBPeriphClockCmd(
		RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC
				| RCC_AHBPeriph_GPIOD, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //UART clock

GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_7); //RX, via M00118585.pdf
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_7); //TX, via M00118585.pdf

GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
gpio.GPIO_Mode = GPIO_Mode_AF; //Alternate function for UART
gpio.GPIO_OType = GPIO_OType_PP;
gpio.GPIO_PuPd = GPIO_PuPd_UP;
gpio.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &gpio); //UART init

gpio.GPIO_Pin = GPIO_Pin_5; //pin 5 port A - onboard LED
gpio.GPIO_Mode = GPIO_Mode_OUT;
gpio.GPIO_OType = GPIO_OType_PP;
GPIO_Init(GPIOA, &gpio);

USART_StructInit(&uart);
uart.USART_BaudRate = 115200;
USART_Init(USART2, &uart);

USART_Cmd(USART2, ENABLE);

int my_buffer_size = 5; //size of my buffer
char *my_buffer; //dm alloc
my_buffer = malloc(sizeof(char) * my_buffer_size); 
memset(my_buffer, 0, sizeof(char) * my_buffer_size);//fill with zeros
int buffer_index = 0;

while (1) {
	if (USART_GetFlagStatus(USART2, USART_FLAG_RXNE)) {
		char c = USART_ReceiveData(USART2);
		my_buffer[buffer_index] = c;
		buffer_index++;

		if (buffer_index > my_buffer_size || c == '\r') {
			if (strstr(my_buffer, "on\r")) {
				send_string("Power on onboard LED.\r\n");
				GPIO_SetBits(GPIOA, GPIO_Pin_5);
			}
			else if (strstr(my_buffer, "off\r")) {
				send_string("Power off onboard LED.\r\n");
				GPIO_ResetBits(GPIOA, GPIO_Pin_5);
			}
			else
			{
				send_string("Not recognized command.\r\n");
			}
			memset(my_buffer, 0, sizeof(char) * my_buffer_size);
			buffer_index = 0;
		}

/*			switch (c) {
		case 'b':
			send_string("Odebrano komunikat B!\r\n");
			GPIO_SetBits(GPIOA, GPIO_Pin_5); //set bit
			break;
		case 'a':
			send_string("Odebrano komunikat A!\r\n");
			GPIO_ResetBits(GPIOA, GPIO_Pin_5); //reset bit
			break;
		default:
			send_string("Nieznany komunikat!\r\n");
			break;
		}*/
	}
}
}

Czy to o to chodziło? Przyznam szczerze, że w C już tak mocno zardzewiałem, że nie bardzo wiem jaki bufor mamy na myśli, więc zrobiłem tablicę charów.

Z jakiegoś powodu kompilator wyświetla mi na stałe żółtą strzałkę obok "malloc", co ona oznacza? Nigdy nie pracowałem w Eclipse.

Czy da się tutaj włączyć jakieś przyzwoite kolorowanie składni?

Udostępnij ten post


Link to post
Share on other sites

Jak chodzi o malloc() to funkcja zwraca typ void*, więc Eclipse narzeka na przypisanie go do char* bez jawnego rzutowania.

W programie jest jeden poważny błąd - wyjście poza tablicę. Bufor jest tak mały, że spokojnie można go zadeklarować jako globalny, nie ma potrzeby używania malloc. Ale niezależnie od sposobu przydziału pamięci, ma on rozmiar 5 bajtów. Program po pierwsze odwołuje się do pozycji poza buforem:

if (buffer_index > my_buffer_size

Ten warunek jest spełniony gdy buffer_index = my_buffer_size + 1, czyli 6. Oznacza to, że chwilę wcześniej program zapisał do my_buffer[5]. W języku C tablice są indeksowane od 0, więc bufor kończy się na my_buffer[4].

Kolejny problem to użycie strstr(). Napisy w C kończą się zerem ('\0'). Jeśli tego zera nie będzie, to funkcja będzie przechodziła po pamięci (poza buforem), aż na jakieś zero trafi...

Ponieważ w buforze nie ma zera kończącego napis, więc takie wywołanie jest niepoprawne.

Zamiast strstr() bezpieczniej jest używać funkcji strnstr(), która posiada ograniczenie długości przeglądanego napisu. Wtedy nie byłoby ryzyka wyjścia poza bufor, nawet bez zera kończącego napis.

Ostatnia uwaga dotyczy samego rozpoznawania napisów - strstr, sprawdza, czy napis zawiera określony wzorzeć. Więc polecenie "on" zostanie rozpoznane, jeśli wyślemy np. "tona" - to chyba nie jest poprawne działanie.

  • Lubię! 1

Udostępnij ten post


Link to post
Share on other sites

Dziękuję za taką rzeczową odpowiedź!

Załączam wersje z poprawkami wg. wytycznych.

/**
******************************************************************************
* @file    main.c
* @author  Konrad
* @version V1.0
* @date    11-11-2015
* @brief   UART I/O.
******************************************************************************
*/

#include "stm32f30x.h"
#include <string.h>
#include <stdlib.h>

char my_buffer[5] = "";

void send_char(char c) {
   while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET)
       ;
   USART_SendData(USART2, c);
}

void send_string(const char* s) {
   while (*s)
       send_char(*s++);
}

char *strnstr(const char *haystack, const char *needle, size_t len)
{
       int i;
       size_t needle_len;

       /* segfault here if needle is not NULL terminated */
       if (0 == (needle_len = strlen(needle)))
               return (char *)haystack;

       for (i=0; i<=(int)(len-needle_len); i++)
       {
               if ((haystack[0] == needle[0]) &&
                       (0 == strncmp(haystack, needle, needle_len)))
                       return (char *)haystack;

               haystack++;
       }
       return NULL;
}

int main(void) {
   GPIO_InitTypeDef gpio;
   USART_InitTypeDef uart;

   RCC_AHBPeriphClockCmd(
           RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC
                   | RCC_AHBPeriph_GPIOD, ENABLE);
   RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
   RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //UART clock

   GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_7); //RX, via M00118585.pdf
   GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_7); //TX, via M00118585.pdf

   GPIO_StructInit(&gpio);
   gpio.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
   gpio.GPIO_Mode = GPIO_Mode_AF; //Alternate function for UART
   gpio.GPIO_OType = GPIO_OType_PP;
   gpio.GPIO_PuPd = GPIO_PuPd_UP;
   gpio.GPIO_Speed = GPIO_Speed_50MHz;
   GPIO_Init(GPIOA, &gpio); //UART init

   gpio.GPIO_Pin = GPIO_Pin_5; //pin 5 port A - onboard LED
   gpio.GPIO_Mode = GPIO_Mode_OUT;
   gpio.GPIO_OType = GPIO_OType_PP;
   GPIO_Init(GPIOA, &gpio);

   USART_StructInit(&uart);
   uart.USART_BaudRate = 115200;
   USART_Init(USART2, &uart);

   USART_Cmd(USART2, ENABLE);

   int my_buffer_size = 5; //size of my buffer
   //char *my_buffer; //dm alloc
   //my_buffer = malloc(sizeof(char) * my_buffer_size);
   //memset(my_buffer, 0, sizeof(char) * my_buffer_size);//fill with zeros
   int buffer_index = 0;

   while (1) {
       if (USART_GetFlagStatus(USART2, USART_FLAG_RXNE)) {
           char c = USART_ReceiveData(USART2);
           my_buffer[buffer_index] = c;
           buffer_index++;

           if (buffer_index == my_buffer_size || c == '\r') {
               if (strnstr(my_buffer, "on\r", 3)) {
                   send_string("Power on onboard LED.\r\n");
                   GPIO_SetBits(GPIOA, GPIO_Pin_5);
               }
               else if (strnstr(my_buffer, "off\r", 4)) {
                   send_string("Power off onboard LED.\r\n");
                   GPIO_ResetBits(GPIOA, GPIO_Pin_5);
               }
               else
               {
                   send_string("Not recognized command.\r\n");
               }
               memset(my_buffer, 0, my_buffer_size);
               buffer_index = 0;
           }

/*            switch (c) {
           case 'b':
               send_string("Odebrano komunikat B!\r\n");
               GPIO_SetBits(GPIOA, GPIO_Pin_5); //set bit
               break;
           case 'a':
               send_string("Odebrano komunikat A!\r\n");
               GPIO_ResetBits(GPIOA, GPIO_Pin_5); //reset bit
               break;
           default:
               send_string("Nieznany komunikat!\r\n");
               break;
           }*/
       }
   }
}

Czy o to chodziło? Reaguje faktycznie tylko na 'on\r' i 'off\r' jak nie mają żadnych śmieci po drodze. Implementacja strnstr nie moja, tylko jakiś GPL z githuba.

Udostępnij ten post


Link to post
Share on other sites

I to jest świetny przykład dlaczego nie zawsze można brać pierwszy lepszy przykład z sieci. Zobacz komentarz w kodzie:

  /* segfault here if needle is not NULL terminated */ 

Przecież to jest dokładnie to co poprzednio, tylko bardziej skomplikowane. Jeśli napis nie będzie zakończony zerem (NULL), to program się wyłoży - na stm32 nie będzie segfault, ale różne dziwne rzeczy mogą się dziać.

Teraz program chyba w ogóle nie zadziała. Windows wysyła 2 znaki końca linii: \r\n, więc po pierwszym poleceniu, będzie miał zawsze \n na początku kolejnych linii. Chyba nie o to chodziło.

Jeśli komunikacja będzie z unixa (np. linuxa), to koniec linii jest \n, więc też nie zadziała.

Skoro szukasz napisu o dokładnie zadanej treści, to zamiast strstr, możesz użyć strcmp(), albo lepiej strncmp().

Udostępnij ten post


Link to post
Share on other sites

Dołącz do dyskusji, napisz odpowiedź!

Jeśli masz już konto to zaloguj się teraz, aby opublikować wiadomość jako Ty. Możesz też napisać teraz i zarejestrować się później.
Uwaga: wgrywanie zdjęć i załączników dostępne jest po zalogowaniu!

Anonim
Dołącz do dyskusji! Kliknij i zacznij pisać...

×   Wklejony jako tekst z formatowaniem.   Przywróć formatowanie

  Dozwolonych jest tylko 75 emoji.

×   Twój link będzie automatycznie osadzony.   Wyświetlać jako link

×   Twoja poprzednia zawartość została przywrócona.   Wyczyść edytor

×   Nie możesz wkleić zdjęć bezpośrednio. Prześlij lub wstaw obrazy z adresu URL.


×
×
  • Utwórz nowe...