打印

STM32的ADC通过DMA传送数据丢失了8位

[复制链接]
4467|31
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
siabc|  楼主 | 2013-10-16 22:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 siabc 于 2013-10-27 17:14 编辑

用DMA将ADC的值传回来,只进行了通道一的采样。数据丢了八位,单步调试发现DMA的值位0xff,而直接读ADC->DR的值为0XFFF,调了两周了,后面直接抄的野火的例子还有问题。希望各位大神帮忙看下,感激不尽
#include "stm32f10x.h"
#include "delay.h"
#include "lcd.h"
//定义下面的两个值进行对照比较的
__IO uint16_t AD_Data;//DMA传回的值
unsigned short DATT;//直接读ADC寄存器的值

void GPIO_Configuration(void) //GPIO配置函数
{
      GPIO_InitTypeDef GPIO_Struct;
  
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA,ENABLE);
      RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//打开DMA的时钟,使能DMA传输
      delay_us(3); //等待时钟稳定
      GPIO_Struct.GPIO_Pin=GPIO_Pin_All;
      GPIO_Struct.GPIO_Speed=GPIO_Speed_50MHz;
      GPIO_Struct.GPIO_Mode=GPIO_Mode_Out_PP;
      GPIO_Init(GPIOE,&GPIO_Struct);
      GPIO_Init(GPIOD,&GPIO_Struct);
      GPIO_Struct.GPIO_Pin=GPIO_Pin_1;//只采集ADC1的通道1
      GPIO_Struct.GPIO_Mode=GPIO_Mode_AIN;
     GPIO_Init(GPIOA,&GPIO_Struct);
}
void ADC_Configuration(void) //ADC配置函数
{
      ADC_InitTypeDef ADC_Structure;
      ADC_Structure.ADC_Mode=ADC_Mode_Independent;//独立模式
      ADC_Structure.ADC_ScanConvMode=DISABLE;//单通道模式
      ADC_Structure.ADC_ContinuousConvMode=ENABLE;//循环转换
      ADC_Structure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;//由软件促发
      ADC_Structure.ADC_DataAlign=ADC_DataAlign_Right;//右对齐
      ADC_Structure.ADC_NbrOfChannel=1;//通道数
      ADC_Init(ADC1, &ADC_Structure);

      RCC_ADCCLKConfig(RCC_PCLK2_Div6);//六分频

      ADC_RegularChannelConfig(ADC1,ADC_Channel_1,1,ADC_SampleTime_239Cycles5);//ADC1,ADC通道1,规则采样顺序值为1,采样时间为239.5周期
      ADC_DMACmd(ADC1,ENABLE);//使能ADC的DMA请求
      ADC_Cmd(ADC1,ENABLE);//使能ADC1

      ADC_ResetCalibration(ADC1);//使能复位校准,重置ADC1的校准寄存器
      while(ADC_GetResetCalibrationStatus(ADC1));//等待复位校准结束,获取ADC1重置校准寄存器的状态,设置状态则等待
      ADC_StartCalibration(ADC1); //开始ADC的校准状态
      while(ADC_GetCalibrationStatus(ADC1));//等待校准完成         
      ADC_SoftwareStartConvCmd(ADC1,ENABLE);//使能指定的ADC1的软件转换启动功能
}
void DMA_Configuration(void) //DMA配置函数
{
      DMA_InitTypeDef DMA_Stucture;
      DMA_DeInit(DMA1_Channel1);//设置缺省值
      DMA_Stucture.DMA_PeripheralBaseAddr=0x4001244C;//外设基地址ADC1
      DMA_Stucture.DMA_MemoryBaseAddr=(u32)&AD_Data;//内存地址
      DMA_Stucture.DMA_DIR=DMA_DIR_PeripheralSRC;
      DMA_Stucture.DMA_BufferSize=1;
      DMA_Stucture.DMA_PeripheralInc=DMA_PeripheralInc_Disable;//外设地址不变
      DMA_Stucture.DMA_MemoryInc=DMA_PeripheralInc_Disable;//内存地址不变
      DMA_Stucture.DMA_PeripheralDataSize=DMA_MemoryDataSize_HalfWord; //外设数据为16位
      DMA_Stucture.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;//从外设读到内存的数据的长度为两个字节16位

      DMA_Stucture.DMA_Mode=DMA_Mode_Circular;//循环转换
      DMA_Stucture.DMA_Priority=DMA_Priority_High;//通道1DMA优先级为高等
      DMA_Stucture.DMA_M2M=DMA_M2M_Disable;//禁止由内存到内存的数据传输
      DMA_Init(DMA1_Channel1,&DMA_Stucture);
      DMA_Cmd(DMA1_Channel1,ENABLE);//使能DMA
}
int main(void)
{
      u16 AD=0;
      float temp;
      GPIO_Configuration();
      ADC_Configuration();
      DMA_Configuration();
      while(1)
      {
           while(1)
           {
                  if(DMA_GetFlagStatus(DMA1_FLAG_TC1)==SET) //判断通道1传输完成
                  {
                        temp=(float)AD_DATA*(3.3/4096);//读用DMA传回的数,数值是少了八位
                        AD=(int)(temp*10+0.5);
                        Draw_ASCII(40,110,(AD/10+48),White,Black);//显示函数
                        Draw_ASCII(56,110,(AD%10+48),White,Black); //显示函数
                        DMA_ClearFlag(DMA1_FLAG_TC1);//清除通道1传输完成标志
                        break;
                   }
            }

              DATT=ADC1->DR;//不用DMA直接读ADC的寄存器,数值是正确的
              temp=(double)DATT*(3.3/4096);
              AD=(int)(temp*10+0.5);
              Draw_ASCII(40,130,(AD/10+48),White,Black);//显示函数
              Draw_ASCII(56,130,(AD%10+48),White,Black);//显示函数
              delay_ms(300);
             }
   }

