Skocz do zawartości

Kurs STM32 - #5 - Komunikacja z komputerem, UART


Pomocna odpowiedź

Witam,
mam problem z moją płytką NUCLEO. Wykonuję kurs i na temacie komunikacja przez UART lub pomiar napięcia ADC, wszystko wykonuję tak jak jest w instrukcjach, łącze sie z Real Term albo Tera Term ale nic nie widze, nic nie jest wysyłane. Całą konfigurację robie dokładnie jak jest opisane, łącznie z konfiguracją w wyżej wymienionych programach. Nie wiem co się dzieje.

kacpus123, witam na forum 🙂 Czy korzystasz z dokładnie takiej samej płytki jak jest używana w kursie? Pytam, bo nie widzę zarejestrowanego zestawu na Twój adres. Czy port COM jest widoczny w systemie bez problemu?

Witam panowie, niestety straciłem już siłę do zadania domowego. 🙁 Dlaczego program nie wchodzi w obsługę przerwania? Komunikacja z komputerem jest ok, funkcje przykładowe z main działają. Sprawdziłem debugerem że program w ogóle nie wchodzi w przerwanie. Gdzie popełniam błąd?

#include "stm32f10x.h"



void USART2_IRQHandler(void)
{
if(USART_GetFlagStatus(USART2, USART_FLAG_RXNE)!= RESET)
{
	char c = USART_ReceiveData(USART2);

	switch(c)
	{	case 'a':

			if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_4))
				GPIO_ResetBits(GPIOA, GPIO_Pin_4);
			else
				GPIO_SetBits(GPIOA,GPIO_Pin_4);

		break;

			case 'b':

			if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5))
				GPIO_ResetBits(GPIOA, GPIO_Pin_5);
			else
				GPIO_SetBits(GPIOA,GPIO_Pin_5);
			break;


		case 'c':

			if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_6))
				GPIO_ResetBits(GPIOA, GPIO_Pin_6);
			else
				GPIO_SetBits(GPIOA,GPIO_Pin_6);

			break;


		case 'd':

			if(GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_7))
				GPIO_ResetBits(GPIOA, GPIO_Pin_7);
			else
				GPIO_SetBits(GPIOA,GPIO_Pin_7);
			break;


   }

}
USART_ClearITPendingBit(USART2, USART_FLAG_RXNE);
}




void wyslijznak(char z)
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2, z);

}

void wyslijslowo(const char* s)
{
   while (*s)
	{
		wyslijznak(*s++);
	}
}


int main(void)
{ 
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);

GPIO_InitTypeDef port;
USART_InitTypeDef uart;
NVIC_InitTypeDef przerwanie;


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

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

port.GPIO_Pin= GPIO_Pin_4 | GPIO_Pin_5 |GPIO_Pin_6 |GPIO_Pin_7 ;
port.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_Init(GPIOA,&port);







USART_StructInit(&uart);
uart.USART_BaudRate = 9600;
uart.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &uart);

USART_Cmd(USART2, ENABLE);


przerwanie.NVIC_IRQChannel = USART2_IRQn;
przerwanie.NVIC_IRQChannelPreemptionPriority = 0;
przerwanie.NVIC_IRQChannelSubPriority = 0;
przerwanie.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&przerwanie);

wyslijslowo("Hello");
while(1)
{ if (USART_GetFlagStatus(USART2, USART_FLAG_RXNE)) 
    {
		 char c = USART_ReceiveData(USART2);
    switch (c)
    {
        case 'a':
            wyslijslowo("Odebrano komunikat A!\r\n");
            break;
        case 'b':
            wyslijslowo("Odebrano komunikat B!\r\n");
            break;
        default:
            wyslijslowo("Nieznany komunikat:(\r\n");
            break;

	 }


 }
}
}

Co wywołuje to "globalne przerwanie USART2"? Wydaje mi się że pojawienie się bitu startu na Rx kontrolera, a może się mylę?

dzami97, czy przypadkiem nie brakuje Ci jeszcze czegoś w rodzaju "USART_ITConfig(USART2, USART_IT_RXNE, ENABLE)" przy konfiguracji przerwania?

  • 1 miesiąc później...

