OpenEdv-开源电子网

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

关于ADC与DMA中断的问题(菜鸟求指教)

[复制链接]

4

主题

14

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2016-5-31
在线时间
7 小时
发表于 2016-5-31 15:46:32 | 显示全部楼层 |阅读模式
下面的程序功能为从ADC采集一个电压,传输给DMA,传输完成后(10次)产生中断,将数据转换发给串口:可串口采集的值完全不对,且恒定(无论adc输入值)
[mw_shl_code=c,true]#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "sys.h"
#include "stdio.h"

#ifndef __ver_
#define __ver_
#define data_deep 10   //传输深度
u16 databuffer[data_deep];  //存储数组
#endif

void mydma_init0(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr);
void mydma_enble(DMA_Channel_TypeDef*DMA_CHx,u16 DMA1_MEM_LEN);
void Adc_Init(void);

int  main(void)
{

        delay_init();
        uart_init(9600);  

        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);

        Adc_Init();       //adc初始化

        ADC_RegularChannelConfig(ADC1,ADC_Channel_0,0x01,ADC_SampleTime_239Cycles5);

        mydma_init0(DMA1_Channel1,(u32)&ADC1->DR,(u32)databuffer,data_deep);
        mydma_enble(DMA1_Channel1,data_deep);
       
        /*********软件启动**********/
        ADC_SoftwareStartConvCmd(ADC1,ENABLE);
        while(1);
}

/**************************************************
*****************ADC初始化*********************
***************************************************/

void Adc_Init(void)
{
        GPIO_InitTypeDef GPIO_InitTypeDefstructure;
        ADC_InitTypeDef ADC_InitTypeDefstrcuture;
       
        /****step1:使能时钟*************/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO,ENABLE);       
       
        /****step2: IO口初始化**************************/
        GPIO_InitTypeDefstructure.GPIO_Mode=GPIO_Mode_AIN;
        GPIO_InitTypeDefstructure.GPIO_Pin=GPIO_Pin_0;
        GPIO_InitTypeDefstructure.GPIO_Speed=GPIO_Speed_50MHz;
        GPIO_Init(GPIOA,&GPIO_InitTypeDefstructure);
       
        /****step3: 预分频*********************/
        ADC_DeInit(ADC1);
        RCC_ADCCLKConfig(RCC_PCLK2_Div6);
       
        /*****step4: *****************/
        ADC_InitTypeDefstrcuture.ADC_ContinuousConvMode=ENABLE;       //á¬Dø×a»»
        ADC_InitTypeDefstrcuture.ADC_DataAlign=ADC_DataAlign_Right;
        ADC_InitTypeDefstrcuture.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
        ADC_InitTypeDefstrcuture.ADC_Mode=ADC_Mode_Independent;
        ADC_InitTypeDefstrcuture.ADC_NbrOfChannel=1;
        ADC_InitTypeDefstrcuture.ADC_ScanConvMode=DISABLE;
        ADC_Init(ADC1,&ADC_InitTypeDefstrcuture);
       
        ADC_DMACmd(ADC1,ENABLE);  //使能adc DMA
       
       
        ADC_Cmd(ADC1,ENABLE);     //step5:使能ADC*********/
       
        ADC_ResetCalibration(ADC1); //校准
        while(ADC_GetCalibrationStatus(ADC1));
        ADC_StartCalibration(ADC1);
        while(ADC_GetCalibrationStatus(ADC1));
       
        ADC_RegularChannelConfig(ADC1,ADC_Channel_0,0x01,ADC_SampleTime_239Cycles5); //通道配置
        ADC_SoftwareStartConvCmd(ADC1,ENABLE);   //软
       
}
/**************************************************
*****************DMA初始化********************
***************************************************/
void mydma_init0(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
        DMA_InitTypeDef DMA_InitTypeDefstructure;
        NVIC_InitTypeDef NVIC_InitTypeDefstructure;
       
        /*******时钟************/
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
       
        /******************/
        DMA_DeInit(DMA_CHx);   
       
        /********* ***********/
        DMA_InitTypeDefstructure.DMA_BufferSize=cndtr;          //  data_deep
        DMA_InitTypeDefstructure.DMA_DIR=DMA_DIR_PeripheralSRC; // ′óíaéè¶áè¡êy¾Y
        DMA_InitTypeDefstructure.DMA_M2M=DMA_M2M_Disable;
        DMA_InitTypeDefstructure.DMA_MemoryBaseAddr=cmar;       //memory_ad
        DMA_InitTypeDefstructure.DMA_MemoryDataSize=DMA_PeripheralDataSize_HalfWord;      //data_size
        DMA_InitTypeDefstructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
        DMA_InitTypeDefstructure.DMA_Mode=DMA_Mode_Circular;//DMA_Mode_Circular
        DMA_InitTypeDefstructure.DMA_PeripheralBaseAddr=cpar;         //periph_ad
        DMA_InitTypeDefstructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;  //periph dataSize 16bit
        DMA_InitTypeDefstructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
        DMA_InitTypeDefstructure.DMA_Priority=DMA_Priority_VeryHigh;  
        DMA_Init(DMA_CHx,&DMA_InitTypeDefstructure);

/**********中断使能**********************/
        DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);   //tran_finish
