The TPC116S8/TPC112S8 use a versatile 3-wire serial interface that operates at clock rates up to 30 MHz and is compatiblewith standard SPI®, QSPI™, MICROWIRE™, and DSP
interface standards。
简而言之tpc116s8使用一根时钟线,一根数据线,一根片选线完成控制,时序简单。
上图为tpc116s8对应的时序图,数据在SYNC一个下降沿拉低后,每一个时钟下降沿写入一位数据,SYNC拉高后停止写入。tpc116s8一帧数据24位。
高四位可以是任意值无影响,D19-D16四位数据位为通道选择位。
D19 - D16 0 - 7
0 0 0 0 通道A(0) 0 0 0 0
0 0 1 0 通道B(1) 0 0 0 1
0 1 0 0 通道C(2) 0 0 1 0
0 1 1 0 通道D(3) 0 0 1 1
1 0 0 0 通道E(4) 0 1 0 0
1 0 1 0 通道F(5) 0 1 0 1
1 1 0 0 通道G(6) 0 1 1 0
1 1 1 0 通道H(7) 0 1 1 1
也即控制位的四位,为对应通道阿拉伯数字左移一位得到。
低十六位为数据位 0xffff - 0x0000;对应电压换算,我想作为工程师的大家一定可以搞定。
接下来介绍我的测试电路,以及代码。
我通过LDAC管脚挂了三片tpc116s8。
DIN ---> PA15
ASCLK ----> PB3
ASYNC ----> PB4
LDAC1 -----> PB5
LDAC2 -----> PB7
LDAC3 -----> PB9
宏定义段
#ifndef _TPC116S8_H_
#define _TPC116S8_H_
#include "stm32f10x.h"
#include "delay.h"
#define ADIN(a) if(a) \
GPIO_SetBits(GPIOA, GPIO_Pin_15);\
else \
GPIO_ResetBits(GPIOA, GPIO_Pin_15)
#define ASCLK(a) if(a) \
GPIO_SetBits(GPIOB, GPIO_Pin_3);\
else \
GPIO_ResetBits(GPIOB, GPIO_Pin_3)
#define ASYNC(a) if(a) \
GPIO_SetBits(GPIOB, GPIO_Pin_4);\
else \
GPIO_ResetBits(GPIOB, GPIO_Pin_4)
#define LDAC_N1(a) if(a) \
GPIO_SetBits(GPIOB, GPIO_Pin_5);\
else \
GPIO_ResetBits(GPIOB, GPIO_Pin_5)
#define LDAC_N2(a) if(a) \
GPIO_SetBits(GPIOB, GPIO_Pin_7);\
else \
GPIO_ResetBits(GPIOB, GPIO_Pin_7)
#define LDAC_N3(a) if(a) \
GPIO_SetBits(GPIOB, GPIO_Pin_9);\
else \
GPIO_ResetBits(GPIOB, GPIO_Pin_9)
void tpc116s8_Init(void);
void set_VI_value(uint8_t cs, uint8_t ch, uint32_t value);
#endif
逻辑实现主代码
#include "tpc116s8.h"
//初始化GPIO
void tpc116s8_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PB端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); //使能复用功能时钟
GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE );
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PA端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_7|GPIO_Pin_9; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOA
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //50M
GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA
//把所有的控制端I/O口置低
GPIO_SetBits(GPIOB, GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7 | GPIO_Pin_9);
GPIO_SetBits(GPIOA, GPIO_Pin_15);
}
//设置输出通道以及输出电压值
void set_VI_value(uint8_t cs, uint8_t ch, uint32_t value)
{
uint8_t out_ch = 0, i = 0;
uint32_t temp = 0;
temp = value; // 20位去除了控制位
out_ch = (ch << 1); // 左移一位得到要输出的控制位
ASYNC(0); //拉低 开始传输这一帧数据
DelayUs(1);
for (i = 0; i < 4; i++)
{
if (temp & 0x80000)
ADIN(1);
else
ADIN(0);
ASCLK(1);
DelayUs(1);
ASCLK(0); //下降沿写入数据
DelayUs(1);
ASCLK(1);
temp <<= 1; //左移一位
}
for (i = 0; i < 4; i++)
{
if (out_ch & 0x08) //高位
ADIN(1);
else
ADIN(0);
ASCLK(1);
DelayUs(1);
ASCLK(0); //下降沿写入数据
DelayUs(1);
ASCLK(1);
out_ch <<= 1; //左移一位
}
//传送数据位
for (i = 0; i < 16; i++)
{
if (temp & 0x80000)
ADIN(1);
else
ADIN(0);
ASCLK(1);
DelayUs(1);
ASCLK(0); //下降沿写入数据
DelayUs(1);
ASCLK(1);
temp <<= 1; //左移一位
}
ASYNC(1); //拉高结束传输
DelayUs(1);
switch(cs)
{
case 1: LDAC_N1(0); DelayUs(1); LDAC_N1(1); break;
case 2: LDAC_N2(0); DelayUs(1); LDAC_N2(1); break;
case 3: LDAC_N3(0); DelayUs(1); LDAC_N3(1); break;
default: break;
}
}
测试代码
set_VI_value(1, 0, (uint32_t)20000); //
set_VI_value(1, 1, (uint32_t)65535);
set_VI_value(1, 2, (uint32_t)57343);
set_VI_value(1, 3, (uint32_t)53247);
set_VI_value(1, 4, (uint32_t)49191);
set_VI_value(1, 5, (uint32_t)45055);
set_VI_value(1, 6, (uint32_t)40959);
set_VI_value(1, 7, (uint32_t)32767);
set_VI_value(2, 0, 0xfffff); //
set_VI_value(2, 1, 0xfefff);
set_VI_value(2, 2, 0xfdfff);
set_VI_value(2, 3, 0xfcfff);
set_VI_value(2, 4, 0xfbfff);
set_VI_value(2, 5, 0xfafff);
set_VI_value(2, 6, 0xf9fff);
set_VI_value(2, 7, 0xf7fff);
set_VI_value(3, 0, 0xfffff); //
set_VI_value(3, 1, 0xfefff);
set_VI_value(3, 2, 0xfdfff);
set_VI_value(3, 3, 0xfcfff);
set_VI_value(3, 4, 0xfbfff);
set_VI_value(3, 5, 0xfafff);
set_VI_value(3, 6, 0xf9fff);
set_VI_value(3, 7, 0xf7fff);
测试无图,但是DAC输出正常,可见程序可用,我会在附件里添加上完整的工程,需要的自取,亲点赞支持喔,原创不易。