Operácie

Zbernica SPI: D/A prevodník MCP4812

Zo stránky SensorWiki

Verzia z 14:34, 6. jún 2026, ktorú vytvoril StudentMIPS (diskusia | príspevky)
(rozdiel) ← Staršia verzia | Aktuálna úprava (rozdiel) | Novšia verzia → (rozdiel)

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.

Vývojová doska ACROB.

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.

Pohľad na jednotlivé bity

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.

Jednotlivé piny prevodníka
Popis pinov 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.

Schéma zapojenia.


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.

Zapojenie

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.