Skocz do zawartości

[C] Przetwornik ADC w połączeniu z USART na STM32F411RE


pirx1988

Pomocna odpowiedź

Witam,

napisałem sobie kod z wykorzystaniem bibliotek STM32 peripheral, w którym robię pomiar na potencjometrze za pomocą przetwornika ADC. Po zakończeniu każdego pomiaru mikrokontroler wchodzi w przerwanie, w którym chcę przesyłać wynik pomiaru na PC za pomocą USART. Niestety coś idzie nie tak, gdyż program wysyła co najwyżej 2 pomiary i potem się zawiesza. Kod zaimplementowałem na płytce NUCLEO-F411RE z mikrokontrolerem STM32F411RE.

Niżej przedstawiam kod mojego programu:

#include "stm32f4xx.h"
void send_char(char c)
{
while (USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2, c);
}

int __io_putchar(int c)
{
  if (c=='\n')
send_char('\r');

send_char(c);
return c;
}

void ADC_IRQHandler() {

  ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
     uint16_t conv_result;
     conv_result = ADC_GetConversionValue(ADC1);
     printf("Adc = %d V_conv = %f\n",conv_result,conv_result * 3.3f / 4096.0f);

}
int main(void)
{

// podłączenie zegara taktującego na przetwornik ADC
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
// zegar dla UART
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
// zegar dla portu A
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);


USART_InitTypeDef uart;
GPIO_InitTypeDef gpio;
GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2);
GPIO_StructInit(&gpio);
gpio.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
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(GPIOA, &gpio);
gpio.GPIO_Pin = GPIO_Pin_0;
gpio.GPIO_Mode = GPIO_Mode_AN;
gpio.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &gpio);

USART_StructInit(&uart);
uart.USART_BaudRate = 115200;
uart.USART_Mode = USART_Mode_Tx;
uart.USART_Parity = USART_Parity_No;
uart.USART_StopBits = USART_StopBits_1;
uart.USART_WordLength = USART_WordLength_8b;
uart.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Init(USART2, &uart);
USART_Cmd(USART2, ENABLE);

// inicjalizacja przetwornika ADC
ADC_InitTypeDef adc;
// Struktura, która zawiera informacje o wspólnej konfiguracji dla paru przetworników ADC, ale
// na płytce F411RE jest tylko jeden przetwornik
ADC_CommonInitTypeDef ADC_CommonInitStructure;
ADC_StructInit(&adc);
ADC_CommonStructInit(&ADC_CommonInitStructure);
NVIC_InitTypeDef NVIC_InitStructure;


// ustawienie częstotliwości przetwornika na 25 MHZ
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
// wyłączenie DMA
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
// opóźnienie pomiędzy dwoma konwersjami w liczbie cykli
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_16Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
// tryb ciągły działania przetwornika
adc.ADC_ContinuousConvMode = ENABLE;
adc.ADC_ScanConvMode = DISABLE;
adc.ADC_Resolution = ADC_Resolution_12b;
adc.ADC_DataAlign = ADC_DataAlign_Right;
// The total number of channels to be converted in sequence is specified by:
adc.ADC_NbrOfConversion= 1;
adc.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
adc.ADC_ExternalTrigConv = 0;
ADC_Init(ADC1, &adc);

//ADC_RegularChannelConfig(ADC1,ADC_Channel_17,1,ADC_SampleTime_480Cycles);
ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_480Cycles);
// This call enables the end-of-conversion flag after each channel
ADC_EOCOnEachRegularChannelCmd(ADC1, ENABLE);

/* Enable ADC interrupts */
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);

/* Configure NVIC */
NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_Init(&NVIC_InitStructure);
// uruchomienie przetwornika
ADC_Cmd(ADC1,ENABLE);
ADC_TempSensorVrefintCmd(ENABLE);
ADC_SoftwareStartConv(ADC1);
for(;;){

}
}

Przesłanie pomiary w terminalu:

Jak widać przesłane są zaledwie dwa pomiary, później rekacjii nie ma. Jestem pewien co do tego, że przetwornik jest skonfigurowany dobrze i działa w trybie ciągłym(ang. continuous mode). Na potwierdzenie, że tak jest pokazuje poniżej co dostaję, jak zmodyfikuję kod przerwania ADC_IRQHandler() do postaci:

uint16_t conv_buffer[5];
int index = 0;
void ADC_IRQHandler() {

  ADC_ClearITPendingBit(ADC1, ADC_IT_EOC);
     uint16_t conv_result;
     conv_result = ADC_GetConversionValue(ADC1);
     conv_buffer[index] = conv_result;
     index++;
     if(index == 5){

   	  int i;
   	  for(i = 0; i < 5; i++){

   		  printf("Adc = %d V_conv = %f\n",conv_buffer[i],conv_buffer[i] * 3.3f / 4096.0f);

   	  }
   	  index = 0;
     }

}

I wtedy mam 5 przesłanych próbek, jak widać w terminalu poniżej:

Stąd wyciągnąłem wniosek, że przetwornik ADC działa dobrze, tylko wszystko się zawiesza przy wysyłaniu przez USART. Nie wiem jak to rozwiązać, brakuję mi już pomysłów.

Obecnie wydaje mi się, że może zanim informacja się prześlę, to przetwornik kończy pomiar i chcę wejść znowu w przerwanie i wszystko wysiada? Nie wiem. Próbowałem też kombinować z ustawieniem sprzętowej kontroli przepływu(ang. hardware flow control), ale nic to nie zmieniło.

Gdyby ktoś mógł mi pomóc, miałby jakiś pomysł co tu może być nie tak, to byłbym bardzo wdzięczny.

Pozdrawiam 🙂

Link do komentarza
Share on other sites

Jedną z zasad stosowanych w oprogramowaniu do systemów wbudowanych jest realizacja przerwań możliwie najszybciej. Wysyłanie danych przez port szeregowy w przerwaniu na pewno nie jest dobrym pomysłem.

Najprawdopodobniej Twoje przerwanie trwa tak długo, że kolejne jest zgłoszone jeszcze w trakcie trwania poprzedniego. Podejrzewałbym, że pojawia się jakieś przerwanie, dla którego nie masz napisanego handlera, więc wykonywany jest domyślnych handler w postaci while(1);

Wykorzystaj debugger do sprawdzenia jaki jest przebieg działania kodu.

Link do komentarza
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...

Ważne informacje

Ta strona używa ciasteczek (cookies), dzięki którym może działać lepiej. Więcej na ten temat znajdziesz w Polityce Prywatności.