【TLV5638使用--采用MSP430F5529控制】

前言

  题主在备赛2023全国大学生电子设计大赛,在练习题目时使用了压控增益放大器,使用的MSP430F5529单片机不具备片上DAC,于是采用了TLV5638作为DAC输出稳定电压对压控增益放大器进行控制,结合网络找到的资料(代码几乎全是),写下这篇文章供后来者参考。

硬件电路

  TLV5638采用比较简单的SPI通信协议,硬件电路比较简单。基本上没有什么需要注意的点,我采用的硬件电路采用芯片内部的参考电压,外围没有设计外部参考电压选择,具体的电路如下:
TLV5638硬件电路

软件驱动

控制时序分析

  从前面硬件电路可以看出,TLV5638的控制引脚只有三个,分别是数据传输引脚DIN、传输时钟SCLK和片选信号CS,使用时注意和单片机供地。芯片手册上给出了时序图如下:
在这里插入图片描述
  根据时序图可以看出,传输过程是这样的:首先将CS置低,而后设置DIN,再将SCLK由地置高,而后将SCLK置低,由此连续传输完16个数据后将CS置高。

  芯片手册上也给出了输出电压的计算公式,其中REF使用芯片内部的有1.024V和2.048V两种,芯片手册上计算公式如下图:
输出电压计算公式
  其中需要注意各个信号的最小持续时间如下:
在这里插入图片描述
SCLK的最短周期时间是50ns,即SCLK频率应该不高于20MHz。官方的信号频率要求如下:
在这里插入图片描述

官方示例

  TLV5638的控制字可以在手册中找到,基本上是先对控制寄存器进行数值写入,而后对需要控制的通道写入数据。
  根据芯片手册,对TLV5638的控制一共有三种,第一种是对DAC A的参考电压和输出进行控制:
在这里插入图片描述
先对控制寄存器写值,选择参考电压、电压工作模式和控制模式,然后将数据写到DAC A并将buffer中数据写到DAC B。

  官方的示例二是对DAC B进行控制,如下图:
在这里插入图片描述
首先对控制寄存器写值,然后将数据写到DAC B和buffer.
  官方示例三是对DAC A 和DAC B同时进行控制,如下图:
在这里插入图片描述
首先将数据写到控制寄存器,然后将数据写到buffer,最后将数据写到DAC A的同时将buffer中数据写到DAC B。

主要函数

  1. SPI通信的传输函数:
    下面展示一些 内联代码片
//向SPI写16位数据函数:SPIWrite( )
void SPIWrite(uint temp)
{
    
    
    uint i,n;
    Clr_PinCS();
    for(i=0;i<16;i++)
    {
    
    
        n=(temp&0x8000);
        if (n==0x8000)
            {
    
    Set_PinDIN();}
        else
            {
    
    Clr_PinDIN();}
        Set_PinSCLK();
        watch6=temp;
        temp<<=1;
        watch7=temp;
        nNop(1);
        Clr_PinSCLK();
        nNop(1);
    }
    Set_PinCS();
}
  1. 将电压从V转换成控制数据:
// An highlighted block
//将电压值转换为对应的12位数字量函数:VoltToData( )
int VoltToData(uint ref,float ex_ref,float out_volt)
{
    
    
    int temp;
    switch(ref)
    {
    
    
        case EXTERNAL:temp=(int)((out_volt*4096)/(2*ex_ref));
        break;
        case IN_1024:temp=(int)((out_volt*4096)/(2*1.024)/1.1);
        break;
        case IN_2048:temp=(int)((out_volt*4096)/(2*2.048)/1.1);
        break;
        default:break;
    }
    watchint=temp;
    watchint1=(temp&0xfff);
    return(temp&0xfff);
}

可以注意到后面两个都除了1.1,这个我也不知道为什么,除了之后输出的电压才与设置的一致。

  1. 实现官方例子的三种对DAC控制的方法:
//设置DAC A(即A通道)输出函数:SetDAC_A( )
void SetDAC_A(uint speed,uint ref,float ex_ref,float temp)
{
    
    
    int ModCMD;
    int Data;
    ModCMD=0x9000|(speed<<14)|(ref);
    Data=VoltToData(ref,ex_ref,temp);
    Data=Data|0x8000|(speed<<14);
    SPIWrite(ModCMD);
    nNop(10);
    SPIWrite(Data);
}

//设置DAC B(即B通道)输出函数:SetDAC_B( )
void SetDAC_B(uint speed,uint ref,float ex_ref,float temp)
{
    
    
    int ModCMD;
    int Data;
    ModCMD=0x9000|(speed<<14)|(ref);
    watchint5=ModCMD;
    Data=VoltToData(ref,ex_ref,temp);
    watchint2=temp;
    watchint3=Data;
    Data=Data|0x0000|(speed<<14);
    watchint4=Data;
    SPIWrite(ModCMD);
    nNop(10);
    SPIWrite(Data);
}

