当前位置:首页 > 工业控制 > 工业控制
[导读] 例1 利用驱动库函数的8x过采样代码段1.a ADC配置-驱动库函数// // 初始化ADC,使用定序器0对通道1进行8x过采样// 定序器将被其中一个通用定时器触发// ADCSequenceConfigure(ADC_BASE, 0, ADC_TRIGGER_TIMER, 0);

 

1 利用驱动库函数的8x过采样
代码段1.a ADC配置-驱动库函数
//
// 初始化ADC,使用定序器0对通道1进行8x过采样
// 定序器将被其中一个通用定时器触发
//
ADCSequenceConfigure(ADC_BASE, 0, ADC_TRIGGER_TIMER, 0);
ADCSoftwareOversampleConfigure(ADC_BASE, 0, 8);
ADCSoftwareOversampleStepConfigure(ADC_BASE, 0, 0, (ADC_CTL_CH1
| ADC_CTL_IE | ADC_CTL_END));
//
// 初始化定时器0,每隔10ms触发一次ADC转换
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 100);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
代码段1.aADC配置表示在采样完成时产生一个中断,这样就必须具有中断处理程序(见代码段1.b)。驱动库的过采样函数自动将采样的数据进行平均,因此,中断处理函数相对来说也是很基础的。但要记住:要将每次中断中计算的平均值和计算的开销提供给中断处理程序。
代码段1.b ADC中断处理程序
void
ADCIntHandler(void)
{
long lStatus;
//
// 清除ADC中断
//
ADCIntClear(ADC_BASE, 0);
//
// 获得ADC的平均数据
//
lStatus = ADCSoftwareOversampleDataGet(ADC_BASE, 0, &g_ulAverage);
//
// 占位符,供ADC处理数据
//
}
在将配置步骤和中断处理程序放在适当位置后,启动转换处理。定时器打开(开始计数)之前,ADC定序器和中断必须使能(见代码段1.c)。
代码段1.c 使能ADC和中断
//
// 使能ADC定序器0及其中断 (ADCNVIC)
//
ADCSequenceEnable(ADC_BASE, 0);
ADCIntEnable(ADC_BASE, 0);
IntEnable(INT_ADC0);
//
//使能定时器并启动转换处理
//
TimerEnable(TIMER0_BASE, TIMER_A);
使用多个定序器或一个定时器实现大于8倍的过采样
驱动库的过采样函数最大只能进行8倍过采样(根据采样定序器的硬件限制),因此需要更大过采样因子的应用必须使用其它的实现。本小节将描述如何使用下面的两种方法:在过采样频率下运行的多个采样定序器和一个定时器来解决这个问题。
2:使用多个采样定序器的16x过采样
采样定序器的灵活性允许对其进行多种配置。将采样定序器0-2累积起来可获得16个采样(8+4+4),因此使用采样定序器0-2可实现16倍过采样。为使该级别的过采样能够工作,定序器中的所有阶段必须设置为对相同的模拟输入进行采样,这意味着丢弃了使用一个定序器采样多个输入的功能。
代码段2.a使用定序器0-2配置一个10ms的周期转换。使用一个定时器触发就可启动所有3个定序器的采样操作,而无需复杂的触发配置。为获得所需的结果,要对采样定序器的优先级进行配置,这样,采样定序器2的优先级最低(即它最后采样),并且在采样定序器2的最后一步之后,配置为发出一个转换结束中断。
代码段2.a ADC配置-多个采样定序器
//
// 初始化ADC,以便使用定序器0-2对通道1进行16x过采样
// 转换操作通过GPTM触发
//
ADCSequenceConfigure(ADC_BASE, 0, ADC_TRIGGER_TIMER, 0);
ADCSequenceConfigure(ADC_BASE, 1, ADC_TRIGGER_TIMER, 1);
ADCSequenceConfigure(ADC_BASE, 2, ADC_TRIGGER_TIMER, 2);
//
// 配置定序器0的序列步骤(sequence step
//
ADCSequenceStepConfigure(ADC_BASE, 0, 0, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 1, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 2, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 3, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 4, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 5, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 6, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 0, 7, (ADC_CTL_CH1 | ADC_CTL_END));
//
//配置定序器1的序列步骤
//
ADCSequenceStepConfigure(ADC_BASE, 1, 0, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 1, 1, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 1, 2, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 1, 3, (ADC_CTL_CH1 | ADC_CTL_END));
//
//配置定序器2的序列步骤
//
ADCSequenceStepConfigure(ADC_BASE, 2, 0, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 2, 1, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 2, 2, ADC_CTL_CH1);
ADCSequenceStepConfigure(ADC_BASE, 2, 3, (ADC_CTL_CH1 | ADC_CTL_IE
| ADC_CTL_END));
//
// 初始化定时器0,每隔10ms触发一次ADC转换
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 100);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
在代码段2.b中,中断处理程序必须收集FIFO的数据并进行平均计算。因为不需要处理函数开销就可以获得所需的结果,所以不使用ADCSequenceDataGet函数,并且使用直接的寄存器读操作来清空定序器的FIFO。而使用ADCSequenceDataGet时,要求函数定义一个额外的8入口采样缓冲区,即使使用直接的寄存器读操作,中断处理程序中执行的总和计算和平均计算仍然会有可计算的开销。
代码段2.b ADC中断处理程序
void
ADCIntHandler(void)
{
unsigned long ulIdx;
unsigned long ulSum = 0;
//
// 清除中断
//
ADCIntClear(ADC_BASE, 2);
//
// 获得来自定序器0的数据
//
for(ulIdx = 8; ulIdx; ulIdx--)
{
ulSum += HWREG(ADC_BASE + ADC_O_SSFIFO0);
}
//
// 获得来自定序器12的数据
//
for(ulIdx = 4; ulIdx; ulIdx--)
{
ulSum += HWREG(ADC_BASE + ADC_O_SSFIFO1);
ulSum += HWREG(ADC_BASE + ADC_O_SSFIFO2);
}
//
// 将过采样的数据进行平均
//
g_ulAverage = ulSum >> 4;
//
// 占位符,以便ADC处理代码
//
}
在启动转换处理之前,将采样定序器和中断使能(见代码段2.c)。
代码段2.c 使能ADC和中断
//
// 使能定序器和中断
//
ADCSequenceEnable(ADC_BASE, 0);
ADCSequenceEnable(ADC_BASE, 1);
ADCSequenceEnable(ADC_BASE, 2);
ADCIntEnable(ADC_BASE, 2);
IntEnable(INT_ADC2);
//
// 使能定时器并启动转换处理
//
TimerEnable(TIMER0_BASE, TIMER_A);
3 使用在fOS下运行的定时器进行16x过采样
另一个实现16x过采样的方法(无需消耗ADC定序器的大部分资源)是使用一个在过采样频率下运行的周期定时器。例如,如果转换处理每10ms必须返回到主应用程序并且即将进行16倍过采样,则能够将定时器配置为每625µs获得一个采样值。让定时器在过采样频率下触发一次转换明显地产生了额外的ADC中断,这必须在应用程序中说明。
ADC和定时器配置为执行上述操作的代码见代码段3.a
代码段3.a ADC配置-在fOS下运行的定时器
//
// 初始化ADC,以便在检测到一次触发时在通道1、定序器3上获得一个采样值。
// 
//
ADCSequenceConfigure(ADC_BASE, 3, ADC_TRIGGER_TIMER, 0);
ADCSequenceStepConfigure(ADC_BASE, 3, 0, (ADC_CTL_CH1 | ADC_CTL_IE
| ADC_CTL_END));
//
//初始化定时器0,每625µs触发一次ADC转换
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 1600);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
既然ADC在过采样频率下进行采样操作,中断处理程序必须知道已获得的采样数以及总和(见代码段3.b)。在累积了16次转换后,将这16个采样值进行平均,并清除全局采样计数变量和总和变量。
代码段3.b ADC中断处理程序
void
ADCIntHandler(void)
{
//
// 清除中断
//
ADCIntClear(ADC_BASE, 3);
//
// 将新的采样值加到全局总和中
//
g_ulSum += HWREG(ADC_BASE + ADC_O_SSFIFO3);
//
// g_ucOversampleCnt1
//
g_ucOversampleCnt++;
//
// 如果累积了16个采样值,则将它们平均并将全局变量复位
//
if(g_ucOversampleCnt == 16)
{
g_ulAverage = g_ulSum >> 4;
g_ucOversampleCnt = 0;
g_ulSum = 0;
}
//
// 占位符,以便ADC处理代码
//
}
最后,在使能定时器之前,将定序器3及其中断使能,并清除全局计数器和总和变量(见代码段3.c)。
代码段3.c 使能ADC、中断并清除全局变量
//
// 使能定序器和中断
//
ADCSequenceEnable(ADC_BASE, 3);
ADCIntEnable(ADC_BASE, 3);
IntEnable(INT_ADC3);
//
// 将过采样计数器和总和变量清零
//
g_ucOversampleCnt = 0;
g_ulSum = 0;
//
// 使能定时器并启动转换处理
//
TimerEnable(TIMER0_BASE, TIMER_A);
使用滑动平均进行过采样
当采样频率接近ADC的最大采样率时,滑动平均非常有用。滑动平均应用中的主要元件是采样缓冲区,它在每次转换完成时减去/加上数据。
4ADC配置为每隔100µs进行一次采样,采样缓冲区含有16个入口。注意:应用程序不向采样缓冲区预先填充有效的数据,这样,前16个采样值必须相应地由软件来处理。ADC配置为在定时器触发时采样,并在每次转换之后将处理器中断。
4 使用滑动平均每100µs过采样
代码段4.a ADC配置-滑动平均
//
// 初始化ADC,以便在检测到触发时在通道1、定时器3上获得一个采样值。
// 
//
ADCSequenceConfigure(ADC_BASE, 3, ADC_TRIGGER_TIMER, 0);
ADCSequenceStepConfigure(ADC_BASE, 3, 0, (ADC_CTL_CH1 | ADC_CTL_IE
| ADC_CTL_END));
//
// 初始化定时器0,每100µs触发一次ADC转换
//
TimerConfigure(TIMER0_BASE, TIMER_CFG_32_BIT_PER);
TimerLoadSet(TIMER0_BASE, TIMER_A, SysCtlClockGet() / 10000);
TimerControlTrigger(TIMER0_BASE, TIMER_A, true);
中断处理程序必须更新采样缓冲区并进行平均计算(见代码段4.b)。在每次ADC中断时,去掉采样缓冲区中的最后一个元素,缓冲区中剩下的数据移动一个位置。然后,在计算平均值之前将新的转换结果放在采样缓冲区的开始处。中断处理程序中执行的额外计算又一次增加了开销,这一点必须要考虑到。
代码段4.b ADC中断处理程序
void
ADCIntHandler(void)
{
//
// 清除中断
//
ADCIntClear(ADC_BASE, 3);
//
// 检查g_ucOversampleIdx,确保它的值在范围内
//
if(g_ucOversampleIdx == 16)
{
g_ucOversampleIdx = 0;
}
//
// 从全局总和中减去最早的值
//
g_ulSum -= g_ulSampleBuffer[g_ucOversampleIdx];
//
// 用新的采样值代替最早的值
//
g_ulSampleBuffer[g_ucOversampleIdx] = HWREG(ADC_BASE + ADC_O_SSFIFO3);
//
// 将新的采样值加到总和中
//
g_ulSum += g_ulSampleBuffer[g_ucOversampleIdx];
//
// g_ucOversampleIdx1
//
g_ucOversampleIdx++;
//
// 从采样缓冲区的数据中获得平均值
//
g_ulAverage = g_ulSum >> 4;
//
// 占位符,供ADC处理代码
//
}
在启动定时器之前,使能定时器及其中断(见代码段4.c)。
代码段4.c 使能ADC和中断
//
// 使能定序器和中断
//
ADCSequenceEnable(ADC_BASE, 3);
ADCIntEnable(ADC_BASE, 3);
IntEnable(INT_ADC3);
//
// 使能定时器并启动转换处理
//
TimerEnable(TIMER0_BASE, TIMER_A);
需考虑的问题
本文档中描述的过采样技术需要额外的代码来执行平均计算,附加中断,和/或大部分采样定序器资源,因此它在整个系统性能上有一个显著的影响。在选择最适合应用的技术时,需在增加的中断和庞大的中断处理程序之间进行权衡。
结论
Luminary Micro的采样定序器结构为过采样技术的实现提供了大量的选项。当与软件平均技术相结合时,该结构能够使系统设计人员有效地在采样频率、系统性能和采样解决方案之间进行权衡。
本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: 驱动电源

