Modyfikacja drivera Nanjg 105C

Coś Ci się zepsuło? Nie chce działać jak powinno? Opisz dokładnie swój problem a postaramy się pomóc...
Awatar użytkownika
@GUTEK@
Posty: 149
Rejestracja: środa 01 cze 2011, 17:08
Lokalizacja: Gliwice
Kontakt:

Modyfikacja drivera Nanjg 105C

Post autor: @GUTEK@ »

Witam.

Wziąłem się za moją pierwszą modyfikację latarki. W tym celu między innymi kupiłem driver Nanjg 105C. Muszę go tylko przerobić na sterowanie microswitchem.
Niestety żadnego fajnego softu w internecie się nie znajdzie, więc pozostaje coś wklepać samemu. Znalazłem na stronie http://drjones.nerdcamp.net/mini.html prosty przykład softu do sterowania microswitchem. Po wgraniu go do Attiny w driverze działa bardzo fajnie. I co najważniejsze, rozumiem ten kod, więc będę mógł go pod siebie przerobić.
Mam tylko problem z trybem uśpienia. W tym przykładzie go nie ma i driver przy wyłączonej latarce pobiera około 2mA, więc dużo za dużo.
Niestety nie ogarniam jak zmusić Attiny do uśpienia, gdy latarka jest wyłączona. Znalazłem taki przykład: http://www.eevblog.com/forum/microcontr ... interrupt/ - jedyny który mi zadziałał i udało mi się zejść do 170uA, co już jest wynikiem znacznie lepszym. Jednak z tego co czytam wszystkie te "super softy" w trybie uśpienia pobierają około 5uA. Dlatego mam prośbę, czy ktoś mógłby mi pomóc i dopisać czego mi brakuje, żeby jeszcze zmniejszyć pobór prądu. Mój kod poniżej:

Kod: Zaznacz cały

//MiniMo -- minimalistic driver firmware for momentary buttons (no blinkies)  --  DrJones 2014
#define F_CPU 4800000                    //use fuses  low:0x75  high:0xff
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
//change modes here; just change/add/delete values. The "0" is 'off'
uint8_t modes&#91;&#93;=&#123;0,  8,90,255&#125;;          //PWM values, 6..255 - LEAVE THE "0" THERE


void powerDown&#40;void&#41;
&#123;
	GIFR |= &#40;1<<PCIF&#41;; // Clear eventually occurred previous pin change interrupts
	GIMSK |= &#40;1<<PCIE&#41;; // Activate Pin change interrupts
	MCUCR = &#40;MCUCR | &#40;1<<SM1&#41;&#41; & ~&#40;1<<SM0&#41;;
	MCUCR |= &#40;1<<SE&#41;; //Enable Power-Down
	sleep_mode&#40;&#41;;
	MCUCR &= ~&#40;1<<SE&#41;; //Disable Power-Down
	GIMSK &= ~&#40;1<<PCIE&#41;; // Deactivate Pin change interrupts
&#125;

ISR&#40;PCINT0_vect&#41;
&#123;
&#125;

