Operácie

Metódy zvýšenie presnosti A/D prevodu: Rozdiel medzi revíziami

Zo stránky SensorWiki

StudentMIPS (diskusia | príspevky)
StudentMIPS (diskusia | príspevky)
 
(22 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 18: Riadok 18:
== Analýza  a opis riešenia ==
== Analýza  a opis riešenia ==


Cielom zadania je porovnat 3 odlisne metody ziskavania dat z A/D prevodnika. Po interakcii s uzivatelom, ktory mu zada napatie VREF (potrebne na prepocet nameranej hodnoty v bitoch na realnu hodnotu v mV) a realneho meraneho napatia (potrebne na statisticke vyhodnotenie posunu), program automaticky zoberie potrebne mnozstvo vzoriek z kazdej meracej metody a vykona aj statisticke vyhodnotenie ktore zobrazi uzivatelovi. Interakcia s uzivatelom prebieha prostrednictvom seriovej linky - cez terminal PuTTY.
Cieľom zadania je porovnať 3 odlišné metódy získavania dát z A/D prevodníka. Po interakcii s používateľom, ktorý zadá napätie VREF (potrebné na prepočet nameranej hodnoty v bitoch na reálnu hodnotu v mV) a reálne merané napätie (potrebné na štatistické vyhodnotenie posunu), program automaticky namerá potrebné množstvo vzoriek z každej meracej metódy a vykoná aj štatistické vyhodnotenie, ktoré zobrazí používateľovi. Interakcia s používateľom prebieha prostredníctvom sériovej linky cez terminál PuTTY.
=== Vyhodnocovacie metody===
===Vyhodnocovacie metódy===
Pre vyhodnotenie dat vyuzijeme nasledujuce ukazovatele kvality namernaych udajov, aby sme mohli jednotlive meracie metody porovnat.  
Pre vyhodnotenie dát využijeme nasledujúce ukazovatele kvality nameraných údajov, aby sme mohli jednotlivé meracie metódy porovnať.
==== Priemerna hodnota====
====• Priemerná hodnota====
Je aritmeticky priemer nameranych hodnot, je vyuzivany pri pocitani otatnych ukazovatelov a hovori nam, aka bola priemerna namerana hodnota
Je aritmetický priemer nameraných hodnôt, je využívaný pri počítaní ostatných ukazovateľov a hovorí nám, aká bola priemerná nameraná hodnota.
==== Najvacsia odchylka====
====• Najväčšia odchýlka====
Je najvacsia odchylka nameranej hodnoty od priemernej hodnoty. (mensie = lepsie)
Je najväčšia odchýlka nameranej hodnoty od priemernej hodnoty. (menšie = lepšie)
==== Offset====
Je rozdiel nameranej priemernej hodnoty a realnej hodnoty napatia na meranom pine. (mensie = lepsie)
==== ISE====
Je suma stvorcov odchylok. Casto sa pouziva ako ukazovatel kvality (mensie = lepsie)


=== Porovnanie metod===
====• Offset====
Kedze porovnam viacero metod, tu je ich teoreticke porovnaie.
Je rozdiel nameranej priemernej hodnoty a reálnej hodnoty napätia na meranom pine. (bližšie k 0 = lepšie)
==== Jednotlive maranie ====
====• ISE====
Tato metoda je najrychlejsia a zaroven najmenej presna. Je najrychlejsia vdaka tomu, ze berie iba 1 vzorku. Po odstatovani merania moze navyse procesor vykonavat ine instrukcie a vzorku vyhodnotit az po dokonceni A/D prevodu. Nepouziva sa pri tom ziadne opatrenie na zvysenie presnosti prevodu.
Je suma štvorcov odchýlok. Často sa používa ako ukazovateľ kvality. (menšie = lepšie)


==== Meranie s uspatym procesorom ====
=== Porovnanie metód===
Procesor ATmega 328P ma niekolko rezimov spanku, tato metoda vyuziva rezim "ADC Noise Reduction". V tomto rezime je vypnuty hodinovy signal pre procesor, flash a aj pre input/output. Tieto hodinove signaly su pri A/D prevode zdrojom rusenia, teda ich vypnutim toto rusenie odstanime a dostaneme menej zasumeny prevod. Navyse ma pocas prevodu procesor mensi odber prudu co moze byt uzitocne pri niektorych aplikaciach. Procesor sa prebudi zo spanku po dokonceni A/D prevodu (prerusenie). Medzi nevyhody (v niektorych pripadoch) patri napriklad to, ze pocas prevodu procesor spi, teda nemoze vykonavat instrukcie.
Keďže porovnávame viaceré metódy, tu je ich teoretické porovnanie:
====• Jednotlivé meranie ====
Táto metóda je najrýchlejšia a zároveň najmenej presná. Je rýchla vďaka tomu, že berie iba jednu vzorku. Po odštartovaní merania môže navyše procesor vykonávať iné inštrukcie a vzorku vyhodnotiť až po dokončení A/D prevodu. Nepoužíva sa pri tom žiadne opatrenie na zvýšenie presnosti prevodu.


==== Priemerovanie 64 vzoriek ====
====• Meranie s uspaným procesorom ====
Pri tejto metode sa zoberie 64 vzoriek a tie sa aritmeticky spriemeruju. Vyhodou je velmi presne meranie, ktore filtuje napatove spicky vo vstupnom siganle (moze but aj nevyhoda, ked chceme tieto spicky detekovat). Hlavnou nevyhodou je, ze toto trvanie trva podstatne dlhsie ako meranie 1 vzorky.
Procesor ATmega328P má niekoľko režimov spánku, táto metóda využíva režim ADC Noise Reduction. V tomto režime je vypnutý hodinový signál pre procesor, flash a aj pre input/output. Tieto hodinové signály sú pri A/D prevode zdrojom rušenia – ich vypnutím toto rušenie odstránime a získame menej zašumený prevod. Navyše má počas prevodu procesor menší odber prúdu, čo môže byť užitočné pri niektorých aplikáciách. Procesor sa prebudí zo spánku po dokončení A/D prevodu (prerušenie). Medzi nevýhody patrí napríklad to, že počas prevodu procesor spí, teda nemôže vykonávať inštrukcie.
 
====• Priemerovanie 64 vzoriek ====
Pri tejto metóde sa zoberie 64 vzoriek a tie sa aritmeticky spriemerujú. Výhodou je veľmi presné meranie, ktoré filtruje napäťové špičky vo vstupnom signáli (čo môže byť aj nevýhoda, ak chceme tieto špičky detekovať). Hlavnou nevýhodou je, že toto meranie trvá podstatne dlhšie ako meranie jednej vzorky.


[[Súbor:GeminiAI-image3.jpg|400px|thumb|center|Celkový pohľad na zariadenie.]]
=== Meranie ===
=== Meranie ===
Zdroj Z2 sluzi na nastavenie meraneho napatia (na pine A7). Napatie z presneho (linearneho) zdroja je navyse filtrovane cez RC clen s casovou konstantou 0.7s, teda napatie je v case velmi stabilne. Ako napajanie je zvoleny zdroj Z1 a to z dovodu, ze napatie dodavane z USB portu moze vyrazne kolisat, s cim by kolisalo aj referencne napatie pre A/D prevodnik. Po pripojeni externeho zdroju napatia na pin VIN ide toto napatie do linearnecho regulatoru napatia pritomneho na doske Arduino NANO. Arduino NANO si v pripade, ze su pritomne 2 zdroje napatia (USB a VIN), zvoli vzdy VIN. Cela doska je teda napajana z linearneho regulatoru, ktory ma podstatne stabilnejsie napatie.
Zdroj Z2 slúži na nastavenie meraného napätia (na pine A7). Napätie z presného (lineárneho) zdroja je navyše filtrované cez RC člen s časovou konštantou 0,7 s, teda napätie je v čase veľmi stabilné. Ako napájanie je zvolený zdroj Z1, a to z dôvodu, že napätie dodávané z USB portu môže výrazne kolísať, čo by spôsobovalo aj kolísanie referenčného napätia pre A/D prevodník. Po pripojení externého zdroja napätia na pin VIN ide toto napätie do lineárneho regulátora napätia prítomného na doske Arduino Nano. Arduino Nano si v prípade, že sú prítomné dva zdroje napätia (USB a VIN), zvolí vždy VIN. Celá doska je teda napájaná z lineárneho regulátora, ktorý má podstatne stabilnejšie napätie.


[[Súbor:schemaRogerpng.png|400px|thumb|center|Schéma zapojenia.]]
[[Súbor:schemaRogerpng.png|400px|thumb|center|Schéma zapojenia.]]


Po zapojeni napajacieho napatia (Z1, U=9V) som zmeral napatie VREF (= napatie na 5V pine). Nasledne som nastavil napatie na zdroji Z2 podla zadania a pockal na jeho ustalenie. Ustalene napatie som tiez zadal mikroprocesoru. Namerane udaje su v uvedene v tabulke nizsie.
Po zapojení napájacieho napätia (Z1, U = 9 V) som zmeral napätie VREF (= napätie na 5V pine). Následne som nastavil napätie na zdroji Z2 podľa zadania a počkal na jeho ustálenie. Ustálené napätie som tiež zadal mikropočítaču. Namerané údaje sú uvedené v tabuľke nižšie.


{| class="wikitable"
{| class="wikitable"
|+ Namerane udaje
|+ Namerané údaje
|-
|-
! Merane napatie
! Merané napätie
! Metoda merania
! Metóda merania
! Priemerna hodnota [mV]
! Priemerná hodnota [mV]
! Najvacsia odchylka [mV]
! Najväčšia odchýlka [mV]
! Offset [mV]
! Offset [mV]
! ISE [-]
! ISE [-]
|-
|-
| rowspan="3" | 0V  
| rowspan="3" | 0V  
| Jednotlive merania
| Jednotlivé merania
| 0
| 0
| 0
| 0
Riadok 79: Riadok 79:
|-
|-
| rowspan="3" | 2.5V (=2.550V)
| rowspan="3" | 2.5V (=2.550V)
| Jednotlive merania
| Jednotlivé merania
| 2539
| 2539
| 5
| 5
Riadok 98: Riadok 98:
|-
|-
| rowspan="3" | Vcc (=5.133V)
| rowspan="3" | Vcc (=5.133V)
| Jednotlive merania
| Jednotlivé merania
| 5129
| 5129
| 0
| 0
Riadok 116: Riadok 116:
| 0
| 0
|}
|}
Vidime z merania 2.5V, ze najlepsie je meranie za pomoci priemerovania 64 vzoriek a najhorsie za pomoci jednotlivych vozriek. Kedze hodnoty 0V a Vcc su zaroven aj krajne hodnoty pre A/D prevod, maju 0 odchylky. Pre mernaie 2.5V som vytvoril aj histogram.
Vidíme, že pri meraní 2,5 V je najlepšie meranie za pomoci priemerovania 64 vzoriek a najhoršie pri použití jednotlivých vzoriek. Keďže hodnoty 0 V a Vcc sú zároveň aj krajné hodnoty pre A/D prevod, namerané údaje sú veľmi presné. Pre meranie 2,5 V som vytvoril aj histogram, kde na X-ovej osi je reálne nameraná 10-bitová hodnota z A/D prevodníka, na Y-ovej osi je ich počet v 100 meraniach.
[[Súbor:histogramjednotlive.png|300px|thumb|left|Jednotlivé merania]]
[[Súbor:histogramjednotlive.png|500px|thumb|center|Jednotlivé merania]]
[[Súbor:histogramuspproc.png|300px|thumb|left|Meranie s usp. procesorom]]
[[Súbor:histogramuspproc.png|500px|thumb|center|Meranie s usp. procesorom]]
[[Súbor:histogramupriemer.png|300px|thumb|left|Priemerovanie 64 vzoriek]]
[[Súbor:histogramupriemer.png|500px|thumb|center|Priemerovanie 64 vzoriek]]
<br clear="left" />
<br clear="left" />


=== Algoritmus a program ===
=== Algoritmus a program ===


Algoritmus programu využíva toto a toto, základné funkcie sú takéto a voláma ich tuto...  
Program si ako prvé vypýta hodnotu VREF (t. j. napätie na 5V pine). Následne zoberie 100 vzoriek, ktoré si postupne ukladá do poľa. Nasleduje funkcia vyhodnotenie, ktorá zo získaných dát vykoná ich štatistické vyhodnotenie. Taktiež, ak používateľ na začiatku programu zadefinuje, že si praje zobraziť aj jednotlivé namerané hodnoty, program ich vypíše. Tento postup sa opakuje aj pre meranie s uspatým procesorom. V tomto prípade sa najprv nastaví režim spánku, následne sa spustí meranie a procesor sa uspí. Zo spánku ho prebudí prerušenie po dokončení A/D prevodu. Režim priemerovania 64 vzoriek funguje tak, že zoberie 64 vzoriek, ktoré následne aritmeticky spriemeruje a výsledok uloží ako jednu nameranú hodnotu do poľa. V tomto programe sa pomerne často vyskytuje násobenie a delenie mocninami čísla 2 (napr. *1024, /1024, /64 atď.), ktoré je pre zrýchlenie výpočtov realizované pomocou bitových posunov. Používateľ si môže jednoducho zmeniť pin pre meranie pomocou definície na začiatku programu.
Výpis kódu je nižšie...
 


<tabs>
<tabs>
<tab name="AVR C-code"><syntaxhighlight  lang="c++" style="background: LightYellow;">
<tab name="AVR C-code"><syntaxhighlight  lang="c++" style="background: LightYellow;">
/*
* Created: 18. 4. 2025 9:28:26
* Author : Rene Roger
*/
#include <avr/io.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#define BAUD 9600
#define F_CPU 16000000UL
#include "uart.h"
#include <stdio.h>
#include <util/delay.h>
//#define raw //zakomentovat ak nechceme vypisovat raw data na analyzu
#define ADC_PIN 7 // pin pouzity na meranie
#define SAMPLES 100 // pocet vzoriek na meranie
FILE uart_output = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
FILE uart_input  = FDEV_SETUP_STREAM(NULL, uart_getc, _FDEV_SETUP_READ);
unsigned int Measured[SAMPLES]={};
long Bmeastrue = 0;
unsigned int Vcc = 0;
unsigned int Vmeastrue = 0;
void adc_init(){
ADMUX |= (1<<REFS0)|(ADC_PIN & 0x0F);
ADCSRA |= (1<<ADEN)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2)|(1<<ADIE);
}
unsigned int adc_read(){
ADCSRA |= (1<<ADSC);
while (ADCSRA & (1<<ADSC));
return(ADC);
}
unsigned int adc_get(){
return(ADC);
}
void ADC_noise_reduction() {
sei();
SMCR |= (1 << SM0);
SMCR |= (1 << SE);
ADCSRA |= (1 << ADIF);
__asm__ __volatile__("sleep");
SMCR &= ~(1 << SE);
}
void summary(){
uint32_t ISE=0;
unsigned int Bavg=0;
unsigned int Bmax=Measured[0];
unsigned int Bdev=0;
unsigned int Bmin=Measured[0];
uint32_t sum=0;
for (int i=0;i<SAMPLES;i++)
{
sum+=Measured[i];
}
Bavg=sum/SAMPLES;
for (int i=0;i<SAMPLES;i++)
{
if (Measured[i]>Bmax)
{
Bmax=Measured[i];
}
else if (Measured[i]<Bmin)
{
Bmin=Measured[i];
}
ISE+=(Measured[i]-Bavg)*(Measured[i]-Bavg);
}
Bdev = (Bmax - Bavg) > (Bavg - Bmin) ? (Bmax - Bavg) : (Bavg - Bmin);
printf("vyhodnotenie:\n");
printf("priemerna hodnota: %ld mV\n",((long)Bavg*(long)Vcc)>>10);
printf("max odchylka: %ld mV\n",((long)Bdev*(long)Vcc)>>10);
printf("posunutie: %ld mV\n",(((long)Bavg*(long)Vcc)>>10)-(long)Vmeastrue);
printf("ISE: %lu\n\n",ISE);
#ifdef raw
for (int i=0;i<SAMPLES;i++)
{
printf("%d ",Measured[i]);
}
printf("\n\n");
#endif
}


