你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

【经验分享】STM32F103单片机使用DMA功能读取ADC采样数据

[复制链接]
STMCU小助手 发布时间:2022-3-20 13:03
  使用DMA功能操作外设时,可以极大的简化代码,提高程序的执行效率。特别是在需要频繁操作的外设上。比如现在要采集单片机16个ADC通道的电压值,就可以使用DMA功能,直接将ADC通道转换好的值,传输到数组中。需要操纵ADC的值时,直接去数组中拿数据就行。不需要再去判断ADC数据转换是否结束。下面直接通过代码来实现。

  首先初始化ADC,这里将ADC的16个采样通道全部开启。


  1. void ADC1_Init ( void )
  2. {
  3.     GPIO_InitTypeDef GPIO_InitStructure;
  4.     ADC_InitTypeDef  ADC_InitStructure;  
  5.         
  6.     RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO, ENABLE );
  7.     RCC_ADCCLKConfig ( RCC_PCLK2_Div6 );                // 72M / 6 = 12M  ADC最大不能超过14M

  8.     // ADC1 --- ADC8
  9.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  10.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  11.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12.     GPIO_Init ( GPIOA, &GPIO_InitStructure );
  13.     // ADC9 ADC10
  14.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
  15.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  16.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  17.     GPIO_Init ( GPIOB, &GPIO_InitStructure );
  18.    // ADC11 --- ADC 16
  19.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5;
  20.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  21.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  22.     GPIO_Init ( GPIOC, &GPIO_InitStructure );

  23.     ADC_DeInit ( ADC1 );

  24.     ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;                                        //独立模式
  25.     ADC_InitStructure.ADC_ScanConvMode = ENABLE;                                                //扫描模式
  26.     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;                                        //连续转换
  27.     ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //不使用外部触发
  28.     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                //数据右对齐
  29.     ADC_InitStructure.ADC_NbrOfChannel = 16;                                                                //ADC通道数
  30.     ADC_Init ( ADC1, &ADC_InitStructure );

  31.     //规则通道配置
  32.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5 );
  33.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_1, 2, ADC_SampleTime_239Cycles5 );
  34.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_2, 3, ADC_SampleTime_239Cycles5 );
  35.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_3, 4, ADC_SampleTime_239Cycles5 );
  36.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_4, 5, ADC_SampleTime_239Cycles5 );
  37.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_5, 6, ADC_SampleTime_239Cycles5 );
  38.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_6, 7, ADC_SampleTime_239Cycles5 );
  39.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_7, 8, ADC_SampleTime_239Cycles5 );
  40.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_8, 9, ADC_SampleTime_239Cycles5 );
  41.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_9, 10, ADC_SampleTime_239Cycles5 );
  42.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_10, 11, ADC_SampleTime_239Cycles5 );
  43.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_11, 12, ADC_SampleTime_239Cycles5 );
  44.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_12, 13, ADC_SampleTime_239Cycles5 );
  45.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_13, 14, ADC_SampleTime_239Cycles5 );
  46.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_14, 15, ADC_SampleTime_239Cycles5 );
  47.     ADC_RegularChannelConfig ( ADC1, ADC_Channel_15, 16, ADC_SampleTime_239Cycles5 );

  48.    ADC_DMACmd ( ADC1, ENABLE );                                        //使能ADC DMA传输

  49.     ADC_Cmd ( ADC1, ENABLE );                                                //使能ADC1
  50.         
  51.     ADC_ResetCalibration ( ADC1 );                                        //使能复位校准
  52.     while ( ADC_GetResetCalibrationStatus ( ADC1 ) );        //等待复位校准结束
  53.         
  54.     ADC_StartCalibration ( ADC1 );                                        //开启AD校准
  55.     while ( ADC_GetCalibrationStatus ( ADC1 ) );        //等待校准结束
  56. //    ADC_SoftwareStartConvCmd ( ADC1, ENABLE );        //启动转换
  57. }
复制代码

