DSP28335 数据采集与 DA 输出控制程序
基于 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;
// 配置 DAC1
DAC_ConfigChannel(DAC_CHANNEL_1);
// 配置 DAC2
DAC_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; // 使能输出
// 设置初始值为 0
DacaRegs.DACVALS.all = 0;
break;
case DAC_CHANNEL_2:
// 配置 DAC2 控制寄存器
DacbRegs.DACCTL.bit.DACREFSEL = 1; // 内部参考电压
DacbRegs.DACCTL.bit.LOADMODE = 0; // 立即加载
DacbRegs.DACCTL.bit.DACOUTEN = 1; // 使能输出
// 设置初始值为 0
DacbRegs.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 个 SYSCLK
AdcRegs.ADCCTL1.bit.CPS = 0; // 不分频
AdcRegs.ADCCTL1.bit.SUSMOD = 0; // 自由运行
// SOC 配置
AdcRegs.ADCSOC0CTL.bit.CHSEL = 0; // ADCINA0
AdcRegs.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.5V
DAC_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 段 |