ATtiny45 převod ADC

C,C++,C#

Moderátori: psichac, Moderátori

Používateľov profilový obrázok
jirka.jirka.
Ultimate člen
Ultimate člen
Príspevky: 1537
Dátum registrácie: 17 Okt 2008, 00:00
Bydlisko: Uherské Hradiště
Kontaktovať používateľa:

ATtiny45 převod ADC

Príspevok od používateľa jirka.jirka. » 25 Sep 2016, 14:16

Zdravím přátelé.

Mám malý problém s ADC-čkem u ATtiny45. Napsal jsem si jednoduchý program, který má za úkol měřit napětí na dvou hall sondách ACS712.
Tyto sondy mají na výstupu napětí 2,5V a podle proudu potom buť zvyšují výstup, nebo snižují.

Takže dejme tomu, že defaultně mám na vstupu hodnotu 2,5V. Referenci mám externí 3V. Potom hodnota ADC bude 853. Jakmile připojím zátěž, tak na výstupu budu mít třeba 2,6V, což odpovídá ADC = 887.

Pokud dojde k tomu, že hodnota výchozí je menší než aktuálně naměřená, dojde k překlopení výstupu.

Program takhle funguje, ale mám problém s tím, že místo toho, aby byl výstup trvale seplý (pokud teče proud), tak mi výstup pulzuje. Proto se obracím sem, jestli někdo v těch mých pár řádcích neuvidí nějakou chybu. Díky moc

Init ADC.

Kód: Vybrať všetko

void init_adc()
{
	/* Nastaveni externi reference na pinu PB0 */
	ADMUX |=  (1 << REFS0);
	ADMUX &= ~(1 << REFS1);

	/* povoli ADC */
	ADCSRA |= (1 << ADEN);

	/* preruseni od ADC */
	ADCSRA |= (1 << ADIF);

	/* nastavi delicku na 64 (125kHz) */
	ADCSRA |= (1 << ADPS2);
	ADCSRA |= (1 << ADPS1);
	ADCSRA &=~(1 << ADPS0);
}
Fce pro výčet hodnoty ADC

Kód: Vybrať všetko

unsigned int Read_ADC(unsigned char channel){
	
	// vloz cislo kanala, vymaskuj nepouzite bity
	ADMUX &= 0xF0;
	ADMUX |= channel & 0x0F;
	
	// Start prevodu
	ADCSRA |= (1 << ADSC);
	
	// ceka, dokud se neskonci konverze
	while(!(ADCSRA & (1<<ADIF)));
	
	//  navratova hodnota - vysledok ad prevodu
	return ADC;
	
}
Komplet program:

Kód: Vybrať všetko

/*
 * DEKM.c
 *
 * Created: 25.9.2016 10:55:13
 * Author : Jirka
 */ 

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

#define		OUT1	PB1
#define		OUT2	PB3

unsigned int Read_ADC(unsigned char channel){
	
	// vloz cislo kanala, vymaskuj nepouzite bity
	ADMUX &= 0xF0;
	ADMUX |= channel & 0x0F;
	
	// Start prevodu
	ADCSRA |= (1 << ADSC);
	
	// ceka, dokud se neskonci konverze
	while(!(ADCSRA & (1<<ADIF)));
	
	//  navratova hodnota - vysledok ad prevodu
	return ADC;
	
}

void init_adc()
{
	/* Nastaveni externi reference na pinu PB0 */
	ADMUX |=  (1 << REFS0);
	ADMUX &= ~(1 << REFS1);

	/* povoli ADC */
	ADCSRA |= (1 << ADEN);

	/* preruseni od ADC */
	ADCSRA |= (1 << ADIF);

	/* nastavi delicku na 64 (125kHz) */
	ADCSRA |= (1 << ADPS2);
	ADCSRA |= (1 << ADPS1);
	ADCSRA &=~(1 << ADPS0);
}