int main(void)
int main(void)
{
{
  unsigned int measuredValue;
    uart_init();
    stdout = &uart_output;
    stdin = &uart_input;
   
    adc_init();
sei();
 
    puts("Vitaj!");
_delay_ms(500);
 
puts("Zadaj napatie Vcc [mV]:");
 
char input;
uint8_t i=0;
 
while(1){//ziska napatie Vcc od uzivatela- urcite bude 4 miestne
i++;
if (i > 4)
{
break;
}
input = uart_getc();
Vcc = Vcc*10;
Vcc += input-48;
printf("%d\r",Vcc);
}
 
printf("Vcc je %d mV\n\n",Vcc);
_delay_ms(500);
 
    while (1)
    {
puts("\n----------------------------------------------------------------\n");
puts("Zadaj napatie na meranom pine [mV]:");
i=0;Vmeastrue=0;
while(1){//ziska napatie napatie od uzivatela- moze byt menej ako 4 miestne- caka na enter
input = uart_getc();
if (input == '\r')
{
break;
}
else
{
Vmeastrue = Vmeastrue*10;
Vmeastrue += input-48;
}
printf("%d\r",Vmeastrue);
}
 
printf("merane napatie: %d mV\n\n",Vmeastrue);
Bmeastrue=((long)Vmeastrue<<10)/(long)Vcc;//*1024
_delay_ms(500);
 
for (int j=0;j<SAMPLES;j++)
{
Measured[j]=adc_read();
}
 
printf("JEDNOTLIVE merania ");
summary();
_delay_ms(500);


  while (1)
for (int j=0;j<SAMPLES;j++)
  {
{
     /*  relax  */ 
ADC_noise_reduction();
  }
Measured[j]=adc_get();
}
      
printf("SPANOK ");
summary();
_delay_ms(500);


  return(0);
unsigned int avgmeas=0;
for (int j=0;j<SAMPLES;j++)
{
avgmeas=0;
for (int k=0;k<64;k++)
{
avgmeas+=adc_read();
}
Measured[j]=avgmeas>>6;///64
}
printf("PRIEMER z 64 ");
summary();
_delay_ms(500);
}
}
}
ISR (ADC_vect){} //musi tu byt kvoli compileru


