打印
[STM32F4]

stm32F407 ADC

[复制链接]
楼主: c17
手机看帖
扫描二维码
随时随地手机跟帖
21
c17|  楼主 | 2023-5-27 00:51 | 只看该作者 |只看大图 回帖奖励 |倒序浏览
电压转换

使用特权

评论回复
22
c17|  楼主 | 2023-5-27 00:51 | 只看该作者
多重工作模式:
ADC_CCR:MULTI[4:0]

ADC_CCR:DMA[1:0]

使用特权

评论回复
23
c17|  楼主 | 2023-5-27 00:52 | 只看该作者
独立模式

使用特权

评论回复
24
c17|  楼主 | 2023-5-27 00:52 | 只看该作者
双重规则同步模式

1、规则指的是只适用于规则通道,注入通道不行
2、同步指的是两个/三个ADC同时采集多个通道,
比如示波器的双通道同时采集。
注意:不要在同步模式时采集同一个通道

   如下是ADC 1/2 双重规则同步模式图

ADC1采集ch10 和ch11

ADC2采集ch11 和ch12

ADC 1/2 同步采集 ch10/11  ch11/12

使用特权

评论回复
25
c17|  楼主 | 2023-5-27 00:52 | 只看该作者
多重交替模式
1、交替模式只能用于规则组,通常只有一个通道,在一个ADC转换的时候,另外一个ADC又开始采集,这样可以提高ADC的采样率,最高为6M
2、数据传输时使用DMA模式2,当有两个数据项可用时( 32bit),生成一个DMA请求。

这是三个ADC 交替模式,用模式2,数据组合方式

使用特权

评论回复
26
c17|  楼主 | 2023-5-27 00:53 | 只看该作者



DMA mode 2: On each DMA request (two data items are available) two halfwords
representing two ADC-converted data items are transferred as a word.
In Dual ADC mode, both ADC2 and ADC1 data are transferred on the first request
(ADC2 data take the upper half-word and ADC1 data take the lower half-word) and
so on.
In Triple ADC mode, three DMA requests are generated. On the first request, both
ADC2 and ADC1 data are transferred (ADC2 data take the upper half-word and
ADC1 data take the lower half-word). On the second request, both ADC1 and
ADC3 data are transferred (ADC1 data take the upper half-word and ADC3 data
take the lower half-word).On the third request, both ADC3 and ADC2 data are
transferred (ADC3 data take the upper half-word and ADC2 data take the lower
half-word) and so on.
DAM mode 2 is used in interleaved mode and in regular simultaneous mode (for
Dual ADC mode only).
Example:
a) Interleaved dual mode: a DMA request is generated each time 2 data items are
available:
1st request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]
2nd request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]
b) Interleaved triple mode: a DMA request is generated each time 2 data items are
available//这是上面三个ADC图数据的组合方式,假如用DMA 的时候,用三个32位数组

使用特权

评论回复
27
c17|  楼主 | 2023-5-27 00:53 | 只看该作者
第一个存储的是1st request:  ,二个是2nd request,三个是3rd request
1st request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]


2nd request: ADC_CDR[31:0] = ADC1_DR[15:0] | ADC3_DR[15:0]
3rd request: ADC_CDR[31:0] = ADC3_DR[15:0] | ADC2_DR[15:0]
4th request: ADC_CDR[31:0] = ADC2_DR[15:0] | ADC1_DR[15:0]

使用特权

评论回复
28
c17|  楼主 | 2023-5-27 00:53 | 只看该作者
固件结构介绍:
ADC_InitTypeDef


ADC_Resolution: 配置 ADC 的分辨率,可选的分辨率有12 位、 10 位、 8 位和 6 位。 ADC_CR1:RES[1:0]
ScanConvMode: 配置是否使用扫描模式,单通道DISABLE,多通道 ENABLE。 ADC_CR1:SCAN
ADC_ContinuousConvMode: 配置连续转换还是单次转换。 ADC_CR1: CONT
ADC_ExternalTrigConvEdge: 外部触发极性选择,如果使用外部触发,可以选择触发的极性,可选有禁止触发检测、上升沿触发检测、下降沿触发检测以及上升沿和下降沿均可触发检测。 ADC_CR2: EXTEN/ JEXTEN

使用特权

评论回复
29
c17|  楼主 | 2023-5-27 00:54 | 只看该作者
ADC_ExternalTrigConv: 外部触发选择,实际上,我们一般使用软件自动触发。 ADC_CR2: EXTSEL[3:0]/ JEXTSEL[3:0]
ADC_DataAlign: 转换结果数据对齐模式,可选ADC_DataAlign_Right 或ADC_DataAlign_Left。ADC_CR2:ALIGN
ADC_NbrOfChannel: AD 转换通道数目。 ADC_SQR1:L[3:0]/ADC_JSQR:JL[1:0]
ADC_CommonInitTypeDef 这是ADC共用初始化结构体