void init_output()
{
	DDRB |= (1 << OUT1);	//tento piny jako vystupni
	DDRB |= (1 << OUT2);	//tento piny jako vystupni

	PORTB |= (1 << OUT1) | (1 << OUT2);	//nastavi pullup odpory

}

int main(void)
{
	/* inicializace ADC */
	init_adc();
	/* inicializace vystupu */
	init_output();
	/* povoleni preruseni */
	sei();

	uint16_t adc1 = 0, adc2 = 0, initADC1 = 0, initADC2 = 0, pomocna1 = 0, pomocna2 = 0;
	pomocna1 = Read_ADC(1);
	pomocna2 = Read_ADC(2);

	pomocna1 = 0; pomocna2 = 0;
	for (int i = 0; i < 5; i++)
	{
		pomocna1 += Read_ADC(1);	//po zapnuti vyctu hodnotu z ADC pro lepsi stabilitu
		_delay_ms(1);
		pomocna2 += Read_ADC(2);	//po zapnuti vyctu hodnotu z ADC pro lepsi stabilitu
		_delay_ms(1);
	}
	initADC1 = pomocna1 / 5;
	initADC2 = pomocna2 / 5;

    /* Replace with your application code */
    while (1) 
    {
		/* prumer z 5 hodnot */
		pomocna1 = 0;	pomocna2 = 0;
		for (int i = 0; i < 5; i++)
		{
			pomocna1 += Read_ADC(1);
			_delay_ms(2);
			pomocna2 += Read_ADC(2);
			_delay_ms(2);
		}
		adc1 = pomocna1 / 5;
		adc2 = pomocna2 / 5;
			
		if (adc1 > (initADC1+10 ) )	//hodnota 850 prevedeno na napeti (850*3)/2^10 = 2,49V (kde 10 odpovida zmene napeti o 0,03V)
			PORTB &= ~(1 << OUT1);
		else
			PORTB |= (1 << OUT1);

		if (adc2 > (initADC2+10) )
			PORTB &= ~(1 << OUT2);
		else
			PORTB |= (1 << OUT2);
    }
}

Prílohy
Nastavení pojistek
Nastavení pojistek
0

StavJi
Okoloidúci
Okoloidúci
Príspevky: 42
Dátum registrácie: 22 Jan 2014, 14:01
Bydlisko: Olomouc

Re: ATtiny45 převod ADC

Príspevok od používateľa StavJi » 25 Sep 2016, 14:33

Víš jaké hodnoty ti to měří? Máš možnost si je poslat?

Jinak já používám něco takového

Kód: Vybrať všetko

unsigned int ADC_Read(unsigned char pin)
{
	ADMUX = (1 << REFS0) | (1 << ADLAR) | (7 & pin);	// reference = AVcc, zarovnání vlevo, nastavení PINu
	_delay_us(10);	// počkat (eliminuje ovlivňování kanálů), čekání na nabití ADC kapacity
	ADCSRA |= (1 << ADSC);	// start převodu
	while((ADCSRA & (1 << ADSC)) != 0);	// čekání na konec převodu
	ADMUX = (1 << REFS0) | (1 << ADLAR) | 15;	// přepnutí vstupu na 0V (eliminuje ovlivňování kanálů)
	return ((ADCL >> 6) | (ADCH << 2));	// pro ADLAR=0: ((ADCH << 8) | ADCL);
}
}
Jinak ten kód je celkem hnus hlavně ten klouzavej filtr s těma delay funkcema v hlavní smyčce. Klouzavej filtr se počítá pomocí bitových operací http://petr-kubac.blog.cz/1308/matemati ... avy-prumer . A místo delay funkcí můžeš použít jeden časovač nastavenej třeba na 1 ms pomocí kterého nastavuješ co se má dělat. Třeba vzorkovat tlačítka, měřit, překreslovat LCD atd.
0

