当前位置:   article > 正文

STM32同时测量4路模拟电压,用DMA自动搬运到数组内,不用软件干预。

STM32同时测量4路模拟电压,用DMA自动搬运到数组内,不用软件干预。

下午我做的实验室同时测量4路模拟信号,测量的结果通过ADC开启DMA触发,叫数据转运小帮手自动把数据搬走,放到数组内,就省去了,各种检测啊,恢复标志位啊,等等的麻烦操作,直接去读数组的值就好了,数据已经被更新了。是不是很方便呢?好了,先看看实验的结果:

这样看起来是不是和上篇文章的结果差不多呢?

再来看看主函数中的操作吧,就很简单了:

这样看是不是就非常简单了啊,只是调用一下初始化函数,就把需要读的4路模拟电压数据放到了一个数组中了,接下来就来看看这个初始化到底都干了些什么工作吧?我先来简单的总结一下初始化顺序:代码中可能有点不一样,那是没有总结的结果。

1:/*开启时钟(ADC1,GPIOA,DMA1)*/

2:/*设置ADC时钟*/

3:/*GPIO初始化*/(模拟输入模式,A0,A1,A2,A3四个端口)

4:/*规则组通道配置*/(序列1放通道0,序列2放通道1,序列3放通道2,序列4放通道3)

5:/*ADC初始化*/(独立模式,数据右对齐,不使用外部触发,连续转换,扫描模式,通道数4)

6:/*DMA初始化*/(外设地址:ADC的DR也就是电压值的寄存器

                                        数据宽度:16位的半字

                                        地址自增:外设不自增,内存地址(目标地址)自增

                                        传输方向:外设为源

                                        转运次数:4(一次16位)

                                        DMA_Mode模式:循环模式

                                        DMA_M2M存储器到存储器:失能,由ADC外设触发转运

                                        优先级:中等)

7:    /*DMA使能*/ DMA_Cmd()

8:      /*ADC1触发DMA1使能*/  ADC_DMACmd

9:     /*ADC使能*/ADC_Cmd()

10:/*ADC校准*/  复位校准   开始校准

11:/*ADC触发*/    ADC_SoftwareStartConvCmd

好了总共总结起来就是上面的11步就能实现STM32自动把4路模拟信号的值搬运到一个数组中,完成在主函数中只调用数组就能知道结果的目标。下面开始展示我写的程序了,感觉有点乱,就不整理了:

MyADC.c文件:

  1. #include "stm32f10x.h" // Device header
  2. uint16_t AD_Value[4]; //###########################
  3. void MyADC_Init(void)
  4. {
  5. //开始RCC时钟,包括ADC和GPIO的时钟,ADCCLK的分频器也需要配置一下。
  6. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟
  7. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟
  8. RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
  9. RCC_ADCCLKConfig(RCC_PCLK2_Div6); // ADC的时钟选择6分频,也就是72M/6=12M
  10. //配置GPIO,把需要用的GPIO配置成模拟输入的模式
  11. GPIO_InitTypeDef GPIO_InitStruct; //GPIO初始化的结构体
  12. GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AIN; // 模式为模拟输入
  13. GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; // 初始化端口0
  14. GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //端口频率50M
  15. GPIO_Init(GPIOA, &GPIO_InitStruct); // GPIOA初始化
  16. //配置多路开关,把左边的通道接入规则组列表里
  17. ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_28Cycles5); //ADC1规则配置(ADC1,通道1,列表1,转换时间28.5个时钟(12M))
  18. ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_28Cycles5); //#############################
  19. ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_28Cycles5); //###########################
  20. ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4, ADC_SampleTime_28Cycles5); //XXXXXXXXXXXXXXXX
  21. //配置ADC转换器,用结构体配置,一大块的参数。
  22. ADC_InitTypeDef ADC_InitStruct; //ADC初始化结构体
  23. ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; //连续转换模式:开启 ####################
  24. ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right; // 数据对齐:右对齐
  25. ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //ADC中断触发:空,也就是软件触发
  26. ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; // ADC模式:独立模式
  27. ADC_InitStruct.ADC_NbrOfChannel = 4; //规则组中的通道数:4 #######################################3
  28. ADC_InitStruct.ADC_ScanConvMode = ENABLE; //扫描模式:开启 ######################################
  29. ADC_Init(ADC1, &ADC_InitStruct); //ADC初始化
  30. //************************************************
  31. //调用DMA_Init,初始化各个参数(包括外设和存储器的起始地址,数据宽度,地址是否自增,方向,传输计数器,是否需要自动重装,选择触发源,通道优先级)
  32. DMA_InitTypeDef DMA_InitStruct;
  33. DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; //######################################
  34. DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度,按半字的宽度(16位)搬运 #######################
  35. DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //不启用地址自增 ########################
  36. // 以上是外设站点(数据来源)的起始地址、数据宽度、是否自增。
  37. DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)AD_Value; //###############################
  38. DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度,按半字的宽度粘贴 #######################
  39. DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //启用地址++自增
  40. //以上3条是存储器(目的地)的起始地址、数据宽度、是否自增。
  41. DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //传输方向
  42. DMA_InitStruct.DMA_BufferSize = 4; //缓存区大小,其实就是传输计数器 传输4次半个字(16位) ##########################
  43. DMA_InitStruct.DMA_Mode = DMA_Mode_Circular; //传输模式,其实就是是否启用自动重装 自动重装 ###############
  44. DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //选择是硬件触发还是软件触发 硬件触发 ######################
  45. DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; // 优先级 选择中等优先级
  46. DMA_Init(DMA1_Channel1, &DMA_InitStruct); //第一个参数选择了是哪个DMA到哪个DMA通道,第二个参数结构体
  47. //调用DMA_CMD,通道使能(要在对应的外设调用XXX_DMACmd开启一下触发信号的输出,如果需要DMA的中断,就调用DMA_ITConfig,开启中断输出,再在NVIC里,配置中断通道,最后写中断函数就行了)
  48. DMA_Cmd(DMA1_Channel1, ENABLE); //################### 失能改使能
  49. ADC_DMACmd(ADC1, ENABLE); //开启ADC1的DMA请求 ##################################
  50. //************************************************
  51. //打开ADC_CMD()开启ADC。
  52. ADC_Cmd(ADC1, ENABLE); // ADC开启
  53. //校准ADC
  54. ADC_ResetCalibration(ADC1); // 复位校准ADC
  55. while(ADC_GetResetCalibrationStatus(ADC1) == SET); // 等待校准标志位置0
  56. ADC_StartCalibration(ADC1); // 开始复位校准ADC
  57. while(ADC_GetCalibrationStatus(ADC1) == SET); // 等待开始校准结束标志位置0
  58. ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发
  59. }

下面是MyADC.h文件:

  1. #ifndef __MYADC_H
  2. #define __MYADC_H
  3. extern uint16_t AD_Value[4];
  4. void MyADC_Init(void);
  5. #endif

下面是主函数main.c文件:

  1. #include "stm32f10x.h" // Device header
  2. #include "OLED.h"
  3. #include "MyADC.h"
  4. #include "Delay.h"
  5. int main(void)
  6. {
  7. OLED_Init(); //oled 屏幕初始化
  8. MyADC_Init(); //ADC初始化
  9. OLED_ShowString(1,1,"Val_1:");
  10. OLED_ShowString(2,1,"Val_2:");
  11. OLED_ShowString(3,1,"Val_3:");
  12. OLED_ShowString(4,1,"Val_4:");
  13. while(1)
  14. {
  15. OLED_ShowNum(1,7, AD_Value[0], 4); //显示val的数值,这个数值的范围为0-4095
  16. OLED_ShowNum(2,7, AD_Value[1], 4);
  17. OLED_ShowNum(3,7, AD_Value[2], 4);
  18. OLED_ShowNum(4,7, AD_Value[3], 4);
  19. Delay_ms(200);
  20. }
  21. }

好了,通过上面的一顿操作猛如虎,编译下载后就能看到自己想要的结果了,想要屏幕上的字不闪的那么快主函数中的循环内就加大点延时,不在乎就小点或是没有,我为了拍照拍全就加了200毫秒的延时,就能拍全了。

声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号