基于 TI TMS320F28335 DSP,实现 多通道 ADC 数据采集 + DAC 输出控制,包含完整的 DA 配置、输出调节及实时采集功能,适用于工业采集、信号发生、闭环控制等场景。
一、硬件资源配置
| 外设 | 引脚 | 功能说明 |
|---|---|---|
| ADCINA0–A7 | GPIO0–7 | 8 路模拟量采集(0–3V) |
| ADCINB0–B7 | GPIO8–15 | 8 路模拟量采集(0–3V) |
| DAC1OUTA | GPIO0 (复用) | DA 输出通道 1 |
| DAC2OUTA | GPIO1 (复用) | DA 输出通道 2 |
| EPWM1A | GPIO0 | PWM 触发 ADC 采样 |
| SCI-A | GPIO28/29 | 串口调试输出 |
二、程序总体结构
DSP28335_DataAcquisition/
├── main.c # 主程序
├── adc_config.c/.h # ADC 配置
├── dac_config.c/.h # DA 配置与控制
├── epwm_config.c/.h # PWM 触发配置
├── sci_debug.c/.h # 串口调试
└── sys_ctrl.c/.h # 系统时钟与中断
三、代码实现
3.1 DA 配置与控制(dac_config.h)
#ifndef DAC_CONFIG_H
#define DAC_CONFIG_H#include "DSP2833x_Device.h"
#include "DSP2833x_Examples.h"// DA 参数定义
#define DAC_RESOLUTION 1024 // 10 位 DAC
#define DAC_REF_VOLTAGE 3.0f // 参考电压 3.0V
#define DAC_MAX_VALUE 1023 // 最大值// DA 通道枚举
typedef enum {DAC_CHANNEL_1 = 0,DAC_CHANNEL_2 = 1
} DAC_Channel;// DA 输出模式
typedef enum {DAC_MODE_STATIC = 0, // 静态输出DAC_MODE_WAVE, // 波形输出DAC_MODE_PID // PID 控制输出
} DAC_OutputMode;// DA 控制结构体
typedef struct {DAC_Channel channel;DAC_OutputMode mode;float voltage; // 输出电压float minVoltage; // 最小电压float maxVoltage; // 最大电压uint16_t digitalValue; // 数字量uint8_t enabled; // 使能标志
} DAC_Control;// 函数声明
void DAC_Init(void);
void DAC_ConfigChannel(DAC_Channel channel);
void DAC_SetVoltage(DAC_Channel channel, float voltage);
void DAC_SetDigitalValue(DAC_Channel channel, uint16_t value);
float DAC_GetVoltage(DAC_Channel channel);
void DAC_StartOutput(DAC_Channel channel);
void DAC_StopOutput(DAC_Channel channel);
void DAC_UpdateOutput(DAC_Control *dac);#endif // DAC_CONFIG_H
3.2 DA 驱动实现(dac_config.c)
#include "dac_config.h"DAC_Control dac1_control;
DAC_Control dac2_control;/*** @brief 初始化 DA 模块*/
void DAC_Init(void)
{EALLOW;// 使能 DAC 时钟SysCtrlRegs.PCLKCR0.bit.DACAENCLK = 1;SysCtrlRegs.PCLKCR0.bit.DACBENCLK = 1;// 配置 DAC1DAC_ConfigChannel(DAC_CHANNEL_1);// 配置 DAC2DAC_ConfigChannel(DAC_CHANNEL_2);EDIS;// 初始化控制结构体dac1_control.channel = DAC_CHANNEL_1;dac1_control.mode = DAC_MODE_STATIC;dac1_control.voltage = 0.0f;dac1_control.minVoltage = 0.0f;dac1_control.maxVoltage = DAC_REF_VOLTAGE;dac1_control.enabled = 1;dac2_control.channel = DAC_CHANNEL_2;dac2_control.mode = DAC_MODE_STATIC;dac2_control.voltage = 0.0f;dac2_control.minVoltage = 0.0f;dac2_control.maxVoltage = DAC_REF_VOLTAGE;dac2_control.enabled = 1;
}/*** @brief 配置 DA 通道*/
void DAC_ConfigChannel(DAC_Channel channel)
{EALLOW;switch (channel) {case DAC_CHANNEL_1:// 配置 DAC1 控制寄存器DacaRegs.DACCTL.bit.DACREFSEL = 1; // 内部参考电压DacaRegs.DACCTL.bit.LOADMODE = 0; // 立即加载DacaRegs.DACCTL.bit.DACOUTEN = 1; // 使能输出// 设置初始值为 0DacaRegs.DACVALS.all = 0;break;case DAC_CHANNEL_2:// 配置 DAC2 控制寄存器DacbRegs.DACCTL.bit.DACREFSEL = 1; // 内部参考电压DacbRegs.DACCTL.bit.LOADMODE = 0; // 立即加载DacbRegs.DACCTL.bit.DACOUTEN = 1; // 使能输出// 设置初始值为 0DacbRegs.DACVALS.all = 0;break;}EDIS;
}/*** @brief 设置 DA 输出电压*/
void DAC_SetVoltage(DAC_Channel channel, float voltage)
{uint16_t digitalValue;// 电压限幅if (voltage < 0.0f) voltage = 0.0f;if (voltage > DAC_REF_VOLTAGE) voltage = DAC_REF_VOLTAGE;// 电压转数字量digitalValue = (uint16_t)((voltage / DAC_REF_VOLTAGE) * DAC_MAX_VALUE);// 设置 DA 输出DAC_SetDigitalValue(channel, digitalValue);
}/*** @brief 设置 DA 数字量*/
void DAC_SetDigitalValue(DAC_Channel channel, uint16_t value)
{EALLOW;// 数字量限幅if (value > DAC_MAX_VALUE) value = DAC_MAX_VALUE;switch (channel) {case DAC_CHANNEL_1:DacaRegs.DACVALS.all = value;break;case DAC_CHANNEL_2:DacbRegs.DACVALS.all = value;break;}EDIS;
}/*** @brief 获取 DA 当前输出电压*/
float DAC_GetVoltage(DAC_Channel channel)
{uint16_t digitalValue;switch (channel) {case DAC_CHANNEL_1:digitalValue = DacaRegs.DACVALS.all;break;case DAC_CHANNEL_2:digitalValue = DacbRegs.DACVALS.all;break;default:digitalValue = 0;break;}return (float)digitalValue / DAC_MAX_VALUE * DAC_REF_VOLTAGE;
}/*** @brief 启动 DA 输出*/
void DAC_StartOutput(DAC_Channel channel)
{EALLOW;switch (channel) {case DAC_CHANNEL_1:DacaRegs.DACCTL.bit.DACOUTEN = 1;break;case DAC_CHANNEL_2:DacbRegs.DACCTL.bit.DACOUTEN = 1;break;}EDIS;
}/*** @brief 停止 DA 输出*/
void DAC_StopOutput(DAC_Channel channel)
{EALLOW;switch (channel) {case DAC_CHANNEL_1:DacaRegs.DACCTL.bit.DACOUTEN = 0;break;case DAC_CHANNEL_2:DacbRegs.DACCTL.bit.DACOUTEN = 0;break;}EDIS;
}/*** @brief 更新 DA 输出(根据控制结构体)*/
void DAC_UpdateOutput(DAC_Control *dac)
{if (!dac->enabled) {DAC_StopOutput(dac->channel);return;}switch (dac->mode) {case DAC_MODE_STATIC:DAC_SetVoltage(dac->channel, dac->voltage);break;case DAC_MODE_WAVE:// 波形输出(示例:正弦波){static float phase = 0.0f;float waveVoltage = (dac->maxVoltage - dac->minVoltage) / 2.0f *sin(phase) + (dac->maxVoltage + dac->minVoltage) / 2.0f;DAC_SetVoltage(dac->channel, waveVoltage);phase += 0.1f;if (phase > 2 * 3.14159f) phase = 0.0f;}break;case DAC_MODE_PID:// PID 控制输出(需外部调用 PID 计算)DAC_SetVoltage(dac->channel, dac->voltage);break;}
}
3.3 ADC 采集配置(adc_config.c)
#include "adc_config.h"uint16_t adc_result[16];/*** @brief ADC 初始化*/
void ADC_Init(void)
{EALLOW;// 使能 ADC 时钟SysCtrlRegs.PCLKCR0.bit.ADCENCLK = 1;// ADC 校准AdcRegs.ADCCTL1.bit.ADCBGPWD = 1; // 带隙电源AdcRegs.ADCCTL1.bit.ADCREFPWD = 1; // 参考电源AdcRegs.ADCCTL1.bit.ADCPWDN = 1; // ADC 电源AdcRegs.ADCCTL1.bit.ADCENABLE = 1; // 使能 ADC// 采样窗口设置AdcRegs.ADCCTL1.bit.ACQ_PS = 6; // 采样窗口 7 个 SYSCLKAdcRegs.ADCCTL1.bit.CPS = 0; // 不分频AdcRegs.ADCCTL1.bit.SUSMOD = 0; // 自由运行// SOC 配置AdcRegs.ADCSOC0CTL.bit.CHSEL = 0; // ADCINA0AdcRegs.ADCSOC0CTL.bit.TRIGSEL = 5; // EPWM1A 触发AdcRegs.ADCSOC0CTL.bit.ACQPS = 6; // 采样窗口EDIS;DELAY_US(1000); // 等待 ADC 稳定
}/*** @brief 读取 ADC 通道*/
uint16_t ADC_ReadChannel(uint16_t channel)
{uint16_t result;EALLOW;AdcRegs.ADCSOC0CTL.bit.CHSEL = channel; // 选择通道EDIS;AdcRegs.ADCSOCFRC1.bit.SOC0 = 1; // 强制启动转换while (AdcRegs.ADCINTFLG.bit.ADCINT1 == 0); // 等待转换完成AdcRegs.ADCINTFLGCLR.bit.ADCINT1 = 1; // 清除中断标志result = AdcRegs.ADCRESULT0;return result;
}/*** @brief 批量读取所有 ADC 通道*/
void ADC_ReadAllChannels(void)
{uint16_t i;for (i = 0; i < 16; i++) {adc_result[i] = ADC_ReadChannel(i);}
}/*** @brief 将 ADC 值转换为电压*/
float ADC_ToVoltage(uint16_t adcValue)
{return (float)adcValue * 3.0f / 4096.0f; // 12 位 ADC,3V 参考
}
3.4 PWM 触发配置(epwm_config.c)
#include "epwm_config.h"/*** @brief EPWM 初始化(用于触发 ADC)*/
void EPWM_Init(void)
{EALLOW;// 使能 EPWM 时钟SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 0;// EPWM1 配置EPwm1Regs.TBCTL.bit.CTRMODE = TB_COUNT_UP; // 向上计数EPwm1Regs.TBCTL.bit.PHSEN = TB_DISABLE; // 禁止相位加载EPwm1Regs.TBCTL.bit.HSPCLKDIV = TB_DIV1; // 高速时钟不分频EPwm1Regs.TBCTL.bit.CLKDIV = TB_DIV1; // 时钟不分频// 设置周期(10kHz)EPwm1Regs.TBPRD = 7500; // 75MHz / 7500 = 10kHz// 设置比较值EPwm1Regs.CMPA.half.CMPA = 3750; // 50% 占空比// 动作限定EPwm1Regs.AQCTLA.bit.CAU = AQ_SET; // 计数到 CMPA 时置高EPwm1Regs.AQCTLA.bit.ZRO = AQ_CLEAR; // 计数到 0 时清零// 使能同步SysCtrlRegs.PCLKCR0.bit.TBCLKSYNC = 1;EDIS;
}
3.5 主程序(main.c)
#include "DSP2833x_Device.h"
#include "DSP2833x_Examples.h"
#include "adc_config.h"
#include "dac_config.h"
#include "epwm_config.h"
#include "sci_debug.h"// 系统参数
typedef struct {float adc_voltage[16]; // ADC 电压值float dac_output[2]; // DAC 输出电压uint16_t sample_count; // 采样计数uint8_t system_ready; // 系统就绪标志
} System_Data;System_Data sys_data;/*** @brief 系统初始化*/
void System_Init(void)
{InitSysCtrl(); // 初始化系统时钟InitPieCtrl(); // 初始化 PIE 控制InitPieVectTable(); // 初始化中断向量表InitGpio(); // 初始化 GPIO// 外设初始化SCI_Init(); // 串口初始化ADC_Init(); // ADC 初始化DAC_Init(); // DAC 初始化EPWM_Init(); // EPWM 初始化// 启动 DA 输出DAC_StartOutput(DAC_CHANNEL_1);DAC_StartOutput(DAC_CHANNEL_2);sys_data.system_ready = 1;SCI_SendString("System Initialized!\r\n");
}/*** @brief 数据采集与 DA 控制主循环*/
void DataAcquisition_Loop(void)
{uint16_t i;float control_voltage;while (1) {// 1. 采集 ADC 数据ADC_ReadAllChannels();// 2. 转换为电压for (i = 0; i < 16; i++) {sys_data.adc_voltage[i] = ADC_ToVoltage(adc_result[i]);}// 3. DA 输出控制(示例:将 ADC0 的电压映射到 DA1 输出)control_voltage = sys_data.adc_voltage[0]; // ADC0 输入DAC_SetVoltage(DAC_CHANNEL_1, control_voltage);sys_data.dac_output[0] = control_voltage;// 4. DA2 输出固定 1.5VDAC_SetVoltage(DAC_CHANNEL_2, 1.5f);sys_data.dac_output[1] = 1.5f;// 5. 串口输出调试信息if (sys_data.sample_count % 1000 == 0) {SCI_SendString("ADC0: ");SCI_SendFloat(sys_data.adc_voltage[0], 3);SCI_SendString(" V, DAC1: ");SCI_SendFloat(sys_data.dac_output[0], 3);SCI_SendString(" V\r\n");}sys_data.sample_count++;DELAY_US(100); // 100us 采样周期}
}/*** @brief 主函数*/
void main(void)
{System_Init();DataAcquisition_Loop();
}
四、DA 输出模式示例
4.1 静态电压输出
// 输出 2.5V
DAC_SetVoltage(DAC_CHANNEL_1, 2.5f);
4.2 波形输出(正弦波)
// 在 DAC_UpdateOutput 中启用 DAC_MODE_WAVE
dac1_control.mode = DAC_MODE_WAVE;
DAC_UpdateOutput(&dac1_control);
4.3 PID 控制输出
// 计算 PID 输出并更新 DA
float pid_output = PID_Calculate(&pid_ctrl);
dac1_control.voltage = pid_output;
dac1_control.mode = DAC_MODE_PID;
DAC_UpdateOutput(&dac1_control);
参考 DSP28335板的用于数据采集的程序 www.youwenfan.com/contentcnv/72201.html
五、编译与下载
5.1 CCS 工程配置
- Target: TMS320F28335
- Linker Command File:
28335_RAM_lnk.cmd - Include Paths: 添加所有头文件路径
- Predefined Symbols:
LARGE_MODEL
5.2 烧录步骤
# 使用 XDS100 仿真器
1. 连接 USB 仿真器到 JTAG 接口
2. 在 CCS 中点击 "Debug"
3. 加载程序到 DSP
4. 运行程序
六、调试与验证
6.1 示波器验证
- ADC 输入:用信号源输入 0–3V 正弦波
- DA 输出:用示波器观察 DAC1OUTA 引脚
- PWM 触发:观察 EPWM1A 波形
6.2 串口监控
System Initialized!
ADC0: 1.234 V, DAC1: 1.234 V
ADC0: 1.567 V, DAC1: 1.567 V
ADC0: 2.000 V, DAC1: 2.000 V
七、常见问题
| 问题 | 原因 | 解决 |
|---|---|---|
| DA 无输出 | 未使能 DACOUTEN | 检查 DACCTL.bit.DACOUTEN |
| 输出电压不准 | 参考电压错误 | 校准参考电压 |
| ADC 采样异常 | PWM 未触发 | 检查 EPWM 配置 |
| 程序跑飞 | 堆栈溢出 | 增大 .stack 段 |
