OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 10297|回复: 3

多通道AD采样DMA传输,出现了一点问题,大神指点一下,稍微指点一下就行,想了一下午也没找出毛病来

[复制链接]

13

主题

40

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
344
金钱
344
注册时间
2012-7-13
在线时间
83 小时
发表于 2012-7-28 14:45:47 | 显示全部楼层 |阅读模式
我用ADC1采样0,1,2,3,通道,用的是扫描模式,DMA传输数据,配置DMA时,传输数据应该是1还是4呢(红色的数字),我认为是4可是,液晶显示不行ADC1_MYDMA_Config(DMA1_Channel1,(u32)(&ADC1->DR),(u32)buffer,4);显示图片如下




采样的数据总是四个数据循环显示,只是肿么一回事啊??请各位朋友帮我一下,万分感谢
下面是代码主函数部分
 GLCD_displayStringLn(Line0,"AD TEST");
    ADC1_MYDMA_Config(DMA1_Channel1,(u32)(&ADC1->DR),(u32)buffer,4); 
 Set_Adc_Channel(ADC1_CH0|ADC1_CH1<<5|ADC1_CH2<<10|ADC1_CH3<<15);
// Set_Adc_Channel(ADC1_CH0);
// Set_Adc_Channel(<<5);
// Set_Adc_Channel(ADC1_CH2<<10);
// Set_Adc_Channel(ADC1_CH3<<15);
 ADC1_MYDMA_Enable(DMA1_Channel1);
// AWD_Set_Channel(ADC1_CH1); 
 
