Bärbar högtalare och SMPS som laddare (mkt bilder!)

Berätta om dina pågående projekt.
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Bärbar högtalare och SMPS som laddare (mkt bilder!)

Inlägg av Korken »

Högtalaren

Hörtalaren vart färdigbygd redan i somras, och har inte så jätte mycket att säga om den men väntade med att lägga ut byggloggen innan batteriladdaren också var klar.
Var väldigt inspirerad av maDas högtalare, så byggde en egen genom att kolla på bilder av hans.

Och hur allt gick till:

Det första jag gjorde var att räkna på lådan och skaffade förstärkaren och kraftagget.
Kraftagget är på 350W (overkill) men de va billigare än 150W agget jag först tänkte ta.
1.jpg
Sen ritade jag upp allt på papper så jag kunde på en känsla över hur allt kommer ligga i lådan.
3.jpg
Efter att jag var nöjd med hur allt skulle ligga så började jag göra alla sidor och ta ut hål och liknande:
5.jpg
6.jpg
Sen var det bara att börja skruva ihop allt. Liberala mängder trälim användes ;)
Kan berätta att vägglister fungerar perfekt som batterihållare!
7.jpg
8.jpg
9.jpg
Nu skulle en frontpanel byggas, plastade den, tog ut hål och spacklade den:
10.jpg
11.jpg
12.jpg
Sen efter målning så var den klar!
Är helt nöjd med resultatet och den spelar riktigt fint!
13.jpg
Batteriladdaren - Switchat Nätaggregat med CC och CV funktioner

Lite rapport stil på denna, lite för att ge en insikt i hur jag har tänkt och resonerat. :)
Det kan vara lite konstigt skrivet ibland då jag har skrivit denna text över lång tid.

Introduktion:

Detta projekt har jag startat för att ge mig en bättre kunskap inom analog elektronik, störningar från switchande nätaggregat och att lära mig kontrollera ett sådant aggregat.
Men anledningen till att detta projekt startade, i grund och botten - innan jag såg vad jag kunde lära mig av det, är på grund av ett sommarprojekt jag byggde på hemma över sommaren. Det är så att vi i klassen gillar att träffas ute och så gillar vi musik, men ingen av oss har en bärbar högtalare, så jag byggde en sådan över sommaren. Men då den både kunde drivas på batteri och ett inbyggt nätaggregat så ville jag inte behöva ha en separat laddare till batterierna. MaDa fixade detta genom att ställa in kraftaggregatet på en lagom nivå och koppla in batterierna rakt därpå, men jag ville ha mer kontroll.
Och här startade min långa vandring in i den stora och underbara världen av switchade nätaggregat och hur man kan kontrollera dessa, både ur spänning- och strömsynpunk.

Tillvägagångssätt:

Det första jag gjorde var att snabbt skissa upp hur jag ville att det skulle fungera (ungefärligt).
Och efter lite funderade kom jag fram till denna bild:
ide.png
Problem:

Det jag försöker åstadkomma är så att min krets F ska ha denna funktion (ändrades lite på vägen, men huvud idén är den samma):
- Finns det spänning i A samt att spänningen över batteriet är > X volt så ska F vara avbrott (där X är gränsen för ett fulladdat batteri).
- Finns det spänning i A samt att spänningen över batteriet är < Y volt så ska F ha kontakt (där Y är gränsen för att påbörja laddning).
- Om den laddar och spänningen kommer upp till gränsen X volt så ska den hålla kontakt i en bestämd tid, Z timmar, och sedan bli avbrott.
- Finns det ingen spänning från kraftagget så ska F ha kontakt (då ska batteriet driva instrumentet).

Samt:
- När F är kopplad för laddning så behöver laddströmmen begränsas och bör ligga som högst omkring 0.9A.
- Men vid urladdning ska det inte finnas någon begränsning.

Lösning:

Jag googlade på mitt problem och ramlade då över switchade nätaggregat. Och efter lite läsning och simuleringar så gjorde jag en illustrerande bild över kretsen Fs funktion när det gäller laddningen:
smps_adc_sense.png
Och det mest förklarar sig självt här, men ska tydliggöra lite:
- När bilden ritades så var jag osäker på om man skulle ha en P-MOS eller en N-MOS, så ritade det som en strömbrytare.
- Gain är en icke inverterande förstärkare, som förstärker 23 gånger, med ett lågpassfiler på. Den mäter spänningsfallet över det försumbart lilla motståndet (dvs. för resten av kretsen) så att jag kan beräkna strömmen i kretsen och styra den.
- Ref2 är spänningsreferens så jag kan styra spänningen.
- PWM Ctrl är en 8-bitars mikrokontroller av märket AVR. Den kör en hårdvaru PWM på 31.2 kHz och läser samtidigt av Ref 1 och Ref 2 och gör nödvändiga ändringar på PWMens Duty (D) för att spänning och ström ska ligga inom gränserna.
- Load representerar batteriet, men det jag ritade var för en generell design, det behöver inte vara just ett batteri man har där.

Efter detta läste jag på om hur man beräknar värdena på komponenterna i dessa såkallade ”Buck converters”. Jag gjorde ett Excelblad för att göra mina beräkningar lätta för ändring, men denna är också för en generell design, behöver inte vara ett batteri, så vissa onödiga saker är inkluderade.
Jag har bifogat ett exempel på olika värden som jag satt och testade med. De vart också dessa värden som vart de slutgiltiga.
excel.png
Jag valde ett ganska stort värden på induktansen därför att jag inte ville att strömmen skulle svänga så mycket pga. slutna blybatteriers natur. De tål inte för höga strömmar.

Design:

Nu var det dags att designa kopplingsschemat och att göra en boardlayout som kan skickas till Kina för produktion. Jag har tyvärr inga bilder på mina gamla versioner. Den första versionen gick sönder pga. P-MOSen var kopplad så den drogs till jord för att öppna sig och det vart då en gatespänning på ca -31V. Den klarade denna spänning i ca 1 timmes användning innan den började bete sig sporadiskt och tillslut att den inte öppnade sig mer. Men till min lycka så innan transistorn gick sönder så fungerade allt perfekt, precis enligt mina beräkningar och simuleringar.

Men efter lite om design så fick jag den nuvarande designen:
smps.png
Och denna design fungerar precis som jag ville! :D Den sparka på just nu och laddar min högtalare.
Samt koden för de som är sugna:

Kod: Markera allt

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

#define F_CPU 8000000UL

// Pin and Port definitions [PORTA]
#define CONTROL_DDR		DDRA
#define CONTROL_PORT 	PORTA
#define I_ADC_PIN		0
#define V_ADC_PIN		1
#define RELAY_PIN		2
#define LED_PIN			3

// Pin and Port definitions [PORTB]
#define PWM_DDR			DDRB
#define PWM_PORT 		PORTB
#define PWM_PIN			2

// Pointers for different blink-routines
#define BLINK_STOP 		0
#define BLINK_SEQ_ERR3	1
#define BLINK_SEQ_ERR2	3
#define BLINK_SEQ_ERR1	5
#define BLINK_SEQ_DONE	8

// Flags that controll various things (their bit position)
#define FLAG_RUN_UPD	0		// bit = 1 -> Run the PWM update
#define FLAG_PWM_CONT	1		// bit = 0 -> Use current controll -||- bit = 1 -> Use voltage controll
#define FLAG_ADC_CHK	2		// bit = 0 -> Summing ADC current -||- bit = 1 -> Summing ADC voltage
#define FLAG_TIMER		3

// Maximum and minimum PWM dutys (safe guards)
#define PWM_MAX			255
#define PWM_MIN			15

//Timing constants
#define TIMER_1H		76200	// = 1h with time error corection
#define TIMER_3H		228600	// = 3h with time error corection

// ADC values that the controller works to achieve
#define ADC_AIM_CURR		414
#define ADC_AIM_VOLT		894
#define ADC_AIM_VOLT_LOW	823
#define ADC_MIN_CURR		3

// Globals
volatile uint8_t flags = 0;
volatile uint8_t blink_seq = 0;
volatile uint16_t adc_value_c = 0;
volatile uint16_t adc_value_v = 0;
volatile uint16_t adc_aim = ADC_AIM_CURR;
volatile uint32_t timer_cnt = 0;

// Functions
void init_ADC();
void init_PWM();
void PWM_off();
void init_DELAY();

