OpenEdv-开源电子网

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

ADC+DMA转换中DMA设值问题;

[复制链接]

3

主题

7

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2012-12-31
在线时间
0 小时
发表于 2014-6-23 15:52:18 | 显示全部楼层 |阅读模式
5金钱
思路:使用战舰开发板对原子的ADC实验进行验证,后改用开发板P3接口的ADC通道采集一组32个点的数值后,再在LCD上显示波形;
存在的情况:用ADC直接读取32个数值,填入数组,再将该数组逐点在LCD上画出,正确!
                   用DMA方式将ADC转换值存入数组:出错;存入的值要么超过4096,要么是0;
关于程序:
   主程序中:分别可以用ADC直接读取或DMA,只要注释掉相应的行就好了;对原子ADC实验例程里的ADC相关函数有简单的改动,但不影响ADC直接读取结果的正确性。也就是问题出在DMA相关部分;看了网站上很多相关的帖子了,也修改过,实在是找不到错误原因了。。请各位牛人和原子兄百忙中帮忙看看,谢谢了。

又:采集信号我用的是5Khz的正弦信号,该波形Vol=0v,Voh=3V,从开发板P3接口的ADC插针输入;附件中的程序可以直接在战舰开发板上运行。

ADC实验 - test - 副本.rar

2.28 MB, 下载次数: 593

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

使用道具 举报

3

主题

7

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2012-12-31
在线时间
0 小时
 楼主| 发表于 2014-6-23 15:57:57 | 显示全部楼层
主要程序如下:
main.c:

#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "lcd.h"
#include "usart.h"  
#include "adc.h"
#include "dma.h"
//ALIENTEK战舰STM32开发板实验17
//ADC 实验  
//技术支持:www.openedv.com
//广州市星翼电子科技有限公司   



 int main(void)
 {
  u32  adcx[32];
// u32 adcx;
    int i;
int x_position;
   // u16 adcxtemp;
u16 adc_disp_v;
// float temp;
delay_init();     //延时函数初始化  
NVIC_Configuration(); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(9600); //串口初始化为9600
  LED_Init();     //LED端口初始化
LCD_Init();  
  MYDMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)adcx,32);//DMA1通道1,外设为ADC1,存储器为adcx,长度32.
Adc_Init();

x_position=0;

for(i=0;i<32;i++) adcx=Get_Adc(ADC_Channel_1); //直接读取ADC转换值,正确;此时注释下面2句DMA语句;

   // ADC_DMACmd(ADC1,ENABLE); //此时注释上面ADC读取语句;
   //  MYDMA_Enable(DMA1_Channel1);
for(i=0;i<32;i++)
{
LCD_ShowxNum(156,x_position,adcx,4,16,0);//显示ADC的值  
adc_disp_v=(adcx*240)/4096;
    LCD_ShowString( adc_disp_v,x_position,200,16,16,"*");
x_position+=10;
LED0=!LED0;  
delay_ms(100);
}
 }


dam.c:

#include "dma.h"
//////////////////////////////////////////////////////////////////////////////////  
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//DMA 代码   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/8
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved  
//////////////////////////////////////////////////////////////////////////////////

DMA_InitTypeDef DMA_InitStructure;

u16 DMA1_MEM_LEN;//保存DMA每次数据传送的长度    
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHxMA通道CHx
//cpar:外设地址
//cmar:存储器地址
//cndtr:数据传输量 
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输

    DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值
DMA1_MEM_LEN=cndtr;
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar;  //DMA外设ADC基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar;  //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,外设作为DMA传输的源地;
DMA_InitStructure.DMA_BufferSize = cndtr;  //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增   
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;  //数据宽度为8位8->32 by  zsxhie;
DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为8位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;  //工作在正常缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级 
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
 

//开启一次DMA传输
void MYDMA_Enable(DMA_Channel_TypeDef*DMA_CHx)

DMA_Cmd(DMA_CHx, DISABLE );  //关闭USART1 TX DMA1 所指示的通道      
  DMA_SetCurrDataCounter(DMA1_Channel1,DMA1_MEM_LEN);//DMA通道的DMA缓存的大小
  DMA_Cmd(DMA_CHx, ENABLE);  //使能USART1 TX DMA1 所指示的通道 
}  

ADC.c:
#include "adc.h"
 #include "delay.h"
