Заинтересовала возможность использовать R-2R ЦАП, потому что из-за разброса напряжения нулевого смещения обычных операционников сильно большое усиление делать неудобно - с одним экземпляром микросхемы находишься в диапазоне, а с другой- нет. А с ЦАП и компаратором можно усиление сделать поменьше, а разницу в смещении компенсировать программой контроллера, предварительно сравнивая с каким-то эталоном результат измерения.
Жаль, что больше приходится заниматься тем, за что платят, а не тем, что хочется изучить, остаются на творчество какие-то крупицы времени
Собрал R-2R ЦАП на макетке, подключил к готовому контроллеру и попробовал написать тестовую программу. Т.к. программирование МК тоже осваиваю от случая к случаю получается конечно причудливо, но все же работает
. Оказалось, что полноценный SPI для управления таким ЦАП и не нужен, подойдут любые 3 цифровых линии контроллера. Получилось плавное изменение напряжение от 0В до 4.4В, непонятно, почему не 5В?
Дальше прикинул схему усилителя токового шунта с компаратором, правильно-ли?
Исходил из того, что падение напряжения на токовом шунте R=0,054Ом при изменении нагрузки от 0,01А до 3А будет меняться от 0,00054В до 0,162В, усиление первого каскада равно 28.5, значит на выходе будет 0,01539В...4,617В и к этому добавить до 0,01В нулевого смещения ОУ, получится 0,3В...4.92В. Дальше это напряжение поступает на прямой вход компаратора, а на инверсный вход подается напряжение с выхода R-2R ЦАПа. Резисторы R42 и R43 должны задать гистерезис VH=R42/(R42+R43)= 1/(1+1000)=0,004995В.
В качестве языка программирования выбрал Pascal, а среды разработки - mikroPascal for AVR v.3.5.0
Тестовая программа получилась такой.
Код: Выделить всё
program R_2R_DAC;
const _THRESHOLD = 20;
var counter,c0,c1 : byte;
c2:short;
br1:array[0..8] of byte;
procedure byte_to_bits(c2:byte);
var c3:byte;
begin
if (c2 and 128)=128 then br1[0]:=1 else br1[0]:=0;{Q7}
if (c2 and 64)=64 then br1[1]:=1 else br1[1]:=0;{Q6}
if (c2 and 32)=32 then br1[2]:=1 else br1[2]:=0;{Q5}
if (c2 and 16)=16 then br1[3]:=1 else br1[3]:=0;{Q4}
if (c2 and 8)=8 then br1[4]:=1 else br1[4]:=0;{Q3}
if (c2 and 4)=4 then br1[5]:=1 else br1[5]:=0;{Q2}
if (c2 and 2)=2 then br1[6]:=1 else br1[6]:=0;{Q1}
if (c2 and 1)=1 then br1[7]:=1 else br1[7]:=0;{Q0}
br1[8]:=1; {зачем-то нужно отправлять лишний бит}
end;
procedure clear_reg;
begin
PORTB.1:=0; {PB1 - LATCH, когда равен 1 на выходы регистра выводится то что в него записано}
for c0:=0 to 7 do begin
PORTB.0:=0;{PB0 - SCK}
delay_ms(1);
PORTB.0:=1;
delay_ms(1);
PORTB.2:=0;{PB2- MOSI, побитно записываются данные в регистр}
delay_ms(1);
end;
end;
procedure send_byte;
begin
clear_reg;
for c0:=0 to 8 do begin
PORTB.0:=0;
delay_ms(1);
PORTB.0:=1;
if br1[c0]=1 then PORTB.2:=1 else PORTB.2:=0;
delay_ms(1);
end;
PORTB.1:=1;
end;
procedure Timer0Overflow_ISR(); org IVT_ADDR_TIMER0_OVF ;
begin
if (counter >= _THRESHOLD) then
begin
counter := 0; // сброс счетчика
if c1<255 then begin {периодическое плавное нарастание и убывание напряжения}
c1:=c1+c2;
byte_to_bits(c1);
end
else begin c2:=-c2;c1:=254; end;
send_byte;
end
else
Inc(counter); // увеличение счетчика
end;
begin
{ Main program }
DDRB := 0xFF; // PORTB переключить на вывод
PORTB := 0; // обнулить PORTB
c1:=0; {счетчик цикла}
c2:=1;
SREG_I_bit := 1; // Разрешить прерывания
TOIE0_bit := 1; // Разрешить прерывание переполнения Timer0
TCCR0 := 5; // Запустить таймер с делителем 1024 T=((8000000/1024)/256)* _THRESHOLD
byte_to_bits(c1);{установка начального значения напряжения Vout=(5/256)*c1}
// Бесконечный цикл основной программы контроллера
while TRUE do
begin
end;
end.