ADC_Mode: ADC模工作式选择,有独立模式、双重模式以及三重模式。 ADC_CCR:MULTI
ADC_Prescaler: ADC 时钟分频系数选择, ADC 时钟是有 PCLK2 分频而来,分频系数决定 ADC 时钟频率,可选的分频系数为 2、 4、 6 和 8。 ADC 最大时钟配置为36MHz。 ADC_CCR:ADCPRE

使用特权

评论回复
30
c17|  楼主 | 2023-5-27 00:54 | 只看该作者
ADC_DMAAccessMode: DMA 模式设置,只有在双重或者三重模式才需要设置,可以设置三种模式,具体可参考参考手册11.9章节的说明。 ADC_CCR:DMA
Bits 15:14 DMA: Direct memory access mode for multi ADC mode
This bit-field is set and cleared by software. Refer to the DMA controller section for more
details.
00: DMA mode disabled
01: DMA mode 1 enabled (2 / 3 half-words one by one - 1 then 2 then 3)
10: DMA mode 2 enabled (2 / 3 half-words by pairs - 2&1 then 1&3 then 3&2)
11: DMA mode 3 enabled (2 / 3 bytes by pairs - 2&1 then 1&3 then 3&2)

使用特权

评论回复
31
c17|  楼主 | 2023-5-27 00:54 | 只看该作者
ADC_TwoSamplingDelay: 2 个采样阶段之间的延迟,仅适用于双重或三重交错模式。 ADC_CCR:DELAY

Bit 11:8 DELAY: Delay between 2 sampling phases
Set and cleared by software. These bits are used in dual or triple interleaved modes.
0000: 5 * TADCCLK
0001: 6 * TADCCLK
0010: 7 * TADCCLK
...
1111: 20 * TADCCLK
Bits 7:5 Reserved, must be kept at reset value.

使用特权

评论回复
32
c17|  楼主 | 2023-5-27 00:54 | 只看该作者
1-配置规则通道的转换顺序


ADC_RegularChannelConfig
(ADC_TypeDef* ADCx,    // 使用哪个ADC
uint8_t ADC_Channel,      // 使用哪个通道
uint8_t Rank,                      // 通道的转换顺序
uint8_t ADC_SampleTime) // 采样时间

使用特权

评论回复
33
c17|  楼主 | 2023-5-27 00:54 | 只看该作者
2、使能ADC


ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState)
ADC_CR2:ADON

使用特权

评论回复
34
c17|  楼主 | 2023-5-27 00:55 | 只看该作者
3-软件触发转换
ADC_SoftwareStartConv(ADC_TypeDef* ADCx)
ADC_CR2:SWSTART

使用特权

评论回复
35
c17|  楼主 | 2023-5-27 00:55 | 只看该作者
4-单重ADC DMA 请求
ADC_DMARequestAfterLastTransferCmd(ADC_TypeDef* ADCx,
FunctionalState NewState)
ADC_CR2:DDS
ADC_DMACmd(RHEOSTAT_ADC, ENABLE);
ADC_CR2:DMA

使用特权

评论回复
36
c17|  楼主 | 2023-5-27 00:55 | 只看该作者
5-多重ADC DMA 请求
ADC_MultiModeDMARequestAfterLastTransferCmd(FunctionalState
NewState)
ADC_CCR:DDS, ADC_CCR:DMA

使用特权

评论回复
37
c17|  楼主 | 2023-5-27 00:55 | 只看该作者
编程
#ifndef __BSP_ADC_H
#define        __BSP_ADC_H

#include "stm32f4xx.h"

// ADC GPIO 宏定义
#define RHEOSTAT_ADC_GPIO_PORT    GPIOB
#define RHEOSTAT_ADC_GPIO_PIN     GPIO_Pin_0
#define RHEOSTAT_ADC_GPIO_CLK     RCC_AHB1Periph_GPIOB

// ADC 序号宏定义
#define RHEOSTAT_ADC              ADC1
#define RHEOSTAT_ADC_CLK          RCC_APB2Periph_ADC1
#define RHEOSTAT_ADC_CHANNEL      ADC_Channel_8


// ADC 中断宏定义
#define Rheostat_ADC_IRQ            ADC_IRQn
#define Rheostat_ADC_INT_FUNCTION   ADC_IRQHandler


void Rheostat_Init(void);

#endif /* __BSP_ADC_H */