Používateľov profilový obrázok
jirka.jirka.
Ultimate člen
Ultimate člen
Príspevky: 1537
Dátum registrácie: 17 Okt 2008, 00:00
Bydlisko: Uherské Hradiště
Kontaktovať používateľa:

Re: ATtiny45 převod ADC

Príspevok od používateľa jirka.jirka. » 25 Sep 2016, 14:43

jj. Ty delay teď ostraňuju. Taky se mi to moc nelíbilo. Ale když ten program nemá dělat nic jiného, tak jsem to zkoušel skrze ně.
0

StavJi
Okoloidúci
Okoloidúci
Príspevky: 42
Dátum registrácie: 22 Jan 2014, 14:01
Bydlisko: Olomouc

Re: ATtiny45 převod ADC

Príspevok od používateľa StavJi » 25 Sep 2016, 17:30

Jako jestli na to nebude nic navazovat a bude to dělat jen to co jsi poslal, tak nevidím problém proč to dělat složitější. Spíš pro příště nebo při nějakém rozšíření.
0

Používateľov profilový obrázok
jirka.jirka.
Ultimate člen
Ultimate člen
Príspevky: 1537
Dátum registrácie: 17 Okt 2008, 00:00
Bydlisko: Uherské Hradiště
Kontaktovať používateľa:

Re: ATtiny45 převod ADC

Príspevok od používateľa jirka.jirka. » 25 Sep 2016, 17:38

No toto má pouze monitorovat dva ADC kanály. Podle toho rozhodnout jak nastavit výstup. Teď se snažím rozchodit ten klouzavý průměr, ale nedaří se.


Nemáte někdo nějaký příklad, jak ADC hodnot tento klouzavý průměr udělat?
0

Používateľov profilový obrázok
Najgel
Ultimate člen
Ultimate člen
Príspevky: 1695
Dátum registrácie: 02 Júl 2010, 00:00
Bydlisko: Námestovo, Žilina(škola)
Vek: 29

Re: ATtiny45 převod ADC

Príspevok od používateľa Najgel » 25 Sep 2016, 18:02

Vždy sčítaj 2 čísla a vydeľ dvoma. (Read1 + Read2 ) / 2= Vysledok1 ... (Vysledok1 + Read3 )/2 = Vysledok2 ... (Vysledok2 + Read4)/2 = Vysledok3 atd...
0
Keď neodpisujem tak tu nie som, alebo som a neodpisujem :D

MPLAB & PIC
Texas Instruments DSP TMS320Fxxxxx
Tevo Tarantula 3D
Ponúkam 3D tlač.
Ponúkam návrh a vývoj elektroniky na zákazku.

UNIZA 5.ročník

Používateľov profilový obrázok
vosa
Stály člen
Stály člen
Príspevky: 103
Dátum registrácie: 24 Okt 2012, 09:34
Bydlisko: Bratislava

Re: ATtiny45 převod ADC

Príspevok od používateľa vosa » 26 Sep 2016, 00:02

Uz dlho som nekodil. Mozem sa opytat preco su tam zapnute prerusenia? Ak k nejakemu dojde a premenne nemas volatilne, tak sa resetnu.

K prispevku od Najgela. Myslim, ze iterativny priemer sa pocita inak: http://www.heikohoffmann.de/htmlthesis/node134.html
Pre delenie dvojkou potom pouzi binarny shift, kedze sa robi v cykle.
0

Používateľov profilový obrázok
jirka.jirka.
Ultimate člen
Ultimate člen
Príspevky: 1537
Dátum registrácie: 17 Okt 2008, 00:00
Bydlisko: Uherské Hradiště
Kontaktovať používateľa:

Re: ATtiny45 převod ADC

Príspevok od používateľa jirka.jirka. » 01 Okt 2016, 20:49

Zdravím páni. Opět jsem se vrátil k tomu měření na hallových sondách.

Mám ACS712 - 5A.

Ale, program se chová pořád trošku divně.

