在实验室电源HY3005D中用数字代替模拟调整

     本文将讨论使用PIC16F1829微控制器和移位寄存器74HC595在Mastech HY3005D电源单元中用EC11机械编码器(累积角度传感器)替换标准电位计,以及在R2R电阻矩阵上实现DAC的移位寄存器

前言


     几年前,我购买了Mastech HY3005D电源。不久前,电压调节出现了问题-变阻器的石墨涂层磨损了,设置所需的电压成为一项艰巨的任务。没有合适的变阻器,我决定不购买类似的变阻器,而是改变调整方法。
     输出电压和电流的水平由提供给运算放大器的参考电压设置。因此,通过将电位计替换为能够提供所需范围电压的DAC,可以完全摆脱电位计。
     在微芯片目录中,我找不到合适的微控制器,该微控制器上有两个DAC,而外部DAC的价格不菲,而且功能过多。因此,我获得了R2R矩阵的移位寄存器74HC595和电阻。PIC16F1829微控制器已经有现货。
     为了能够返回到原始电路,所有更改都应最小化-更换在单独板上制作的调整单元。

职位描述


     该电路基于工作在32 MHz频率下PIC16F1829微控制器。时钟频率由内置时钟发生器设置,根据数据表,它不太准确,但是对于该电路而言,它并不重要。该MK的优势在于,所有数字输入和两个实现SPI的MSSP模块上均具有上拉电阻。微控制器的所有18个逻辑引脚均已使用。
     在四个移位寄存器上74HC595和R2R矩阵实现了两个16位DAC。该寄存器的优点包括存在单独的移位寄存器和存储寄存器。这使您可以在不中断当前输出值的情况下将数据写入寄存器。 R2R矩阵组装在电阻上,误差为1%。值得注意的是,选择性测量显示的误差不超过10欧姆。最初计划使用3个寄存器,但是在对电路板进行布线时,对我来说这不是一个好的解决方案,此外,有必要添加半字节。
     MC内置的上拉电阻在所有输入上均被激活,从而简化了电路。编码器的所有输出都直接连接到MK端子,总共4个编码器,每个都有两个用于旋转传感器本身的输出,一个用于内置按钮。共有12个结论MK用于处理输入数据。接触反弹的能力为100nF。根据来自编码器的输入数据更改16位电流和电压缓冲器的值后,这些值通过SPI传输到移位寄存器74HC595。为了减少数据传输时间,使用了两个SPI模块,这些模块允许同时传输电流和电压数据。数据传输到寄存器后,发送命令以将数据从移位缓冲区传输到存储缓冲区。寄存器的输出连接到矩阵R2R,作为DAC的分频器。来自矩阵的输出电压被传输到运算放大器的输入。
     编码器中内置的按钮分别为电流或电压设置最小值(用于平滑调节的编码器按钮)或最大值(用于粗调的编码器按钮)。

方案


     在Internet上,我没有找到与我完全吻合的方案,因此我选择了第一个链接。对发现的不一致之处进行更正,然后添加更改。我在TinyCAD中绘制了调整块的示意图-下载文件HY3005D-regulator.dsn

原来的


发现错误后


优化后的最终方案

带有调整功能便携式单元(红色突出显示)放置在单独的方案中。

J3连接器上连接了一个数字电压表,该数字电压表的前面板上有显示屏(未在图中显示)。

使用的组件


     以下是使用的组件列表(括号中表示大小写)。所有这些都是在中国的不同时间购买的。重要的是,使用与本地LED具有相同特性的LED,因为 它们串联在运算放大器的输出电路中(我拿的是主板上的相同)。
  • U1:PIC16F1829I / ML单片机(QFN)
  • U2-U5:移位寄存器74HC595BQ(DHVQFN16或SOT-763)
  • U6:AMS1117 5V线性稳压器(SOT-223)
  • RE1-RE4:机械累积角传感器EC11
  • R1,R2和R2R矩阵:1和2kΩ电阻(SMD 0402)
  • C1-C12,C14-C17:陶瓷电容器GRM21BR71E104KA01L 100nF(SMD 0805)
  • C13:钽电容器22mkF 16V(tiv B)
  • D1,D2:前面板电压/电流LED


手续费


     我在Sprint Layout 6中繁殖了该板-下载文件HY3005D-regulator.lay6不幸的是,我制作版本时所使用的原始版本并没有保留,其格式为莱利6格式,并且在组装过程中发现了一些更正:

  1. 我将固件接口旁边的跳线添加到了平滑电流控制编码器的中断连接,因为 容量过滤触点反弹可防止控制器闪烁
  2. 在两侧之间增加了地面缺少的跳线
  3. 将5V稳定组件移至另一侧以减少跳线
  4. 在电源线上添加了平滑电容器(讨论

蚀刻和钻孔后的照片(第一版)



     使用薄膜光刻胶制成。寄存器接线小,我受了很长时间。在后一种版本中,蚀刻后必须清除一些小的缺陷。但总的来说,董事会失败了。仍然没有足够的两个跳线来连接正面和背面的地面。

输入确定的问题之后(第二版)


0 SMD 0805.

拆焊并安装到位后的照片


      . — . — 12.

     如您所见,更改很小,所有旧连接器均保持不变。我不得不单独添加食物,因为 仅2.5V调节板上的电压不适用于本机分压器。如果在电源设备主板上将齐纳二极管移至2.5V(V5A),并在电阻器(R1A)处放置跳线,则无需额外提供12V电源。

韧体


XC8编译器的C代码。拼接了原始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               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(); }
    };
}


     对于最小值,将VoltageMin和CurrentMin设置为1,因为在缓冲区中的0处,调整将停止工作,直到我了解问题出在哪里。费率*费率*选择多个,在我看来是最方便的。对于SendData方法,我没有将变量作为参数传递来保存机器指令和内存。必须关闭低电压固件(LVP)模式,否则RA3不能用作数字输入。不使用中断,代码中包含tc_int方法,以便编译器将主块放在ROM的开头。
     对于固件,只需删除跳线,连接PICkit 3(或另一个编程器)并执行固件即可。在第一个版本中,CLK和DAT上没有跳线,因此我必须拆焊平滑电容器,将其闪光,然后再焊接回去。
UPD:在电源线上安装附加容量后,从零位置退出计数器的问题就消失了。我还必须更改旋转方向。显然,来自AMS1117整流器的噪声阻止了对编码器状态的正确识别。另外,我添加了一个起始值设置,现在默认电压设置为5伏(电流仍然最大)。在第一次发送数据之前,将50ms的延迟插入寄存器(该延迟值采用较大的余量)以等待SPI模块初始化。

输出电压特性


     在设备的最终组装之后,在触点J4.1-J4.2(电压调节)和J4.1-J4.7(电流调节)之间进行了电压测量。根据获得的数据,绘制DAC的值/电压相关性的图形(在扰流板下方)。
图表



电压的计算值通过公式(U * D)/(2 ^ K)获得,其中
U是寄存器的输出电压,其中考虑了主电路中的分压器(对于电流DAC-4950mV,对于电压DAC-3550mV);
D是DAC计数器的十进制值;
K-DAC位深度(16位)

有什么可以改善的


  • 添加计时器值保存
  • 将标准值绑定到编码器按钮,例如,电压:3.3;5.0; 7.5; 12伏
  • 为了防止启动时出现未知值,最好将MR连接至1,并在初始化MK之后将OE通过电阻拉至1,然后重置为0。
  • 与链替换DAC PWM平滑(提议 LampTester 这里

Source: https://habr.com/ru/post/zh-CN391617/


All Articles