Замена аналоговой регулировки на цифровую в лабораторном блоке питания HY3005D

в 6:51, , рубрики: microchip, microcontrollers, pic16, Блок питания, Железо, Программирование, программирование микроконтроллеров, Производство и разработка электроники

В статье пойдет речь о замене штатных потенциометров на механические энкодеры EC11 (накапливающие датчики угла поворота) в блоке питания Mastech HY3005D с использованием микроконтроллера PIC16F1829 и сдвигового регистра 74HC595 реализующей ЦАП на резисторной матрице R2R

Предисловие

Несколько лет назад приобрел блок питания Mastech HY3005D. Не так давно возникли проблемы с регулировкой напряжения — истерлось графитовое покрытие реостатов и выставить необходимое напряжение стало сложной задачей. Подходящих реостатов не нашлось и я решил не покупать аналогичные, а изменить способ регулировки.

Уровень выходного напряжения и тока задается опорным напряжением подаваемым на операционные усилители. Таким образом можно полностью избавиться от потенциометров заменив их на ЦАП способный выдавать напряжение в нужном диапазоне.

В каталоге microchip я не смог подобрать подходящего микроконтроллера имеющего два ЦАП на борту, а внешние ЦАП имеют не малый ценник и слишком много лишнего функционала. Поэтому приобрел сдвиговые регистры 74HC595 и резисторы для матрицы R2R. Микроконтроллер PIC16F1829 уже был в наличии.

Для возможности вернуться к первоначальной схеме все изменения сведены к минимуму — замене блока регулировки выполненного на отдельной плате.

Описание работы

В основе схемы лежит микроконтроллер PIC16F1829 работающий на частоте 32МГц. Тактовая частоста задается встроенным тактовым генератором, согласно даташиту он не слишком точный, но для данной схемы это не критично. Плюсом данного МК является наличие подтягивающих резисторов на всех цифровых входах и два MSSP модуля реализующих SPI. Все 18 логических вывода микроконтроллера использованы.

На сдвиговом регистре 74HC595 и R2R матрице реализован простой ЦАП. К плюсам данного регистра можно отнести наличие раздельного сдвигового регистра и регистра хранения. Это позволяет записывать данные в регистр не сбивая текущие выходные значения. Матрица R2R собрана на резисторах с погрешностью 1% в корпусе SMD 0402. Стоит заметить что выборочные замеры показали погрешность не более 10 Ом.

Встроенные в МК подтягивающие резисторы активированы на всех входах и позволяют упростить схему. Все выходы с энкодеров подключены напрямую к выводам МК, всего 4 энкодера у каждого по два вывода для самого датчика поворота и один для встроенной кнопки. Итого 12 выводов МК используется для обработки входных данных. Дребезг контактов сглаживается емкостью 100нФ. После изменения значений 16-битных буферов тока и напряжения в соответствии с входными данными от энкодеров значения передаются в сдвиговые регистры 74HC595 по SPI. Для сокращения времени передачи данных используется два SPI-модуля что позволяет передавать данные одновременно для тока и напряжения. После того как данные переданы на регистр подается команда переноса данных из сдвигового буфера в буфер хранения. Выходы регистра подключены к матрице R2R выполняющую роль делителя для ЦАП. Выходное напряжение с матрицы передается на входы операционных усилителей.

Кнопки встроенные в энкодеры устанавливают значения на минимум (кнопка энкодера плавной регулировки) или максимум (кнопка энкодера грубой регулировки) соотвественно для тока или напряжения.

Схема

В интернете не нашел схему полностью совпадающую с моей, поэтому взял по первой ссылке. Внес исправления по выявленным несоответствиям и затем добавил свои изменения. Схему блока регулировки чертил в TinyCAD — скачать файл HY3005D-regulator.dsn.

Оригинал

image

После найденных неточностей

image

После доработки
image

Выносной блок с регулировкой (выделен красным) вынес в отдельную схему.

image

К разъему J3 подключается цифровой вольтметр с дисплеем на лицевой панели (его нет на схемах)

Плата

Плату разводил в Sprint Layout 6 — скачать файл HY3005D-regulator.lay6. К сожалению, оригинал, на котором я сделал свой вариант, не сохранился, в формате lay6 уже с исправлениями, выявленными в ходе сборки:

  1. В разврыв подключения энкодера плавной регулировки тока добавил перемычки рядом с интерфейсом для прошивки, т.к. емкости фильтрующие дребезг контактов не позволяли прошивать контроллер
  2. Добавил недостающие перемычки для земпли между сторонами
  3. Переместил стабилизирующую сборку на 5В на другую сторону для уменьшения сквозных перемычек

