当前位置:   article > 正文

STM32----DMA+ADC+单通道_stm32 adc dma

stm32 adc dma

DMA的基本介绍

什么是DMA (DMA的基本定义)

DMA,全称Direct Memory Access,即直接存储器访问。

DMA传输将数据从一个地址空间复制到另一个地址空间,提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。

配置流程(光照)(需要配置GPIO、ADC、DMA)

一、配置GPIO

1.开引脚时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); 

2.配置引脚工作模式

  1. //定义结构体
  2. GPIO_InitTypeDef GPIO_InitStruct={0};
  3. //给结构体赋值
  4. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;//工作模式 模拟输入 (1)看官方例程 (2)参考手册8.1.11
  5. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5; //引脚
  6. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //工作速度
  7. //调用XXX_init函数,将参数写入到寄存器中
  8. GPIO_Init(GPIOA,&GPIO_InitStruct);

二、配置ADC

1、开ADC1时钟

RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);

2、对ADC分频  

        参考手册11.1中  描述时钟不能超过14M   ADC1挂载在APB2上,时钟为72M,进行6分频  变成12M<14M

RCC_ADCCLKConfig(RCC_PCLK2_Div6);

3、配置ADC

       (1) 参数ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;         分为连续转换和不连续转换

        连续转换 给1次命令,之后自动转换  ADC_SoftwareStartConvCmd(ADC1,ENABLE);

        不连续转换,需要每次都给一个命令      ADC_SoftwareStartConvCmd(ADC1,ENABLE);

  1. //定义结构体
  2. ADC_InitTypeDef ADC_InitStruct={0};
  3. //对结构体赋值
  4. ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //连续转换 给1次命令,之后自动转换 ADC_SoftwareStartConvCmd(ADC1,ENABLE);
  5. ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; //数据靠右对齐 16位的DR寄存器 12位的分辨率 转换结果最多12位,靠右对齐方便读取数据
  6. ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不外部触发 通过软件触发转换
  7. ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; //独立模式 ADC1和ADC2独立工作
  8. ADC_InitStruct.ADC_NbrOfChannel = 1; //待转换的通道数量 -- 更改
  9. ADC_InitStruct.ADC_ScanConvMode = ENABLE; //1个通道也可以配置扫描
  10. //调用xxx_init函数将参数写入到寄存器中
  11. ADC_Init(ADC1,&ADC_InitStruct);

三、配置DMA

1、开DMA时钟

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);

2、配置DMA

        目标地址可以是数组也可以是变量,但变量只能定义一个,存放数据会被重复覆盖,因此多个通道时候只能用数组,如光照+烟雾时候。     

(1)数组用法   

  1. //定义DMA相关的结构体
  2. DMA_InitTypeDef DMA_InitStruct={0};
  3. //给结构体赋值
  4. //目标地址
  5. DMA_InitStruct.DMA_BufferSize = sizeof(ADC_DMA_Buff)/sizeof(ADC_DMA_Buff[0]); //能够存放的转换后数据的数量
  6. DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)ADC_DMA_Buff; //内存的基地址
  7. DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存递增 目标地址有10个存储空间
  8. //源地址
  9. DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //外设ADC作为数据的来源
  10. DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //使用外设ADC-->内存 不使用内存到内存
  11. DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度为半字 ADC1转换结果存放在ADC_DR低16位
  12. DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //循环模式 目标地址占用完之后,会重头覆盖
  13. DMA_InitStruct.DMA_PeripheralBaseAddr = 0x4001244C; //ADC1_DR寄存器的地址
  14. DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度
  15. DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不累加 每次ADC转换的结果都存放在ADC1_DR 会覆盖
  16. DMA_InitStruct.DMA_Priority = DMA_Priority_High; //DMA通道的优先级
  17. //调用xxx_init函数将参数写入到寄存器中
  18. DMA_Init(DMA1_Channel1,&DMA_InitStruct); //参考手册 10.3.7

(2)变量用法

  1. //定义DMA相关的结构体
  2. DMA_InitTypeDef DMA_InitStruct={0};
  3. //给结构体赋值
  4. //目标地址
  5. DMA_InitStruct.DMA_BufferSize = 1; //能够存放的转换后数据的数量
  6. DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&ADC_DMA_Date; //内存的基地址
  7. DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Disable; //内存不递增
  8. //源地址
  9. DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //外设ADC作为数据的来源
  10. DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //使用外设ADC-->内存 不使用内存到内存
  11. DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度为半字 ADC1转换结果存放在ADC_DR低16位
  12. DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //循环模式 目标地址占用完之后,会重头覆盖
  13. DMA_InitStruct.DMA_PeripheralBaseAddr = 0x4001244C; //ADC1_DR寄存器的地址
  14. DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度
  15. DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不累加 每次ADC转换的结果都存放在ADC1_DR 会覆盖
  16. DMA_InitStruct.DMA_Priority = DMA_Priority_High; //DMA通道的优先级
  17. //调用xxx_init函数将参数写入到寄存器中
  18. DMA_Init(DMA1_Channel1,&DMA_InitStruct); //参考手册 10.3.7