int main(void)
{
	cli();
	CONTROL_DDR |= ((1<<RELAY_PIN)|(1<<LED_PIN));		// LED & Relay Outputs
	CONTROL_DDR &= ~((1<<I_ADC_PIN)|(1<<V_ADC_PIN));	// ADC Inputs
	CONTROL_PORT = 0;
	PWM_DDR |= (1<<PWM_PIN);							// PWM output
	PWM_PORT = 0;
	init_DELAY();
	init_ADC();
	CONTROL_PORT |= (1<<RELAY_PIN);
	sei();

	no_battery:							// Restart point if the battery was disconnected


	/*--- Checking for battery ---*/
	blink_seq = BLINK_SEQ_ERR1;			// Start "waiting for battery"-blink
	PWM_off();
	flags = 0;							// Reset variables
	adc_aim = ADC_AIM_CURR;
	timer_cnt = 0;
	
	for (uint8_t i = 0; i < 133; i++) 	// 8s delay for the capacitors to discharge and not give a faulty voltage reading
	{
		_delay_ms(30);
		_delay_ms(30);
	}
	while (adc_value_v < 700);			// Check if battery is connected, if the voltage is over 23V = battery connected
	blink_seq = BLINK_STOP;
	CONTROL_PORT |= (1<<LED_PIN);		// Start "battery charging"-light
	

	/*--- Starting first charging cycle with CC = 0.9A and CV = 29.3V ---*/
	init_PWM();

	while (timer_cnt < TIMER_3H)				// timer_cnt is 0 until CV kicks in
	{
		if (adc_value_c < ADC_MIN_CURR)			// If the battery is disconnected restart the program.
			goto no_battery;

		if (adc_value_c > ADC_AIM_CURR)			// If the current has risen over the allowed limit, switch to CC
		{
			flags &= ~(1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_CURR;
		}

		else if (adc_value_v > ADC_AIM_VOLT)	// If the voltage has risen over the allowed limit, switch to CV
		{	
			flags |= ((1<<FLAG_PWM_CONT)|(1<<FLAG_TIMER));		// Start counting timer_cnt when CV kicks in
			adc_aim = ADC_AIM_VOLT;
		}
	}


	/*--- Starting second charging cycle with CC = 0.9A and CV = 27V ---*/
	timer_cnt = 0;								 // Reset timer_cnt, timer_cnt is still counting
	while (timer_cnt < TIMER_1H)
	{
		if (adc_value_c < ADC_MIN_CURR)			// If the battery is disconnected restart the program.
			goto no_battery;

		if (adc_value_c > ADC_AIM_CURR)			// If the current has risen over the allowed limit, switch to CC
		{
			flags &= ~(1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_CURR;
		}

		else if (adc_value_v > ADC_AIM_VOLT_LOW)	// If the voltage has risen over the allowed limit, switch to CV
		{
			flags |= (1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_VOLT_LOW;
		}
	}


	/*--- Charge completed! Continue with tickle charge CV = 27V ---*/
	blink_seq = BLINK_SEQ_DONE;

	
	while (1)
	{
		if (adc_value_c < ADC_MIN_CURR)			// If the battery is disconnected restart the program.
			goto no_battery;

		if (adc_value_c > ADC_AIM_CURR)			// If the current has risen over the allowed limit, switch to CC
		{
			flags &= ~(1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_CURR;
		}

		else if (adc_value_v > ADC_AIM_VOLT_LOW)	// If the voltage has risen over the allowed limit, switch to CV
		{
			flags |= (1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_VOLT_LOW;
		}
	}
}

void init_ADC()
{
	ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADATE)); 	// ADC prescaler 128 - Autotrigger
	ADMUX &= ~((1<<REFS0)|(1<<REFS1));							// Vcc as voltage reference
	ADCSRB &= ~((1<<ADTS0)|(1<<ADTS1)|(1<<ADTS2)); 				// Free running mode
	ADCSRA |= ((1<<ADIE)|(1<<ADEN)|(1<<ADSC));					// Interupt enable - Enable ADC - Start conversion
	ADMUX &= ~0b00111111;										// Start with a current reading
}

void init_DELAY()
{
	TCCR1B |= ((1<<WGM12)|(1<<CS10)|(1<<CS12));					// Start Timer1, CTC mode, 1024 prescaler
	TIMSK1 |= (1<<OCIE1A); 										// Compare interupt
	OCR1AH = 1;
	OCR1AL = 105; 												// 8000000Hz / 1024 / 390 = ~20Hz
}

void init_PWM()
{
	TCCR0A |= ((1<<WGM00)|(1<<WGM01)|(1<<COM0A1));				// Start Timer0, Fast PWM mode, output pin OC0A (PB2)
	TCCR0B |= (1<<CS00);										// No prescaler, 8000000Hz / 256 = ~31 250Hz PWM
	OCR0A = PWM_MIN;
}

void PWM_off()
{
	OCR0A = 0;
	TCCR0B &= ~(1<<CS00);
	TCCR0A &= ~((1<<WGM00)|(1<<WGM01)|(1<<COM0A1));
}

ISR(TIM1_COMPA_vect)
{
	const static uint8_t blinklist[] = {0,3,3,3,3,3,20,0,20,20,0};
	static uint8_t cnt = 0;
	static uint8_t count = 0;
	static uint8_t ptr = 0;	
	static uint16_t adc_value = 0;

	if (flags & (1<<FLAG_PWM_CONT))							// Check if Current or Voltage controll
		adc_value = adc_value_v;							// and adjust adc_value
	else
		adc_value = adc_value_c;

	if (cnt & 1)
	{
		if ((adc_value > adc_aim) && (OCR0A > PWM_MIN))			// Adjust PWM Duty, if needed
			OCR0A--;
			
		else if ((adc_value < adc_aim) && (OCR0A < PWM_MAX))
			OCR0A++;

		else if (OCR0A < PWM_MIN)
			OCR0A++;
	}
	
	if ((cnt >= count) && (blink_seq != 0))					
	{
		cnt = 0;
		count = blinklist[ptr++];

		if (count == 0)
		{
			CONTROL_PORT &= ~(1<<LED_PIN);
			ptr = blink_seq;
		}
		else
			CONTROL_PORT ^= (1<<LED_PIN);
	}
	
	if (flags & FLAG_TIMER)
		timer_cnt++;

	cnt++;
}


ISR(ADC_vect)								// Sum 64 readings and then divide by 64 for average 
{											// Every second is voltage average and the other is current average
	static uint8_t cnt = 0;
	static uint16_t sum = 0;
	
	if (cnt >= 63)
	{
		if (flags & (1<<FLAG_ADC_CHK))
		{
			adc_value_v = (sum>>6);
			ADMUX &= ~0b00111111; 			// Clear all MUX0..5 - ADC on ADC0 pin (PA0) (current reading)
			flags &= ~(1<<FLAG_ADC_CHK);	// Set flags for current reading
		}
		else
		{
			adc_value_c = (sum>>6);
			ADMUX |= (1<<MUX0);				// ADC on ADC1 pin (PA1) (voltage reading)
			flags |= (1<<FLAG_ADC_CHK);		// Set flags for voltage reading
		}

		cnt = 0;
		sum = 0;
	}
	else
	{
		sum += ADCL;
		sum += (ADCH<<8);
		cnt++;
	}
}
Samt lite byggbilder och test video.
Färdigbyggd version 1:
2010-08-17 19.34.16-1.jpg
Slaktad version 1 och version 2s kretskort:
2010-09-30 23.19.37.jpg
Testbänken under testerna:
2010-12-02 00.08.14.jpg
2010-12-02 01.33.43.jpg
Och testet i högtalaren då jag laddade batteriena för första gången.
Film:
2010-12-02 16.29.56.jpg
Det här var mitt första stora projekt och jag är väldigt nöjd!
Kom gärna med kommentarer, men en förbättring som kan göras är att ha en differentialförstärkare över motståndet för bättre strömmätning och mindre störningar, men det blir kanske i en senare design. :)
Och det var allt för mig! Och beklagar över dålig svenska samt felskrivningar!
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Senast redigerad av Korken 26 december 2010, 20:50:07, redigerad totalt 1 gång.
Användarvisningsbild
maDa
Inlägg: 4079
Blev medlem: 11 november 2005, 22:13:16
Ort: Malmö
Kontakt:

Re: Bärbar högtalare och SMPS som laddare (mkt bilder!)

Inlägg av maDa »

Ojoj, jag blir lite rörd här :)

Verkligen häftig laddare. Absolut bättre lösning än mig.

Vad använder du för element? Kör du någon bi-amp histora (för den modulen har väll 4 förstärkare)?
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Re: Bärbar högtalare och SMPS som laddare (mkt bilder!)

Inlägg av Korken »

Nej, det är samma som din fast äldre version har jag för mig. :)
Kanal 3 och 4 är icke fungerande så det är fortfarande 2x100W.