</syntaxhighlight ></tab>
</syntaxhighlight ></tab>


<tab name="filename.h"><syntaxhighlight  lang="c++" style="background: LightYellow;">
<tab name="uart.h"><syntaxhighlight  lang="c++" style="background: LightYellow;">
#ifndef UART_H_
#define UART_H_
#define BAUD 9600
#define F_CPU 16000000UL
void uart_init( void );
   
void uart_putc( char c );
void uart_puts( const char *s );
 
char uart_getc( void );
 
#endif
</syntaxhighlight ></tab>
 
<tab name="uart.c"><syntaxhighlight  lang="c++" style="background: LightYellow;">
#include <avr/io.h>
#include <avr/io.h>
//#include <util/setbaud.h>
#define BAUD 9600
#define F_CPU 16000000UL
void uart_init( void )
{
    UBRR0 =103;
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);  /* Enable RX and TX */
}


void adc_init(void);                                  // A/D converter initialization


unsigned int adc_read(char a_pin);
void uart_putc(char c)  
{
  if (c == '\n')
    {
      uart_putc('\r');
    }
  loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
  UDR0 = c;
}
 
 
void uart_puts(const char *s)
{
  while(*s!='\0'){
  uart_putc(*s);
  s++;
  }
}
char uart_getc(void) {
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}
</syntaxhighlight ></tab>
</syntaxhighlight ></tab>


