1 votos

Conversión de valores ADC

Estoy obteniendo el valor ADC de escala completa de 0 to 16348 . Estoy tratando de convertirlo a 4-20mA y luego a 0-25 bar de presión, ya que al final estoy midiendo la presión.

Estoy utilizando el y = mx+c ecuación pero fracasando estrepitosamente. Puede alguien por favor guiar para que pueda aprender algo.

Estoy intentando algo como

4 = m*0 +c
c = 4.

20 = m*16348 +4.

m = 0.0009789.

Mi controlador no soporta puntos flotantes... de ahí que me esté creando problemas. ¿Puede alguien ayudarme>?

6voto

Matt McMinn Puntos 6067

Como tu microcontrolador no admite la coma flotante, tienes que escalar los números y luego volver a dividirlos. Para ello, tendrá que utilizar la aritmética larga (32 bits).

Para el ADC, 4 ma = 0 y 20 ma = 16384. Por lo tanto, la diferencia 16 ma también está representada por 16384.

Si tomamos la lectura de la escala completa del gráfico de barras, 25, y la dividimos por 16384, obtenemos: 0.001526. Pero no podemos utilizar ese valor directamente porque es de coma flotante. Así que en su lugar tomamos un millón, y hacemos lo mismo. 1000000 / 16384 = 61,03 Ahora tenemos un número lo suficientemente cercano a un entero con el que podemos trabajar.

Si sabemos tomar la lectura del ADC, multiplicar por 61, y dividir por 40000 (que es 1000000 / 25), entonces tendremos un número en el rango 0-25. Para probar esto, si tomamos un valor igual a la mitad del rango (16384/2), entonces para 8192 * 61 / 40000 obtenemos 12,49 o la mitad de 25 (pero como es una división entera, se redondeará a 12)

Si, para alguna otra aplicación, quisieras un valor entero en centenas a escala (es decir, multiplicado por 100), podrías dividir por 400 en lugar de 40000 y obtener 1249 (que representa 12,49).

Así que el código es algo así (he utilizado el casting para asegurarme de que todos los cálculos necesarios se hacen como longs)

#define CONSTANT1 = (1000000L / 16384L)       // 61    
#define CONSTANT2 = (1000000L / 25L)          // 40000

unsigned short ADC_value;
unsigned short bar_value;

ADC_value = get_ADC();
bar_value = (unsigned char)(((unsigned long)ADC_Value * CONSTANT1) / CONSTANT2);

2voto

Rory Alsop Puntos 2709

No está muy claro lo que estás haciendo, así que vamos a ir paso a paso.

Así, el sensor da una corriente, donde 0-25 Bar corresponden a 4-20mA.

$$I_{sens}=16mA\cdot \frac{p}{25 Bar} +4mA$$

Ahora, el propio ADC tiene un rango de entrada, por ejemplo 0-5V y lo convierte en un número entero. No sé cómo se obtiene 16348, el siguiente valor coincidente sería 16383, que es binario 111111'11111111. (Ese es el valor máximo de un ADC de 14 bits)

Por lo tanto, necesitas una resistencia como R=250 Ohm conectada a la salida de tu sensor (a tierra), que convierta la corriente en 1-5V

Ahora, la fórmula es

$$V_{ADC}=4V\cdot \frac{p}{25 Bar}+1V$$

y esto se asigna a la gama de ADC

$$N_{ADC}=\frac{16383\cdot 16}{20} \cdot \frac{p}{25 Bar}+\frac{16383\cdot 4}{20}$$ y su reverso $$p=\left(N_{ADC}-\frac{16383\cdot 4}{20}\right)\cdot\frac{20\cdot 25Bar}{16383\cdot 16}$$

o después de la limpieza: $${p={\frac{125\cdot N_{ADC}-409575}{262128}}Bar}$$

Esto es lo mejor que se puede conseguir, sin embargo, la resolución es sólo 1 Bar, porque p es un número entero. Y como se dice en los comentarios, es importante hacer la división como el último paso.

