Operácie

Číslicovo-analógový prevodník (DAC)

Z SensorWiki


Ak potrebujeme previesť číslicový signál na analógový, tak máme niekoľko možností.


1. Najjednoduchší spôsob je využiť D/A prevodník priamo na čipe mikropočítača. To však, žiaľ, nie je prípad procesoru ATmega328P, s ktorým tento semester pracujeme. Ale ak by ste si mohli vybrať, aj priamo v rodine mikroprocesorov AVR sa nájdu takéto typy - napr. procesor ATtiny214 z rodiny ATtiny[REF 1].

MIPS ATtinyDAC.png
Bloková schéma D/A prevodníka v procesore ATtiny214.


2. Druhá možnosť je použiť špecializovaný integrovaný obvod, ktorý pripojíme k mikropočítaču buď cez zbernicu I2C. Takýchto obvodov existuje veľa, často k nim existuje už aj fungujúca knižnica napr. PCF5891 - 1x 8-bit DAC, alebo MCP4728 - 4x 12-bit DAC. Druhou často používanou zbernicou je SPI, aj k nej je možno nájsť podobné prevodníky, napr. MCP4921 - 1x 12-bit SPI DAC, alebo MAX5715 - 4x 12-Bit SPI DAC.

Túto možnosť podrobne preskúmame na jednom z ďalších cvičení, kde sa budeme venovať externému modulu s čipom PCF5891.


MIPS MCP4921.jpg
MCP4921 - dvojitý 12-bitový A/D prevodník na zbernicu SPI.


3. Tretia možnosť je postaviť si vlastný D/A prevodník z presných rezistorov, tzv. R-2R siete[REF 2]. Jej principiálna schéma zapojenia je na nasledovnom obrázku, podrobný princíp funkcie je veľmi dobre vysvetlený v citovanom odkaze.

MIPS R-2Rnetwork.jpg
Odporový R-2R prevodník signálu.


4. No a posledná možnosť, ktorej sa budeme venovať aj na cvičení je využiť šírkovo modulovaný signál PWM

V niektorých aplikáciach potrebujeme premenlivú šírku impulzu, v iných nás viac zaujíma stredná hodnota napätia, impulzy sa naopak snažíme vyfiltrovať. Dôležité sú dva parametre: frekvencia a tzv. plnenie (pozri obr.).

AVR PWM signal.gif

T_{on} je doba, počas ktorej je výstup v log. 1 a T_{off} je čas v log. nule. Celková perióda signálu je T_{total}.



T_{total} = T_{on} + T_{off}


Plnenie (duty cycle) je pre obdĺžnikový signál definované ako



D = \frac{T_{on}}{T_{total}} = \frac{T_{on}}{T_{on} + T_{off}}


A výstupné napätie


V_{out} = D V_{in} = \frac{T_{on}}{T_{total}} V_{in}


Ako vidno, výstupné napätie môžeme meniť zmenou periódy T_{on}.

Ak je T_on 0, V_out je tiež 0, ak je T_on T_total, potom V_out je maximalne.


Brute force: softvérové PWM

Ak si spravíme svoje vlastné počítadlo time, tak vieme spraviť šírkovo modulovaný výstup na ľubovoľnom pine procesora čisto softvérovými prostriedkami. Daňou za toto riešenie je, že procesor nerobí nič iné, len počíta čas na prepnutie stavu. Nasledovný program je ukážkou takéhoto prístupu, ovládame LED diódu zapojenú na PORTD.7 (Adrudino D7).

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

/* Pripojenie periferii k vyvojovej doske Arduino: */

#define LED2 PD7   // externa LED dioda 

#define LED2_ON  (PORTD |= (1<<LED2))
#define LED2_OFF (PORTD &= ~(1<<LED2))


