发新帖我要提问
12
返回列表
打印

关于STM32 ADC使用的一个奇怪问题

[复制链接]
楼主: linjinming2000
手机看帖
扫描二维码
随时随地手机跟帖
21
linjinming2000|  楼主 | 2012-3-18 14:17 | 只看该作者 回帖奖励 |倒序浏览
/***************************************************************************************************
* 函数名称: ADCIrqEn()
* 函数功能: ADC中断使能函数
* 入口参数: 无
* 出口参数: 无
* 使用说明:变量、硬件初始化完成后调用该函数
* 创建日期: 2011年04月20日
***************************************************************************************************/
void ADCIrqEn(void)
{                                                                                                  
        NVIC_IPR_SETUP(TIM2_IRQn,ADC_TIM_IPR);                                                        // 定时器2作为ADC定时触发
        NVIC_ISER_SETUP(TIM2_IRQn);          
    TIM2->CR1 |= TIM_CR1_CEN;                                                      // enable timer
}

使用特权

评论回复
22
linjinming2000|  楼主 | 2012-3-18 14:42 | 只看该作者
/***************************************************************************************************
* 函数名称: stm32_TimerSetup()
* 函数功能: STM32 定时器设置
* 入口参数: 无
* 出口参数: 无
* 使用说明:初始化Timer相关寄存器
* 创建日期: 2010年08月09日
***************************************************************************************************/
__inline static void stm32_TimerSetup(void)
{                              
        // 定时器2用于内部ADC定时采集控制                                                      
    RCC->APB1ENR |= RCC_APB1ENR_TIM2EN;                                     // 使能TIM2时钟
    Delay(20);
   
        TIM2->PSC =  __PSC1(__TIMXCLK, ADC_SAMP_FRQ);                            // set prescaler
        TIM2->ARR =  __ARR1(__TIMXCLK, ADC_SAMP_FRQ,TIM2->PSC);                 // 设置从装载寄存器的值
                                                                           
    TIM2->CR1 = 0;                                                          // reset command register 1
    TIM2->CR2 = 0;                                                          // reset command register 2
    TIM2->CNT = 0;                                                                           
        TIM2->DIER = __TIM2_DIER;                                                     // enable interrupt
        WaitTimerUpdate(TIM2);                                                                                        // 软件产生更新事件,以便更新PSC,然后清除状态标识
       
//         以下代码在ADC_IRQ_Enable()函数中        
//        NVIC_IPR_SETUP(TIM2_IRQn,ADC_TIM_IPR);
//        NVIC_ISER_SETUP(TIM2_IRQn);          
//        TIM2->CR1 |= TIM_CR1_CEN;                                              // enable timer
}

/***************************************************************************************************
* 函数名称: TIM2_IRQHandler()
* 函数功能: TIM2全局中断服务程序
* 入口参数: 无
* 出口参数: 无
* 使用说明:无
* 创建日期: 2010年08月09日
* 修改日期:
***************************************************************************************************/       
void TIM2_IRQHandler(void)
{
    TIM2->SR &= ~TIM_SR_UIF;
        if(adc1_dma_flag == 0)                                                                                        // 上次中断还未处理完成,则该次中断不处理
        {
                adc1_dma_cnt  = 0;
                adc1_dma_flag = 1;
                               
                ADCChlChg(adc_chl_cnt,0);                                                                        // 切换A相电压、电流信号,关闭ADC1的DMA传输       
//                ADC1DMAEnable();                                                                       
                DMAConfig(DMA1_Channel1,(uint32)&ADC1->DR,(uint32)&adc_data_dma_buf[0],16);                               
                ADC1->CR2 |= ADC_SWSTART;                                                                         // 软件触发启动规则转换,换结束就会产生DMA请求
        }
        else
        {
                adc1_dma_flag = adc1_dma_flag;
        }
}

/***************************************************************************************************
* 函数名称: DMAChannel1_IRQHandler()
* 函数功能: ADC1中断服务程序
* 入口参数: 无
* 出口参数: 无
* 使用说明:data_num 当前数据存放的位置,left_data_num新一帧已采集数据个数,data_start新帧数据起始位置
* 创建日期: 2010年07月14日
* 修改日期:
* 修改内容:
***************************************************************************************************/
void DMAChannel1_IRQHandler(void)
{       
        DMA1->IFCR |= 0x0F;                                                                                                // 清除ADC1的DMA中断标志

//---------------------------------------读取三通道采集数据-----------------------------------------       
        if(adc1_dma_cnt == 0)
        {
                ADCChlChg(adc_chl_cnt,1);                                                                        // 切换B相电压、电流信号                                                                       
                DMAConfig(DMA1_Channel1,(uint32)&ADC1->DR,(uint32)&adc_data_dma_buf[16],16);                                                       
                ReadAdcData(16,&adc_data_dma_buf[0],&voltage_sample[0][data_num],&current_sample[0][data_num],32768);
                ADC1->CR2 |= ADC_SWSTART;               
        }
           else if(adc1_dma_cnt == 1)
        {
                ADCChlChg(adc_chl_cnt,2);                                                                        // 切换C相电压、电流信号                                                               
                DMAConfig(DMA1_Channel1,(uint32)&ADC1->DR,(uint32)&adc_data_dma_buf[32],16);                                                                                               
                ReadAdcData(16,&adc_data_dma_buf[16],&voltage_sample[1][data_num],&current_sample[1][data_num],32768);
                ADC1->CR2 |= ADC_SWSTART;                                                                               
        }
        else if(adc1_dma_cnt == 2)
        {
//                ADC1DMADisable();                                                                                        // 关闭ADC的DMA传输
                adc1_dma_flag = 0;
                ReadAdcData(16,&adc_data_dma_buf[32],&voltage_sample[2][data_num],&current_sample[2][data_num],32768);
                                                       
//---------------------------------------单次数据采集完成,进行后续处理-----------------------------
                data_num++;                                                                                       
                if(data_num >= BUF_SIZE)                                                       
                {
                          data_num = 0;
                }
           
                left_data_num ++;
                if(left_data_num >= data_num_cycle3)                                                // 采集完成完整的数据
                {
                        adc_chl_copy        = adc_chl_cnt;
                        adc_chl_cnt ++;
                        if(adc_chl_cnt >= MAX_PHASE_NUM)
                        {
                                adc_chl_cnt = 0;
                        }
                        MUXChlChg(adc_chl_cnt);                                                                        // 切换指定回路的电流信号
                                               
                        left_data_num = left_data_num - data_num_cycle3;                // 该语句如果在计算程序中执行,必须关中断,否则会出错
                        if(!data_compu_flag)                                                                        // 上帧数据已经处理完成
                        {
                                compu_ovr_flag        = 0;                               
                                data_compu_flag = 1;
                        }
                        else                                                                                                        // 上帧数据没有处理完成,需要丢弃一桢数据
                        {
                                compu_ovr_flag        = 1;                               
                        }
                }
        adc1_dma_cnt ++;
}

使用特权

评论回复
23
linjinming2000|  楼主 | 2012-3-18 15:05 | 只看该作者
以上是ADC相关的程序,只有PA0和PA1的精度较高,看原始值就有1.4%左右的误差

使用特权

评论回复
24
linjinming2000|  楼主 | 2012-3-18 22:30 | 只看该作者
今天晚上又看了几遍ADC的资料,可能的问题是程序采样时间配置的问题,主要出现在以下语句:

// 设置通道0 ~ 1的采样时间,41.5 + 12.5个周期 fadc = 11059.200 / 54 = 204.8 KHz
        ADC1->SMPR2 = (ADC_SAMP_CYC) | (ADC_SAMP_CYC << 3);               
        ADC2->SMPR2 = (ADC_SAMP_CYC) | (ADC_SAMP_CYC << 3);

程序中只配置了通道0和通道1的采样时间为41.5,其余通道的采样时间是默认值1.5个周期,太短了,所以精度比较差,明天到公司再试一下。

使用特权

评论回复
25
哲哲55| | 2012-3-18 23:01 | 只看该作者
mak

使用特权

评论回复
26
linjinming2000|  楼主 | 2012-3-19 09:30 | 只看该作者
问题解决了,就是采样时间设置问题!谢谢各位!

使用特权

评论回复
27
zchong| | 2015-3-18 16:03 | 只看该作者
linjinming2000 发表于 2012-3-19 09:30
问题解决了,就是采样时间设置问题!谢谢各位!

不同通道不是同时采样造成的吗?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则