ADC配置与使用

目录

  1. ADC基础
  2. 与STM32对比
  3. ADC寄存器
  4. 手动配置ADC
  5. SysConfig配置ADC
  6. 实战示例

ADC基础

F280049C有3个独立的12位ADC模块:

  • ADCA: 16个输入通道
  • ADCB: 16个输入通道
  • ADCC: 16个输入通道

ADC特性

  • 分辨率: 12位(0-4095)
  • 采样速率: 最高3.45 MSPS
  • 输入范围: 0-3.3V(单端)或±VREFHI(差分)
  • 转换模式: 单次转换、连续转换
  • 触发源: 软件、定时器、ePWM等
  • SOC: 16个独立的Start-of-Conversion通道

ADC架构

1
2
3
输入引脚 → 采样保持 → 12位ADC → 结果寄存器 → 中断/DMA

SOC触发

与STM32对比

ADC功能对比

功能 STM32 F280049C
ADC数量 1-3个 3个
分辨率 12位 12位
通道数 16-19 16×3=48
采样速率 最高5 MSPS 3.45 MSPS
DMA支持
触发源 定时器、外部 ePWM、定时器、软件

配置流程对比

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// STM32 HAL库
ADC_HandleTypeDef hadc1;
hadc1.Instance = ADC1;
hadc1.Init.Resolution = ADC_RESOLUTION_12B;
hadc1.Init.ScanConvMode = DISABLE;
HAL_ADC_Init(&hadc1);
HAL_ADC_Start(&hadc1);
HAL_ADC_PollForConversion(&hadc1, 100);
uint32_t value = HAL_ADC_GetValue(&hadc1);

// F280049C DriverLib
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY,
ADC_CH_ADCIN0, 15);
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
while(ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1) == false);
uint16_t value = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);

ADC寄存器

主要寄存器

1. ADCxCTL1 - 控制寄存器1

1
AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1;  // 上电ADC

2. ADCxCTL2 - 控制寄存器2

1
2
3
AdcaRegs.ADCCTL2.bit.PRESCALE = 6;  // 时钟分频
AdcaRegs.ADCCTL2.bit.RESOLUTION = 0; // 12位分辨率
AdcaRegs.ADCCTL2.bit.SIGNALMODE = 0; // 单端模式

3. ADCSOCxCTL - SOC控制寄存器

1
2
3
AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0;      // 选择通道0
AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; // 采样窗口
AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 0; // 软件触发

4. ADCINTxSEL - 中断选择寄存器

1
2
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0;  // INT1由SOC0触发
AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // 使能INT1

5. ADCRESULTx - 结果寄存器

1
uint16_t result = AdcaResultRegs.ADCRESULT0;

手动配置ADC

方法1: 直接寄存器操作

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include "F28x_Project.h"

void ADCA_Init_Register(void)
{
EALLOW;

// 1. 上电ADC
AdcaRegs.ADCCTL2.bit.PRESCALE = 6; // ADCCLK = SYSCLK/4/2 = 12.5MHz
AdcaRegs.ADCCTL1.bit.ADCPWDNZ = 1; // 上电ADC
DELAY_US(1000); // 等待ADC上电

// 2. 配置ADC
AdcaRegs.ADCCTL2.bit.RESOLUTION = 0; // 12位分辨率
AdcaRegs.ADCCTL2.bit.SIGNALMODE = 0; // 单端模式

// 3. 配置SOC0(通道0,软件触发)
AdcaRegs.ADCSOC0CTL.bit.CHSEL = 0; // ADCIN0
AdcaRegs.ADCSOC0CTL.bit.ACQPS = 14; // 采样窗口75ns
AdcaRegs.ADCSOC0CTL.bit.TRIGSEL = 0; // 软件触发

// 4. 配置中断
AdcaRegs.ADCINTSEL1N2.bit.INT1SEL = 0; // INT1由SOC0触发
AdcaRegs.ADCINTSEL1N2.bit.INT1E = 1; // 使能INT1
AdcaRegs.ADCINTSEL1N2.bit.INT1CONT = 0; // 单次中断

EDIS;
}

uint16_t ADCA_ReadChannel(void)
{
// 触发转换
AdcaRegs.ADCSOCFRC1.bit.SOC0 = 1;

// 等待转换完成
while(AdcaRegs.ADCINTFLG.bit.ADCINT1 == 0);

// 清除中断标志
AdcaRegs.ADCINTFLGCLR.bit.ADCINT1 = 1;

// 读取结果
return AdcaResultRegs.ADCRESULT0;
}

方法2: DriverLib库函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "driverlib.h"
#include "device.h"

void ADCA_Init_DriverLib(void)
{
// 1. 配置ADC时钟
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);