void Rheostat_Init(void)
{
        Rheostat_ADC_GPIO_Config();
        Rheostat_ADC_Mode_Config();
        Rheostat_ADC_NVIC_Config();
}

static void Rheostat_ADC_GPIO_Config(void)
{
                GPIO_InitTypeDef GPIO_InitStructure;
       
        // 使能 GPIO 时钟
        RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK, ENABLE);
               
        // 配置 IO
        GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;            
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
        GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);               
}

static void Rheostat_ADC_Mode_Config(void)
{
        ADC_InitTypeDef ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
       
  // 开启ADC时钟
        RCC_APB2PeriphClockCmd(RHEOSTAT_ADC_CLK , ENABLE);

  // -------------------ADC Common 结构体 参数 初始化------------------------
        // 独立ADC模式
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  // 时钟为fpclk x分频       
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
  // 禁止DMA直接访问模式       
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  // 采样时间间隔       
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;  
  ADC_CommonInit(&ADC_CommonInitStructure);
       
  // -------------------ADC Init 结构体 参数 初始化--------------------------
        ADC_StructInit(&ADC_InitStructure);
  // ADC 分辨率
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  // 禁止扫描模式,多通道采集才需要       
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  // 连续转换       
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  //禁止外部边沿触发
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  //外部触发通道,本例子使用软件触发,此值随便赋值即可
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  //数据右对齐       
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  //转换通道 1个
  ADC_InitStructure.ADC_NbrOfConversion = 1;                                    
  ADC_Init(RHEOSTAT_ADC, &ADC_InitStructure);
  //---------------------------------------------------------------------------
       
  // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期
  ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL, 1, ADC_SampleTime_56Cycles);
        // ADC 转换结束产生中断,在中断服务程序中读取转换值
       

        ADC_ITConfig(RHEOSTAT_ADC, ADC_IT_EOC, ENABLE);
  // 使能ADC
  ADC_Cmd(RHEOSTAT_ADC, ENABLE);  
  //开始adc转换,软件触发
  ADC_SoftwareStartConv(RHEOSTAT_ADC);
}

// 配置中断优先级
static void Rheostat_ADC_NVIC_Config(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
       
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
       
  NVIC_InitStructure.NVIC_IRQChannel = Rheostat_ADC_IRQ;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
       
  NVIC_Init(&NVIC_InitStructure);
}


中断函数
extern __IO uint16_t ADC_ConvertedValue;

// ADC 转换完成中断服务程序
void ADC_IRQHandler(void)
{
        if(ADC_GetITStatus(RHEOSTAT_ADC,ADC_IT_EOC)==SET)
        {
  // 读取ADC的转换值
                ADC_ConvertedValue = ADC_GetConversionValue(RHEOSTAT_ADC);

        }
        ADC_ClearITPendingBit(RHEOSTAT_ADC,ADC_IT_EOC);

}       

int main(void)
{       
  /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
  Debug_USART_Config();
        Rheostat_Init();       
       
    while (1)
    {
           
                        ADC_Vol =(float) ADC_ConvertedValue/4096*(float)3.3; // 读取转换的AD值

      printf("\r\n The current AD value = 0x%04X \r\n", ADC_ConvertedValue);
      printf("\r\n The current AD value = %f V \r\n",ADC_Vol);     

      Delay(0xffffee);  
    }
}

使用特权

评论回复
38
c17|  楼主 | 2023-5-27 00:55 | 只看该作者
ADC—独立模式-单通道-DMA
#ifndef __BSP_ADC_H
#define        __BSP_ADC_H

#include "stm32f4xx.h"

// ADC GPIO 宏定义
#define RHEOSTAT_ADC_GPIO_PORT    GPIOB
#define RHEOSTAT_ADC_GPIO_PIN     GPIO_Pin_0
#define RHEOSTAT_ADC_GPIO_CLK     RCC_AHB1Periph_GPIOB

// ADC 序号宏定义
#define RHEOSTAT_ADC              ADC1
#define RHEOSTAT_ADC_CLK          RCC_APB2Periph_ADC1
#define RHEOSTAT_ADC_CHANNEL      ADC_Channel_8

// ADC DR寄存器宏定义,ADC转换后的数字值则存放在这里
#define RHEOSTAT_ADC_DR_ADDR    ((u32)ADC1+0x4c)

// ADC DMA 通道宏定义,这里我们使用DMA传输
#define RHEOSTAT_ADC_DMA_CLK      RCC_AHB1Periph_DMA2
#define RHEOSTAT_ADC_DMA_CHANNEL  DMA_Channel_0
#define RHEOSTAT_ADC_DMA_STREAM   DMA2_Stream0