//设置DAC A与DAC B同时输出函数SetDAC_AB( )
void SetDAC_AB(uint speed,uint ref,float ex_ref,float temp1,float temp2)
{
    
    
    int ModCMD;
    int DataA,DataB;
    ModCMD=0x9000|(speed<<14)|(ref);
    DataA=VoltToData(ref,ex_ref,temp1);
    DataA=DataA|0x8000|(speed<<14);
    DataB=VoltToData(ref,ex_ref,temp2);
    DataB=DataB|0x1000|(speed<<14);
    SPIWrite(ModCMD);
    SPIWrite(DataB);
    SPIWrite(DataA);
}

完整代码

TLV5638.h文件:

//****************tlv5638头文件******************//

#ifndef _tlv5638_H_
#define _tlv5638_H_

#define uint unsigned int
#define uchar unsigned char

/*** 参数定义 ***/
//速度模式参数
#define FASTSP 1 //快速模式
#define SLOWSP 0 //慢速模式

//电源模式参数
#define PWR_DOWN 1 //掉电模式
#define PWR_ON 0 //正常模式

//寄存器选择参数
#define DACB_BUFFER 0 //写DACB和BUFFER
#define BUFFER 1 //写BUFFER
#define DACA_BUFFERTOB 2 //写DACA和BUFFER的值更新DACB
#define CONTROL 3 //写控制寄存器

//参考源选择参数
#define EXTERNAL 0 //外部参考源
#define IN_1024 1 //内部1.024V参考源
#define IN_2048 2 //内部2.048V参考源

//引脚定义
//sbit PinDIN=P0^0;
//sbit PinSCLK=P0^2;
//sbit PinCS=P0^4;

//引脚定义 p1.5 DIN ; P1.4 SCLK;P1.3 CS;

#define PinDIN BIT5
#define PinSCLK BIT4
#define PinCS BIT3

#define Set_PinDIN() P1OUT |= PinDIN //因为脚不能位处理,所以这样子对脚赋值
#define Set_PinSCLK() P1OUT |= PinSCLK
#define Set_PinCS() P1OUT |= PinCS


#define Clr_PinDIN() P1OUT |= PinDIN; P1OUT&=~PinDIN
#define Clr_PinSCLK() P1OUT |= PinSCLK; P1OUT&=~PinSCLK //此处是给其求反,得到该位为零
#define Clr_PinCS() P1OUT |= PinCS; P1OUT&=~PinCS

//函数功能:短延时
void nNOP(uchar x);

//函数功能:长延时
void LongDelay(uint i);

//函数功能:置/复位CS信号
//说明:x=1—置位,x=0—复位
//#define SetCS(x)(PinCS=(x)?1:0)

//函数功能:置/复位SCLK信号
//说明:x=1—置位,x=0—复位
//#define SetSCLK(x) (PinSCLK=(x)?1:0)

//函数功能:向SPI写16位数据
//说明:temp为16位的数据
void SPIWrite(uint temp);

//函数功能:将电压值转换为对应的12位数字量
//说明:ref为参考源,ex_ref为当选择外部参考源的电压值,
// out_volt为输出模拟电压值
// 返回12数字量
int VoltToData(uint ref,float ex_ref,float out_volt);

//函数功能:设置DAC A(即A通道)输出
//说明:speed为速度模式,ref为参考源选择,temp为需要输出的电压
// ex_ref为当选择外部参考源的电压值
void SetDAC_A(uint speed,uint ref,float ex_ref,float temp);

//函数功能:设置DAC B(即B通道)输出
//说明:speed为速度模式,ref为参考源选择,temp为需要输出的电压
// ex_ref为当选择外部参考源的电压值
void SetDAC_B(uint speed,uint ref,float ex_ref,float temp);

//函数功能:设置DAC A与DAC B同时输出
//说明:speed为速度模式,ref为参考源选择,
// temp1为A通道需要输出的电压,temp2为B通道需要输出的电压
// ex_ref为当选择外部参考源的电压值
void SetDAC_AB(uint speed,uint ref,float ex_ref,float temp1,float temp2);
#endif//_TLV5638_H_

TLV5638.c文件:

/*
 * TLV5638.c
 *
 *  Created on: 2023年7月25日
 *      Author: jrz
 */
//**************主函数*****************//

#include <msp430.h>
#include "tlv5638.h"
//unsigned char watchar=0;
//long watchlong=0;
unsigned int watchint=0,watchint1=0,watchint2=0 ,watchint3=0,watchint4=0,watchint5=0,watch6=0,watch7;
//短延时函数:nNop( )
void nNop(uchar i)
{
    
    
    for(;i>0;i--);
}

//长延时函数:LongDelay( )
void LongDelay(uint i)
{
    
    
    uint j;
    for(;i>0;i--)
    {
    
    
        for(j=1000;j>0;j--);
    }
}

