Skocz do zawartości

[C] STM32f3 Discovery - Problem z ADC


ms.brigittte

Pomocna odpowiedź

Witam,

Zrobiłam projekt zgodnie z kursem

https://forbot.pl/blog/artykuly/programowanie/kurs-stm32-6-pomiar-napiecia-przetwornik-adc-id8462

na moim stm32f3discovery. Wszystko pięknie działa, ale jest pewien problem z funkcją:

int ADC_read(int channel)

{

ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_7Cycles5);

ADC_Cmd(ADC1,ENABLE);

while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));

return ADC_GetConversionValue(ADC1);

}

Ponieważ co kilka cykli (czasem po trzech, czasem po 20kilku) program zapętla się w while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); i przestaje wysyłać dane. Czy jest jakiś sposób na usunięcie błędu? 🙂

__________

Komentarz dodany przez: Treker

Kod programów, dla lepszej czytelności, należy umieszczać w tagach .

Popraw to proszę 🙂

Link do komentarza
Share on other sites

Programy pisane na potrzeby kursu były maksymalnie uproszczone. W "prawdziwym" programie bardzo niebezpieczne jest używanie pętli while, które mogą czekać w nieskończoność. Znacznie lepszym rozwiązaniem jest dodanie pewnego timeout-u, lub chociaż licznika pętli i przerywanie oczekiwania po pewnym czasie.

Jednak taka zmiana nie wyeliminowałaby przyczyny problemu, tylko "załagodziła" skutki.

W programie brakuje uruchomienia konwersji, czyli wywołania ADC_SoftwareStartConvCmd.

Link do komentarza
Share on other sites

Wystarczy się dowiedzieć ile "powinna" trwać konwersja. Na to są oczywiście różne metody, m.in:

* losowa - wpisać coś co nam przyjdzie do głowy, jeśli działa pogratulować sobie sukcesu (bardzo popularne rozwiązanie)

* ostrożna - dać najdłuższy timeout jaki możemy, np. 10s. Na pewno wystarczy

* naukowa - wiedząc jaka jest częstotliwość taktowania przetwornika oraz ile cykli zajmuje konwersja, można policzyć ile czasu zajmuje konwersja

* empiryczna - podłączyć oscyloskop, analizator stanów logicznych lub inne tajemne urządzenie i pomierzyć ile faktycznie czasu zajmuje dany fragment programu

* googlowa - wyszukać przykład w internecie i przepisać (bardzo ostrożni mogą sprawdzić, czy przepisany kod działa)

* na autorytet - odmiana metody googlowania - zapytać kogoś mądrego i bez refleksji zastosować

Pewnie jeszcze sporo metod się znajdzie.

Ja radziłbym jednak zacząć od ustalenia przyczyny problemu - pewnie coś jest z programem źle skoro nie wychodzi z pętli. Timout-y są bardzo ważne w profesjonalnych programach. Podczas nauki ich zastosowanie może mieć poważną wadę. Zamiast szukać przyczyny problemu, będziemy zadowoleni, że przecież działa (najwyżej co drugi raz, ale działa).

  • Lubię! 2
Link do komentarza
Share on other sites

Zarejestruj się lub zaloguj, aby ukryć tę reklamę.
Zarejestruj się lub zaloguj, aby ukryć tę reklamę.

jlcpcb.jpg

jlcpcb.jpg

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

Poniżej zamieszczam pełny kod programu, bo pomimo przeszukania go dokładnie nie znalazłam błędu, będę wdzięczna za wszelkie sugestie. Dodam tylko, że inicjalizację ADC zrobiłam analogiczną do tej ze strony producenta, kiedy używam tylko jednego kanału wszystko działa idealnie.

#include"stm32f30x.h"
#include"stm32f30x_gpio.h"
#include"stm32f30x_rcc.h"
#include"stm32f30x_usart.h"
#include"stm32f30x_misc.h"
#include"stm32f30x_adc.h"

__IO uint16_t ADC1ConvertedValue = 0, ADC1ConvertedVoltage1 = 0; ADC1ConvertedVoltage2 = 0;
__IO uint16_t ADC1ConvertedVoltage3 = 0;ADC1ConvertedVoltage4 = 0;
__IO uint16_t calibration_value = 0, ADC1ConvertedTemp=0;
__IO uint32_t TimingDelay = 0;

void GPIO_init(void);
void usart_init(void);
void ADC_init(void);
void usart_num(int);
void usart_float(float);
int ADC_read(int);
void USART_puts(USART_TypeDef* USARTx,char *str)
{
while(*str)
{
	while(USART_GetFlagStatus(USARTx,USART_FLAG_TC)==RESET);
	USART_SendData(USARTx,*str);
	*str++;

}
}

int main(void)
{
usart_init();
GPIO_init();
ADC_init();
int k;
int i=0;
char data;

while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_RDY));

USART_puts(USART1,"ok");