/***********************************************/

/******中断分组********/
        NVIC_InitTypeDefstructure.NVIC_IRQChannel=DMA1_Channel1_IRQn ;
        NVIC_InitTypeDefstructure.NVIC_IRQChannelCmd=ENABLE;
        NVIC_InitTypeDefstructure.NVIC_IRQChannelPreemptionPriority=3;
        NVIC_InitTypeDefstructure.NVIC_IRQChannelSubPriority=2;
        NVIC_Init(&NVIC_InitTypeDefstructure);
/**************************************/
}



/*********一次DMA传输***********/
void mydma_enble(DMA_Channel_TypeDef*DMA_CHx,u16 DMA1_MEM_LEN)
{

        DMA_Cmd(DMA_CHx,DISABLE);
        DMA_CHx->CNDTR=DMA1_MEM_LEN;
        DMA_Cmd(DMA_CHx,ENABLE);
}


/********************************
******************
*********************************/
void DMA1_Channel1_IRQHandler(void)
{
        u8 i;
        float temp[data_deep]={0};
        if(DMA_GetFlagStatus(DMA1_FLAG_TC1)!=RESET)
        {
                        ADC_DMACmd(ADC1,DISABLE);         //disable the adc_dma request
                  DMA_Cmd(DMA1_Channel1,DISABLE);   //close DMA_channel1
                       
                        for(i=0;i<data_deep;i++)
                        {
                                temp=databuffer*(3.3/4096);       
                                printf("\n ADC2é&#209;ùμ&#231;&#209;1V=%f\n\r",temp);
                        }
                        printf("\r\n----------\r\n");
                       
                        DMA_ClearFlag(DMA1_FLAG_TC1);   //clear the flag
                        ADC_DMACmd(ADC1,ENABLE);        //enable the adc_dma request
                  DMA_Cmd(DMA1_Channel1,ENABLE);  //enable DMA_channel1
        }
               
}
[/mw_shl_code]
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11546
金钱
11546
注册时间
2014-4-1
在线时间
1315 小时
发表于 2016-5-31 16:42:30 | 显示全部楼层

仿真器,直接观察ADC结果,
不正常则先查ADC,正常则查DMA。
把两件事分开来。


回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2016-5-31
在线时间
7 小时
 楼主| 发表于 2016-5-31 22:25:40 | 显示全部楼层
xuande 发表于 2016-5-31 16:42
仿真器,直接观察ADC结果,
不正常则先查ADC,正常则查DMA。
把两件事分开来。

查了一下,ADC部分是正确的。有个问题请教一下,请问程序中中断部分的程序有问题吗,能不能如程序中那样直接用"temp=(float)databuffer*(3.3/4096)“将内存中的数据进行电压值转换,然后发送给串口呢?如果不行,该如何取出处理内存中码值进行电压转换呢?谢谢!总感觉中断函数部分有问题,通过串口传输的值不对。谢谢!
回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2016-5-31
在线时间
7 小时
 楼主| 发表于 2016-5-31 22:28:59 | 显示全部楼层
xuande 发表于 2016-5-31 16:42
仿真器,直接观察ADC结果,
不正常则先查ADC,正常则查DMA。
把两件事分开来。

