controller-pcba/User/driver/DAC8568.c

303 lines
11 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* 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);
}