ADC配合DMA采样规则是怎样的?

模拟技术

2431人已加入

描述

在做有AD模块项目的时候遇到几个问题:

1, ADC配合DMA采样规则是怎样的。

2, ADC在DMA采可否不连续采样,以提高有效采样使用率和降低功耗。

3, 如何提高有效利用率和降低功耗,并减少CPU的占用时间。

4, ADC的如何多通道采样。

针对以上几个问题做解答。

ADC的采样模式主要分两个:规则采样和注入采样。规则模式可采样16个通道,注入模式最多只能4个通道。

配合DMA使用时主要是用规则采样模式。在初始化时配置采样端口为规则采样通道即可如下:

列:DC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);

端口1为规则采样的第一位,239.5的ADC时钟采样周期。

ADC在DMA下可以不连续采样,既采样一定数据后,关闭ADC及DMA通道。但是这样子存在一些问题。DMA的存储的变量数组中的数据会出现错位问题。

测试过很多方法,包括ADC和DMA一起重新初始化,依然无法解决这个问题。系统只进行一次初始化时,DMA数据无错位现象。 但是对于长时间不关机的产品来说,缺少了几分可靠性。网上也有相关的评测,ADC用DMA工作在强电磁的环境中可能会输出丢失部分数据的可能。

这里就想到了用中断的方式,进行采样。无法用规则模式,因为只能用单次采样触发中断。由于无法确定第一个通道,这样同样会遇到数据错位的现象。所以这里使用注入模式进行中断出发。

有以下几个优点:

1,可以最多4路为一组采样,每组采样结束后才产生一次中断,减少了进中断的次数。

2,在读取数据时几路通道都是预先配置好的。某个变量存放指定某个指定通道。这样永远不可能出现错位现象。

由以总结 在4路及以下通道进行采样时,首选注入模式进行中断采样。超过4路及不是长时间工作的产品(几天以上不断电)可以考虑。

单路采样时,这两种方法都很可靠。

最近刚好在学习uCosII系统,并参考了下通用驱动程序开发。附上ADC驱动代码,希望有所帮助。

提示,在使用某路通道 只要 该通道宏定义置1就可以了。

#defineADCx_CHANNEL0_EN1//ADCx通道11:便能,0:失能

注意: 在使用注入模式时 最多使能4个通道。

1 /*

2 ********************************************************************************

3 * uC/OS-II

4 * AD采样驱动程序设计

5 * ARM Cortex-M3 Port

6 *

7 * File : ADCxDrv.C

8 * Version : V1.0

9 * By : 王宏强

10 *

11 * For : Stm32f10x

12 * Mode : Thumb2

13 * Toolchain :

14 * RealView Microcontroller Development Kit (MDK)

15 * Keil uVision

16 * Description : 定时器驱动

17 * 占用ADCx(ADC1,ADC2)

18 *

19 * 1,DMA规则模式(可靠性低,多路用此模式) 加宏定义 #define ADC_DMA

20 * 2,4路以下,用注入模式(可靠性高,占资源少)

21 *

22 * ADCxOpen

23 * ADCxClose

24 * ADCxWrite

25 * ADCxRead

26 * ADCxIoCtl

27 * ADCxInstall

28 * ADCxNuinstall

29 * Date : 2012.05.22

30 *******************************************************************************/

31

32 #include “ADCxDrv.h”

33

34 //DMA采样缓冲区

35 static volatile INT16U ADC_ConvertedValueTab[MAX_AD_SAMPLE_COUNTER] = {0};

36 static INT16U ADCxBuff[CHANNEL_COUNT] = {0}; //缓冲区数据平均值

37 static INT16U index = 0;

38

39 #ifdef UCOSII

40 static OS_EVENT *adcSem;

41 static INT8U err;

42 #endif

43

44 //总采样时间(单位ms) = 读样个数 * 采样1个值所用时间 / 72mHz * 1000

45 //static INT16U sampingTime = (INT16U)(CHANNEL_COUNT * ADCx_SAMPLE_COUNT *

46 // 239 * 5 / 9e3 + 1);

47

48 /* Private macro -------------------------------------------------------------*/

49 /* Private variables ---------------------------------------------------------*/

50 ADC_InitTypeDef ADC_InitStructure;

51 DMA_InitTypeDef DMA_InitStructure;

52 NVIC_InitTypeDef NVIC_InitStructure;

53

54

55

56 /*******************************************************************************

57 * Function Name :INT16U GetSampleTemp(INT16U order)

58 * Description :获取采样到的数据,并进行平均

59 * Input :order:通道序列号

60 * Output :返回本通道 采样平均值

61 * Other :

62 * Date :2012.05.23 14:48:23

63 *******************************************************************************/

64 static INT16U GetSampleValue(INT16U order)

65 {

66 u32 sum = 0;

67 u16 i = order;

68

69 if (order 》= CHANNEL_COUNT) return 0; //序列号超出范围

70

71 for (i = order; i 《 MAX_AD_SAMPLE_COUNTER; i+=CHANNEL_COUNT)

72 {

73 sum += ADC_ConvertedValueTab[i];

74 }

75 sum /= ADCx_SAMPLE_COUNT;

76

77 return (u16)sum;

78 }

79

80 void StartAdc(FunctionalState stat)

81 {

82 if (stat == ENABLE) index = 0;

83

84 ADC_ITConfig(ADCx, ADC_IT_JEOC, stat);

85 ADC_Cmd(ADCx, stat);

86 }

87

88

89 /*******************************************************************************

90 * Function Name :static INT32S ADCxOpen(void *pd)

91 * Description :

92 * Input :

93 * Output :

94 * Other :

95 * Date :2012.05.23 10:25:06

96 *******************************************************************************/

97 static INT32S ADCxOpen(void *pd)

98 {

99 GPIO_InitTypeDef GPIO_InitStructure;

100 INT32U rccApb = 0;

101 INT16U gpioPin = 0;

102

103 /* Enable peripheral clocks ----------------------------------------------*/

104 /* Enable DMA1 and DMA2 clocks */

105 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMAx, ENABLE);

106

107

108 #if ADCx_GPIOX_1_EN

109 rccApb |= RCC_APBXPeriph_GPIOX_1;

110 #endif

111

112 #if ADCx_GPIOX_2_EN

113 rccApb |= RCC_APBXPeriph_GPIOX_2;

114 #endif

115

116 #if ADCx_GPIOX_3_EN

117 rccApb |= RCC_APBXPeriph_GPIOX_3;

118 #endif

119

120 rccApb |= RCC_APBXPeriph_ADCx;

121 RCC_APB2PeriphClockCmd(rccApb, ENABLE);

122 RCC_ADCCLKConfig(RCC_PCLK2_Div8);

123

124

125 #if ADCx_GPIOX_1_EN

126 gpioPin = 0;

127 #if ADCx_CHANNEL0_EN

128 gpioPin |= ADCx_GPIOX_PIN_CH0;

129 #endif

130 #if ADCx_CHANNEL1_EN

131 gpioPin |= ADCx_GPIOX_PIN_CH1;

132 #endif

133 #if ADCx_CHANNEL2_EN

134 gpioPin |= ADCx_GPIOX_PIN_CH2;

135 #endif

136 #if ADCx_CHANNEL3_EN

137 gpioPin |= ADCx_GPIOX_PIN_CH3;

138 #endif

139 #if ADCx_CHANNEL4_EN

140 gpioPin |= ADCx_GPIOX_PIN_CH4;

141 #endif

142 #if ADCx_CHANNEL5_EN

143 gpioPin |= ADCx_GPIOX_PIN_CH5;

144 #endif

145 #if ADCx_CHANNEL6_EN

146 gpioPin |= ADCx_GPIOX_PIN_CH6;

147 #endif

148 #if ADCx_CHANNEL7_EN

149 gpioPin |= ADCx_GPIOX_PIN_CH7;

150 #endif

151 GPIO_InitStructure.GPIO_Pin = gpioPin;

152 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;

153 GPIO_Init(ADCx_GPIOX_1, &GPIO_InitStructure);

154 #endif

155
       责任编辑:pj

156

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分