我选的传感器两线制输出4-20MA,怎么接到STM32的AD上?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了我选的传感器两线制输出4-20MA,怎么接到STM32的AD上?相关的知识,希望对你有一定的参考价值。

我选的传感器两线制输出4-20MA,怎么接到STM32的AD上?怎样把4-20mA电流信号转换成0-3.3V电压信号?最好有有专门的转换芯片

基于负载的考虑,不能够使用电阻分压。
用运算放大器最适合了.
想将4mA-20mA信号转为0-3.3V电压,你的4-20mA是电流环输出的吧.
运放同相端接地,反相端与输出端之间串接一个反馈电阻,阻值为3.3V/20mA.
这样就可以在20mA的时候输出-3.3V信号,要想4mA的时候输出0V,运放反相端还要一个调零电压,最后把输出电压再倒相一次.就输出为+3.3V-0V可以接到STM32F的AD口上了。
参考技术A 这个我用过,传感器的参数里面有个‘负载’参数,通常是250欧,或500欧,选个精密电阻就行,记得要并个小电容,高频分路用。后面跟一个运放就行了,它是高输入阻抗的。
起点4毫安是用于断线检测的。
参考技术B AD公司有电流电压转换专用电路,应该是RVS系列或者什么,到网站上看看就可以了 参考技术C 你想转换成电压信号 得加个电阻,找个模块 一一对应.就么问题.

STM32 ADC 值读数过高

【中文标题】STM32 ADC 值读数过高【英文标题】:STM32 ADC values reading too high 【发布时间】:2014-09-07 16:43:38 【问题描述】:

我正在使用 STM3240G-EVAL 板从 ADC 读取值。我使用下面的打印功能将 ADC 的值打印到板上的 LCD 上。我将温度传感器物理连接到评估板上的 3.3V、ADC3 和 GND。返回的值太大。 ADC 分辨率应该是 12 位,因此 4096 应该是 ADC_GetConversionValue 函数输出的最大值。我在室温下收到 5000+ 个值!有没有人对为什么 ADC 值可以被缩放有任何直觉?

////// stm324xg_eval.c
// to configure the ADC
void STM_EVAL_TEMPInit(Temp_TypeDef Temp) 


RCC_PCLK2Config(RCC_HCLK_Div8);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC3, ENABLE);
/* Enable the GPIO_TEMP Clock */
RCC_AHB1PeriphClockCmd(GPIO_TEMP_CLK[Temp], ENABLE);

/* Configure the GPIO_TEMP pin */
GPIO_InitTypeDef  GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_TEMP_PIN[Temp];
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIO_TEMP_PORT[Temp], &GPIO_InitStructure);


/* Enable ADC3 Clock */
ADC_InitTypeDef           ADC_InitStructure;
ADC_CommonInitTypeDef     ADC_CommonInitStructure;

ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled;
ADC_CommonInitStructure.ADC_TwoSamplingDelay = 0;
ADC_CommonInit(&ADC_CommonInitStructure);

ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
ADC_InitStructure.ADC_ScanConvMode = DISABLE;
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;      
ADC_Init(ADC3, &ADC_InitStructure);

ADC_RegularChannelConfig(ADC3, ADC_Channel_4, 1, ADC_SampleTime_144Cycles);
ADC_Cmd(ADC3, ENABLE);



////// main.cpp
// to print to lcd  
ADC_SoftwareStartConv(ADC3);
temp_value = ADC_GetConversionValue(ADC3);
uint8_t mymsg[20];
sprintf((char *)mymsg, "ADC = %d",(int)temp_value);
LCD_DisplayStringLine(Line6, mymsg);


////// stm32f4xx_adc.c
// ADC_GetConversionValue function
/**
* @brief  Returns the last ADCx conversion result data for regular channel.
* @param  ADCx: where x can be 1, 2 or 3 to select the ADC peripheral.
* @retval The Data conversion value.
*/
uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx)

   /* Check the parameters */
   assert_param(IS_ADC_ALL_PERIPH(ADCx));
   /* Return the selected ADC conversion value */
   return (uint16_t) ADCx->DR;

【问题讨论】:

大型评估板通常使用较大的封装,该封装会将 VRef 引出到引脚上。你确定你的 12 位代表 0v - 3.3v 而不是 0v - 2.5v? 【参考方案1】:

我缺少一个 ADC 配置;

ADC_InitStructure.ADC_NbrOfConversion = 1;

确保您在使用 ADC 时使用了所有配置并且没有遗漏任何配置。包括这个之后,我能够使用万用表获得与传感器读取的 ADC 值相同的电压。

