打印
[STM32F1]

求助:STM32F103 AD采样结果不正确

[复制链接]
6737|26
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
xxggqq_123|  楼主 | 2018-5-3 21:16 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 xxggqq_123 于 2018-5-7 15:16 编辑

使用STM32F103C8T6进行ADC采样,参考电压3.3V,AD采样口电压1.6V,12位ADC采用右对齐方式,采样结果理论上应该是4096的一半,大概是0x800,可是我采样结果大概是0x00f0,求大神帮忙。

以下是部分程序性:
void GPIO_Configuration(void)
{
        GPIO_InitTypeDef GPIO_InitStructure;
        
        //===================ADC ===================================
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_Init(GPIOA, &GPIO_InitStructure);

        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
        GPIO_Init(GPIOB, &GPIO_InitStructure);
}

void RCC_Configuration(void)
{
        /* Enable GPIO clock */
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO, ENABLE );
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
        RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE );

        /* TIM2 clock enable */
        RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE );
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1 , ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
}



void ADC_Configuration(void)
{
        vu16 i;
        ADC_InitTypeDef ADC_InitStructure;
        
        ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
        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_InitStructure.ADC_NbrOfChannel = 6;
        ADC_Init(ADC1, &ADC_InitStructure);
        /* ADC1 regular channel configuration */
        ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_13Cycles5);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 2, ADC_SampleTime_13Cycles5);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_13Cycles5);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 4, ADC_SampleTime_13Cycles5);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 5, ADC_SampleTime_13Cycles5);
        ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 6, ADC_SampleTime_13Cycles5);

        /* Enable ADC1 DMA */
        ADC_DMACmd(ADC1, ENABLE);               
               
        /* Enable ADC1 */
        ADC_Cmd(ADC1, ENABLE);
        
        /* Enable ADC1 reset calibaration register */   
        ADC_ResetCalibration(ADC1);
        /* Check the end of ADC1 reset calibration register */
        i=0;
        while((ADC_GetResetCalibrationStatus(ADC1))&&(i<3000))
        {
                i++;
        }
        /* Start ADC1 calibaration */
        ADC_StartCalibration(ADC1);
        /* Check the end of ADC1 calibration */
        i=0;
        while((ADC_GetCalibrationStatus(ADC1))&&(i<3000))
        {
                i++;
        }
}

void DMA_Configuration(void)
{
        DMA_InitTypeDef DMA_InitStructure;
        
        /* DMA1 channel1 configuration ----------------------------------------------*/
        DMA_DeInit(DMA1_Channel1);
        DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)ADC1_DR_Address;
        DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue;
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
        DMA_InitStructure.DMA_BufferSize =6;
        DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
        DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
        DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
        DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
        DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
        DMA_InitStructure.DMA_Priority = DMA_Priority_High;
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);
        /* Enable DMA1 channel1 interrupt*/
        DMA_ITConfig(DMA1_Channel1,DMA_IT_TC,ENABLE);
        /* Enable DMA1 Channel1 */
        DMA_Cmd(DMA1_Channel1, ENABLE);
}

void NVIC_Configuration(void)
{
        NVIC_InitTypeDef NVIC_InitStructure;

        /* Configure the NVIC Preemption Priority Bits */  
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);

        /* Enable the TIM2 global Interrupt */
        NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);

        NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn; //设置中断通道
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =1;
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
        NVIC_Init(&NVIC_InitStructure);
}


沙发
mmuuss586| | 2018-5-3 21:52 | 只看该作者
你的AD值结果处理在哪段啊?

使用特权

评论回复
板凳
xxggqq_123|  楼主 | 2018-5-3 21:59 | 只看该作者
mmuuss586 发表于 2018-5-3 21:52
你的AD值结果处理在哪段啊?

Timer2 每50US中断一次,触发一次ADC转换,同时读取上一次ADC采样结果