Tack för inspirationen! :D
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Re: Bärbar högtalare och SMPS som laddare (mkt bilder!)

Inlägg av Korken »

Tackar! :D

Kommer snart lite uppdateringar, har skrivit om delar av koden, i mitt rus så tänkte jag bara på funktionen och glömde lägga in "safe guards" i fall något går fel eller om man kopplar ur batteriet medans det laddas, något kortsluts och så vidare.
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Re: Bärbar högtalare och SMPS som laddare (mkt bilder!)

Inlägg av Korken »

Edit: Fixade det tror jag, men ska testa lite mer innan jag säger något.




Okej, nu ska vi se här.

Jag har fastnat lite och behöver tankehjälp.
Det jag har fastnat på är hur jag ska se om batteriet är inkopplat. Det fungerade förut, men med hur jag kollar om batteriet har blivit urkopplat så fungerar inte den gamla koden.

Det är såhär att istället för att kolla efter spänning så kollar jag strömmen.
Om strömmen kommer under en viss gräns så hoppar koden till "no battery" (den hoppar till början av programmet).
Detta fungerar perfekt, men när jag nu ska kolla om batteriet är inkopplat via om någon ström flyter så säger den att ström flyter, även då batteriet är urkopplat.
Då detta är omöjligt så måste det vara störningar i ADCn som ibland ger ett högt värde, men jag vet inte hur jag ska navigera mig runt problemet.

