ms.brigittte Napisano Styczeń 16, 2016 Udostępnij Napisano Styczeń 16, 2016 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 More sharing options...
Elvis Styczeń 16, 2016 Udostępnij Styczeń 16, 2016 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 More sharing options...
ms.brigittte Styczeń 16, 2016 Autor tematu Udostępnij Styczeń 16, 2016 w jaki sposób dobrać czas trwania timeoutu? Link do komentarza Share on other sites More sharing options...
Elvis Styczeń 16, 2016 Udostępnij Styczeń 16, 2016 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). 2 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
ms.brigittte Styczeń 16, 2016 Autor tematu Udostępnij Styczeń 16, 2016 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 More sharing options...
Elvis Styczeń 16, 2016 Udostępnij Styczeń 16, 2016 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 More sharing options...
Pomocna odpowiedź
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ę »