Pico Capacimetro con Arduino y Display


Este es sin duda un proyecto muy interesante para aquellos que trabajen con circuito de RF donde siempre se requiere el uso de capacitores en el orden de los Pico Faradios. 
En el mercado encontraremos una gran cantidad de multimetros digitales con medidor de capacitores, pero la gran mayoría (algo así como el 99.9% de los casos) no nos permiten medir capacitores del orden de por ejemplo 10pF sin mostrarnos un error muy grande. Esto se debe a que la mayoría de los DMM con capacimetro tienen una escala de entre 10nF y 20nF como mínimo, y esto es también sumando el problema de capacidad de las puntas del DMM.
En algunos instrumentos como los Puentes LCR que son instrumentos dedicados a medir Inductancias, Capacitancias y Resistencias, podremos encontrar que el mínimo puede ser de 1nF o 100pF (dependiendo de que tan costoso sea ese instrumento) también nos va a proporcionar la medición en circuito (sin necesidad de extraer el componente pasivo del PCB para su medición) gracias a la medición inyectando distintos valores de frecuencia al componente.
En nuestro caso se ha implementado un proyecto muy simple y de bajo costo que nos permitirá medir un fondo de escala de 1nF con 4 dígitos de resolución, esto es de 0000pF a 1000pF, y realmente funciona mejor de lo que esperaba, he probado capacitores de 2.7pF 5.7pF 10pF 12pF 22pF 100pF 220pF 560pF 1nF, y todos los ha medido muy bine, incluso he probado trimmers y varicap sin ningún problema.
El circuito es muy sencillo y básicamente no necesita ningún componente externo (mas que los display y los transistores de multiplexado) las puntas de medición serán los mismos pines del MCU, claro esta, que es necesario realizar las pistas lo mas corto posible para que la medición sea mas fiel, también hay que tener en cuenta la capacidad parásita del PCB, hay que tener cuidado con los planos de tierra debido que pueden sumarnos capacidad si tenemos un clearance muy chico.
Este proyecto basa todo su funcionamiento en el programa y aprovecha parámetros eléctricos del microcontrolador.
Básicamente lo que hacemos es poner un capacitor entre un GPIO y un canal de ADC, iniciamos con el ADC en alta impedancia y con el GPIO en 0, entonces podemos decir que el capacitor esta descargado en el inicio. Luego ponemos el GPIO en 1 y comenzara a cargar el mismo, inmediatamente después pondremos el ADC como lectura y según el valor que el ADC lee (el capacitor comenzó a cargarse y luego realizamos una lectura de ADC, entonces el ADC leerá el valor de tensión que el capacitor llego a cargar en el tiempo que tardo de pasar el ADC de alta impedancia a lectura) sera la capacidad del capacitor. Recordemos que si el capacitor es pequeño, entonces el tiempo que tardara en cargarse sera menor que el tiempo que tardara en cargarse un capacitor mas grande, de mayor capacidad. Tomando en cuenta este proceso entonces podemos decir que obtendremos un valor de ADC entre 0 y 1023 que sera proporcional al valor de capacidad en pF del capacitor en cuestión. Una vez que se realizo la lectura, entonces volvemos a poner GPIO a 0 y el ADC lo pasamos a salida.
Estos tiempos de propagación de pasar un GPIO de 0 a 1 y de 1 a 0 se encuentran en el datasheet del AVR, es al menos unos 30ns según datasheet, lo mismo que el tiempo que demanda la medición del ADC, recordemos que interiormente tenemos un sigma-delta con un sample & hold para la medición. Este sample & hold tendrá una llave y un capacitor, capacitor que debemos tener en cuenta en nuestro programa porque nos sumara una capacidad que tendremos que calcular luego para saber el valor de capacidad real. 
En mi calculo muy simple, he utilizado una constante de 24.5 (es el valor que sale de la prueba entre el capacitor interno del ADC, mas la capacidad parásita del PCB y de los pines), He probado entre 20 y 30, y este valor ha respondió mejor, pero es un valor que deberían probar en su practica a modo calibración cuando realicen el proyecto. 
Esto sera solo unas 10 lineas de código, luego realizamos un filtrado de ruido agregando un promedio de 100 muestras, el resto del programa es solo el manejo multiplexado de los 4 dígitos para mostrar el valor.