Фото после травления и сверления (первая версия)

image

image

Изготавливал с использованием пленочного фоторезиста. Долго мучался с мелкой разводкой регистров. В последнем варианте были небольшие огрехи которые пришлось зачищать после травления. Но в целом плата удалась. Здесь еще не хватает двух перемычек для соединения земли на лицевой и тыльной сторонах.

После внесения выявленных исправлений (вторая версия)

Замена аналоговой регулировки на цифровую в лабораторном блоке питания HY3005D - 7

Замена аналоговой регулировки на цифровую в лабораторном блоке питания HY3005D - 8

Фото после распайки и установки на место

image

В левой части сам блок питания. В правой — лицевая панель лицом в низ. Зеленый провод из левого верхнего угла в правый нижний — дополнительное питание 12В.

Как видно, изменения минимальны, все старые разъемы остались без изменений. Пришлось добавить отдельно питание, т.к. единственное напряжение приходящее на плату регулировки 2.5В для родного делителя не подходит. Если на основной плате блока питания убрать стабилитрон на 2.5В (V5A) и поставить перемычку в место резистора (R1A) можно обойтись и без дополнительного подведения 12В питания.

Прошивка

Код на Си для компилятора XC8. Прошивал оригинальным PICkit 3.

config.h

// PIC16F1829 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable (Brown-out Reset disabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = OFF       // Internal/External Switchover (Internal/External Switchover mode is disabled)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is disabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = OFF      // PLL Enable (4x PLL disabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF        // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)

main.c

#include "config.h"

#define _XTAL_FREQ 32000000
#pragma intrinsic(_delay)
extern void _delay(unsigned long);
#define __delay_us(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((unsigned long)((x)*(_XTAL_FREQ/4000.0)))

#define TransferNotDone          !(SSP2STAT&0b00000001)

#define StoreAll                 LATA4
#define ResetAll                 LATC6

#define VoltageSharpCHA          RC1
#define VoltageSharpCHB          RC0
#define VoltageSharpBTN          RA2

#define VoltageSmoothCHA         RB5
#define VoltageSmoothCHB         RB4
#define VoltageSmoothBTN         RC2

#define CurrentSharpCHA          RC5
#define CurrentSharpCHB          RC4
#define CurrentSharpBTN          RC3

#define CurrentSmoothCHA         RA1
#define CurrentSmoothCHB         RA0
#define CurrentSmoothBTN         RA3

#define VoltageRateSharp         0x0100
#define VoltageRateSmooth        0x0010
#define CurrentRateSharp         0x0040
#define CurrentRateSmooth        0x0004

#define VoltageMax               0xC000
#define CurrentMax               0x5000
#define VoltageMin               0x0001
#define CurrentMin               0x0001

unsigned short VoltageBuff;
unsigned short CurrentBuff;

void interrupt tc_int() {
};

void SendData() {
    SSP1BUF = VoltageBuff>>8;
    SSP2BUF = CurrentBuff>>8;
    while ( TransferNotDone );
    SSP1BUF = VoltageBuff;
    SSP2BUF = CurrentBuff;
    while ( TransferNotDone );
    StoreAll = 1;
    StoreAll = 0;
};