Riadok 257: Riadok 472:
     506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506];
     506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506];


figure("Name","histogram jednotlive")
figure("Name","histogram jednotlivé")
histogram(jednotliveRaw)
histogram(jednotliveRaw)
title("histogram - jednotlive merania")
title("histogram - jednotlivé merania")
xticks(floor(min(xlim)):ceil(max(xlim)));
xticks(floor(min(xlim)):ceil(max(xlim)));
xticklabels(string(xticks));
xticklabels(string(xticks));
Riadok 269: Riadok 484:
xticklabels(string(xticks));
xticklabels(string(xticks));


figure("Name","histogram jednotlive")
figure("Name","histogram 64 vzoriek")
histogram(pr64Raw)
histogram(pr64Raw)
title("histogram - priemerovanie 64 vzoriek")
title("histogram - priemerovanie 64 vzoriek")
Riadok 278: Riadok 493:
</tabs>
</tabs>


Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'':


Zdrojový kód: [[Médiá:projektMenoPriezvisko.zip|zdrojaky.zip]]
Zdrojový kód: [[Médiá:projektReneRoger.zip|ADprevod.zip]]


=== Overenie ===
=== Overenie ===


Postup merania je v sekcii "Meranie". Vykonanie merania je intuitivne, nakolko uzivatel je navadzany textom v terminali. Fotografia hotoveho zariadnia nizsie.
Postup merania je uvedený v sekcii „Meranie“. Vykonanie merania je intuitívne, nakoľko používateľ je navigovaný textom v termináli. Fotografia hotového zariadenia je uvedená nižšie.


