DAC芯片——TLV5636ID
TLV5636是一个12位电压输出的DAC芯片,它的内部控制寄存器为16位,其中高4位是控制位,后12位是DAC的数据位。可以通过写入16位数据对芯片进行配置,
一、TLV5636ID介绍。
1.封装图
2.各引脚意义
(1)DIN:串行数据的输入管脚
(2)SCLK: DAC的时钟输入管脚
(3)CS:DAC芯片的片选信号,低电平有效。
(4)FS:同步信号。
(5)AGND:模拟地
(6)REF:DAC的外部参考电压输入,可通过编程选取内部基准还是外部基准电压。
(7)OUT:DAC芯片输出电压。电压计算为 V = 2 *(data)/(2*exp(12) = 4096)
(8) VDD:电源
3.内部结构电路
可以看到芯片的输入为DIN、SCLK、 、FS四个信号,在其内部有一个12位的数据锁存器,用于存放输入数据,另外2位的控制参考电压锁存器和2位功率和速度控制锁存器,共同构成16位输入数据。
4.TLV5636ID的时序图
从数据手册上看,TLV5636ID的 最小时钟周期时间为50ns,也就是最大的时钟频率为20MHz,在编程的时候应该考虑到这个,一般SPI挂接在APB1或者APB2上,时钟周期拿STM32F103来说是72MHz/36MHz。通过对SPI设置分频系数来满足不超过20MHz的条件。
其中几个重要的时间如下:
a. TwH(FS):FS信号拉高持续时间,最低为半个时钟周期。FS信号非常重要,FS的下降沿告诉DAC芯片开始数据传输。所以在开启使能后必须要使得FS信号线产生一个下降沿信号
b.Tsu(D):数据准备时间。其实相当于数据稳定时间,这个时间最小为1/6个SPI时钟周期。
d.Tsu(H):数据有效时间。这段数据可以经SPI读取最小为1/10个SPI时钟周期。
e.Tsu(c16-cs):D0被采样后的第一个上升沿到CS拉高的最小时间,最小为1/10个SPI时钟周期。
5.串行接口
TLV5636ID兼容3种接口如下:
各种接口协议下的连接如上图。
必须注意的是:TLV5636ID的工作必须拉低CS信号,其次要给FS信号一个下降沿,告诉数据传输开始,这样移位寄存器将数据移入(MSB,高位先移动,软件需设置成一样)锁存器中,在16个数据被采集完毕或者FS拉高后,数据将会输出到OUT端。 另外,如果是使用SPI接口时,需要对DAC芯片进行配置,所以写入的第一个数据是配置DAC的工作模式的,如果数据位宽是8位的,那么需要进行两次写操作,这个不必重复进行。配置完后可以进行正常的数据传输。
6.TLV5636ID的数据格式
二、软件编程
1.流程
根据前面的数据手册,为了方便,先用软件模拟SPI进行数据传输,硬件的还没有试。
第一步:初始化TLV5636ID,软件模拟的话就初始化个人选择的4个端口,分别代表DAC的DIN,SCLK,CS和FS信号。我选择的分别是PB15,PB13,PB12,PA6。
第二步:配置 SPI的工作模式,写入数据0xD003(外部输入基准电压),使用内部的基准电压时写入数据0xD002或者0xD000。
第三步:写入需要写入的数据。(数据时一次性的,只为了测试DAC芯片的输出功能是否正常)
2.代码
//tlv5636.h
#ifndef __TLC5636_H__
#define __TLC5636_H__
#include “stm32f10x.h”
/* 定义GPIO端口 */
#define RCC_SCK RCC_APB2Periph_GPIOB
#define PORT_SCK GPIOB
#define PIN_SCK GPIO_Pin_13
#define RCC_DIN RCC_APB2Periph_GPIOB
#define PORT_DIN GPIOB
#define PIN_DIN GPIO_Pin_15
//#define RCC_DOUT RCC_APB2Periph_GPIOB
//#define PORT_DOUT GPIOB
//#define PIN_DOUT GPIO_Pin_14
#define RCC_CS RCC_APB2Periph_GPIOB
#define PORT_CS GPIOB
#define PIN_CS GPIO_Pin_12
#define RCC_FS RCC_APB2Periph_GPIOA
#define PORT_FS GPIOA
#define PIN_FS GPIO_Pin_6
/* 定义口线置0和置1的宏 */
#define CS_0() GPIO_ResetBits(PORT_CS, PIN_CS)
#define CS_1() GPIO_SetBits(PORT_CS, PIN_CS)
#define SCK_0() GPIO_ResetBits(PORT_SCK, PIN_SCK)
#define SCK_1() GPIO_SetBits(PORT_SCK, PIN_SCK)
#define DI_0() GPIO_ResetBits(PORT_DIN, PIN_DIN)
#define DI_1() GPIO_SetBits(PORT_DIN, PIN_DIN)
#define FS_0() GPIO_ResetBits(PORT_FS, PIN_FS)
#define FS_1() GPIO_SetBits(PORT_FS, PIN_FS)
void tlc5636_Init(void);
void tlc5636_Send16Bit(uint16_t _data);
void tlc5636_Write2Byte(uint16_t data);
#endif
//tlv5636.c
#include “tlc5636.h”
#include “SysTick.h”
#include “gpioport.h”
/*
*********************************************************************************************************
* 函 数 名: tlc5636_Init
* 功能说明: TLV5636的初始化
* 形 参: 无
* 返 回 值: 无
*********************************************************************************************************
*/
void tlc5636_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_SCK | RCC_DIN |RCC_FS| RCC_CS, ENABLE);
/* 配置几个推挽输出IO */
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* 设为输出口 */
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = PIN_SCK;
GPIO_Init(PORT_SCK, &GPIO_InitStructure);//时钟引脚初始化
GPIO_InitStructure.GPIO_Pin = PIN_DIN; /*对于主机而言为输入,对于从机而言为输出,因此此处配置成输出*/
GPIO_Init(PORT_DIN, &GPIO_InitStructure);//MOSI引脚初始化
GPIO_InitStructure.GPIO_Pin = PIN_CS;
GPIO_Init(PORT_CS, &GPIO_InitStructure);//CS端初始化
GPIO_InitStructure.GPIO_Pin = PIN_FS;
GPIO_Init(PORT_FS, &GPIO_InitStructure);//FS端初始化
SCK_0(); CS_1(); FS_0();//空闲状态时,SCLK置0,CS置1,FS置0
}
/*
*********************************************************************************************************
* 函 数 名: TLC5636_Send16Bit
* 功能说明: 向TLV5636总线发送16个bit数据。
* 形 参: _data : 数据
* 返 回 值: 无
*********************************************************************************************************
*/
void tlc5636_Send16Bit(uint16_t _data)
{
uint8_t i;
FS_1();
delay_us(12);
FS_0();
for(i = 0; i < 16; i++)
{
if (_data & 0x8000)
{
DI_1();
}
else
{
DI_0();
}
SCK_1();
_data <<= 1;
delay_us(10);
SCK_0();
delay_us(10);
}
}
void tlc5636_Write2Byte(uint16_t _data)
{
CS_0();
tlc5636_Send16Bit(_data);
CS_1();
// FS_1();//这条不能写,因为FS = 1,意味着数据传输完成,所以DAC芯片的输出测不到电压值。切记
}
//main.c
#include “gpioport.h”
#include “system.h”
#include “SysTick.h”
#include “tlc5636.h”
int main(void)
{
RCC_HSE_Config(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
SysTick_Init(72);
LED1_Init();
tlc5636_Init();
tlc5636_Write2Byte(0xD003);//设置DAC得参考电压和工作模式
while(1)
{
LED1 = 0;
delay_s(1);
LED1 = 1;
delay_s(1);
tlc5636_Write2Byte(0x4FFF);
}
}
#include “system.h” 系统位带定义头文件
#include “SysTick” 系统定时器的头文件
至此,TLV5636软件模拟SPI驱动DAC工作程序完成
三、总结问题
1.数据手册的时序很重要以及DAC芯片的工作原理。
2.配置时的数据可以不放入到循环中,而写入的数据时,函数必须放大循环内部,让DAC芯片不断的去读取,这样输出端才能输出电压。之前老是没有电压,可能是DAC输出的电压输出后就清0了,根据他的工作原理。时间很短,所以不能测量,所以需要不停的写入。(这块后续再理解理解,感觉这样解释很勉强)
后续:硬件SPI驱动TLC5636工作
经过调试,之前不能写FS = 1的问题的理解是错误的,可以写。在使用SPI驱动时,出现CS拉高后不能测出电压的情况,经过调试,知道是SPI在发送数据的时候,指令SPI2_WriteByte(0xD003)仅仅是芯片给SPI的一个命令,给完芯片继续执行下一条指令,自己的程序没有考虑到SPI总线的数据缓冲器发送完16位数据所需要的时间,所以有可能没发送完就被CS_1()给断掉了。后续加入一个延时就可以了。
1.代码
//main.c
#include “system.h”
#include “gpioport.h”
#include “SysTick.h”
#include “spi.h”
#include “tlc5636.h”
int main(void)
{
RCC_HSE_Config(RCC_PLLSource_HSE_Div2,RCC_PLLMul_2);//16MHz系统时钟
SysTick_Init(8);//系统定时器初始化
LED1_Init();//LED1初始化
SPI2_Init();//初始化SPI2
TLC5636_Init();//初始化DAC芯片
while(1)
{
LED1 = 1;
delay_s(1);//延时1s
LED1 = 0;
delay_s(1);
TLC5636_Write16Bit(0x48ff);
}
//tlc5636.h
#include “tlc5636.h”
#include “SysTick.h”
#include “gpioport.h”
void TLC5636_Init(void)
{
CS_0();
delay_us(10);
while( SCLK != 0 );//SCLK为0退出
FS_1();
delay_us(20);
FS_0();
SPI2_WriteByte(0xD003);//配置DAC芯片
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空
delay_us(1000);
CS_1();
FS_1();
}
void TLC5636_Write16Bit(u16 data)
{
CS_0();//CS拉低,开启DAC
delay_us(10);//延时10us
while( SCLK != 0 );//判断SCLK为空闲状态
FS_1();
delay_us(20);
FS_0();
SPI2_WriteByte(data);//配置DAC芯片
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空
delay_us(1000);//SPI时钟周期为32us,16位数据移位完成最少512us,延时1000us
CS_1();//CS拉高
FS_1();//FS拉高
}
//tlc5636.c
#include “tlc5636.h”
#include “SysTick.h”
#include “gpioport.h”
void TLC5636_Init(void)
{
CS_0();
delay_us(10);
while( SCLK != 0 );//SCLK为0退出
FS_1();
delay_us(20);
FS_0();
SPI2_WriteByte(0xD003);//配置DAC芯片
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空
delay_us(1000);
CS_1();
FS_1();
}
void TLC5636_Write16Bit(u16 data)
{
CS_0();//CS拉低,开启DA
delay_us(10);//延时10us
while( SCLK != 0 );//判断SCLK为空闲状态
FS_1();
delay_us(20);
FS_0();
SPI2_WriteByte(data);//配置DAC芯片
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空
delay_us(1000);//SPI时钟周期为32us,16位数据移位完成最少512us,延时1000us
CS_1();//CS拉高
FS_1();//FS拉高
}
//spi.h
#ifndef _spi_H
#define _spi_H
#include “system.h”
/* 定义GPIO端口 */
#define RCC_SCK RCC_APB2Periph_GPIOB
#define PORT_SCK GPIOB
#define PIN_SCK GPIO_Pin_13
#define RCC_DIN RCC_APB2Periph_GPIOB
#define PORT_DIN GPIOB
#define PIN_DIN GPIO_Pin_15
//#define RCC_DOUT RCC_APB2Periph_GPIOB
//#define PORT_DOUT GPIOB
//#define PIN_DOUT GPIO_Pin_14
#define RCC_CS RCC_APB2Periph_GPIOB
#define PORT_CS GPIOB
#define PIN_CS GPIO_Pin_12
#define RCC_FS RCC_APB2Periph_GPIOA
#define PORT_FS GPIOA
#define PIN_FS GPIO_Pin_6
/* 定义口线置0和置1的宏 */
#define CS_0() GPIO_ResetBits(PORT_CS, PIN_CS)
#define CS_1() GPIO_SetBits(PORT_CS, PIN_CS)
#define SCK_0() GPIO_ResetBits(PORT_SCK, PIN_SCK)
#define SCK_1() GPIO_SetBits(PORT_SCK, PIN_SCK)
#define DI_0() GPIO_ResetBits(PORT_DIN, PIN_DIN)
#define DI_1() GPIO_SetBits(PORT_DIN, PIN_DIN)
#define FS_0() GPIO_ResetBits(PORT_FS, PIN_FS)
#define FS_1() GPIO_SetBits(PORT_FS, PIN_FS)
void SPI2_Init(void); //初始化SPI2口
void SPI2_SetSpeed(u8 SpeedSet); //设置SPI2速度
//u16 SPI2_ReadWriteByte(u16 TxData);//SPI2总线读写一个字节
void SPI2_WriteByte(u16 data);
#endif
//spi.c
#include “spi.h”
#include “gpioport.h”
//SPI口初始化
void SPI2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
/* SPI的IO口和SPI外设打开时钟 */
RCC_APB2PeriphClockCmd( RCC_SCK | RCC_DIN | RCC_FS | RCC_CS, ENABLE );
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
//配置SPI的外设端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = PIN_SCK;
GPIO_Init(PORT_SCK, &GPIO_InitStructure);//时钟引脚初始化
GPIO_InitStructure.GPIO_Pin = PIN_DIN;
GPIO_Init(PORT_DIN, &GPIO_InitStructure);//数据输出引脚初始化
//配置CS,FS端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = PIN_CS;
GPIO_Init(PORT_CS, &GPIO_InitStructure);//CS端初始化
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Pin = PIN_FS;
GPIO_Init(PORT_FS, &GPIO_InitStructure);//FS端初始化
//配置SPI的工作模式
SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx; //SPI设置为单线传输模式,不需要读取DAC数据
SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //设置SPI工作模式:设置为主SPI
SPI_InitStructure.SPI_DataSize = SPI_DataSize_16b; //设置SPI的数据大小:SPI发送接收16位帧结构
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //串行同步时钟的空闲状态为低电平,保持与TLC5636的时序一致
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge; //串行同步时钟的下降沿数据被采样
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //内部NSS信号有SSI位控制
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;//波特率预分频值为256
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据传输从MSB位开始,与TLC5636的规定一致
SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC值计算的多项式
SPI_Init(SPI2, &SPI_InitStructure); //根据SPI_InitStruct中指定的参数初始化外设SPIx寄存器
SPI_Cmd(SPI2, ENABLE); //使能SPI外设
CS_1();//取消片选
FS_0();//拉高同步信号
SPI2_WriteByte(0xffff);//启动传输
}
//SPI2速度设置函数
void SPI2_SetSpeed(u8 SPI_BaudRatePrescaler)
{
SPI2->CR1&=0XFFC7;//位3-5清零,用来设置波特率
SPI2->CR1|=SPI_BaudRatePrescaler; //设置SPI速度
SPI_Cmd(SPI2,ENABLE); //使能SPI2
}
void SPI2_WriteByte(u16 data)
{
while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET);//等待发送区空
SPI_I2S_SendData(SPI2,data);
// while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); //等待接收完一个byte
// return SPI_I2S_ReceiveData(SPI2); //返回通过SPIx最近接收的数据
}
今天的文章stm32驱动tm1638_芯片id是什么意思「建议收藏」分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/89521.html