int main&#40;&#41; &#123;
	DDRB=2; PORTB=8;                       //define PB1 as output and pull-up switch on PB3
	PCMSK |= &#40;1<<PCINT3&#41;; // Sets the Pin change interrupt mask, only PB3 will trigger the PCINT once it is enabled before sleep
	SREG |= &#40;1<<SREG_I&#41;; //Enables Interrupts globally after setup
	TCCR0A=32+3; TCCR0B=1;                 //PWM setup, 18kHz
	uint8_t count=0,mode=0,waspressed=0, lastmode=1;   //define some variables used below

	while&#40;1&#41; &#123;                             //endless loop
		if &#40;&#40;PINB&8&#41;==0&#41; &#123;                   //when the button is pressed &#40;PB3 pulled down&#41;
			count++;                           //count length of button press
			if &#40;count==16&#41; &#123;                   //pressed long &#40;16*25ms=0.4s&#41;
				if &#40;mode>0&#41; &#123;lastmode=mode; mode=0;&#125;  //was on?  -> off, but remember the mode
				else mode=lastmode;                   //was off? -> on, with previous mode.
			&#125;
			waspressed=1;                      //remember that the button was pressed, see below
		&#125;
		else &#123;                               //button not pressed
			if &#40;waspressed&#41; &#123;                    //but it was pressed, so it has just been released!
				waspressed=0;                      //reset that
				if &#40;count<16 && mode>0&#41; &#123;          //really was a short press AND the light is on
					mode++; if &#40;mode>=sizeof&#40;modes&#41;&#41; mode=1; //next mode, wrap around
				&#125;
				count=0;                           //reset counter
			&#125;
		&#125;
		OCR0B=modes&#91;mode&#93;;                     //set PWM level &#40;0 is off&#41;
		if &#40;mode==0 && &#40;PINB&8&#41;!=0&#41; powerDown&#40;&#41;;
		_delay_ms&#40;25&#41;;                         //wait a bit before checking again, important for counting
	&#125;
&#125;
Z góry dzięki za pomoc.
Awatar użytkownika
Pyra
Site Admin
Posty: 8527
Rejestracja: niedziela 02 sie 2009, 20:35
Lokalizacja: Gądki

Post autor: Pyra »

Witam
Wiesz co, ja stosuję standardowe rozwiązanie...

Kod: Zaznacz cały

#include <avr/sleep.h>

.......

	OCR0B=0;						//wyłącz LEDa
	OCR0A=0;
     set_sleep_mode&#40;SLEEP_MODE_PWR_DOWN&#41;;  //Power down
     sleep_mode&#40;&#41;;
Działa bez pudła.

Już nie pamiętam, kiedyś robiłem doświadczenia, to uzyskałem ułamek mikroampera.

Pozdrawiam
Izali miecz godniejszy niżli topór w boju?
Piszmy po polsku, wszak jesteśmy Polakami.
Awatar użytkownika
alienth
Posty: 270
Rejestracja: poniedziałek 08 paź 2012, 19:10
Lokalizacja: Rzeszów

Post autor: alienth »

Około 150uA pobiera sam dzielnik napięcia.
Trzeba zastosować A25 i pozbyć się dzielnika.
Moje sterowniki:
AHE+ v1
KHE
v201 / v211
Awatar użytkownika
@GUTEK@
Posty: 149
Rejestracja: środa 01 cze 2011, 17:08
Lokalizacja: Gliwice
Kontakt:

Post autor: @GUTEK@ »

Czyli przy Attiny13A nie da się zejść niżej z poborem prądu?

Tu znalazłem opis do Attiny13A: http://homecircuits.eu/blog/low-power-p ... attiny13a/
Tylko nie bardzo się orientuje w konfiguracji tego watchdoga. A dodanie tej linijki wyłączającej ADC do mojego kodu nic nie zmienia, mimo że autorowi spadł po tym pobór właśnie do tych 5uA
Awatar użytkownika
alienth
Posty: 270
Rejestracja: poniedziałek 08 paź 2012, 19:10
Lokalizacja: Rzeszów

Post autor: alienth »

Jeżeli zostawisz dzielnik to nie zejdziesz niżej.
W swoim sterowniku również zszedłem do 5uA.

Przejrzyj jeszcze raz kod. Musisz mieć babola.
Moje sterowniki:
AHE+ v1
KHE
v201 / v211
Awatar użytkownika
@GUTEK@
Posty: 149
Rejestracja: środa 01 cze 2011, 17:08
Lokalizacja: Gliwice
Kontakt:

Post autor: @GUTEK@ »

Żebym to ja się jeszcze orientował gdzie ten babol. No nic pozostaje mi kombinować:)

