野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 11935|回复: 5

多路ADC使用DMA传输时,全速运行时无法读出DMA数组中的数据(已解决)

[复制链接]
发表于 2017-11-3 12:08:33 | 显示全部楼层 |阅读模式
本帖最后由 nanodesu 于 2017-11-6 09:16 编辑

想用多路ADC采集电压值,就创建了一个二维数组,用来存储多次采集的多路电压值。然后用来求平均值,把求出来的值赋给串口发送用数组,之后就通过串口发出来。

现在的问题是
我用断点去看运行到赋给串口发送用数组时,察看那个AD值的二维数组,能看到正确的数据,
继续下一步,下一步,的点也能把这个值赋给串口发送用数组,发送出来。

但是,一旦全速运行串口就收不到采集的值,只能看到0,
而且我试过直接把这个二维数组中有数据的其中那个值放到串口中,全速运行也只能显示0

我在程序的最开始把串口发送数组全赋值为0xffff,然后全速运行,也只能收到0,说明读取二维数组值这块确实是有点什么问题

希望帮忙解答一下是什么问题导致的,谢谢!

这是ADC DMA的配置 汉字是乱码就去掉了,跟着例程抄的。
  1. DMA_InitTypeDef DMA_InitStructure;
  2.         ADC_InitTypeDef ADC_InitStructure;
复制代码
这就是那个二维数组
  1. __IO uint16_t ADC_ConvertedValue[5][14];
复制代码




回复

使用道具 举报

 楼主| 发表于 2017-11-3 12:11:37 | 显示全部楼层
配置函数没显示出来完整,但是自己也检查过几遍,没有问题的。毕竟在用断点的时候是能看到正确的AD值的。
回复 支持 反对

使用道具 举报

发表于 2017-11-3 14:05:05 | 显示全部楼层
检查一下ADC初始化结构体是不是对每个结构体成员都有赋予初始值
回复 支持 反对

使用道具 举报

 楼主| 发表于 2017-11-6 09:15:22 | 显示全部楼层
从新建了个工程,就没有出现这个问题了
估计是由于原来那个工程是在其他工程基础上修改来用的,所以在代码逻辑上出了什么问题。
至于到底是哪里有问题我也不清楚···
回复 支持 反对

使用道具 举报

发表于 2017-11-8 15:55:18 | 显示全部楼层
我这找到了一个ADC 使用DMA的代码,简单改了改挺好的!
回复 支持 反对

使用道具 举报