void Rheostat_Init(void);

#endif /* __BSP_ADC_H */





/**
  ******************************************************************************
  * [url=home.php?mod=space&uid=288409]@file[/url]    bsp_bsp_adc.c
  * [url=home.php?mod=space&uid=187600]@author[/url]  fire
  * [url=home.php?mod=space&uid=895143]@version[/url] V1.0
  * [url=home.php?mod=space&uid=212281]@date[/url]    2015-xx-xx
  * [url=home.php?mod=space&uid=247401]@brief[/url]   adc驱动
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火  STM32 F407 开发板  
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */
#include "./adc/bsp_adc.h"

__IO uint16_t ADC_ConvertedValue;

static void Rheostat_ADC_GPIO_Config(void)
{
                GPIO_InitTypeDef GPIO_InitStructure;
       
        // 使能 GPIO 时钟
        RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK, ENABLE);
               
        // 配置 IO
        GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;            
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
        GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);               
}

static void Rheostat_ADC_Mode_Config(void)
{
        DMA_InitTypeDef DMA_InitStructure;
        ADC_InitTypeDef ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
       
  // ------------------DMA Init 结构体参数 初始化--------------------------
  // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的
  // 开启DMA时钟
  RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_DMA_CLK, ENABLE);
        // 外设基址为:ADC 数据寄存器地址
        DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_DR_ADDR;       
  // 存储器地址,实际上就是一个内部SRAM的变量       
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)&ADC_ConvertedValue;  
  // 数据传输方向为外设到存储器       
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;       
        // 缓冲区大小为,指一次传输的数据量
        DMA_InitStructure.DMA_BufferSize = 1;       
        // 外设寄存器只有一个,地址不用递增
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  // 存储器地址固定
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;
  // // 外设数据大小为半字,即两个字节
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  //        存储器数据大小也为半字,跟外设数据大小相同
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;       
        // 循环传输模式
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  // 禁止DMA FIFO        ,使用直连模式
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;  
  // FIFO 大小,FIFO模式禁止时,这个不用配置       
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  
        // 选择 DMA 通道,通道存在于流中
  DMA_InitStructure.DMA_Channel = RHEOSTAT_ADC_DMA_CHANNEL;
  //初始化DMA流,流相当于一个大的管道,管道里面有很多通道
        DMA_Init(RHEOSTAT_ADC_DMA_STREAM, &DMA_InitStructure);
        // 使能DMA流
  DMA_Cmd(RHEOSTAT_ADC_DMA_STREAM, ENABLE);
       
        // 开启ADC时钟
        RCC_APB2PeriphClockCmd(RHEOSTAT_ADC_CLK , ENABLE);
  // -------------------ADC Common 结构体 参数 初始化------------------------
        // 独立ADC模式
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  // 时钟为fpclk x分频       
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
  // 禁止DMA直接访问模式       
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  // 采样时间间隔       
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;  
  ADC_CommonInit(&ADC_CommonInitStructure);
       
  // -------------------ADC Init 结构体 参数 初始化--------------------------
        ADC_StructInit(&ADC_InitStructure);
  // ADC 分辨率
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  // 禁止扫描模式,多通道采集才需要       
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  // 连续转换       
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  //禁止外部边沿触发
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  //外部触发通道,本例子使用软件触发,此值随便赋值即可
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  //数据右对齐       
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  //转换通道 1个
  ADC_InitStructure.ADC_NbrOfConversion = 1;                                    
  ADC_Init(RHEOSTAT_ADC, &ADC_InitStructure);
  //---------------------------------------------------------------------------
       
  // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期
  ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL, 1, ADC_SampleTime_56Cycles);

  // 使能DMA请求 after last transfer (Single-ADC mode)
  ADC_DMARequestAfterLastTransferCmd(RHEOSTAT_ADC, ENABLE);
  // 使能ADC DMA
  ADC_DMACmd(RHEOSTAT_ADC, ENABLE);
       
        // 使能ADC
  ADC_Cmd(RHEOSTAT_ADC, ENABLE);  
  //开始adc转换,软件触发
  ADC_SoftwareStartConv(RHEOSTAT_ADC);
}



void Rheostat_Init(void)
{
        Rheostat_ADC_GPIO_Config();
        Rheostat_ADC_Mode_Config();
}


int main(void)
{       
  /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
  Debug_USART_Config();
        Rheostat_Init();       
       
    while (1)
    {
   
      printf("\r\n The current AD value = 0x%04X \r\n", ADC_ConvertedValue);
      printf("\r\n The current AD value = %f V \r\n",ADC_Vol);     

                        ADC_Vol =(float) ADC_ConvertedValue/4096*(float)3.3; // 读取转换的AD值


      Delay(0xffffee);  
    }
}