// 2. 设置分辨率和信号模式
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);

// 3. 上电ADC
ADC_enableConverter(ADCA_BASE);
DEVICE_DELAY_US(1000);

// 4. 配置SOC0
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0,
ADC_TRIGGER_SW_ONLY,
ADC_CH_ADCIN0,
15); // 采样窗口

// 5. 配置中断
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
}

uint16_t ADCA_ReadChannel_DriverLib(void)
{
// 触发转换
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);

// 等待转换完成
while(ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1) == false);

// 清除中断标志
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);

// 读取结果
return ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
}

ADC采样时间计算

公式

1
2
采样时间 = (ACQPS + 1) × (1 / ADCCLK)
转换时间 = 采样时间 + 转换周期

示例

1
2
3
4
5
// SYSCLK = 100MHz
// PRESCALE = 6 → ADCCLK = 100MHz / 4 / 2 = 12.5MHz
// ACQPS = 14 → 采样时间 = 15 × 80ns = 1.2μs
// 转换周期 = 12个ADCCLK周期 = 960ns
// 总转换时间 = 1.2μs + 0.96μs = 2.16μs

SysConfig配置ADC

步骤1: 添加ADC模块

  1. 在SysConfig中找到 ADC
  2. 点击 “+” 添加ADC实例
  3. 选择 ADCA/ADCB/ADCC

步骤2: 配置参数

1
2
3
4
5
6
7
8
9
10
11
ADC Instance: ADCA
├── ADC Clock Prescaler: 4.0
├── Resolution: 12-bit
├── Signal Mode: Single-ended
└── SOC Configuration
├── SOC0
│ ├── Channel: ADCIN0
│ ├── Trigger: Software
│ ├── Sample Window: 15
│ └── Interrupt: INT1
└── Enable Interrupt: ✓

步骤3: 使用生成的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include "board.h"

void main(void)
{
Device_init();
Device_initGPIO();

// 调用SysConfig生成的初始化
Board_init();

while(1)
{
// 触发ADC转换
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);

// 等待转换完成
while(ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1) == false);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);

// 读取结果
uint16_t result = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);

// 转换为电压(0-3.3V)
float voltage = (float)result * 3.3f / 4095.0f;

DEVICE_DELAY_US(100000); // 100ms延时
}
}

实战示例

示例1: 单通道ADC采集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include "driverlib.h"
#include "device.h"

void ADCA_Init(void)
{
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
ADC_enableConverter(ADCA_BASE);
DEVICE_DELAY_US(1000);

ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0,
ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN0, 15);
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
}

float ADCA_ReadVoltage(void)
{
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
while(ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1) == false);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);

uint16_t result = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
return (float)result * 3.3f / 4095.0f;
}

void main(void)
{
Device_init();
Device_initGPIO();

ADCA_Init();

while(1)
{
float voltage = ADCA_ReadVoltage();
// 使用voltage值
DEVICE_DELAY_US(10000); // 10ms
}
}

示例2: 多通道ADC采集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include "driverlib.h"
#include "device.h"

#define NUM_CHANNELS 4

void ADCA_Init_MultiChannel(void)
{
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
ADC_enableConverter(ADCA_BASE);
DEVICE_DELAY_US(1000);

// 配置4个SOC(通道0-3)
for(int i = 0; i < NUM_CHANNELS; i++)
{
ADC_setupSOC(ADCA_BASE, i, ADC_TRIGGER_SW_ONLY, i, 15);
}

// INT1在SOC3完成时触发
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER3);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
}

void ADCA_ReadMultiChannel(uint16_t *results)
{
// 触发所有SOC
for(int i = 0; i < NUM_CHANNELS; i++)
{
ADC_forceSOC(ADCA_BASE, i);
}

// 等待最后一个SOC完成
while(ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1) == false);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);

// 读取所有结果
for(int i = 0; i < NUM_CHANNELS; i++)
{
results[i] = ADC_readResult(ADCARESULT_BASE, i);
}
}

void main(void)
{
Device_init();
Device_initGPIO();

ADCA_Init_MultiChannel();

uint16_t adc_results[NUM_CHANNELS];

while(1)
{
ADCA_ReadMultiChannel(adc_results);

// 处理结果
for(int i = 0; i < NUM_CHANNELS; i++)
{
float voltage = (float)adc_results[i] * 3.3f / 4095.0f;
// 使用voltage值
}

DEVICE_DELAY_US(10000);
}
}

示例3: ePWM触发ADC

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
#include "driverlib.h"
#include "device.h"

volatile uint16_t adc_result = 0;

__interrupt void adcA1ISR(void)
{
adc_result = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
Interrupt_clearACKGroup(INTERRUPT_ACK_GROUP1);
}

