核心板:STM32F407
实验目的:使用ADC采集电压值将其打印在串口助手上
目录
ADC简介
STM32F407 ADC通道对应的引脚
STM32F407中的数据寄存器
ADC 规则数据寄存器 (ADC_DR)
ADC 注入数据寄存器 x (ADC_JDRx) (x= 1..4)
适用于双重和三重模式的 ADC 通用规则数据寄存器(ADC_CDR)
对于F407在ADC实验中使用的函数理解
非DMA的相关函数
ADC_RegularChannelConfig()
ADC_Cmd()与ADC_SoftwareStartConv()
有关DMA的相关函数
ADC_DMARequestAfterLastTransferCmd()与ADC_DMACmd()
ADC_MultiModeDMARequestAfterLastTransferCmd()与ADC_CommonInitTypeDef中的成员ADC_DMAAccessMode
ADC-独立模式-单通道-采集电压(中断)
ADC-独立模式-多通道-采集电压(DMA)
ADC-双重模式-单通道-规则同步采集电压(DMA)
ADC-三重模式-单通道-交替采集电压(DMA)
ADC简介
ADC就是一种数模转换器。在以下介绍的实验中,都是ADC对电压的采集,而ADC的输入电压为0-3.3v,如果ADC我们设置为12位,那么3.3v对应这2的12次方即4096,那么单位数字量对应的模拟量则为3.3/4096。而ADC的功能可以帮助我们获取数字量X,那么我们读取ADC获取的数字量X再乘以3.3/4096,就是电压值。
STM32F407 ADC通道对应的引脚
STM32F407中的数据寄存器
在STM32F407中有三个数据寄存器,他们对应着不同的模式下数据存放的地方,在使用DMA时注意不要吧外设地址设置错误。
ADC 规则数据寄存器 (ADC_DR)
ADC规则数据寄存器是一个32位只适用于独立模式的寄存器,但是只有低16位有效来存储数据,ADC最大精度为12位,所以我们在ADC在存放数据时我们需要设置左对齐还是右对齐来存储数据。
ADC 注入数据寄存器 x (ADC_JDRx) (x= 1..4)
ADC注入数据寄存器有四个,对应四个注入通道,所以不会存在向规则数据寄存器那样数据被覆盖的问题。
适用于双重和三重模式的 ADC 通用规则数据寄存器(ADC_CDR)
ADC_DR仅适用于独立模式,而ADC_CDR适用于多重ADC即多个ADC使用的情况。
对于F407在ADC实验中使用的函数理解
在刚开始写这个实验的时候,在配置时某个函数该什么时候用什么时候不用,在哪用,就比较懵,其实就是多读读手册就好了,这里给大家小小的总结以下。
非DMA的相关函数
ADC_RegularChannelConfig()
其参数为(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime)
哪个ADC(ADCx),哪个通道(ADC_Channel),在这个ADC的转换顺序为第几(Rank),其采样周期为多少(ADC_SampleTime)。
ADC_Cmd()与ADC_SoftwareStartConv()
这两函数操作的寄存器均为ADC_CR2,前者操作的为ADC_CR2中的ADON,后者为ADC_CR2中的SWSTART。
所以我们在不是用外部触发时,我们应该如下写这两句代码(颠倒顺序我也不知道OK不)。
有关DMA的相关函数
ADC_DMARequestAfterLastTransferCmd()与ADC_DMACmd()
其操作的分别为ADC_CR2中的DDS与DMA。
所以这两个函数是针对只使用一个ADC时启用DMA该调用的函数。
ADC_MultiModeDMARequestAfterLastTransferCmd()与ADC_CommonInitTypeDef中的成员ADC_DMAAccessMode
其操作的分别为ADC_CCR中的DMA和DDS。
所以这两个函数是针对只使用多个ADC时启用DMA该调用的函数。
初学的应该懂得为什么上面禁止DMA下面又使能DMA了吧!
下面开始写实验,这里我只写ADC相关的配置和主程序,串口就交给大家了。
ADC-独立模式-单通道-采集电压(中断)
实验内容:使用ADC1将PB0引脚上电压值转化成数字量,然后我们在通过运算将其电压值打印在串口助手上。
bsp_adc.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21#ifndef _BSP__ADC_H #define _BSP__ADC_H #include "stm32f4xx.h" /* ADC1 */ #define ADC_CLK RCC_APB2Periph_ADC1 #define ADC_CHANNEL ADC_Channel_8 /* 电压输入引脚 (ADC1 通道8 引脚 ——PB0) */ #define ADC_PIN GPIO_Pin_0 #define ADC_GPIO_PORT GPIOB #define ADC_GPIO_CLK RCC_AHB1Periph_GPIOB extern uint16_t Value;//数字量 void ADC_Config(void); #endif
bsp_adc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68#include "bsp_adc.h" uint16_t Value;//数字量 static void ADC_NVIC_Config(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 嵌套向量中断控制器组选择 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); /* 配置ADC1为中断源 */ NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQn; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; NVIC_Init(&NVIC_InitStructure); } void ADC_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK,ENABLE); RCC_APB2PeriphClockCmd(ADC_CLK, ENABLE); /* GPIO相关配置 */ GPIO_InitStructure.GPIO_Pin = ADC_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ;//GPIO 用于 AD 转换功能必须配置为模拟输入模式 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉 无下拉 GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速 GPIO_Init (ADC_GPIO_PORT,&GPIO_InitStructure); ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC 连续转换模式选择 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//输出数据对齐方式 //ADC 外部触发选择(本实验用软件触发,随便配置) ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发 ADC_InitStructure.ADC_NbrOfConversion = 1;//转换通道数目 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//ADC 分辨率选择 ADC_InitStructure.ADC_ScanConvMode = DISABLE;// 禁止扫描模式,多通道采集才需要 ADC_Init(ADC1, &ADC_InitStructure); ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;//禁止DMA直接访问模式 ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;// 独立ADC模式 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//4分频 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔 ADC_CommonInit(&ADC_CommonInitStructure); ADC_NVIC_Config(); //配置 ADC 通道转换顺序为1(第一个转换),采样时间为56个时钟周期 ADC_RegularChannelConfig(ADC1, ADC_CHANNEL, 1, ADC_SampleTime_56Cycles); ADC_ITConfig(ADC1,ADC_IT_EOC, ENABLE);//开启转换结束中断 ADC_Cmd(ADC1,ENABLE);//使能ADC ADC_SoftwareStartConv(ADC1);//开始adc转换 }
中断服务函数
1
2
3
4
5
6
7
8
9
10void ADC_IRQHandler(void) { if(ADC_GetITStatus(ADC1, ADC_IT_EOC) == SET) { Value = ADC_GetConversionValue(ADC1);//读取采集到的数字量 ADC_ClearITPendingBit(ADC1, ADC_IT_EOC); } }
main.c(写一个)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27void Delay(__IO u32 nCount); float Data;//最终的电压值 int main(void) { USART_Config(); ADC_Config(); printf("一切OKn"); while (1) { //数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量 Data = (float) (Value *3.3 /4096) ; printf("电压值为:%f Vn",Data); Delay(0xffffff); } } void Delay(__IO uint32_t nCount) //简单的延时函数 { for(; nCount != 0; nCount--); }
实验结果(PB0连接着滑动变阻器)
ADC-独立模式-多通道-采集电压(DMA)
实验内容:使用ADC1将PB0、PB1、PA6引脚上电压值转化成数字量,然后我们在通过运算将其电压值打印在串口助手上。
bsp_adc.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38#ifndef _BSP__ADC_H #define _BSP__ADC_H #include "stm32f4xx.h" /* 电压输入引脚 (ADC 通道8 引脚 ——PB0) */ #define ADC_PIN1 GPIO_Pin_0 #define ADC_GPIO_PORT1 GPIOB #define ADC_GPIO_CLK1 RCC_AHB1Periph_GPIOB /* 光敏电阻 (ADC 通道9 引脚 ——PB1)*/ #define ADC_PIN2 GPIO_Pin_1 #define ADC_GPIO_PORT2 GPIOB #define ADC_GPIO_CLK2 RCC_AHB1Periph_GPIOB /* 悬空 用杜邦线连接GND或VCC(ADC 通道6 引脚 ——PA6) */ #define ADC_PIN3 GPIO_Pin_6 #define ADC_GPIO_PORT3 GPIOA #define ADC_GPIO_CLK3 RCC_AHB1Periph_GPIOA /* ADC1 */ #define ADC_CLK RCC_APB2Periph_ADC1 #define ADC_CHANNEL1 ADC_Channel_8 #define ADC_CHANNEL2 ADC_Channel_9 #define ADC_CHANNEL3 ADC_Channel_6 #define ADC1_DR_BASE ((uint32_t)ADC1+0x4c) /* DMA */ #define ADC_DMA_CLK RCC_AHB1Periph_DMA2 #define ADC_DMA_CHANNEL DMA_Channel_0 #define ADC_DMA_STREAM DMA2_Stream0 extern uint16_t Value[3]; void ADC_Config(void); #endif
bsp_adc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93#include "bsp_adc.h" uint16_t Value[3]; static void ADC_DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; RCC_AHB1PeriphClockCmd(ADC_DMA_CLK,ENABLE); /* 配置DMA */ DMA_InitStructure.DMA_BufferSize = 3;//一次性传输3个数据 DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL;//ADC1 DMA通道 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//DMA搬运方向:外设到存储器 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Value;//存储器地址 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择:单次模式 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据宽度:半字16位 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//使能存储器地址自动递增功能 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA 传输模式选择:循环模式 DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_BASE;//外设地址 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择:单次模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度:半字16位 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//禁止外设地址自动递增功能 DMA_InitStructure.DMA_Priority = DMA_Priority_High;//软件设置数据流的优先级:高级 /* FIFO不用随便配置 */ DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure); DMA_Cmd(ADC_DMA_STREAM, ENABLE);//使能DMA } void ADC_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; /* 开启时钟 */ RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1|ADC_GPIO_CLK2|ADC_GPIO_CLK3,ENABLE); RCC_APB2PeriphClockCmd(ADC_CLK, ENABLE); /* GPIO相关配置 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ;//GPIO 用于 AD 转换功能必须配置为模拟输入模式 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉 无下拉 GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速 GPIO_InitStructure.GPIO_Pin = ADC_PIN1; GPIO_Init (ADC_GPIO_PORT1,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = ADC_PIN2; GPIO_Init (ADC_GPIO_PORT2,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = ADC_PIN3; GPIO_Init (ADC_GPIO_PORT3,&GPIO_InitStructure); ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC 连续转换模式选择 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//输出数据对齐方式 //ADC 外部触发选择(本实验用软件触发,随便配置) ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发 ADC_InitStructure.ADC_NbrOfConversion = 3;//转换通道数目 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//ADC 分辨率选择 ADC_InitStructure.ADC_ScanConvMode = ENABLE;// 开启扫描模式,多通道采集需要 ADC_Init(ADC1, &ADC_InitStructure); ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;//禁止直接存储器访问模式(对于多个 ADC 模式) ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;// 独立ADC模式 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//4分频 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔 ADC_CommonInit(&ADC_CommonInitStructure); ADC_DMA_Config(); //配置 ADC 通道转换顺序为1(第一个转换),采样时间为56个时钟周期 ADC_RegularChannelConfig(ADC1, ADC_CHANNEL1, 1, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC1, ADC_CHANNEL2, 2, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC1, ADC_CHANNEL3, 3, ADC_SampleTime_56Cycles); ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);//只要发生数据转换就会发生DMA请求 ADC_DMACmd(ADC1, ENABLE);//允许直接存储器访问模式(对于单一 ADC 模式) ADC_Cmd(ADC1,ENABLE);//使能ADC //再次软件开启ADC转换是因为让ADC转换可以由其他的一些条件什么的开启ADC转化,这里我们用软件开启 ADC_SoftwareStartConv(ADC1);//开始转换规则通道 }
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31void Delay(__IO uint32_t nCount) //简单的延时函数 { for(; nCount != 0; nCount--); } float Data[3];//最终的电压值 int main(void) { USART_Config(); ADC_Config(); printf("一切OKn"); while (1) { //数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量 Data[0] = (float) (Value[0] *3.3 /4096) ; Data[1] = (float) (Value[1] *3.3 /4096) ; Data[2] = (float) (Value[2] *3.3 /4096) ; printf("rnData1=%f Vn",Data[0]); printf("Data2=%f Vn",Data[1]); printf("Data3=%f Vrn",Data[2]); Delay(0xffffff); } }
ADC-双重模式-单通道-规则同步采集电压(DMA)
实验内容:使用ADC1将PB0引脚上电压值转化成数字量,然后我们在通过运算将其电压值打印在串口助手上。
为了演示DMA模式1与2,这里我们使用模式1,下一个使用模式2。
模式1DMA应设置传输数据大小为16位,模式2DMA应设置传输数据大小为32位。
bsp_adc.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36#ifndef _BSP__ADC_H #define _BSP__ADC_H #include "stm32f4xx.h" /* 滑动变阻器(ADC1 通道8 引脚 ——PB0) */ #define ADC_PIN1 GPIO_Pin_0 #define ADC_GPIO_PORT1 GPIOB #define ADC_GPIO_CLK1 RCC_AHB1Periph_GPIOB /* 滑动变阻器(ADC2 通道9 引脚 ——PB1) */ #define ADC_PIN2 GPIO_Pin_1 #define ADC_GPIO_PORT2 GPIOB #define ADC_GPIO_CLK2 RCC_AHB1Periph_GPIOB /* ADC1 */ #define ADC1_CLK RCC_APB2Periph_ADC1 #define ADC2_CLK RCC_APB2Periph_ADC2 #define ADC1_CHANNEL ADC_Channel_8 #define ADC2_CHANNEL ADC_Channel_9 #define ADC1_CDR_ADDR ((uint32_t)ADC1+0x300+0x08)//多重ADC数据寄存器地址 /* DMA */ #define ADC_DMA_CLK RCC_AHB1Periph_DMA2 #define ADC_DMA_CHANNEL DMA_Channel_0 #define ADC_DMA_STREAM DMA2_Stream0 //多重模式下,ADC1还是主,所以只需要配置ADC1的DMA通道 extern uint16_t Value[2]; void ADC_Config(void); #endif
bsp_adc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96#include "bsp_adc.h" uint16_t Value[2]; static void ADC_DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; RCC_AHB1PeriphClockCmd(ADC_DMA_CLK,ENABLE); /* 配置DMA */ DMA_InitStructure.DMA_BufferSize = 2;//一次性传输2个数据 DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL;//ADC1 DMA通道 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//DMA搬运方向:外设到存储器 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Value;//存储器地址 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择:单次模式 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//存储器数据宽度:半字16位 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//使能存储器地址自动递增功能 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA 传输模式选择:循环模式 DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_CDR_ADDR;//外设地址 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择:单次模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度:半字16位 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//禁止外设地址自动递增功能 DMA_InitStructure.DMA_Priority = DMA_Priority_High;//软件设置数据流的优先级:高级 /* FIFO不用随便配置 */ DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure); DMA_Cmd(ADC_DMA_STREAM, ENABLE);//使能DMA } void ADC_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; /* 开启时钟 */ RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK1 | ADC_GPIO_CLK2,ENABLE); RCC_APB2PeriphClockCmd(ADC1_CLK | ADC2_CLK, ENABLE); /* GPIO相关配置 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ;//GPIO 用于 AD 转换功能必须配置为模拟输入模式 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉 无下拉 GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速 GPIO_InitStructure.GPIO_Pin = ADC_PIN1; GPIO_Init (ADC_GPIO_PORT1,&GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = ADC_PIN2; GPIO_Init (ADC_GPIO_PORT2,&GPIO_InitStructure); ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC 连续转换模式选择 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//输出数据对齐方式 //ADC 外部触发选择(本实验用软件触发,随便配置) ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发 ADC_InitStructure.ADC_NbrOfConversion = 1;//转换通道数目 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//ADC 分辨率选择 ADC_InitStructure.ADC_ScanConvMode = DISABLE;// 禁止扫描模式,多通道采集才需要(对于两个ADC只有一个通道) ADC_Init(ADC1, &ADC_InitStructure); ADC_Init(ADC2, &ADC_InitStructure); ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;//允许直接存储器访问模式(对于多个 ADC 模式) ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;// 二重模式规则同步采集 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//4分频 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔 ADC_CommonInit(&ADC_CommonInitStructure); ADC_DMA_Config(); //配置 ADC 通道转换顺序为1(第一个转换),采样时间为56个时钟周期 ADC_RegularChannelConfig(ADC1, ADC1_CHANNEL, 1, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC2, ADC2_CHANNEL, 1, ADC_SampleTime_56Cycles); // ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);//只要发生数据转换就会发生DMA请求(单通道) //对于多通道不用使能 // ADC_DMACmd(ADC1, ENABLE);//允许直接存储器访问模式(对于单一 ADC 模式) ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);//只要发生数据转换就会发生DMA请求(多通道) ADC_Cmd(ADC1,ENABLE);//使能ADC ADC_Cmd(ADC2,ENABLE); //再次软件开启ADC转换是因为让ADC转换可以由其他的一些条件什么的开启ADC转化,这里我们用软件开启 ADC_SoftwareStartConv(ADC1);//开始转换规则通道(主ADC触发了,从ADC也会触发) }
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28void Delay(__IO uint32_t nCount) //简单的延时函数 { for(; nCount != 0; nCount--); } float Data[2];//最终的电压值 int main(void) { USART_Config(); ADC_Config(); printf("一切OKn"); while (1) { //数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量 Data[0] = (float) (Value[0] *3.3 /4096) ; Data[1] = (float) (Value[1] *3.3 /4096) ; printf("rnADC1转化的数据为:%f Vn",Data[0]); printf("ADC2转化的数据为:%f Vn",Data[1]); Delay(0xffffff); } }
ADC-三重模式-单通道-交替采集电压(DMA)
实验内容:使用ADC1、ADC2、ADC3将PC2引脚上电压值转化成数字量,然后我们在通过运算将其电压值打印在串口助手上。
我们使用DMA模式2。
bsp_adc.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31#ifndef _BSP__ADC_H #define _BSP__ADC_H #include "stm32f4xx.h" /* 悬空 用杜邦线连接GND或VCC(ADC 通道12 引脚 ——PC2) */ #define ADC_PIN GPIO_Pin_2 #define ADC_GPIO_PORT GPIOC #define ADC_GPIO_CLK RCC_AHB1Periph_GPIOC /* ADC1 */ #define ADC1_CLK RCC_APB2Periph_ADC1 #define ADC2_CLK RCC_APB2Periph_ADC2 #define ADC3_CLK RCC_APB2Periph_ADC3 #define ADC_CHANNEL ADC_Channel_12 #define ADC1_CDR_ADDR ((uint32_t )ADC1+0x300+0x08 ) /* DMA */ #define ADC_DMA_CLK RCC_AHB1Periph_DMA2 #define ADC_DMA_CHANNEL DMA_Channel_0 #define ADC_DMA_STREAM DMA2_Stream0 //多重模式下,ADC1还是主,所以只需要配置ADC1的DMA通道 extern uint32_t Value[3]; void ADC_Config(void); #endif
bsp_adc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95#include "bsp_adc.h" uint32_t Value[3]; static void ADC_DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; RCC_AHB1PeriphClockCmd(ADC_DMA_CLK,ENABLE); /* 配置DMA */ DMA_InitStructure.DMA_BufferSize = 3;//一次性传输3个数据 DMA_InitStructure.DMA_Channel = ADC_DMA_CHANNEL;//ADC1 DMA通道 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;//DMA搬运方向:外设到存储器 DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)Value;//存储器地址 DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;//存储器突发模式选择:单次模式 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;//存储器数据宽度:字32位 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable ;//使能存储器地址自动递增功能 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;//DMA 传输模式选择:循环模式 DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_CDR_ADDR;//外设地址 DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;//外设突发模式选择:单次模式 DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;//外设数据宽度:字32位 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//禁止外设地址自动递增功能 DMA_InitStructure.DMA_Priority = DMA_Priority_High;//软件设置数据流的优先级:高级 /* FIFO不用随便配置 */ DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable; DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull; DMA_Init(ADC_DMA_STREAM, &DMA_InitStructure); DMA_Cmd(ADC_DMA_STREAM, ENABLE);//使能DMA } void ADC_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; ADC_InitTypeDef ADC_InitStructure; ADC_CommonInitTypeDef ADC_CommonInitStructure; /* 开启时钟 */ RCC_AHB1PeriphClockCmd(ADC_GPIO_CLK,ENABLE); RCC_APB2PeriphClockCmd(ADC1_CLK | ADC2_CLK | ADC3_CLK, ENABLE); /* GPIO相关配置 */ GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN ;//GPIO 用于 AD 转换功能必须配置为模拟输入模式 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;//无上拉 无下拉 GPIO_InitStructure.GPIO_Speed = GPIO_High_Speed ;//高速 GPIO_InitStructure.GPIO_Pin = ADC_PIN; GPIO_Init (ADC_GPIO_PORT,&GPIO_InitStructure); ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC 连续转换模式选择 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//输出数据对齐方式 //ADC 外部触发选择(本实验用软件触发,随便配置) ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1; ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止外部边沿触发 ADC_InitStructure.ADC_NbrOfConversion = 1;//转换通道数目 ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//ADC 分辨率选择 ADC_InitStructure.ADC_ScanConvMode = DISABLE;// 禁止扫描模式,多通道采集才需要 ADC_Init(ADC1, &ADC_InitStructure);//通道相同只需要初始化ADC1就好 // ADC_Init(ADC2, &ADC_InitStructure); // ADC_Init(ADC3, &ADC_InitStructure); ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_2;//允许直接存储器访问模式(对于多个 ADC 模式) ADC_CommonInitStructure.ADC_Mode = ADC_TripleMode_Interl;// 三重模式交替采集 ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;//4分频 ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;// 采样时间间隔 ADC_CommonInit(&ADC_CommonInitStructure); ADC_DMA_Config(); //配置 ADC 通道转换顺序为1(第一个转换),采样时间为56个时钟周期 ADC_RegularChannelConfig(ADC1, ADC_CHANNEL, 1, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC2, ADC_CHANNEL, 1, ADC_SampleTime_56Cycles); ADC_RegularChannelConfig(ADC3, ADC_CHANNEL, 1, ADC_SampleTime_56Cycles); // ADC_DMARequestAfterLastTransferCmd(ADC1, ENABLE);//只要发生数据转换就会发生DMA请求(单通道) //对于多通道不用使能 // ADC_DMACmd(ADC1, ENABLE);//允许直接存储器访问模式(对于单一 ADC 模式) ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);//只要发生数据转换就会发生DMA请求(多通道) ADC_Cmd(ADC1,ENABLE);//使能ADC ADC_Cmd(ADC2,ENABLE); ADC_Cmd(ADC3,ENABLE); //再次软件开启ADC转换是因为让ADC转换可以由其他的一些条件什么的开启ADC转化,这里我们用软件开启 ADC_SoftwareStartConv(ADC1);//开始转换规则通道(主ADC触发了,从ADC也会触发) }
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30void Delay(__IO uint32_t nCount) //简单的延时函数 { for(; nCount != 0; nCount--); } float Data[3];//最终的电压值 int main(void) { USART_Config(); ADC_Config(); printf("一切OKn"); while (1) { //数字量乘单位数字量对应的模拟量就是我们真正的要读的模拟量 Data[0] = (float) ((uint16_t)Value[0] *3.3 /4096) ; Data[1] = (float) ((uint16_t)Value[1] *3.3 /4096) ; Data[2] = (float) ((uint16_t)Value[2] *3.3 /4096) ; printf("rnADC1转化的数据为:%f Vn",Data[0]); printf("ADC2转化的数据为:%f Vn",Data[2]); printf("ADC3转化的数据为:%f Vrn",Data[1]); Delay(0xffffff); } }
以上仅供自己与大家学习积累,欢迎各位大佬批评与指正!
最后
以上就是害羞招牌最近收集整理的关于基于STM32F407使用ADC采集电压实验ADC简介STM32F407 ADC通道对应的引脚STM32F407中的数据寄存器对于F407在ADC实验中使用的函数理解ADC-独立模式-单通道-采集电压(中断)ADC-独立模式-多通道-采集电压(DMA)ADC-双重模式-单通道-规则同步采集电压(DMA)ADC-三重模式-单通道-交替采集电压(DMA)的全部内容,更多相关基于STM32F407使用ADC采集电压实验ADC简介STM32F407内容请搜索靠谱客的其他文章。
发表评论 取消回复