使用特权

评论回复
39
c17|  楼主 | 2023-5-27 00:56 | 只看该作者
ADC—独立模式-多通道-DMA  scan模式 三根个引脚采集
#ifndef __BSP_ADC_H
#define        __BSP_ADC_H

#include "stm32f4xx.h"

#define RHEOSTAT_NOFCHANEL      3

/*=====================通道1 IO======================*/
// PB0 通过调帽接电位器
// ADC IO宏定义
#define RHEOSTAT_ADC_GPIO_PORT1    GPIOB
#define RHEOSTAT_ADC_GPIO_PIN1     GPIO_Pin_0
#define RHEOSTAT_ADC_GPIO_CLK1     RCC_AHB1Periph_GPIOB
#define RHEOSTAT_ADC_CHANNEL1      ADC_Channel_8
/*=====================通道2 IO ======================*/
// PB1 通过调帽接光敏电阻
// ADC IO宏定义
#define RHEOSTAT_ADC_GPIO_PORT2    GPIOB
#define RHEOSTAT_ADC_GPIO_PIN2     GPIO_Pin_1
#define RHEOSTAT_ADC_GPIO_CLK2     RCC_AHB1Periph_GPIOB
#define RHEOSTAT_ADC_CHANNEL2      ADC_Channel_9
/*=====================通道3 IO ======================*/
// PA6 悬空,可用杜邦线接3V3或者GND来实验
// ADC IO宏定义
#define RHEOSTAT_ADC_GPIO_PORT3    GPIOA
#define RHEOSTAT_ADC_GPIO_PIN3     GPIO_Pin_6
#define RHEOSTAT_ADC_GPIO_CLK3     RCC_AHB1Periph_GPIOA
#define RHEOSTAT_ADC_CHANNEL3     ADC_Channel_6

// ADC 序号宏定义
#define RHEOSTAT_ADC              ADC1
#define RHEOSTAT_ADC_CLK          RCC_APB2Periph_ADC1
// ADC DR寄存器宏定义,ADC转换后的数字值则存放在这里
#define RHEOSTAT_ADC_DR_ADDR    ((u32)ADC1+0x4c)


// ADC DMA 通道宏定义,这里我们使用DMA传输
#define RHEOSTAT_ADC_DMA_CLK      RCC_AHB1Periph_DMA2
#define RHEOSTAT_ADC_DMA_CHANNEL  DMA_Channel_0
#define RHEOSTAT_ADC_DMA_STREAM   DMA2_Stream0



void Rheostat_Init(void);

#endif /* __BSP_ADC_H */

/**
  ******************************************************************************
  * @file    bsp_bsp_adc.c
  * @author  fire
  * @version V1.0
  * @date    2015-xx-xx
  * @brief   adc驱动
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火  STM32 F407 开发板  
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */
#include "./adc/bsp_adc.h"

__IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL]={0};

static void Rheostat_ADC_GPIO_Config(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;       
        /*=====================通道1======================*/       
        // 使能 GPIO 时钟
        RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK1,ENABLE);               
        // 配置 IO
  GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN1;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  //不上拉不下拉       
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
        GPIO_Init(RHEOSTAT_ADC_GPIO_PORT1, &GPIO_InitStructure);

        /*=====================通道2======================*/
        // 使能 GPIO 时钟
        RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK2,ENABLE);               
        // 配置 IO
  GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN2;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  //不上拉不下拉       
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
        GPIO_Init(RHEOSTAT_ADC_GPIO_PORT2, &GPIO_InitStructure);       

        /*=====================通道3=======================*/
        // 使能 GPIO 时钟
        RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK3,ENABLE);               
        // 配置 IO
  GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN3;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  //不上拉不下拉       
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ;
        GPIO_Init(RHEOSTAT_ADC_GPIO_PORT3, &GPIO_InitStructure);
}

