Portar el código MikroC a MPLAB para PIC16F1508 agregando ruido adicional a ADC

Decidí comenzar a usar MPLAB con XC8 después de que comencé a alcanzar el límite de tamaño de código de 2k en MikroC. El problema es que, dado que todas las bibliotecas de Mikroc son propietarias y no hay bibliotecas disponibles para la serie PIC16F en MPLAB, tuve que escribir mis propias funciones ADC.

Estas son las dos funciones que escribí para configurar mi ADC usando la hoja de datos:

void ADC_Init(){
    PIR1bits.ADIF = 0; // Clear interrupt flag
    PIE1bits.ADIE = 0; // Disable ADC interrupt
    INTCONbits.PEIE = 0; // Disable perriferal interrupts

    ADCON2 = 0; // No ADC Trigger

    ADCON1bits.ADCS = 0b111; // Select internal RC clock source
    ADCON1bits.ADPREF = 0b00; // Select VDD as Vref
    ADCON1bits.ADFM = 0; // Left justify, upper 8 MSB in ADRESH

    ADCON0bits.ADON = 1; // Turn on ADC Module
}

int ADC_Read(char channel){
    ADCON0bits.CHS = channel; // Set channel, must be between 0 and 11
    __delay_us(5); // Wait some arbitrary acquisiton time

    PIR1bits.ADIF = 0; // Clear interrupt flag
    ADCON0bits.GO_nDONE = 1; // Start acquisioin

    while(ADCON0bits.GO_nDONE) {} // Wait for the conversion to finish

    return (ADRESH << 2) | ADRESL;

}

Para empezar, la señal de entrada que estoy leyendo es bastante ruidosa. En mi programa MikroC con las funciones ADC de la biblioteca, el ruido de fondo en las muestras osciló entre 60 y 100 (ADC de 10 bits). Por piso de ruido, me refiero al rango de valores que el ADC estaba leyendo sin entrada. Ruido del resto del sistema, supongo.

En MPLAB con las funciones anteriores, el ruido de fondo se ha disparado de 200 a 300. En un ADC de 10 bits, tanto ruido es inaceptable. Ejecuto la función ADC_Init() una vez fuera de mi ciclo de programa principal, luego uso la función ADC_Read(..) en mi ciclo de programa.

¿Alguna idea de por qué el ruido es mucho mayor? ¿O alguna idea sobre cómo MikroC obtiene este rendimiento? Sospecho que tiene algo que ver con la forma en que configuré el ADC.

EDITAR

En respuesta a la respuesta de Olin, creo que el "tiempo de adquisición" de 5us podría ser un nombre inapropiado, ese retraso está ahí para permitir que el condensador de retención se cargue después de cambiar los canales ADC. La hoja de datos muestra un ejemplo de una impedancia de señal de 10 kohm que necesita un tiempo de carga de 7,4 us. La impedancia de mi señal es de solo 700 ohmios, así que pensé que 5us debería ser más que suficiente. En cuanto al circuito, no ha cambiado, solo el software. Y la señal que estoy midiendo es una señal digital ligeramente ruidosa que sale de un IC de filtro MSGEQ7.

Respuestas (2)

Esta es una buena ilustración de los problemas con los que se encuentra al usar bibliotecas enlatadas.

Si originalmente tenía un 10% de ruido en la señal, entonces tal vez el problema esté en el circuito. ¿Qué tipo de señal estás midiendo? ¿Cuál es su frecuencia superior? ¿Con qué frecuencia toma muestras? Sería útil mostrar el esquema.

Parece que está permitiendo 5 µs para la adquisición, pero ¿cómo sabe que es suficiente? ¿Qué impedancia es la señal que se alimenta al A/D? Una posible explicación de sus síntomas es que la impedancia de la señal es demasiado alta y el código anterior usaba un tiempo de adquisición más largo, lo que permitió que la muestra y la retención se asentaran más cerca del valor correcto.

