单通道ADC采用DMA传输(寄存器版)

2019-08-20 19:22发布

参考论坛@linshisong 大神的程序写的寄存器版本,因为自己需要用到ADC+DMA,而且这个也研究了挺久的。
先说一下我遇到的问题:
1.我是在原来自己写的代码的基础上改的,然后ADC没有设置成连续转换模式,需要开启连续转换模式ADC才会连续不断的给DMA发送启动信号,
不然就要在循环里面一直等待AD转换完成然后开启下一次转换。
2.DMA如果没有设置成循环模式,就需要在DMA的中断里面不断重装缓存值(DMA1_Channel1->CNDTR)。
3.外设地址的写法:(u32)(&ADC1->DR)。
希望可以帮到大家,因为一直都是伸手党,现在也来贡献一下。
[mw_shl_code=applescript,true]#include "adc.h"
#include "stm32f10x.h"                  // Device header
#include "usart.h"
#include "led.h"

extern volatile u16 SendBuff[SEND_BUF_SIZE];//AD转换保存的数据


void adc1_in1_init(void)
{
        RCC->APB2ENR |= 1<<2;//开启PA口时钟
        RCC->APB2ENR |= 1<<9;//开启ADC1时钟
        /*修改*/
        GPIOA->CRL &= ~(0xFF<<(1*4));//PA1口配置为模拟输入
       
        RCC->CFGR &= ~(3<<14);
        RCC->CFGR |=  (2<<14);//选择6分频,72/6=12MHz
       
        RCC->APB2RSTR |=  (1<<9);//复位ADC1模块
        RCC->APB2RSTR &= ~(1<<9);//复位完成
       
        ADC1->CR1 &= ~(1<<23);   //在规则通道上禁用模拟看门狗
        ADC1->CR1 &= ~(1<<22);   //在注入通道上禁用模拟看门狗
        ADC1->CR1 &= ~(0xF<<16); //独立模式
       
        ADC1->CR2 |= 1<<20;//开启规则通道外部触发
        ADC1->CR2 |= 7<<17;//规则通道可以通过SWSTART来开启转换
        ADC1->CR2 &= ~(1<<15);//不开启注入通道外部触发
       
        ADC1->CR2 &= ~(1<<11);//数据右对齐
        ADC1->CR2 |=   1<<1;  //ADC工作在连续模式
        /*修改*/
        ADC1->SMPR2 &= ~(0x7<<3);
        ADC1->SMPR2 |=  (0x7<<3);//设置通道1采样时间为239.5个周期
       
        ADC1->SQR1 &= ~(0xF<<20);//设置规则组的有一个通道转换
        /*修改*/
        ADC1->SQR3 &= ~(0x1F<<(0*5));
        ADC1->SQR3 |= 0x1<<(0*5);//通道1第一个转换
       
        ADC1->CR2 |= 0x1<<8;   //使用DMA模式
       
        ADC1->CR2 |= 1<<0;   //ADC1进入断电模式,等待唤醒
        delay_us(10);
       
        ADC1->CR2 |= 1<<3;  //初始化校准寄存器
        while(ADC1->CR2 & (1<<3));//等待校准寄存器初始化完成
       
        ADC1->CR2 |= 1<<2;  //开始校准
        while(ADC1->CR2 & (1<<2));//等待校准完成
       
        ADC1->CR2 |= 1<<22;   //开启ADC并开始转换
}
  
/*****************************************
函数:MYDMA1_CH1_Config(u32 src_addr,u32 target_addr,u16 transfer_num)
功能:
DMA1的通道1配置
这里的传输形式是固定的,这点要根据不同的情况来修改
从存储器->外设模式/16位数据宽度/存储器增量模式
参数:
src_addr:外设地址
target_addr:存储器地址
返回值:无
*****************************************/
void MYDMA1_CH1_Config(u32 src_addr,u32 target_addr)
{
        u32 priority;
        RCC->AHBENR|=1<<0;                        //开启DMA1时钟
        delay_ms(5);                                //等待DMA时钟稳定
  DMA1_Channel1->CCR &= ~(1<<0);  //先关闭DMA1通道1
       
        //生成一个优先级编码,组2,抢占优先级2个位(范围0~3),响应优先级2(范围0~3)
        priority=NVIC_EncodePriority (7-2,1,2);
        //设置优先级
        NVIC_SetPriority(DMA1_Channel1_IRQn,priority);
        //使能DMA1中断
        NVIC_EnableIRQ(DMA1_Channel1_IRQn);
       
       
        DMA1_Channel1->CCR &= ~(1<<4);  //从外设读
        DMA1_Channel1->CCR |=  (1<<5);   //工作在循环模式
        DMA1_Channel1->CCR &= ~(1<<6);  //外设地址不增
        DMA1_Channel1->CCR |=   1<<7;   //存储器地址增
        DMA1_Channel1->CCR |=   1<<10;  //数据宽度为16位,adc的精度为12位
        DMA1_Channel1->CCR |=   1<<12;  //通道优先级为中
        DMA1_Channel1->CCR &= ~(1<<14); //非存储器到存储器模式
       
        DMA1_Channel1->CNDTR=50;//DMA传输数量
       
        DMA1_Channel1->CMAR=target_addr; //存储器地址送入寄存器
        DMA1_Channel1->CPAR=src_addr;    //外设地址送入寄存器
       
        DMA1->IFCR &= ~(1<<0);         //清除全局中断标志
        DMA1_Channel1->CCR &= ~(1 << 3);                          //禁止传输错误中断
        DMA1_Channel1->CCR &= ~(1 << 2);                        //禁止半传输中断
        DMA1_Channel1->CCR |=   1<<1; //使能传输完成中断
       
        DMA1_Channel1->CCR |= 1<<0;  //开启DMA传输
}

/*****************************************
函数:adc1_get
功能:单次转换AD
参数:无
返回值:转换后的数字量
*****************************************/
u16 adc1_get(void)
{
        ADC1->CR2 |= 1<<22;
        while(!(ADC1->SR & (1<<1)));//等待转换完成
        return ADC1->DR;
}

/*****************************************
函数:adc1_getnum
功能:多次转换AD
参数:num:转换的次数
返回值:转换后的数字量
*****************************************/
u16 adc1_getnum(u8 num)
{
        u32 times=0;
        u16 sum=0;
        for(times=0;times<num;times++)
          sum+=adc1_get();
        return sum/times;
}

/*****************************************
函数:DMA1_Channel1_IRQHandler
功能:dma1通道1中断服务函数
参数:none
返回值:none
*****************************************/
void DMA1_Channel1_IRQHandler()  
{  
        LED2=!LED2;
        if(DMA1->ISR & (1<<1))
        {
                char i=50;
       
                for(i=0;i<50;i++)
                        printf("%d ",SendBuff);
       
                DMA1->IFCR= ~(1<<1);                              //清除中断标志位
                /*如果DMA工作在循环模式则不需要下面这三行代码*/
//                DMA1_Channel1->CCR &= ~(1<<0);  //先关闭DMA1通道1
//                DMA1_Channel1->CNDTR=50;//DMA传输数量
//                DMA1_Channel1->CCR |= 1<<0;  //开启DMA传输
        }
        printf("jinzhongduan ");
}
[/mw_shl_code]
ADC DMA(寄存器版).zip (895.53 KB, 下载次数: 135) 2017-2-22 16:03 上传 点击文件名下载附件
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。