Výstup na hallově sondě je bez procházejícího proudu 2,47V (Vcc/2). Pokud přivedu zátěž (odběr cca 200mA), tak na výstupu mám napětí 2,5V. Což je rozdíl 30mV.

Jako první co udělám při zapnutí AVR je, že si změřím výstupní napětí (tzn. bez připojené zátěže). Potom jsem si vytvořil TIMER, který má periodu 10ms, kde nastavuju příznak, ať mi změří napětí a toto potom stále porovnávám. Mám externí referenci 3V. Hodnota na ACS drží, na tu jsem koukal hned jako první.

Tzn. hodnota 30mV je převedeno do ADC hodnoty = 10.
A porovnávám hodnotu:

Kód: Vybrať všetko

if (adc1 > (initADC1 + 10) )
			PORTB &= ~(1 << OUT1);
		else
			PORTB |= (1 << OUT1);
A nyní, když mám na výstupu napětí vyšší než 2,5V, tak mi výstup kmitá (tzn. že program mi spíná a rozpíná kontakt). Pouze pokud zátěž adekvátně snížím (tzn. zvýším protékající proud) na výstupu je tudíž vyšší napětí, tak se mi výstup přepne do log 1. Ale tady se bavíme o proudu cca 400mA. Však se na výstup podívejte sami.
Obrázok

Zde je komplet program, bez inicializačních funkcí.

Kód: Vybrať všetko


unsigned int Read_ADC(unsigned char channel){
	
	ADMUX = (1 << ADLAR) | (7 & channel);   // reference = AVcc, zarovnání vlevo, nastavení PINu
	_delay_us(25);   // počkat (eliminuje ovlivňování kanálů), čekání na nabití ADC kapacity
	ADCSRA |= (1 << ADSC);   // start převodu
	while((ADCSRA & (1 << ADSC)) != 0);   // čekání na konec převodu
	ADMUX = (1 << ADLAR) | 15;   // přepnutí vstupu na 0V (eliminuje ovlivňování kanálů)
	return ((ADCL >> 6) | (ADCH << 2));   // pro ADLAR=0: ((ADCH << 8) | ADCL);
}

volatile char flag = 0;
ISR (TIMER0_COMPA_vect)	//preruseni nastane kazdych 10ms
{
 	flag = 1;
}

uint16_t initADC1 = 0, initADC2 = 0;
uint16_t pomocna1 = 0, pomocna2 = 0, adc1 = 0, adc2 = 0;
int main(void)
{
	/* inicializace ADC */
	init_adc();
	/* inicializace vystupu */
	init_output();
	/* inicializace timeru */
	init_timer();
	/* povoleni preruseni */
	sei();

	for (int i = 0; i < 10; i++)
	{
		pomocna1 += Read_ADC(1);	//po zapnuti vyctu hodnotu z ADC pro lepsi stabilitu
		pomocna2 += Read_ADC(2);	//po zapnuti vyctu hodnotu z ADC pro lepsi stabilitu
	}
	initADC1 = pomocna1 / 10;
	initADC2 = pomocna2 / 10;

    while (1) 
    {
		if (flag == 1)
		{
			adc1 = Read_ADC(1);
			adc2 = Read_ADC(2);
			flag = 0;
		}

		/* nastavuje vystupy, podle namereneho napeti */
		if (adc1 > (initADC1 + 10) )	//hodnota 850 prevedeno na napeti (850*3)/2^10 = 2,49V (kde 10 odpovida zmene napeti o 0,03V)
			PORTB &= ~(1 << OUT1);
		else
			PORTB |= (1 << OUT1);

		if (adc2 > (initADC2 + 10) )
			PORTB &= ~(1 << OUT2);
		else
			PORTB |= (1 << OUT2);

    }
}
Zde jsou pouze inicializační funkce.

Kód: Vybrať všetko