static void Rheostat_ADC_Mode_Config(void)
{
        DMA_InitTypeDef DMA_InitStructure;
        ADC_InitTypeDef ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
       
  // ------------------DMA Init 结构体参数 初始化--------------------------
  // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的
  // 开启DMA时钟
  RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_DMA_CLK, ENABLE);
        // 外设基址为:ADC 数据寄存器地址
        DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_DR_ADDR;       
  // 存储器地址,实际上就是一个内部SRAM的变量       
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_ConvertedValue;  
  // 数据传输方向为外设到存储器       
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;       
        // 缓冲区大小为,指一次传输的数据量
        DMA_InitStructure.DMA_BufferSize = RHEOSTAT_NOFCHANEL;       
        // 外设寄存器只有一个,地址不用递增
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  // 存储器地址固定
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  // // 外设数据大小为半字,即两个字节
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  //        存储器数据大小也为半字,跟外设数据大小相同
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;       
        // 循环传输模式
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  // 禁止DMA FIFO        ,使用直连模式
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;  
  // FIFO 大小,FIFO模式禁止时,这个不用配置       
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  
        // 选择 DMA 通道,通道存在于流中
  DMA_InitStructure.DMA_Channel = RHEOSTAT_ADC_DMA_CHANNEL;
  //初始化DMA流,流相当于一个大的管道,管道里面有很多通道
        DMA_Init(RHEOSTAT_ADC_DMA_STREAM, &DMA_InitStructure);
        // 使能DMA流
  DMA_Cmd(RHEOSTAT_ADC_DMA_STREAM, ENABLE);
       
        // 开启ADC时钟
        RCC_APB2PeriphClockCmd(RHEOSTAT_ADC_CLK , ENABLE);
  // -------------------ADC Common 结构体 参数 初始化------------------------
        // 独立ADC模式
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  // 时钟为fpclk x分频       
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
  // 禁止DMA直接访问模式       
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
  // 采样时间间隔       
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_20Cycles;  
  ADC_CommonInit(&ADC_CommonInitStructure);
       
  // -------------------ADC Init 结构体 参数 初始化--------------------------
        ADC_StructInit(&ADC_InitStructure);
  // ADC 分辨率
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  // 扫描模式,多通道采集需要       
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;
  // 连续转换       
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  //禁止外部边沿触发
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  //外部触发通道,本例子使用软件触发,此值随便赋值即可
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  //数据右对齐       
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  //转换通道 1个
  ADC_InitStructure.ADC_NbrOfConversion = RHEOSTAT_NOFCHANEL;                                    
  ADC_Init(RHEOSTAT_ADC, &ADC_InitStructure);
  //---------------------------------------------------------------------------
       
  // 配置 ADC 通道转换顺序和采样时间周期
  ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL1, 1,
                                 ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL2, 2,
                                 ADC_SampleTime_3Cycles);
  ADC_RegularChannelConfig(RHEOSTAT_ADC, RHEOSTAT_ADC_CHANNEL3, 3,
                                 ADC_SampleTime_3Cycles);

  // 使能DMA请求 after last transfer (Single-ADC mode)
  ADC_DMARequestAfterLastTransferCmd(RHEOSTAT_ADC, ENABLE);
  // 使能ADC DMA
  ADC_DMACmd(RHEOSTAT_ADC, ENABLE);
       
        // 使能ADC
  ADC_Cmd(RHEOSTAT_ADC, ENABLE);  
  //开始adc转换,软件触发
  ADC_SoftwareStartConv(RHEOSTAT_ADC);
}



void Rheostat_Init(void)
{
        Rheostat_ADC_GPIO_Config();
        Rheostat_ADC_Mode_Config();
}



/**
  ******************************************************************************
  * @file    main.c
  * @author  fire
  * @version V1.0
  * @date    2015-xx-xx
  * @brief   ADC例程
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火  STM32 F407 开发板
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */
  
#include "stm32f4xx.h"
#include "./usart/bsp_debug_usart.h"
#include "./adc/bsp_adc.h"

// ADC转换的电压值通过MDA方式传到SRAM
extern __IO uint16_t ADC_ConvertedValue[RHEOSTAT_NOFCHANEL];

// 局部变量,用于保存转换计算后的电压值          
float ADC_ConvertedValueLocal[RHEOSTAT_NOFCHANEL]={0};

static void Delay(__IO uint32_t nCount)         //简单的延时函数
{
        for(; nCount != 0; nCount--);
}

/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{       
  /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
  Debug_USART_Config();
        Rheostat_Init();       
       
        while (1)
        {
                ADC_ConvertedValueLocal[0] =(float) ADC_ConvertedValue[0]/4096*(float)3.3;
                ADC_ConvertedValueLocal[1] =(float) ADC_ConvertedValue[1]/4096*(float)3.3;
                ADC_ConvertedValueLocal[2] =(float) ADC_ConvertedValue[2]/4096*(float)3.3;
               
                printf("\r\n CH1_C3 value = %f V \r\n",ADC_ConvertedValueLocal[0]);
                printf("\r\n CH2_PA4 value = %f V \r\n",ADC_ConvertedValueLocal[1]);
                printf("\r\n CH3_PA6 value = %f V \r\n",ADC_ConvertedValueLocal[2]);
               
                printf("\r\n\r\n");
                Delay(0xffffff);  
        }
}