在工业自动化蓬勃发展的当下,工业电机作为核心动力设备,其驱动电源的性能直接关系到整个系统的稳定性和可靠性。其中,反电动势抑制与过流保护是驱动电源设计中至关重要的两个环节,集成化方案的设计成为提升电机驱动性能的关键。

关键字: 工业电机 驱动电源

LED 驱动电源作为 LED 照明系统的 “心脏”,其稳定性直接决定了整个照明设备的使用寿命。然而,在实际应用中,LED 驱动电源易损坏的问题却十分常见,不仅增加了维护成本,还影响了用户体验。要解决这一问题,需从设计、生...

关键字: 驱动电源 照明系统 散热

根据LED驱动电源的公式,电感内电流波动大小和电感值成反比,输出纹波和输出电容值成反比。所以加大电感值和输出电容值可以减小纹波。

关键字: LED 设计 驱动电源

电动汽车(EV)作为新能源汽车的重要代表,正逐渐成为全球汽车产业的重要发展方向。电动汽车的核心技术之一是电机驱动控制系统,而绝缘栅双极型晶体管(IGBT)作为电机驱动系统中的关键元件,其性能直接影响到电动汽车的动力性能和...

关键字: 电动汽车 新能源 驱动电源

在现代城市建设中,街道及停车场照明作为基础设施的重要组成部分,其质量和效率直接关系到城市的公共安全、居民生活质量和能源利用效率。随着科技的进步,高亮度白光发光二极管(LED)因其独特的优势逐渐取代传统光源,成为大功率区域...

关键字: 发光二极管 驱动电源 LED

LED通用照明设计工程师会遇到许多挑战,如功率密度、功率因数校正(PFC)、空间受限和可靠性等。

关键字: LED 驱动电源 功率因数校正

在LED照明技术日益普及的今天,LED驱动电源的电磁干扰(EMI)问题成为了一个不可忽视的挑战。电磁干扰不仅会影响LED灯具的正常工作,还可能对周围电子设备造成不利影响,甚至引发系统故障。因此,采取有效的硬件措施来解决L...

关键字: LED照明技术 电磁干扰 驱动电源

开关电源具有效率高的特性,而且开关电源的变压器体积比串联稳压型电源的要小得多,电源电路比较整洁,整机重量也有所下降,所以,现在的LED驱动电源

关键字: LED 驱动电源 开关电源

LED驱动电源是把电源供应转换为特定的电压电流以驱动LED发光的电压转换器,通常情况下:LED驱动电源的输入包括高压工频交流(即市电)、低压直流、高压直流、低压高频交流(如电子变压器的输出)等。

关键字: LED 隧道灯 驱动电源
关闭