[[Súbor:Rzapojenie.jpg|400px|thumb|center|Zapojenie]]
[[Súbor:Rzapojenie.jpg|400px|thumb|center|Zapojenie]]


'''Video:'''
'''Video:'''
<center><youtube>D0UnqGm_miA</youtube></center>
<center><youtube>7Dzdl47dkWk</youtube></center>








Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.


[[Category:AVR]] [[Category:MIPS]]
[[Category:AVR]] [[Category:MIPS]]

Aktuálna revízia z 14:04, 9. máj 2025

Záverečný projekt predmetu MIPS / LS2025 - René Roger


Zadanie

Porovnáme dve možnosti ako spresniť výsledok A/D prevodu v mikroprocesore. Výsledky porovnáme v tabuľke pre 3 rozličné vstupné napätia (0,2.5 a Vcc) pri jednom meraní, priemere zo 64 meraní a pri meraní s uspatými perifériami procesora. Meranie zopakujeme 100x a vyhodnotíme štatisticky.

Arduino NANO

Literatúra:


Analýza a opis riešenia

Cieľom zadania je porovnať 3 odlišné metódy získavania dát z A/D prevodníka. Po interakcii s používateľom, ktorý zadá napätie VREF (potrebné na prepočet nameranej hodnoty v bitoch na reálnu hodnotu v mV) a reálne merané napätie (potrebné na štatistické vyhodnotenie posunu), program automaticky namerá potrebné množstvo vzoriek z každej meracej metódy a vykoná aj štatistické vyhodnotenie, ktoré zobrazí používateľovi. Interakcia s používateľom prebieha prostredníctvom sériovej linky – cez terminál PuTTY.

Vyhodnocovacie metódy

Pre vyhodnotenie dát využijeme nasledujúce ukazovatele kvality nameraných údajov, aby sme mohli jednotlivé meracie metódy porovnať.

• Priemerná hodnota

Je aritmetický priemer nameraných hodnôt, je využívaný pri počítaní ostatných ukazovateľov a hovorí nám, aká bola priemerná nameraná hodnota.

• Najväčšia odchýlka

Je najväčšia odchýlka nameranej hodnoty od priemernej hodnoty. (menšie = lepšie)

• Offset

Je rozdiel nameranej priemernej hodnoty a reálnej hodnoty napätia na meranom pine. (bližšie k 0 = lepšie)

• ISE

Je suma štvorcov odchýlok. Často sa používa ako ukazovateľ kvality. (menšie = lepšie)

Porovnanie metód

Keďže porovnávame viaceré metódy, tu je ich teoretické porovnanie:

• Jednotlivé meranie

Táto metóda je najrýchlejšia a zároveň najmenej presná. Je rýchla vďaka tomu, že berie iba jednu vzorku. Po odštartovaní merania môže navyše procesor vykonávať iné inštrukcie a vzorku vyhodnotiť až po dokončení A/D prevodu. Nepoužíva sa pri tom žiadne opatrenie na zvýšenie presnosti prevodu.

• Meranie s uspaným procesorom

