Double-Precision DAC (Dual DAC) – Parte II

Olá humano!

Dando continuidade (enfim), ao teste do circuito Dual DAC, vou colocar o firmware e os resultados que obtive com o circuito proposto.

Abaixo temos o código (em Pascal) utilizado neste projeto:

[sourcecode language=”pascal”]
program Dual_DAC;

{ Declarations section }
//****************************************************************************//
// www.sbampato.com/blogbr (pt-br) //
// //
// Author: Mario Sbampato //
// License: Free, at anyway //
// Date: 15.08.2014 //
// Version: 1.0.0.0 //
// Contact: mario@sbampato.com //
// //
// www.sbampato.com/blogbr (english) //
//****************************************************************************//

//Hardware: placa de teste dual DAC
//PIC18F4550
//20MHz – Quartz Cristal
//
// MAX232 ligado nos pinos TX/RX do pic, para com. serial
// Pin 19 (RD0/SPP0) – Chip Select (~CS) do DAC01
// Pin 20 (RD1/SPP1) – Chip Select (~CS) do DAC02
// Pin 21 (RD2/SPP2) – ~LDAC dos DAC
// Pin 33 (RB0/SDI) – Ligado aos pinos SDI dos DAC
// Pin 34 (RB1/SCK) – Ligado aos pinos SCK dos DAC
// Pin 35 (RB2/INT2) – NC
// Pin 26 (RC7/SDO) – NC
//
// DAC – 2x MCP4921 (SPI DAC / 12 bits resolution)

// Variables list

// DAC01 CS
var Chip_Select02 : sbit at RD0_bit;
Chip_Select_Direction02 : sbit at TRISD0_bit;
// End DAC01 CS

// DAC02 CS
var Chip_Select01 : sbit at RD1_bit;
Chip_Select_Direction01 : sbit at TRISD1_bit;
// End DAC02 CS

// DAC module connections
var
SoftSpi_CLK : sbit at RB1_bit;
SoftSpi_SDI : sbit at RB2_bit; // Note: Input signal
SoftSpi_SDO : sbit at RB0_bit;

var
SoftSpi_CLK_Direction : sbit at TRISB1_bit;
SoftSpi_SDI_Direction : sbit at TRISB2_bit;
SoftSpi_SDO_Direction : sbit at TRISB0_bit;
// End DAC module connections

var value : word;
value2 : word;
uart_rd01: byte;
uart_rd02: byte;
uart_rd03: byte;
uart_rd04: byte;
str1 : string[13];
vlstr1 : string[4];
vlstr2 : string[4];
i, j : byte;

//Added Routines and procedures

procedure InitMain();
begin
Chip_Select01 := 1; // Deselect DAC01
Chip_Select_Direction01 := 0; // Set CS# pin as Output
Chip_Select02 := 1; // Deselect DAC02
Chip_Select_Direction02 := 0; // Set CS# pin as Output
Soft_SPI_Init(); // Initialize SPI module
end;

// DAC increments (0..4095) –> output voltage (0..Vref)
procedure DAC01_Output( valueDAC : word);
var temp : byte;
begin
Chip_Select01 := 0; // Select DAC chip

// Send High Byte
temp := word(valueDAC shr 8) and 0x0F; // Store valueDAC[11..8] to temp[3..0]
temp := temp or 0x30; // Define DAC setting, see MCP4921 datasheet
Soft_SPI_Write(temp); // Send high byte via SPI

// Send Low Byte
temp := valueDAC; // Store valueDAC[7..0] to temp[7..0]
Soft_SPI_Write(temp); // Send low byte via SPI

Chip_Select01 := 1; // Deselect DAC chip
end;

// DAC increments (0..4095) –> output voltage (0..Vref)
procedure DAC02_Output( valueDAC : word);
var temp : byte;
begin
Chip_Select02 := 0; // Select DAC chip