Några idéer? Allt är välkommet! :humm:

Koden om någon är intresserad:

Kod: Markera allt

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

#define F_CPU 8000000UL

// Pin and Port definitions [PORTA]
#define CONTROL_DDR		DDRA
#define CONTROL_PORT 	PORTA
#define I_ADC_PIN		0
#define V_ADC_PIN		1
#define RELAY_PIN		2
#define LED_PIN			3


// Pin and Port definitions [PORTB]
#define PWM_DDR			DDRB
#define PWM_PORT 		PORTB
#define PWM_PIN			2

// Pointers for different blink-routines
#define BLINK_STOP 		0
#define BLINK_SEQ_ERR3	1
#define BLINK_SEQ_ERR2	3
#define BLINK_SEQ_ERR1	5
#define BLINK_SEQ_DONE	8

// Flags that controll various things (their bit position)
#define FLAG_RUN_UPD	0		// bit = 1 -> Run the PWM update
#define FLAG_PWM_CONT	1		// bit = 0 -> Use current controll -||- bit = 1 -> Use voltage controll
#define FLAG_ADC_CHK	2		// bit = 0 -> Summing ADC current -||- bit = 1 -> Summing ADC voltage
#define FLAG_TIMER		3

// Maximum and minimum PWM dutys (safe guards)
#define PWM_MAX			255
#define PWM_MIN			5

//Timing constants
#define TIMER_1H		76200	// = 1h with time error corection
#define TIMER_3H		228600	// = 3h with time error corection

// ADC values that the controller works to achieve
#define ADC_AIM_CURR		414
#define ADC_AIM_VOLT		889
#define ADC_AIM_VOLT_LOW	821
#define ADC_MIN_CURR		5
#define ADC_MIN_VOLT		610

//Globals
volatile uint8_t flags = 0;
volatile uint8_t blink_seq = 0;
volatile uint16_t adc_value_c = 0;
volatile uint16_t adc_value_v = 0;
volatile uint16_t adc_aim = ADC_AIM_CURR;
volatile uint32_t timer_cnt = 0;

void init_ADC();
void ADC_off();
void init_PWM();
void PWM_off();
void init_DELAY();

