打印
[STM32F1]

STM32F103 AD采样结果不正确

[复制链接]
1182|36
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wenfen|  楼主 | 2021-11-13 18:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
使用STM32F103C8T6进行ADC采样,参考电压3.3V,AD采样口电压1.6V,12位ADC采用右对齐方式,采样结果理论上应该是4096的一半,大概是0x800,可是我采样结果大概是0x00f0,求大神帮忙。

使用特权

评论回复
沙发
heweibig| | 2021-11-13 18:35 | 只看该作者
楼主程序可以公开吗?贴程序看下吧,这么说看不出什么原因

使用特权

评论回复
板凳
wenfen|  楼主 | 2021-11-13 18:38 | 只看该作者

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);
}

使用特权

评论回复
地板
juventus9554| | 2021-11-13 18:42 | 只看该作者
你的AD值结果处理在哪段啊?

使用特权

评论回复
5
wenfen|  楼主 | 2021-11-13 18:45 | 只看该作者

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;
                }
        }
}

使用特权

评论回复
6
wenfen|  楼主 | 2021-11-13 18:49 | 只看该作者
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;
        }
}

使用特权

评论回复
7
wenfen|  楼主 | 2021-11-13 18:51 | 只看该作者
6个通道ADC分别采样两路电源的三相电压,采样结果暂不处理,先保存在数组中

使用特权

评论回复
8
stly| | 2021-11-13 18:53 | 只看该作者
我用的很正常,会不会是采样周期过短导致,你试下把采样周期放长看看

使用特权

评论回复
9
yszong| | 2021-11-13 18:55 | 只看该作者
你的采样转换周期设的多少?

使用特权

评论回复
10
chuxh| | 2021-11-13 18:57 | 只看该作者
50us采6个样采得完吗?

使用特权

评论回复
11
kangzj| | 2021-11-13 19:00 | 只看该作者
还有你的 channel_RMS->value类型和你的ADC1_ConvertedValueLocal类型对应吗?

使用特权

评论回复
12
houcs| | 2021-11-13 19:01 | 只看该作者
算了下可以采完,那就是你的返回值类型不对应

使用特权

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

使用特权

评论回复
14
wenfen|  楼主 | 2021-11-13 19:05 | 只看该作者
现在问题已经很明显了,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位

使用特权

评论回复
15
wenfen|  楼主 | 2021-11-13 19:10 | 只看该作者
返回值类型我设置成无符号16位,实际运行结果只有8位,能不能再帮忙看看那里出了问题

使用特权

评论回复
16
chuxh| | 2021-11-13 19:12 | 只看该作者
DMA数据长度似乎是按字节计算的,你可以试试

使用特权

评论回复
17
yszong| | 2021-11-13 19:14 | 只看该作者
这句好像有毛病:
ADC1_ConvertedValueLocal=ADC_ConvertedValue;
至少改成
ADC1_ConvertedValueLocal【i]=ADC_ConvertedValue【i];

使用特权

评论回复
18
wenfen|  楼主 | 2021-11-13 19:16 | 只看该作者

这个已经改过了

使用特权

评论回复
19
kangzj| | 2021-11-13 19:18 | 只看该作者
(uint16_t)ADC1_ConvertedValueLocal【i】=(uint16_t)ADC_ConvertedValue【i】;

使用特权

评论回复
20
wenfen|  楼主 | 2021-11-13 19:20 | 只看该作者
DMA数据长度可以设置成字节,半字或字,我设置成半字16位

使用特权

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

本版积分规则

737

主题

8940

帖子

8

粉丝