FastBond2阶段2-基于AD8220的程控放大器模块设计
基于ADI公司轨到轨输出JFET输入仪表放大器AD8220和1024位、1%电阻容差误差、SPI接口存储器数字变阻器AD5270设计了程控放大器模块,使用arduino编程控制放大器增益。
标签
测量
FastBond第二季
hhjinghh
更新2023-10-23
361

一、前言

之前在FastBond2阶段1的项目中展示了使用Scheme-it设计的原理图,介绍了程控放大模块的设计原理,也展示了项目中所使用到的活动规定厂家的芯片。本设计是程序控制的放大器模块,使用微控制器来控制SPI接口数字电位器AD5270的电阻值,从而调节仪表放大器AD8220的放大倍数,编程语言采用C语言,测试平台为arduino,十分方便移植到其它平台。

阶段1项目链接如下:https://www.eetree.cn/project/detail/2032

本文的内容是使用kicad设计原理图和PCB,样板的功能测试和主要程序的说明。

二、原理图及PCB介绍

阶段1的流程图及原理图初步设计都是由Scheme-it网页来绘制的,使用体验非常好,自带了很多元器件库和模块,还有其它伙伴的设计分享。使用了FastBond活动中要求的厂商芯片,ADI公司的AD5270数字电位器芯片和AD8220仪表放大器芯片。这里是链接:https://www.digikey.cn/schemeit/project/基于ad8220的程控放大器模块设计-686eb1feb7274c3493ea08b4616fa8db

如下图所示,输入信号和电源由排针接口输入,输出也是通过排针接口,输入采用了电容和电阻构成的高通滤波器,电容可以隔离直流信号,输出预留了RC低通滤波电路,可以根据实际应用需要焊接不同的电阻电容。

FqrGmhoiSApEQ-PWBpXWZrdmCiY2

仪表放大器AD8220的增益通过调节RG管脚2和3之间的电阻值,数字电位器AD5270电阻输出A、W管脚连接到RG脚上,AD5270采用SPI接口驱动,只需片选、数据输入、时钟即可。这样通过微控制驱动AD5270调节输出电阻就能控制仪表放大器的增益了。

之后设计PCB如下, 采用双面板设计,尺寸是追求mini一些,硬禾学堂提供的kicad教程十分有用,快速教我掌握了新版kicad设计要点。

FlAHhgFR3o17S9zCOFj2uup926Fk

三、样板功能测试

首先焊接板子,电源退耦电容先不焊接,先测试下功能的正确性,图中有一根飞线,果然第一次设计容易出问题,AD5270如果采用双电源供电,C4电容另一端应连接VSS而不是GND,如果用单电源供电就没问题,本次测试用双电源供电,所以飞线一下,还请大佬们见谅菜鸟的失误:

FkFffqU-Glo7hs5YH2kpt3vjTtk8

微控制器采用teensy开发板进行测试,SPI接口连接板子即可,电源、信号发生器、示波器均采用ADALM2000口袋仪表,下图是连线:

Fu0Oia5TXQNSWuIqSneMjrmQMfYB

四、程序功能说明

下面是完整的arduino测试程序,首先定义了SPI时钟等参数,然后定义了AD5270的控制命令(AD5270的数据手册详细说明了控制时序和各个命令的功能,这里就不赘述了),接下来封装了AD5270的控制函数:

#include "SPI.h"

#define SPI_FREQ_FAST      500000
#define SPI_FREQ_SLOW      500000
#define MOSI_PIN           5
#define SCK_PIN            4
#define CHIP_SEL_MEAS      13

// AD5270 commands - new digital potentiometer
#define CMD_WR_RDAC        0x01
#define CMD_RD_RDAC        0x02
#define CMD_ST_RDAC        0x03
#define CMD_RST            0x04
#define CMD_RD_MEM         0x05
#define CMD_RD_ADDR        0x06
#define CMD_WR_CTRL        0x07
#define CMD_RD_CTRL        0x08
#define CMD_SHTDN          0x09

/* Write a 4-bit command and a 10-bit data word */
void AD5270_Write(const int chip_sel, uint8_t cmd, uint16_t data)
{
    uint16_t data_word = ((cmd & 0x0F) << 10) | (data & 0x03FF);
  
    digitalWrite(chip_sel, LOW);
    delayMicroseconds(500);
    spi_write(MOSI_PIN, SCK_PIN, SPI_FREQ_FAST, MSBFIRST, SPI_MODE1, 16, data_word);
    delayMicroseconds(500);
    digitalWrite(chip_sel, HIGH);
}