int main(void)
{
  /*  SETUP   */ 
  
  	DDRD = (1<<LED2);       // PORTD: LED2 na PD7  je output
   
  /*   LOOP   */ 
 
    unsigned char duty = 250;
   
    while(1)
    {             	   
     // nase vlastne pocitadlo pocita stale dokola, rychlost dana delay

       for (int time=0;time<255;time++)
	   {
 	     if (time > duty)	
		   LED2_ON;
	     else 
	       LED2_OFF;	
	     _delay_us(200);
	   }	 	
    	
	
	}  /* end of while */
	
	return(0); 
}
 /* predosly program doplnime o premennu smer (+1/-1) a budeme hodnotu 'duty' postupne
    zvacsovat a po dosiahnuti maxima (255) zasa zmensovat (-1) az po nulu. A takto stale
    dookola dosiahneme znamy efekt "dychajucej" LED diody                                 */

    unsigned char smer = 1;    // doplnujuca premenna 
   
    /* toto musime doplnit do hlavnej slucky */ 
 
    if (duty == 255)
     smer = -1;
    if (duty == 0 )
     smer = 1;
	   
    duty = duty+smer;


Dýchajúcu LED diódu ako prví použili vo firme Apple na počítači iBook G3 a dali si tento dizajnový prvok aj patentovať[REF 3]. Podrobný výskum a verné napodobnenie tohoto efektu nájdete aj v článku Avitala Pekkera[REF 4]


Generovanie PWM pomocou 8-bitového počítadla a časovača T0

Vyššie uvedený prístup je síce možný, ale vysoko neefektívny. Preto si v tejto časti ukážeme to isté, ale zrealizované pomocou zabudovanej periférie - niektorého počítadla. Najvýhodnejšie by na to bolo počítadlo T1, ktoré so svojim 16-bitovým rozlíšením umožňuje naozaj presné generovanie impulzov požadovanej šírky. Žiaľ, na našej doštičke sme si výstupy obsadili displejom a preto musíme preskočiť celú túto kapitolku a použijeme T0.

V tomto príklade nakonfigurujeme 8-bitové počítadlo T0 v režime 3 (FastPWM) tak, aby počítalo od 0 po 255 (8-bit) s najnižšou možnou frekvenciou, t.j. preddeličkou 1:1024. Impulzy budeme generovať na oboch výstupoch OCR0A a OCR0B, pričom šírka impulzu bude závisieť na hodnote v registri OCR0A resp 0B. Hodnota 0 bude znamenať plnenie 0, teda výstup bude trvale v log. 0, hodnota 128 bude predstavovať plnenie 50% až napokon 255 bude plnenie 1.

Pre nastavenia jednotlivých bitov v konfiguračných registroch TCCR0A a TCCR0B treba nahliadnuť do datasheetu procesora.

Parametre sme zvolili tak, aby sa impulzmi dalo ovládať modelárske servo (viď nižšie).

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

int main(void)
{
  DDRD|=(1<<PD6)|(1<<PD5);        // Init PD5 and PD6 pins as output


  //Initialize Timer0

  TCNT0=0;                        // Set Initial Timer value

  OCR0A=15;                       // Set Initial Pulse width
  OCR0B=31;                       // for both outputs

                                 //Set fast PWM mode + clear OC0A and set OC0B on compare match

  TCCR0A|=(1<<COM0A1)|(1<<COM0B1)|(1<<WGM01)|(1<<WGM00);

  TCCR0B|=(1<<CS02)|(1<<CS00);      // Set prescaller 1024 and start timer

   
  while(1)
  {
     /* do nothing */         
  }

  return(0);
}
/* do hlavnej slucky mozeme doplnat rozlicne funkcie manipulujuce s OCR0A */

    OCR0A++;   // rychle demo na zaciatok
   _delay_ms(10);

Výsledkom uvedeného programu budú impulzy s šírkou 1ms a 2ms na dvoch výstupoch mikroprocesora, ktoré môžeme zachytiť napríklad osciloskopom.

MIPS-PWMimpulzy.png

Tento program môžeme využiť na oládanie polohy modelárskeho RS servomotorčeka. Je to zariadenie, ktoré reaguje na impulz špecifickej šírky tak, že nastaví hriadeľ motora do uhla v rozsahu 0 až 180 stupňov. Tieto motorčeky sú pomerne rozšírené, predávajú sa v rozličných veľkostiach a majú plastovú, alebo kvalitnejšie kovovú prevodovku. Majú trojvodičové pripojenie, dva vodiče slúžia na napájanie, tretí je riadiaci signál. Okrem týchto tzv. polohových servomotorov existujú aj tzv. modifikované servomotory, ktorým môžeme ovládať rovnakými impulzmi rýchlosť otáčania. Po úprave signál pre 90 stupňov (impulz šírky 1,5 ms) motorček zastaví, impulz 1ms pre 180 roztočí motor max. rýchlosťou jedným smerom a impulz 2ms pre uhol 0 zasa roztočí motor max. rýchlosťou druhým smerom. Najlepšie to asi ilustruje tento obrázok