// Send High Byte
temp := word(valueDAC shr 8) and 0x0F; // Store valueDAC[11..8] to temp[3..0]
temp := temp or 0x30; // Define DAC setting, see MCP4921 datasheet
Soft_SPI_Write(temp); // Send high byte via SPI

// Send Low Byte
temp := valueDAC; // Store valueDAC[7..0] to temp[7..0]
Soft_SPI_Write(temp); // Send low byte via SPI

Chip_Select02 := 1; // Deselect DAC chip
end;

//Main routine
begin
{ Main program }

TRISB := 0; // Configure PORTB all Output
PORTB := 0; // Turn off all PORTB
TRISA := 0; // Configure PORTA all Output
PORTA := 0; // Turn off all PORTA
TRISD := 0; // Configure PORTD all Output
PORTD := 7; // Turn off all PORTD
ADCON1 := 0x0F; // Configure all ports with analog function as digital
CMCON := CMCON or 7; // Configure AN pins as digital I/O

InitMain(); // Call Soft_SPI ini procedure

value := 1206; // Set DAC_01 = 1.200V
value2:= 0; // Set DAC_02 = 0.000V
PORTD := 7; // Hold DAC latch
DAC01_Output(value); // Send value to DAC01 chip
DAC02_Output(value2); // Send value to DAC02 chip
PORTD := 0; // Release DAC latch
Delay_ms(300); // Wait 0.3 seconds
PORTD := 7; // Lock DAC registers latch

uart_rd01 := 0;
uart_rd02 := 0;
uart_rd03 := 0;
uart_rd04 := 0;

str1 := ”;
vlstr1 := ”;
vlstr2 := ”;

UART1_Init(9600); // Initialize UART module at 9600 bps
Delay_ms(120); // Wait for UART module to stabilize
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘****************************************’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘Author: Mario Sbampato’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘Contact: contact@sbampato.com’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘Website: www.sbampato.com/blog’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘—————————————-‘);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘Send data in this format:’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘M:XXXX;YYYY;S’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘Where XXXX —> Data to DAC01, [0..4095]’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘and’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘YYYY —> Data to DAC02, [0..4095]’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘Always use four digits for the values!’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘—————————————–‘);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘Sao Carlos / SP. August, 2014. ‘);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘****************************************’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’

UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write_Text(‘Dual DAC Test Board Ready!’);
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’
UART1_Write(13); //
UART1_Write(10); // Add a break line – as ‘enter’

while (TRUE) do // Endless loop
begin
i := 0;

if (UART1_Data_Ready() = 1) then
begin
for i:=0 to 11 do // if data is received
begin
str1[i] := UART1_Read();
while (UART1_Data_Ready() <> 1) do
begin
j := i;
end;
end;

Inc(i);
str1[i] := UART1_Read();

vlstr1 := ‘0000’;
for i:=0 to 3 do
vlstr1[i] := str1[i+2];

vlstr2 := ‘0000’;
for i:=0 to 3 do
vlstr2[i] := str1[i+7];

Delay_ms(12);
UART1_Write(13);
UART1_Write(10);

UART1_Write_Text(‘Received: ‘);
UART1_Write_Text(str1);
UART1_Write(13);
UART1_Write(10);

UART1_Write_Text(‘Value DAC1: ‘);
UART1_Write_Text(vlstr1);
UART1_Write(13);
UART1_Write(10);

UART1_Write_Text(‘Value DAC2: ‘);
UART1_Write_Text(vlstr2);
UART1_Write(13);
UART1_Write(10);

//value := 1206; // Set DAC_01 = 1.200V
//value2:= 0; // Set DAC_02 = 0.000V

value := StrToWord(vlstr1);
value2:= StrToWord(vlstr2);

if (value < 0) then
value := 0
else
if (value > 4095) then
value := 4095;

if (value2 < 0) then
value2 := 0
else
if (value2 > 4095) then
value2 := 4095;

PORTD := 7; // Hold DAC latch
DAC01_Output(value); // Send value to DAC01 chip
DAC02_Output(value2); // Send value to DAC02 chip
PORTD := 0;
Delay_ms(120);
PORTD := 7; // Lock DAC registers latch