Procesor ATmega328P má niekoľko režimov spánku, táto metóda využíva režim ADC Noise Reduction. V tomto režime je vypnutý hodinový signál pre procesor, flash a aj pre input/output. Tieto hodinové signály sú pri A/D prevode zdrojom rušenia – ich vypnutím toto rušenie odstránime a získame menej zašumený prevod. Navyše má počas prevodu procesor menší odber prúdu, čo môže byť užitočné pri niektorých aplikáciách. Procesor sa prebudí zo spánku po dokončení A/D prevodu (prerušenie). Medzi nevýhody patrí napríklad to, že počas prevodu procesor spí, teda nemôže vykonávať inštrukcie.

• Priemerovanie 64 vzoriek

Pri tejto metóde sa zoberie 64 vzoriek a tie sa aritmeticky spriemerujú. Výhodou je veľmi presné meranie, ktoré filtruje napäťové špičky vo vstupnom signáli (čo môže byť aj nevýhoda, ak chceme tieto špičky detekovať). Hlavnou nevýhodou je, že toto meranie trvá podstatne dlhšie ako meranie jednej vzorky.

Meranie

Zdroj Z2 slúži na nastavenie meraného napätia (na pine A7). Napätie z presného (lineárneho) zdroja je navyše filtrované cez RC člen s časovou konštantou 0,7 s, teda napätie je v čase veľmi stabilné. Ako napájanie je zvolený zdroj Z1, a to z dôvodu, že napätie dodávané z USB portu môže výrazne kolísať, čo by spôsobovalo aj kolísanie referenčného napätia pre A/D prevodník. Po pripojení externého zdroja napätia na pin VIN ide toto napätie do lineárneho regulátora napätia prítomného na doske Arduino Nano. Arduino Nano si v prípade, že sú prítomné dva zdroje napätia (USB a VIN), zvolí vždy VIN. Celá doska je teda napájaná z lineárneho regulátora, ktorý má podstatne stabilnejšie napätie.

Schéma zapojenia.

Po zapojení napájacieho napätia (Z1, U = 9 V) som zmeral napätie VREF (= napätie na 5V pine). Následne som nastavil napätie na zdroji Z2 podľa zadania a počkal na jeho ustálenie. Ustálené napätie som tiež zadal mikropočítaču. Namerané údaje sú uvedené v tabuľke nižšie.

Namerané údaje
Merané napätie Metóda merania Priemerná hodnota [mV] Najväčšia odchýlka [mV] Offset [mV] ISE [-]
0V Jednotlivé merania 0 0 0 0
Meranie s usp. proc. 0 0 0 0
Priemerovanie 64 vz. 0 0 0 0
2.5V (=2.550V) Jednotlivé merania 2539 5 -11 36
Meranie s usp. proc. 2539 5 -11 10
Priemerovanie 64 vz. 2539 0 -11 0
Vcc (=5.133V) Jednotlivé merania 5129 0 -4 0
Meranie s usp. proc. 5129 0 -4 0
Priemerovanie 64 vz. 5129 0 -4 0

Vidíme, že pri meraní 2,5 V je najlepšie meranie za pomoci priemerovania 64 vzoriek a najhoršie pri použití jednotlivých vzoriek. Keďže hodnoty 0 V a Vcc sú zároveň aj krajné hodnoty pre A/D prevod, namerané údaje sú veľmi presné. Pre meranie 2,5 V som vytvoril aj histogram, kde na X-ovej osi je reálne nameraná 10-bitová hodnota z A/D prevodníka, na Y-ovej osi je ich počet v 100 meraniach.

Jednotlivé merania
Meranie s usp. procesorom
Priemerovanie 64 vzoriek


Algoritmus a program

Program si ako prvé vypýta hodnotu VREF (t. j. napätie na 5V pine). Následne zoberie 100 vzoriek, ktoré si postupne ukladá do poľa. Nasleduje funkcia vyhodnotenie, ktorá zo získaných dát vykoná ich štatistické vyhodnotenie. Taktiež, ak používateľ na začiatku programu zadefinuje, že si praje zobraziť aj jednotlivé namerané hodnoty, program ich vypíše. Tento postup sa opakuje aj pre meranie s uspatým procesorom. V tomto prípade sa najprv nastaví režim spánku, následne sa spustí meranie a procesor sa uspí. Zo spánku ho prebudí prerušenie po dokončení A/D prevodu. Režim priemerovania 64 vzoriek funguje tak, že zoberie 64 vzoriek, ktoré následne aritmeticky spriemeruje a výsledok uloží ako jednu nameranú hodnotu do poľa. V tomto programe sa pomerne často vyskytuje násobenie a delenie mocninami čísla 2 (napr. *1024, /1024, /64 atď.), ktoré je pre zrýchlenie výpočtov realizované pomocou bitových posunov. Používateľ si môže jednoducho zmeniť pin pre meranie pomocou definície na začiatku programu.

/*
 * Created: 18. 4. 2025 9:28:26
 * Author : Rene Roger
 */ 

