diff --git a/Core/Inc/main.h b/Core/Inc/main.h index ecb59b3..e6db426 100644 --- a/Core/Inc/main.h +++ b/Core/Inc/main.h @@ -198,8 +198,8 @@ extern "C" #define DAC1_MISO_Pin GPIO_PIN_4 #define DAC1_MISO_GPIO_Port GPIOB //DAC8568引脚定义 -#define DAC8568_CS_Pin GPIO_PIN_15 -#define DAC8568_CS_GPIO_Port GPIOD +#define DAC8568_SYNC_Pin GPIO_PIN_15 +#define DAC8568_SYNC_GPIO_Port GPIOD #define DAC8568_SCLK_Pin GPIO_PIN_10 #define DAC8568_SCLK_GPIO_Port GPIOC #define DAC8568_DIN_Pin GPIO_PIN_12 diff --git a/Core/Src/freertos.c b/Core/Src/freertos.c index 21fd991..e5d4a1a 100644 --- a/Core/Src/freertos.c +++ b/Core/Src/freertos.c @@ -802,34 +802,37 @@ void start_dac161s997_test_task(void const *argument) /* USER CODE END Header_start_dac8568_test_task */ void start_dac8568_test_task(void const *argument) { - /* USER CODE BEGIN start_dac8568_test_task */ - static float test_voltage = 0.0f; // 测试电压值 - static uint8_t channel = 0; // 当前测试通道 - static TickType_t last_update_time = 0; - TickType_t current_time; - - // 等待系统稳定 - osDelay(100); - // // 初始化DAC8568 - DAC8568_Init(); - osDelay(100); - // SPI3裸发测试 - uint8_t test_tx[4] = {0xAA, 0x55, 0xFF, 0x00}; - uint8_t test_rx[4] = {0}; - - for (;;) { - // 拉低CS - HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET); - // 发送数据 - HAL_SPI_TransmitReceive(&hspi3, test_tx, test_rx, 4, 1000); - // 拉高CS - HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET); + // 初始化DAC8568 + DAC8568_Init(&hspi3); // 使用SPI3 + HAL_Delay(10); + + // 启用静态内部参考(2.5V) + DAC8568_EnableStaticInternalRef(); - osDelay(10); + while(1) + { + uint16_t i = 65535; + //DAC8568_WriteAndUpdate(CHANNEL_A, (uint16_t)i); + //DAC8568_WriteAndUpdate(CHANNEL_B, (uint16_t)i); + //DAC8568_WriteAndUpdate(CHANNEL_C, (uint16_t)i); + //DAC8568_WriteAndUpdate(CHANNEL_D, (uint16_t)i); + DAC8568_WriteAndUpdate(CHANNEL_E, (uint16_t)i); + //DAC8568_WriteAndUpdate(CHANNEL_F, (uint16_t)i); + DAC8568_WriteAndUpdate(CHANNEL_G, (uint16_t)i); + //DAC8568_WriteAndUpdate(CHANNEL_H, (uint16_t)i); + + + // for (int i = 65535; i >= 0; i = i - 4096) // 从65535到0,步长4096 + // { + + // // 写入并更新所有通道的值 + // DAC8568_WriteAndUpdate(BROADCAST, (uint16_t)i); + + // // 计算电压值 (假设Vref=2.5V,16位分辨率,2倍增益) + // float voltage = 2.5f * 2.0f * i / 65536.0f; + + // 延时2秒 + osDelay(2000); + //} } - - - /* Infinite loop */ - - /* USER CODE END start_dac8568_test_task */ } \ No newline at end of file diff --git a/Public/~WRL2044.tmp b/Public/~WRL2044.tmp deleted file mode 100644 index cf876b8..0000000 Binary files a/Public/~WRL2044.tmp and /dev/null differ diff --git a/User/driver/DAC8568.c b/User/driver/DAC8568.c index f0cee06..31e904d 100644 --- a/User/driver/DAC8568.c +++ b/User/driver/DAC8568.c @@ -1,96 +1,303 @@ -#include "DAC8568.h" -#include "stm32f4xx_hal.h" // 添加HAL库头文件 +/* + * DAC8568/DAC8168/DAC8568 驱动程序 + * 作者: 雪豹 + */ +#include "dac8568.h" #include "main.h" -#include "user_spi.h" -#include // 添加标准整型定义 -#define DAC_MAX_VALUE 65535 +static SPI_HandleTypeDef *hspi_dac; // SPI句柄指针,用于SPI通信 /** - * @brief DAC8568通用写函数 - * @param cmd 命令类型:0-初始化内部参考电压,1-写入并更新DAC值 - * @param channel 通道号(0-7),仅在cmd=1时有效 - * @param value DAC值(0-65535)或命令值,根据cmd决定 - * @return void + * @brief 初始化DAC8568驱动。 + * @param hspi SPI外设句柄指针。 + * @note 此函数会保存SPI句柄,并将CS和LDAC引脚初始化为高电平。 + * 默认执行软件复位,可选启用内部参考电压。 */ -void DAC8568_Write(uint8_t cmd, uint8_t channel, uint32_t value) +void DAC8568_Init(SPI_HandleTypeDef *hspi) { - uint8_t tx_data[4]; - uint8_t rx_data[4] = {0}; // Initialize receive buffer - uint32_t send_data; - - // 根据命令类型准备发送数据 - if(cmd == 0) // 初始化内部参考电压 - { - send_data = DAC8568_EN_INTER_REF_STATIC; - } - else // 写入并更新DAC值 - { - // 输入参数合法性检查 - if(channel > 7) - { - channel = 7; - } - if(value > DAC_MAX_VALUE) - { - value = DAC_MAX_VALUE; - } - - send_data = DAC8568_WRITE_UPDATE_SEL_DAC; - send_data |= (channel << 20); - send_data |= (value << 4); - } - - // 准备发送数据 - tx_data[0] = (uint8_t)(send_data >> 24); - tx_data[1] = (uint8_t)(send_data >> 16); - tx_data[2] = (uint8_t)(send_data >> 8); - tx_data[3] = (uint8_t)(send_data & 0xFF); - - // 开始SPI传输 - DAC8568_CS_L; // 拉低CS,使能SPI接口 - extern SPI_HandleTypeDef hspi3; // 声明外部SPI句柄 - spi_transmit_receive(&hspi3, tx_data, rx_data, 4); // 使用hspi3发送4字节数据 - DAC8568_CS_H; // 拉高CS,禁止SPI接口 + 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 初始化DAC8568芯片 - * @return void + * @brief 向DAC指定通道的输入寄存器写入数据。 + * @param channel 目标DAC通道 (CHANNEL_A 到 CHANNEL_H, 或 BROADCAST)。 + * @param data 要写入的16位数据。 */ -void DAC8568_Init(void) +void DAC8568_Write(uint8_t channel, uint16_t data) { - //初始化GPIO和SPI - dac8568_spi_init(); - // 将LDAC置低,DAC8568处于同步模式 - DAC8568_LD_L; - // 初始化内部参考电压 - DAC8568_Write(0, 0, 0); - + 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 设置DAC8568指定通道的电压值 - * @param mCh 通道号(0-7) - * @param mVol 电压值(0-2.5V) - * @return void + * @brief 更新DAC指定通道的输出。 + * @param channel 目标DAC通道 (CHANNEL_A 到 CHANNEL_H, 或 BROADCAST)。 */ -void dac8568_set_voltage(unsigned char mCh, float mVol) +void DAC8568_Update(uint8_t channel) { - float mDatafloat; - uint16_t mDtashort; - - // 将电压值转换为DAC值 - mDatafloat = mVol * (65536/(5*1.91)); - mDtashort = (uint16_t)mDatafloat; - mDtashort &= 0xffff; - - // 限制DAC值范围 - if(mDtashort > 65535) - mDtashort = 65535; - - // 写入并更新DAC值 - DAC8568_Write(1, mCh, mDtashort); + 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); +} \ No newline at end of file diff --git a/User/driver/DAC8568.h b/User/driver/DAC8568.h index d297f02..dd0c15e 100644 --- a/User/driver/DAC8568.h +++ b/User/driver/DAC8568.h @@ -1,62 +1,183 @@ -#include "stm32f4xx_hal.h" // 添加HAL库头文件 +/* + * DAC8568/DAC8168/DAC8568 驱动程序 + * 参考数据手册: https://www.ti.com.cn/product/cn/DAC8568 + * 版本: 2025-4-10 + * 作者: 雪豹 + * 描述: 驱动TI DAC8568系列DAC芯片,支持SPI通信和基本功能 + * 开源协议: MIT + * 版权所有 (c) 2025 雪豹 + * 注意:本代码仅供参考,使用前请仔细阅读数据手册和相关文档。 + * 使用本代码即表示您同意承担所有风险和责任。 + */ +/* + * TI DAC7568/DAC8168/DAC8568 核心特性 (数据手册第1/5-7页) + * + * 【共同特性】 + * - 通道数量: 8通道独立电压输出 + * - 内部基准: 2.5V (±0.004%初始精度, 2ppm/°C温漂典型值) + * - 毛刺能量: 0.1nV-s (代码切换瞬态) + * - 输出缓冲: 轨到轨输出,驱动能力 20mA sink/source + * - 电源范围: 2.7V至5.5V单电源供电 + * - 接口速度: 最高50MHz SPI时钟 + * - 低功耗: + * > 工作模式: 1.25mA @5V (含基准) + * > 断电模式: 0.18μA @5V (典型) + * - 温度范围: -40°C至+125°C + * - 复位特性: 上电复位至零电平/中间电平(型号后缀A/B/C/D区分) + * + * 【关键性能参数】 + * - DAC建立时间: + * > 5μs (典型值, 空载, 1/4至3/4量程, ±0.024%误差) + * > 10μs (最大值, 接1MΩ负载) + * + * 【型号差异】 + * >> DAC7568 (12位): + * - 分辨率: 12位 (0x000-0xFFF) + * - INL: ±1 LSB (最大值) + * - 封装: TSSOP-14/16 + * + * >> DAC8168 (14位): + * - 分辨率: 14位 (0x0000-0x3FFF) + * - INL: ±4 LSB (最大值) + * - 封装: TSSOP-14/16 + * + * >> DAC8568 (16位): + * - 分辨率: 16位 (0x0000-0xFFFF) + * - INL: ±12 LSB (最大值) + * - 封装: TSSOP-16 + * + * 【编程注意】 + * 1. 数据对齐差异: + * DAC7568使用12位数据(D11-D0),需左移4位填充到SPI帧 + * DAC8168使用14位数据(D13-D0),需左移2位 + * DAC8568使用全部16位数据(D15-D0) + * + * 2. 建立时间影响: + * 输出稳定需等待至少10μs,高速连续写入时需添加延时: + * HAL_Delay(1); // 保守延时1ms (实际最低10μs) + */ +/* + * SPI 外设配置说明 (针对 DAC8568) + * ---------------------------------------------------------------- + * 参数要求(参考数据手册第7-8页时序图和第6页电气特性): + * 1. 模式: 全双工主模式 (DAC8568 为从设备) + * 2. 数据大小: 8位 (需手动组合为24/32位帧) + * 3. 时钟极性 (CPOL): 低电平空闲 (CPOL=0) + * 4. 时钟相位 (CPHA): 数据在第一个边沿采样 (CPHA=0) + * 5. 传输顺序: MSB 高位在前 (强制要求) + * 6. 波特率: ≤50MHz (建议根据主频选择分频器) + * 7. 硬件NSS: 禁用 (使用独立GPIO控制SYNC引脚) + * + * CubeMX 具体设置步骤: + * 1. Connectivity → SPIx → Mode = "Full-Duplex Master" + * 2. Parameter Settings → + * - Data Size = 8 Bits + * - First Bit = MSB First + * - Clock Polarity = High 注意这个 + * - Clock Phase = 1 Edge + * - Baud Rate Prescaler = 分频值 (如 2/4/8,确保 SCLK ≤50MHz) + * 3. GPIO Settings → + * - 配置 SYNC 引脚为 GPIO_Output (初始化高电平) + * - MOSI/SCK 自动分配,模式为 Alternate Function Push-Pull + */ +/* + * DAC8568 硬件连接说明: + * ---------------------------------------------------------------- + * DAC8568引脚 | STM32引脚 | 备注 + * -----------|----------------|----------------------------------- + * DIN | SPIx_MOSI | 主设备输出,直连无需上拉 + * SCLK | SPIx_SCK | 保持短走线,减少干扰 + * SYNC | 任意GPIO (如PA4)| 需配置为输出模式,传输前拉低 + * VDD | 3.3V | 电源需并联100nF去耦电容 + * GND | GND | 共地 + */ + +#ifndef DAC8568_H +#define DAC8568_H + +#ifdef __cplusplus +extern "C" +{ +#endif + #include "main.h" +#include "stm32f4xx_hal.h" +#include -/************************DA8568寄存器SR的值*****************************/ +// DAC8568数据帧结构 (31-0位) +// 31-28位: 前缀位 (PREFIX BITS) - 始终为0 +// 27-24位: 命令位 (CONTROL BITS) +// 23-20位: 地址位 (ADDRESS BITS) +// 19-4位: 数据位 (DATA BITS) +// 3-0位: 特征位 (FEATURE BITS) -#define PrefixControlbyte 0x03//前缀控制字节 -#define AddressOutA 0x0//通道A地址 -#define AddressOutB 0x1//通道B地址 -#define AddressOutC 0x2//通道C地址 -#define AddressOutD 0x3//通道D地址 -#define AddressOutE 0x4//通道E地址 -#define AddressOutF 0x5//通道F地址 -#define AddressOutG 0x6//通道G地址 -#define AddressOutH 0x7//通道H地址 -#define Featurebyte 0x0//特征字节 +// DAC8568命令定义 (27-24位控制位) (参考数据手册第35-38页表4) +#define CMD_WRITE_INPUT_REG 0b0000 // 写入输入寄存器 +#define CMD_UPDATE_DAC_REG 0b0001 // 更新DAC寄存器 +#define CMD_WRITE_INPUT_UPDATE_ALL 0b0010 // 写入所有输入寄存器并更新所有DAC寄存器 +#define CMD_WRITE_INPUT_UPDATE_ONE 0b0011 // 写入单个输入寄存器并更新相应的DAC寄存器 +#define CMD_POWER_DOWN 0b0100 // 电源模式控制 +#define CMD_CLEAR_CODE_REG 0b0101 // 清除代码寄存器 +#define CMD_LDAC_REG 0b0110 // LDAC寄存器控制 +#define CMD_SOFTWARE_RESET 0b0111 // 软件复位 +#define CMD_INTERNAL_REF 0b1000 // 内部参考控制 -/*****DA8568寄存器SR的值-结尾*************************************/ +// DAC通道选择 (23-20位地址位) (参考数据手册第36页) +#define CHANNEL_A 0b0000 // 通道A对应CH0 +#define CHANNEL_B 0b0001 // 通道B对应CH4 +#define CHANNEL_C 0b0010 // 通道C对应CH1 +#define CHANNEL_D 0b0011 // 通道D对应CH5 +#define CHANNEL_E 0b0100 // 通道E对应CH2 +#define CHANNEL_F 0b0101 // 通道F对应CH6 +#define CHANNEL_G 0b0110 // 通道G对应CH3 +#define CHANNEL_H 0b0111 // 通道H对应CH7 +#define BROADCAST 0b1111 // 广播模式(所有通道) -/****************************DAC8568命令************************/ -#define SETUP_INTERNAL_REGISTER 0 -#define POWER_UP 1 -#define RESET 2 -/*****DAC8568命令-结尾*******************************************/ +// 电源模式定义 (特征位F1-F0) (参考数据手册第47页表13) +#define POWER_UP 0b00 // 正常工作模式 +#define POWER_DOWN_1K 0b01 // 关断模式,1K电阻接地 +#define POWER_DOWN_100K 0b10 // 关断模式,100K电阻接地 +#define POWER_DOWN_HIZ 0b11 // 关断模式,高阻态 -//---------------------------------------- Pin definition +// 内部参考控制 (特征位) (参考数据手册第44-45页) +#define REF_DISABLE 0b0000 // 禁用内部参考 +#define REF_ENABLE 0b0001 // 启用内部参考 +#define REF_FLEX_MODE_ENABLE 0b0010 // 启用灵活模式 +#define REF_FLEX_MODE_ALWAYS_ON 0b0011 // 灵活模式常开 +#define REF_FLEX_MODE_ALWAYS_OFF 0b0100 // 灵活模式常关 -//---------------------------------------- Command definition -#define DAC8568_EN_INTER_REF_STATIC 0x08000001 -#define DAC8568_WRITE_UPDATE_SEL_DAC 0x03000000 +// 清除代码控制 (特征位F1-F0) (参考数据手册第39页表5) +#define CLEAR_CODE_ZERO_SCALE 0b00 // 清除为零刻度 +#define CLEAR_CODE_MID_SCALE 0b01 // 清除为中间刻度 +#define CLEAR_CODE_FULL_SCALE 0b10 // 清除为全刻度 +#define CLEAR_CODE_NO_OPERATION 0b11 // 无操作 -//---------------------------------------- Reference Voltage -#define DAC8568_REF_VOLTAGE 2.5 +// 硬件相关定义 +#define DAC8568_CS_GPIO_Port GPIOD +#define DAC8568_CS_Pin GPIO_PIN_15 +#define DAC8568_LDAC_GPIO_Port GPIOD +#define DAC8568_LDAC_Pin GPIO_PIN_14 -void DAC8568_Init(void); -void DAC8568_Write_Update_Sel_DAC(uint32_t ChannelNum, uint32_t DACValue); +// 函数声明 +void DAC8568_Init(SPI_HandleTypeDef *hspi); +void DAC8568_Write(uint8_t channel, uint16_t data); +void DAC8568_Update(uint8_t channel); +void DAC8568_WriteAndUpdate(uint8_t channel, uint16_t data); +void DAC8568_WriteAllChannels(uint16_t *data); +void DAC8568_UpdateAllChannels(void); +void DAC8568_SetPowerMode(uint8_t channel, uint8_t mode); +void DAC8568_EnableStaticInternalRef(void); +void DAC8568_DisableStaticInternalRef(void); +void DAC8568_EnableFlexMode(void); +void DAC8568_DisableFlexMode(void); +void DAC8568_SetFlexModeRefAlwaysOn(uint8_t enable); +void DAC8568_SetFlexModeRefAlwaysOff(uint8_t enable); +void DAC8568_SetClearCode(uint8_t mode); +void DAC8568_SoftwareReset(void); +void DAC8568_SendRawCommand(uint8_t cmd_bits, uint8_t addr_bits, uint16_t data_bits, uint8_t feature_bits); +void DAC8568_SendRawData(uint8_t raw_data[4]); - -// #define DAC8568_SYNC_H GPIO_SetBits(GPIOA,GPIO_Pin_15) -// #define DAC8568_SYNC_L GPIO_ResetBits(GPIOA,GPIO_Pin_15) -// #define DAC8568_SCLK_H GPIO_SetBits(GPIOC,GPIO_Pin_10) -// #define DAC8568_SCLK_L GPIO_ResetBits(GPIOC,GPIO_Pin_10) -// #define DAC8568_DIN_H GPIO_SetBits(GPIOC,GPIO_Pin_12) -// #define DAC8568_DIN_L GPIO_ResetBits(GPIOC,GPIO_Pin_12) -//引脚拉高拉低 -#define DAC8568_CS_H HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET) -#define DAC8568_CS_L HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_RESET) -#define DAC8568_SCLK_H HAL_GPIO_WritePin(DAC8568_SCLK_GPIO_Port, DAC8568_SCLK_Pin, GPIO_PIN_SET) -#define DAC8568_SCLK_L HAL_GPIO_WritePin(DAC8568_SCLK_GPIO_Port, DAC8568_SCLK_Pin, GPIO_PIN_RESET) -#define DAC8568_DIN_H HAL_GPIO_WritePin(DAC8568_DIN_GPIO_Port, DAC8568_DIN_Pin, GPIO_PIN_SET) -#define DAC8568_DIN_L HAL_GPIO_WritePin(DAC8568_DIN_GPIO_Port, DAC8568_DIN_Pin, GPIO_PIN_RESET) -#define DAC8568_LD_H HAL_GPIO_WritePin(DAC8568_LD_GPIO_Port, DAC8568_LD_Pin, GPIO_PIN_SET) -#define DAC8568_LD_L HAL_GPIO_WritePin(DAC8568_LD_GPIO_Port, DAC8568_LD_Pin, GPIO_PIN_RESET) - -void dac8568_init(void); -void dac8568_set_voltage(unsigned char mCh,float mVol); -void SPI_SendByte(uint8_t m); -void DAC8568_Write_passageway(uint8_t Addressbyte, uint16_t Datashort); -void DAC8568_Write_Command(uint8_t command); -void dac8568_set_voltage(unsigned char mCh, float mVol); -void dac8568_spi_init(void); -void DAC8568_Init(void); -void dac8568_output_ch0_1v5(void); \ No newline at end of file +#ifdef __cplusplus +} +#endif +#endif /* DAC8568_H */ \ No newline at end of file diff --git a/User/system/user_spi.c b/User/system/user_spi.c index fb3c9bd..bc67733 100644 --- a/User/system/user_spi.c +++ b/User/system/user_spi.c @@ -178,7 +178,7 @@ void dac8568_spi_init(void) hspi3.Init.Mode = SPI_MODE_MASTER; hspi3.Init.Direction = SPI_DIRECTION_2LINES; hspi3.Init.DataSize = SPI_DATASIZE_8BIT; - hspi3.Init.CLKPolarity = SPI_POLARITY_LOW; // CPOL = 0 + hspi3.Init.CLKPolarity = SPI_POLARITY_HIGH; // CPOL = 0 hspi3.Init.CLKPhase = SPI_PHASE_1EDGE; // CPHA = 0 hspi3.Init.NSS = SPI_NSS_SOFT; hspi3.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_32; // 提高SPI速度 @@ -194,7 +194,7 @@ void dac8568_spi_init(void) // 初始化CS和LDAC引脚状态 HAL_GPIO_WritePin(DAC8568_CS_GPIO_Port, DAC8568_CS_Pin, GPIO_PIN_SET); // CS初始为高电平 - HAL_GPIO_WritePin(DAC8568_LD_GPIO_Port, DAC8568_LD_Pin, GPIO_PIN_RESET); // LDAC初始为低电平 + HAL_GPIO_WritePin(DAC8568_LD_GPIO_Port, DAC8568_LD_Pin, GPIO_PIN_SET); // LDAC初始为高电平 // 等待一段时间确保DAC8568稳定 HAL_Delay(10);