/*********************************************END OF FILE**********************/



使用特权

评论回复
40
c17|  楼主 | 2023-5-27 00:56 | 只看该作者
ADC—双重ADC-多通道-规则同步   可以是SCAN模式,每个ADCX的多个通道

现在是ADC1 和2 的每一个通道
/**
  ******************************************************************************
  * @file    main.c
  * @author  fire
  * @version V1.0
  * @date    2015-xx-xx
  * @brief   ADC例程
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火  STM32 F407 开发板
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */
  
#include "stm32f4xx.h"
#include "./usart/bsp_debug_usart.h"
#include "./adc/bsp_adc.h"

// ADC1转换的电压值通过MDA方式传到SRAM
extern __IO uint16_t ADC_ConvertedValue[2];

// 局部变量,用于保存转换计算后的电压值          
float ADC_ConvertedValueLocal[2];

static void Delay(__IO uint32_t nCount)         //简单的延时函数
{
        for(; nCount != 0; nCount--);
}

/**
  * @brief  主函数
  * @param  无
  * @retval 无
  */
int main(void)
{       
  /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
  Debug_USART_Config();
        Rheostat_Init();       
       
  while (1)
  {
    Delay(0xffffee);  
   
    ADC_ConvertedValueLocal[0] =(float)((uint16_t)ADC_ConvertedValue[0]*3.3/4096);
    ADC_ConvertedValueLocal[1] =(float)((uint16_t)ADC_ConvertedValue[1]*3.3/4096);   
   
    printf("\r\n The current AD value = 0x%08X \r\n", ADC_ConvertedValue[0]);
    printf("\r\n The current AD value = 0x%08X \r\n", ADC_ConvertedValue[1]);     
   
    printf("\r\n The current ADC1 value = %f V \r\n",ADC_ConvertedValueLocal[0]);
    printf("\r\n The current ADC2 value = %f V \r\n",ADC_ConvertedValueLocal[1]);   
  }
}



/*********************************************END OF FILE**********************/



#ifndef __BSP_ADC_H
#define        __BSP_ADC_H

#include "stm32f4xx.h"

/*=====================通道1 IO======================*/
// PB0 通过调帽接电位器
// ADC IO宏定义
#define RHEOSTAT_ADC_GPIO_PORT1    GPIOB
#define RHEOSTAT_ADC_GPIO_PIN1     GPIO_Pin_0
#define RHEOSTAT_ADC_GPIO_CLK1     RCC_AHB1Periph_GPIOB

// ADC 序号宏定义
#define RHEOSTAT_ADC1             ADC1
#define RHEOSTAT_ADC1_CLK         RCC_APB2Periph_ADC1
#define RHEOSTAT_ADC_CHANNEL1     ADC_Channel_8
/*=====================通道2 IO ======================*/
// PB1 通过调帽接光敏电阻
// ADC IO宏定义
#define RHEOSTAT_ADC_GPIO_PORT2    GPIOB
#define RHEOSTAT_ADC_GPIO_PIN2     GPIO_Pin_1
#define RHEOSTAT_ADC_GPIO_CLK2     RCC_AHB1Periph_GPIOB

#define RHEOSTAT_ADC2             ADC2
#define RHEOSTAT_ADC2_CLK         RCC_APB2Periph_ADC2
#define RHEOSTAT_ADC_CHANNEL2     ADC_Channel_9

// ADC CDR寄存器宏定义,ADC转换后的数字值则存放在这里
#define RHEOSTAT_ADC_CDR_ADDR    ((uint32_t)0x40012308)

// ADC DMA 通道宏定义,这里我们使用DMA传输
#define RHEOSTAT_ADC_DMA_CLK      RCC_AHB1Periph_DMA2
#define RHEOSTAT_ADC_DMA_CHANNEL  DMA_Channel_0
#define RHEOSTAT_ADC_DMA_STREAM   DMA2_Stream0


void Rheostat_Init(void);

#endif /* __BSP_ADC_H */

/**
  ******************************************************************************
  * @file    bsp_bsp_adc.c
  * @author  fire
  * @version V1.0
  * @date    2015-xx-xx
  * @brief   adc驱动
  ******************************************************************************
  * @attention
  *
  * 实验平台:野火  STM32 F407 开发板  
  * 论坛    :http://www.firebbs.cn
  * 淘宝    :https://fire-stm32.taobao.com
  *
  ******************************************************************************
  */
#include "./adc/bsp_adc.h"

__IO uint16_t ADC_ConvertedValue[2];

