【TLV5638使用–采用MSP430F5529控制】

【TLV5638使用–采用MSP430F5529控制】文章介绍了在全国大学生电子设计大赛中使用 TLV5638 作为 DAC 配合 MSP430F5529 单片机进行电压控制的实践经验

大家好,欢迎来到IT知识分享网。

前言

  题主在备赛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的固定信号,很奇怪,最后也没有找到引起这个结果的原因,猜测可能是电源造成的,因为在电源上也有看到,但是使用其他模块的未出现这个现象,要是找到原因的可以指导一下,最后是采用了有源低通滤波器滤掉了这个交流信号,因为控制信号为直流,滤除后结果如下:
在这里插入图片描述
在这里插入图片描述
  最后数值还算准确,噪声也比较小,勉强达到了使用的要求。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/155706.html

(0)
上一篇 2025-02-17 18:00
下一篇 2025-02-17 18:05

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信