Tak jeszcze dla jasności, dzielnik napięcia to ten ADC tak ?
A czy problemem może być też kompilator lub programator?
Używam Atmel Studio 6.2 i za programator robi mi Arduino Uno + avrdude.
Awatar użytkownika
alienth
Posty: 270
Rejestracja: poniedziałek 08 paź 2012, 19:10
Lokalizacja: Rzeszów

Post autor: alienth »

Dzielnik napięcia to te dwa rezystory obok procesora. Dzielnik jest podłączony do jednej z nóżek ADC procesora. Dzięki temu można monitorować napięcie ogniwa. Stosując ATtiny25 i małą sztuczkę w programie można pominąć wspomniany dzielnik zachowując możliwość monitorowania napięcia na ogniwie.
Moje sterowniki:
AHE+ v1
KHE
v201 / v211
Awatar użytkownika
@GUTEK@
Posty: 149
Rejestracja: środa 01 cze 2011, 17:08
Lokalizacja: Gliwice
Kontakt:

Post autor: @GUTEK@ »

A czyli musiałbym wylutować te rezystory. Fakt nie pomyślałem, że to pobiera też prąd, a patrzyłem na schemat. Dzięki za wyjaśnienie.

Tak się jeszcze zastanawiam, czysto teoretycznie, bo raczej tego nie będę robić.
Schemat jest taki:
* VCC
* |
* Vd (~.25 v drop from protection diode)
* |
* 1912 (R1 19,100 ohms)
* |
* |---- PB2 from MCU
* |
* 4701 (R2 4,700 ohms)
* |
* GND

Gdyby odłączyć VCC i podłączyć pod nóżkę np. PB4. Potem zrobić taki numer, ustawić jedynkę na PB4, zmierzyć napięcie i ustawić zero na PB4.
* PB4
* |
* Vd (~.25 v drop from protection diode)
* |
* 1912 (R1 19,100 ohms)
* |
* |---- PB2 from MCU
* |
* 4701 (R2 4,700 ohms)
* |
* GND

Ma to szansę zadziałać, czy procek zgłupieje?
Awatar użytkownika
Pyra
Site Admin
Posty: 8527
Rejestracja: niedziela 02 sie 2009, 20:35
Lokalizacja: Gądki

Post autor: Pyra »

Witam
@GUTEK@ pisze:Gdyby odłączyć VCC i podłączyć pod nóżkę np. PB4. Potem zrobić taki numer, ustawić jedynkę na PB4, zmierzyć napięcie i ustawić zero na PB4.
* PB4
* |
* Vd (~.25 v drop from protection diode)
* |
* 1912 (R1 19,100 ohms)
* |
* |---- PB2 from MCU
* |
* 4701 (R2 4,700 ohms)
* |
* GND

Ma to szansę zadziałać, czy procek zgłupieje?
Ktoś na forum robił takie próby, niestety nie pamiętam wyników...

Pozdrawiam
Izali miecz godniejszy niżli topór w boju?
Piszmy po polsku, wszak jesteśmy Polakami.
Awatar użytkownika
alienth
Posty: 270
Rejestracja: poniedziałek 08 paź 2012, 19:10
Lokalizacja: Rzeszów

Post autor: alienth »

Jakoś nie łapie tego pomysłu. Ale to chyba dlatego że padam ze zmęczenia..

Generalnie zastosowanie A25 dużo upraszcza i daje większe możliwości.
Ostatnio zmieniony wtorek 05 kwie 2016, 07:46 przez alienth, łącznie zmieniany 2 razy.
Moje sterowniki:
AHE+ v1
KHE
v201 / v211
Awatar użytkownika
@GUTEK@
Posty: 149
Rejestracja: środa 01 cze 2011, 17:08
Lokalizacja: Gliwice
Kontakt:

Post autor: @GUTEK@ »

No tak, tylko A25 to kolejne koszty i tak powoli cena latarki dojdzie do ceny jakiegoś gotowca. A mi chodzi hobbistycznie się tym pobawić i zobaczyć co wyjdzie :)