ADC设置为扫描模式,连续转换,16个通道依次扫描采样,一轮采样结束后,接着开启下一轮采样。

  下面初始化DMA功能。

  1. void MYDMA_Config ( DMA_Channel_TypeDef *DMA_CHx, u32 cpar, u32 cmar, u16 cndtr )
  2. {
  3.     DMA_InitTypeDef DMA_InitStructure;
  4.     RCC_AHBPeriphClockCmd ( RCC_AHBPeriph_DMA1, ENABLE );
  5.         
  6.     DMA_DeInit ( DMA_CHx );
  7.         
  8.     DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;                        //外设基地址
  9.     DMA_InitStructure.DMA_MemoryBaseAddr = cmar;                                //内存基地址
  10.     DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                        //数据传输从外设到内存
  11.     DMA_InitStructure.DMA_BufferSize = cndtr;                                        //DMA缓存
  12.     DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;        //外设地址不变
  13.     DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                //内存地址递增
  14.     DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据16位
  15.     DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                        //内存地址1位
  16.     DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                //循环工作模式
  17.     DMA_InitStructure.DMA_Priority = DMA_Priority_High;                        //高优先级
  18.     DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                //没有设置内存到内存传输
  19.         
  20.     DMA_Init ( DMA_CHx, &DMA_InitStructure );
  21. }
复制代码

这里DMA的数据方向要设置为从外设到内存,也就是将外设ADC采样的数据结果保存到内部存储空间中。

初始化完成之后,在主函数中直接启动DMA转换功能。

  1. #define ADC1_DR_Address    ((uint32_t)0x4001244C)
  2. u16 AD_Value[6];
  3. float volta[16];
  4. u8 i, j;
  5. uint16_t ADC1ConvertedValue[10][16];
  6. uint32_t ADC1ConvertedVoltage[16];
  7. int main ( void )
  8. {
  9.     delay_init();       //延时函数初始化
  10.     NVIC_PriorityGroupConfig ( NVIC_PriorityGroup_2 );
  11.     uart_init ( 115200 );
  12.     LED_Init();         //初始化与LED连接的硬件接口
  13.     MYDMA_Config ( DMA1_Channel1, ( u32 ) &ADC1->DR, ( u32 ) &ADC1ConvertedValue, 160 );
  14.     ADC1_Init();
  15.     DMA_Cmd ( DMA1_Channel1, ENABLE );          //启动DMA通道
  16.     ADC_SoftwareStartConvCmd ( ADC1, ENABLE );  //启动ADC1软件转换
  17.     while ( 1 )
  18.     {
  19.         ADC1ConvertedVoltage[0] = 0;
  20.         for ( i = 0; i < 16; i++ )
  21.         {
  22.             ADC1ConvertedVoltage= 0;
  23.             for ( j = 0; j < 10; j++ )                        //采样10次取平均值
  24.             {
  25. ADC1ConvertedVoltage += ADC1ConvertedValue[j];
  26.             }
  27.             ADC1ConvertedVoltage = ADC1ConvertedVoltage / 10;
  28.         }
  29.                 for(i=0;i<16;i++)
  30.                 {
  31.                         volta = ADC1ConvertedVoltage * 3.3 / 4096;
  32.                         printf("AD%2d:  value: %4d  vol: %f\r\n",i,ADC1ConvertedVoltage,volta);

  33.                 }
  34.                  printf ( "\r\n\r\n" );

  35.         LED0 = 0;
  36.         LED1 = 1;
  37.         delay_ms ( 500 ); //延时300ms
  38.         LED0 = 1;
  39.         LED1 = 0;
  40.         delay_ms ( 500 ); //延时300ms
  41.     }
  42. }
复制代码

通过一个二维数据存储16个通道的转换值,每个通道存储10个数据然后取平均值。最后将采样的16个通道值依次打印出来。


收藏 评论0 发布时间:2022-3-20 13:03

举报

0个回答

所属标签

相似分享

官网相关资源

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版