ServoAnimation.gif

Tieto modelárske servomotorčeky sa predávajú v širokom rozsahu veľkostí, výkonov a samozrejme aj cien. Od najlacnejších, celoplastových mikro servomotorčekov SG-90 s hmotnosťou len 10 gramov a rozmermi 23x12x28 mm a ťahom cca 2 kg/cm až po tie najväčšie s kvalitnými kovovými prevodmi, napr. HS-755 s rozmermi 59x29x50 mm a ťahom až 14,4 kg/cm. Viac o servách...

ServoPhoto.jpg

Motorček v MIPSkite nemáte, preto realizáciu predvedie len cvičiaci.

Keďže tento rok máte v MIPSkite aj malý modrý servomotorček, môžete si uvedený program aj vyskúšať. Motorček pripojte podľa nasledovnej schémy zapojenia na výstup D6

ArduinoServoConnection.jpg

Program je vhodné doplniť o možnosť zmeny hodnoty OCR aby sa poloha hriadeľa motorčeka skutočne menila.


Generovanie PWM pomocou 16-bitového počítadla a časovača T1

Ako vidíme, počítadlo T0 umožní riadiť polohu servomotorčeka len v 16 krokoch od 15 po 31 (to zodpovedá rozlíšeniu 4 bity, resp. cca 11 stupňov na hriadeli serva). Preto by predsa len bolo vhodnejšie počítadlo T1, ktoré so svojim 16-bitovým rozlíšením umožňuje naozaj presné generovanie impulzov požadovanej šírky.

Návod s počítadlom T1 (kliknutím rozbaliť / zbaliť)


Zadanie

  1. Naprogramujte PWM tak, aby generovalo impulzy 1Hz, 1:1 (kontrola LED diódou pripojenou na Dx)
  2. Naprogramujte PWM tak, aby generovalo impulzy {1,0ms 1,5ms 2,0ms} s periódou opakovania 50Hz (kontrola pripojením serva)


T1: režim Fast PWM

V režime Fast PWM (Pulse Width Modulation) môžeme použiť T1 buď ako 8,9 alebo 10-bitový voľnobežný PWM generátor, alebo rozlíšenie definovať registrom ICR1. Timer/Counter 1 funguje ako počítadlo, ktoré ráta najprv smerom nahor od 0x0000 až po vybraný TOP (8bit -> 0x00FF, 9bit -> 0x01FF, 10bit -> 0x03FF alebo hodnota v ICR1), tam sa otočí a počíta zasa smerom nadol až po 0x0000 a toto sa opakuje stále dokola.

Keď sa hodnota počítadla zhoduje s obsahom porovnávacívch registrov (OCR1A, OCR1B), zmení sa aj hodnota na výstupných pinoch OCA1 a OCB1 nasledovne:

režim  COM1X1 COM1X0   Čo urobí s OCX1

  0       0      0        nič
  1       0      1        nič
  2       1      0      smerom nahor: 0 pri zhode
                        smerom nadol: 1 pri zhode
  3       1      1      smerom nahor: 1 pri zhode
                        smerom nadol: 0 pri zhode

Príslušné bity COM1A1 a COM1A0 pre výstup OCR1A a bity COM1B1 a COM1B0 pre OCR1B sa nachádzajú v registri TCCR1B.


To, ktorý režim PWM chceme používať sa nastavuje bitmi WGM13..WGM10, ktoré sú rozdelené do registrov TCCR1A a TCCR1B:

Režim  WGM13  WGM12  WGM11  WGM10    TOP     Názov 
  0      0      0      0      0              Normal: PWM zakázané
  5      0      1      0      1     0x00FF   Fast PWM 8-bit
  6      0      1      1      0     0x01FF   Fast PWM 9-bit
  7      0      1      1      1     0x03FF   Fast PWM 10-bit
 14      1      1      1      0      ICR1    Fast PWM 