static void Rheostat_ADC_GPIO_Config(void)
{
                GPIO_InitTypeDef GPIO_InitStructure;
       
        // 使能 GPIO 时钟
        RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK1, ENABLE);
        RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK2, ENABLE);
               
        // 配置 IO
        GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN1;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;            
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
        GPIO_Init(RHEOSTAT_ADC_GPIO_PORT1, &GPIO_InitStructure);

        // 配置 IO
        GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN2;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;            
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
        GPIO_Init(RHEOSTAT_ADC_GPIO_PORT2, &GPIO_InitStructure);       
}

static void Rheostat_ADC_Mode_Config(void)
{
        DMA_InitTypeDef DMA_InitStructure;
        ADC_InitTypeDef ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
       
  // ------------------DMA Init 结构体参数 初始化--------------------------
  // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的
  // 开启DMA时钟
  RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_DMA_CLK, ENABLE);
        // 外设基址为:ADC 数据寄存器地址
        DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_CDR_ADDR;       
  // 存储器地址,实际上就是一个内部SRAM的变量       
        DMA_InitStructure.DMA_Memory0BaseAddr = (u32)ADC_ConvertedValue;  
  // 数据传输方向为外设到存储器       
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;       
        // 缓冲区大小为,指一次传输的数据量
        DMA_InitStructure.DMA_BufferSize = 2;       
        // 外设寄存器只有一个,地址不用递增
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  // 存储器地址固定
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  // // 外设数据大小为半字,即两个字节
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  //        存储器数据大小也为半字,跟外设数据大小相同
        DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;       
        // 循环传输模式
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  // 禁止DMA FIFO        ,使用直连模式
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;  
  // FIFO 大小,FIFO模式禁止时,这个不用配置       
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;  
        // 选择 DMA 通道,通道存在于流中
  DMA_InitStructure.DMA_Channel = RHEOSTAT_ADC_DMA_CHANNEL;
  //初始化DMA流,流相当于一个大的管道,管道里面有很多通道
        DMA_Init(RHEOSTAT_ADC_DMA_STREAM, &DMA_InitStructure);
        // 使能DMA流
  DMA_Cmd(RHEOSTAT_ADC_DMA_STREAM, ENABLE);
       
       
        // 开启ADC时钟
        RCC_APB2PeriphClockCmd(RHEOSTAT_ADC1_CLK , ENABLE);
  RCC_APB2PeriphClockCmd(RHEOSTAT_ADC2_CLK , ENABLE);
       
  // -------------------ADC Common 结构体 参数 初始化------------------------
        // 独立ADC模式
  ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult;
  // 时钟为fpclk x分频       
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
  // 禁止DMA直接访问模式       
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
  // 采样时间间隔       
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;  
  ADC_CommonInit(&ADC_CommonInitStructure);
       
  // -------------------ADC Init 结构体 参数 初始化--------------------------
        ADC_StructInit(&ADC_InitStructure);
  // ADC 分辨率
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  // 禁止扫描模式,多通道采集才需要       
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  // 连续转换       
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  //禁止外部边沿触发
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
  //外部触发通道,本例子使用软件触发,此值随便赋值即可
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
  //数据右对齐       
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  //转换通道 1个
  ADC_InitStructure.ADC_NbrOfConversion = 1;
       
  //---------------------------------------------------------------------------       
  ADC_Init(RHEOSTAT_ADC1, &ADC_InitStructure);       
   // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期
  ADC_RegularChannelConfig(RHEOSTAT_ADC1, RHEOSTAT_ADC_CHANNEL1, 1, ADC_SampleTime_3Cycles);   
  //---------------------------------------------------------------------------
       
        ADC_Init(RHEOSTAT_ADC2, &ADC_InitStructure);
  // 配置 ADC 通道转换顺序为1,第一个转换,采样时间为3个时钟周期
  ADC_RegularChannelConfig(RHEOSTAT_ADC2, RHEOSTAT_ADC_CHANNEL2, 1, ADC_SampleTime_3Cycles);   
  //---------------------------------------------------------------------------
               

  // 使能DMA请求 after last transfer (multi-ADC mode)
  ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
// 使能ADC DMA
  ADC_DMACmd(RHEOSTAT_ADC1, ENABLE);
       
  // 使能ADC
  ADC_Cmd(RHEOSTAT_ADC1, ENABLE);  
  ADC_Cmd(RHEOSTAT_ADC2, ENABLE);   
  
  //开始adc转换,软件触发
  ADC_SoftwareStartConv(RHEOSTAT_ADC1);
  //ADC_SoftwareStartConv(RHEOSTAT_ADC2);
}



void Rheostat_Init(void)
{
        Rheostat_ADC_GPIO_Config();
        Rheostat_ADC_Mode_Config();
}




使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则