int main(void)
{
	cli();
	CONTROL_DDR |= ((1<<RELAY_PIN)|(1<<LED_PIN));		// LED & Relay Outputs
	CONTROL_DDR &= ~((1<<I_ADC_PIN)|(1<<V_ADC_PIN));	// ADC Inputs
	CONTROL_PORT = 0;
	PWM_DDR |= (1<<PWM_PIN);							// PWM output
	PWM_PORT = 0;
	
	init_DELAY();
	init_ADC();
	sei();

	//--- HÄR IFRÅN ÄR PROBLEMET ---

	no_battery:											// If the battery is disconnected restart the program.
	PWM_off();
	flags = 0;											// Reset variables
	timer_cnt = 0;
	adc_value_c = 0;
	adc_value_v = 0;
	adc_aim = ADC_AIM_CURR;
	
	CONTROL_PORT |= (1<<RELAY_PIN);
	init_PWM();
	_delay_ms(30);

	/*--- Checking for battery ---*/
	blink_seq = BLINK_SEQ_ERR1;						// Start "waiting for battery"-blink
	while (adc_value_c < ADC_MIN_CURR);				// Check if battery is connected, if current flows then the battery is connected

	//--- TILL HIT ---

	blink_seq = BLINK_STOP;
	CONTROL_PORT |= (1<<LED_PIN);					// Start "battery charging"-light
	
	/*--- Starting first charging cycle with CC = 0.9A and CV = 29.3V ---*/
	while (timer_cnt < TIMER_3H)
	{
		if (adc_value_c < ADC_MIN_CURR)				// If the battery is disconnected restart the program.
			goto no_battery;

		if (adc_value_c > ADC_AIM_CURR)				// If the current has risen over the allowed limit, switch to CC
		{
			flags &= ~(1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_CURR;
		}

		else if (adc_value_v > ADC_AIM_VOLT)		// If the voltage has risen over the allowed limit, switch to CV
		{
			flags |= ((1<<FLAG_PWM_CONT)|(1<<FLAG_TIMER));	// Start counting timer_cnt when CV kicks in
			adc_aim = ADC_AIM_VOLT;
		}
	}

	/*--- Starting second charging cycle with CC = 0.9A and CV = 27V ---*/
	timer_cnt = 0;									// Reset timer_cnt, timer_cnt is still counting
	
	while (timer_cnt < TIMER_1H)
	{
		if (adc_value_c < ADC_MIN_CURR)				// If the battery is disconnected restart the program.
			goto no_battery;

		if (adc_value_c > ADC_AIM_CURR)				// If the current has risen over the allowed limit, switch to CC
		{
			flags &= ~(1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_CURR;
		}

		else if (adc_value_v > ADC_AIM_VOLT_LOW)	// If the voltage has risen over the allowed limit, switch to CV
		{
			flags |= (1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_VOLT_LOW;
		}
	}

	/*--- Charge completed! Continue with tickle charge CV = 27V ---*/
	blink_seq = BLINK_SEQ_DONE;
	
	while (1)
	{
		if (adc_value_c < ADC_MIN_CURR)				// If the battery is disconnected restart the program.
			goto no_battery;

		if (adc_value_c > ADC_AIM_CURR)				// If the current has risen over the allowed limit, switch to CC
		{
			flags &= ~(1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_CURR;
		}

		else if (adc_value_v > ADC_AIM_VOLT_LOW)	// If the voltage has risen over the allowed limit, switch to CV
		{
			flags |= (1<<FLAG_PWM_CONT);
			adc_aim = ADC_AIM_VOLT_LOW;
		}
	}
}

void init_ADC()
{
	ADCSRA |= ((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADATE)); 	// ADC prescaler 128 - Autotrigger
	ADMUX &= ~((1<<REFS0)|(1<<REFS1));							// Vcc as voltage reference
	ADCSRB &= ~((1<<ADTS0)|(1<<ADTS1)|(1<<ADTS2)); 				// Free running mode
	ADCSRA |= ((1<<ADIE)|(1<<ADEN)|(1<<ADSC));					// Interupt enable - Enable ADC - Start conversion
	ADMUX &= ~0b00111111;										// Start with a current reading
}

void ADC_off()
{
	ADCSRA &= ~((1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0)|(1<<ADATE));
	ADCSRA &= ~((1<<ADIE)|(1<<ADEN)|(1<<ADSC));
}

void init_DELAY()
{
	TCCR1B |= ((1<<WGM12)|(1<<CS10)|(1<<CS12));					// Start Timer1, CTC mode, 1024 prescaler
	TIMSK1 |= (1<<OCIE1A); 										// Compare interupt
	OCR1AH = 1;
	OCR1AL = 105; 												// 8000000Hz / 1024 / 390 = ~20Hz
}

void init_PWM()
{
	TCCR0A |= ((1<<WGM00)|(1<<WGM01)|(1<<COM0A1));				// Start Timer0, Fast PWM mode, output pin OC0A (PB2)
	TCCR0B |= (1<<CS00);										// No prescaler, 8000000Hz / 256 = ~31 250Hz PWM
	OCR0A = 20;
}

void PWM_off()
{
	OCR0A = 0;
	TCCR0A &= ~((1<<WGM00)|(1<<WGM01)|(1<<COM0A1));				// Start Timer0, Fast PWM mode, output pin OC0A (PB2)
	TCCR0B &= ~(1<<CS00);										// No prescaler, 8000000Hz / 256 = ~31 250Hz PWM
}

ISR(TIM1_COMPA_vect)
{
	const static uint8_t blinklist[] = {0,3,3,3,3,3,20,0,20,20,0};
	static uint8_t cnt = 0;
	static uint8_t count = 0;
	static uint8_t ptr = 0;	
	static uint16_t adc_value = 0;

	if (flags & (1<<FLAG_PWM_CONT))							// Check if Current or Voltage controll
		adc_value = adc_value_v;							// and adjust adc_value
	else
		adc_value = adc_value_c;

	if (cnt & 1)
	{
		if ((adc_value > adc_aim) && (OCR0A > PWM_MIN))			// Adjust PWM Duty, if needed
			OCR0A--;
			
		else if ((adc_value < adc_aim) && (OCR0A < PWM_MAX))
			OCR0A++;
	}
	
	if ((cnt >= count) && (blink_seq != 0))					
	{
		cnt = 0;
		count = blinklist[ptr++];

		if (count == 0)
		{
			CONTROL_PORT &= ~(1<<LED_PIN);
			ptr = blink_seq;
		}
		else
			CONTROL_PORT ^= (1<<LED_PIN);
	}
	
	if (flags & (1<<FLAG_TIMER))
		timer_cnt++;

	cnt++;
}


ISR(ADC_vect)								// Sum 64 readings and then divide by 64 for average 
{											// Every second is voltage average and the other is current average
	static uint8_t cnt = 0;
	static uint16_t sum = 0;
	
	if (cnt >= 63)
	{
		if (flags & (1<<FLAG_ADC_CHK))
		{
			adc_value_v = (sum>>6);
			ADMUX &= ~0b00111111; 			// Clear all MUX0..5 - ADC on ADC0 pin (PA0) (current reading)
			flags &= ~(1<<FLAG_ADC_CHK);	// Set flags for current reading
		}
		else
		{
			adc_value_c = (sum>>6);
			ADMUX |= (1<<MUX0);				// ADC on ADC1 pin (PA1) (voltage reading)
			flags |= (1<<FLAG_ADC_CHK);		// Set flags for voltage reading
		}

		cnt = 0;
		sum = 0;
	}
	else
	{
		sum += ADCL;
		sum += (ADCH<<8);
		cnt++;
	}
}
blueint
Inlägg: 23238
Blev medlem: 4 juli 2006, 19:26:11
Kontakt:

Re: Bärbar högtalare och SMPS som laddare (mkt bilder!)

Inlägg av blueint »

Strömmen kanske går via lasten istället för batteriet?

Kontrollmät shunten. Gör en koll vilken väg strömmarna går.

Bild
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Re: Bärbar högtalare och SMPS som laddare (mkt bilder!)

Inlägg av Korken »

Japp, precis det där jag kom på. :)
Så jag beräknade (simulerade) hur mycket AC som går igenom kondensatorn och har satt mitt min värde på strömmen efter det.
Men får behålla spännings koll som första steg, när jag har låg duty så har jag störst rippel, men spännings kollen fungerar bra bara man väntar några sek så kondingarna hinner ladda ur sig efter man har kopplat ur batteriet.

Så nu testar jag alla funktionerna igen. :)
Ska bli kul om allt fungerar som det ska, hoppas iaf. :pray: :wink:
Användarvisningsbild
Korken
Inlägg: 2230
Blev medlem: 3 februari 2006, 19:19:36
Ort: Luleå, Porsön

Re: Bärbar högtalare och SMPS som laddare (mkt bilder!)

Inlägg av Korken »

Så, nu har jag strukit ut alla buggar och den har gjort ca 10st laddningar utan ett ända fel! :D
Nya koden ligger i första inlägget och detta projekt är nu klart.

För det som gillade detta så har designen av version 2 av denna högtalare påbörjats.
Vad som är skillnaden är att den kommer vara ca ½ så stor, ha LiPo batteri och extern kraftkälla (en Powerbrick) istället för en inbyggd, men laddaren kommer vara inbyggd.
Samt för att bära den så ska den ha remmar, så den kan bäras som en ryggsäck eller på axeln.
Tanken är att den ska vara mer portabel men fortfarande ha bra "kick". :)
Dock så kommer det ta ett tag innan jag startar detta, ska vara säker på vad jag gör så det blir mer eller mindre perfekt.

De va allt för mig!

Mvh
Emil Fresk
Skriv svar