Substituindo o ajuste analógico pelo digital na fonte de alimentação do laboratório HY3005D

     O artigo discutirá a substituição de potenciômetros padrão por codificadores mecânicos EC11 (sensores de ângulo de acumulação) em uma fonte de alimentação Mastech HY3005D usando um microcontrolador PIC16F1829 e um registro de deslocamento 74HC595 implementando um DAC em uma matriz de resistores R2R

Prefácio


     Alguns anos atrás, comprei uma fonte de alimentação Mastech HY3005D. Há pouco tempo, houve problemas com a regulação da tensão - o revestimento de grafite dos reostatos estava desgastado e definir a tensão necessária tornou-se uma tarefa difícil. Não havia reostatos adequados, e decidi não comprar outros semelhantes, mas mudar o método de ajuste.
     O nível de tensão e corrente de saída é definido pela tensão de referência fornecida aos amplificadores operacionais. Assim, você pode se livrar completamente dos potenciômetros, substituindo-os por um DAC capaz de fornecer tensão na faixa desejada.
     No catálogo de microchips, não consegui encontrar um microcontrolador adequado que possua dois DACs a bordo e os DACs externos não têm um preço baixo e muita funcionalidade extra. Portanto, adquiri os registros de deslocamento 74HC595 e resistores para a matriz R2R. O microcontrolador PIC16F1829 já estava em estoque.
     Para poder retornar ao circuito original, todas as alterações são minimizadas - substituindo a unidade de ajuste feita em uma placa separada.

Descrição do trabalho


     O circuito é baseado no microcontrolador PIC16F1829, operando a uma frequência de 32 MHz. A frequência do relógio é definida pelo gerador de clock interno, de acordo com a folha de dados, não é muito precisa, mas para este circuito não é crítica. A vantagem deste MK é a presença de resistores pull-up em todas as entradas digitais e dois módulos MSSP que implementam SPI. Todos os 18 pinos lógicos do microcontrolador são usados.
     Em quatro registros de turno 74HC595e matrizes R2R implementaram dois DACs de 16 bits. As vantagens desse registro incluem a presença de um registro de turno e um registro de armazenamento separados. Isso permite gravar dados no registro sem quebrar os valores de saída atuais. A matriz R2R é montada em resistores com um erro de 1%. Vale ressaltar que as medições seletivas apresentaram um erro não superior a 10 ohms. Inicialmente, planejava-se o uso de três registros, mas ao fazer a fiação da placa, pareceu-me que não era uma boa solução, além disso, era necessário adicionar mordidelas.
     Os resistores pull-up embutidos no MC são ativados em todas as entradas e simplificam o circuito. Todas as saídas dos codificadores são conectadas diretamente aos terminais MK, um total de 4 codificadores, cada um com duas saídas para o próprio sensor de rotação e uma para o botão embutido. Um total de 12 conclusões MK é usado para processar dados de entrada. O retorno do contato é suavizado com uma capacidade de 100nF. Após alterar os valores dos buffers de corrente e tensão de 16 bits, de acordo com os dados de entrada dos codificadores, os valores são transferidos para os registros de deslocamento 74HC595 via SPI. Para reduzir o tempo de transferência de dados, são utilizados dois módulos SPI, que permitem que os dados sejam transmitidos simultaneamente para corrente e tensão. Depois que os dados são transferidos para o registro, um comando é enviado para transferir dados do buffer de deslocamento para o buffer de armazenamento. As saídas do registro são conectadas à matriz R2R, atuando como um divisor para o DAC.A tensão de saída da matriz é transmitida para as entradas dos amplificadores operacionais.
     Os botões incorporados nos codificadores definem o mínimo (botão do codificador para ajuste suave) ou máximo (botão do codificador para ajuste grosso), respectivamente, para corrente ou tensão.

Esquema


     Na Internet, não encontrei um esquema que coincidisse completamente com o meu, então peguei o primeiro link. Fez correções nas inconsistências reveladas e depois adicionou as alterações. Desenhei um diagrama do bloco de ajuste no TinyCAD - baixe o arquivo HY3005D-regulator.dsn .

O original


Depois de encontrar imprecisões


O esquema final após o refinamento A

unidade portátil com ajuste (destacada em vermelho) foi colocada em um esquema separado.

Um voltímetro digital com um display no painel frontal (não está nos diagramas) está conectado ao conector J3.

Componentes Utilizados


     Abaixo está uma lista de componentes utilizados (o caso é indicado entre parênteses). Todos foram comprados em momentos diferentes na China. É importante usar LEDs com as mesmas características dos nativos, pois eles ficam em série no circuito de saída dos amplificadores operacionais (eu peguei os mesmos que estavam na minha placa-mãe).
  • U1: Microcontrolador PIC16F1829I / ML (QFN)
  • U2 - U5: registrador de deslocamento 74HC595BQ (DHVQFN16 ou SOT-763)
  • U6: AMS1117 Regulador de tensão linear de 5V (SOT-223)
  • RE1 - RE4: sensor mecânico de ângulo de acumulação EC11
  • Matrizes R1, R2 e R2R: resistores de 1 e 2 kΩ (SMD 0402)
  • C1 - C12, C14-C17: Capacitores de cerâmica GRM21BR71E104KA01L 100nF (SMD 0805)
  • C13: capacitor de tântalo 22mkF 16V (tiv B)
  • D1, D2: LEDs de tensão / corrente do painel frontal


