OpenEdv-开源电子网

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

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

[复制链接]

7

主题

64

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
409
金钱
409
注册时间
2016-7-5
在线时间
65 小时
发表于 2017-2-22 16:04:55 | 显示全部楼层 |阅读模式
参考论坛@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\r\n",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\r\n");
}
[/mw_shl_code]
ADC DMA(寄存器版).zip (895.53 KB, 下载次数: 149)
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

19

主题

98

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
308
金钱
308
注册时间
2014-10-19
在线时间
42 小时
发表于 2017-2-23 08:39:42 | 显示全部楼层
帮顶  虽说我一直用库函数版的
回复 支持 反对

使用道具 举报

1

主题

74

帖子

0

精华

初级会员

Rank: 2

积分
127
金钱
127
注册时间
2017-2-9
在线时间
19 小时
发表于 2017-2-23 10:55:18 | 显示全部楼层
帮顶。。。
回复 支持 反对

使用道具 举报

17

主题

109

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
348
金钱
348
注册时间
2016-6-13
在线时间
65 小时
发表于 2017-3-20 22:06:17 | 显示全部楼层
大兄弟 太感谢你了之前我做这也一直不成功  听你建议把ADC转化模式改为连续 DMA模式改为循环就好了 但是不就是太理解这两点为什么这样
回复 支持 反对

使用道具 举报

7

主题

64

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
409
金钱
409
注册时间
2016-7-5
在线时间
65 小时
 楼主| 发表于 2017-3-21 09:45:24 | 显示全部楼层
发条橙子玩电子 发表于 2017-3-20 22:06
大兄弟 太感谢你了之前我做这也一直不成功  听你建议把ADC转化模式改为连续 DMA模式改为循环就好了 但是不 ...

你看看原子哥的ADC实验,初始化是设置单词转换模式,如下:
ADC1->CR2&=~(1<<1);    //单次转换模式
所以每次转换都要在主循环里面开启转换,转换完成会根据我们的设置发出DMA请求。
DMA的设置也是一样的道理,不设置为循环就需要每次得到ADC转换完成的信号自己手动去开启DMA传输,而设置为循环就会在收到ADC的传输完成标志自动开启DMA传输
回复 支持 反对

使用道具 举报

17

主题

109

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
348
金钱
348
注册时间
2016-6-13
在线时间
65 小时
发表于 2017-3-21 12:17:52 | 显示全部楼层
树上的龙猫 发表于 2017-3-21 09:45
你看看原子哥的ADC实验,初始化是设置单词转换模式,如下:
ADC1->CR2&=~(1

恩恩 非常感谢您耐心的指导!
回复 支持 反对

使用道具 举报

13

主题

126

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
399
金钱
399
注册时间
2016-5-25
在线时间
101 小时
发表于 2017-4-19 09:04:08 | 显示全部楼层
非常感谢
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-8-22 03:06

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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