void TIM2_IRQHandler(void)
{
        if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//溢出中断  
        {
                TIM_ClearITPendingBit(TIM2, TIM_FLAG_Update);        //清除TIM2等待中断               
                /* Start ADC1 Software Conversion */
                ADC_SoftwareStartConvCmd(ADC1, ENABLE);

                Get_sampling_Peakvalue(&S1_U1_value,NA_channel);
                Get_sampling_Peakvalue(&S1_U2_value,NB_channel);
                Get_sampling_Peakvalue(&S1_U3_value,NC_channel);

                Get_sampling_Peakvalue(&S2_U1_value,RA_channel);
                Get_sampling_Peakvalue(&S2_U2_value,RB_channel);
                Get_sampling_Peakvalue(&S2_U3_value,RC_channel);
        }   
}  


void DMA1_Channel1_IRQHandler(void)
{
        vu8  i;
       
        if(DMA1_FLAG_TC1!=RESET)
        {
                DMA_ClearITPendingBit(DMA1_FLAG_TC1);
                for(i=0;i<6;i++)
                {
                        ADC1_ConvertedValueLocal=ADC_ConvertedValue;
                }
        }
}

使用特权

评论回复
地板
xxggqq_123|  楼主 | 2018-5-3 22:04 | 只看该作者
ADC采样结果存在数组中暂不处理,先保存最近采样的100个数据,结果大概在0x00f0左右变化

void Get_sampling_Peakvalue(RMS_Value *channel_RMS,Channel_Type channel)
{
        u16 temp;
       
        switch(channel)
        {
                case NA_channel:
                        channel_RMS->value=ADC1_ConvertedValueLocal[3];
                        break;

                case NB_channel:
                        channel_RMS->value=ADC1_ConvertedValueLocal[4];
                        break;
                       
                case NC_channel:
                        channel_RMS->value=ADC1_ConvertedValueLocal[5];
                        break;

                case RA_channel:
                        channel_RMS->value=ADC1_ConvertedValueLocal[0];
                        break;

                case RB_channel:
                        channel_RMS->value=ADC1_ConvertedValueLocal[1];
                        break;
                       
                case RC_channel:
                        channel_RMS->value=ADC1_ConvertedValueLocal[2];
                        break;
                default:
                        break;
        }
        channel_RMS->value_list[channel_RMS->item]=channel_RMS->value;
        channel_RMS->item++;
        if(channel_RMS->item>99)
        {
                channel_RMS->item=0;
        }
}

使用特权

评论回复
5
xxggqq_123|  楼主 | 2018-5-3 22:26 | 只看该作者
6个通道ADC分别采样两路电源的三相电压,采样结果暂不处理,先保存在数组中

使用特权

评论回复
6
xxggqq_123|  楼主 | 2018-5-4 08:11 | 只看该作者
有没有哪位大哥给点意见?

使用特权

评论回复
7
cronus2| | 2018-5-4 10:15 | 只看该作者
你的采样转换周期设的多少?50us采6个样采得完吗?
还有你的 channel_RMS->value类型和你的ADC1_ConvertedValueLocal类型对应吗?

使用特权

评论回复
8
cronus2| | 2018-5-4 10:30 | 只看该作者
cronus2 发表于 2018-5-4 10:15
你的采样转换周期设的多少?50us采6个样采得完吗?
还有你的 channel_RMS->value类型和你的ADC1_ConvertedV ...

算了下可以采完,那就是你的返回值类型不对应

使用特权

评论回复
9
kingkits| | 2018-5-4 13:13 | 只看该作者
你的adc似乎是使用的1.6v做参考电压,所以,数值才会小,你检查一下电路及设置,参考电压为多少

使用特权

评论回复
10
xxggqq_123|  楼主 | 2018-5-4 14:43 | 只看该作者
现在问题已经很明显了,ADC采样结果高4位被舍弃了,12位ADC采用右对齐方式,比如采样结果是0x07ff, 而我DMA中断读到的值是0x00ff, 如果采样结果是0x0809, 我DMA中断读到的值是0x0009, 我看了一下数据类型设置成16位无符号数,以下是数据类型定义:
vu16  ADC_ConvertedValue[6];
vu16 ADC1_ConvertedValueLocal[6];        