while (1)
{
	ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
	ADC1ConvertedValue=ADC_read(ADC_Channel_6);
	ADC1ConvertedVoltage1=(ADC1ConvertedValue *3300)/0xFFF;

	ADC1ConvertedValue=ADC_read(ADC_Channel_7);
	ADC1ConvertedVoltage2=(ADC1ConvertedValue *3300)/0xFFF;

	ADC1ConvertedValue=ADC_read(ADC_Channel_8);
	ADC1ConvertedVoltage3=(ADC1ConvertedValue *3300)/0xFFF;

	ADC1ConvertedValue=ADC_read(ADC_Channel_9);
	ADC1ConvertedVoltage4=(ADC1ConvertedValue *3300)/0xFFF;

	usart_num(ADC1ConvertedVoltage1);
	usart_num(ADC1ConvertedVoltage2);
	usart_num(ADC1ConvertedVoltage3);
	usart_num(ADC1ConvertedVoltage4);

	USART_puts(USART1,"\n\r");
	for(k=0;k<10000000;k++);

}
}

void GPIO_init(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
GPIO_InitTypeDef GPIO_InitStructure1;
GPIO_InitStructure1.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStructure1.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure1.GPIO_PuPd = GPIO_PuPd_NOPULL ;
GPIO_Init(GPIOC, &GPIO_InitStructure1);
}

void usart_init(void)
{
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure2;
GPIO_InitStructure2.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5;
GPIO_InitStructure2.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure2.GPIO_OType=GPIO_OType_PP;
GPIO_InitStructure2.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_InitStructure2.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC,&GPIO_InitStructure2);

GPIO_PinAFConfig(GPIOC,GPIO_PinSource4, GPIO_AF_7);
GPIO_PinAFConfig(GPIOC,GPIO_PinSource5, GPIO_AF_7);

RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

USART_InitTypeDef USART_InitStructure;

USART_InitStructure.USART_BaudRate=9600;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity= USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART1,&USART_InitStructure);
USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);
USART_Cmd(USART1,ENABLE);

}

void usart_num(signed int liczba)
{
int i, length=0,znak=0;
char liczba_str[10] = {0};
if( liczba < 0 )
{
	znak = 1;
	liczba = - liczba;
}

for( i = 1; (i <= liczba) && (length <= 10); i*=10 )
{
	if( (liczba/i) > 0 )
		length++;
}
if(length == 0)
	length = 1;
i = 1;

while(length)
{
	liczba_str[length-1]=liczba%(10*i)/i+48;
	length--;
	i*= 10;
}
if(znak)
	USART_puts(USART1,"-");
else
	USART_puts(USART1," ");
USART_puts(USART1, liczba_str );
}

void ADC_init(void)
{
  RCC_ADCCLKConfig(RCC_ADC12PLLCLK_Div2);
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_ADC12, ENABLE);

  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  ADC_CommonInitStructure.ADC_Clock = ADC_Clock_AsynClkMode;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  ADC_CommonInitStructure.ADC_DMAMode = ADC_DMAMode_OneShot;
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;
  ADC_CommonInit(ADC1, &ADC_CommonInitStructure);

  ADC_InitTypeDef       ADC_InitStructure;
  ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable;
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  ADC_InitStructure.ADC_ExternalTrigConvEvent = ADC_ExternalTrigConvEvent_0;
  ADC_InitStructure.ADC_ExternalTrigEventEdge = ADC_ExternalTrigEventEdge_None;
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  ADC_InitStructure.ADC_OverrunMode = ADC_OverrunMode_Disable;
  ADC_InitStructure.ADC_AutoInjMode = ADC_AutoInjec_Disable;
  ADC_InitStructure.ADC_NbrOfRegChannel = 1;
  ADC_Init(ADC1, &ADC_InitStructure);

  ADC_StructInit(&ADC_InitStructure);
  ADC_VoltageRegulatorCmd(ADC1, ENABLE);
  ADC_SelectCalibrationMode(ADC1, ADC_CalibrationMode_Single);
  ADC_StartCalibration(ADC1);
  while(ADC_GetCalibrationStatus(ADC1) != RESET );
  calibration_value = ADC_GetCalibrationValue(ADC1);

 // ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 1, ADC_SampleTime_7Cycles5);
  ADC_Cmd(ADC1, ENABLE);
}

int ADC_read(int channel)
{
int l=0;

ADC_RegularChannelConfig(ADC1, channel, 1, ADC_SampleTime_7Cycles5);
ADC_StartConversion(ADC1);
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != SET);
return ADC_GetConversionValue(ADC1);
}
Link do komentarza
Share on other sites

Ja niestety nie znam STM32F303, ale proponowałbym "przerobić" przykłady dołączone do płytki. http://www.st.com/web/catalog/tools/FM116/SC959/SS1532/PF254044

Zakładam, że to co dostarcza ST działa - wtedy można porównać oba programy i powinno pomóc.

Tym co wydaje mi się "podejrzane" jest taktowanie przetwornika analogowego-cyfrowego, ale najlepiej zacząć od działającego programu i przerabiać aż przestanie działać 😉

[ Dodano: 16-01-2016, 20:20 ]

Mała podpowiedź, co na pewno jest źle - używasz trybu continous:

ADC_InitStructure.ADC_ContinuousConvMode = ADC_ContinuousConvMode_Enable; 

To niby nic złego, ale musisz pamietać, że kiedy trwa konwersja, nie wolno zmieniać konfiguracji układu - a Ty wywołujesz ADC_RegularChannelConfig.

Ta funkcja odwołuje się do rejestru SQR1, o którym w dokumentacji możemy przeczytać:

"Note: Software is allowed to write these bits only when ADSTART=0 (which ensures that no regular conversion is ongoing)."

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!

Gość
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.