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