DMA中断是这样处理的:
void DMA1_Channel1_IRQHandler(void)
{
        vu8  i;
       
        if(DMA1_FLAG_TC1!=RESET)
        {
                DMA_ClearITPendingBit(DMA1_FLAG_TC1);
                for(i=0;i<6;i++)
                {
                        ADC1_ConvertedValueLocal[i]=ADC_ConvertedValue[i];
                }
        }
}

不知道为什么DMA方式会自动舍弃采样结果的高4位,哪位大哥再帮忙看看哪里配置有问题,谢谢了!

使用特权

评论回复
11
xxggqq_123|  楼主 | 2018-5-4 14:45 | 只看该作者
cronus2 发表于 2018-5-4 10:30
算了下可以采完,那就是你的返回值类型不对应

返回值类型我设置成无符号16位,实际运行结果只有8位,能不能再帮忙看看那里出了问题

使用特权

评论回复
12
kingkits| | 2018-5-4 15:03 | 只看该作者
DMA数据长度似乎是按字节计算的,你可以试试

使用特权

评论回复
13
sky.sun.zz| | 2018-5-4 15:08 | 只看该作者
本帖最后由 sky.sun.zz 于 2018-5-4 15:12 编辑
xxggqq_123 发表于 2018-5-3 21:59
Timer2 每50US中断一次,触发一次ADC转换,同时读取上一次ADC采样结果

void TIM2_IRQHandler(void)

这句好像有毛病:
ADC1_ConvertedValueLocal=ADC_ConvertedValue;
至少改成
ADC1_ConvertedValueLocal【i]=ADC_ConvertedValue【i];


使用特权

评论回复
14
xxggqq_123|  楼主 | 2018-5-4 15:11 | 只看该作者
sky.sun.zz 发表于 2018-5-4 15:08
这句好像有毛病:
ADC1_ConvertedValueLocal=ADC_ConvertedValue;
至少改成

这个已经改过了

使用特权

评论回复
15
sky.sun.zz| | 2018-5-4 15:13 | 只看该作者

(uint16_t)ADC1_ConvertedValueLocal【i】=(uint16_t)ADC_ConvertedValue【i】;

使用特权

评论回复
16
xxggqq_123|  楼主 | 2018-5-4 15:15 | 只看该作者
kingkits 发表于 2018-5-4 15:03
DMA数据长度似乎是按字节计算的,你可以试试

DMA数据长度可以设置成字节,半字或字,我设置成半字16位

使用特权

评论回复
17
sky.sun.zz| | 2018-5-4 15:17 | 只看该作者
ADC_ConvertedValue[]只能定义成uint16_t,不能定义成uint32_t

使用特权

评论回复
18
xxggqq_123|  楼主 | 2018-5-4 15:21 | 只看该作者
sky.sun.zz 发表于 2018-5-4 15:17
ADC_ConvertedValue[]只能定义成uint16_t,不能定义成uint32_t

ADC_ConvertedValue[] 可以定义成uint32_t,但是我现在定义的就是uint16_t

使用特权

评论回复
19
sky.sun.zz| | 2018-5-4 15:26 | 只看该作者
xxggqq_123 发表于 2018-5-4 15:21
ADC_ConvertedValue[] 可以定义成uint32_t,但是我现在定义的就是uint16_t

定义成uint32_t 在DMA条件下STM32会把相邻2次ADC放在uint32_t的高16位和低16位

使用特权

评论回复
20
xxggqq_123|  楼主 | 2018-5-4 16:29 | 只看该作者
sky.sun.zz 发表于 2018-5-4 15:26
定义成uint32_t 在DMA条件下STM32会把相邻2次ADC放在uint32_t的高16位和低16位

我试了定义成uint32_t也不可以

使用特权

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

本版积分规则

4

主题

24

帖子

0

粉丝