Skocz do zawartości

Chev

Użytkownicy
  • Zawartość

    17
  • Rejestracja

  • Ostatnio

Wszystko napisane przez Chev

  1. Dzień dobry, Zmagam się z następującym problemem. Potrzebuję ustawić czas jednego bitu Timera4 w stm8s003f3 na 1 uS. Robiąc to w sposób standardowy, a mianowicie: 1. Ustawiając preskaler HSI oraz CPU na DIV = 1 (czyli korzystam z 16 MHz) void clock_setup(void) { ////////////////////////////// Configure Quartz Clock CLK_DeInit(); CLK_LSICmd(ENABLE); CLK_HSICmd(ENABLE); //CLK_ClockSwitchCmd(ENABLE); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1); CLK_PeripheralClockConfig (CLK_PERIPHERAL_TIMER2 , ENABLE); CLK_PeripheralClockConfig (CLK_PERIPHERAL_TIMER4 , ENABLE); // while(CLK_GetFlagStatus(CLK_FLAG_LSIRDY) == FALSE); // CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE); } 2. Inicjalizuję TIMER4: preskaler ustawiam na f/16, czyli wychodzi mi 1 MHz, co daje mi już 1 uS. void TIMER4_setup(void) { TIM4_DeInit(); TIM4_TimeBaseInit(TIM4_PRESCALER_16, 0x01); // 1 uS TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE); TIM4_Cmd(ENABLE); } 3. Zezwalam na przerwania void interrupt_setup(void) { //EXTI_DeInit(); //EXTI_SetExtIntSensitivity(EXTI_PORT_GPIOB, EXTI_SENSITIVITY_RISE_FALL); enableInterrupts(); } 4. W przerwaniu Timera4 zeruję flagę przepełnienia: TIM4_ClearITPendingBit(TIM4_IT_UPDATE); Efekty jakie doświadczam to resetowanie się układu przez wewnętrznego IWDG, a po jego wyłączeniu zakleszczenie się w jakimś miejscu. Po chwili debugowania okazuje się, że po wzięciu w komentarz enableInterrupts(); lub inicjalizacji timera4 wszystko działa elegancko. Co lepsze, po ustawieniu wartości zliczającej przez timer4 z 0x01 na 0x05 wszystko zaczyna działać prawidłowo. W czym leży problem? Niezależnie jaki Timer użyję (1/2/4) to zawsze jest taki sam problem. Bardzo proszę o sugestię, co tu może być nie tak, bo szczerze ja zgłupiałem.
  2. Poradziłem sobie już w ten sposób, że zastosowałem prostownik jednopołówkowy, dzielnik napięcia, by uzyskać napięcie 1,2V na transoptorze oraz prąd 5 mA bodajże. Do tego elektrolit na wejście 220uF + ceramik 100 nF jako filtracja. Na wyjściu w torze kolektora transoptora rezystor 10k, dczytuje sobie stan zbocza na porcie i wszystko działa jak należy.
  3. Jeśli pytasz o środowisko to jest to darmowa wersja IAR EW for STM8 3.11.1. Jest ograniczenie zapisu do 8kB, ale licencja jest nielimitowana, darmowa. Mi osobiście to wystarcza na tą chwilę. Kiedyś pokombinuje jak to przerobić na Eclipsa, bo widziałem, ze się da.
  4. Przy przekaźniku jest dioda. Problem był prozaiczny. Brak kondensatora 100 nF przy wejściu NRST powodował czasami falowanie napięcia, co wprowadzało reset. Dobry zwyczajem jest podwieszać wszystkie, niewykorzystane porty do przeciwnego stanu, aby nie dopuścić do takich dziwnych sytuacji. Widać, lenistwo dało górę. Najważniejsze, że się poprawiło i jest lekcja na przyszłość
  5. Dzień dobry, kontynuując swój projekt, natchnąłem się na dziwną sytuację. Jest to timer, który odmierza czas, który ustawiony jest za pomocą trzech klawiszy (na każdym wybieramy 1). Wszystko działa do momentu rozpoczęcia wykonywania się funkcji start();. Mało tego. Do procedury odliczania czasu do rozpoczęcia pracy (countdown) wszystko gra. Problem pojawia się w linii GPIO_WriteHigh(GPIOC, GPIO_PIN_6);, kiedy wystawiam stan wysoki na porcie. Generalnie wszystko działa i program wykonuje się poprawnie, ale zdarzają się sytuacje, kiedy funkcja dochodzi do tej linii, wystawia stan wysoki i resetuje całą funkcje i zaczyna wykonywać ją od pierwszej instrukcji, od początku. Na porcie PC6 klucz tranzystorowy BC817-40LT1G, z rezystorem 1k na bazie, wysterowuje cewkę przekaźnika 12V, która to załącza układ. W tym przypadku lampę LED 230V. To co zaobserwowałem na oscyloskopie to w momencie pojawienia się tego błędu, pojawia się napięcie na złączu BE napięcie 0,7V przez chwilę, a następie pojawia się szpilka napięcia, zmiany stanu, gdzie normalnie zmiania stanu z wysokiego na niski objawia się łagodnie opadającym zboczem. Dodam jeszcze, że pisząc na kolanie dwie funkcje for zliczające do 1 mln, bez żadnych timerów, zmieniające co stan logiczny tego portu z wysokiego na niski, ten problem nie występuje. Jeszcze dodam, że inicjalizując to wyjście jako: GPIO_Init(GPIOC, GPIO_PIN_6, GPIO_MODE_OUT_PP_HIGH_FAST); // ON/OFF, czyli przypisując mu zegar 16MHz, co jakiś czas podczas tego eksperymentu następowało podwójne kliknięcie przekaźnika, co po zmianie FAST na SLOW (2MHz) już nie następowało. Pytanie jest następujące. W czym leży problem? Zasilanie jest stabilne, dobrze odfiltrowane. Doszukiwałem się w problemu w przerwaniach timera, którego wykorzystuje, ale nie widzę tu błędu. Prośba jest następująca. Czy jest ktoś w stanie zaglądnąć do mojego kodu i stwierdzić, czy jest w nim coś, co może wywoływać ten reset? Nie dzieje się to często, ale jak się to wydarzy to wszystko się wysypuje. //////////////////////////////LIBRARIES #include <stm8s.h> #include <stm8s_it.h> //////////////////////////////PRIVATE DEFINITIONS #define buttonF (GPIO_ReadInputPin(GPIOD, GPIO_PIN_2)) #define button1 (GPIO_ReadInputPin(GPIOB, GPIO_PIN_4)) #define button2 (GPIO_ReadInputPin(GPIOB, GPIO_PIN_5)) #define button3 (GPIO_ReadInputPin(GPIOA, GPIO_PIN_3)) #define contractron (GPIO_ReadInputPin(GPIOC, GPIO_PIN_4)) #define montionSensor (GPIO_ReadInputPin(GPIOC, GPIO_PIN_3)) #define programSelect (GPIO_ReadInputPin(GPIOC, GPIO_PIN_7)) //////////////////////////////CONSTANT OBJECTS volatile const uint8_t timeWorking_1 = 15; // 1 min (60) volatile const uint16_t timeWorking_2 = 15; // 15 min (900) volatile const uint16_t timeWorking_3 = 15; // 30 min (1800) volatile const uint32_t lifeTime = 28800000; // 8000h (28800000) //////////////////////////////TIMERS uint16_t counter = 1; uint16_t timesUp = 0; uint16_t countTimeKeyPress = 0; uint8_t delayToStart = 5; // 30 sek //////////////////////////////EEPROM //DATA TO SAVE //0x4000 - WORKING TIME //0x4001 - REMAINING LIFE TIME uint16_t timeWorking; // 0x4000 uint32_t remainingLifeTime; // 0x4001 //////////////////////////////CONTROL INSTRUCTION AND GLOBAL OBJECTS bool stop = FALSE; bool detectedMontion = FALSE; bool isWorking = FALSE; bool countdown = FALSE; //////////////////////////////FUNCTIONS void beeper_setup(void); void button_setup(void); void clock_setup(void); void EEPROM_setup(void); void GPIO_setup(void); void interrupt_setup(void); void pause(void); void start(void); void stopU(void); void TIMER2_setup(void); void main(void) { GPIO_setup(); EEPROM_setup(); interrupt_setup(); //beeper_setup(); clock_setup(); TIMER2_setup(); start(); // auto start while(TRUE) { // if((isWorking == FALSE) && (countdown == FALSE)) // button_setup(); //else; for(u32 i = 0; i<500000; i++) GPIO_WriteHigh(GPIOC, GPIO_PIN_6); for(u32 j = 0; j<500000; j++) GPIO_WriteLow(GPIOC, GPIO_PIN_6); } } /* while(TRUE) { GPIO_WriteHigh(GPIOD, GPIO_PIN_4); BEEP_Cmd(ENABLE); delay(20000); GPIO_WriteLow(GPIOD, GPIO_PIN_4); BEEP_Cmd(DISABLE); delay(20000); };*/ //GPIO_WriteLow(GPIOD, GPIO_PIN_4); void beeper_setup(void) { BEEP_DeInit(); BEEP_LSICalibrationConfig(128000); BEEP_Init(BEEP_FREQUENCY_1KHZ); } void button_setup(void) { if(button1 == 0) { timeWorking = timeWorking_1; FLASH_EraseByte(0x4000); FLASH_ProgramByte(0x4000, timeWorking); //GPIO_WriteReverse(GPIOD, GPIO_PIN_3); // TEST } else if(button2 == 0) { timeWorking = timeWorking_2; FLASH_EraseByte(0x4000); FLASH_ProgramByte(0x4000, timeWorking); //GPIO_WriteReverse(GPIOD, GPIO_PIN_3); // TEST } else if(button3 == 0) { timeWorking = timeWorking_3; FLASH_EraseByte(0x4000); FLASH_ProgramByte(0x4000, timeWorking); //GPIO_WriteReverse(GPIOD, GPIO_PIN_3); // TEST } else if(buttonF == 0) { while(buttonF == 0){} if(countTimeKeyPress > 200 || countTimeKeyPress < 10000) { start(); countTimeKeyPress = 0; } else if(countTimeKeyPress > 10000) { FLASH_EraseByte(0x4001); remainingLifeTime = FLASH_ReadByte(0x4001); countTimeKeyPress = 0; } else; } } void clock_setup(void) { ////////////////////////////// Configure Quartz Clock CLK_DeInit(); CLK_HSECmd(ENABLE); CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); CLK_PeripheralClockConfig (CLK_PERIPHERAL_TIMER2 , ENABLE); /*CLK_LSICmd(ENABLE); //while(CLK_GetFlagStatus(CLK_FLAG_LSIRDY) == FALSE); CLK_ClockSwitchCmd(ENABLE); CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1); CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSI, DISABLE, CLK_CURRENTCLOCKSTATE_ENABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_SPI, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_I2C, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_ADC, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_UART1, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER1, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER2, DISABLE); CLK_PeripheralClockConfig(CLK_PERIPHERAL_TIMER4, DISABLE);*/ } void EEPROM_setup(void) { FLASH_DeInit(); FLASH_Unlock(FLASH_MEMTYPE_DATA); FLASH_SetProgrammingTime(FLASH_PROGRAMTIME_STANDARD); timeWorking = FLASH_ReadByte(0x4000); remainingLifeTime = FLASH_ReadByte(0x4001); } void GPIO_setup(void) { GPIO_DeInit(GPIOA); GPIO_DeInit(GPIOB); GPIO_DeInit(GPIOC); GPIO_DeInit(GPIOD); //inputs GPIO_Init(GPIOA, GPIO_PIN_3, GPIO_MODE_IN_PU_NO_IT); // button1 GPIO_Init(GPIOB, GPIO_PIN_4, GPIO_MODE_IN_PU_NO_IT); // button2 GPIO_Init(GPIOB, GPIO_PIN_5, GPIO_MODE_IN_PU_NO_IT); // button3 GPIO_Init(GPIOD, GPIO_PIN_2, GPIO_MODE_IN_PU_NO_IT); // button4 GPIO_Init(GPIOC, GPIO_PIN_7, GPIO_MODE_IN_PU_NO_IT); // programSelect GPIO_Init(GPIOC, GPIO_PIN_3, GPIO_MODE_IN_PU_NO_IT); // con GPIO_Init(GPIOC, GPIO_PIN_4, GPIO_MODE_IN_PU_NO_IT); // montion sensor //outputs GPIO_Init(GPIOC, GPIO_PIN_6, GPIO_MODE_OUT_PP_HIGH_SLOW); // ON/OFF GPIO_Init(GPIOD, GPIO_PIN_3, GPIO_MODE_OUT_PP_HIGH_FAST); // LED //GPIO_Init(GPIOD, GPIO_PIN_4, GPIO_MODE_OUT_PP_HIGH_FAST); //BUZZER GPIO_WriteLow(GPIOD, GPIO_PIN_3); GPIO_WriteLow(GPIOC, GPIO_PIN_6); } void interrupt_setup(void) { enableInterrupts(); } void pause(void) { GPIO_WriteLow(GPIOC, GPIO_PIN_6); GPIO_WriteLow(GPIOC, GPIO_PIN_6); isWorking = FALSE; delayToStart = 5; start(); } void start(void) { countdown = TRUE; while(countdown == TRUE) { if(delayToStart == 0) { isWorking = TRUE; GPIO_WriteHigh(GPIOC, GPIO_PIN_6); while(isWorking == TRUE) { if(buttonF == 0) stopU(); else if(timeWorking == timesUp) stopU(); else if(detectedMontion == TRUE) pause(); else; } } else; } } void stopU(void) { GPIO_WriteLow(GPIOC, GPIO_PIN_6); GPIO_WriteLow(GPIOC, GPIO_PIN_6); stop = TRUE; } void TIMER2_setup(void) { TIM2_DeInit(); TIM2_TimeBaseInit(TIM2_PRESCALER_128, 0x7D); // 127 and 0x7D == Interrupt 1 ms TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE); TIM2_Cmd(ENABLE); } void assert_failed(u8* file, u32 line){} =========== INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13) { TIM2_ClearITPendingBit(TIM2_IT_UPDATE); if((isWorking == FALSE) && (countdown == FALSE)) { if(buttonF == 0) { countTimeKeyPress++; TIM2_ClearITPendingBit(TIM2_IT_UPDATE); } else; } if((countdown == TRUE) && (detectedMontion == FALSE)) { if(delayToStart > 0) { counter++; if(counter > 1000) { //GPIO_WriteReverse(GPIOD, GPIO_PIN_3); // TEST counter = 1; delayToStart--; TIM2_ClearITPendingBit(TIM2_IT_UPDATE); } TIM2_ClearITPendingBit(TIM2_IT_UPDATE); } else countdown = FALSE; } if(isWorking == TRUE) { if(timeWorking > timesUp) { counter++; if(counter > 1000) { //GPIO_WriteReverse(GPIOD, GPIO_PIN_3); // TEST counter = 1; timesUp++; remainingLifeTime++; FLASH_EraseByte(0x4001); FLASH_ProgramByte(0x4001, remainingLifeTime); TIM2_ClearITPendingBit(TIM2_IT_UPDATE); } TIM2_ClearITPendingBit(TIM2_IT_UPDATE); } } if((montionSensor == 0) || (contractron == 0)) detectedMontion = TRUE; else detectedMontion = FALSE; if(stop == TRUE) { counter++; if(counter > 1000) { isWorking = FALSE; timesUp = 0; delayToStart = 5; stop = FALSE; TIM2_ClearITPendingBit(TIM2_IT_UPDATE); } TIM2_ClearITPendingBit(TIM2_IT_UPDATE); } else; } Z góry dziękuję za pomoc.
  6. Dziękuję Panom za pomoc. Udało mi się to wykonać w przerwaniu timera jak napisał @rajszym. Daje kod dla przyszłych pokoleń. Mało informacji jest ogólnie o procesorze STM8S. Myślę, że taki przykład się komuś przyda w przyszłości INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13) { if((GPIO_ReadInputPin(GPIOA, GPIO_PIN_3) == 0)) // sprawdzam stan przycisku { timeTIM2++; // jeśli wciśnięty, liczę czas +1ms TIM2_ClearITPendingBit(TIM2_IT_UPDATE); //zeruje flagę przerwania } else //jeśli zmienił się stan interrupt = 1; // ustawiam flagę, o zakończeniu liczenia if(interrupt == 1) { if(timeTIM2 >= 200) // jeśli >200 ms to długi przycisk, zeruje flagę, resetuje timer { GPIO_WriteHigh(GPIOD, GPIO_PIN_3); interrupt = 0; timeTIM2 = 1; } else if((timeTIM2 > 20) && (timeTIM2 < 200)) // krótki przycisk { GPIO_WriteLow(GPIOD, GPIO_PIN_3); interrupt = 0; timeTIM2 = 1; } else; } }
  7. Dzień dobry, Mam problem z pozbyciem się debouncingu na wejściu procesora spowodowanego przez przyciski. Do nogi procesora mam oczywiście dołożony rezystor pull-up 10k oraz kondensator 100nF, równolegle z przyciskiem. Walczę z tym od kilku dni i już nie mam pomysłu dlaczego to nie działa. Problem jest taki: staram się stworzyć softwarową eliminacje debouncingu. W tym celu w przerwaniu przycisku sprawdzam stan przycisku na porcie PA3. Timer TIM2 ustawiony jest na takt 1ms, więc ustawiam sobie w pętli while czas 20ms, aby po tym jeszcze raz sprawdzić stan portu, czy oby na pewno jest niski (takim wyzwalam przycisk). I tu już klapa. Chcąc zapalić sobie diodę po drugim sprawdzeniu stanu przycisku, niestety, ale nie daje to żadnego efektu. Specjalnie jeszcze kupiłem nowy przycisk, aby wyeliminować element sprzętu, ale też nie jest to tego wina. Generalnie celem jest sprawdzenie stanu przyciska czy użytkownik wcisnął przycisk na krótko, czy go przytrzymał i puścił. Byłbym wdzięczny za jakieś wskazówki, bo już naprawdę nie mam pomysłu co zrobić. Wklejam kod, którym chcę to obsłużyć. Inicjalizacji przycisków, zegara itp. nie wklejam, bo to akurat działa poprawnie. INTERRUPT_HANDLER(EXTI_PORTA_IRQHandler, 3) { if(GPIO_ReadInputPin(GPIOA, GPIO_PIN_3) == RESET) { countTimeKeyPress = TRUE; while(timeTIM2 < 10){} if(GPIO_ReadInputPin(GPIOA, GPIO_PIN_3) == RESET) { timeTIM2 = 1; while(GPIO_ReadInputPin(GPIOA, GPIO_PIN_3) == RESET){} if((timeTIM2 > 15) && (timeTIM2 < 100)) { GPIO_WriteHigh(GPIOD, GPIO_PIN_3); countTimeKeyPress = FALSE; timeTIM2 = 1; } else if(timeTIM2 >= 100) { GPIO_WriteLow(GPIOD, GPIO_PIN_3); countTimeKeyPress = FALSE; timeTIM2 = 1; } else; } } } INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13) { if(countTimeKeyPress == TRUE) { if(timeTIM2 > 101) { countTimeKeyPress = FALSE; } else { timeTIM2++; TIM2_ClearITPendingBit(TIM2_IT_UPDATE); } } }
  8. Super. Dziękuję za dobre info! Dopytam jeszcze, bo kto pyta nie błądzi. Powiedzmy, że przerwanie pojawi się, gdy na wejściu pojawi się stan niski. Nogę kolektora w takim przypadku podłączam bezpośrednio do uC bez zasilania, tak jak jest na rysunku, tak?
  9. Masz rację, że wystarczy przekaźnik z cewką 230V, ale dla samej nauki chciałbym to zrobić na transoptorze. Przychodzi mi do głowy rozwiązanie dołożenia drugiej diody równolegle w przeciwnym kierunku. Wtedy przepływ napięcia będzie dwukierunkowy. Rozwiąże to problem?
  10. Dzień dobry. Postanowiłem zbudować układ, który pozwoliłby mi na monitorowanie poziomu sieci 230V. Chcę wykorzystać czujnik ruchu, aby za jego pomocą zaświecać lampę, jak to się po bożemu robi, a przy okazji dodatkowo wysterować inne urządzenie za pomocą mikrokontrolera i przekaźnika. Zbudowałem schemat pokazany na zdjęciu. Zasada działania jest taka: Zasilam układ i czujnik ruchu z napięcia 230V. W momencie załączenia się czujnika ruchu, przekaźnik w nim zostaje zwarty i ten sygnał chciałbym badać, ale idźmy dalej. Dioda zaczyna przewodzić, wycinając połowę sinusa na fototranzystor. Z niego zbieram sygnał i sprawdzam czy zmienił się stan wejścia mikrokontrolera. Z noty PC817 wynika, że typową wartościa Vf diody jest 1,2V oraz prąd 20 mA. Tych wartości się trzymałem. Nie wiem czy poprawnie rozumuję zbieranie sygnału wyjściowego z tranzystora. Sygnał będzie próbkowany z częstotliwością sieci 50Hz czyli sygnał ten muszę próbkować przynajmniej z częstotliwością 100Hz żeby rzetelnie ocenić czy czujnik nadal jest aktywny czy też nie. W dalszej logice, jeśli czujnik jest aktywny to występuje przerwanie, które aktywuje dany port mikrokontrolera z kluczem tranzystorowym, który dołącza napięcie 12V na cewkę przekaźnika, zasilając przez ten czas inne szpejo. Podsumowując. Czy metoda detekcji fazy narysowana przez mnie jest prawidłowa czy wymaga zmodyfikowania? Dziękuję z góry za pomoc.
  11. Tak jest to policzone. 1,4V (nowe 1,45V ale biorąc uwagę degradację, biorę pod uwagę gorszy przypadek) osiąga naładowane ogniwo NiCd, więc naładowanie moich 6 pastylek, będzie wymagało 8,4V. Tak samo LiFePo4. Naładowane ogniwo osiąga napięcie 3,65V, lecz to w porównaniu do NiCd można trochę przeforsować napięciowo do 4,1V, co nie wpływa znacząco na jego kondycję. Ja przyjąłem ładować je do 3,85V na celę, bo tak pozwalają na to rezystory użyte w układzie (nie chcę generować nowych elementów, bo później wiąże się to też z kosztami układania przez zewnętrzną firmę. Ciągle kompromisy). Jest kilka algorytmów dla NiCd. Ja wybrałem -dV. Porównuję cały czas napięcie i patrzę czy podczas ładowania, napięcie na akumulatorze nie spada. Jeśli tak jest, odcinam ładowanie kluczem. Nie powinno to nigdy nastąpić, ale zawsze to zabezpieczenie przed przeładowaniem. LiFePo4 zaleca się ładować wysokim prądem do 60% pojemności, a resztę prądem niższym przy badaniu cały czas temperatury ogniwa. Tak jak napisałem - nie zależy mi na szybkości ładowania, więc w obu przypadkach wybieram 0,1C, by na 100% nie dopuścić do przegrzania się ogniwa. Także jest to w miarę przemyślane. Układowo mam to zrobione tak, że z przetwornicy wejściowej 12V doprowadzam napięcie na wejście pierwszego stabilizatora liniowego, którego wykorzystuje do stabilizacji prądu 180mA, a jego wyjście do wejścia drugiego stabilizatora liniowego, gdzie wybieram sobie już odpowiednie napięcie na switchu. Wydaje mi się to najprostsze. Docelowo robi się to tak, że jest jedna centrala, która zbiera wszystkie informacje o stanie i kondycji urządzenia i ew. sygnalizuje jakieś błędy. Może jestem w błędzie, ale wydaje mi się, że pomiar prądu rozładowania i ładowania w funkcji czasu jest informacją bardziej wiarygodną niż pomiar napięcia w funkcji czasu, aby wiedzieć czy akumulator nadal trzyma swoją znamionową pojemność. (raz rocznie trzeba wykonać test B, który polega na pełnym rozładowaniu i naładowaniu akumulatora oraz sprawdzenia czy oprawa nadal podtrzymywana jest przez określony czas (1,2,3h w zależności od wersji)).
  12. Akumulator jest ładowany zawsze stałym prądem 180 mA z możliwością wybrania napięcia ładowania na switchu: 8,5V oraz 11,5V, by ładować ogniwa NiCd (7,2V) lub LiFePo4 (9,6V). Po uzyskaniu napięcia 8,4V dla NiCd oraz 11V dla LiFePo4 nastąpi jakaś zmiana sygnalizacji LED, a w przypadku, gdy napięcie na złączu akumulatora będzie niższe niż 6,5V, co ma sygnalizować błąd lub brak akumulatora, ma na nastąpić adekwatna do tego faktu sygnalizacja LED. Oba akumulatory będą o pojemności 1800mAh. Ładuje je prądem 0,1C z bardzo prostego powodu. Nie chcę generować dodatkowych kosztów na czujnik temperatury, a norma mówi, że po 24h ma nastąpić pełne naładowanie akumulatorów, więc po co kombinować. W przyszłości chciałbym, by układ ten został skomercjalizowany stąd poszukiwanie przez mnie jak najtańszych rozwiązań. MCP6061 jest jeszcze do przełknięcia. Generalnie projektuję moduł zasilania awaryjnego dla opraw LED, gdzie po zaniku zasilania sieciowego (tu również zasilania podstawowego LED), zasilanie przełączane jest przekaźnikiem na akumulator który ma uruchomić przetwornicę do zasilania LED oraz podtrzymać układ sterowania. W jednej z wersji tego modułu zwanej centralnym monitoringiem wymaganie jest podanie napięcia akumulatora. Ja uznałem, że fajnie byłoby też mierzyć prąd, by wiedzieć w jakiej kondycji jest akumulator jako bonus. Co do dzielnika napięcia to mamy: R3 = 100k, R4 = 3k, co daje 96 mV. Nie zmieniam nic, bo wszystkie obliczenia są zrobione z offsetem taki jak ma być. Tak się złożyło szczęśliwie. Wzmacniacz x30 ma pasmo ok. 24kHz. Wydaje mi się, że można je spokojnie zawęzić do 2kHz, żeby nie wchodzić na kolano charakterystyki. Napięcie szumów na wyjściu to suma szumu 1/f, termicznego, szerokopasmowego oraz prądowego. Są na to wzory, można to policzyć.
  13. Z gotowych rozwiązań mogę polecić system sterownia Casambi CBU-PWM4. Wystarczy podłączyć zasilacz oraz pasek LED RGB lub RGBW, do sterownika, pobrać aplikacje na telefon i skonfigurować sceny, które mają uruchomić się o danej godzinie. Kosztuje trochę, ale jest to gotowe, przyzwoicie działające rozwiązanie.
  14. 1. Nie używałem jeszcze nigdy ADC, więc stąd te pokłady niewiedzy. Wiedziałem o separacji fizycznej tych ścieżek, ale jakoś nie przyszło mi do głowy, że to jednak faktycznie ta sam potencjał. Teraz wiem jak to wykonać fizycznie. 3. Faktycznie, chochlik. Wzmacniacz na wejściu dodatnim widzi napięcie 3,3V, a te moje nieszczęsne R3 razem z R1 i R2 mają wpływ na wzmocnienie pochodzące z wejścia nieodwracającego. Trochę doczytałem i narysowałem kolejny schemat. Przy dopasowaniu R1=R3, R2=R4 moje napięcie wyjściowe wyniesie Uwy = R2/R1 (U2-U1), z tym że chcąc zastosować LM258 czy jego bliźniaczych kumpli, trzeba pamiętać, że górną szyną napięciową tego wzmacniacza jest Vcc-1,5V. Tranzystory same się nie polaryzują, a szkoda. W moim przypadku górnym progiem jest 1,8V, więc napięcie na dzielniku napięcia trzeba dobrać tak, aby po podaniu napięcia U1 nie okazało się, że wyskoczę poza ten zakres. Sądzę, że w moim przypadku nie będzie to więcej niż +/- 200mV, ale jeszcze może się zdarzyć wahnięcie napięcia na samym stabilizatorze 3,3V, które wynosi 2%, więc w najgorszym przypadku będzie to 3,2V, co obniży górną szynę zasilania na 1,7V. Sądzę, że rozsądnie będzie przyjąć 0,7V za odniesienie, żeby można było wzmocnić napięcie przynajmniej dwukrotnie.
  15. Kubeł zimnej wody jeszcze nikomu na złe nie wyszedł. No chyba, że ktoś złapał po nim katarek. Do rzeczy. Uzupełniłem pokaźne pokłady niewiedzy dot. OPAmpów. Załączam kolejny schemat, przemyślany, nie wykonany ,,od czapy''. Zaczniemy od zasilania. Doprowadzam zasilanie +3V3 - AGND do OPAmpa, z tych samych linii, które doprowadzają zasilanie do uC. W ten sposób zapewniam sobie ten sam punkt odniesienia dla pomiaru napięcia wyjściowego plus dodatkowo robię dzielnik napięcia 1:1 na wejściu nieodwracającym, by przesunąć off-set mojej masy na 1/2Vcc zasilania OPAmpa, czyli 1,65V jak kolega @RFM proponował, przez co niezależnie od przyłożonego napięcia wejściowego, czy będzie ono dodatnie czy ujemne - zawsze będę znajdować się nad poziomem 0V. Drugą "nogę" rezystora pomiarowego doprowadzam również do AGND, żeby w ogóle pojawiło się jakiekolwiek napięcie wejściowe na OPAmpie. Widać światełko w tunelu?
  16. @marek1707 @RFM Stosując się do Waszych rad narysowałem nowy schemat. Czy takie rozwiązanie mieliście na myśli? BTW. Dziękuję już teraz z góry za tak miły odzew
  17. Dzień dobry. Jestem obecnie w trakcie budowy ładowarki akumulatorowej i lekko się już zakręciłem. Chcę po prostu potwierdzić czy to, co myślę jest zgodne z rzeczywistością, a jak nie jest to w jakiś magiczny sposób to skorygować Do rzeczy. Założenie projektowe jest takie: - w torze masy akumulatora wstawiam bocznik 100mOhm do pomiaru napięcia na nim, aby później sobie wyliczyć z niego prąd; - chcę badać prąd przepływający przez rezystor dwukierunkowo: w trakcie ładowania (180mA), w czasie rozładowania (ok. 700-1300mA). - odczyt napięcia będzie odbywać się na jakimś uC, zapewne padnie na jakiegoś STMa; na pewno ADC będzie zasilany +3V3. - wykorzystuje LM258 do wzmocnienia sygnału do jakiś sensownych granic odczytu. Z noty katalogowej wynika, że można na jego wyprowadzenia przyłożyć napięcia niedodatnie na wejście odwracające > - 0V3 oraz na wejście nieodwracające > -1V5. Według moich obliczeń wynika, że wzmocnienie na poziomie G=23 jest wystarczające do pokrycia zakresu od 180mA do 1300mA, bo wychodzi to (414mV do 2990mV) Pytanie moje jest takie. Czy układ zaproponowany przez mnie będzie pracować tak jak ja to rozumiem, czy jest nieco inaczej? Z góry dziękuję za pomoc i opinie do mojego szalonego projektu.
×
×
  • Utwórz nowe...