Witam,
dostałem od kolegi taki zestaw i próbuje odebrać dane z mikro kontrolera przez USB(STMicroelectronics STLink Virtual COM Port), lecz nic nie otrzymuje. Po podłączeniu konwerter na pinach PA2 i PA3 dane przychodzą. Już drugi tydzień kombinuje z tym, bo ciekawi mnie czemu, to nie działa :/. Działam na systemie Win 10 i wykonałem wszystkie aktualizacje dla sterowników mikro kontrolera.

  • 3 tygodnie później...

Witam,

Ktoś może wie dlaczego strcmp nie działa? Czy jest jakaś możliwość że Tera Term wysyła mi jakieś dziwne rzeczy i dlatego compare nie działa?

	int bufferSize = 0;
char commandBuffer[3];

while (1)
{
	if (USART_GetFlagStatus(USART2, USART_FLAG_RXNE)) {
		commandBuffer[bufferSize] = USART_ReceiveData(USART2);
		bufferSize++;
	}
	if (bufferSize >= 3) {
		if (strcmp(commandBuffer, "L1T") == 0)
			GPIO_SetBits(GPIOB, LED_1);
		else if (strcmp(commandBuffer, "L1O") == 0)
			GPIO_ResetBits(GPIOB, LED_2);
		bufferSize = 0;
	}
}
  • 2 tygodnie później...

Problemy początkującego:

Próbuje komunikować się z mikrokontrolerem za pomocą USB. Powinienem widzieć wirtualny port w menedzerze urządzeń po COM&LPT ports. Niestety nic takiego nie mam. Efekt jest taki, że nie mogę połączyć się choćby z Tera Term VT i wymieniać danych między płytką a PCtem. Dodam, że wcześniejsze próby z mryganiem diodą na płytce zakończyły się sukcesem.

Dla testu podłączyłem Arduino Nano i po podłączeniu pokazuje się port COM.

kleszcz, czy zainstalowałeś sterowniki do płytki Nucleo (pobrane ze strony producenta) przed podłączeniem jej do komputera?

  • 4 tygodnie później...

Witam,

Skopiowałem pierwszy program odnośnie transmisji UART do płytki Nucleo (wysyłanie napisu Hello) a w terminalu otrzymuje komunikat "Cannot open port COM5.NOt found.".

Dodam ,że wszystkie poprzednie programy z tego kursu działają bez problemu.

Prosze o rade co może powodować taki bład . Dodam , ze terminal widzi nucleo.

PS. dlaczego w programie nie dodano takich komend ?

uart.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
uart.USART_Mode=USART_Mode_Tx;
uart.USART_Parity=USART_Parity_No;
uart.USART_WordLength=USART_WordLength_8b;
uart.USART_StopBits=USART_StopBits_1;

[ Dodano: 20-04-2018, 16:30 ]

Już to naprawiłem, musiałem zmienić wersje z 32 na 64 - bitową środowiska.

  • Lubię! 1
  • 4 miesiące później...
(edytowany)

Cześć ! 

W programie obsługi interfejsu USART dla kursu stm32 zamieszczony jest następujący kod :

#include "stm32f10x.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_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_GPIOD, ENABLE);
 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
 RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
 
 GPIO_StructInit(&gpio);
 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);
 
 USART_StructInit(&uart);
 uart.USART_BaudRate = 115200;
 USART_Init(USART2, &uart);
 
 USART_Cmd(USART2, ENABLE);
 
 char tab[12] = {':', '8', '8', '8', '8', '0', '9', '0', '0', '8','\r', '\n'}; //dziwny znak na poczatku widoczny w TeraTerm
 char tab2[13] = {':', '8', '8', '8', '8', '0', '9', '0', '0', '8','\r', '\n','\0'}; //OK
 char tab3[13] = {':', '8', '8', '8', '8', '0', '9', '0', '0', '8','\r', '\n'}; //OK
  
 while (1) {
 //send_string("Hello world!\r\n");
   send_string(&tab[0]);
 }
}

To co wyświetlane jest w Terminalu TeraTerm jest następujące :

znaki.png

I teraz pytanie dlaczego wyświetla taki dziwny znak na początku ciągu znakowego, jak to wyeliminować ? Nie zawszę będziemy wpisywać do funkcji 

send_string("ciag znakow.....r\n"); 

Chciałoby się mieć też możliwość podania adresu wskazującego na pierwszy element tablicy znakowej jak zrealizowano to w 

send_string_BT(&tab[0]);