void main() {
    // Configure oscillator for 32MHz
    //             76543210
    OSCCON     = 0b11110000; //B1

    // Enable individual pull-ups
    //             76543210
    OPTION_REG = 0b01111111; //B1

    // Configure analog port (1 - enable, 0 - disable)
    //             76543210
    ANSELA     = 0b00000000; //B3
    ANSELB     = 0b00000000; //B3
    ANSELC     = 0b00000000; //B3

    // Reset latch
    //             76543210
    LATA       = 0b00000000; //B2
    LATB       = 0b00000000; //B2
    LATC       = 0b00000000; //B2

    // Alternate pin function (set SDO2 on RA5)
    //             76543210
    APFCON0    = 0b00000000; //B2
    APFCON1    = 0b00100000; //B2

    // Configure digital port (1 - input, 0 - output)
    //             76543210
    TRISA      = 0b00001111; //B1
    TRISB      = 0b00110000; //B1
    TRISC      = 0b00111111; //B1

    // Configure input level (1 - CMOS, 0 - TTL)
    INLVLA     = 0b11000000; //B7
    INLVLB     = 0b00001111; //B7
    INLVLC     = 0b00000000; //B7

    // Configure individual pull-ups (1 - enable, 0 - disable)
    //             76543210
    WPUA       = 0b00111111; //B4
    WPUB       = 0b11110000; //B4
    WPUC       = 0b11111111; //B4

    ResetAll = 0;
    ResetAll = 1;

    // Configure SPI in master mode
    //             76543210
  //SSP1ADD     = 0b00000000; //B4
    SSP1STAT    = 0b01000000; //B4
    SSP1CON3    = 0b00000000; //B4
    SSP1CON1    = 0b00100000; //B4
  //SSP1ADD     = 0b00000000; //B4
    SSP2STAT    = 0b01000000; //B4
    SSP2CON3    = 0b00000000; //B4
    SSP2CON1    = 0b00100000; //B4

    VoltageBuff = VoltageMin;
    CurrentBuff = CurrentMax;
    SendData();

    while ( 1 ) {
        if ( !VoltageSharpCHA ) {
            if ( VoltageSharpCHB ) { VoltageBuff+=VoltageRateSharp; if ( VoltageBuff > VoltageMax ) VoltageBuff = VoltageMax; }
                              else { VoltageBuff-=VoltageRateSharp; if ( VoltageBuff > VoltageMax ) VoltageBuff = VoltageMin; }
            while ( !VoltageSharpCHA );
            SendData();
        }

        if ( !VoltageSmoothCHA ) {
            if ( VoltageSmoothCHB ) { VoltageBuff+=VoltageRateSmooth; if ( VoltageBuff > VoltageMax ) VoltageBuff = VoltageMax; }
                               else { VoltageBuff-=VoltageRateSmooth; if ( VoltageBuff > VoltageMax ) VoltageBuff = VoltageMin; }
            while ( !VoltageSmoothCHA ); 
            SendData();
        }

        if ( !CurrentSharpCHA ) {
            if ( CurrentSharpCHB ) { CurrentBuff+=CurrentRateSharp; if ( CurrentBuff > CurrentMax ) CurrentBuff = CurrentMax; }
                              else { CurrentBuff-=CurrentRateSharp; if ( CurrentBuff > CurrentMax ) CurrentBuff = CurrentMin; }
            while ( !CurrentSharpCHA );
            SendData();
        }

        if ( !CurrentSmoothCHA ) {
            if ( CurrentSmoothCHB ) { CurrentBuff+=CurrentRateSmooth; if ( CurrentBuff > CurrentMax ) CurrentBuff = CurrentMax; }
                               else { CurrentBuff-=CurrentRateSmooth; if ( CurrentBuff > CurrentMax ) CurrentBuff = CurrentMin; }
            while ( !CurrentSmoothCHA );
            SendData();
        }

        if ( !VoltageSharpBTN  ) { VoltageBuff = VoltageMax; while ( !VoltageSharpBTN  ); SendData(); }
        if ( !VoltageSmoothBTN ) { VoltageBuff = VoltageMin; while ( !VoltageSmoothBTN ); SendData(); }
        if ( !CurrentSharpBTN  ) { CurrentBuff = CurrentMax; while ( !CurrentSharpBTN  ); SendData(); }
        if ( !CurrentSmoothBTN ) { CurrentBuff = CurrentMin; while ( !CurrentSmoothBTN ); SendData(); }
    };
}

Для минимальных значений VoltageMin и CurrentMin выставлена 1, т.к. при 0 в буфере регулировка перестает работать, пока не понял где проблема. Рейты *Rate* подбирал кратные и наиболее удобные на мой взгляд. Для метода SendData не делал передачу переменных в качестве параметров для экономии машинных команд и памяти. Режим прошивки с низким напряжением (LVP) должен быть выключен, иначе RA3 не будет работать как цифровой вход. Прерывания не используются, метод tc_int присутствует в коде для того чтобы компилятор поместил основной блок в начало ППЗУ.

Для перепрошивки достаточно снять перемычки, подключить PICkit 3 и выполнить прошивку. В первой версии не было перемычек на CLK и DAT, поэтому мне пришлось выпаять сглаживающие конденсаторы, прошить и потом впаять их обратно.

Автор: Michael314

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js