#include <avr/io.h>
#include <avr/interrupt.h>
#define BAUD 9600
#define F_CPU 16000000UL
#include "uart.h"
#include <stdio.h>
#include <util/delay.h>

//#define raw //zakomentovat ak nechceme vypisovat raw data na analyzu
#define ADC_PIN 7	// pin pouzity na meranie
#define SAMPLES 100 // pocet vzoriek na meranie

FILE uart_output = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
FILE uart_input  = FDEV_SETUP_STREAM(NULL, uart_getc, _FDEV_SETUP_READ);

unsigned int Measured[SAMPLES]={};
long Bmeastrue = 0;
unsigned int Vcc = 0;
unsigned int Vmeastrue = 0;

void adc_init(){
	ADMUX |= (1<<REFS0)|(ADC_PIN & 0x0F);
	ADCSRA |= (1<<ADEN)|(1<<ADPS0)|(1<<ADPS1)|(1<<ADPS2)|(1<<ADIE);
}

unsigned int adc_read(){
	ADCSRA |= (1<<ADSC);
	while (ADCSRA & (1<<ADSC));
	return(ADC);
}

unsigned int adc_get(){
	return(ADC);
}

void ADC_noise_reduction() {
	sei();	

	SMCR |= (1 << SM0);
	SMCR |= (1 << SE);
	ADCSRA |= (1 << ADIF);
	__asm__ __volatile__("sleep");

	SMCR &= ~(1 << SE);
}
void summary(){
	uint32_t ISE=0;
	unsigned int Bavg=0;
	unsigned int Bmax=Measured[0];
	unsigned int Bdev=0;
	unsigned int Bmin=Measured[0];
	uint32_t sum=0;

	for (int i=0;i<SAMPLES;i++)
	{
		sum+=Measured[i];
	}
	Bavg=sum/SAMPLES;

	for (int i=0;i<SAMPLES;i++)
	{
		if (Measured[i]>Bmax)
		{
			Bmax=Measured[i];
		}
		else if (Measured[i]<Bmin)
		{
			Bmin=Measured[i];
		}
		ISE+=(Measured[i]-Bavg)*(Measured[i]-Bavg);
	}

	Bdev = (Bmax - Bavg) > (Bavg - Bmin) ? (Bmax - Bavg) : (Bavg - Bmin);

	printf("vyhodnotenie:\n");
	printf("priemerna hodnota: %ld mV\n",((long)Bavg*(long)Vcc)>>10);
	printf("max odchylka: %ld mV\n",((long)Bdev*(long)Vcc)>>10);
	printf("posunutie: %ld mV\n",(((long)Bavg*(long)Vcc)>>10)-(long)Vmeastrue);
	printf("ISE: %lu\n\n",ISE);
	
	#ifdef raw
	for (int i=0;i<SAMPLES;i++)
	{
		printf("%d ",Measured[i]);
	}
	printf("\n\n");
	#endif
}

int main(void)
{
    uart_init();
    stdout = &uart_output;
    stdin = &uart_input;
    
    adc_init();
	sei();

    puts("Vitaj!");
	_delay_ms(500);

	puts("Zadaj napatie Vcc [mV]:");

	char input;
	
	uint8_t i=0;

	while(1){//ziska napatie Vcc od uzivatela- urcite bude 4 miestne
		i++;
		if (i > 4)
		{
			break;
		}
		input = uart_getc();
		Vcc = Vcc*10;
		Vcc += input-48;
		printf("%d\r",Vcc);
	}

	printf("Vcc je %d mV\n\n",Vcc);
	_delay_ms(500);

    while (1) 
    {
	puts("\n----------------------------------------------------------------\n");
	puts("Zadaj napatie na meranom pine [mV]:");
	i=0;Vmeastrue=0;
	while(1){//ziska napatie napatie od uzivatela- moze byt menej ako 4 miestne- caka na enter
		input = uart_getc();
		if (input == '\r')
		{
			break;
		}
		else
		{
			Vmeastrue = Vmeastrue*10;
			Vmeastrue += input-48;
		}
		printf("%d\r",Vmeastrue);
	}

	printf("merane napatie: %d mV\n\n",Vmeastrue);
	Bmeastrue=((long)Vmeastrue<<10)/(long)Vcc;//*1024
	_delay_ms(500);

	for (int j=0;j<SAMPLES;j++)
	{
		Measured[j]=adc_read();
	}

	printf("JEDNOTLIVE merania ");
	summary();
	_delay_ms(500);

	for (int j=0;j<SAMPLES;j++)
	{
		ADC_noise_reduction();
		Measured[j]=adc_get();
	}
    
	printf("SPANOK ");
	summary();
	_delay_ms(500);

	unsigned int avgmeas=0;
	for (int j=0;j<SAMPLES;j++)
	{
		avgmeas=0;
		for (int k=0;k<64;k++)
		{
			avgmeas+=adc_read();
		}
		Measured[j]=avgmeas>>6;///64
	}
	printf("PRIEMER z 64 ");
	summary();
	_delay_ms(500);
	}
}