void init_adc()
{
	/* Nastaveni externi reference na pinu PB0 */
	ADMUX |=  (1 << REFS0);
	ADMUX &= ~(1 << REFS1);
	/* preruseni od ADC */
	ADCSRA |= (1 << ADIF);
	/* nastavi delicku na 64 (125kHz) */
	ADCSRA |= (1 << ADPS2);
	ADCSRA |= (1 << ADPS1);
	ADCSRA &=~(1 << ADPS0);
	/* povoli ADC */
	ADCSRA |= (1 << ADEN);
}

void init_timer() 
{
	// CTC mode
	TCCR0A |= (1 << WGM01); 
	//1024 prescaller
	TCCR0B |= (1 << CS00);
	TCCR0B &= ~(1 << CS01);
	TCCR0B |= (1 << CS02);
	// OCR0A interrupt only.
	TIMSK |= (1 << OCIE0A); 
	//10ms
	OCR0A = 79; 
}

void init_output()
{
	DDRB |= (1 << OUT1);	//tento piny jako vystupni
	DDRB |= (1 << OUT2);	//tento piny jako vystupni

	PORTB |= (1 << OUT1) | (1 << OUT2);	//nastavi pullup odpory
}
0

peterple
Ultimate člen
Ultimate člen
Príspevky: 2328
Dátum registrácie: 25 Jún 2013, 21:06
Bydlisko: Krajné
Vek: 57
Kontaktovať používateľa:

Re: ATtiny45 převod ADC

Príspevok od používateľa peterple » 01 Okt 2016, 21:59

ten prúd záťaže je teda jednosmerný, keď píšeš že sa nemení? Nie je tam ani žiadne PWM?
Najjednoduchšie je si logovať namerané hodnoty na sériový port a sledovať terminálom. Takto len hádaš čo sa asi vnútri deje.
Ak sa ti to nedá tak by som zaviedol hysteréziu a postupne ju zvyšoval. Tak by sa tiež dalo nepriamo zistiť v akom rozsahu prevodník hádže čísla. Alebo si ukladať min a max a zobrazovať si to na LCD. Bez debugu sa takéto veci zle vyvíjajú.
0
Ukáž múdremu chybu a on sa ti poďakuje. Ukáž chybu hlupákovi a on sa urazí.

Používateľov profilový obrázok
jirka.jirka.
Ultimate člen
Ultimate člen
Príspevky: 1537
Dátum registrácie: 17 Okt 2008, 00:00
Bydlisko: Uherské Hradiště
Kontaktovať používateľa:

Re: ATtiny45 převod ADC

Príspevok od používateľa jirka.jirka. » 01 Okt 2016, 22:03

Vím že bez debugu to jde špatně, ale nemám teď nic po ruce. Mám jenom attiny45, hallovku a USBasp. Zbytek zůstal doma. A kdy se vrátím domů to sám netuším.

Takže jsem tuto konverzi trošku poladil. Je vidět zlepšení, ale pořád ten výstup není optimální.

Upravil jsem inizializaci ADC:

Kód: Vybrať všetko

void init_adc()
{
	/* Nastaveni externi reference na pinu PB0 */
	ADMUX |=  (1 << REFS0);
	ADMUX &= ~(1 << REFS1);
	/* preruseni od ADC */
	ADCSRA |= (1 << ADIF);
	/* nastavi delicku na 64 (125kHz) */
	ADCSRA |= (1 << ADPS2);
	ADCSRA |= (1 << ADPS1);
	ADCSRA &=~(1 << ADPS0);
	/* povoli ADC */
	ADCSRA |= (1 << ADEN);
	ADCSRA |= (1<<ADSC);   // zapne konverzi
	while (ADCSRA & (1<<ADSC) ) { }  // ceka na dokonceni konverze 
	(void) ADCW;	//"vycte se ADCW"
}
Dále jsem upravil vyčítání ADC:

Kód: Vybrať všetko

