OpenEdv-开源电子网

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

stm32 双adc模式DMA传输多通道的执行问题

[复制链接]

3

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
85
金钱
85
注册时间
2019-3-15
在线时间
18 小时
发表于 2020-8-9 14:55:13 | 显示全部楼层 |阅读模式
1金钱

#define PHASE_A_ADC_CHANNEL               ADC_Channel_11
#define PHASE_A_GPIO_PORT                 GPIOC
#define PHASE_A_GPIO_PIN                  GPIO_Pin_1

#define PHASE_B_ADC_CHANNEL               ADC_Channel_10
#define PHASE_B_GPIO_PORT                 GPIOC
#define PHASE_B_GPIO_PIN                  GPIO_Pin_0

#define TEMP_FDBK_CHANNEL                 ADC_Channel_13
#define TEMP_FDBK_CHANNEL_GPIO_PORT       GPIOC
#define TEMP_FDBK_CHANNEL_GPIO_PIN        GPIO_Pin_3

#define BUS_VOLT_FDBK_CHANNEL             ADC_Channel_14
#define BUS_VOLT_FDBK_CHANNEL_GPIO_PORT   GPIOC
#define BUS_VOLT_FDBK_CHANNEL_GPIO_PIN    GPIO_Pin_4

#define   ADC1_DR_Address    ((uint32_t)0x4001244C)       //ADC数据寄存器地址
#define   BufferLenght       2   

volatile u32  ADC_DualConvertedValueTab[BufferLenght];
volatile u16  ADC1_RegularConvertedValueTab[BufferLenght];
volatile u16  ADC2_RegularConvertedValueTab[BufferLenght];

u16 h_ADCBusvolt;
u16 h_ADCTemp;
u16 h_ADCPhase_A;
u16 h_ADCPhase_B;