La resolución es pobre, aunque el rango dinámico es de 16383/20*16=13106 (Ese es el número de pasos al que el ADC mapea su rango de entrada). Para una mejor resolución, puedes optar por los milibares:

$${p={\frac{1000\cdot(125\cdot N_{ADC}-409575)}{262128}}millibar}$$

De nuevo, haz primero la multiplicación. Y: El mayor valor del numerador es 1.638.300.000, que ocupa 31 bits. Así que tienes que asegurarte de que tu microcontrolador hace este cálculo con valores enteros de 32 bits.

Algunas ideas:

  • Si no le gustan estos números tan grandes, puede utilizar 16384 en lugar de 16383. Esto es sólo una pequeña desviación, pero puede permitir más cancelaciones en la fracción. Además, si nunca va a medir 25Bar, pruebe con una resistencia que dé la tensión máxima ya a 24 bar. Este valor también permite más cancelaciones.

  • Algunos microcontroladores, por ejemplo de microchip, permiten dar tensiones de referencia mínimas/máximas, por ejemplo puedes conectar dos tensiones que definan el límite superior e inferior del ADC. Con 1V y 5V, esto mapeará los 1-5V de la resistencia a los 14bit completos del ADC, dándote los 16384 pasos completos, no sólo el 80% de ellos.

  • El último punto también se puede conseguir con un amplificador de funcionamiento.

EDITAR:

Como los valores necesitan un máximo de 31 bits, debes utilizar un valor entero de 32 bits con signo (que es 1bit para el signo y 31 para el número). Si no se conecta ningún sensor / el ADC recibe menos de 1V, se obtiene un valor negativo para la presión que se puede decir que no es válido.

Si se utilizan enteros de 32 bits sin signo, en este caso se obtiene una basura y no se puede distinguir entre valor válido y no válido.

1voto

Neil Foley Puntos 1313

Supongo que en realidad estás obteniendo un valor de 0 a 16383 (3FFFh) como es estándar para un ADC de 14 bits. Parece bastante extraño que tu ADC dé valor cero para 4mA, pero eso es lo que nos dices, así que asumiré que tienes algún circuito especial haciendo esto por ti.

Convertir a miliamperios como paso intermedio no tiene sentido, esa es una representación utilizada por los humanos y no es necesaria para tu software, a menos que desees mostrar la corriente en una pantalla o algo así. Parece que no necesitas ese paso intermedio, todo lo que hará es causar errores de redondeo.

Lo mismo ocurre con el punto flotante: en la mayoría de los casos no deberías usar números flotantes, porque lo más probable es que sean terriblemente lentos. Siempre son más lentos que los enteros, pero especialmente si no hay una FPU a bordo.

Así que lo que deberías hacer es: cuando programes, deja de pensar como cuando haces matemáticas. La coma flotante se reserva para los casos en los que necesitas precisión y matemáticas más avanzadas, como la trigonometría. Tu programa funcionará perfectamente con enteros crudos en el 95% de los casos.

En cuanto al problema que nos ocupa, tenemos un valor entero de 0 a 16383 que queremos convertir en 0-25 bar. Utilizando y = mx + c le da 25 = m*16838 + 0 , m = 25/16838 . S 25/16383 obtendrá el valor de la barra, es decir adc_read * 25 / 16383 .

También hay que multiplicar por 1000 para obtener una mayor resolución, milibar en lugar de bar. Así que aparentemente el valor más grande que podemos encontrar en este caso es 16383 (lectura máxima del ADC) multiplicado por 25*1000 = 159*10^6. Esto no cabe en un entero de 16 bits, así que tenemos que utilizar la aritmética de 32 bits.

uint32_t adc_read = ADC_DATA_REGISTER;
uint8_t millibar = (uint8_t)(adc_read * 25ul * 1000ul / 16383ul);

Y eso es todo. Asumiendo que el 0 corresponde realmente a 4mA.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X