uint16_t ADC_Read( uint8_t channel )
{
	// Vyber kanalu
	ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
	ADCSRA |= (1<<ADSC);            // Zapne konverzi
	while (ADCSRA & (1<<ADSC) ) { }  // ceka na dokonceni konverze
	return ADCW;                    // navrati hodnotu ADC
}
Teď jdu zkusit ten klouzavý průměr, ale myslím si, že tímto to nebude. Zde by mě mohl stačit i klasický aritmetický průměr.

Jinak proud je stejnosměrný. Aspoň že tak.
0

peterple
Ultimate člen
Ultimate člen
Príspevky: 2328
Dátum registrácie: 25 Jún 2013, 21:06
Bydlisko: Krajné
Vek: 57
Kontaktovať používateľa:

Re: ATtiny45 převod ADC

Príspevok od používateľa peterple » 01 Okt 2016, 22:09

tak si to pošli von sériovo na nejaký pin (MOSI) a naber to skopom a je.
0
Ukáž múdremu chybu a on sa ti poďakuje. Ukáž chybu hlupákovi a on sa urazí.

Používateľov profilový obrázok
jirka.jirka.
Ultimate člen
Ultimate člen
Príspevky: 1537
Dátum registrácie: 17 Okt 2008, 00:00
Bydlisko: Uherské Hradiště
Kontaktovať používateľa:

Re: ATtiny45 převod ADC

Príspevok od používateľa jirka.jirka. » 01 Okt 2016, 22:16

Naštěstí mám na PB3 jenom tranzistor, takže hned zítra tam pověsím převodník a budu si posílat data po sériovce a budu moudřejší. Aspoň budu vědět, co vyčítám.
0

peterple
Ultimate člen
Ultimate člen
Príspevky: 2328
Dátum registrácie: 25 Jún 2013, 21:06
Bydlisko: Krajné
Vek: 57
Kontaktovať používateľa:

Re: ATtiny45 převod ADC

Príspevok od používateľa peterple » 01 Okt 2016, 22:19

ja by som teraz vyskúšal urobiť mrtvé pásmo +-1 potom +-2 atd
na niekoľko pokusov by si mohol zistiť o koľko ti to tam lieta.
0
Ukáž múdremu chybu a on sa ti poďakuje. Ukáž chybu hlupákovi a on sa urazí.

Používateľov profilový obrázok
jirka.jirka.
Ultimate člen
Ultimate člen
Príspevky: 1537
Dátum registrácie: 17 Okt 2008, 00:00
Bydlisko: Uherské Hradiště
Kontaktovať používateľa:

Re: ATtiny45 převod ADC

Príspevok od používateľa jirka.jirka. » 01 Okt 2016, 23:21

No takže úpravou přerušení od TIMERu, úpravou předděličky u ADC, přidání krátkého delay do vyčítání ADC a průměrováním hodnot, jsem se dopracoval stabilnímu řešení. Od 130mA mám výstup trvale v log. 1. Zítra ještě mrknu na ty hodnoty ADC přes UART ať vím co se té v té Attině honí za hodnoty.

Výčet hodnot z ADC a průměrování:

Kód: Vybrať všetko

uint16_t ADC_Read( uint8_t channel )
{
	// Vyber kanalu
	ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
	ADCSRA |= (1<<ADSC);            // Zapne konverzi
	while (ADCSRA & (1<<ADSC) ) { }  // ceka na dokonceni konverze
	return ADCW;                    // navrati hodnotu ADC
}


uint16_t ADC_Read_Avg( uint8_t channel, uint8_t nsamples )	//jenom jednoduchy prumer
{
	uint32_t sum = 0;

	for (uint8_t i = 0; i < nsamples; ++i ) {
		sum += ADC_Read( channel );
		_delay_us(10);
	}

	return (uint16_t)( sum / nsamples );
}
Init ADC

Kód: Vybrať všetko