ISR (ADC_vect){} //musi tu byt kvoli compileru
#ifndef UART_H_
#define UART_H_
#define BAUD 9600
#define F_CPU 16000000UL
void uart_init( void );
     
void uart_putc( char c );
void uart_puts( const char *s );

char uart_getc( void );

#endif
#include <avr/io.h>
//#include <util/setbaud.h>
#define BAUD 9600
#define F_CPU 16000000UL
void uart_init( void ) 
{
    UBRR0 =103;
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);   /* Enable RX and TX */
}


void uart_putc(char c) 
{
   if (c == '\n') 
    {
       uart_putc('\r');
    }
   loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
   UDR0 = c;
}


void uart_puts(const char *s)
{
  while(*s!='\0'){
	  uart_putc(*s);
	  s++;
  }
}
char uart_getc(void) {
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}
Vitaj!
Zadaj napatie Vcc [mV]:
Vcc je 5131 mV


----------------------------------------------------------------

Zadaj napatie na meranom pine [mV]:
merane napatie: 0 mV

JEDNOTLIVE merania vyhodnotenie:
priemerna hodnota: 0 mV
max odchylka: 0 mV
posunutie: 0 mV
ISE: 0

SPANOK vyhodnotenie:
priemerna hodnota: 0 mV
max odchylka: 0 mV
posunutie: 0 mV
ISE: 0

PRIEMER z 64 vyhodnotenie:
priemerna hodnota: 0 mV
max odchylka: 0 mV
posunutie: 0 mV
ISE: 0


----------------------------------------------------------------

Zadaj napatie na meranom pine [mV]:
merane napatie: 2550 mV

JEDNOTLIVE merania vyhodnotenie:
priemerna hodnota: 2539 mV
max odchylka: 5 mV
posunutie: -11 mV
ISE: 36

SPANOK vyhodnotenie:
priemerna hodnota: 2539 mV
max odchylka: 5 mV
posunutie: -11 mV
ISE: 10

PRIEMER z 64 vyhodnotenie:
priemerna hodnota: 2539 mV
max odchylka: 0 mV
posunutie: -11 mV
ISE: 0


----------------------------------------------------------------

Zadaj napatie na meranom pine [mV]:
merane napatie: 5133 mV

JEDNOTLIVE merania vyhodnotenie:
priemerna hodnota: 5129 mV
max odchylka: 0 mV
posunutie: -4 mV
ISE: 0

SPANOK vyhodnotenie:
priemerna hodnota: 5129 mV
max odchylka: 0 mV
posunutie: -4 mV
ISE: 0

PRIEMER z 64 vyhodnotenie:
priemerna hodnota: 5129 mV
max odchylka: 0 mV
posunutie: -4 mV
ISE: 0
jednotliveRaw=[506 506 507 506 506 507 506 506 506 506 507 507 507 506,...
    507 506 507 506 506 506 506 506 506 506 507 507 507 506 506 506 506,...
    506 506 506 506 506 507 507 507 507 507 507 507 507 506 506 506 506,...
    506 506 506 506 507 506 506 506 506 506 506 506 506 506 506 507 507,...
    506 506 506 506 506 506 506 507 507 507 506 507 506 506 506 507 507,...
    506 507 507 507 507 506 506 506 506 506 506 506 506 507 507 507,...
    507 507];

spanokRaw=[506 506 506 506 506 506 506 506 506 506 506 506 506 506 506,...
    506 506 506 506 506 506 506 506 506 506 506 507 506 506 506 506 506,...
    506 506 507 507 506 507 506 506 506 506 506 506 506 506 506 506 506,...
    506 506 506 506 506 506 506 506 506 506 506 507 507 507 506 506 506,...
    506 506 506 506 506 506 507 507 507 506 506 506 506 506 506 506 506,...
    506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506];

pr64Raw=[506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506,...
    506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506,...
    506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506,...
    506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506,...
    506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506,...
    506 506 506 506 506 506 506 506 506 506 506 506 506 506 506 506];

figure("Name","histogram jednotlivé")
histogram(jednotliveRaw)
title("histogram - jednotlivé merania")
xticks(floor(min(xlim)):ceil(max(xlim)));
xticklabels(string(xticks));

figure("Name","histogram usp. proc.")
histogram(spanokRaw)
title("histogram - meranie s usp. procesorom")
xticks(floor(min(xlim)):ceil(max(xlim)));
xticklabels(string(xticks));

figure("Name","histogram 64 vzoriek")
histogram(pr64Raw)
title("histogram - priemerovanie 64 vzoriek")
xticks(floor(min(xlim)):ceil(max(xlim)));
xticklabels(string(xticks));


Zdrojový kód: ADprevod.zip

Overenie

Postup merania je uvedený v sekcii „Meranie“. Vykonanie merania je intuitívne, nakoľko používateľ je navigovaný textom v termináli. Fotografia hotového zariadenia je uvedená nižšie.

Zapojenie

Video: