Stm32f103 ADC 學(xué)習(xí)筆記
在做有AD模塊項(xiàng)目的時(shí)候遇到幾個(gè)問(wèn)題:
1, ADC配合DMA采樣規(guī)則是怎樣的。
2, ADC在DMA采可否不連續(xù)采樣,以提高有效采樣使用率和降低功耗。
3, 如何提高有效利用率和降低功耗,并減少CPU的占用時(shí)間。
4, ADC的如何多通道采樣。
針對(duì)以上幾個(gè)問(wèn)題做解答。
ADC的采樣模式主要分兩個(gè):規(guī)則采樣和注入采樣。規(guī)則模式可采樣16個(gè)通道,注入模式最多只能4個(gè)通道。
配合DMA使用時(shí)主要是用規(guī)則采樣模式。在初始化時(shí)配置采樣端口為規(guī)則采樣通道即可如下:
列:DC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);
端口1為規(guī)則采樣的第一位,239.5的ADC時(shí)鐘采樣周期。
ADC在DMA下可以不連續(xù)采樣,既采樣一定數(shù)據(jù)后,關(guān)閉ADC及DMA通道。但是這樣子存在一些問(wèn)題。DMA的存儲(chǔ)的變量數(shù)組中的數(shù)據(jù)會(huì)出現(xiàn)錯(cuò)位問(wèn)題。
測(cè)試過(guò)很多方法,包括ADC和DMA一起重新初始化,依然無(wú)法解決這個(gè)問(wèn)題。系統(tǒng)只進(jìn)行一次初始化時(shí),DMA數(shù)據(jù)無(wú)錯(cuò)位現(xiàn)象。 但是對(duì)于長(zhǎng)時(shí)間不關(guān)機(jī)的產(chǎn)品來(lái)說(shuō),缺少了幾分可靠性。網(wǎng)上也有相關(guān)的評(píng)測(cè),ADC用DMA工作在強(qiáng)電磁的環(huán)境中可能會(huì)輸出丟失部分?jǐn)?shù)據(jù)的可能。
這里就想到了用中斷的方式,進(jìn)行采樣。無(wú)法用規(guī)則模式,因?yàn)橹荒苡脝未尾蓸佑|發(fā)中斷。由于無(wú)法確定第一個(gè)通道,這樣同樣會(huì)遇到數(shù)據(jù)錯(cuò)位的現(xiàn)象。所以這里使用注入模式進(jìn)行中斷出發(fā)。
有以下幾個(gè)優(yōu)點(diǎn):
1,可以最多4路為一組采樣,每組采樣結(jié)束后才產(chǎn)生一次中斷,減少了進(jìn)中斷的次數(shù)。
2,在讀取數(shù)據(jù)時(shí)幾路通道都是預(yù)先配置好的。某個(gè)變量存放指定某個(gè)指定通道。這樣永遠(yuǎn)不可能出現(xiàn)錯(cuò)位現(xiàn)象。
由以總結(jié) 在4路及以下通道進(jìn)行采樣時(shí),首選注入模式進(jìn)行中斷采樣。超過(guò)4路及不是長(zhǎng)時(shí)間工作的產(chǎn)品(幾天以上不斷電)可以考慮。
單路采樣時(shí),這兩種方法都很可靠。
最近剛好在學(xué)習(xí)uCosII系統(tǒng),并參考了下通用驅(qū)動(dòng)程序開(kāi)發(fā)。附上ADC驅(qū)動(dòng)代碼,希望有所幫助。
提示,在使用某路通道 只要 該通道宏定義置1就可以了。
#defineADCx_CHANNEL0_EN1//ADCx通道11:便能,0:失能
注意: 在使用注入模式時(shí) 最多使能4個(gè)通道。
1 /*
2 ********************************************************************************
3 * uC/OS-II
4 * AD采樣驅(qū)動(dòng)程序設(shè)計(jì)
5 * ARM Cortex-M3 Port
6 *
7 * File : ADCxDrv.C
8 * Version : V1.0
9 * By : 王宏強(qiáng)
10 *
11 * For : Stm32f10x
12 * Mode : Thumb2
13 * Toolchain :
14 * RealView Microcontroller Development Kit (MDK)
15 * Keil uVision
16 * Description : 定時(shí)器驅(qū)動(dòng)
17 * 占用ADCx(ADC1,ADC2)
18 *
19 * 1,DMA規(guī)則模式(可靠性低,多路用此模式) 加宏定義 #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采樣緩沖區(qū)
35 static volatile INT16U ADC_ConvertedValueTab[MAX_AD_SAMPLE_COUNTER] = {0};
36 static INT16U ADCxBuff[CHANNEL_COUNT] = {0}; //緩沖區(qū)數(shù)據(jù)平均值
37 static INT16U index = 0;
38
39 #ifdef UCOSII
40 static OS_EVENT *adcSem;
41 static INT8U err;
42 #endif
43
44 //總采樣時(shí)間(單位ms) = 讀樣個(gè)數(shù) * 采樣1個(gè)值所用時(shí)間 / 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 :獲取采樣到的數(shù)據(jù),并進(jìn)行平均
59 * Input :order:通道序列號(hào)
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; //序列號(hào)超出范圍
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
156