Zbernica SPI: D/A prevodník MCP4812
Zo stránky SensorWiki
Záverečný projekt predmetu MIPS / LS2026 - Jakub Milošev
Zadanie
Navrhnúť a realizovať program pre Arduino ATmega328P, ktorý komunikuje s D/A prevodníkom MCP4812. Program má umožniť zadávanie celých čísel v rozsahu 0 až 4 prostredníctvom sériovej komunikácie (PuTTY). Po zadaní hodnoty sa na výstupe D/A prevodníka vytvorí analógové napätie zodpovedajúce zadanému číslu v rozsahu 0 V až 4 V.

Literatúra:
Analýza a opis riešenia
Najprv sme museli ísť do datasheetu prevodníka na dozvedenie informácii ako koľko bitový je, čo jednotlivé bity robia.

A/B sme nastavili ako 0 aby sme vybrali výstup A (VoutA). GA sme nastavili ako 0 aby sme mali 2 násobok napätia Vref (2*Vref=4,096) a mohli sme sa pohybovať v rozpätí 0 až 4 V. Ako posledné sme nastavili hodnotu SHDN na 1, lebo tým sa prevodník zapne.
Piny prevodníka.


Schéma zapojenia
Podľa datasheetu samotnej dosky a obrázka vyššie sme prepojili pin CS s pinom SS (PB2), pin SCK s pinom SCK (PB5) a pin SDI s pinom MOSI (PB3). Piny VSS a LDAC boli pripojené na zem (GND). Pin LDAC bol pripojený na GND, aby sa výstup prevodníka automaticky aktualizoval po prijatí novej hodnoty bez potreby dodatočného impulzu.

Algoritmus a program
Ako prvé sa spustí UART (oba sú totožné z UARTami z cvík) čo umožní komunikáciu s PuTTY. Potom sa spustí SPI kde sa nastavia piny PB3, PB5 a PB2 ako výstupy a CS pin nastaví na HIGH čo znamená že prevodník zatiaľ nekomunikuje.
Ďalej program prejde do while slučky kde čaká na znak z PuTTY. Funkcia uart_getc() čaká na prijatie znaku z PuTTY a následne ho uloží do premennej prijate (if skontroluje či je daný znak číslo od 0 do 4).
Program skontroluje či je teda to číslo od 0 do 4 a následne ho prevedie z ASCII na číslo odčítaním ‘0‘ napríklad ‘3‘ - ‘0‘ = 3 a uloží ho do premennej hodnota.
Hodnota sa následne vynásobí 1024 a vydelí referenčnou hodnotou napätia 4,096, a uloží sa do premennej vysledok (napríklad pre 3 je výsledok 750 túto hodnotu si už prevodník prevedie na napätie).
Výsledok sa pošle do funkcie DAC_write kde sa poskladá 16 bitový príkaz. Výsledok sa posunie o 2 bity doľava a pomocou OR sa vloží do command. Výsledný príkaz obsahuje v horných 4 bitoch konfiguráciu a v zvyšných bitoch dáta.
CS pin sa nastaví na LOW čím prevodník začne očakávať hodnoty. Príkaz sa rozdelý na 2 byty horný byte sa pošle ako prvý do SPI_send kde sa zapíše do registra SPDR. Program čaká kým sa odosielanie dokončí pomocou while slučky ktorá kontroluje bit SPIF v registri SPSR aby sa náhodou neprepísala správna hodnota. Potom sa rovnako pošle dolný byte (Keďže naše arduino umožňuje prenášať iba 8 bitov naraz, 16 bitový príkaz je potrebné rozdeliť na horný a dolný byte). Po odoslaní oboch bytov sa CS nastaví na HIGH čím sa komunikácia ukončí.
Prevodník následne poskladá oba prijaté byty späť do 16 bitového príkazu, skontroluje konfiguračné bity a dátové bity, a nastaví napätie na VoutA.
Ako potvrdenie program vypíše do PuTTY Nastavena hodnota: 3V a vráti sa na začiatok while slučky.
#define F_CPU 16000000UL
#include <avr/io.h>
#include "uart.h"
void SPI_init(void)
{
DDRB |= (1 << PB3) | (1 << PB5) | (1 << PB2); //nastavenie vystupov jednotlivych pinov
SPCR = (1 << SPE) | (1 << MSTR) | (1 << SPR0);
PORTB |= (1 << PB2);
}
// Funkcia na odoslanie 1 bytu cez SPI
void SPI_send(uint8_t data)
{
// Zapise data do SPI registra
SPDR = data;
while (!(SPSR & (1 << SPIF))); // caka na skoncenie odosielania
}
void DAC_write(uint16_t vysledok)
{
uint16_t command;
command = 0b0001000000000000; //príkaz z datasheetu
// Posunutie 10-bit dat na spravne miesto
command |= (vysledok << 2);
PORTB &= ~(1 << PB2);
SPI_send(command >> 8);
SPI_send(command & 0xFF);
PORTB |= (1 << PB2);
}
int main(void)
{
uart_init();
SPI_init();
char prijate;
uint8_t hodnota;
uint16_t vysledok;
while (1)
{
prijate = uart_getc();
if(prijate >= '0' && prijate <= '4')
{
hodnota = prijate - '0';
// Prevod napatia na DAC hodnotu
vysledok = (hodnota) * 250; //250=1024/4.096
// Zapis hodnoty do DAC
DAC_write(vysledok);
// Vypis textu do Putty
uart_puts("Nastavena hodnota: ");
uart_putc(prijate);
uart_puts("V\n");
}
}
}
Zdrojový kód: ProjektJakubMilosev.zip
Overenie
Program sme otestovali zapojením vyššie uvedenej schémy. Zapisovali sme do PuTTY rôzne čísla od 0 do 4 a sledovali sme výstup prevodníka pomocou multimetru kde ukazovalo správne hodnoty.

Video:
Čo by som urobil inak
Namiesto zadávania iba celých čísel 0 až 4 by som umožnil zadávanie desatinných hodnôt pre lepšie využitie celého výstupného napätia prevodníka.