void init_adc()
{
	/* Nastaveni externi reference na pinu PB0 */
	ADMUX |=  (1 << REFS0);
	ADMUX &= ~(1 << REFS1);
	/* preruseni od ADC */
	ADCSRA |= (1 << ADIF);
	/* nastavi delicku na 128 (62,5kHz) */
	ADCSRA |= (1 << ADPS2);
	ADCSRA |= (1 << ADPS1);
	ADCSRA |= (1 << ADPS0);
	/* povoli ADC */
	ADCSRA |= (1 << ADEN);
	ADCSRA |= (1<<ADSC);   // zapne konverzi
	while (ADCSRA & (1<<ADSC) ) { }  // ceka na dokonceni konverze 
	(void) ADCW;	//"vycte se ADCW"
}
Init Timer

Kód: Vybrať všetko

void init_timer() 
{
	// CTC mode
	TCCR0A |= (1 << WGM01); 
	//1024 prescaller
	TCCR0B |= (1 << CS00);
	TCCR0B &= ~(1 << CS01);
	TCCR0B |= (1 << CS02);
	// OCR0A interrupt only.
	TIMSK |= (1 << OCIE0A); 
	//79 = 10ms; 39 = 5ms; 23 = 3ms; 8 = 1ms
	OCR0A = 39; 
}
A nakonec nekonečná smyčka:

Kód: Vybrať všetko

while (1) 
    {
		if (flag == 1)
		{
			adc1 = ADC_Read_Avg(1, 60);
			adc2 = ADC_Read_Avg(2, 60);
			flag = 0;
		}

 		/* nastavuje vystupy, podle namereneho napeti */
		if (adc1 > (initADC1 + 2) )	//hodnota 850 prevedeno na napeti (850*3)/2^10 = 2,49V (kde 10 odpovida zmene napeti o 0,03V)
			PORTB &= ~(1 << OUT1);
		else
			PORTB |= (1 << OUT1);

		if (adc2 > (initADC2 + 2) )
			PORTB &= ~(1 << OUT2);
		else
			PORTB |= (1 << OUT2);
    }
0

Zahor1
Okoloidúci
Okoloidúci
Príspevky: 20
Dátum registrácie: 03 Mar 2017, 23:09
Vek: 49

Re: ATtiny45 převod ADC

Príspevok od používateľa Zahor1 » 08 Mar 2017, 21:48

Občas sa hrám s arduinom. Mal som podobný problém
RGB dióda sa mala stievať, meniť farbu podľa intenzity osvetlenia, na to tam boli 3 fotoodpory, namiesto toho aby sa stiemavali jednotlivé farby podľa hodnoty fotoodporu kdejako blikala a bola neustálená.
Vyriešil som to vyhladením (spriemerovaním) hodnôt potom to už nebol problém.
je to kód Arduina ale pointa je jednoduchá. Využil som na to základ z tohto kódu.

http://www.instructables.com/id/Arduino-EMF-Detector/
https://cdn.instructables.com/ORIG/FPD/ ... HVHG23.txt
moja verzia má 3 kanály RGB a počet načítaných hodnôt na spriemerovanie je 128 (viac nepustila pamäť arduina )

Kód: Vybrať všetko


#define sample 128

const int ledzelenypin=9;
const int ledcervenypin=11;
const int ledmodrypin=10;
const int cervenySpin=A0;
const int zelenySpin=A1;
const int modrySpin=A2;
const int ledpin=13;
int cervena=0;
int modra=0;
int zelena=0;


//spriemerovanie hodnot
float hodnotar;
float hodnotag;
float hodnotab; 
 
int arrayr[sample];
int arrayg[sample];
int arrayb[sample];

unsigned long averagingr;
unsigned long averagingg;
unsigned long averagingb;

//autokalibrácia podla svetla
int mincervena=1023;
int maxcervena=0;
int minzelena=1023;
int maxzelena=0;
int minmodra=1023;
int maxmodra=0;
int hodnotasenzoru;
int unsigned long intervalkalib;

