conversión de valor ADC

1

Estoy obteniendo un valor de ADC a escala completa de 0 to 16348 . Estoy tratando de convertirlo a 4-20 mA y luego a 0-25 bar de presión, ya que en última instancia estoy midiendo la presión.

Estoy usando la ecuación y = mx+c pero estoy fallando miserablemente. ¿Puede alguien guiarme 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 admite puntos flotantes ... por lo que me está creando problemas. ¿Alguien puede ayudarme & gt ;?

    
pregunta sam

3 respuestas

6

Ya que su microcontrolador no admite el punto flotante, entonces necesita escalar los números y luego dividir hacia abajo. Para hacerlo, deberá utilizar una 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 a escala completa del gráfico de barras, 25, y dividimos por 16384, obtenemos: 0.001526. Pero no podemos usar ese valor directamente ya que es un punto flotante. Así que en lugar de eso 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 de 0-25. Para probar esto, si tomamos un valor igual a la mitad del rango (16384/2), para 8192 * 61/40000 obtenemos 12.49 o la mitad de 25 (pero, debido a su división entera, se redondeará a 12)

Si, para alguna otra aplicación, quisiera un valor entero en cientos escalados (es decir, multiplicado por 100), podría dividir por 400 en lugar de 40000 y obtener 1249 (que representa 12.49).

Entonces, el código es algo como esto (he usado el casting para asegurarme de que todos los cálculos necesarios se realicen en largos)

#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);
    
respondido por el tcrosley
2

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

Entonces, 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 obtienes 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)

Entonces, necesita una resistencia como R = 250 Ohmios conectada a la salida de su sensor (a tierra), que convierte la corriente a 1-5 V

Ahora, la fórmula es

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

y esto se asigna al rango 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 limpiar: $$ {p = {\ frac {125 \ cdot N_ {ADC} -409575} {262128}} Barra} $$

Esto es lo mejor que puedes obtener, sin embargo, la resolución es de solo 1 barra, porque p es un entero. Y como se dijo en los comentarios, es importante hacer la división como el último paso.

La resolución es deficiente, aunque el rango dinámico es 16383/20 * 16 = 13106 (Ese es el número de pasos a los que ADC asigna el rango de entrada). Para una mejor resolución, puede ir por milli-Bar:

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

De nuevo, haz la multiplicación primero. Y: El mayor valor del numerador es 1,638,300,000, que ocupa 31 bits. Por lo tanto, debe asegurarse de que su microcontrolador realice este cálculo con valores enteros de 32 bits.

Algunas ideas:

  • Si no te gustan estos números grandes, puedes usar 16384 en lugar de 16383. Esto es solo una pequeña desviación, pero puede permitir más cancelaciones en la fracción. Además, si nunca va a medir 25 Bar, pruebe una resistencia que proporcione el voltaje máximo ya a 24 bar. Este valor también permite más cancelaciones.

  • Algunos microcontroladores, p. desde el microchip, permita dar voltajes de referencia mín. / máx. Puede conectar dos voltajes que definen los límites superior e inferior del ADC. Con 1V y 5V, esto asignará el 1-5V desde la resistencia hasta los 14 bits completos del ADC, brindándole los 16384 pasos completos, no solo el 80% del mismo.

  • El último punto también se puede lograr con un amplificador de operación.

EDIT:

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

Si usa enteros de 32 bits sin signo, en este caso obtendrá algo de basura y no podrá distinguir entre valores válidos e inválidos.

    
respondido por el sweber
1

Supongo que en realidad está obteniendo un valor de 0 a 16383 (3FFFh) como es estándar para un ADC de 14 bits. Parece bastante extraño que su ADC dé un valor cero para 4 mA, pero eso es lo que nos dice, así que asumiré que tiene un circuito especial que lo hace por usted.

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

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

Entonces, lo que deberías estar haciendo es: cuando programes, deja de pensar como lo haces cuando haces matemáticas. El punto flotante se reserva para los casos en los que necesita precisión y matemáticas más avanzadas, como la trigonometría. Su programa funcionará perfectamente bien con enteros en bruto en el 95% de los casos.

Para el problema en cuestión, tiene un valor entero de 0 a 16383 que desea convertir a 0-25 bar. El uso de y = mx + c te da 25 = m*16838 + 0 , m = 25/16838 . Entonces al multiplicar cualquier lectura de ADC con 25/16383 obtendrá el valor de la barra, es decir, adc_read * 25 / 16383 .

También necesitamos multiplicar por 1000 para obtener una mayor resolución, milibar en lugar de barra. Entonces, aparentemente, el mayor valor que podemos encontrar en este caso es 16383 (lectura máxima de ADC) multiplicado con 25*1000 = 159 * 10 ^ 6. Esto no cabrá en un entero de 16 bits, por lo que necesitamos usar 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. Suponiendo que 0 corresponde en realidad a 4mA.

    
respondido por el Lundin

Lea otras preguntas en las etiquetas

Comentarios Recientes

no se puede ver. La Prop. # 1337 permite que la clase X idéntica se convierta en B. API de conjunto de inicialización de campo con valores de puntero sin formato mezclados con direcciones sin formato sin marcar, causa un error 'Nombre de campo sin formato no válido' al analizar un tipo F. El mismo problema que TDL POC (clase y enlace de prototipo: adición lógica condicional), cuando se usan campos controlados por PS. ¡Pero menos tiempo de compilación y sin verificación de tipo binario! Los valores de enlace... Lees verder