//  Get_Adc(ADC1_CH1<<5);
//  Get_Adc(ADC1_CH2<<10); 
//  Get_Adc(ADC1_CH3<<15);
// ADC1->CR2|=1<<22;       //启动规则转换通道 连续转换模式  */ 
           
 while(1)                                     
 { 
// Set_Adc_Channel(ADC1_CH0|ADC1_CH1<<5|ADC1_CH2<<10|ADC1_CH3<<15);     
  
//  ADC1->CR2|=1<<22;    
/*  adcx=Get_Adc(ADC1_CH0);
  GLCD_displayChar(24, 160,adcx/1000+0x30);
  GLCD_displayChar(24, 140,adcx%1000/100+0x30); 
  GLCD_displayChar(24, 120,adcx%100/10+0x30);
  GLCD_displayChar(24, 100,adcx%10+0x30);
  temp=(float)adcx*(3.3/4096);
  adcx=temp;
  GLCD_displayChar(48, 160,adcx%10+0x30);
  temp-=adcx;
  temp*=1000;
  GLCD_displayChar(48, 140,'.');
  GLCD_displayChar(48, 120,(u16)temp/100+0x30); 
  GLCD_displayChar(48, 100,(u16)temp%100/10+0x30);
  GLCD_displayChar(48, 80,(u16)temp%10+0x30); */  
  if(DMA1->ISR&(1<<1))          //等待通道4传输完成
  {
   DMA1->IFCR|=1<<1;           //清除通道1传输完成标志   
            ADC1_MYDMA_Enable(DMA1_Channel1);
   }
   if(ADC1->SR&1<<1)
   {
    ADC1->SR&=~(1<<1);
   }
  GLCD_displayChar(24, 160,buffer[0]/1000+0x30);
  GLCD_displayChar(24, 140,buffer[0]%1000/100+0x30); 
  GLCD_displayChar(24, 120,buffer[0]%100/10+0x30);
  GLCD_displayChar(24, 100,buffer[0]%10+0x30);  
//  temp=(float)buffer[0]*(3.3/4096);
//  buffer[0]=temp;  
//  temp-=buffer[0];
//  temp*=1000;
//   GLCD_displayChar(48, 160,buffer[0]%10+0x30);  //整数部分
//  GLCD_displayChar(48, 140,'.');
//  GLCD_displayChar(48, 120,(u16)temp/100+0x30); 
//  GLCD_displayChar(48, 100,(u16)temp%100/10+0x30);
//  GLCD_displayChar(48, 80,(u16)temp%10+0x30); 
  GLCD_displayChar(72, 160,buffer[1]/1000+0x30);
  GLCD_displayChar(72, 140,buffer[1]%1000/100+0x30); 
  GLCD_displayChar(72, 120,buffer[1]%100/10+0x30);
  GLCD_displayChar(72, 100,buffer[1]%10+0x30);  
//  temp=(float)buffer[1]*(3.3/4096);
//  buffer[1]=temp;  
//  temp-=buffer[1];
//  temp*=1000;
//   GLCD_displayChar(96, 160,buffer[1]%10+0x30);  //整数部分
//  GLCD_displayChar(96, 140,'.');
//  GLCD_displayChar(96, 120,(u16)temp/100+0x30); 
//  GLCD_displayChar(96, 100,(u16)temp%100/10+0x30);
//  GLCD_displayChar(96, 80,(u16)temp%10+0x30); 
  GLCD_displayChar(120, 160,buffer[2]/1000+0x30);
  GLCD_displayChar(120, 140,buffer[2]%1000/100+0x30); 
  GLCD_displayChar(120, 120,buffer[2]%100/10+0x30);
  GLCD_displayChar(120, 100,buffer[2]%10+0x30);  
//  temp=(float)buffer[2]*(3.3/4096);
//  buffer[2]=temp;  
//  temp-=buffer[2];
//  temp*=1000;
//   GLCD_displayChar(144, 160,buffer[2]%10+0x30);  //整数部分
//  GLCD_displayChar(144, 140,'.');
//  GLCD_displayChar(144, 120,(u16)temp/100+0x30); 
//  GLCD_displayChar(144, 100,(u16)temp%100/10+0x30);
//  GLCD_displayChar(144, 80,(u16)temp%10+0x30); 
  GLCD_displayChar(168, 160,buffer[3]/1000+0x30);
  GLCD_displayChar(168, 140,buffer[3]%1000/100+0x30); 
  GLCD_displayChar(168, 120,buffer[3]%100/10+0x30);
  GLCD_displayChar(168, 100,buffer[3]%10+0x30);
   
//  temp=(float)adcx*(3.3/4096);
//  buffer[3]=temp;  
//  temp-=buffer[3];
//  temp*=1000;
//   GLCD_displayChar(192, 160,buffer[3]%10+0x30);  //整数部分
//  GLCD_displayChar(192, 140,'.');
//  GLCD_displayChar(192, 120,(u16)temp/100+0x30); 
//  GLCD_displayChar(192, 100,(u16)temp%100/10+0x30);
//  GLCD_displayChar(192, 80,(u16)temp%10+0x30);   
  
  LED2=!LED2;     
  delay_ms(200);
  下面是ad部分
#include"ADC.h"
#include "sys.h"
#include "led.h"
#include "delay.h"
/********************************
adc驱动代码
初始化adc这里仅以规则通道为例;默认开启通道0~3
********************************/    
void Adc_Init(void)                 
{                     
  RCC->APB2ENR|=1<<2|1<<9; //开启PA时钟 ,以及ADC时钟
  RCC->APB2RSTR|=1<<9;//复位adc1
  RCC->APB2RSTR&=~(1<<9);//复位完成,需要将复位关闭,否则将一直保持复位    
  RCC->CFGR|=1<<15;//设置为6分频给ADC转换时钟        //读取ADC0的值
  GPIOA->CRL&=0XFFFF0000;   //模拟输入   0,1,2,3 
  ADC1->CR2|=1<<20;//允许软件外部触发   
  ADC1->CR2|=1<<19|1<<18|1<<17;//选择为软件触发
 
  ADC1->SQR1&=~(0XF<<20);    //清零重置
  ADC1->SQR1&=3<<20;          //4个转换
  //设置通道0~3的采样时间
  ADC1->SMPR2&=0XFFFFF000;    //通道0,1,2,3,采样时间清空重置
  ADC1->SMPR2|=7<<9;           //通道3,239.5周期,提高采样时间可以提高精度
  ADC1->SMPR2|=7<<6;           //通道2,239.5周期,提高采样时间可以提高精度
  ADC1->SMPR2|=7<<3;           //通道1,239.5周期,提高采样时间可以提高精度
  ADC1->SMPR2|=7<<0;           //通道0,239.5周期,提高采样时间可以提高精度
 
  ADC1->CR2|=1<<0;//开启转换   
  ADC1->CR1|=1<<8;//开启扫描模式  
  ADC1->CR2|=1<<3;//初始化复位校准寄存器
   ADC1->CR2|=1<<8;//允许dma访问
  while(ADC1->CR2&1<<3);  //等待校准结束    
  ADC1->CR2|=1<<2;//开始校准
  while(ADC1->CR2&1<<2);  //等待校准结束
  //ADC1->CR1|=1<<5;//允许中断
  ADC1->CR2|=1<<1;//设置为连续模式
  ADC1->SQR1|=3<<20;//开启4个转换
  ADC1->CR2|=1<<22;//开始规则转换
  // MY_NVIC_Init(2,1,ADC1_2_IRQChannel,2);//设置中断优先级
  ADC1->SQR3=0|1<<5|2<<10|3<<15;  //这个表明在第一规则通道当中,进行转换的将是16通道的数据
 

}
//获得ADC值
//ch:通道值0~3
u16 Get_Adc(u32 ch)
{
 //设置转换序列
 ADC1->SQR3&=0XFFFF8000;      //规则序列1通道0,1,2,3 清除源通道
 ADC1->SQR3|=ch;       //选择转换的通道
 ADC1->CR2|=1<<22;            //启动规则转换通道
 while(!(ADC1->SR&1<<1));     //等待转换结束
 return ADC1->DR;             //返回adc值
}
//设置通道 并启动 只能是0,1,2,3
void Set_Adc_Channel(u32 ch)
{
 ADC1->SQR3&=0XFFFF8000;      //规则序列1通道0,1,2,3 清除源通道
 ADC1->SQR3|=ch;       //选择转换的通道
 ADC1->CR2|=1<<22;            //启动规则转换通道 
}

//设置模拟看门狗的通道
void AWD_Set_Channel(u8 channel)
{
  ADC1->CR1|=channel;
}
//模拟中断服务程序
void ADC1_2_IRQHandler(void)                          
{
  if(ADC1->SR&0X1)
  {
     ADC1->SR&=~(1<<0); 
     test2();
   
  }
}
 
//dma和usart1的数据传输
u16 DMA1_MEM_LEN;  //保存dma每次数据传送的长度
//dma_channel_typedef*dma_chx 应该是结构体指针指向各通道的寄存器地址
//没有配置中断允许位
void  ADC1_MYDMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
    u32 DR_Base;      //作缓冲用,不知道为什么非要不可
    RCC->AHBENR|=1<<0;        //开启DMA1时钟
   
    __nop();                    //等待 DMA1 时钟稳定
       __nop();                    //经测试最少 2 个 nop
       __nop();
    delay_ms(100);      //等待时钟稳定
    DR_Base=cpar;
    DMA_CHx->CPAR=DR_Base;   //DMA1,外设地址
    DMA_CHx->CMAR=(u32)cmar;   //DMA1存储器地址
    DMA1_MEM_LEN=cndtr;    //保存DMA传输数据总量
    DMA_CHx->CNDTR=cndtr;     //dma,传输数据量
    DMA_CHx->CCR=0X00000000;     //复位  以便重新设置
    #ifdef EN_DMA_INTERRUPT
    DMA_CHx->CCR|=1<<1;    //开启传输完成中断
    #endif
    DMA_CHx->CCR&=~(1<<4);           //设置方向,从ADC读数据
    DMA_CHx->CCR|=0<<5;             //非循环模式
    DMA_CHx->CCR|=0<<6;            //外设地址不增
    DMA_CHx->CCR|=1<<7;            //存储器地址曾
    DMA_CHx->CCR|=1<<8;             //外设数据宽度为16位
    DMA_CHx->CCR|=1<<10;           //存储器数据宽度是16位
    DMA_CHx->CCR|=1<<12;             //中等有优先级
    DMA_CHx->CCR|=1<<14;             //非存储器到存储器模式
}
   //开启一次传输