//////////////////////////////////////////////////////////////////////////////////  
//本程序只供学习使用,未经作者许可,不得用于其它任何用途
//ALIENTEK战舰STM32开发板
//ADC 代码   
//正点原子@ALIENTEK
//技术论坛:www.openedv.com
//修改日期:2012/9/7
//版本:V1.0
//版权所有,盗版必究。
//Copyright(C) 广州市星翼电子科技有限公司 2009-2019
//All rights reserved  
////////////////////////////////////////////////////////////////////////////////// 
  
  
//初始化ADC
//这里我们仅以规则通道为例
//我们默认将开启通道0~3   
void  Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure; 
GPIO_InitTypeDef GPIO_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |RCC_APB2Periph_ADC1 , ENABLE );  //使能ADC1通道时钟
 

RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M

//PA1 作为模拟通道输入引脚                         
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);

ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值

ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADC1和ADC2工作在独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //模数转换工作在单次转换模式 ->连续(zshxie)
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目
ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器  

//直接配置,避免一直配置的时间; 
//设置指定ADC的规则组通道,一个序列,采样时间
   
  ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_239Cycles5);//直接指定通道 zshxie

// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能

   //由zshxie 由别的函数移动到此处47 49的位置;
  
ADC_Cmd(ADC1, ENABLE); //使能指定的ADC1

ADC_ResetCalibration(ADC1); //使能复位校准  
 
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束

ADC_StartCalibration(ADC1); //开启AD校准
 
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
 
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能

}  
//获得ADC值
//ch:通道值 0~3
u16 Get_Adc(u8 ch)   
{
  //设置指定ADC的规则组通道,一个序列,采样时间
// ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_239Cycles5 ); //ADC1,ADC通道,采样时间为239.5周期      
  
// ADC_SoftwareStartConvCmd(ADC1, ENABLE); //使能指定的ADC1的软件转换启动功能
 
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

return ADC_GetConversionValue(ADC1); //返回最近一次ADC1规则组的转换结果
}

u16 Get_Adc_Average(u8 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}  

请大家帮忙看看问题在哪里。ADC使用的是ADC1通道1,DMA使用的也是DMA1通道1;

回复

使用道具 举报

1

主题

17

帖子

0

精华

新手上路

积分
41
金钱
41
注册时间
2013-10-20
在线时间
0 小时
发表于 2014-6-23 19:56:13 | 显示全部楼层
你的存数据的数组怎么是32位型的数据
每天都在进步,这就是成长,哪怕一点点总比没有或者倒退好!!!
回复

使用道具 举报

3

主题

7

帖子

0

精华

新手上路

积分
40
金钱
40
注册时间
2012-12-31
在线时间
0 小时
 楼主| 发表于 2014-6-23 20:18:52 | 显示全部楼层
U32用ADC直存是可以的,DMA时,改成U16也是不行。
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165359
金钱
165359
注册时间
2010-12-1
在线时间
2110 小时
发表于 2014-6-23 22:28:47 | 显示全部楼层
回复【4楼】zshxie:
---------------------------------
论坛不是有很多ADC DMA的例程么?
你先搞通ADC DMA。
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

13

主题

206

帖子

1

精华

高级会员

Rank: 4

积分
613
金钱
613
注册时间
2014-10-26
在线时间
32 小时
发表于 2015-5-9 16:46:02 | 显示全部楼层
奇怪,我移植你的程序,可以有数据出来啊~
学习!
回复

使用道具 举报

0

主题

1

帖子

0

精华

新手上路

积分
25
金钱
25
注册时间
2014-9-9
在线时间
1 小时
发表于 2015-5-13 14:12:02 | 显示全部楼层
MINI板可以用不
回复

使用道具 举报

4

主题

24

帖子

1

精华

中级会员

Rank: 3Rank: 3

积分
223
金钱
223
注册时间
2015-8-13
在线时间
6 小时
发表于 2015-11-14 21:16:12 | 显示全部楼层
同学我和你一样的思路。。读出的数字电压值没有一个超过255的。。把3.3V电压接上了测出的还是255.。。感觉12位ADC变8位了/。。。
回复

使用道具 举报

2

主题

7

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2015-4-11
在线时间
4 小时
发表于 2017-5-8 22:52:41 | 显示全部楼层
菜鸟520 发表于 2015-11-14 21:16
同学我和你一样的思路。。读出的数字电压值没有一个超过255的。。把3.3V电压接上了测出的还是255.。。感觉1 ...

需要设置PSIZE[1:0]:外设数据宽度 (Peripheral size)  位9:8
这些位由软件设置和清除。
00:8位
01:16位
10:32位
11:保留

把PSIZE[1:0]设置成01
回复

使用道具 举报

5

主题

69

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
374
金钱
374
注册时间
2014-2-13
在线时间
98 小时
发表于 2017-7-23 06:25:56 | 显示全部楼层
楼主,问题是怎么解决的?我也遇到同样的麻烦,20多天没有进展
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2024-12-23 02:17

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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