OpenEdv-开源电子网

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

大家好,最近用stm32F103VB, ADC多道通,扫描方式,单次转换,完成后DMA传送,再DMA中断完成数据的采集并保存, ADC的启动使...

[复制链接]

1

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
56
金钱
56
注册时间
2016-4-14
在线时间
15 小时
发表于 2018-2-4 15:05:49 | 显示全部楼层 |阅读模式
5金钱
大家好,最近用stm32F103VB, ADC多道通,扫描方式,单次转换,完成后DMA传送,再DMA中断完成数据的采集并保存,ADC的启动使用定时器中断完成定时启动,现在就是死活进不了DMA完成中断,累崩了…………请教大神们。以下代码

u16 adc_dma_tab[6];
void adc_gpio_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE );         //使能ADC1通道时钟
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7; //PA2~7
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;                 //配置为模拟输入
    GPIO_Init(GPIOA, &GPIO_InitStructure);                         //x=GPIOx
}


void  adc_config(void)
{        
    ADC_InitTypeDef ADC_InitStructure;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE );          //使能ADC1通道时钟
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);   //AD采样时钟72M/6=12M,不能超过14M,否则精度下降
    ADC_DeInit(ADC1);  //将外设 ADC1的全部寄存器重设为缺省值
    ADC_StructInit(&ADC_InitStructure);
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;        //ADC工作模式:ADC1和ADC2工作在独立模式
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;        //模数转换工作在多通道模式
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;        //转换由软件而不是外部触发启动
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;        //ADC数据右对齐
    ADC_InitStructure.ADC_NbrOfChannel = 6;        //顺序进行规则转换的ADC通道的数目,此处为1个通道
    ADC_Init(ADC1, &ADC_InitStructure);        //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器   

    ADC_RegularChannelConfig(ADC1,ADC_Channel_4,1,ADC_SampleTime_239Cycles5);//规则组顺序
    ADC_RegularChannelConfig(ADC1,ADC_Channel_5,2,ADC_SampleTime_239Cycles5);//规则组顺序
    ADC_RegularChannelConfig(ADC1,ADC_Channel_3,3,ADC_SampleTime_239Cycles5);//规则组顺序
    ADC_RegularChannelConfig(ADC1,ADC_Channel_6,4,ADC_SampleTime_239Cycles5);//规则组顺序
    ADC_RegularChannelConfig(ADC1,ADC_Channel_2,5,ADC_SampleTime_239Cycles5);//规则组顺序
    ADC_RegularChannelConfig(ADC1,ADC_Channel_7,6,ADC_SampleTime_239Cycles5);//规则组顺序

    ADC_DMACmd(ADC1, ENABLE);   //使能ADC1 DMA
    ADC_Cmd(ADC1, ENABLE);        //使能指定的ADC1   

    ADC_ResetCalibration(ADC1);        //重置指定的ADC1的校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC1));        //获取ADC1重置校准寄存器的状态,直到校准寄存器设置完成
    ADC_StartCalibration(ADC1);                //开始指定ADC1的校准状态
    while(ADC_GetCalibrationStatus(ADC1));                //获取指定ADC1的校准程序,直到校准完成
    //ADC_SoftwareStartConvCmd(ADC1, ENABLE);                //使能指定的ADC1的软件转换启动功能
}       

void adc_dma_init(void)
{
    DMA_InitTypeDef DMA_InitStructure;
    NVIC_InitTypeDef nvic_init_structure;

    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA时钟

    nvic_init_structure.NVIC_IRQChannel = DMA1_Channel1_IRQn; //选择DMA1通道中断
    nvic_init_structure.NVIC_IRQChannelCmd = ENABLE; //中断使能
    nvic_init_structure.NVIC_IRQChannelSubPriority = 1; //优先级设为0
    nvic_init_structure.NVIC_IRQChannelPreemptionPriority = 2;//从优先级3级   
    NVIC_Init(&nvic_init_structure);

    DMA_DeInit(DMA1_Channel1); //复位DMA1_channel1
    DMA_StructInit(&DMA_InitStructure); //初始化DMA结构体

    DMA_InitStructure.DMA_PeripheralBaseAddr = (u32) &(ADC1->DR);//取值的外设地址;  //DMA外设ADC基地址
    DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&adc_dma_tab;  //DMA内存基地址
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //外设作为数据传输的目的地
    DMA_InitStructure.DMA_BufferSize = 6;  //DMA通道的DMA缓存的大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;  //外设地址寄存器不变
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;  //内存地址寄存器递增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_MemoryDataSize_HalfWord;  //数据宽度为16位
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
    DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;  //工作在正常缓存模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器


    //DMA_Init(DMA1_Channel1, &DMA_InitStructure);

    //DMA_ClearITPendingBit(DMA_IT_TC); //清除一次DMA中断标志
    DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA1
    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE); //使能DMA中断

}