添加说明:

这是因为您已将以下结构定义为本地

ADC_InitTypeDef           ADC_InitStructure;

ADC_CommonInitTypeDef     ADC_CommonInitStructure;

并且一个局部变量有一个不可靠(随机)的初始值,因此它可能导致例如ADC_NbrOfConversion变成不合适的数字,使得这样的当它被写入相应的寄存器时出现问题。

【讨论】:

【参考方案2】:

以下代码对我有用:


#define HW_DIVIDE      2
#define VREF_IN_mV     2500
#define MAX_RESOLUTION 255

static void _setup_rcc()

    // Enable the ADC interface clock
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);

    // Enable the clock for the ADC GPIOs
    RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_GPIOA, ENABLE);


static void _setup_gpio()

    GPIO_InitTypeDef GPIO_InitStructure;

    // Configure source 1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // Configure source 2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // Configure source 3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

    // Configure source 4
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;
    GPIO_Init(GPIOA, &GPIO_InitStructure);


static void _setup_adc()

    ADC_InitTypeDef ADC_InitStructure;
    ADC_DeInit();
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_Resolution = ADC_Resolution_8b;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfConversion = 16;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_Init(ADC1, &ADC_InitStructure);

    // Enable ADC
    ADC_Cmd(ADC1, ENABLE);


void drv_adc_init()

    _setup_rcc();
    _setup_gpio();
    _setup_adc();


uint16_t drv_adc_get_voltage(ADC_CHANNEL_IN type)

    uint16_t val;

    switch (type)
    
    case ADC_3V3:
        ADC_RegularChannelConfig(ADC1,ADC_Channel_4,1,ADC_SampleTime_15Cycles);
        break;
    case ADC_1V2:
        ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_15Cycles);
        break;
    case ADC_3VA:
        ADC_RegularChannelConfig(ADC1,ADC_Channel_6,1,ADC_SampleTime_15Cycles);
        break;
    case VIB_CUR:
        ADC_RegularChannelConfig(ADC1,ADC_Channel_7,1,ADC_SampleTime_15Cycles);
        break;
    

    do
    
        // Start the conversion
        ADC_SoftwareStartConv(ADC1);

        // Processing the conversion
        if (ADC_GetFlagStatus(ADC1, ADC_FLAG_OVR))
        
            ADC1->SR &= ~ADC_FLAG_OVR;
        
    
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));

    // Calculate the converted data
    val = ADC_GetConversionValue(ADC1);

    // Return voltage in millivolts
    return HW_DIVIDE * VREF_IN_mV * val / MAX_RESOLUTION;

【讨论】:

【参考方案3】:

您必须等待转换完成:

ADC_SoftwareStartConv(ADC3);

while( ADC_GetFlagStatus( ADC3, ADC_FLAG_EOC ) == RESET )

    // do nothing (or something useful perhaps)


temp_value = ADC_GetConversionValue(ADC3);

【讨论】:

这个。如果输入> =参考,我从未见过正确的ADC读数不饱和。这向我表明 OP 做错了什么。我的建议:查阅技术参考手册和应用说明 - 我敢打赌,这里有 ADC 读数的示例代码 :)【参考方案4】:

您是否测量了温度传感器上的电压、ACD 输入上的电压和设备上的 VCC 电压?最好在您获得 5000+ 输出时包含它们的运行时值。

您是否尝试将预先已知的电压(例如 3.3 V)馈送到相同的 ADC 输入并比较测量/获得的值?因为你测得5000+的电压好像是4+V。

对于代码,最好屏蔽返回值以便仅考虑 12 位:

return (uint16_t) ((ADCx->DR) & 0xFFF)

【讨论】:

如果需要屏蔽,硬件损坏或配置错误!最好选择 ADC_DataAlign_Left 并将所有样本视为 16 位 - 如果使用不同的 ADC 分辨率(例如此掩码),则可以最大限度地减少必要的更改。

以上是关于我选的传感器两线制输出4-20MA,怎么接到STM32的AD上?的主要内容,如果未能解决你的问题,请参考以下文章

4-20MA电流是怎么产生的?

标准电流信号为什么是4-20MA?(网络摘录)

STM32处理变送器输出的4-20ma,STM32的AD转换只能接受0-3.3V的电压输入,怎么用运放实现转换

STM32F412应用开发笔记之三:SPI总线通讯与AD采集

怎样把电机电流转化为DC4~20ma信号?

三线一控电动球阀三线两控电动球阀两线制断电开阀两线制断电关阀四类电动球阀的区别