• STM32--ADC


    一、简介

    *ADC(Analog-Digital Converter)模拟-数字转换器

    *ADC可以将引脚上连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁

    *12位逐次逼近型ADC,1us转换时间

    *输入电压范围:0~3.3V,转换结果范围:0~4095(12位转换分辨率)

    *18个输入通道,可测量16个外部和2个内部信号源(在任意多个通道上以任意顺序进行的一系列转换构成成组转换(规则通道)。例如,可以如下顺序完成转换:通道3、通道8、通道2、通道0、通道2、通道2、通道15

    *规则组和注入组两个转换单元(规则通道:我们平时用的一般通道,按顺序进行转换),(注入通道:可以理解为插入。它是一种在规则通道转换的时候强行插入要转换的一种。注入通道只有在规则通道存在的时候才会出现

    *模拟看门狗自动监测输入电压范围

    *转换时间:最短的转化时间--Tconv = 采样时间 + 12.5个周期

                        PCLK2 = 72M,ADC_CLK = 72/6 = 12M

                        Tconv = 1.5+12.4 = 14周期 = 14/12us = 1.17us

    *AD转换的步骤:采样,保持,量化,编码

    *STM32F103C8T6 ADC资源:ADC1、ADC2,10个外部输入通道(F4有三个ADC)

    1、电压输入范围

    *输入电压: VREF- <= VIN  <=  VREF+

    *决定输入电压的引脚:VREF-,VREF+,VDDA,VSSA

    *VSSA和VREF- 接地,VREF+ 和VDDA 接3.3V

    *得到ADC的电压输入范围为: 0-3.3V

    电压怎么测?

    电压输入范围:ADC可以测量-10V ~  +10V

      根据基尔霍夫定理:(Vin - Vout)/R2 + (3v3-Vout)/R1=Vout/R3

                                        Vout=(Vint + 10)/6

    二、ADC的基本结构

    ps:STM32f103c8t6有ADC1和ADC2,有两个转换单元(规则组、注入组),规则组有16个通道,注入组有4个通道。

    规则通道有数据覆盖的问题(用DMA来解决 只能用于ADC1,只有一个数据寄存器),注入通道没有数据覆盖的问题(四个通道有四个存放寄存器)

    三、转换模式

    1、单次转换,非扫描模式

    *单次转换模式下, ADC 只执行一次转换(如果需要再进行转换需要软件来执行)
    *如果一个规则通道被转换:转换数据被储存在 16 ADC_DR寄存器中,EOC( 转换结束 )标志被设置为1,如果设置了 EOCIE ,则产生中断。
    *非扫描模式,只能用于只有一个转换通道,有多个转换通道时要设置扫描模式

    2、连续转换,非扫描模式

     
    *在连续转换模式中,当前面 ADC 转换一结束马上就启动另一次转换。此模式可通过外部触发启
    动或通过设置 ADC_CR2 寄存器上的 ADON 位启动,此时 CONT 位是 1
    *如果一个规则通道被转换:转换数据被储存在 16 ADC_DR寄存器中,EOC( 转换结束 )标志被设置为1,如果设置了 EOCIE ,则产生中断。
    *非扫描模式,只能用于只有一个转换通道,有多个转换通道时要设置扫描模式

    3、单次转换,扫描模式

    *ADC规则通道的转换次序是由由序列1到序列16依次转换(有通道就转换没通道就跳过),如果转换次序需要较高优先级,那就要把该通道放在靠前序列
    *连续转换模式是当前面ADC转换一结束马上就启动另一次转换。此模式可通过外部触发启动或通过设置ADC_CR2寄存器上的ADON位启动,此时CONT位是1。
    *扫描模式只用于一个规则组中有多个通道需要转换的情况

    4、连续转换,扫描模式

    *在连续转换模式中,当前面 ADC 转换一结束马上就启动另一次转换。此模式可通过外部触发启
    动或通过设置 ADC_CR2 寄存器上的 ADON 位启动,此时 CONT 位是 1
    *如果一个规则通道被转换:转换数据被储存在 16 ADC_DR寄存器中,EOC( 转换结束 )标志被设置为1,如果设置了 EOCIE ,则产生中断。
    *扫描模式只用于一个规则组中有多个通道需要转换的情况
    PS:转换序列里可以可以出现多个相同的转换通道

    四、转换顺序

    通过设置寄存器里面不同的值,来配置不同通道的转换顺序以及转换的总通道数量

    规则通道:

    注入通道:

    五、代码

    1、ADC单通道DMA读取

    1. #include "adc.h"
    2. uint16_t ADC_conversionValue;//单ADC模式时,数据寄存器只用到低16位(用来存放 ADC发过来的数据)
    3. static void ACDx_GPIO_Config(void)
    4. {
    5. GPIO_InitTypeDef ADC_GPIO_StructInit;
    6. ADCx_PIN_RCC_Clock_Cmd(ADCx_PIN_Periph,ENABLE);
    7. ADC_GPIO_StructInit.GPIO_Mode = GPIO_Mode_AIN; //必须是模拟输入
    8. ADC_GPIO_StructInit.GPIO_Pin = ADCx_PIN;
    9. GPIO_Init(ADCx_PIN_PORT, &ADC_GPIO_StructInit);
    10. }
    11. static void Config_ADC_Init(void)
    12. {
    13. ADC_InitTypeDef ADC_StructInit;
    14. DMA_InitTypeDef DMA_StructInit;
    15. /*--------------------------DMA-----------------------------------------*/
    16. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //打开时钟
    17. DMA_DeInit(DMA1_Channel1); //将DMA寄存器复位成刚上电的样子
    18. DMA_StructInit.DMA_MemoryBaseAddr = (uint32_t)&ADC_conversionValue; //存储器地址
    19. DMA_StructInit.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_x->DR)); //外设地址
    20. DMA_StructInit.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向
    21. DMA_StructInit.DMA_BufferSize = 1; //传输数目
    22. DMA_StructInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度,数据寄存器只用到低16
    23. DMA_StructInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据宽度,数据寄存器只用到低16
    24. DMA_StructInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址是否递增
    25. DMA_StructInit.DMA_MemoryInc = DMA_MemoryInc_Disable; //存储器地址是否递增
    26. DMA_StructInit.DMA_Mode = DMA_Mode_Circular; //模式选择(现在时循环模式)
    27. DMA_StructInit.DMA_Priority = DMA_Priority_High; //通道优先级
    28. DMA_StructInit.DMA_M2M = DMA_M2M_Disable; //存储器到存储器模式
    29. DMA_Init( DMA1_Channel1, &DMA_StructInit);
    30. DMA_Cmd(DMA1_Channel1, ENABLE);
    31. /*---------------------ADC------------------------------------*/
    32. ADCx_RCC_Clock_Cmd(ADCx_Periph, ENABLE);
    33. ADC_StructInit.ADC_Mode = ADC_Mode_Independent; //设置独立模式(因为只有一个ADC通道)
    34. ADC_StructInit.ADC_ScanConvMode = DISABLE; //配置是否扫描(用在多通道)
    35. ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
    36. ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
    37. ADC_StructInit.ADC_NbrOfChannel = 1; //配置要转换通道的数目
    38. ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者GPIO才会使用)
    39. ADC_Init(ADC_x, &ADC_StructInit);
    40. RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
    41. ADC_RegularChannelConfig(ADC_x, ADCx_Channel, 1, ADC_SampleTime_55Cycles5); //规则通道的配置,第三个参数是配置第几次转换,第四个参数是配置采样周期
    42. ADC_Cmd(ADC_x, ENABLE); //使能ADC中断
    43. ADC_StartCalibration(ADC_x); //开始校准ADC
    44. while(ADC_GetCalibrationStatus(ADC_x)); //等待校准完成
    45. ADC_SoftwareStartConvCmd(ADC_x, ENABLE); //软件触发使能(开始工作)
    46. //使能DMA ADC
    47. ADC_DMACmd(ADC_x, ENABLE);
    48. }
    49. void ADCx_Init(void)
    50. {
    51. ACDx_GPIO_Config();
    52. Config_ADC_Init();
    53. }
    54. extern uint16_t ADC_conversionValue;
    55. int main()
    56. {
    57. float conversionValue = 0;
    58. initSysTick();
    59. usart_init();
    60. ADCx_Init();
    61. while(1)
    62. {
    63. conversionValue = (float)ADC_conversionValue/4096*3.3;
    64. printf("hex %04x\r\n",ADC_conversionValue);
    65. printf("conversionValue %f\r\n",conversionValue);
    66. ms_delay(2000);
    67. }
    68. }

    2、ADC单通道中断读取

    1. #ifndef ADC_H
    2. #define ADC_H
    3. #include "stm32f10x.h"
    4. static void ACDx_GPIO_Config(void);
    5. static void Config_ADC_Init(void);
    6. static void ADCx_NVIC_Config(void);
    7. void ADCx_Init(void);
    8. //ADC引脚配置的宏
    9. #define ADCx_PIN GPIO_Pin_1
    10. #define ADCx_PIN_PORT GPIOA
    11. #define ADCx_PIN_Periph RCC_APB2Periph_GPIOA
    12. #define ADCx_PIN_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
    13. //ADC配置的宏
    14. #define ADCx_Periph RCC_APB2Periph_ADC2
    15. #define ADCx_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
    16. #define ADC_x ADC2
    17. #define ADCx_Channel ADC_Channel_1
    18. #define ADCx_IRQHandler ADC1_2_IRQHandler
    19. #endif
    20. #include "adc.h"
    21. static void ACDx_GPIO_Config(void)
    22. {
    23. GPIO_InitTypeDef ADC_GPIO_StructInit;
    24. ADCx_PIN_RCC_Clock_Cmd(ADCx_PIN_Periph,ENABLE);
    25. ADC_GPIO_StructInit.GPIO_Mode = GPIO_Mode_AIN; //必须是模拟输入
    26. ADC_GPIO_StructInit.GPIO_Pin = ADCx_PIN;
    27. GPIO_Init(ADCx_PIN_PORT, &ADC_GPIO_StructInit);
    28. }
    29. static void Config_ADC_Init(void)
    30. {
    31. ADC_InitTypeDef ADC_StructInit;
    32. ADCx_RCC_Clock_Cmd(ADCx_Periph, ENABLE);
    33. ADC_StructInit.ADC_Mode = ADC_Mode_Independent; //设置独立模式(因为只有一个ADC通道)
    34. ADC_StructInit.ADC_ScanConvMode = DISABLE; //配置是否扫描(用在多通道)
    35. ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
    36. ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
    37. ADC_StructInit.ADC_NbrOfChannel = 1; //配置要转换通道的数目
    38. ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者输入引脚触发才会使用)
    39. ADC_Init(ADC_x, &ADC_StructInit);
    40. RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
    41. ADC_RegularChannelConfig(ADC_x, ADCx_Channel, 1, ADC_SampleTime_55Cycles5); //规则通道的配置,第三个参数是配置第几个转换换通道,第四个参数是配置采样周期,第二个参数是第几个通道(例:A0是通道1
    42. ADC_ITConfig(ADC_x, ADC_IT_EOC, ENABLE); //配置成规则通道中断
    43. ADC_Cmd(ADC_x, ENABLE); //使能ADC中断
    44. ADC_StartCalibration(ADC_x); //开始校准ADC
    45. while(ADC_GetCalibrationStatus(ADC_x)); //等待校准完成
    46. ADC_SoftwareStartConvCmd(ADC_x, ENABLE); //软件触发使能(开始工作)
    47. }
    48. static void ADCx_NVIC_Config(void)
    49. {
    50. NVIC_InitTypeDef ADCx_NVIC_StructInit;
    51. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    52. ADCx_NVIC_StructInit.NVIC_IRQChannel = ADC1_2_IRQn;
    53. ADCx_NVIC_StructInit.NVIC_IRQChannelCmd = ENABLE;
    54. ADCx_NVIC_StructInit.NVIC_IRQChannelPreemptionPriority = 1;
    55. ADCx_NVIC_StructInit.NVIC_IRQChannelSubPriority = 1;
    56. NVIC_Init(&ADCx_NVIC_StructInit);
    57. }
    58. void ADCx_Init(void)
    59. {
    60. ACDx_GPIO_Config();
    61. Config_ADC_Init();
    62. ADCx_NVIC_Config();
    63. }
    64. extern uint32_t ADC_Conversion_value;
    65. int main()
    66. {
    67. float ADC_Value = 0;
    68. initSysTick();
    69. usart_init();
    70. ADCx_Init();
    71. while(1)
    72. {
    73. ADC_Value = (float)ADC_Conversion_value/4096*3.3;
    74. printf("adc_float=%fv\r\n",ADC_Value);
    75. printf("adc_Hex=%04x\r\n",ADC_Conversion_value);
    76. ms_delay(2000);
    77. }
    78. }
    79. void ADCx_IRQHandler(void)
    80. {
    81. if(ADC_GetITStatus(ADC_x, ADC_IT_EOC) == SET)
    82. {
    83. ADC_Conversion_value = ADC_GetConversionValue(ADC_x);//读取转换的数值
    84. }
    85. ADC_ClearITPendingBit(ADC_x, ADC_IT_EOC);
    86. }

    3、ADC多通道DMA读取

    1. #ifndef ADC_H
    2. #define ADC_H
    3. #include "stm32f10x.h"
    4. static void ACDx_GPIO_Config(void);
    5. static void Config_ADC_Init(void);
    6. void ADCx_Init(void);
    7. //ADC引脚配置的宏
    8. #define ADCx_PIN GPIO_Pin_1
    9. #define ADCx_PIN_PORT GPIOA
    10. #define ADCx_PIN_Periph RCC_APB2Periph_GPIOA
    11. #define ADCx_PIN_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
    12. //ADC配置的宏
    13. #define ADCx_Periph RCC_APB2Periph_ADC1
    14. #define ADCx_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
    15. #define ADC_x ADC1
    16. #define ADCx_Channel ADC_Channel_1
    17. #define len 3
    18. #endif
    19. #include "adc.h"
    20. uint16_t ADC_conversionValue[len];//单ADC模式时,数据寄存器只用到低16位(用来存放 ADC发过来的数据)
    21. static void ACDx_GPIO_Config(void)
    22. {
    23. GPIO_InitTypeDef ADC_GPIO_StructInit;
    24. ADCx_PIN_RCC_Clock_Cmd(ADCx_PIN_Periph,ENABLE);
    25. ADC_GPIO_StructInit.GPIO_Mode = GPIO_Mode_AIN; //必须是模拟输入
    26. ADC_GPIO_StructInit.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;
    27. GPIO_Init(ADCx_PIN_PORT, &ADC_GPIO_StructInit);
    28. }
    29. static void Config_ADC_Init(void)
    30. {
    31. ADC_InitTypeDef ADC_StructInit;
    32. DMA_InitTypeDef DMA_StructInit;
    33. /*--------------------------DMA-----------------------------------------*/
    34. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //打开时钟
    35. DMA_DeInit(DMA1_Channel1); //将DMA寄存器复位成刚上电的样子
    36. DMA_StructInit.DMA_MemoryBaseAddr = (uint32_t)ADC_conversionValue; //存储器地址
    37. DMA_StructInit.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_x->DR)); //外设地址
    38. DMA_StructInit.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向
    39. DMA_StructInit.DMA_BufferSize = len; //传输数目(缓冲区大小,应该等于数据目的地的大小)
    40. // 外设数据大小为半字,即两个字节
    41. DMA_StructInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;//外设数据宽度,数据寄存器只用到低16
    42. // 内存数据大小也为半字,跟外设数据大小相同
    43. DMA_StructInit.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //存储器数据宽度,数据寄存器只用到低16
    44. DMA_StructInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址是否递增
    45. DMA_StructInit.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址是否递增
    46. DMA_StructInit.DMA_Mode = DMA_Mode_Circular; //模式选择(现在时循环模式)
    47. DMA_StructInit.DMA_Priority = DMA_Priority_High; //通道优先级
    48. DMA_StructInit.DMA_M2M = DMA_M2M_Disable; //存储器到存储器模式
    49. DMA_Init( DMA1_Channel1, &DMA_StructInit);
    50. DMA_Cmd(DMA1_Channel1, ENABLE);
    51. /*---------------------ADC------------------------------------*/
    52. ADCx_RCC_Clock_Cmd(ADCx_Periph, ENABLE);
    53. ADC_StructInit.ADC_Mode = ADC_Mode_Independent; //设置独立模式(因为只有一个ADC)
    54. ADC_StructInit.ADC_ScanConvMode = ENABLE; //配置是否扫描(用在多通道)
    55. ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
    56. ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
    57. ADC_StructInit.ADC_NbrOfChannel = len; //配置要转换通道的数目
    58. ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者输入引脚触发才会使用)
    59. ADC_Init(ADC_x, &ADC_StructInit);
    60. RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
    61. ADC_RegularChannelConfig(ADC_x, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); //规则通道的配置,第三个参数是配置第几次转换,第四个参数是配置采样周期
    62. ADC_RegularChannelConfig(ADC_x, ADC_Channel_2, 2, ADC_SampleTime_55Cycles5);
    63. ADC_RegularChannelConfig(ADC_x, ADC_Channel_3, 3, ADC_SampleTime_55Cycles5);
    64. ADC_Cmd(ADC_x, ENABLE); //使能ADC中断
    65. // 初始化ADC 校准寄存器
    66. ADC_ResetCalibration(ADC_x);
    67. // 等待校准寄存器初始化完成
    68. while(ADC_GetResetCalibrationStatus(ADC_x));
    69. ADC_StartCalibration(ADC_x); //开始校准ADC
    70. while(ADC_GetCalibrationStatus(ADC_x)); //等待校准完成
    71. ADC_SoftwareStartConvCmd(ADC_x, ENABLE); //软件触发使能(开始工作)
    72. //使能DMA ADC请求
    73. ADC_DMACmd(ADC_x, ENABLE);
    74. }
    75. void ADCx_Init(void)
    76. {
    77. ACDx_GPIO_Config();
    78. Config_ADC_Init();
    79. }
    80. // 局部变量,用于保存转换计算后的电压值
    81. float ADC_ConvertedValueLocal[len];
    82. int main()
    83. {
    84. float conversionValue = 0;
    85. initSysTick();
    86. usart_init();
    87. ADCx_Init();
    88. printf("\r\n ----这是一个ADC多通道采集实验----\r\n");
    89. while(1)
    90. {
    91. ADC_ConvertedValueLocal[0] =(float) ADC_conversionValue[0]/4096*3.3;
    92. ADC_ConvertedValueLocal[1] =(float) ADC_conversionValue[1]/4096*3.3;
    93. ADC_ConvertedValueLocal[2] =(float) ADC_conversionValue[2]/4096*3.3;
    94. printf("\r\n CH0 value = %f V \r\n",ADC_ConvertedValueLocal[0]);
    95. printf("\r\n CH1 value = %f V \r\n",ADC_ConvertedValueLocal[1]);
    96. printf("\r\n CH2 value = %f V \r\n",ADC_ConvertedValueLocal[2]);
    97. ms_delay(2000);
    98. }
    99. }

    4、双ADC_DMA读取_同步规则

    *此模式在 规则通道组 上执行。外部触发来自 ADC1 的规则组多路开关 ( ADC1_CR2 寄存器的
    EXTSEL[2:0] 选择 ) 它同时给 ADC2 提供同步触发。
    *不要在2个ADC上转换相同的通道((两个ADC在同一个通道上的采样时间不能重善)。
    * ADC1 ADC2 的转换结束时:产生一个32位DMA传输请求(如果设置了DMA位),32位的ADC1_DR寄存器内容传输到SRAM中,它 上半个字包含ADC2的转换数据, 低半个字包含ADC1的转换数据。
    * 当所有 ADC1/ADC2 规则通道都被转换完时,产生 EOC 中断 ( 若任一 ADC 接口开放了中断 )
    1. #ifndef ADC_H
    2. #define ADC_H
    3. #include "stm32f10x.h"
    4. static void ACDx_GPIO_Config(void);
    5. static void Config_ADC_Init(void);
    6. void ADCx_Init(void);
    7. //ADC引脚配置的宏
    8. #define ADCx_PIN GPIO_Pin_1
    9. #define ADCx_PIN_PORT GPIOA
    10. #define ADCx_PIN_Periph RCC_APB2Periph_GPIOA
    11. #define ADCx_PIN_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
    12. //ADC配置的宏
    13. #define ADCx_Periph RCC_APB2Periph_ADC1
    14. #define ADCx_RCC_Clock_Cmd RCC_APB2PeriphClockCmd
    15. #define ADC_x ADC1
    16. #define ADCx_Channel ADC_Channel_1
    17. #define len 1
    18. #endif
    19. #include "adc.h"
    20. uint32_t ADC_conversionValue[len];//单ADC模式时,数据寄存器只用到低16位(用来存放 ADC发过来的数据)
    21. static void ACDx_GPIO_Config(void)
    22. {
    23. GPIO_InitTypeDef ADC_GPIO_StructInit;
    24. ADCx_PIN_RCC_Clock_Cmd(ADCx_PIN_Periph,ENABLE);
    25. ADC_GPIO_StructInit.GPIO_Mode = GPIO_Mode_AIN; //必须是模拟输入
    26. ADC_GPIO_StructInit.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2 ;
    27. GPIO_Init(ADCx_PIN_PORT, &ADC_GPIO_StructInit);
    28. }
    29. static void Config_ADC_Init(void)
    30. {
    31. ADC_InitTypeDef ADC_StructInit;
    32. DMA_InitTypeDef DMA_StructInit;
    33. /*--------------------------DMA-----------------------------------------*/
    34. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //打开时钟
    35. DMA_DeInit(DMA1_Channel1); //将DMA寄存器复位成刚上电的样子
    36. DMA_StructInit.DMA_MemoryBaseAddr = (uint32_t)ADC_conversionValue; //存储器地址
    37. DMA_StructInit.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_x->DR)); //外设地址
    38. DMA_StructInit.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向
    39. DMA_StructInit.DMA_BufferSize = len; //传输数目(缓冲区大小,应该等于数据目的地的大小)
    40. // 外设数据大小为半字,即两个字节
    41. DMA_StructInit.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; //外设数据宽度(32位)
    42. // 内存数据大小也为半字,跟外设数据大小相同
    43. DMA_StructInit.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; //存储器数据宽度(32位)
    44. DMA_StructInit.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址是否递增
    45. DMA_StructInit.DMA_MemoryInc = DMA_MemoryInc_Enable; //存储器地址是否递增
    46. DMA_StructInit.DMA_Mode = DMA_Mode_Circular; //模式选择(现在时循环模式)
    47. DMA_StructInit.DMA_Priority = DMA_Priority_High; //通道优先级
    48. DMA_StructInit.DMA_M2M = DMA_M2M_Disable; //存储器到存储器模式
    49. DMA_Init( DMA1_Channel1, &DMA_StructInit);
    50. DMA_Cmd(DMA1_Channel1, ENABLE);
    51. /*---------------------ADC1------------------------------------*/
    52. ADCx_RCC_Clock_Cmd(ADCx_Periph, ENABLE);
    53. ADC_StructInit.ADC_Mode = ADC_Mode_RegSimult; //设置成规则同步模式(因为有两个ADC)
    54. ADC_StructInit.ADC_ScanConvMode = ENABLE; //配置是否扫描(用在多通道)
    55. ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
    56. ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
    57. ADC_StructInit.ADC_NbrOfChannel = len; //配置要转换通道的数目
    58. ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者输入引脚触发才会使用)
    59. ADC_Init(ADC_x, &ADC_StructInit);
    60. RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
    61. ADC_Cmd(ADC_x, ENABLE); //使能ADC中断
    62. ADC_RegularChannelConfig(ADC_x, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);//设置通道1(PA1
    63. //使能DMA ADC请求
    64. ADC_DMACmd(ADC_x, ENABLE);
    65. /*--------------------ADC2-------------------------------------*/
    66. ADCx_RCC_Clock_Cmd(RCC_APB2Periph_ADC2, ENABLE);
    67. ADC_StructInit.ADC_Mode = ADC_Mode_RegSimult; //设置成规则同步模式(因为有两个ADC)
    68. ADC_StructInit.ADC_ScanConvMode = ENABLE; //配置是否扫描(用在多通道)
    69. ADC_StructInit.ADC_ContinuousConvMode = ENABLE; //配置是否要连续转换
    70. ADC_StructInit.ADC_DataAlign = ADC_DataAlign_Right; //配置数据的对齐模式
    71. ADC_StructInit.ADC_NbrOfChannel = len; //配置要转换通道的数目
    72. ADC_StructInit.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//配置触发模式(这里是软件触发,外部触发是有定时器或者GPIO才会使用)
    73. // RCC_ADCCLKConfig(RCC_PCLK2_Div8); //时钟配置72/8=9M
    74. ADC_Init(ADC2, &ADC_StructInit);
    75. ADC_Cmd(ADC2, ENABLE); //使能ADC中断
    76. ADC_RegularChannelConfig(ADC2, ADC_Channel_2, 1, ADC_SampleTime_55Cycles5);//设置通道2(PA2
    77. /* 使能ADCx_2的外部触发转换 */
    78. ADC_ExternalTrigConvCmd(ADC2, ENABLE);
    79. // 初始化ADC1 校准寄存器
    80. ADC_ResetCalibration(ADC_x);
    81. // 等待校准寄存器初始化完成
    82. while(ADC_GetResetCalibrationStatus(ADC_x));
    83. ADC_StartCalibration(ADC_x); //开始校准ADC
    84. while(ADC_GetCalibrationStatus(ADC_x)); //等待校准完成
    85. // 初始化ADC2 校准寄存器
    86. ADC_ResetCalibration(ADC2);
    87. // 等待校准寄存器初始化完成
    88. while(ADC_GetResetCalibrationStatus(ADC2));
    89. ADC_StartCalibration(ADC2); //开始校准ADC
    90. while(ADC_GetCalibrationStatus(ADC2)); //等待校准完成
    91. ADC_SoftwareStartConvCmd(ADC_x, ENABLE); //软件触发使能(开始工作)
    92. }
    93. void ADCx_Init(void)
    94. {
    95. ACDx_GPIO_Config();
    96. Config_ADC_Init();
    97. }
    98. extern uint32_t ADC_conversionValue[len];//单ADC模式时,数据寄存器只用到低16位(用来存放 ADC发过来的数据)
    99. // 局部变量,用于保存转换计算后的电压值
    100. float ADC_ConvertedValueLocal[len*2];
    101. int main()
    102. {
    103. uint16_t temp0=0 ,temp1=0;
    104. initSysTick();
    105. usart_init();
    106. ADCx_Init();
    107. printf("\r\n ----这是一个双ADC规则同步采集实验----\r\n");
    108. while(1)
    109. {
    110. // 取出ADC1数据寄存器的高16位,这个是ADC2的转换数据
    111. temp0 = (ADC_conversionValue[0]&0XFFFF0000) >> 16;//取高16位(ADC2的数据)
    112. // 取出ADC1数据寄存器的低16位,这个是ADC1的转换数据
    113. temp1 = (ADC_conversionValue[0]&0XFFFF); //取低16位(ADC1的数据)
    114. ADC_ConvertedValueLocal[0] =(float) temp0/4096*3.3;
    115. ADC_ConvertedValueLocal[1] =(float) temp1/4096*3.3;
    116. printf("\r\n ADC1 value = %f V \r\n",
    117. ADC_ConvertedValueLocal[1]);
    118. printf("\r\n ADC2 value = %f V \r\n",
    119. ADC_ConvertedValueLocal[0]);
    120. ms_delay(2000);
    121. }
    122. }

    PS:

    *多路ADC模式的时候 ,要配置外部触发转换,单路ADC只需要配置软件触发转换

    *多路ADC模式的时候,ADC1,ADC2一起使用,例如设置规则同步的时候,通道的数目要一致,ADC1有两个通道,ADC2也需要有两个通道

    *

    五、触发源

     *ADC 的触发转换有两种方法:分别是通过软件或外部事件(也就是硬件)触发转换。

     *软件触发转换的方法。方法是:通过写 ADC_CR2 寄存器的 ADON 这个位来控制,写 1 就开始转换,写 0 就停止转换,这个控制 ADC 转换的方式非常简单。

    *外部事件触发转换的方法,有定时器和输入引脚触发等等

    六、校准

    *ADC有一个内置自校准模式。校准可大幅减小因内部电容器组的变化而造成的准精度误差。校准期间,在每个电容器上都会计算出一个误差修正码(数字值),这个码用于消除在随后的转换中每个电容器上产生的误差

    *建议在每次上电后执行一次校准

    *启动校准前, ADC必须处于关电状态超过至少两个ADC时钟周期

    七、DMA请求

    *因为规则通道转换的值储存在一个仅有的数据寄存器中,所以当转换多个规则通道时需要使用 DMA,这可以避免丢失已经存储在ADC_DR寄存器中的数据。

    *只有在规则通道的转换结束时才产生DMA请求,并将转换的数据从ADC_DR寄存器传输到用户 指定的目的地址。

    *只有ADC1和ADC3拥有DMA功能。由ADC2转化的数据可以通过双ADC模式,利用ADC1的DMA功能传输。(ADC2转换的数据要用DMA传输的时候,就可以用双ADC模式)。

    八、中断

    *规则和注入组转换结束时能产生中断,当模拟看门狗状态位被设置时也能产生中断。它们都有
    独立的中断使能位。

    *ADC1和ADC2的中断映射在同一个中断向量上,而ADC3的中断有自己的中断向量。

    * ADC_SR 寄存器中有 2 个其他标志,但是它们没有相关联的中断:

    九、数据对齐

    *ADC_CR2 寄存器中的 ALIGN 位选择转换后数据储存的对齐方式。数据可以左对齐或右对齐
    *
    注入组通道转换的数据值已经减去了在 ADC_JOFRx 寄存器中定义的偏移量,因此结果可以是一
    个负值。 SEXT 位是扩展的符号值。
    *对于规则组通道,不需减去偏移值,因此只有 12 个位有效。

  • 相关阅读:
    005. 组合总和 II
    电大搜题——学习的好机会
    【算法刷题日记之本手篇】微信红包与计算字符串的编辑距离
    Ubuntu18.04安装 ROS Melodic教程
    Android MQTT连接阿里云使用Json解析数据
    以爱情规律为例,浅谈三段式描述状态机
    Windows操作系统登录双因素认证解决方案 安当加密
    每秒10W次分词搜索,产品经理又提了一个需求!!!(收藏)
    Docker-简介,安装,测试
    找不到d3dx9_43.dll如何修复?d3dx9_43.dll丢失的解决办法分享
  • 原文地址:https://blog.csdn.net/weixin_61921209/article/details/139247997