Sin embargo, una mejor respuesta probablemente sea repensar toda la estrategia A/D en primer lugar. No lo base en las rutinas de la biblioteca que están disponibles o alguna tontería similar. Lea la sección de la hoja de datos sobre el A/D y piense en la mejor manera de usarlo, posiblemente junto con otro hardware, como temporizadores, para resolver el problema de medición general.

Una estrategia que utilizo con frecuencia es tomar lecturas A/D en una interrupción periódica. Ejecute esto tan rápido como el A/D le permita adquirir y convertir la señal, y dentro de los límites de dejar suficientes ciclos de primer plano para el resto del sistema. Esta interrupción A/D muestrea el A/D mucho más rápido de lo que realmente necesita, luego filtra los resultados con filtros de paso bajo. Cuando el código principal quiere la última lectura, no sale y toma una sola lectura A/D. Solo usa el valor actual de la salida del filtro de paso bajo. He hecho este tipo de cosas muchas veces. De hecho, es mi forma normal de tomar lecturas A/D a menos que haya una razón específica para hacerlo de manera diferente.

En un microcontrolador pequeño, no hay sustituto para comprender realmente el hardware y ser consciente de cómo se usa exactamente, ya sea a través de su propio código o de rutinas de "biblioteca".

Añadido sobre interrupciones A/D periódicas

Ahora dice que está utilizando interrupciones periódicas para leer el A/D, pero entonces su código tiene aún menos sentido que antes. Si solo está leyendo un solo canal, entonces dejaría el A/D configurado en ese canal y no lo cambiaría durante la operación normal. Si está leyendo varios canales, la interrupción los recorrerá. En ese caso, la interrupción de la conversión A/D realizada cambiaría el hardware al nuevo canal justo después de obtener los resultados de la conversión. De esa manera, la mayor parte del tiempo que no es conversión se usa para adquirir la siguiente señal. Incluso si tuviera que ejecutar el A/D bastante rápido, como 100 kHz por ejemplo, eso aún deja la mayoría de 10 µs para la adquisición.

Por lo general, no llamaría a una rutina de conversión A/D desde una interrupción de todos modos, e incluso si lo hiciera, no estaría cambiando el canal y luego esperando la adquisición y la conversión mientras el código de primer plano está bloqueado fuera del procesador. . Eso no tiene sentido y es innecesario.

Luego está el problema de devolver el valor de 10 bits sin signo justificado a la izquierda en un entero con signo. No tiene sentido que los valores de 512 y superiores se interpreten como negativos.

Una vez más, ¿cuál es el contenido de frecuencia superior de la señal? ¿Con qué frecuencia el firmware necesita su valor? Hago estas preguntas por buenas razones, y espero que las responda ya sea que crea que son relevantes o que entienda las razones o no. Después de todo, este es tu problema. Somos voluntarios tratando de ayudar, pero si se niega a cooperar, encontraremos otros lugares para pasar nuestro tiempo limitado aquí.

Agregué una edición a mi publicación basada en tu respuesta. De hecho, estoy usando una técnica similar en la que el ADC se muestrea en interrupciones periódicas y se usa un filtro complementario simple para LPF la señal. A pesar de eso, todavía no explica por qué el ADC estaría leyendo valores mucho más altos sin entrada que antes.
@Shub: Eso todavía no responde las otras preguntas. El código que muestra no tiene sentido para una interrupción, ya que cambia el canal solo a pedido, luego hace una espera ocupada. Una interrupción periódica cambiaría el canal en la interrupción para la conversión anterior. Luego, el A/D obtiene la mayor parte del período de interrupción para la adquisición.

No hay nada inherente a ninguna de las bibliotecas que deba afectar el ruido de fondo. El estado predeterminado para muchos PIC ADC es de 8 bits, y debe configurar las cosas para obtener los 10 bits completos (no sé cómo se hace eso en MPLAB). Esto puede haber sido manejado por usted en MikroC. Además, debe asegurarse de que sus datos estén justificados correctamente en el entero de 16 bits. Si lo tiene justificado a la izquierda, y solía estar justificado a la derecha, su piso de ruido se vería grande