void ADC1_MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)
{
  //只有先关闭DMA传输才能更改寄存器设置
   DMA_CHx->CCR&=~(1<<0);
   DMA_CHx->CNDTR=DMA1_MEM_LEN;
   DMA_CHx->CCR|=1<<0;    //开启DMA传输
}

/*********************************
当测量温度时,跟测其他通道的相似,只不过把取得的电压值转换成
温度值,利用公式转换
*******************************************/
怎样才能将采集到的数据同时显示在液晶屏上;各位朋友指点一下吧。


正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165377
金钱
165377
注册时间
2010-12-1
在线时间
2111 小时
发表于 2012-7-28 16:05:16 | 显示全部楼层
参考下这个:http://www.openedv.com/posts/list/1772.htm#8989
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复 支持 反对

使用道具 举报

38

主题

292

帖子

1

精华

高级会员

Rank: 4

积分
614
金钱
614
注册时间
2012-7-6
在线时间
0 小时
发表于 2012-7-31 15:38:26 | 显示全部楼层
好花,看的我眼睛多快花了
STM32F3系列公司现有货供应!STM32F0,STM32F2,STM32F3,STM32F4 银洋电子专业一级代理http://www.y-ec.com 联系电话:021-53086303  淘宝网:http://y-ec.taobao.com
回复 支持 反对