沙发
金融小数| | 2013-10-16 22:38 | 只看该作者
不要用STM32的DMA,那玩意不可靠

使用特权

评论回复
板凳
ticomi| | 2013-10-17 07:31 | 只看该作者
我使用的DMA采集是正常的,前提是在ADC转换完成启动DMA期间必须关中断!

使用特权

评论回复
地板
siabc|  楼主 | 2013-10-17 07:43 | 只看该作者
ticomi 发表于 2013-10-17 07:31
我使用的DMA采集是正常的,前提是在ADC转换完成启动DMA期间必须关中断!

可我整个程序都没用中断啊,都是查询的是否DMA传输完成

使用特权

评论回复
5
596142041| | 2013-10-17 07:46 | 只看该作者
应该是不需要用查询吧!

使用特权

评论回复
6
siabc|  楼主 | 2013-10-17 07:57 | 只看该作者
596142041 发表于 2013-10-17 07:46
应该是不需要用查询吧!

如果不查询,怎么知道DMA是否传输完成呢

使用特权

评论回复
7
ticomi| | 2013-10-17 16:50 | 只看该作者
siabc 发表于 2013-10-17 07:57
如果不查询,怎么知道DMA是否传输完成呢

DMA传输完成会产生中断,不需要实时查询的。

使用特权

评论回复
8
siabc|  楼主 | 2013-10-17 18:09 | 只看该作者
ticomi 发表于 2013-10-17 16:50
DMA传输完成会产生中断,不需要实时查询的。

可如果我没开启DMA的中断呢?只是使能了ADC的DMA请求,那样要不要不要查询呢?我仿真看到DMA传回的数据似乎少了几位,比如说正确的是0x00000fff,而DMA的却是0x000000ff的样子

使用特权

评论回复
9
ticomi| | 2013-10-17 19:43 | 只看该作者
siabc 发表于 2013-10-17 18:09
可如果我没开启DMA的中断呢?只是使能了ADC的DMA请求,那样要不要不要查询呢?我仿真看到DMA传回的数据似 ...

这个可能是设置问题,我不清楚你怎么做的?很疑问为什么不使用中断呢?

使用特权

评论回复
10
siabc|  楼主 | 2013-10-17 21:22 | 只看该作者
ticomi 发表于 2013-10-17 19:43
这个可能是设置问题,我不清楚你怎么做的?很疑问为什么不使用中断呢? ...

确实不用查询也能得到那个结果,不知道为什么

使用特权

评论回复
11
ticomi| | 2013-10-18 07:12 | 只看该作者
siabc 发表于 2013-10-17 21:22
确实不用查询也能得到那个结果,不知道为什么

DMA的工作模式及其工作原理等需要看看就明白了,通常都是DMA采集完成自动产生中断的,这样效率很高的。

使用特权

评论回复
12
siabc|  楼主 | 2013-10-26 16:04 | 只看该作者
各位大神帮帮忙啊,实在没办法了

使用特权

评论回复
13
lllaaa| | 2013-10-26 16:59 | 只看该作者
unsigned char AD_Data;//DMA传回的值

这能是16bit么

使用特权

评论回复
14
siabc|  楼主 | 2013-10-26 18:21 | 只看该作者
lllaaa 发表于 2013-10-26 16:59
unsigned char AD_Data;//DMA传回的值

这能是16bit么

不好意思刚刚编辑的时候没改过来,实际测试时是int型的也不对。。。。

使用特权

评论回复
15
lllaaa| | 2013-10-26 22:12 | 只看该作者
__IO uint16_t AD_Data;

使用特权

评论回复
16
siabc|  楼主 | 2013-10-27 12:33 | 只看该作者
lllaaa 发表于 2013-10-26 22:12
__IO uint16_t AD_Data;

改了,可是还不管用,老问题只有8位,调了两周真的崩溃了

使用特权

评论回复
17
金融小数| | 2013-10-27 12:39 | 只看该作者
已经说过了STM32的DMA不靠谱,你还用,真是无语了!

使用特权

评论回复
18
lllaaa| | 2013-10-27 12:41 | 只看该作者
int main(void)
{
      u8 AD=0;

使用特权

评论回复
19
siabc|  楼主 | 2013-10-27 17:16 | 只看该作者
金融小数 发表于 2013-10-27 12:39
已经说过了STM32的DMA不靠谱,你还用,真是无语了!

可是有人用的没问题啊,不知道我的怎么就不可以

使用特权

评论回复
20
siabc|  楼主 | 2013-10-27 17:18 | 只看该作者
lllaaa 发表于 2013-10-27 12:41
int main(void)
{
      u8 AD=0;

那个变量是用来存放实际转换后的电压值,用char型应该够了,我用了int型也不行

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

6

主题

38

帖子

0

粉丝