Taxa


     Criei o quadro no Sprint Layout 6 - baixe o arquivo HY3005D-regulator.lay6 . Infelizmente, o original em que fiz minha versão não foi preservado, no formato lay6 já com as correções identificadas durante a montagem:

  1. Adicionei jumpers ao lado da interface do firmware para a conexão de interrupção do codificador de controle de corrente suave, porque filtragem de capacidade de contato impedida de piscar o controlador
  2. Adicionados jumpers ausentes para o solo entre os lados
  3. Moveu o conjunto estabilizador de 5V para o outro lado para reduzir os jumpers
  4. Adicionado capacitores de suavização na linha de energia ( discussão )

Foto após gravação e perfuração (primeira versão)



     Feito usando filme fotorresistente. Sofri por muito tempo com uma pequena fiação de registros. Na última versão, havia pequenas falhas que precisavam ser limpas após a gravação. Mas, em geral, o conselho falhou. Ainda não existem dois jumpers suficientes para conectar o solo nos lados dianteiro e traseiro.

Depois de inserir os problemas identificados (segunda versão)


0 SMD 0805.

Foto após dessoldagem e instalação no local


      . — . — 12.

     Como você pode ver, as alterações são mínimas, todos os conectores antigos permaneceram inalterados. Eu tive que adicionar comida separadamente, porque a única tensão que chega à placa de ajuste de 2,5V não é adequada para o divisor nativo. Se você remover o diodo zener para 2,5V (V5A) na placa principal da fonte de alimentação e colocar um jumper no lugar do resistor (R1A), poderá fazê-lo sem fornecimento adicional de energia de 12V.

Firmware


Código C para o compilador XC8. Costurou o PICkit 3 original.

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               0x0000
#define CurrentMin               0x0000

#define VoltageStart             0x1E00
#define CurrentStart             CurrentMax

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 = VoltageStart;
    CurrentBuff = CurrentStart;
    __delay_ms(50);
    SendData();

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

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

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

        if ( !CurrentSmoothCHA ) {
            if ( CurrentSmoothCHB ) { CurrentBuff-=CurrentRateSmooth; if ( CurrentBuff > CurrentMax ) CurrentBuff = CurrentMin; }
                               else { CurrentBuff+=CurrentRateSmooth; if ( CurrentBuff > CurrentMax ) CurrentBuff = CurrentMax; }
            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(); }
    };
}


     Para os valores mínimos, VoltageMin e CurrentMin são definidos como 1, porque em 0 no buffer, o ajuste para de funcionar até que eu entenda onde está o problema. Taxas * Taxa * selecionado vários e mais conveniente na minha opinião. Para o método SendData, eu não passei variáveis ​​como parâmetros para salvar instruções e memória da máquina. O modo Firmware de baixa tensão (LVP) deve estar desativado, caso contrário, o RA3 não funcionará como uma entrada digital. As interrupções não são usadas, o método tc_int está presente no código para que o compilador coloque o bloco principal no início da ROM.
     Para o firmware, basta remover os jumpers, conectar o PICkit 3 (ou outro programador) e executar o firmware. Na primeira versão, não havia jumpers no CLK e no DAT, então tive que dessoldar os capacitores de suavização, piscar com eles e depois soldá-los.
UPD:Após instalar tanques adicionais na linha de energia, o problema de sair do contador da posição zero desapareceu. Eu também tive que mudar a direção da rotação. Aparentemente, o ruído do retificador AMS1117 impediu o reconhecimento correto do estado dos codificadores. Além disso, adicionei uma configuração de valores iniciais, agora a tensão padrão está definida para 5 volts (a corrente ainda está no máximo). Antes do primeiro envio de dados, um atraso de 50 ms foi inserido nos registros (o valor do atraso foi obtido com uma grande margem) para aguardar a inicialização dos módulos SPI.

Características de tensão de saída


     Após a montagem final do dispositivo, foi realizada uma medição de tensão entre os contatos J4.1 - J4.2 (regulação de tensão) e J4.1 - J4.7 (regulação de corrente). De acordo com os dados obtidos, gráficos (abaixo do spoiler) das dependências de valor / tensão para o DAC são plotados.
Gráficos



Os valores calculados das tensões são obtidos pela fórmula (U * D) / (2 ^ K), onde
U é a tensão na saída do registro, levando em consideração os divisores no circuito principal (para a corrente DAC - 4950mV, para a tensão DAC - 3550mV);
D é o valor decimal do contador DAC;
K - profundidade de bits DAC (16 bits)

O que pode ser melhorado


  • adicionar valores de timer salvando
  • amarre os valores padrão aos botões do encoder, por exemplo, para tensão: 3.3; 5,0; 7,5; 12V
  • para proteger contra um valor desconhecido na inicialização, é melhor conectar o MR a 1 e puxar o OE através do resistor para 1 e redefinir para 0 depois de inicializar o MK.
  • substitua o DAC por um PWM por uma corrente de alisamento (sugerido pelo LampTester aqui )

Source: https://habr.com/ru/post/pt391617/


All Articles