裸机--ADC
- 简介
- STM32f103 系列有 3 个 ADC,精度为 12 位,每个 ADC 最多有 16 个外部通道。
- 其中ADC1 和 ADC2 都有 16 个外部通道,ADC3 根据 CPU 引脚的不同通道数也不同,一般都有8 个外部通道。
- 功能
- 电压输入范围:
- ADC 输入范围为:VREF- ≤ VIN ≤ VREF+。由 VREF-、VREF+ 、VDDA 、VSSA、这四个外部引脚决定.
- 一般把 VSSA 和 VREF-接地,把 VREF+和 VDDA 接 3V3,得到ADC 的输入电压范围为:0~3.3V。
- 电压范围变宽
- 外部电压转换为0-3.3V.
- 输入通道
- 外部通道(最多16道)
- ADCx_IN0~~ADCx_IN15
- 内部通道
- ADC1 的通道 16 连接到了芯片内部的温度传感器,Vrefint 连接到了通道 17。
- ADC2 的模拟通道 16 和 17 连接到了内部的 VSS。
- ADC3 的模拟通道 9、14、15、16 和 17 连接到了内部的 VSS。
![](file:///C:/Users/RC/AppData/Local/Temp/enhtmlclip/Image(25).png)
- 规则通道
- 注入通道
- 触发源
- ADC控制写0/1
- 定时器触发
- 外部IO触发
- 转换时间
- 时钟
- ADC 输入时钟 ADC_CLK 由 PCLK2 经过分频产生,最大是 14M,
- 采样时间
- 采样周期最小1.5个周期
- Tconv = 采样时间 +12.5 个周期。当 ADCLK = 14MHZ (最高),采样时间设置为 1.5 周期(最快),
- 那么总的转换时间(最短)Tconv = 1.5 周期 + 12.5 周期 = 14 周期 = 1us。
- 一般我们设置 PCLK2=72M,经过 ADC 预分频器能分频到最大的时钟只能是 12M,采样周期设置为 1.5 个周期,算出最短的转换时间为 1.17us,这个才是最常用的。
- 中断
- 转换结束中断
- 规则通道转换结束中断和注入转换通道转换结束中断
- 规则和注入通道转换结束后,除了产生中断外,还可以产生 DMA 请求,把转换好的数据直接存储在内存里面。要注意的是只有 ADC1 和 ADC3 可以产生 DMA 请求.
- 模拟看门狗中断
- 当被 ADC 转换的模拟电压低于低阈值或者高于高阈值时,就会产生中断,前提是我们开启了模拟看门狗中断,其中低阈值和高阈值由 ADC_LTR 和 ADC_HTR 设置。例如我们设置高阈值是 2.5V,那么模拟电压超过 2.5V 的时候,就会产生模拟看门狗中断,反之低阈值也一样。
- 电压转换
- ADC是 12 位的,那么 12 位满量程对应的就是 3.3V,12 位满量程对应的数字值是:2^12。数值0 对应的就是 0V。如果转换后的数值为 X ,X 对应的模拟电压为 Y,那么会有这么一个等式成立: 2^12 / 3.3 = X / Y,=> Y = (3.3 * X ) / 2^12。
- 流程--独立模式单通道
- 1) 初始 ADC 用到的 GPIO;
- 2) 设置 ADC 的工作参数并初始化;
- 3) 设置 ADC 工作时钟;
- 4) 设置 ADC 转换通道顺序及采样时间;
- 5) 配置使能 ADC 转换完成中断,在中断内读取转换完数据;
- 6) 使能 ADC;
- 7) 使能软件触发 ADC 转换。
- ADC 转换结果数据使用中断方式读取,这里没有使用 DMA 进行数据传输。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 独立模式单通道 */ /* ADC 宏定义 */ 1 // ADC 编号选择 2 // 可以是 ADC1/2,如果使用 ADC3,中断相关的宏要改成 ADC3 的 3 #define ADC_APBxClock_FUN RCC_APB2PeriphClockCmd 4 #define ADCx ADC2 5 #define ADC_CLK RCC_APB2Periph_ADC2 6 7 // ADC GPIO 宏定义 8 // 注意:用作 ADC 采集的 IO 必须没有复用,否则采集电压会有影响 9 #define ADC_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd 10 #define ADC_GPIO_CLK RCC_APB2Periph_GPIOC 11 #define ADC_PORT GPIOC 12 #define ADC_PIN GPIO_Pin_1 13 // ADC 通道宏定义 14 #define ADC_CHANNEL ADC_Channel_11 15 16 // ADC 中断相关宏定义 17 #define ADC_IRQ ADC1_2_IRQn 18 #define ADC_IRQHandler ADC1_2_IRQHandler /* ADC GPIO 初始化 */ 1 static void ADCx_GPIO_Config(void) 2 { 3 GPIO_InitTypeDef GPIO_InitStructure; 4 5 // 打开 ADC IO 端口时钟 6 ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE ); 7 8 // 配置 ADC IO 引脚模式 9 // 必须为模拟输入 10 GPIO_InitStructure.GPIO_Pin = ADC_PIN; 11 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 12 13 // 初始化 ADC IO 14 GPIO_Init(ADC_PORT, &GPIO_InitStructure); 15 } /* ADC 工作模式配置 */ 1 static void ADCx_Mode_Config(void) 2 { 3 ADC_InitTypeDef ADC_InitStructure; 4 5 // 打开 ADC 时钟 6 ADC_APBxClock_FUN ( ADC_CLK, ENABLE ); 7 8 // ADC 模式配置 9 // 只使用一个 ADC,属于独立模式 10 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 11 12 // 禁止扫描模式,多通道才要,单通道不需要 13 ADC_InitStructure.ADC_ScanConvMode = DISABLE ; 14 15 // 连续转换模式 16 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 17 18 // 不用外部触发转换,软件开启即可 19 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 20 21 // 转换结果右对齐 22 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 23 24 // 转换通道 1 个 25 ADC_InitStructure.ADC_NbrOfChannel = 1; 26 27 // 初始化 ADC 28 ADC_Init(ADCx, &ADC_InitStructure); 29 30 // 配置 ADC 时钟为 PCLK2 的 8 分频,即 9MHz 31 RCC_ADCCLKConfig(RCC_PCLK2_Div8); 32 33 // 配置 ADC 通道转换顺序和采样时间 34 ADC_RegularChannelConfig(ADCx, ADC_CHANNEL, 1, 35 ADC_SampleTime_55Cycles5); 36 37 // ADC 转换结束产生中断,在中断服务程序中读取转换值 38 ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE); 39 40 // 开启 ADC ,并开始转换 41 ADC_Cmd(ADCx, ENABLE); 42 43 // 初始化 ADC 校准寄存器 44 ADC_ResetCalibration(ADCx); 45 // 等待校准寄存器初始化完成 46 while (ADC_GetResetCalibrationStatus(ADCx)); 47 48 // ADC 开始校准 49 ADC_StartCalibration(ADCx); 50 // 等待校准完成 51 while (ADC_GetCalibrationStatus(ADCx)); 52 53 // 由于没有采用外部触发,所以使用软件触发 ADC 转换 54 ADC_SoftwareStartConvCmd(ADCx, ENABLE); 55 } /* ADC中断配置 */ 1 static void ADC_NVIC_Config(void) 2 { 3 NVIC_InitTypeDef NVIC_InitStructure; 4 5 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); 6 7 NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ; 8 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; 9 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; 10 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; 11 12 NVIC_Init(&NVIC_InitStructure); 13 } /* ADC中断服务函数 */ 1 void ADC_IRQHandler(void) 2 { 3 if (ADC_GetITStatus(ADCx,ADC_IT_EOC)==SET) { 4 // 读取 ADC 的转换值 5 ADC_ConvertedValue = ADC_GetConversionValue(ADCx); 6 7 } 8 ADC_ClearITPendingBit(ADCx,ADC_IT_EOC); 9 10 } /* 主函数 */ 1 int main(void) 2 { 3 // 配置串口 4 USART_Config(); 5 6 // ADC 初始化 7 ADCx_Init(); 8 9 printf("\r\n ----这是一个 ADC 单通道中断读取实验----\r\n"); 10 11 while (1) 12 { 13 ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*3.3; 14 15 printf("\r\n The current AD value = 0x%04X \r\n", 16 ADC_ConvertedValue); 17 printf("\r\n The current AD value = %f V \r\n", 18 ADC_ConvertedValueLocal); 19 printf("\r\n\r\n"); 20 21 Delay(0xffffee); 22 } 23 }
- 流程2--独立模式多通道
- 1) 初始化 ADC GPIO;
- 2) 初始化 ADC 工作参数;
- 3) 配置 DMA 工作参数;
- 4) 读取 ADC 采集的数据;
- ADC 转换结果数据使用 DMA 方式传输至指定的存储区,这样取代单通道实验使用中断服务的读取方法。实际上,多通道 ADC 采集一般使用 DMA 数据传输方式更加高效方便。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 独立模式多通道采集 */ /* 宏定义 */ 1 // ADC 宏定义 2 #define ADCx ADC1 3 #define ADC_APBxClock_FUN RCC_APB2PeriphClockCmd 4 #define ADC_CLK RCC_APB2Periph_ADC1 5 6 #define ADC_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd 7 #define ADC_GPIO_CLK RCC_APB2Periph_GPIOC 8 #define ADC_PORT GPIOC 9 10 // 转换通道个数 11 #define NOFCHANEL 5 12 13 #define ADC_PIN1 GPIO_Pin_0 14 #define ADC_CHANNEL1 ADC_Channel_10 15 16 #define ADC_PIN2 GPIO_Pin_1 17 #define ADC_CHANNEL2 ADC_Channel_11 18 19 #define ADC_PIN3 GPIO_Pin_3 20 #define ADC_CHANNEL3 ADC_Channel_13 21 22 #define ADC_PIN4 GPIO_Pin_4 23 #define ADC_CHANNEL4 ADC_Channel_14 24 25 #define ADC_PIN5 GPIO_Pin_5 26 #define ADC_CHANNEL5 ADC_Channel_15 27 28 // ADC1 对应 DMA1 通道 1,ADC3 对应 DMA2 通道 5,ADC2 没有 DMA 功能 29 #define ADC_DMA_CHANNEL DMA1_Channel1 /* ADC GPIO 初始化 */ 1 static void ADCx_GPIO_Config(void) 2 { 3 GPIO_InitTypeDef GPIO_InitStructure; 4 5 // 打开 ADC IO 端口时钟 6 ADC_GPIO_APBxClock_FUN ( ADC_GPIO_CLK, ENABLE ); 7 8 /* 配置 ADC IO 引脚模式 GPIO用于adc必须模拟输入模式 */ 9 GPIO_InitStructure.GPIO_Pin = ADC_PIN1 10 |ADC_PIN2 11 |ADC_PIN3 12 |ADC_PIN4 13 |ADC_PIN5; 14 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 15 // 初始化 ADC IO 16 GPIO_Init(ADC_PORT, &GPIO_InitStructure); 17 } /* ADC 工作模式配置 */ 1 static void ADCx_Mode_Config(void) 2 { 3 DMA_InitTypeDef DMA_InitStructure; 4 ADC_InitTypeDef ADC_InitStructure; 5 6 // 打开 DMA 时钟 7 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 8 // 打开 ADC 时钟 9 ADC_APBxClock_FUN ( ADC_CLK, ENABLE ); 10 11 /* ------------------DMA 模式配置---------------- */ 12 // 复位 DMA 控制器 13 DMA_DeInit(ADC_DMA_CHANNEL); 14 // 配置 DMA 初始化结构体 15 // 外设基址为:ADC 数据寄存器地址 16 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&( ADCx->DR )); 17 // 存储器地址 18 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue; 19 // 数据源来自外设 20 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 21 // 缓冲区大小,应该等于数据目的地的大小 22 DMA_InitStructure.DMA_BufferSize = NOFCHANEL; 23 // 外设寄存器只有一个,地址不用递增 24 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 25 // 存储器地址递增 26 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 27 // 外设数据大小为半字,即两个字节 28 DMA_InitStructure.DMA_PeripheralDataSize = 29 DMA_PeripheralDataSize_HalfWord; 30 // 内存数据大小也为半字,跟外设数据大小相同 31 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; 32 // 循环传输模式 33 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 34 // DMA 传输通道优先级为高,当使用一个 DMA 通道时,优先级设置不影响 35 DMA_InitStructure.DMA_Priority = DMA_Priority_High; 36 // 禁止存储器到存储器模式,因为是从外设到存储器 37 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 38 // 初始化 DMA 39 DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure); 40 // 使能 DMA 通道 41 DMA_Cmd(ADC_DMA_CHANNEL , ENABLE); 42 43 /* ----------------ADC 模式配置--------------------- */ 44 // 只使用一个 ADC,属于单模式 45 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 46 // 扫描模式 多通道所以扫描 47 ADC_InitStructure.ADC_ScanConvMode = ENABLE ; 48 // 连续转换模式 49 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 50 // 不用外部触发转换,软件开启即可 51 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 52 // 转换结果右对齐 53 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 54 // 转换通道个数 55 ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL; 56 // 初始化 ADC 57 ADC_Init(ADCx, &ADC_InitStructure); 58 // 配置 ADC 时钟为 PCLK2 的 8 分频,即 9MHz 59 RCC_ADCCLKConfig(RCC_PCLK2_Div8); 60 // 配置 ADC 通道的转换顺序和采样时间 61 ADC_RegularChannelConfig(ADCx, ADC_CHANNEL1, 1, 62 ADC_SampleTime_55Cycles5); 63 ADC_RegularChannelConfig(ADCx, ADC_CHANNEL2, 2, 64 ADC_SampleTime_55Cycles5); 65 ADC_RegularChannelConfig(ADCx, ADC_CHANNEL3, 3, 66 ADC_SampleTime_55Cycles5); 67 ADC_RegularChannelConfig(ADCx, ADC_CHANNEL4, 4, 68 ADC_SampleTime_55Cycles5); 69 ADC_RegularChannelConfig(ADCx, ADC_CHANNEL5, 5, 70 ADC_SampleTime_55Cycles5); 71 // 使能 ADC DMA 请求 72 ADC_DMACmd(ADCx, ENABLE); 73 // 开启 ADC ,并开始转换 74 ADC_Cmd(ADCx, ENABLE); 75 // 初始化 ADC 校准寄存器 76 ADC_ResetCalibration(ADCx); 77 // 等待校准寄存器初始化完成 78 while (ADC_GetResetCalibrationStatus(ADCx)); 79 // ADC 开始校准 80 ADC_StartCalibration(ADCx); 81 // 等待校准完成 82 while (ADC_GetCalibrationStatus(ADCx)); 83 // 由于没有采用外部触发,所以使用软件触发 ADC 转换 84 ADC_SoftwareStartConvCmd(ADCx, ENABLE); 85 } /* 主函数 */ 1 int main(void) 2 { 3 // 配置串口 4 USART_Config(); 5 6 // ADC 初始化 7 ADCx_Init(); 8 9 printf("\r\n ----这是一个 ADC 多通道采集 DMA 读取实验----\r\n"); 10 11 while (1) 12 { 13 14 ADC_ConvertedValueLocal[0] =(float) 15 ADC_ConvertedValue[0]/4096*3.3; 16 ADC_ConvertedValueLocal[1] =(float) 17 ADC_ConvertedValue[1]/4096*3.3; 18 ADC_ConvertedValueLocal[2] =(float) 19 ADC_ConvertedValue[2]/4096*3.3; 20 ADC_ConvertedValueLocal[3] =(float) 21 ADC_ConvertedValue[3]/4096*3.3; 22 ADC_ConvertedValueLocal[4] =(float) 23 ADC_ConvertedValue[4]/4096*3.3; 24 25 printf("\r\n CH1 value = %f V \r\n",ADC_ConvertedValueLocal[0]); 26 printf("\r\n CH2 value = %f V \r\n",ADC_ConvertedValueLocal[1]); 27 printf("\r\n CH3 value = %f V \r\n",ADC_ConvertedValueLocal[2]); 28 printf("\r\n CH2 value = %f V \r\n",ADC_ConvertedValueLocal[3]); 29 printf("\r\n CH3 value = %f V \r\n",ADC_ConvertedValueLocal[4]); 30 31 printf("\r\n\r\n"); 32 Delay(0xffffee); 33 34 } 35 } 36
- 双重ADC同步规则模式采集
- 双重ADC作用:提高采样率,弥补单个ADC采样不够快的缺点
- 双重ADC模式
- 同步注入模式
- ADC1 和 ADC2 同时转换一个注入通道组,其中 ADC1 为主,ADC2 为从。转换的数据存储在每个 ADC 接口的 ADC_JDRx 寄存器中。
- 同步规则模式
- ADC1 和 ADC2 同时转换一个规则通道组,其中 ADC1 为主,ADC2 为从。ADC1 转换的结果放在 ADC1_DR 的低 16 位,ADC2 转换的结果放在 ADC1_DR 的高十六位。必须开启DMA.
- 流程
- 1) 初始化 ADC GPIO;
- 2) 初始化 DMA 配置;
- 3) 初始化 ADC 参数;
- 4) 读取 ADC 采集的数据,并打印出来校正;
- 注意
- ADC 工作模式要设置为同步规则模式;两个 ADC 的通道的采样时间需要一致;ADC1设置为软件触发;ADC2 设置为外部触发。其他的基本一样,看代码注释理解即可。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/* 宏定义 */ 1 // 双模式时,ADC1 和 ADC2 转换的数据都存放在 ADC1 的数据寄存器, 2 // ADC1 的在低十六位,ADC2 的在高十六位 3 // 双 ADC 模式的第一个 ADC,必须是 ADC1 4 #define ADCx_1 ADC1 5 #define ADCx_1_APBxClock_FUN RCC_APB2PeriphClockCmd 6 #define ADCx_1_CLK RCC_APB2Periph_ADC1 7 8 #define ADCx_1_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd 9 #define ADCx_1_GPIO_CLK RCC_APB2Periph_GPIOC 10 #define ADCx_1_PORT GPIOC 11 #define ADCx_1_PIN GPIO_Pin_1 12 #define ADCx_1_CHANNEL ADC_Channel_11 13 14 // 双 ADC 模式的第二个 ADC,必须是 ADC2 15 #define ADCx_2 ADC2 16 #define ADCx_2_APBxClock_FUN RCC_APB2PeriphClockCmd 17 #define ADCx_2_CLK RCC_APB2Periph_ADC2 18 19 #define ADCx_2_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd 20 #define ADCx_2_GPIO_CLK RCC_APB2Periph_GPIOC 21 #define ADCx_2_PORT GPIOC 22 #define ADCx_2_PIN GPIO_Pin_4 23 #define ADCx_2_CHANNEL ADC_Channel_14 24 25 #define NOFCHANEL 1 26 27 // ADC1 对应 DMA1 通道 1,ADC3 对应 DMA2 通道 5,ADC2 没有 DMA 功能 28 #define ADC_DMA_CHANNEL DMA1_Channel1 /* ADC GPIO 初始化 */ 1 static void ADCx_GPIO_Config(void) 2 { 3 GPIO_InitTypeDef GPIO_InitStructure; 4 5 // ADCx_1 GPIO 初始化 6 ADCx_1_GPIO_APBxClock_FUN ( ADCx_1_GPIO_CLK, ENABLE ); 7 GPIO_InitStructure.GPIO_Pin = ADCx_1_PIN; 8 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 9 GPIO_Init(ADCx_1_PORT, &GPIO_InitStructure); 10 11 // ADCx_2 GPIO 初始化 12 ADCx_1_GPIO_APBxClock_FUN ( ADCx_2_GPIO_CLK, ENABLE ); 13 GPIO_InitStructure.GPIO_Pin = ADCx_2_PIN; 14 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 15 GPIO_Init(ADCx_2_PORT, &GPIO_InitStructure); 16 } /* 规则同步模式配置 */ 1 static void ADCx_Mode_Config(void) 2 { 3 DMA_InitTypeDef DMA_InitStructure; 4 ADC_InitTypeDef ADC_InitStructure; 5 6 // 打开 DMA 时钟 7 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); 8 // 打开 ADC 时钟 9 ADCx_1_APBxClock_FUN ( ADCx_1_CLK, ENABLE ); 10 ADCx_2_APBxClock_FUN ( ADCx_2_CLK, ENABLE ); 11 12 /* ------------------DMA 模式配置---------------- */ 13 // 复位 DMA 控制器 14 DMA_DeInit(ADC_DMA_CHANNEL); 15 // 配置 DMA 初始化结构体 16 // 外设基址为:ADC 数据寄存器地址 17 DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&( ADCx_1->DR )); 18 // 存储器地址 19 DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_ConvertedValue; 20 // 数据源来自外设 21 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 22 // 缓冲区大小,应该等于数据目的地的大小 23 DMA_InitStructure.DMA_BufferSize = NOFCHANEL; 24 // 外设寄存器只有一个,地址不用递增 25 DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 26 // 存储器地址递增 27 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 28 // 外设数据大小 29 DMA_InitStructure.DMA_PeripheralDataSize = 30 DMA_PeripheralDataSize_Word; 31 // 内存数据大小,跟外设数据大小相同 32 DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; 33 // 循环传输模式 34 DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 35 // DMA 传输通道优先级为高,当使用一个 DMA 通道时,优先级设置不影响 36 DMA_InitStructure.DMA_Priority = DMA_Priority_High; 37 // 禁止存储器到存储器模式,因为是从外设到存储器 38 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; 39 // 初始化 DMA 40 DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure); 41 // 使能 DMA 通道 42 DMA_Cmd(ADC_DMA_CHANNEL , ENABLE); 43 44 /* ----------------ADCx_1 模式配置--------------------- */ 45 // 双 ADC 的规则同步 46 ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; 47 // 扫描模式 48 ADC_InitStructure.ADC_ScanConvMode = ENABLE ; 49 // 连续转换模式 50 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 51 // 不用外部触发转换,软件开启即可 52 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; 53 // 转换结果右对齐 54 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 55 // 转换通道个数 56 ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL; 57 // 初始化 ADC 58 ADC_Init(ADCx_1, &ADC_InitStructure); 59 // 配置 ADC 时钟为 PCLK2 的 8 分频,即 9MHz 60 RCC_ADCCLKConfig(RCC_PCLK2_Div8); 61 // 配置 ADC 通道的转换顺序和采样时间 62 ADC_RegularChannelConfig(ADCx_1, ADCx_1_CHANNEL, 1, 63 ADC_SampleTime_239Cycles5); 64 // 使能 ADC DMA 请求 65 ADC_DMACmd(ADCx_1, ENABLE); 66 67 68 /* ----------------ADCx_2 模式配置--------------------- */ 69 // 双 ADC 的规则同步 70 ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult; 71 // 扫描模式 72 ADC_InitStructure.ADC_ScanConvMode = ENABLE ; 73 // 连续转换模式 74 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; 75 // 不用外部触发转换,软件开启即可 76 ADC_InitStructure.ADC_ExternalTrigConv = 77 ADC_ExternalTrigConv_None; 78 // 转换结果右对齐 79 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 80 // 转换通道个数 81 ADC_InitStructure.ADC_NbrOfChannel = NOFCHANEL; 82 // 初始化 ADC 83 ADC_Init(ADCx_2, &ADC_InitStructure); 84 // 配置 ADC 时钟为 PCLK2 的 8 分频,即 9MHz 85 RCC_ADCCLKConfig(RCC_PCLK2_Div8); 86 // 配置 ADC 通道的转换顺序和采样时间 87 ADC_RegularChannelConfig(ADCx_2, ADCx_2_CHANNEL, 1, 88 ADC_SampleTime_239Cycles5); 89 /* 使能 ADCx_2 的外部触发转换 */ 90 ADC_ExternalTrigConvCmd(ADC2, ENABLE); 91 92 /* ----------------ADCx_1 校准--------------------- */ 93 // 开启 ADC ,并开始转换 94 ADC_Cmd(ADCx_1, ENABLE); 95 // 初始化 ADC 校准寄存器 96 ADC_ResetCalibration(ADCx_1); 97 // 等待校准寄存器初始化完成 98 while (ADC_GetResetCalibrationStatus(ADCx_1)); 99 // ADC 开始校准 100 ADC_StartCalibration(ADCx_1); 101 // 等待校准完成 102 while (ADC_GetCalibrationStatus(ADCx_1)); 103 104 /* ----------------ADCx_2 校准--------------------- */ 105 // 开启 ADC ,并开始转换 106 ADC_Cmd(ADCx_2, ENABLE); 107 // 初始化 ADC 校准寄存器 108 ADC_ResetCalibration(ADCx_2); 109 // 等待校准寄存器初始化完成 110 while (ADC_GetResetCalibrationStatus(ADCx_2)); 111 // ADC 开始校准 112 ADC_StartCalibration(ADCx_2); 113 // 等待校准完成 114 while (ADC_GetCalibrationStatus(ADCx_2)); 115 116 // 由于没有采用外部触发,所以使用软件触发 ADC 转换 117 ADC_SoftwareStartConvCmd(ADCx_1, ENABLE); 118 } /* 主函数 */ 1 int main(void) 2 { 3 uint16_t temp=0 ,temp1=0; 4 // 配置串口 5 USART_Config(); 6 7 // ADC 初始化 8 ADCx_Init(); 9 10 printf("\r\n ----这是一个双 ADC 规则同步采集实验----\r\n"); 11 printf("欢迎使用野火 STM32 开发板\n"); 12 while (1) 13 { 14 // 取出 ADC1 数据寄存器的高 16 位,这个是 ADC2 的转换数据 15 temp0 = (ADC_ConvertedValue[0]&0XFFFF0000) >> 16; 16 // 取出 ADC1 数据寄存器的低 16 位,这个是 ADC1 的转换数据 17 temp1 = (ADC_ConvertedValue[0]&0XFFFF); 18 19 ADC_ConvertedValueLocal[0] =(float) temp0/4096*3.3; 20 ADC_ConvertedValueLocal[1] =(float) temp1/4096*3.3; 21 22 printf("\r\n ADCx_1 value = %f V \r\n", 23 ADC_ConvertedValueLocal[1]); 24 printf("\r\n ADCx_2 value = %f V \r\n", 25 ADC_ConvertedValueLocal[0]); 26 27 printf("\r\n\r\n"); 28 Delay(0xffffee); 29 30 } 31 }