void setup() {
  // put your setup code here, to run once:
Serial.begin (9600);
pinMode(ledzelenypin , OUTPUT);
pinMode(ledcervenypin , OUTPUT);
pinMode(ledmodrypin , OUTPUT);
pinMode(ledpin , OUTPUT);
digitalWrite(ledpin, LOW);
//zaciatok kalibrácie 
delay (1000);
blik(1);
//cervena
Serial.println("kalibracia cervena ");
intervalkalib=millis();
digitalWrite(ledpin, HIGH);
while (millis() < intervalkalib+5000) {
 hodnotasenzoru = analogRead(cervenySpin) ;
 if (hodnotasenzoru > maxcervena)maxcervena=hodnotasenzoru;
  if (hodnotasenzoru < mincervena)mincervena=hodnotasenzoru;
}

digitalWrite(ledpin, LOW);
delay (1000);
blik(2);

//zelena
Serial.println("kalibracia zelena ");
intervalkalib=millis();
digitalWrite(ledpin, HIGH);
while (millis() < intervalkalib+5000) {
 hodnotasenzoru = analogRead(zelenySpin) ;
 if (hodnotasenzoru > maxzelena)maxzelena=hodnotasenzoru;
  if (hodnotasenzoru < minzelena)minzelena=hodnotasenzoru;
}

digitalWrite(ledpin, LOW);
delay (1000);
blik(3);

//modra
Serial.println("kalibracia modra ");
intervalkalib=millis();
digitalWrite(ledpin, HIGH);
while (millis() < intervalkalib+5000) {
 hodnotasenzoru = analogRead(modrySpin) ;
 if (hodnotasenzoru > maxmodra)maxmodra=hodnotasenzoru;
  if (hodnotasenzoru < minmodra)minmodra=hodnotasenzoru;
}

digitalWrite(ledpin, LOW);
delay (1000);

}

void loop() {
  // put your main code here, to run repeatedly:

//nacitanie retazcov na priemerovanie
for(int i = 0; i < sample; i++){
   //cervena
   arrayr[i] = analogRead(cervenySpin);
   averagingr += arrayr[i];
  
   //zelena
   arrayg[i] = analogRead(zelenySpin);
   averagingg += arrayg[i];

   //modra
   arrayb[i] = analogRead(modrySpin);
   averagingb += arrayb[i];   
}

//spriemerovanie
//cervena 
hodnotar = averagingr / sample;
hodnotar = constrain(hodnotar, mincervena, maxcervena);
cervena = map(hodnotar, mincervena, maxcervena, 0, 255);
averagingr=0;

//zelena 
hodnotag = averagingg / sample;
hodnotag = constrain(hodnotag, minzelena, maxzelena);
zelena = map(hodnotag, minzelena, maxzelena, 0, 255);
averagingg=0;

//modra 
hodnotab = averagingb / sample;
hodnotab = constrain(hodnotab, minmodra, maxmodra);
modra = map(hodnotab, minmodra, maxmodra, 0, 255);
averagingb=0;

//vypis na obrazovku co sa deje  
Serial.print("Data \t Cervena: ");
Serial.print(hodnotar);
Serial.print("\t Zelena: ");
Serial.print(hodnotag);
Serial.print("\t Modra: ");
Serial.println(hodnotab);

Serial.print("Hodnota RGB \t Cervena: ");
Serial.print(cervena);
Serial.print("\t Zelena: ");
Serial.print(zelena);
Serial.print("\t Modra: ");
Serial.println(modra);

//zapísanie hodnot PWM
analogWrite (ledcervenypin, cervena);
analogWrite (ledzelenypin, zelena);
analogWrite (ledmodrypin, modra);

}
void blik(int x) {
for(int j = 0; j < x; j++){
digitalWrite(ledpin, HIGH);
delay (500);
digitalWrite(ledpin, LOW);
delay (500);  
}
}


0
..... a skúsili ste to najskôr vypnúť a zapnúť?

Napísať odpoveď