/*
* 函数名:ADC_GPIO_Init
* 描述:使能ADC1,ADC2和DMA1的时钟,初始化GPIO口
* 输入:无
* 输出:无
* 调用:内部调用
*/
void ADC_GPIO_Init(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
       
        /* Enable DMA clock */
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);       //DMA1
       
        /* Enable ADC1,ADC2,GPIOA,GPIOB,GPIOC clock */
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOC, ENABLE);       

    GPIO_StructInit(&GPIO_InitStructure);                           
    GPIO_InitStructure.GPIO_Pin = PHASE_A_GPIO_PIN;//adc_channel11 PC1     
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(PHASE_A_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = PHASE_B_GPIO_PIN;//adc_channel10 PC0                             
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(PHASE_B_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = TEMP_FDBK_CHANNEL_GPIO_PIN;//adc_channel13 PC3         
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(TEMP_FDBK_CHANNEL_GPIO_PORT, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = BUS_VOLT_FDBK_CHANNEL_GPIO_PIN;//adc_channel14 PC4        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(BUS_VOLT_FDBK_CHANNEL_GPIO_PORT, &GPIO_InitStructure);

}


/*
* 函数名:ADC_DMA_Init
* 描述:配置ADC1的工作模式为DMA模式
* 输入:无
* 输出:无
* 调用:内部调用
*/
void ADC_DMA_Init(void)
{
//    u8 bIndex;
       
    ADC_InitTypeDef ADC_InitStructure;
        DMA_InitTypeDef   DMA_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
       
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);                        //ADCCLK = PCLK2/6=72M/6=12MHz,ADC最大频率不能超过14MHz

    //设置DMA1,用于自动存储ADC1和ADC2规则通道的转换值
    DMA_DeInit(DMA1_Channel1);
    DMA_StructInit(&DMA_InitStructure);
    DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;                  //ADC数据寄存器地址(源地址)
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADC_DualConvertedValueTab;  //转换值存储地址(目标地址)
    DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;                           //从外设到内存
    DMA_InitStructure.DMA_BufferSize = BufferLenght;                             //传输大小
    DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;             //外设地址不增
    DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                      //内存地址自增
    DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;      //外设数据单位(每次传输32位)
    DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;              //内存数据单位(每次传输32位)
    DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                              //循环模式
    DMA_InitStructure.DMA_Priority = DMA_Priority_High;                          //本DMA通道优先级(用了多个通道时,本参数才有效果)
    DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;                                 //没有使用内存到内存的传输
    DMA_Init(DMA1_Channel1, &DMA_InitStructure);
       
    DMA_ClearITPendingBit(DMA1_IT_TC1);                //清除通道1传输完成中断         
    DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);    //打开通道1传输完成中断       
    DMA_Cmd(DMA1_Channel1, ENABLE);                    //使能DMA1

/****使用双ADC模式,ADC1为主,ADC2为从。当ADC转换配置成由外部事件触发时,用户必须设置成仅触发主ADC,从ADC设置成软件触发,这样可以防止意外的触发从转换。
但是,主和从ADC的外部触发必须同时被激活,要调用 ADC_ExternalTrigConvCmd(ADC2, ENABLE);//ADC2外部触发使能****/
    ADC_DeInit(ADC1);
    ADC_DeInit(ADC2);
    ADC_StructInit(&ADC_InitStructure);
    ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;  //ADC1工作在注入模式
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;           //轮流采集各个通道的值
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;     //连续转换模式,触发后就会一直转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换触发信号选择,使用一个软件信号触发ADC1
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;  //数据左对齐,ADC是12位,要存到DR寄存器的高16位或低16位,就有左右对齐问题,决定了高4位无效或低4位无效
    ADC_InitStructure.ADC_NbrOfChannel = 2;                       //要进行ADC转换的通道数:PHASE_A_ADC_CHANNEL,BUS_VOLT_FDBK_CHANNEL
    ADC_Init(ADC1, &ADC_InitStructure);

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

    ADC_StructInit(&ADC_InitStructure);
    ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;  //ADC2工作在注入模式
    ADC_InitStructure.ADC_ScanConvMode = ENABLE;           
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;     //连续转换模式,触发后就会一直转换
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //转换触发信号选择,由软件给信号触发,双ADC模式的从ADC必须设置为软件触发
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
    ADC_InitStructure.ADC_NbrOfChannel = 2;                //要进行ADC转换的通道数:PHASE_B_ADC_CHANNEL,TEMP_FDBK_CHANNEL
    ADC_Init(ADC2, &ADC_InitStructure);
    ADC_ExternalTrigConvCmd(ADC2, ENABLE);                 //ADC2外部触发使能,双ADC模式的从ADC必须要用这条语句
       
    ADC_RegularChannelConfig(ADC1, PHASE_A_ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);           //A相电流
    ADC_RegularChannelConfig(ADC1, BUS_VOLT_FDBK_CHANNEL, 2, ADC_SampleTime_55Cycles5);   //母线电压

    ADC_RegularChannelConfig(ADC2, PHASE_B_ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);   //B相电流
    ADC_RegularChannelConfig(ADC2, TEMP_FDBK_CHANNEL, 2, ADC_SampleTime_55Cycles5);   //温度电压

       
    ADC_Cmd(ADC1, ENABLE);                                   //ADC1使能
    ADC_TempSensorVrefintCmd(ENABLE);                  //开启MCU内存温度传感器及Vref通道
       
    ADC_ResetCalibration(ADC1);                        //复位校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC1));       //等待校准寄存器复位完成
    ADC_StartCalibration(ADC1);                        //ADC1开始校准
    while(ADC_GetCalibrationStatus(ADC1));            //等待校准完成

    ADC_Cmd(ADC2, ENABLE);                             //ADC2使能
    ADC_ResetCalibration(ADC2);                        //复位校准寄存器
    while(ADC_GetResetCalibrationStatus(ADC2));       //等待校准寄存器复位完成
    ADC_StartCalibration(ADC2);                        //ADC2开始校准  
    while(ADC_GetCalibrationStatus(ADC2));                   //等待校准完成



    NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

      ADC_SoftwareStartConvCmd(ADC1, ENABLE);    //给主ADC一个软件触发信号,之后ADC就会一直转换下去
}
/*
* 函数名:ADC_DMA_Init
* 描述:配置ADC1的工作模式为DMA模式
* 输入:无
* 输出:无
* 调用:内部调用
*/
void ADC1_Init(void)
{
        ADC_GPIO_Init();
        ADC_DMA_Init();
}