Ostáva nám nastaviť vhodnú frekenciu. Skúsime najprv vypočítať s akou frekvenciou vieme vygenerovať PWM pri použití 10-bitového režimu. Vzťah pre výpočet udáva priamo výrobca v datasheete

fPWM=fCPUN×(1+TOP)f_{PWM} = \frac{f_{CPU}}{N \times (1+TOP)}

kde TOP je v našom prípade 0x3FF, t.j. 1023.

Pre rozličné hodnoty preddeličky dostaneme nasledovné frekvencie:

 CS12  CS11  CS10  prescaler     f_PWM
  0     0     0      stop
  0     0     1       1
  0     1     0       8
  0     1     1      64
  1     0     0     256
  1     0     1    1024

Hodnota 61 Hz by nám pravdepodobne vyhovovala, ale tentoraz sa s ňou neuspokojíme a vypočítame hodnotu TOP, ktorú vložíme do registra ICR1 tak, aby sme dosiahli presne požadovanú frekvenciu 50 Hz.

Opať skúsime nájsť riešenie pre rozličné hodnoty preddeličky:

 prescaler    ICR1     f_PWM
      1
      8
     64
    256
   1024

Požadovanú preddeličku nastavíme bitmi CS12..CS10 v registri TCCR1B.

Posledná vec, ktorú musíme vypočítať, je hodnota, ktorú máme vložiť do registrov OCR1A resp. OCR1B, aby sme dosiahli požadované šírky impulzov 1,0 resp. 2,0 ms. Nesmieme tiež zabudnúť nastaviť piny PB1 a PB2 ako výstupné, inak sa signál nedostane von z procesora.

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

int main(void)
{

  DDRB|=(1<<PB1)|(1<<PB2);        // Init PB1 and PB2 pins as output

  // Initialize Timer1

  TCNT1 = 0;             // Set Initial Timer value
  ICR1  = 0;             // set TOP for counting  
  OCR1A = 0;             // Set Initial Pulse width
  OCR1B = 0;             // for both outputs

  //Set fast PWM mode + Clear OC1A/OC1B on compare match, set OC1A/OC1B at BOTTOM (non-inverting mode)

  TCCR1A|=(1<<COM1A1)|(1<<COM1B1)|(1<<WGM11);

  TCCR1B|=(1<<CS11);      // Set prescaller 8 and start timer

  TCCR1B|=(1<<WGM12)|(1<<WGM13);  // Fast PWM mode 14 where TOP = ICR1
  
  while(1)
  {
    /* relax */
  }  

  return(0);
}



Príklad:

PWMscopeView.png

Na obrázku je priebeh PWM signálu s plnením 25% tak ako opúšťa procesor (červený) a po vyfiltrovaní RC členom (zelený). Perióda PWM je 3,56 ms (281,25 Hz), T_{on} je 0,9 ms, T_{off} je 2,65 ms. T_{63} (zelený priebeh) je 100 us. Osciloskop: 500us/d., 2.00V/d. Parametre: Timer0, mode 8-bit Fast PWM, Prescaler 1:256, OCR0A = 63.



Úloha Vaša úloha je naprogramovať dýchajúcu LED diódu pomocou časovača T0. Využite na to vyššieuvedený program pre RC servo. Aby sme odstránili blikanie (60 Hz je trocha vidno), zmeňte frekvenciu generovaného signálu na približne 1kHz. Okrem toho vo vašom programe nebudete generovať len impulzy šírky 1 až 2 ms, ale budete meniť plnenie v celom rozsahu, teda od 0 po 100% a späť. LED diódu si pripojte na ľubovoľný z výstupov D5 alebo D6, teda OCR0A alebo 0B.

Alternatíva: Môžete odovzdať aj program, v ktorom budete pomocou dvoch tlačítiek meniť polohu hriadeľa servomotora. Jedným sa bude hodnota zvyšovať, druhým znižovať.

Literatúra

  1. Victor Berzan: Getting Started with DAC. Application Note TB3210, Microchip Technology, 2018.
  2. Alan Wolke Tutorial: Digital to Analog Conversion – The R-2R DAC. Textronix Blog, June 23, 2015
  3. Breathing status LED indicator. US patent No. US6658577B2, Apple Inc., 2002
  4. Avital Pekker: A closer look at Apple's breathing light. Personal blog, 2016


Doplnková literatúra:


Návrat na zoznam cvičení...