Znalazłem takie coś: http://www.swiatelka.pl/viewtopic.php?p ... ht=#100516
Z tym, że tam masa jest podpięta pod nóżkę, a nie zasilanie.
Awatar użytkownika
ElSor
Site Admin
Posty: 5041
Rejestracja: niedziela 13 wrz 2009, 12:52
Lokalizacja: Ozimek

Post autor: ElSor »

@GUTEK@ pisze:Znalazłem takie coś: http://www.swiatelka.pl/v...ghlight=#100516
Z tym, że tam masa jest podpięta pod nóżkę, a nie zasilanie.
No i na końcu zadałem pytanie, całkiem istotne.

Ostatnio robiłem migałkę do bojki, w której użyłem fotorezystora podpiętego pomiędzy GND a pin procka. 2gi rezystor dzielnika to rezystor wewnętrzny procka o wartości ok 40k. Układ jest bardzo prosty i działa zgodnie z oczekiwaniami. Pobór prądu w uśpieniu ok 5uA a podczas pracy ok 350mA (przez 20ms) i kilkaset uA przez kilka ms, kiedy to jest dokonywany pomiar ilości światła itp. Czas realnego działania na 1 ładowaniu aku 2Ah oceniam na 1-2 miesiąca w zależności od pory roku. Kod z komentarzami poniżej.

Fusy 0xFF 0x7B, lockbity 0xFC.

Kod: Zaznacz cały

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>

uint8_t U1;
uint16_t srednia=100;

void przerwa&#40;uint8_t czas&#41; //przerwa 10ms x czas
&#123;
	while &#40;czas--&#41;
	&#123;
		_delay_ms&#40;10&#41;;
	&#125;
&#125;


void LED_ON &#40;uint8_t x&#41;
&#123;
	PORTB |= &#40;1<<PB0&#41;; //zapal LEDa
	przerwa&#40;x&#41;;
	PORTB &= ~&#40;1<<PB0&#41;; //zgaś LEDa
&#125;

int main&#40;&#41;
&#123;
		ACSR |= &#40;1<<ACD&#41;; //wylaczenie komparatora
	
		ADCSRA= &#40;1<<ADEN&#41;; //załączenie ADC
		ADCSRA|= &#40;1<<ADPS0&#41;; //prescaler = 2 &#40;64kHz&#41;

		ADMUX=34; //ustaw pomiar napięcia na  ADC3 PB3 &#40;ADMUX1 i ADMUX0 HI&#41;, ADLAR=1 &#40;6ty bit, wartośc 32&#41; Vref = Vcc bo REFS0 =0 w ADMUX

		DDRB= &#40;1<<DDB2&#41;|&#40;1<<DDB1&#41;|&#40;1<<DDB0&#41;; //ustaw PB2, PB1 i PB0 jako wyjście
		PORTB= &#40;1<<PB3&#41;|&#40;1<<PB4&#41;; //ustaw wejścia w stan wysoki

		LED_ON&#40;100&#41;; //selftest
	
		WDTCR |= &#40;1<<WDTIE&#41; | &#40;1<<WDCE&#41; | &#40;1<<WDP2&#41; | &#40;1<<WDP1&#41; | &#40;1<<WDP0&#41;; //2 sek
		sei&#40;&#41;; //zezwolenie na przerwania
	
	while&#40;1&#41; //Pętla nieskonczona

	&#123;
		ADCSRA|= &#40;1<<ADSC&#41;; //start konwersji
		while &#40;ADCSRA &&#40;1<<ADSC&#41;&#41;; //czekaj na koniec konwersji
		U1 = ADCH;
		srednia=srednia*4;
		srednia=srednia+U1;
		srednia=srednia/5;
		if &#40;srednia > 200&#41; //jeśli mało światła to zapal na chwile diodkę
		&#123;
			LED_ON&#40;2&#41;;
		&#125;
				
		PORTB &= ~ &#40;1<<PB4&#41;; //ustaw wejścia w stan niski
		MCUCR|= &#40;1<<SE&#41;|&#40;1<<SM1&#41;; //sleep enable = power down
		ADCSRA&= ~&#40;1<<ADEN&#41;; //wylaczenie ADC
		PRR = 3; //|= &#40;1<<PRTIM0&#41; | &#40;1<<PRADC&#41;; //wyłączenie ADC i TIMERa0
		sleep_cpu&#40;&#41;; //uspienie
	&#125;
&#125;

ISR &#40;WDT_vect&#41;
&#123;
	MCUCR &= ~&#40;1<<SE&#41;;
	PORTB |= &#40;1<<PB4&#41;; //ustaw wejścia w stan wysoki
	PRR &= ~ &#40;1<<PRADC&#41;; //załączenie ADC - wylączenie oszczedzania pradu
	ADCSRA= &#40;1<<ADEN&#41;; //załączenie ADC
&#125;
Awatar użytkownika
alienth
Posty: 270
Rejestracja: poniedziałek 08 paź 2012, 19:10
Lokalizacja: Rzeszów

Post autor: alienth »

Przejrzałem dziś na spokojnie temat i pomysł.
Jak czas pozwoli to wieczorem to przetestuje.
Moje sterowniki:
AHE+ v1
KHE
v201 / v211
Awatar użytkownika
@GUTEK@
Posty: 149
Rejestracja: środa 01 cze 2011, 17:08
Lokalizacja: Gliwice
Kontakt:

Post autor: @GUTEK@ »

alienth i jak próbowałeś czy ta metoda się sprawdza i nie powoduje problemów?

Ja dzisiaj siadłem do tego i posklejałem kawałek funkcji na próbę:

Kod: Zaznacz cały

#define ADC_CHANNEL 0x01	// MUX 01 corresponds with PB2
#define ADC_DIDR 	ADC1D	// Digital input disable bit corresponding with PB2
#define ADC_PRSCL   0x06	// clk/64

.....

void sprawdzanie_napiecia&#40;void&#41;
&#123;
	int niskie_napiecie=255;
	PORTB &= ~&#40;1<<PB4&#41;;
	ADMUX  = &#40;1 << REFS0&#41; | &#40;1 << ADLAR&#41; | ADC_CHANNEL; // 1.1v reference, left-adjust, ADC1/PB2
	DIDR0 |= &#40;1 << ADC_DIDR&#41;;							// disable digital input on ADC pin to reduce power consumption
	ADCSRA = &#40;1 << ADEN &#41; | &#40;1 << ADSC &#41; | ADC_PRSCL;   // enable, start, prescale
	while &#40;ADCSRA &&#40;1<<ADSC&#41;&#41;; //czekaj na koniec konwersji
	niskie_napiecie = ADCH; 
	if&#40;niskie_napiecie<150&#41; &#123;PORTB |= &#40;1<<PB0&#41;;&#125; else &#123;PORTB &= ~&#40;1<<PB0&#41;;&#125;
	PORTB |= &#40;1<<PB4&#41;;
	
	ADCSRA &= ~&#40;1<<7&#41;; //ADC off
	
&#125;
Wygląda, że to działa poprawnie. Przy około 3,4V zaświeca mi się podłączony led pod PB0. A uśpiony układ pobiera tak mało, że miernik nie jest wstanie mi tego zmierzyć.
Tylko czy ta metoda nie będzie miała jakichś skutków ubocznych przy dłuższym użytkowaniu ?
Awatar użytkownika
alienth
Posty: 270
Rejestracja: poniedziałek 08 paź 2012, 19:10
Lokalizacja: Rzeszów

Post autor: alienth »

@GUTEK@, niestety nie miałem na to czasu. Cieszę się, że Ci się udało rozwiązać problem. :)
Moje sterowniki:
AHE+ v1
KHE
v201 / v211
ODPOWIEDZ