发表于 2017-11-8 15:55:44 | 显示全部楼层
  1. /*****************************************************************
  2. 四路ADC采用连续转换 扫描模式,每路采集100个值后开启DMA中断,
  3. 在DMA中断中进行平均值滤波处理
  4. *****************************************************************/

  5. #include "ADC.h"
  6. #include "delay.h"

  7. uint16_t ADC_ConvertedValue[4]={0,0,0,0}; // ADC1转换的电压值通过 MDA 方式传到 SRAM
  8. float ADC_ConvertedValueLocal[4];        //转换后电压值

  9. uint16_t AD_Value[100][4];        //AD采样值
  10. uint16_t After_filter[4];        //AD滤波后

  11. uint16_t TEMP0,TEMP1;        //左侧,右侧设置温度值

  12. float Temp[4] ={0};//转换后温度值
  13. u8 TempValue_change = 0;//采集的值变化标志位

  14. /**
  15.   * @brief  ADC GPIO 初始化
  16.   * @param  无
  17.   * @retval 无
  18.   */
  19. static void ADC1_GPIO_Config(void)        //使用ADC1的channel 10,11,12,13,IO口为PC0~PC3
  20. {
  21.         GPIO_InitTypeDef GPIO_InitStructure;
  22.        
  23.         // 打开 ADC IO端口时钟
  24.         RCC_APB2PeriphClockCmd (RCC_APB2Periph_GPIOC, ENABLE);
  25.        
  26.         // 配置 ADC IO 引脚模式
  27.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;        //TC1
  28.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;        //TC2
  29.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;        //ADC1
  30.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;        //ADC2

  31.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
  32.        
  33.         // 初始化 ADC IO
  34.         GPIO_Init(GPIOC, &GPIO_InitStructure);                               
  35. }


  36. /**
  37.   * @brief  配置DMA1工作模式
  38.   * @param  无
  39.   * @retval 无
  40.   */
  41. static void DMA1_Mode_Config(void)
  42. {
  43.         DMA_InitTypeDef DMA_InitStructure;
  44.        
  45.         RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);// 打开DMA时钟
  46.        

  47.         DMA_DeInit(DMA1_Channel1);        // 复位DMA控制器
  48.        
  49.         // 配置 DMA 初始化结构体
  50.         DMA_InitStructure.DMA_PeripheralBaseAddr = ((uint32_t)0x40012400+0x4c);                // 外设基址为:ADC 数据寄存器地址       
  51.         DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&AD_Value;                                                                // 存储器地址               
  52.         DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                                                                                                // 数据源来自外设       
  53.         DMA_InitStructure.DMA_BufferSize = 400;                                                                                                                                                // 缓冲区大小,应该等于数据目的地的大小       
  54.         DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                                        // 外设寄存器只有一个,地址不用递增
  55.         DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                                                                         // 存储器地址递增       
  56.         DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;// 外设数据大小为半字,即两个字节       
  57.         DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;                                // 内存数据大小也为半字,跟外设数据大小相同               
  58.         DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                                                                                                                // 循环传输模式       
  59.         DMA_InitStructure.DMA_Priority = DMA_Priority_High;                // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
  60.         DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                                                                                                        // 禁止存储器到存储器模式,因为是从外设到存储器
  61.                
  62.         DMA_Init(DMA1_Channel1, &DMA_InitStructure);                        // 初始化DMA
  63.         DMA_Cmd(DMA1_Channel1 , ENABLE);                                                                        // 使能 DMA 通道
  64.         DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);               
  65. }

  66. static void DMA1_NVIC_Config(void)
  67. {
  68.         NVIC_InitTypeDef NVIC_InitStructure;
  69.        
  70.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);//中断组为1,2个抢占优先级,8个响应优先级
  71.        
  72.         NVIC_InitStructure.NVIC_IRQChannel =        DMA1_Channel1_IRQn;       
  73.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;       
  74.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0; //抢占优先级       
  75.         NVIC_InitStructure.NVIC_IRQChannelSubPriority =3; //响应优先级

  76.         NVIC_Init(&NVIC_InitStructure);
  77. }

  78. /**
  79.   * @brief  配置ADC工作模式
  80.   * @param  无
  81.   * @retval 无
  82.   */
  83. static void ADC1_Mode_Config(void)
  84. {
  85.        
  86.         ADC_InitTypeDef ADC_InitStructure;
  87.        
  88.         RCC_APB2PeriphClockCmd (RCC_APB2Periph_ADC1, ENABLE);        // 打开ADC时钟
  89.        
  90.         // ADC 模式配置
  91.         ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        // 只使用一个ADC,属于单模式
  92.         ADC_InitStructure.ADC_ScanConvMode = ENABLE ;                                // 扫描模式
  93.         ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;        // 连续转换模式,
  94.         ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        // 不用外部触发转换,软件开启即可
  95.         ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                                        // 转换结果右对齐
  96.         ADC_InitStructure.ADC_NbrOfChannel = 4;                                                                                                                        // 转换通道个数
  97.                
  98.        
  99.         ADC_Init(ADC1, &ADC_InitStructure);        // 初始化ADC
  100.        
  101.         RCC_ADCCLKConfig(RCC_PCLK2_Div6); // 配置ADC时钟为CLK2的8分频,即9MHz 确保ADC时钟不超过14M
  102.        
  103.         // 配置ADC 通道的转换顺序和采样时间
  104.         ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_239Cycles5);  //PC0 ->TC1
  105.         ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_239Cycles5);        //PC1 ->TC2
  106.         ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_239Cycles5);        //PC2        ->ADC1
  107.         ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_239Cycles5);        //PC3 ->ADC2
  108.                
  109.         ADC_DMACmd(ADC1, ENABLE);                                // 使能ADC DMA 请求
  110.         ADC_Cmd(ADC1, ENABLE);                                        // 开启ADC ,并开始转换
  111.        
  112.         /* 必须执行复位校准和AD校准,不准将导致结果不准确*/
  113.        
  114.         ADC_ResetCalibration(ADC1);                        // 初始化ADC 复位校准寄存器  
  115.         while(ADC_GetResetCalibrationStatus(ADC1));// 等待校准寄存器初始化完成
  116.         ADC_StartCalibration(ADC1);                                                                        // ADC开始校准
  117.         while(ADC_GetCalibrationStatus(ADC1));                  // 等待校准完成
  118.                
  119.         ADC_SoftwareStartConvCmd(ADC1, ENABLE);        // 由于没有采用外部触发,所以使用软件触发ADC转换
  120. }

  121. /**
  122.   * @brief  ADC初始化
  123.   * @param  无
  124.   * @retval 无
  125.   */
  126. void ADC1_Init(void)
  127. {
  128.   DMA1_Mode_Config();
  129.   DMA1_NVIC_Config();
  130.         ADC1_GPIO_Config();
  131.         ADC1_Mode_Config();
  132. }

  133. void filter(void)                //在中断中滤波
  134. {
  135.         int sum = 0;
  136.         u8 count,i;
  137.         for(i=0;i<4;i++)
  138.         {
  139.                 for(count=0;count<100;count++)
  140.                 {
  141.                         sum += AD_Value[count][i];
  142.                 }
  143.                 After_filter[i] = sum/100;
  144.                 sum = 0;
  145.         }
  146.         TEMP0 =         After_filter[0]*70/4096;        //左侧设置温度值
  147.         TEMP1 =         After_filter[1]*70/4096;        //右侧设置温度值
  148.         TempValue_change =1;
  149. }


  150. void DMA1_Channel1_IRQHandler(void)
  151. {
  152.         if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)
  153.         {
  154.                 filter();
  155.                 DMA_ClearITPendingBit(DMA1_IT_TC1);
  156.         }
  157. }


  158. void Get_ADC()        //换算电压值(调试用)
  159. {
  160.         int i = 0;
  161. //        for(i = 0;i<2;i++)
  162. //        {
  163. //                ADC_ConvertedValueLocal[i] =(float) ADC_ConvertedValue[i]/4096*3.22;                //设置电压值
  164. //        }
  165.         for(i=2;i<4;i++)
  166.         {
  167.                 ADC_ConvertedValueLocal[i] =(float) After_filter[i]/4096*3.20;        //实际电压值
  168.         }
  169. }
  170. /*********************************************END OF FILE**********************/













复制代码
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2025-1-17 01:30 , Processed in 0.056297 second(s), 23 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表