/* Shift a byte out serially with the given frequency in Hz (<= 500kHz) */
void spi_write(uint8_t data_pin, uint8_t clock_pin, uint32_t freq, uint8_t bit_order, uint8_t mode, uint8_t bits, uint32_t val){
    uint32_t period = (freq >= 500000) ? 1 : (500000 / freq);   // Half clock period in uS
    uint8_t cpol = (mode == SPI_MODE2 || mode == SPI_MODE3);
    uint8_t cpha = (mode == SPI_MODE1 || mode == SPI_MODE3);
    uint8_t sck = cpol ? HIGH : LOW;

    uint8_t i;
    uint32_t start_time;

    // Set clock idle for 2 periods
    digitalWrite(clock_pin, sck);
    delayMicroseconds(period*4);

    for (i = 0; i < bits; i++)  {
        start_time = micros();

        // Shift bit out
        if (bit_order == LSBFIRST)
            digitalWrite(data_pin, !!(val & (1 << i)));
        else    
            digitalWrite(data_pin, !!(val & (1 << ((bits-1) - i))));

        // Toggle clock leading edge
        sck = !sck;
        if (cpha) {
            digitalWrite(clock_pin, sck);
            while(micros() - start_time < period);
        } else {
            while(micros() - start_time < period);
            digitalWrite(clock_pin, sck);
        }

        // Toggle clock trailing edge
        start_time = micros();
        sck = !sck;
        if (cpha) {
            digitalWrite(clock_pin, sck);
            while(micros() - start_time < period);
        } else {
            while(micros() - start_time < period);
            digitalWrite(clock_pin, sck);
        }
    }
}

/* Enable/disable rheostat value changes */
void AD5270_LockUnlock(const int chip_select, uint8_t lock){
  AD5270_Write(chip_select, CMD_WR_CTRL, lock ? 0 : 0x002);
}

/* Enable/disable hardware shutdown */
void AD5270_Shutdown(const int chip_select, uint8_t shutdown){
  AD5270_Write(chip_select, CMD_SHTDN, shutdown ? 1 : 0);
}

/* Set the value of the digital rheostat - range is 0-0x3FF (0-100kOhm) */
void AD5270_Set(const int chip_select, uint16_t val)
{
  AD5270_Write(chip_select, CMD_WR_RDAC, val);
}


void setup() 
{
  Serial.begin(115200);

  pinMode(CHIP_SEL_MEAS, OUTPUT);
  digitalWrite(CHIP_SEL_MEAS, HIGH);

  pinMode(MOSI_PIN, OUTPUT);
  pinMode(SCK_PIN, OUTPUT);

  Serial.println("starting with ");
  Serial.println(SPI_FREQ_FAST);

  delay(100);
  AD5270_LockUnlock(CHIP_SEL_MEAS, 0);
  delay(100);
  AD5270_Shutdown(CHIP_SEL_MEAS, 0);
  delay(100);
  AD5270_Set(CHIP_SEL_MEAS, 1023);

  delay(100);
}

int i = 0;
void loop() 
{
  for(i=0;i<1000;i+=10)
  {
    AD5270_Set(CHIP_SEL_MEAS, i);
    Serial.print("dat:");
    Serial.println(i);
    delay(2000);  
  }                
}

程序开始初始化了驱动管脚,SPI这里采用的是GPIO管脚模拟SPI时序的方法,这样相比用库更加灵活,初始化完成后就在主循环里面设置AD5270的输出电阻值,可以设置值为0~1023对应输出电阻值为0~50kΩ。根据AD8220数据手册中增益公式,G=1+49.4kΩ/RG,可以知道设置值越大最终放大器的增益越低。

FvZfQNI2Upae3ZolLfjVBdTwUFs0

这里有一个大坑需要注意的是AD5270的稳定时间较长,350ms左右,另外信号的稳定也需要时间,所以主循环中设置值后延时2秒再设置下一个,实际测试中如果延时1S就会出问题!!

最后关于测试的结果,在视频结尾给出了展示。

四、活动总结

感谢eetree和digkey举办的FastBond2活动,让我有机会分享一些电子模块的DIY,通过活动学习到了不少新技能,希望活动明年继续。

附件下载
原理图.pdf
原理图
pga.zip
kicad工程
ad5270_demo.ino
arduino程序
团队介绍
爱捣鼓电子模块
团队成员
hhjinghh
电子DIY爱好者。
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号