驱动如下:
#include <stdint.h>
#include <math.h>
#include "LTC2656.h"
#include "BSP.h"
#include "SysConfig.h"
#include "global.h"
#define Debug_SPI 0
#define LTC2656_NUM_0 0U
#define LTC2656_NUM_1 1U
#define LTC2656_NUM_2 2U
// DAC Reference State
// Could have been zero or 1, this allows you to use the
// variable "reference_mode" as the command argument to a write
#define REF_INTERNAL LTC2656_CMD_INTERNAL_REFERENCE //!< Stored reference state is Internal
#define REF_EXTERNAL LTC2656_CMD_EXTERNAL_REFERENCE //!< Stored reference state is External
// Global variables
static uint8 shift_count = 0; //!< The data align shift count. For 16-bit=0, for 12-bits=4
static uint8 reference_mode; //!< Tells whether to set internal or external reference
// Global calibration variables
static int16 LTC2656_offset[9]; //!< DAC offset - index 8 for "all DACs"
static float LTC2656_lsb[9]; //!< The LTC2656 lsb - index 8 for "all DACs"
//! Lookup table for DAC address. Allows the "All DACs" address to be indexed right after DAC D in loops.
//! This technique is very useful for devices with non-monotonic channel addresses.
const uint8 address_map[9] = {LTC2656_DAC_A, LTC2656_DAC_B, LTC2656_DAC_C, LTC2656_DAC_D, LTC2656_DAC_E,
LTC2656_DAC_F, LTC2656_DAC_G, LTC2656_DAC_H,LTC2656_DAC_ALL
}; //<! Map entered option 0..2 to DAC address
typedef union LT_union_int16_2bytes
{
int16 LT_int16;
uint16 LT_uint16;
uint8 LT_byte[2];
}U_LT_Write;
static void LTC2656_1_Operation(const uint8* p_u8WriteBuf, uint8 *p_u8ReadBuf, uint8 u8Size);
static void LTC2656_2_Operation(const uint8* p_u8WriteBuf, uint8 *p_u8ReadBuf, uint8 u8Size);
static void LTC2656_3_Operation(const uint8* p_u8WriteBuf, uint8 *p_u8ReadBuf, uint8 u8Size);
static void LTC2656_write(uint8 LTC2656_Num, uint8 dac_command, uint8 dac_address, uint16 dac_code);
static uint16 LTC2656_voltage_to_code(float dac_voltage, float LTC2656_lsb, int16_t LTC2656_offset);
static void LTC2656_calibrate(uint16 dac_code1, uint16 dac_code2, float voltage1, float voltage2, float *LTC2656_lsb, int16_t *LTC2656_offset);
/*
*******************************************************************************
功能:初始化
参数:
LTC2656_Num LTC2656序号
返回: 无
*******************************************************************************
*/
void LTC2656_Init(uint32 u32_hard_version, uint8 LTC2656_Num)
{
uint8 i;
f32 dac_count = 0.0; /* The number of codes, 4096 for 12 bits, 65536 for 16 bits*/
f32 full_scale = 0.0; /* To avoid confusion - in internal ref mode, FS=Vref, in ext mode, FS=2*Vref*/
/* 设置外部参考电压模式*/
reference_mode = REF_EXTERNAL; /* Redundant if already set*/
/* Write the reference mode to the DAC right away*/
LTC2656_write(LTC2656_Num, reference_mode, 0x0F, 0x0000);
if(u32_hard_version <= DEFAULT_HARDWARE_VERSION)
{
/* V1.0.0.0硬件版本,LTC2656基准为5.0V */
full_scale = 5.0F;
}
else
{
/* V1.0.0.0之后硬件版本,LTC2656基准为4.096V */
full_scale = 4.096F;
}
/* Set up default values, shift count, DAC count*/
/* LTC2656CUF-H12, 12-bits, 4.096V full scale*/
shift_count = 4U;
dac_count = 4096U;
for (i = 0; i <= 8; i++)
{
LTC2656_offset[i] = 0;
LTC2656_lsb[i] = full_scale / dac_count;
}
}
//! Power down DAC
void LTC2656_power_down_dac(uint8 LTC2656_Num, uint8 selected_dac)
{
// Power down DAC
LTC2656_write(LTC2656_Num, LTC2656_CMD_POWER_DOWN, address_map[selected_dac], 0x0000);
}
//!Write data to DAC register (which updates output immediately)
void LTC2656_write_and_update_dac(uint8 LTC2656_Num, uint8 selected_dac, f32 dac_voltage)
{
uint16_t dac_code;
dac_code = LTC2656_voltage_to_code(dac_voltage, LTC2656_lsb[selected_dac], LTC2656_offset[selected_dac]);
if(dac_code >= 4096)
{
dac_code = 4095;
}
LTC2656_write(LTC2656_Num, LTC2656_CMD_WRITE_UPDATE, address_map[selected_dac], dac_code << shift_count);
}
//! Write data to input register, but do not update DAC output
void LTC2656_write_to_input_register(uint8 LTC2656_Num, uint8 selected_dac, float dac_voltage)
{
uint16_t dac_code;
dac_code = LTC2656_voltage_to_code(dac_voltage, LTC2656_lsb[selected_dac], LTC2656_offset[selected_dac]);
if(dac_code >= 4096)
{
dac_code = 4095;
}
LTC2656_write(LTC2656_Num, LTC2656_CMD_WRITE, address_map[selected_dac], dac_code << shift_count);
}
//! Update DAC with data that is stored in input register, power up if sleeping
void LTC2656_update_power_up_dac(uint8 LTC2656_Num, uint8 selected_dac)
{
// Update DAC
LTC2656_write(LTC2656_Num, LTC2656_CMD_UPDATE, address_map[selected_dac], 0x0000);
}
/*
*******************************************************************************
功能:读写操作
参数:
p_u8WriteBuf 要写入的数据
p_u8ReadBuf 读出的数据
u8Size 要写入数据的长度
返回: 无
*******************************************************************************
*/
static void LTC2656_1_Operation(const uint8* p_u8WriteBuf, uint8 *p_u8ReadBuf, uint8 u8Size)
{
uint8 u8Index = 0U;
uint8 u8WriteData = 0U;
uint8 u8ReadData = 0U;
SPI1_CS_LOW();
for(u8Index = 0U; u8Index < u8Size; u8Index++)
{
u8WriteData = *(p_u8WriteBuf + u8Index);
u8ReadData = SPI1_u8ReadWriteByte(u8WriteData);
*(p_u8ReadBuf + u8Index) = u8ReadData;
}
SPI1_CS_HIGH();
}
/*
*******************************************************************************
功能:读写操作
参数:
p_u8WriteBuf 要写入的数据
p_u8ReadBuf 读出的数据
u8Size 要写入数据的长度
返回: 无
*******************************************************************************
*/
static void LTC2656_2_Operation(const uint8* p_u8WriteBuf, uint8 *p_u8ReadBuf, uint8 u8Size)
{
uint8 u8Index = 0U;
uint8 u8WriteData = 0U;
uint8 u8ReadData = 0U;
SPI2_CS_LOW();
for(u8Index = 0U; u8Index < u8Size; u8Index++)
{
u8WriteData = *(p_u8WriteBuf + u8Index);
u8ReadData = SPI2_u8ReadWriteByte(u8WriteData);
*(p_u8ReadBuf + u8Index) = u8ReadData;
}
SPI2_CS_HIGH();
}
/*
*******************************************************************************
功能:读写操作
参数:
p_u8WriteBuf 要写入的数据
p_u8ReadBuf 读出的数据
u8Size 要写入数据的长度
返回: 无
*******************************************************************************
*/
static void LTC2656_3_Operation(const uint8* p_u8WriteBuf, uint8 *p_u8ReadBuf, uint8 u8Size)
{
uint8 u8Index = 0U;
uint8 u8WriteData = 0U;
uint8 u8ReadData = 0U;
SPI2_CS_HIGH();
for(u8Index = 0U; u8Index < u8Size; u8Index++)
{
u8WriteData = *(p_u8WriteBuf + u8Index);
u8ReadData = SPI3_u8ReadWriteByte(u8WriteData);
*(p_u8ReadBuf + u8Index) = u8ReadData;
}
SPI2_CS_LOW();
}
static void LTC2656_write(uint8 LTC2656_Num, uint8 dac_command, uint8 dac_address, uint16 dac_code)
// Write the 16-bit dac_code to the LTC2656
{
uint8 data_array[3], rx_array[3];
U_LT_Write data;
data.LT_uint16 = dac_code;
data_array[0] = dac_command | dac_address;
data_array[1] = data.LT_byte[1];
data_array[2] = data.LT_byte[0];
#if Debug_SPI
{
uint8 u8Index = 0U;
uint8 u8WriteData = 0U;
uint8 u8ReadData = 0U;
SPI2_CS_LOW();
for(u8Index = 0U; u8Index < 3; u8Index++)
{
u8WriteData = *(data_array + u8Index);
u8ReadData = SPI2_u8ReadWriteByte(u8WriteData);
*(rx_array + u8Index) = u8ReadData;
}
SPI2_CS_HIGH();
}
#else
if(LTC2656_NUM_0 == LTC2656_Num)
{
LTC2656_1_Operation(data_array, rx_array, (uint8)3);
}
else if(LTC2656_NUM_1 == LTC2656_Num)
{
LTC2656_2_Operation(data_array, rx_array, (uint8)3);
}
else if(LTC2656_NUM_2 == LTC2656_Num)
{
LTC2656_3_Operation(data_array, rx_array, (uint8)3);
}
else
{
/* nothing*/
}
#endif
}
static uint16 LTC2656_voltage_to_code(float dac_voltage, float LTC2656_lsb, int16_t LTC2656_offset)
// Calculate a LTC2656 DAC code given the desired output voltage and DAC address (0-7)
{
int32_t dac_code;
float float_code;
float_code = dac_voltage / LTC2656_lsb; //! 1) Calculate the DAC code
float_code = (float_code > (floor(float_code) + 0.5)) ? ceil(float_code) : floor(float_code); //! 2) Round
dac_code =(int32_t)float_code - LTC2656_offset; //! 3) Subtract offset
if (dac_code < 0) //! 4) If DAC code < 0, Then DAC code = 0
dac_code = 0;
return ((uint16_t)dac_code); //! 5) Cast DAC code as uint16_t
}
float LTC2656_code_to_voltage(uint16_t dac_code, float LTC2656_lsb, int16_t LTC2656_offset)
// Calculate the LTC2656 DAC output voltage given the DAC code and DAC address (0-7)
{
float dac_voltage;
dac_voltage = ((float)(dac_code + LTC2656_offset)* LTC2656_lsb); //! 1) Calculates the dac_voltage
return (dac_voltage);
}
/* 以下为修正用函数*/
static void LTC2656_calibrate(uint16 dac_code1, uint16 dac_code2, float voltage1, float voltage2, float *LTC2656_lsb, int16_t *LTC2656_offset)
// Calculate the LTC2656 offset and LSB voltage given two measured voltages and their corresponding codes
{
float temp_offset;
*LTC2656_lsb = (voltage2 - voltage1) / ((float) (dac_code2 - dac_code1)); //! 1) Calculate the LSB
temp_offset = voltage1/(*LTC2656_lsb) - (float)dac_code1; //! 2) Calculate the offset
temp_offset = (temp_offset > (floor(temp_offset) + 0.5)) ? ceil(temp_offset) : floor(temp_offset); //! 3) Round offset
*LTC2656_offset = (int16_t)temp_offset; //! 4) Cast as int16_t
}
//! Calibrate all DACs by measuring two known outputs
// Calibrate the selected DAC using a voltmeter. The routine does a linear curve fit given two data points.
void calibrate_dacs(uint8 LTC2656_Num)
{
// Calibrate the DACs using a multimeter
uint8 index;
uint16 code1 = 0x0200; //! Calibration code 1
uint16 code2 = 0xFFFF; //! Calibration code 2
float voltage1; //! Calibration voltage 1
float voltage2; //! Calibration voltage 2
for (index = 0; index < 8; index++)
{
// Left align 12-bit code1 to 16 bits & write to DAC
LTC2656_write(LTC2656_Num, LTC2656_CMD_WRITE_UPDATE, index, code1 << shift_count);
/* 用万用表读出测量值*/
// voltage1 = read_float();
// Left align 12-bit code2 to 16 bits & write to DAC
LTC2656_write(LTC2656_Num, LTC2656_CMD_WRITE_UPDATE, index, code2 << shift_count);
/* 用万用表读出测量值*/
// voltage2 = read_float();
LTC2656_calibrate(code1, code2, voltage1, voltage2, <C2656_lsb[index], <C2656_offset[index]);
}
}
头文件如下:
#ifndef LTC2656_H
#define LTC2656_H
#include "SPI.h"
//! @name LTC2656 Command Codes
//! @{
//! OR'd together with the DAC address to form the command byte
#define LTC2656_CMD_WRITE 0x00 //!< Write to input register n
#define LTC2656_CMD_UPDATE 0x10 //!< Update (power up) DAC register n
#define LTC2656_CMD_WRITE_UPDATE_ALL 0x20 //!< Write to input register n, update (power up) all
#define LTC2656_CMD_WRITE_UPDATE 0x30 //!< Write to input register n, update (power up) all
#define LTC2656_CMD_POWER_DOWN 0x40 //!< Power down n
#define LTC2656_CMD_POWER_DOWN_ALL 0x50 //!< Power down chip (all DACs and reference)
#define LTC2656_CMD_INTERNAL_REFERENCE 0x60 //!< Select internal reference (power up reference)
#define LTC2656_CMD_EXTERNAL_REFERENCE 0x70 //!< Select external reference (power down internal reference)
#define LTC2656_CMD_NO_OPERATION 0xF0 //!< No operation
//! @}
//! @name LTC2656 DAC Addresses
//! @{
//! Which DAC to operate on
#define LTC2656_DAC_A 0x00
#define LTC2656_DAC_B 0x01
#define LTC2656_DAC_C 0x02
#define LTC2656_DAC_D 0x03
#define LTC2656_DAC_E 0x04
#define LTC2656_DAC_F 0x05
#define LTC2656_DAC_G 0x06
#define LTC2656_DAC_H 0x07
#define LTC2656_DAC_ALL 0x0F
//! @}
/*
*******************************************************************************
功能:初始化
参数:
LTC2656_Num LTC2656序号
返回: 无
*******************************************************************************
*/
extern void LTC2656_Init(uint32 u32_hard_version, uint8 LTC2656_Num);
//! Power down DAC
extern void LTC2656_power_down_dac(uint8 LTC2656_Num, uint8 selected_dac);
//!Write data to DAC register (which updates output immediately)
extern void LTC2656_write_and_update_dac(uint8 LTC2656_Num, uint8 selected_dac, float dac_voltage);
//! Write data to input register, but do not update DAC output
extern void LTC2656_write_to_input_register(uint8 LTC2656_Num, uint8 selected_dac, float dac_voltage);
//! Update DAC with data that is stored in input register, power up if sleeping
extern void LTC2656_update_power_up_dac(uint8 LTC2656_Num, uint8 selected_dac);
#endif