//向SPI写16位数据函数:SPIWrite( )
void SPIWrite(uint temp)
{
    
    
    uint i,n;
    Clr_PinCS();
    for(i=0;i<16;i++)
    {
    
    
        n=(temp&0x8000);
        if (n==0x8000)
            {
    
    Set_PinDIN();}
        else
            {
    
    Clr_PinDIN();}
        Set_PinSCLK();
        watch6=temp;
        temp<<=1;
        watch7=temp;
        nNop(1);
        Clr_PinSCLK();
        nNop(1);
    }
    Set_PinCS();
}

//将电压值转换为对应的12位数字量函数:VoltToData( )
int VoltToData(uint ref,float ex_ref,float out_volt)
{
    
    
    int temp;
    switch(ref)
    {
    
    
        case EXTERNAL:temp=(int)((out_volt*4096)/(2*ex_ref));
        break;
        case IN_1024:temp=(int)((out_volt*4096)/(2*1.024)/1.1);
        break;
        case IN_2048:temp=(int)((out_volt*4096)/(2*2.048)/1.1);
        break;
        default:break;
    }
    watchint=temp;
    watchint1=(temp&0xfff);
    return(temp&0xfff);
}

//设置DAC A(即A通道)输出函数:SetDAC_A( )
void SetDAC_A(uint speed,uint ref,float ex_ref,float temp)
{
    
    
    int ModCMD;
    int Data;
    ModCMD=0x9000|(speed<<14)|(ref);
    Data=VoltToData(ref,ex_ref,temp);
    Data=Data|0x8000|(speed<<14);
    SPIWrite(ModCMD);
    nNop(10);
    SPIWrite(Data);
}

//设置DAC B(即B通道)输出函数:SetDAC_B( )
void SetDAC_B(uint speed,uint ref,float ex_ref,float temp)
{
    
    
    int ModCMD;
    int Data;
    ModCMD=0x9000|(speed<<14)|(ref);
    watchint5=ModCMD;
    Data=VoltToData(ref,ex_ref,temp);
    watchint2=temp;
    watchint3=Data;
    Data=Data|0x0000|(speed<<14);
    watchint4=Data;
    SPIWrite(ModCMD);
    nNop(10);
    SPIWrite(Data);
}

//设置DAC A与DAC B同时输出函数SetDAC_AB( )
void SetDAC_AB(uint speed,uint ref,float ex_ref,float temp1,float temp2)
{
    
    
    int ModCMD;
    int DataA,DataB;
    ModCMD=0x9000|(speed<<14)|(ref);
    DataA=VoltToData(ref,ex_ref,temp1);
    DataA=DataA|0x8000|(speed<<14);
    DataB=VoltToData(ref,ex_ref,temp2);
    DataB=DataB|0x1000|(speed<<14);
    SPIWrite(ModCMD);
    SPIWrite(DataB);
    SPIWrite(DataA);
}

示例主函数:

#include <msp430.h>
#include "tlv5638.h"
float vout,m;
int i,j;
void Init_DA5638()
{
    
    
    Clr_PinDIN();
    Clr_PinCS();
    Clr_PinSCLK();
}

void main(void)
{
    
    
    WDTCTL = WDTPW | WDTHOLD;     // Stop watchdog timer
    P1DIR|=PinDIN+PinSCLK+PinCS;
    Init_DA5638();
    while(1)
    {
    
    
        SetDAC_AB(FASTSP,IN_1024,0,2.0,0.5);
    }
}

一些问题

  实际使用的过程中有这样的问题,函数都是按照芯片手册上写出来的,但是对DAC A或者DAC B单独进行设置时会发现设置不成功,对DAC A 和DAC B同时设置时会只对DAC B设置,而DAC A没有设置成功(只设置一次)。但是将对DAC A 和DAC B同时设置的函数反复执行时是设置成功的,考虑到控制电压也只是直流电压,这样也能勉强满足要求,没有进一步思索。

输出结果

  使用上面的反复设置的方法对DAC A和DAC B进行了同时的设置,分别将两通道电压设置为0.8V和0.1V,示波器显示的结果如下:
在这里插入图片描述
在这里插入图片描述
  可见电压数值还是比较准确的,但是在信号上叠加了一个100多K的固定信号,很奇怪,最后也没有找到引起这个结果的原因,猜测可能是电源造成的,因为在电源上也有看到,但是使用其他模块的未出现这个现象,要是找到原因的可以指导一下,最后是采用了有源低通滤波器滤掉了这个交流信号,因为控制信号为直流,滤除后结果如下:
在这里插入图片描述
在这里插入图片描述
  最后数值还算准确,噪声也比较小,勉强达到了使用的要求。

猜你喜欢

转载自blog.csdn.net/qq_55600803/article/details/131946733