UART1_Write_Text(‘Values updated:’);
UART1_Write(13);
UART1_Write(10);
str1 := ‘0’;
WordToStr(value, str1);
UART1_Write_Text(‘DAC01:’);
UART1_Write_Text(str1);
UART1_Write(13);
UART1_Write(10);
str1 := ‘0’;
WordToStr(value2, str1);
UART1_Write_Text(‘DAC02:’);
UART1_Write_Text(str1);
UART1_Write(13);
UART1_Write(10);
end; // Release DAC latch

end;

end.
[/sourcecode]

O código também pode ser copiado aqui.

Após fazer o download do firmware no PIC, procedi o teste utilizando a ferramenta de terminal (USART Terminal) do próprio MikroPascal. E com isso pude enviar os comandos e variar os valores de tensão da maneira que achei mais interessante. O formato do dado que envio é o seguinte: M:XXXX;YYYY;S. Sendo M e S os indicadores de inicio e fim do dado e XXXX e YYYY os valores dos DAC01 e DAC02, respectivamente.

A montagem para o teste do circuito pode ser vista abaixo:

Circuito em teste
Figura 07: Circuito em teste
Set-up utilizado no teste
Figura 08: Set-up utilizado no teste
Foto dos equipamentos utilizados
Figura 09: Foto dos equipamentos utilizados

Com este set-up, variei primeiramente o DAC01 (onde cada incremento é 100 vezes menor que o incremento do DAC02), de zero até o final da escala (4095), obviamente que não na totalidade de pontos. Posteriormente variei o DAC02, porem até o valor de 50, uma vez que notei que o valor apresentado no display do multímetro oscilava muito (na casa das dezenas e centenas de μV).

Mesmo sem ter tomado todos os pontos, decidi parar o teste, e depois, se achar interessante, refaze-lo de maneira mais completa num outro dia.

Abaixo podemos verificar uma analise dos dados obtidos, e a quem interessar, estes dados podem ser baixados aqui em formato Excel, para analise.

Na tabela do Excel, onde os valores enviados se repetirem significa que após ir aumentando os valores, eu voltava algum valor anterior (mais baixo) para verificar se o circuito apresentava histerese, o que não consegui notar.

Pretendo fazer uma parte III deste circuito, com algumas mudanças, como a adição de um capacitor na saída final de forma a evitar a oscilação que percebi quando variava o valor do DAC02. Outras opções, opiniões etc… podem surgir. Um outro teste, seria colocar um osciloscópio e tentar enxergar esta oscilação da tensão, se conseguirmos verificar uma variação de tensão tão pequena. Uma outra possibilidade ainda, seria ligar o multímetro no computador e montar um software que faça leituras automáticas, possibilitando assim a obtenção dos valores para cada ponto dos conversores (mais de 8100 medições se variarmos cada um de um em um, ou 16 769 025 variações caso verificarmos todas as combinações possíveis…).

Conclusões até o momento:

* O circuito é parece funcionar (bom)
* O erro quando comparado valores ideais (calculados) e reais é bem pequeno (ao menos, quando usado somente um dos conversores, que não apresentava oscilação na saída)

* O circuito é complexo (muito mais complicado dois conversores, mais dois resistores, mais um amplificador operacional, quando comparamos com somente um conversor de maior resolução)
* O circuito apresentou uma oscilação quando um dos conversores era exigido, quando o outro era exigido esta oscilação não se apresentava (necessita mais investigação)
* O algoritmo para correlacionar valor (valores) e tensão de saída é mais complexo do que de um conversor de maior resolução nativa.

Se alguém (dos meus poucos leitores) possuir alguma duvida, ou sugestão para testar/modificar o circuito, por favor entre em contato. Manterei esta placa pelo menos por mais algum tempo, para pensar se vale mais investigação.

Os arquivos que utilizei neste projeto podem ser baixados aqui.

Até a próxima!

Deixe uma resposta