使用道具 举报

36

主题

1263

帖子

1

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1612
金钱
1612
注册时间
2012-6-15
在线时间
39 小时
发表于 2012-8-2 16:56:29 | 显示全部楼层
你的值的处理上有些不太好,


值的处理
ADChannelNum 为通道数
ADGetTimes 为 每个通道连续采样的次数
ADValues 为DMA接收数据存放的内存区
为 ADChannelNum *ADGetTimes 个

我是用C++写的 可以参考下
对数据的处理, 
void Application::GetADValues(u16 *adv)
{
for(int n=0; n<ADChannelNum; n++)
{
u16 max=ADValues[n], min=ADValues[n],curr;
u32 sum = 0;
for(int i=0; i<ADGetTimes; i++)
{
curr = ADValues[n+i*ADChannelNum] ;
if(min > curr) min = curr;
if(max < curr) max = curr;
sum += curr;
}
sum -= max + min;
adv[n] = sum / (ADGetTimes-2) ;
}
}
为了精度,取每个的平均值,并去掉峰值 放到 adv 里面
u16 V[ADChannelNum ];
调用时候, GetADValues(&V),  就把处理结果放到V里面

//采样次数较多的时候, 可用float/double类型传递,分辨率可更高,

初始化过程:
    /****** ADC初始化 ********
    --通道数 9 采集10次
    --DMA循环采集
    **************************/
DMA1_Channel1->Config(
true, //使能
ADChannelNum*ADGetTimes, //传输数据数量
DMAChannelType::Circular, //循环模式
(u32)&ADC1->DR, //外设地址
(u32)&ADValues, //内存地址
DMAChannelType::ReadFromPhi,         //传输方向
false, //外设增量
true, //内存增量
DMAChannelType:_16b, //外设数据宽度
DMAChannelType:_16b, //内存数据宽度
DMAChannelType:_L, //优先级
DMAChannelType::Null //中断禁止
);
ADC1->Config(ADChannelNum);                            //ADC按默认模式,独立、连续转换
ADC1->RegularChannelConfig( ADCType::Chn_5,  1 );
ADC1->RegularChannelConfig( ADCType::Chn_4,  2 );
ADC1->RegularChannelConfig( ADCType::Chn_1,  3 );
ADC1->RegularChannelConfig( ADCType::Chn_0,  4 );
ADC1->RegularChannelConfig( ADCType::Chn_13, 5 );
ADC1->RegularChannelConfig( ADCType::Chn_12, 6 );
ADC1->RegularChannelConfig( ADCType::Chn_11, 7 );
ADC1->RegularChannelConfig( ADCType::Chn_10, 8 );
ADC1->RegularChannelConfig( ADCType::Chn_16, 9 , ADCType::T_239p5 ); //芯片温度

ADC1->TempAndVrefEnable(true);
ADC1->DMAEnable(true);                                  //使能DMA采集
ADC1->Enable(true);
ADC1->RegularSoftTrigEnable(true);                        //软件触发

ADC1->RstCalibration();                                  //复位校准
while(ADC1->WaitRstCalibration());    
ADC1->Calibration();                                     //校准
while(ADC1->WaitCalibration());

ADC1->RegularSoftTrigEnable(true);                      //必须再次触发 或再次使能也可




回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-2-27 02:48

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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