I teraz najważniejsze pytanie, czy jeśli chcę pozbyć się dziwnego znaku na początku to muszę zwiększyć tablice znakową o miejsce na wartość NULL i czy po stronie odbiorcy liczba bajtów będzie równa : liczba znaków w tablicy + znak \0 (NULL) ????? 

co dla tab[12] daje : 12bajtów + 1bajt(NULL) = 13 bajtów ???

Bardzo proszę o pomoc w wyjaśnieniu tej kwestii 🙂

Edytowano przez simba92

Znak nie jest wyświetlany na początku, a na końcu poprzedniego komunikatu.

Po prostu języki C/C++ nic nie wiedzą o rozmiarach tablic, w tym przypadku traktują je po prostu jako ciąg bajtów umieszczonych w pamięci, a wszelkiego typu napisy muszą kończyć się znakiem \0.

Tutaj w przypadku tablicy tab funkcja send_string po prostu nie wie gdzie ma skończyć wysyłanie, i lezie poza tablicę wysyłając śmiecie aż napotka przypadkowe zero.

Czyli tak - trzeba przewidzieć miejsce na dodatkowy znak.

Po stronie odbiorcy to już zależy od programu.

Tak przy okazji - znak o kodzie zero to NUL (przez jedno L), NULL to pusty wskaźnik.

  • Lubię! 1
  • Pomogłeś! 1
  • 2 miesiące później...

Cześć! 🙂

Dlaczego wyjście sygnału UART ustawiamy w trybie alternatywnym push-pull, a wejście w trybie floating? Czym się kierować podczas samodzielnego konfigurowania?

Z góry dzięki! 🙂

 

Bo obowiązuje zasada, że każdy kabelek, każdy sygnał musi mieć swojego "drivera" czyli układ sterujący, który zadaje tam jakiś stan logiczny. Za to odbierać może taki sygnał wiele odbiorników / wejść. Tak więc jeśli wysyłasz informacje z procesora (np. linia TXD UARTa) to muszisz sprawić, by ten pin był wyjściem - to on będzie zadawał napięcie w tym drucie i przesyłał je do oddalonego odbiornika, do jego wejścia RXD. W przypadku gdy chcesz wprowadzać inofrmacje do procesora (pin RXD) to ktoś inny musi tym kabelkiem sterować (podłączyć tam swoje TXD) a Ty musisz być wejściem. Stąd kierunki "wyjście " i "wejście".

Powinieneś kierować się przeznaczeniem linii. Z czystymi wejściami i wyjściami jak rozumiem nie będziesz miał już problemów. Wiadomo, że diodka LED czy tranzystor sterujacy przekaźnikiem potrzebuje wyjścia, a przycisk czy jakiś czujnik musi być podłączony do wejścia. Pewnym niuansem są typy szczegółowe, dostępne w niektórych procesorach np. floating, pull-up, pull-down czy schmitt (wejścia) albo open-collector, open-emitter czy hi-z/bidirectional (wyjścia), ale to spróbuj wyszukać. Te konfiguracje umożliwiają pewne ciekawe tryby i są używane w przypadkach gdy np. kilku "konkurentów" ubiega się o sterowanie tą samą linią lub też z powodów konstrukcyjnych nie możesz (lub nie chcesz) zapewnić ciągłego sterowania jednym "driverem". Gdyby ktoś odpiął wtyczkę z odległym, bliźniaczym UARTem od Twojego porcesora, to wyjściu TXD to nie zaszkodzi - zawsze może nadawać "w pustkę", ale wejście RXD przestanie być sterowane i zacznie odbierać zakłócenia z powietrza. Jeśłi Twój program ma odpalać np. rakietę, to pewnie nie chciałbyś żeby wystartowała z powodu poluzowania się głupiego złącza. Wtedy możesz zabezpieczyć się wybraniem typu wejścia "pull-up", który bez sygnału podciąga linię do stanu wysokiego, co dla UARTa oznacza "nic się nie dzieje".

  • Lubię! 1
  • Pomogłeś! 1

Bądź aktywny - zaloguj się lub utwórz konto!

Tylko zarejestrowani użytkownicy mogą komentować zawartość tej strony

Utwórz konto w ~20 sekund!

Zarejestruj nowe konto, to proste!

Zarejestruj się »

Zaloguj się

Posiadasz własne konto? Użyj go!

Zaloguj się »
×
×
  • Utwórz nowe...