四、开ADC的DMA功能

ADC_DMACmd(ADC1,ENABLE);

五、配置ADC规则通道

            //参数1   使用哪个ADC转换   ADC1  ADC2  ADC3
            //参数2   转换哪个通道   PA5  ADC12_IN5
            //参数3   规则组采样顺序    --  ADC_SQR
            //参数4   ADC 通道的采样时间值    周期越大:时间越长,准确率越高  
                //参考手册  11.6  TCONV = 采样时间+ 12.5个周期
                //TCONV = 采样时间+ 12.5个周期=55+12.5=67.5周期
                //分频之后 ADC1的频率位12M   周期t=1/12000000S
                //转换完成需要的时间 T =67.5周期*t=(67.5/12000000)s       -- 更改

ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5);   //stm32f10x_adc.h 440行

六、开使能

1.使能ADC

  ADC_Cmd(ADC1, ENABLE);

2、使能DMA

DMA_Cmd(DMA1_Channel1,ENABLE);

七、校准

         参考手册  11.4中  描述  开机必须校准1次
         重置指定的 ADC 的校准寄存器  参考手册11.12.3 位3 stm32f10x_adc.h  434行  

1、重置指定的 ADC 的校准寄存器

ADC_ResetCalibration(ADC1);

2、等待校准寄存器初始化 参考手册11.12.3 位3  stm32f10x_adc.h  435行 

while(ADC_GetResetCalibrationStatus(ADC1));

3、启动校准  参考手册11.12.3 位2    stm32f10x_adc.h   435行 

ADC_StartCalibration(ADC1);

4、等待校准结束 参考手册11.12.3 位2    stm32f10x_adc.h  436行

while(ADC_GetCalibrationStatus(ADC1));

八、启动转换

ADC_SoftwareStartConvCmd(ADC1,ENABLE); 

九、完成DMA+ADC(光照)代码