VERSIÓN REDUCIDA POR PUERTO SERIE (NO REQUIERE CIRCUITO):


  1. const int OUT_PIN = A4;
  2. const int IN_PIN = A0;
  3. long int acumulado=0;
  4. long int actualizado=0;
  5. void setup(){
  6.    Serial.begin(9600);
  7.    pinMode(OUT_PIN, OUTPUT);
  8.    pinMode(IN_PIN, OUTPUT);
  9. }
  10. void loop(){
  11.    for(int i=0; i<100; i++){
  12.       pinMode(IN_PIN, INPUT);
  13.       digitalWrite(OUT_PIN, HIGH);
  14.       int val = analogRead(IN_PIN);
  15.       digitalWrite(OUT_PIN, LOW);
  16.       pinMode(IN_PIN, OUTPUT);
  17.       float capacitancia = (float)val * 24.5 / (float)(1023 - val);
  18.       acumulado = capacitancia + acumulado;
  19.    }  
  20.    actualizado = acumulado/100;
  21.    acumulado=0;
  22.    Serial.print("Valor en pF: ");
  23.    Serial.println(actualizado);
  24.    delay(100);
  25. }

VERSIÓN COMPLETA CON 4 DÍGITOS:


  1. #define G 12
  2. #define F 11
  3. #define A 10
  4. #define B 9
  5. #define E 8
  6. #define D 7
  7. #define C 6
  8. #define DP 13
  9. #define GND1 5
  10. #define GND2 4
  11. #define GND3 3
  12. #define GND4 2
  13. void digito_0(){
  14. digitalWrite(A, HIGH);
  15. digitalWrite(B, HIGH);
  16. digitalWrite(C, HIGH);
  17. digitalWrite(D, HIGH);
  18. digitalWrite(E, HIGH);
  19. digitalWrite(F, HIGH);
  20. digitalWrite(G, LOW);
  21. }
  22. void digito_1(){
  23. digitalWrite(A, LOW);
  24. digitalWrite(B, HIGH);
  25. digitalWrite(C, HIGH);
  26. digitalWrite(D, LOW);
  27. digitalWrite(E, LOW);
  28. digitalWrite(F, LOW);
  29. digitalWrite(G, LOW);
  30. }
  31. void digito_2(){
  32. digitalWrite(A, HIGH);
  33. digitalWrite(B, HIGH);
  34. digitalWrite(C, LOW);
  35. digitalWrite(D, HIGH);
  36. digitalWrite(E, HIGH);
  37. digitalWrite(F, LOW);
  38. digitalWrite(G, HIGH);
  39. }
  40. void digito_3(){
  41. digitalWrite(A, HIGH);
  42. digitalWrite(B, HIGH);
  43. digitalWrite(C, HIGH);
  44. digitalWrite(D, HIGH);
  45. digitalWrite(E, LOW);
  46. digitalWrite(F, LOW);
  47. digitalWrite(G, HIGH);
  48. }
  49. void digito_4(){
  50. digitalWrite(A, LOW);
  51. digitalWrite(B, HIGH);
  52. digitalWrite(C, HIGH);
  53. digitalWrite(D, LOW);
  54. digitalWrite(E, LOW);
  55. digitalWrite(F, HIGH);
  56. digitalWrite(G, HIGH);
  57. }
  58. void digito_5(){
  59. digitalWrite(A, HIGH);
  60. digitalWrite(B, LOW);
  61. digitalWrite(C, HIGH);
  62. digitalWrite(D, HIGH);
  63. digitalWrite(E, LOW);
  64. digitalWrite(F, HIGH);
  65. digitalWrite(G, HIGH);
  66. }
  67. void digito_6(){
  68. digitalWrite(A, HIGH);
  69. digitalWrite(B, LOW);
  70. digitalWrite(C, HIGH);
  71. digitalWrite(D, HIGH);
  72. digitalWrite(E, HIGH);
  73. digitalWrite(F, HIGH);
  74. digitalWrite(G, HIGH);
  75. }
  76. void digito_7(){
  77. digitalWrite(A, HIGH);
  78. digitalWrite(B, HIGH);
  79. digitalWrite(C, HIGH);
  80. digitalWrite(D, LOW);
  81. digitalWrite(E, LOW);
  82. digitalWrite(F, LOW);
  83. digitalWrite(G, LOW);
  84. }
  85. void digito_8(){
  86. digitalWrite(A, HIGH);
  87. digitalWrite(B, HIGH);
  88. digitalWrite(C, HIGH);
  89. digitalWrite(D, HIGH);
  90. digitalWrite(E, HIGH);
  91. digitalWrite(F, HIGH);
  92. digitalWrite(G, HIGH);
  93. }
  94. void digito_9(){
  95. digitalWrite(A, HIGH);
  96. digitalWrite(B, HIGH);
  97. digitalWrite(C, HIGH);
  98. digitalWrite(D, HIGH);
  99. digitalWrite(E, LOW);
  100. digitalWrite(F, HIGH);
  101. digitalWrite(G, HIGH);
  102. }
  103. void numero(int digito){
  104.    switch(digito){
  105.    case 0:
  106.       digito_0();
  107.       break;
  108.    case 1:
  109.       digito_1();
  110.       break;
  111.    case 2:
  112.       digito_2();
  113.       break;
  114.    case 3:
  115.       digito_3();
  116.       break;
  117.    case 4:
  118.       digito_4();
  119.       break;
  120.    case 5:
  121.       digito_5();
  122.       break;
  123.    case 6:
  124.       digito_6();
  125.       break;
  126.    case 7:
  127.       digito_7();
  128.       break;
  129.    case 8:
  130.       digito_8();
  131.       break;
  132.    case 9:
  133.       digito_9();
  134.       break;
  135.    default:
  136.       break;
  137.    }
  138. }
  139. void mux(int dig4, int dig3, int dig2, int dig1){
  140.    digitalWrite(GND1, HIGH);
  141.    digitalWrite(GND2, LOW);
  142.    digitalWrite(GND3, LOW);
  143.    digitalWrite(GND4, LOW);
  144.    numero(dig1);
  145.    delay(3);
  146.    digitalWrite(GND1, LOW);
  147.    digitalWrite(GND2, HIGH);
  148.    digitalWrite(GND3, LOW);
  149.    digitalWrite(GND4, LOW);
  150.    numero(dig2);
  151.    delay(3);
  152.    digitalWrite(GND1, LOW);
  153.    digitalWrite(GND2, LOW);
  154.    digitalWrite(GND3, HIGH);
  155.    digitalWrite(GND4, LOW);
  156.    numero(dig3);
  157.    delay(3);
  158.    digitalWrite(GND1, LOW);
  159.    digitalWrite(GND2, LOW);
  160.    digitalWrite(GND3, LOW);
  161.    digitalWrite(GND4, HIGH);
  162.    numero(dig4);
  163.    delay(3);
  164. }
  165. void mostrar(int valor){
  166.    int uno, diez, cien, mil;
  167.    mil=valor/1000;
  168.    cien=(valor/100)%10;
  169.    diez=(valor/10)%10;
  170.    uno=valor%10;
  171.    mux(uno,diez,cien,mil);
  172. }
  173. const int OUT_PIN = A4;
  174. const int IN_PIN = A0;
  175. long int acumulado=0;
  176. long int actualizado=0;
  177. void setup(){
  178.    pinMode(A, OUTPUT);
  179.    pinMode(B, OUTPUT);
  180.    pinMode(C, OUTPUT);
  181.    pinMode(D, OUTPUT);
  182.    pinMode(E, OUTPUT);
  183.    pinMode(F, OUTPUT);
  184.    pinMode(G, OUTPUT);
  185.    pinMode(DP, OUTPUT);
  186.    pinMode(GND1, OUTPUT);
  187.    pinMode(GND2, OUTPUT);
  188.    pinMode(GND3, OUTPUT);
  189.    pinMode(GND4, OUTPUT);
  190.    pinMode(OUT_PIN, OUTPUT);
  191.    pinMode(IN_PIN, OUTPUT);
  192. }
  193. void loop(){
  194.    for(int i=0; i<100; i++){
  195.       pinMode(IN_PIN, INPUT);
  196.       digitalWrite(OUT_PIN, HIGH);
  197.       int val = analogRead(IN_PIN);
  198.       digitalWrite(OUT_PIN, LOW);
  199.       pinMode(IN_PIN, OUTPUT);
  200.       float capacitancia = (float)val * 24.5 / (float)(1023 - val);
  201.       acumulado = capacitancia + acumulado;
  202.       mostrar(actualizado);
  203.    }  
  204.    actualizado = acumulado/100;
  205.    acumulado=0;
  206. }