void DMA1_Channel1_IRQHandler(void)
{
    u8 i;
    float temp[data_deep]={0};
    if(DMA_GetFlagStatus(DMA1_FLAG_TC1)!=RESET)
    {
            ADC_DMACmd(ADC1,DISABLE);         //disable the adc_dma request
          DMA_Cmd(DMA1_Channel1,DISABLE);   //close DMA_channel1
            
            for(i=0;i<data_deep;i++)
            {
                temp=databuffer*(3.3/4096);   //取内存中码值进行电压转换
                printf("\n电压值=%f\n\r",temp);  //通过串口发送电压值
            }
            printf("\r\n----------\r\n");
            
            DMA_ClearFlag(DMA1_FLAG_TC1);   //clear the flag
            ADC_DMACmd(ADC1,ENABLE);        //enable the adc_dma request
          DMA_Cmd(DMA1_Channel1,ENABLE);  //enable DMA_channel1
    }
         
}
回复 支持 反对

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11546
金钱
11546
注册时间
2014-4-1
在线时间
1315 小时
发表于 2016-5-31 22:37:27 | 显示全部楼层

                temp[i]=databuffer[i]*(3.3/4096);   
                printf("\n ADC2é&#209;ùμ&#231;&#209;1V=%f\n\r",temp[i]);

temp【i】是浮点数?
这两句恐怕有问题。

回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2016-5-31
在线时间
7 小时
 楼主| 发表于 2016-6-2 16:15:47 | 显示全部楼层
xuande 发表于 2016-5-31 22:37
temp=databuffer*(3.3/4096);   
                printf("\n ADC2é&#209;ùμ&#231;& ...

写错了,是这样的  temp=(float)databuffer*(3.3/4096);  但是问题还是和原来的一致
回复 支持 反对

使用道具 举报

58

主题

6294

帖子

1

精华

资深版主

Rank: 8Rank: 8

积分
11546
金钱
11546
注册时间
2014-4-1
在线时间
1315 小时
发表于 2016-6-2 16:19:50 | 显示全部楼层

注意printf这一句,printf("\n电压值=%f\n\r",temp);

temp是几个字节?一条printf可以发送多个字节吗?
我不了解printf的内容,提醒你搞清楚。


回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2016-5-31
在线时间
7 小时
 楼主| 发表于 2016-6-2 16:22:23 | 显示全部楼层
xuande 发表于 2016-6-2 16:19
注意printf这一句,printf("\n电压值=%f\n\r",temp);

temp是几个字节?一条printf可以发送多个字节吗 ...

谢谢
回复 支持 反对

使用道具 举报

4

主题

14

帖子

0

精华

新手上路

积分
46
金钱
46
注册时间
2016-5-31
在线时间
7 小时
 楼主| 发表于 2016-6-2 21:44:39 | 显示全部楼层

问题已解决,中断函数没有问题,输出显示也没有问题。问题出在DMA配置中,太粗心了。谢谢
回复 支持 反对

使用道具 举报

7

主题

25

帖子

0

精华

初级会员

Rank: 2

积分
72
金钱
72
注册时间
2015-7-17
在线时间
1 小时
发表于 2016-6-11 09:55:44 | 显示全部楼层
潇湘残狼 发表于 2016-6-2 21:44
问题已解决,中断函数没有问题,输出显示也没有问题。问题出在DMA配置中,太粗心了。谢谢

请问你的adc配置出了什么问题
回复 支持 反对

使用道具 举报

1

主题

6

帖子

0

精华

新手上路

积分
20
金钱
20
注册时间
2016-6-7
在线时间
4 小时
发表于 2016-6-11 12:35:07 | 显示全部楼层
zhongzhaoji 发表于 2016-6-11 09:55
请问你的adc配置出了什么问题

DMA_InitTypeDefstructure.DMA_MemoryDataSize=DMA_PeripheralDataSize_HalfWord;      //data_size
    DMA_InitTypeDefstructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
    DMA_InitTypeDefstructure.DMA_Mode=DMA_Mode_Circular;//DMA_Mode_Circular
    DMA_InitTypeDefstructure.DMA_PeripheralBaseAddr=cpar;         //periph_ad
    DMA_InitTypeDefstructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord;  //periph dataSize 16bit

注意第一句和最后一句设置一样了,第一句应该是DMA_MemorylDataSize_HalfWord
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-10 15:07

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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