void adc_timer_init(void)
{
    TIM_TimeBaseInitTypeDef timer_init_structure;
    NVIC_InitTypeDef nvic_init_structure;

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能TIM2时钟

    nvic_init_structure.NVIC_IRQChannel = TIM2_IRQn; //选择TIM2中断通道
    nvic_init_structure.NVIC_IRQChannelCmd = ENABLE; //使能TIM2中断
    nvic_init_structure.NVIC_IRQChannelSubPriority = 1; //优先级为0
    nvic_init_structure.NVIC_IRQChannelPreemptionPriority = 2;//从优先级3级
    NVIC_Init(&nvic_init_structure);

    TIM_DeInit(TIM2); //复位TIM2
    TIM_TimeBaseStructInit(&timer_init_structure); //初始化TIMBASE结构体

    timer_init_structure.TIM_ClockDivision = TIM_CKD_DIV1; //系统时钟,不分频,
    timer_init_structure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
    timer_init_structure.TIM_Period = 500; //每500 uS触发一次中断,
    timer_init_structure.TIM_Prescaler = 72-1; //计数时钟预分频,f=1M,systick=1 uS
    TIM_TimeBaseInit(TIM2, &timer_init_structure);

    TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE); //使能TIM2中断
    TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清除update事件中断标志
    TIM_Cmd(TIM2, ENABLE); //使能TIM2
}


void TIM2_IRQHandler(void)
{
    if(TIM_GetITStatus(TIM2, TIM_IT_Update)) //判断发生update事件中断
    {
        TIM_ClearITPendingBit(TIM2, TIM_IT_Update); //清除update事件中断标志
        if (adc_flag == 0)
        {
            ADC_SoftwareStartConvCmd(ADC1, ENABLE);//使能指定的ADC1的软件转换启动功能;
        //DMA_Cmd(DMA1_Channel1, ENABLE);
        }
    }
}


void DMA1_Channel1_IRQHandler(void)
{
    if(DMA_GetITStatus(DMA1_IT_TC1)!= RESET) //判断DMA传输完成中断
    {
        DMA_ClearITPendingBit(DMA1_IT_TC1); //清除DMA中断标志位
        ;//处理代码
            g_iaADVl[0][adc_coun] = adc_dma_tab[0];
            g_iaADVl[1][adc_coun] = adc_dma_tab[2];
            g_iaADVl[2][adc_coun] = adc_dma_tab[4];
            g_iaADVl[3][adc_coun] = adc_dma_tab[1];
            g_iaADVl[4][adc_coun] = adc_dma_tab[3];
            g_iaADVl[5][adc_coun] = adc_dma_tab[5];
         adc_coun++;
        if (adc_counter >= 20)
        {
            adc_coun = 0;
            adc_flag = 1;
        }

    }
}


adc_flag标志会在MAIN中数据处理结束后,会进行置0,然后定时再断中断启动ADC 20完成ADC的采集。



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

使用道具 举报

51

主题

2166

帖子

2

精华

论坛元老

Rank: 8Rank: 8

积分
10653
金钱
10653
注册时间
2017-4-14
在线时间
2780 小时
发表于 2018-2-4 15:31:24 | 显示全部楼层
使能dma1之前清除dma标志试试DMA_ClearFlag(DMA1_Channel1_IRQn);                                 // 清除DMA所有标志
回复

使用道具 举报

1

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
56
金钱
56
注册时间
2016-4-14
在线时间
15 小时
 楼主| 发表于 2018-2-4 15:47:11 | 显示全部楼层
谢谢啦,试过了,还是不行啊
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165536
金钱
165536
注册时间
2010-12-1
在线时间
2117 小时
发表于 2018-2-5 02:25:06 | 显示全部楼层
论坛搜索,参考下别人的代码吧
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

1

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
56
金钱
56
注册时间
2016-4-14
在线时间
15 小时
 楼主| 发表于 2018-2-5 09:23:35 | 显示全部楼层
知道了,谢谢原子哥~~
回复

使用道具 举报

4

主题

349

帖子

0

精华

金牌会员

Rank: 6Rank: 6

积分
1046
金钱
1046
注册时间
2017-5-19
在线时间
335 小时
发表于 2018-2-5 09:31:26 | 显示全部楼层
主函数呢,初始化也是有顺序的
回复

使用道具 举报

1

主题

6

帖子

0

精华

初级会员

Rank: 2

积分
56
金钱
56
注册时间
2016-4-14
在线时间
15 小时
 楼主| 发表于 2018-2-6 13:42:39 | 显示全部楼层
wxjhby 发表于 2018-2-5 09:31
主函数呢,初始化也是有顺序的

谢谢啊,真的是初始顺序出错了
回复

使用道具 举报

1

主题

4

帖子

0

精华

新手上路

积分
42
金钱
42
注册时间
2018-1-23
在线时间
18 小时
发表于 2018-2-6 14:34:43 | 显示全部楼层
正点原子 发表于 2018-2-5 02:25
论坛搜索,参考下别人的代码吧

原子哥,我的DMA双缓冲模式,bufer0和bufer1.。运行的时候不是bufer0到bufer1再到bufer0.。而是跳的,有时候会跳几次bufer0或bufer1
回复

使用道具 举报

9

主题

56

帖子

0

精华

初级会员

Rank: 2

积分
189
金钱
189
注册时间
2017-12-12
在线时间
19 小时
发表于 2018-2-6 15:26:44 | 显示全部楼层
试试连续转换,               改为 ENABLE;         ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;        //模数转换工作在单次转换模式
回复

使用道具 举报

14

主题

38

帖子

0

精华

初级会员

Rank: 2

积分
110
金钱
110
注册时间
2017-7-13
在线时间
27 小时
发表于 2018-3-26 12:14:27 | 显示全部楼层
ilikeyuanzi666 发表于 2018-2-6 13:42
谢谢啊,真的是初始顺序出错了

楼主初始化顺序是怎么的
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-12 18:04

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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