void DMA1_Channel1_IRQHandler(void)
{
        u8 i,j=0;

        if(DMA_GetITStatus(DMA1_IT_TC1))
        {
                DMA_ClearITPendingBit(DMA1_IT_GL1);    //清除DMA通道1传输完成中断
                for(i=0;i<BufferLenght;i++)
                {
                        ADC1_RegularConvertedValueTab[j++] = (uint16_t)(ADC_DualConvertedValueTab[i]>>4);   //ADC1规则组左对齐,要右移4位

                }

                               
                j = 0;

                for(i=0;i<BufferLenght;i++)
                {
                        ADC2_RegularConvertedValueTab[j++] = (uint16_t)(ADC_DualConvertedValueTab[i] >> 20);//ADC2规则组左对齐,要右移20位
                }
               
        }
}

最佳答案

查看完整内容[请看2#楼]

在break位置加死循环
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

530

主题

11万

帖子

34

精华

管理员

Rank: 12Rank: 12Rank: 12

积分
165540
金钱
165540
注册时间
2010-12-1
在线时间
2117 小时
发表于 2020-8-9 14:55:14 | 显示全部楼层
41kk 发表于 2020-8-9 14:57
int main(void)
{       
        u8 t;

在break位置加死循环
我是开源电子网www.openedv.com站长,有关站务问题请与我联系。
正点原子STM32开发板购买店铺http://openedv.taobao.com
正点原子官方微信公众平台,点击这里关注“正点原子”
回复

使用道具 举报

3

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
85
金钱
85
注册时间
2019-3-15
在线时间
18 小时
 楼主| 发表于 2020-8-9 14:57:27 | 显示全部楼层
int main(void)
{       
        u8 t;
       
        set_speed = (u16)(65536*post/15000);
        delay_init();                     //延时函数初始化       
        TIM1_PWM_Init();
        KEY_Init();
        OLED_Init();
        OLED_Clear();
        OLED_ShowCHinese(40,0,0);
        OLED_ShowCHinese(56,0,1);
        OLED_ShowNum(72,0,post,3,16);
        ADC1_Init();

           while(1)
        {
                t=KEY_Scan(0);                //得到键值
                switch(t)
                {                                 
                        case KEY0_PRES:
                                post+=10;
                                set_speed = (u16)(65536*post/15000);
                                OLED_Clear();
                                OLED_ShowCHinese(40,0,0);
                                OLED_ShowCHinese(56,0,1);
                                OLED_ShowNum(72,0,post,3,16);
                                break;
                        case KEY1_PRES:
                                post-=10;                               
                                set_speed = (u16)(65536*post/15000);
                                OLED_Clear();
                                OLED_ShowCHinese(40,0,0);
                                OLED_ShowCHinese(56,0,1);
                                OLED_ShowNum(72,0,post,3,16);
                                break;
                }

        }
}
我想在main函数里面进行按键操作我使用这段程序后,不能够再执行main函数里的程序,请问各位要如何解决这问题?
回复

使用道具 举报

3

主题

18

帖子

0

精华

初级会员

Rank: 2

积分
85
金钱
85
注册时间
2019-3-15
在线时间
18 小时
 楼主| 发表于 2020-8-9 14:57:49 | 显示全部楼层
问题在2楼
回复

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-30 14:23

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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