主要记录一下,自己最近处学习的DSP的ADC模块。
(自用记录,防止遗忘!!)
采用的是软件触发,TI官方的第一个例子。
输入电压为编码器输出的2.5V的sin+、sin-、cos+、cos-电压,最后利用差分信号进行实际示波器中观察到的图形模拟。
上代码:
(可能会比较乱,因为是自己反复修改,同时添加了好几种方式来实现的。)
#include "driverlib.h"
#include "device.h"
//uint16_t adcAResult0;
//uint16_t adcAResult1;
//uint16_t adcBResult0;
//uint16_t adcBResult1;
uint16_t a1[1024] = {0};
uint16_t a2[1024] = {0};
uint16_t a3[1024] = {0};
uint16_t a4[1024] = {0};
uint16_t a5[1024] = {0};
uint16_t a6[1024] = {0};
uint16_t i = 0 ,j = 0 ;
uint16_t p = 0 ,q =0 ;
uint16_t u = 0 ,v =0 ;
void initADCs(void);
void initADCSOCs(void);
void main(void)
{
Device_init();
Device_initGPIO();
Interrupt_initModule();
Interrupt_initVectorTable();
// 初始化ADC,初始化SOC为软件触发。
initADCs();
initADCSOCs();
EINT;
ERTM;
while(1)
{
// 软件触发ADC转换。
// Convert, wait for completion, and store results
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER0);
ADC_forceSOC(ADCA_BASE, ADC_SOC_NUMBER1);
ADC_forceSOC(ADCB_BASE, ADC_SOC_NUMBER0);
ADC_forceSOC(ADCB_BASE, ADC_SOC_NUMBER1);
ADC_forceSOC(ADCC_BASE, ADC_SOC_NUMBER0);
ADC_forceSOC(ADCC_BASE, ADC_SOC_NUMBER1);
// 等待ADC转换完成,并清除中断标志位
while(ADC_getInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1) == false)
{
}
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
while(ADC_getInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1)== false)
{
}
ADC_clearInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1);
while(ADC_getInterruptStatus(ADCC_BASE, ADC_INT_NUMBER1) == false)
{
}
ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER1);
//static uint16_t a1[100] = {0};
//static uint16_t a2[100] = {0};
//分别将采集到的结果存放至数组a1[100],a2[100]
a1[i++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
// if(i >= sizeof(a1) / sizeof(a1[0])) //(400/4=100)同i>=100,此方法不用修改两处,只用将定义数组处的数组内数据随意修改即可。
if(i >= 1024)
{
i=0;
// ESTOP0;
}
a2[j++] = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1);
// if(j >= sizeof(a2) / sizeof(a2[0]))
if(j >= 1024)
{
j=0;
}
a3[p++] = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER0);
if(p >= 1024)
{
p=0;
}
a4[q++] = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER1);
if(q >= 1024)
{
q=0;
ESTOP0;
}
a5[u++] = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER0);
if(u >= 1024)
{
u=0;
}
a6[v++] = ADC_readResult(ADCCRESULT_BASE, ADC_SOC_NUMBER1);
if(v >= 1024)
{
v=0;
}
// 储存结果
// adcAResult0 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER0);
// adcAResult1 = ADC_readResult(ADCARESULT_BASE, ADC_SOC_NUMBER1);
// adcBResult0 = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER0);
// adcBResult1 = ADC_readResult(ADCBRESULT_BASE, ADC_SOC_NUMBER1);
// 用于调试的软件暂停。
// Software breakpoint. At this point, conversion results are stored in
// adcAResult0, adcAResult1, adcBResult0, and adcBResult1.
// Hit run again to get updated conversions.
// ESTOP0;
//延时20us
// DEVICE_DELAY_US(20);
}
}
// 初始化ADC
void initADCs(void)
{
// ADC使用片内参考3.3V
// Setup VREF as internal
ADC_setVREF(ADCA_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
ADC_setVREF(ADCB_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
ADC_setVREF(ADCC_BASE, ADC_REFERENCE_INTERNAL, ADC_REFERENCE_3_3V);
// ADC时钟4分频
// Set ADCCLK divider to /4
ADC_setPrescaler(ADCA_BASE, ADC_CLK_DIV_4_0);
ADC_setPrescaler(ADCB_BASE, ADC_CLK_DIV_4_0);
ADC_setPrescaler(ADCC_BASE, ADC_CLK_DIV_4_0);
// 设置转换结束时触发中断
// Set pulse positions to late
ADC_setInterruptPulseMode(ADCA_BASE, ADC_PULSE_END_OF_CONV);
ADC_setInterruptPulseMode(ADCB_BASE, ADC_PULSE_END_OF_CONV);
ADC_setInterruptPulseMode(ADCC_BASE, ADC_PULSE_END_OF_CONV);
// 启动AD并延迟1ms
// Power up the ADCs and then delay for 1 ms
ADC_enableConverter(ADCA_BASE);
ADC_enableConverter(ADCB_BASE);
ADC_enableConverter(ADCC_BASE);
DEVICE_DELAY_US(1000);
}
// 初始化ADCSOC
void initADCSOCs(void)
{
// 采样窗口持续10个系统时钟
// - SOC0 will convert pin A0 with a sample window of 10 SYSCLK cycles.
// - SOC1 will convert pin A1 with a sample window of 10 SYSCLK cycles.
//
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN0, 10);
ADC_setupSOC(ADCA_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN1, 10);
// 设置中断为ADCINT1,并启用
// Set SOC1 to set the interrupt 1 flag. Enable the interrupt and make
// sure its flag is cleared.
ADC_setInterruptSource(ADCA_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER1);
ADC_enableInterrupt(ADCA_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(ADCA_BASE, ADC_INT_NUMBER1);
// 采样窗口持续10个系统时钟
// - SOC0 will convert pin B0 with a sample window of 10 SYSCLK cycles.
// - SOC1 will convert pin B1 with a sample window of 10 SYSCLK cycles.
//
ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN0, 10);
ADC_setupSOC(ADCB_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN1, 10);
// 设置中断为ADCINT1,并启用
// Set SOC1 to set the interrupt 1 flag. Enable the interrupt and make
// sure its flag is cleared.
ADC_setInterruptSource(ADCB_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER1);
ADC_enableInterrupt(ADCB_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(ADCB_BASE, ADC_INT_NUMBER1);
ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER0, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN15, 10);
ADC_setupSOC(ADCC_BASE, ADC_SOC_NUMBER1, ADC_TRIGGER_SW_ONLY, ADC_CH_ADCIN15, 10);
// 设置中断为ADCINT1,并启用
// Set SOC1 to set the interrupt 1 flag. Enable the interrupt and make
// sure its flag is cleared.
ADC_setInterruptSource(ADCC_BASE, ADC_INT_NUMBER1, ADC_SOC_NUMBER1);
ADC_enableInterrupt(ADCC_BASE, ADC_INT_NUMBER1);
ADC_clearInterruptStatus(ADCC_BASE, ADC_INT_NUMBER1);
}
附excle结果处理图:
这是sin与cos绘制出的圆
好了,这里来说一下我在实验中所以到的问题以及解决办法。
1. 由于起初,程序只能自动采集一次,后来就去掉了那个自动结束的语句。“ESTOP0”,增加循环。
2. 由于要采集1024个数据存放在一个数组中,因此存在寄存器内存不够的问题,可在.map文件中查看各寄存器内存使用情况,并在cmd文件中修改。
3. 发现ADCA/B/C三个模块中,A独立,B与C配置相同,若只配置B,则无法输出数字信号,须同时对C进行配置,采用其公用引脚,进行任意配置即可。
3.然后为实现采集1024个数据程序自动停止,再循环中添加了结束语句。
4. 为使ADCA/B/C同时采样,删掉主程序中的延时。
结束~~~
接下来想实验一下不用软件触发,用其他寄存器等触发,因为软件触发由上面的excle图中可以看出,除了没有添加滤波等外部因素外,软件触发在实现同时采样方面仍不太理想。