void EPWM1_Init_ADCTrigger(void)
{
// 配置ePWM1(20kHz)
EPWM_setTimeBaseCounterMode(EPWM1_BASE, EPWM_COUNTER_MODE_UP);
EPWM_setClockPrescaler(EPWM1_BASE, EPWM_CLOCK_DIVIDER_1, EPWM_HSCLOCK_DIVIDER_1);
EPWM_setTimeBasePeriod(EPWM1_BASE, 5000);

// 配置ADC触发(在计数器为0时触发)
EPWM_setADCTriggerSource(EPWM1_BASE, EPWM_SOC_A, EPWM_SOC_TBCTR_ZERO);
EPWM_setADCTriggerEventPrescale(EPWM1_BASE, EPWM_SOC_A, 1);
EPWM_enableADCTrigger(EPWM1_BASE, EPWM_SOC_A);
}

void ADCA_Init_EPWMTrigger(void)
{
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
ADC_enableConverter(ADCA_BASE);
DEVICE_DELAY_US(1000);

// 配置SOC0(ePWM1触发)
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0,
ADC_TRIGGER_EPWM1_SOCA, // ePWM1触发
ADC_CH_ADCIN0, 15);

// 配置中断
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
ADC_enableContinuousMode(ADCA_BASE, ADC_INT_NUMBER1);
}

void main(void)
{
Device_init();
Device_initGPIO();

Interrupt_initModule();
Interrupt_initVectorTable();

EPWM1_Init_ADCTrigger();
ADCA_Init_EPWMTrigger();

// 注册中断
Interrupt_register(INT_ADCA1, &adcA1ISR);
Interrupt_enable(INT_ADCA1);

EINT;
ERTM;

while(1)
{
// ADC自动采样,结果在adc_result中
}
}

示例4: ADC平均滤波

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include "driverlib.h"
#include "device.h"

#define FILTER_SIZE 16

uint16_t adc_buffer[FILTER_SIZE];
uint16_t buffer_index = 0;

void ADCA_Init(void)
{
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
ADC_setMode(ADCA_BASE, ADC_RESOLUTION_12BIT, ADC_MODE_SINGLE_ENDED);
ADC_enableConverter(ADCA_BASE);
DEVICE_DELAY_US(1000);

ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0,
ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN0, 15);
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER0);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
}

uint16_t ADCA_ReadFiltered(void)
{
// 读取新的ADC值
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
while(ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1) == false);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);

uint16_t new_value = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);

// 更新缓冲区
adc_buffer[buffer_index] = new_value;
buffer_index = (buffer_index + 1) % FILTER_SIZE;

// 计算平均值
uint32_t sum = 0;
for(int i = 0; i < FILTER_SIZE; i++)
{
sum += adc_buffer[i];
}

return (uint16_t)(sum / FILTER_SIZE);
}

void main(void)
{
Device_init();
Device_initGPIO();

ADCA_Init();

// 初始化缓冲区
for(int i = 0; i < FILTER_SIZE; i++)
{
adc_buffer[i] = 0;
}

while(1)
{
uint16_t filtered_value = ADCA_ReadFiltered();
float voltage = (float)filtered_value * 3.3f / 4095.0f;

DEVICE_DELAY_US(1000); // 1ms
}
}

常见问题

1. ADC读数不准确?

  • 检查参考电压是否稳定
  • 增加采样窗口时间(ACQPS)
  • 使用平均滤波
  • 检查输入阻抗

2. ADC转换速度慢?

  • 减小采样窗口(但要保证足够的采样时间)
  • 提高ADCCLK频率
  • 使用DMA传输

3. 如何提高ADC精度?

  • 使用外部参考电压
  • 多次采样平均
  • 校准ADC
  • 减小输入噪声

4. ePWM触发ADC的优势?

  • 精确的采样时序
  • 减少CPU负担
  • 适合电机控制和电源应用
  • 可实现同步采样

5. 如何使用DMA?

1
2
3
4
5
6
7
// 配置DMA传输ADC结果
DMA_configAddresses(DMA_CH1_BASE,
(uint16_t *)&AdcaResultRegs.ADCRESULT0,
(uint16_t *)adc_buffer);
DMA_configBurst(DMA_CH1_BASE, 1, 1, 1);
DMA_configTransfer(DMA_CH1_BASE, 16, 1, 1);
DMA_startChannel(DMA_CH1_BASE);

下一步

学习完ADC后,继续学习:


参考资料

  • TMS320F28004x Technical Reference Manual - ADC Module
  • C2000Ware DriverLib API Guide - ADC Module
  • ADC Example Code in C2000Ware