1、dma.c

  1. #include "dma.h"
  2. #if (ADC_DMA_USE_BUFF==1)
  3. uint16_t ADC_DMA_Buff[10]; //用来作为DMA的目标地址 待采集通道的整数倍
  4. #elif (ADC_DMA_USE_BUFF==0)
  5. uint16_t ADC_DMA_Date=0;
  6. #endif
  7. /*
  8. DMA 直接内存访问(Direct Memory Access)
  9. DMA是的独立的功能,分为DMA1和DMA2
  10. DMA可以和ADC UART SPI IIC等外设一块使用
  11. 我们采样: ADC+DMA的使用
  12. 配置ADC:
  13. 结构体:GPIO ADC
  14. 实现光照:PA5 ADC12_IN5 -- 硬件原理图决定
  15. 配置DMA:
  16. 结构体:DMA
  17. 使用ADC1采集,ADC1的通道在DMA1上,所以DMA1和ADC1一块使用 -- 参考手册 中文表59决定
  18. 源地址: ADC_DR ADC外设里面的寄存器
  19. 目标地址:ADC_DMA_Buff 内存的地址里面
  20. */
  21. void ADC_DMA_Config(void)
  22. {
  23. //1.开GPIOA时钟
  24. //void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState); stm3210x_rcc.h 693行
  25. //void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
  26. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  27. //2.定义结构体
  28. //void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); stm32f10x_gpio.h 351行
  29. GPIO_InitTypeDef GPIO_InitStruct={0};
  30. //3.给结构体赋值
  31. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN;//工作模式 模拟输入 (1)看官方例程 (2)参考手册8.1.11
  32. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_5; //引脚
  33. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //工作速度
  34. //4.调用XXX_init函数,将参数写入到寄存器中
  35. GPIO_Init(GPIOA,&GPIO_InitStruct);
  36. //5.开ADC1的时钟
  37. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
  38. //6.对ADC分频 参考手册11.1中 描述时钟不能操作14M ADC1挂载在APB2上,时钟为72M,进行6分频 变成12M<14M
  39. //void RCC_ADCCLKConfig(uint32_t RCC_PCLK2); stm32f10x_rcc.h 680行
  40. RCC_ADCCLKConfig(RCC_PCLK2_Div6);
  41. //7.定义结构体 xxx_init
  42. //void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct); stm32f10x_adc.h 429行
  43. ADC_InitTypeDef ADC_InitStruct={0};
  44. //8.对结构体赋值
  45. ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //连续转换 给1次命令,之后自动转换 ADC_SoftwareStartConvCmd(ADC1,ENABLE);
  46. ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; //数据靠右对齐 16位的DR寄存器 12位的分辨率 转换结果最多12位,靠右对齐方便读取数据
  47. ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不外部触发 通过软件触发转换
  48. ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; //独立模式 ADC1和ADC2独立工作
  49. ADC_InitStruct.ADC_NbrOfChannel = 1; //待转换的通道数量 -- 更改
  50. ADC_InitStruct.ADC_ScanConvMode = ENABLE; //1个通道也可以配置扫描
  51. //9.调用xxx_init函数将参数写入到寄存器中
  52. ADC_Init(ADC1,&ADC_InitStruct);
  53. //10.开DMA1的时钟
  54. //void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState); stm32f10x_rcc.h 692行
  55. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
  56. //11.定义DMA相关的结构体
  57. //void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct); stm32f10x_dma.h 411行
  58. DMA_InitTypeDef DMA_InitStruct={0};
  59. //12.给结构体赋值
  60. #if (ADC_DMA_USE_BUFF==1)
  61. DMA_InitStruct.DMA_BufferSize = sizeof(ADC_DMA_Buff)/sizeof(ADC_DMA_Buff[0]); //能够存放的转换后数据的数量
  62. DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)ADC_DMA_Buff; //内存的基地址
  63. DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存递增 目标地址有10个存储空间
  64. #elif (ADC_DMA_USE_BUFF==0)
  65. DMA_InitStruct.DMA_BufferSize = 1; //能够存放的转换后数据的数量
  66. DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&ADC_DMA_Date; //内存的基地址
  67. DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Disable; //内存递增
  68. #endif
  69. DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //外设ADC作为数据的来源
  70. DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //使用外设ADC-->内存 不使用内存到内存
  71. DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;//数据宽度为半字 ADC1转换结果存放在ADC_DR低16位
  72. DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //循环模式 目标地址占用完之后,会重头覆盖
  73. /*
  74. ADC1 0x40012400 -- 0x00127FF 数据手册存储器映像
  75. ADC_DR 相对于外设起始地址偏移 0x4C 参考手册 11.12.14的偏移地址
  76. ADC1_DR 0x40012400+0x4C
  77. */
  78. DMA_InitStruct.DMA_PeripheralBaseAddr = 0x4001244C; //ADC1_DR寄存器的地址
  79. DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度
  80. DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不累加 每次ADC转换的结果都存放在ADC1_DR 会覆盖
  81. DMA_InitStruct.DMA_Priority = DMA_Priority_High; //DMA通道的优先级
  82. //12.调用xxx_init函数将参数写入到寄存器中
  83. DMA_Init(DMA1_Channel1,&DMA_InitStruct); //参考手册 10.3.7
  84. //13.开ADC1的DMA功能
  85. //void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState); stm32f10x_adc.h 432行
  86. ADC_DMACmd(ADC1,ENABLE);
  87. //14.配置ADC规则通道
  88. //参数1 使用哪个ADC转换 ADC1 ADC2 ADC3
  89. //参数2 转换哪个通道 PA5 ADC12_IN5
  90. //参数3 规则组采样顺序 -- ADC_SQR
  91. //参数4 ADC 通道的采样时间值 周期越大:时间越长,准确率越高
  92. //参考手册 11.6 TCONV = 采样时间+ 12.5个周期
  93. //TCONV = 采样时间+ 12.5个周期=55+12.5=67.5周期
  94. //分频之后 ADC1的频率位12M 周期t=1/12000000S
  95. //转换完成需要的时间 T =67.5周期*t=(67.5/12000000)s -- 更改
  96. ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5); //stm32f10x_adc.h 440行
  97. //15.使能ADC stm32f10x_adc.h 431行
  98. ADC_Cmd(ADC1, ENABLE);
  99. //16.使能DMA1
  100. //void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState); //stm32f10x_adc.h 413行
  101. DMA_Cmd(DMA1_Channel1,ENABLE);
  102. //参考手册 11.4中 描述 开机必须校准1次
  103. //17.重置指定的 ADC 的校准寄存器 参考手册11.12.3 位3 stm32f10x_adc.h 434行
  104. ADC_ResetCalibration(ADC1);
  105. //18.等待校准寄存器初始化 参考手册11.12.3 位3 stm32f10x_adc.h 435行
  106. while(ADC_GetResetCalibrationStatus(ADC1));
  107. //19.启动校准 参考手册11.12.3 位2 stm32f10x_adc.h 435行
  108. ADC_StartCalibration(ADC1);
  109. //20.等待校准结束 参考手册11.12.3 位2 stm32f10x_adc.h 436行
  110. while(ADC_GetCalibrationStatus(ADC1));
  111. //21.启动转换
  112. // void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); //stm32f10x_adc.h 438行
  113. ADC_SoftwareStartConvCmd(ADC1,ENABLE);
  114. }

2、dma.h

  1. #ifndef __DMA_H_
  2. #define __DMA_H_
  3. #include "stm32f10x.h"
  4. #define ADC_DMA_USE_BUFF 1 //0 变量接收 1数组接收
  5. void ADC_DMA_Config(void);
  6. #endif

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小桥流水78/article/detail/753036
推荐阅读
相关标签
  

闽ICP备14008679号