303 lines
11 KiB
C
303 lines
11 KiB
C
/*
|
||
* DAC8568/DAC8168/DAC8568 驱动程序
|
||
* 作者: 雪豹
|
||
*/
|
||
#include "dac8568.h"
|
||
#include "main.h"
|
||
|
||
static SPI_HandleTypeDef *hspi_dac; // SPI句柄指针,用于SPI通信
|
||
|
||
/**
|
||
* @brief 初始化DAC8568驱动。
|
||
* @param hspi SPI外设句柄指针。
|
||
* @note 此函数会保存SPI句柄,并将CS和LDAC引脚初始化为高电平。
|
||
* 默认执行软件复位,可选启用内部参考电压。
|
||
*/
|
||
void DAC8568_Init(SPI_HandleTypeDef *hspi)
|
||
{
|
||
hspi_dac = hspi; // 保存SPI句柄
|
||
|
||
// 初始化CS和LDAC引脚为高电平(空闲状态)
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
HAL_GPIO_WritePin(DAC8568_LDAC_GPIO_Port, DAC8568_LDAC_Pin, GPIO_PIN_SET);
|
||
|
||
// 执行软件复位
|
||
DAC8568_SoftwareReset();
|
||
}
|
||
|
||
/**
|
||
* @brief 向DAC指定通道的输入寄存器写入数据。
|
||
* @param channel 目标DAC通道 (CHANNEL_A 到 CHANNEL_H, 或 BROADCAST)。
|
||
* @param data 要写入的16位数据。
|
||
*/
|
||
void DAC8568_Write(uint8_t channel, uint16_t data)
|
||
{
|
||
uint8_t txData[4];
|
||
|
||
// 构造32位帧
|
||
txData[0] = 0b00000000 | (CMD_WRITE_INPUT_REG & 0b00001111);
|
||
txData[1] = ((channel & 0b00001111) << 4) | ((data >> 12) & 0b00001111);
|
||
txData[2] = (data >> 4) & 0xFF;
|
||
txData[3] = ((data & 0b00001111) << 4) | 0b00000000;
|
||
|
||
// 执行SPI传输
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET);
|
||
HAL_SPI_Transmit(hspi_dac, txData, 4, HAL_MAX_DELAY);
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
}
|
||
|
||
/**
|
||
* @brief 更新DAC指定通道的输出。
|
||
* @param channel 目标DAC通道 (CHANNEL_A 到 CHANNEL_H, 或 BROADCAST)。
|
||
*/
|
||
void DAC8568_Update(uint8_t channel)
|
||
{
|
||
uint8_t txData[4];
|
||
|
||
txData[0] = 0b00000000 | (CMD_UPDATE_DAC_REG & 0b00001111);
|
||
txData[1] = ((channel & 0b00001111) << 4) | 0b00000000;
|
||
txData[2] = 0;
|
||
txData[3] = 0;
|
||
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET);
|
||
HAL_SPI_Transmit(hspi_dac, txData, 4, HAL_MAX_DELAY);
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
}
|
||
|
||
/**
|
||
* @brief 向DAC指定通道的输入寄存器写入数据并立即更新其模拟输出。
|
||
* @param channel 目标DAC通道 (CHANNEL_A 到 CHANNEL_H)。
|
||
* @param data 要写入的16位数据。
|
||
*/
|
||
void DAC8568_WriteAndUpdate(uint8_t channel, uint16_t data)
|
||
{
|
||
uint8_t txData[4];
|
||
|
||
txData[0] = 0b00000000 | (CMD_WRITE_INPUT_UPDATE_ONE & 0b00001111);
|
||
txData[1] = ((channel & 0b00001111) << 4) | ((data >> 12) & 0b00001111);
|
||
txData[2] = (data >> 4) & 0xFF;
|
||
txData[3] = ((data & 0b00001111) << 4) | 0b00000000;
|
||
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET);
|
||
HAL_SPI_Transmit(hspi_dac, txData, 4, HAL_MAX_DELAY);
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
}
|
||
|
||
/**
|
||
* @brief 将数据数组中的值分别写入所有8个DAC通道的输入寄存器。
|
||
* @param data_array 包含8个uint16_t类型数据的数组指针,分别对应通道A到H。
|
||
* @note 此函数通过循环调用 DAC8568_Write 实现。
|
||
*/
|
||
void DAC8568_WriteAllChannels(uint16_t *data_array) // 参数为包含8个通道数据的数组指针
|
||
{
|
||
for (uint8_t ch = 0; ch < 8; ch++) // 遍历0到7,代表通道A到H
|
||
{
|
||
DAC8568_Write(ch, data_array[ch]); // 为当前通道 ch 写入数组中对应的数据
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief 更新所有DAC通道的模拟输出。
|
||
* @note 此函数使用CMD_UPDATE_DAC_REG命令和BROADCAST地址。
|
||
*/
|
||
void DAC8568_UpdateAllChannels(void)
|
||
{
|
||
uint8_t txData[4];
|
||
|
||
txData[0] = 0b00000000 | (CMD_UPDATE_DAC_REG & 0b00001111);
|
||
txData[1] = (BROADCAST << 4) | 0b00000000; // 使用 BROADCAST 地址
|
||
txData[2] = 0;
|
||
txData[3] = 0;
|
||
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET);
|
||
HAL_SPI_Transmit(hspi_dac, txData, 4, HAL_MAX_DELAY);
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
}
|
||
|
||
/**
|
||
* @brief 设置指定DAC通道或所有通道的电源模式。
|
||
* @param channel 目标通道 (CHANNEL_A 到 CHANNEL_H) 或 BROADCAST。
|
||
* @param mode 电源模式 (POWER_UP, POWER_DOWN_1K, POWER_DOWN_100K, POWER_DOWN_HIZ)。
|
||
* @note 参考数据手册第47页表13。
|
||
*/
|
||
void DAC8568_SetPowerMode(uint8_t channel, uint8_t mode)
|
||
{
|
||
uint8_t txData[4]; // 定义SPI传输的4字节数据缓冲区
|
||
|
||
// 32位帧格式:
|
||
// [31:28] 前缀位(0000)
|
||
// [27:24] 命令位(CMD_POWER_DOWN = 0100) - 电源控制命令
|
||
// [23:20] 地址位(channel) - 选择目标通道或广播
|
||
// [19:10] 均为0 (不关心)
|
||
// [9:8] PD1和PD0电源模式位 (位于整个SPI帧的DB9, DB8)
|
||
// [7:0] 均为0 (不关心, 包括特征位)
|
||
|
||
// 第一个字节 (DB31-DB24): 前缀位 + 命令位
|
||
txData[0] = 0b00000000 | (CMD_POWER_DOWN & 0b00001111);
|
||
|
||
// 第二个字节 (DB23-DB16): 地址位 + 数据高4位(此命令中为0)
|
||
txData[1] = ((channel & 0b00001111) << 4) | 0b00000000;
|
||
|
||
// 第三个字节 (DB15-DB8): 包含电源模式位 PD1(DB9) 和 PD0(DB8)
|
||
// (mode & 0b00000011) 提取 mode 参数中的 PD1(bit1) 和 PD0(bit0)。
|
||
// 这些位对应SPI帧的DB9和DB8,因此直接放入 txData[2] 的最低两位。
|
||
// txData[2] 的高6位 (DB15-DB10) 为 不关心 (设为0)。
|
||
txData[2] = (mode & 0b00000011); // PD1位于bit1, PD0位于bit0 of txData[2] (对应帧的D9, D8)
|
||
|
||
// 第四个字节 (DB7-DB0): 均为0 (不关心)
|
||
txData[3] = 0;
|
||
|
||
// 执行SPI传输
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET);
|
||
HAL_SPI_Transmit(hspi_dac, txData, 4, HAL_MAX_DELAY);
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
}
|
||
|
||
/**
|
||
* @brief 启用静态内部参考电压(2.5V)。
|
||
* @note 参考数据手册第44页表7。命令 CMD_INTERNAL_REF, 地址 0b0000, 特征位 REF_ENABLE。内部参考电压为2.5V,但是在C/D等级中内部会有一个2倍增益。见数据手册31页8.2.1
|
||
*/
|
||
void DAC8568_EnableStaticInternalRef(void)
|
||
{
|
||
DAC8568_SendRawCommand(CMD_INTERNAL_REF, 0b0000, 0x0000, REF_ENABLE);
|
||
}
|
||
|
||
/**
|
||
* @brief 禁用静态内部参考电压(2.5V)。
|
||
* @note 参考数据手册第44页表7。命令 CMD_INTERNAL_REF, 地址 0b0000, 特征位 REF_DISABLE。内部参考电压为2.5V,但是在C/D等级中内部会有一个2倍增益。见数据手册31页8.2.1
|
||
*/
|
||
void DAC8568_DisableStaticInternalRef(void)
|
||
{
|
||
DAC8568_SendRawCommand(CMD_INTERNAL_REF, 0b0000, 0x0000, REF_DISABLE);
|
||
}
|
||
|
||
/**
|
||
* @brief 启用内部参考的灵活模式 (Flex Mode)。
|
||
* @note 参考数据手册第45页表9。命令 CMD_INTERNAL_REF, 地址 0b0001, 数据位 D13=1, 特征位 0b0000。
|
||
*/
|
||
void DAC8568_EnableFlexMode(void)
|
||
{
|
||
// 数据位 D13 (对应整个16位数据字段的 bit 13) 设置为1
|
||
DAC8568_SendRawCommand(CMD_INTERNAL_REF, 0b0001, (1 << 13), 0b0000);
|
||
}
|
||
|
||
/**
|
||
* @brief 禁用内部参考的灵活模式 (Flex Mode)。
|
||
* @note 参考数据手册第45页表9。命令 CMD_INTERNAL_REF, 地址 0b0001, 数据位 D13=0, 特征位 0b0000。
|
||
* 禁用灵活模式后,内部参考的行为由静态模式控制位决定。
|
||
*/
|
||
void DAC8568_DisableFlexMode(void)
|
||
{
|
||
// 数据位 D13 设置为0
|
||
DAC8568_SendRawCommand(CMD_INTERNAL_REF, 0b0001, 0x0000, 0b0000);
|
||
}
|
||
|
||
/**
|
||
* @brief 在灵活模式下,设置内部参考是否始终开启。
|
||
* @param enable 1 表示始终开启, 0 表示根据需要自动开启/关闭 (默认行为)。
|
||
* @note 参考数据手册第45页表10。命令 CMD_INTERNAL_REF, 地址 0b0001, 数据位 D15 控制, 特征位 0b0000。
|
||
*/
|
||
void DAC8568_SetFlexModeRefAlwaysOn(uint8_t enable)
|
||
{
|
||
uint16_t data_bits = enable ? (1 << 15) : 0; // D15 控制
|
||
DAC8568_SendRawCommand(CMD_INTERNAL_REF, 0b0001, data_bits, 0b0000);
|
||
}
|
||
|
||
/**
|
||
* @brief 在灵活模式下,设置内部参考是否始终关闭。
|
||
* @param enable 1 表示始终关闭, 0 表示根据需要自动开启/关闭。
|
||
* @note 参考数据手册第45页表11。命令 CMD_INTERNAL_REF, 地址 0b0001, 数据位 D14 控制, 特征位 0b0000。
|
||
*/
|
||
void DAC8568_SetFlexModeRefAlwaysOff(uint8_t enable)
|
||
{
|
||
uint16_t data_bits = enable ? (1 << 14) : 0; // D14 控制
|
||
DAC8568_SendRawCommand(CMD_INTERNAL_REF, 0b0001, data_bits, 0b0000);
|
||
}
|
||
|
||
/**
|
||
* @brief 设置DAC清零时的行为。
|
||
* @param mode 清除代码模式 (CLEAR_CODE_ZERO_SCALE, CLEAR_CODE_MID_SCALE, CLEAR_CODE_FULL_SCALE, CLEAR_CODE_NO_OPERATION)。
|
||
* @note 参考数据手册第39页表5。
|
||
*/
|
||
void DAC8568_SetClearCode(uint8_t mode)
|
||
{
|
||
uint8_t txData[4]; // 定义SPI传输的4字节数据缓冲区
|
||
|
||
// 32位帧格式:
|
||
// [31:28] 前缀位(0000)
|
||
// [27:24] 命令位(CMD_CLEAR_CODE_REG = 0101) - 清除代码寄存器命令
|
||
// [23:4] 均为0 (不关心)
|
||
// [3:2] 特征位 F1, F0 (位于整个SPI帧的DB3, DB2) 控制清除模式
|
||
// [1:0] 均为0 (不关心)
|
||
|
||
// 第一个字节 (DB31-DB24): 前缀位 + 命令位
|
||
txData[0] = 0b00000000 | (CMD_CLEAR_CODE_REG & 0b00001111);
|
||
|
||
// 第二个字节 (DB23-DB16): 地址位(不关心, 设为0) + 数据高位(不关心, 设为0)
|
||
txData[1] = 0b00000000;
|
||
|
||
// 第三个字节 (DB15-DB8): 数据中间位(不关心, 设为0)
|
||
txData[2] = 0;
|
||
|
||
// 第四个字节 (DB7-DB0): 包含特征位 F1, F0
|
||
// (mode & 0b00000011) 提取 mode 参数的最低两位作为 F1(bit1)F0(bit0)。
|
||
// 左移2位,将它们放置到SPI帧的DB3和DB2位置。
|
||
txData[3] = (mode & 0b00000011) << 2; // F1(DB3), F0(DB2) 控制清除模式
|
||
|
||
// 执行SPI传输
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET);
|
||
HAL_SPI_Transmit(hspi_dac, txData, 4, HAL_MAX_DELAY);
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
}
|
||
|
||
/**
|
||
* @brief 执行软件复位。
|
||
*/
|
||
void DAC8568_SoftwareReset(void)
|
||
{
|
||
uint8_t txData[4];
|
||
|
||
txData[0] = 0b00000000 | (CMD_SOFTWARE_RESET & 0b00001111);
|
||
txData[1] = 0;
|
||
txData[2] = 0;
|
||
txData[3] = 0;
|
||
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET);
|
||
HAL_SPI_Transmit(hspi_dac, txData, 4, HAL_MAX_DELAY);
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
HAL_Delay(1);
|
||
}
|
||
|
||
/**
|
||
* @brief 直接发送一个完整的32位命令帧到DAC8568。
|
||
*/
|
||
void DAC8568_SendRawCommand(uint8_t cmd_bits, uint8_t addr_bits, uint16_t data_bits, uint8_t feature_bits)
|
||
{
|
||
uint8_t txData[4];
|
||
|
||
txData[0] = 0b00000000 | (cmd_bits & 0b00001111);
|
||
txData[1] = ((addr_bits & 0b00001111) << 4) | ((data_bits >> 12) & 0b00001111);
|
||
txData[2] = (data_bits >> 4) & 0xFF;
|
||
txData[3] = ((data_bits & 0b00001111) << 4) | (feature_bits & 0b00001111);
|
||
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET);
|
||
HAL_SPI_Transmit(hspi_dac, txData, 4, HAL_MAX_DELAY);
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
}
|
||
|
||
/**
|
||
* @brief 直接发送自定义的4字节原始数据到DAC8568。
|
||
* @param raw_data 指向包含4字节数据的数组。
|
||
* @note 此函数用于发送预先构建好的完整SPI帧。
|
||
*/
|
||
void DAC8568_SendRawData(uint8_t raw_data[4])
|
||
{
|
||
// 开始传输(拉低CS)
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET);
|
||
|
||
// SPI传输
|
||
HAL_SPI_Transmit(hspi_dac, raw_data, 4, HAL_MAX_DELAY); // 传输4字节
|
||
|
||
// 结束传输(拉高CS)
|
||
HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET);
|
||
} |