Stm32f103 ADC 学习笔记
在做有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 {
66u32 sum = 0;
67u16 i = order;
68
69if (order >= CHANNEL_COUNT) return 0;//序列号超出范围
70
71for (i = order; i < MAX_AD_SAMPLE_COUNTER; i+=CHANNEL_COUNT)
72{
73sum += ADC_ConvertedValueTab[i];
74}
75sum /= ADCx_SAMPLE_COUNT;
76
77return (u16)sum;
78 }
79
80 void StartAdc(FunctionalState stat)
81 {
82if (stat == ENABLE) index = 0;
83
84ADC_ITConfig(ADCx, ADC_IT_JEOC, stat);
85ADC_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 {
99GPIO_InitTypeDef GPIO_InitStructure;
100INT32U rccApb = 0;
101INT16U gpioPin = 0;
102
103/* Enable peripheral clocks ----------------------------------------------*/
104/* Enable DMA1 and DMA2 clocks */
105RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMAx, ENABLE);
106
107
108 #if ADCx_GPIOX_1_EN
109rccApb |= RCC_APBXPeriph_GPIOX_1;
110 #endif
111
112 #if ADCx_GPIOX_2_EN
113rccApb |= RCC_APBXPeriph_GPIOX_2;
114 #endif
115
116 #if ADCx_GPIOX_3_EN
117rccApb |= RCC_APBXPeriph_GPIOX_3;
118 #endif
119
120rccApb |= RCC_APBXPeriph_ADCx;
121RCC_APB2PeriphClockCmd(rccApb, ENABLE);
122RCC_ADCCLKConfig(RCC_PCLK2_Div8);
123
124
125 #if ADCx_GPIOX_1_EN
126gpioPin = 0;
127 #if ADCx_CHANNEL0_EN
128gpioPin |= ADCx_GPIOX_PIN_CH0;
129 #endif
130 #if ADCx_CHANNEL1_EN
131gpioPin |= ADCx_GPIOX_PIN_CH1;
132 #endif
133 #if ADCx_CHANNEL2_EN
134gpioPin |= ADCx_GPIOX_PIN_CH2;
135 #endif
136 #if ADCx_CHANNEL3_EN
137gpioPin |= ADCx_GPIOX_PIN_CH3;
138 #endif
139 #if ADCx_CHANNEL4_EN
140gpioPin |= ADCx_GPIOX_PIN_CH4;
141 #endif
142 #if ADCx_CHANNEL5_EN
143gpioPin |= ADCx_GPIOX_PIN_CH5;
144 #endif
145 #if ADCx_CHANNEL6_EN
146gpioPin |= ADCx_GPIOX_PIN_CH6;
147 #endif
148 #if ADCx_CHANNEL7_EN
149gpioPin |= ADCx_GPIOX_PIN_CH7;
150 #endif
151GPIO_InitStructure.GPIO_Pin = gpioPin;
152GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
153GPIO_Init(ADCx_GPIOX_1, &GPIO_InitStructure);
154 #endif
155
【Stm32f103 ADC 学习笔记】156
推荐阅读
- 哈佛医学院用机器学习算法开发AI时钟,能够预测剩余寿命
- 快速学习实木复合门的安装流程
- 单片机课程学习与感想
- 跟着小编学习竹地板安装方法吧!
- 51单片机学习笔记:步进电机控制,正转反转等
- TinyOS下CC2430单片机ADC使用方法
- SPI通信协议—STM32f1学习笔记
- 如何为其高速ADC设计清洁电源?
- STM32学习笔记1 IO口学习
- ARM7单片机_学习ing—(六)、SPI接口—02