Elvis Listopad 1, 2015 Udostępnij Listopad 1, 2015 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ą. Cytuj Link do komentarza Share on other sites More sharing options...
simoon87 Listopad 1, 2015 Udostępnij Listopad 1, 2015 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 Cytuj Link do komentarza Share on other sites More sharing options...
Elvis Listopad 1, 2015 Udostępnij Listopad 1, 2015 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; } 1 Cytuj Link do komentarza Share on other sites More sharing options...
simoon87 Listopad 1, 2015 Udostępnij Listopad 1, 2015 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. Cytuj Link do komentarza Share on other sites More sharing options...
Polecacz 101 Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Zarejestruj się lub zaloguj, aby ukryć tę reklamę. Produkcja i montaż PCB - wybierz sprawdzone PCBWay! • Darmowe płytki dla studentów i projektów non-profit • Tylko 5$ za 10 prototypów PCB w 24 godziny • Usługa projektowania PCB na zlecenie • Montaż PCB od 30$ + bezpłatna dostawa i szablony • Darmowe narzędzie do podglądu plików Gerber Zobacz również » Film z fabryki PCBWay
Elvis Listopad 1, 2015 Udostępnij Listopad 1, 2015 A próbowałeś uruchomić program który wkleiłem? Czy też nie chce działać? Cytuj Link do komentarza Share on other sites More sharing options...
simoon87 Listopad 1, 2015 Udostępnij Listopad 1, 2015 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. Cytuj Link do komentarza Share on other sites More sharing options...
Elvis Listopad 1, 2015 Udostępnij Listopad 1, 2015 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. Cytuj Link do komentarza Share on other sites More sharing options...
simoon87 Listopad 2, 2015 Udostępnij Listopad 2, 2015 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 Cytuj Link do komentarza Share on other sites More sharing options...
Elvis Listopad 2, 2015 Udostępnij Listopad 2, 2015 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. 2 Cytuj Link do komentarza Share on other sites More sharing options...
simoon87 Listopad 2, 2015 Udostępnij Listopad 2, 2015 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 Cytuj Link do komentarza Share on other sites More sharing options...
Dżimmi Listopad 7, 2015 Udostępnij Listopad 7, 2015 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? Cytuj Link do komentarza Share on other sites More sharing options...
Czopopo Listopad 11, 2015 Udostępnij Listopad 11, 2015 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? Cytuj Link do komentarza Share on other sites More sharing options...
Elvis Listopad 12, 2015 Udostępnij Listopad 12, 2015 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. 1 Cytuj Link do komentarza Share on other sites More sharing options...
Czopopo Listopad 12, 2015 Udostępnij Listopad 12, 2015 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. Cytuj Link do komentarza Share on other sites More sharing options...
Elvis Listopad 12, 2015 Udostępnij Listopad 12, 2015 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(). Cytuj Link do komentarza Share on other sites More sharing options...
Pomocna odpowiedź
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!