Portierung von MikroC-Code auf MPLAB für PIC16F1508, der ADC zusätzliches Rauschen hinzufügt

Ich entschied mich, MPLAB mit XC8 zu verwenden, nachdem ich anfing, die 2k-Codegrößenbeschränkung in MikroC zu erreichen. Das Problem ist, dass ich meine eigenen ADC-Funktionen schreiben musste, da alle Mikroc-Bibliotheken proprietär sind und keine Bibliotheken für die PIC16F-Serie in MPLAB verfügbar sind.

Dies sind die beiden Funktionen, die ich geschrieben habe, um meinen ADC mithilfe des Datenblatts einzurichten:

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;

}

Das Eingangssignal, das ich einlese, ist zunächst ziemlich laut. In meinem MikroC-Programm mit den Bibliotheks-ADC-Funktionen lag das Grundrauschen der Samples zwischen 60 und 100 (10-Bit-ADC). Mit Grundrauschen meine ich den Wertebereich, den der ADC ohne Eingabe gelesen hat. Rauschen vom Rest des Systems, nehme ich an.

In MPLAB mit den oben genannten Funktionen ist das Grundrauschen um 200 bis 300 hochgeschossen. Bei einem 10-Bit-ADC ist so viel Rauschen nicht akzeptabel. Ich führe die Funktion ADC_Init() einmal außerhalb meiner Hauptprogrammschleife aus und verwende dann die Funktion ADC_Read(..) in meiner Programmschleife.

Irgendwelche Ideen, warum das Geräusch so viel mehr ist? Oder irgendwelche Ideen, wie MikroC diese Leistung bekommt? Ich vermute, dass es etwas mit der Art und Weise zu tun hat, wie ich den ADC konfiguriert habe.

BEARBEITEN

Als Antwort auf Olins Antwort glaube ich, dass die "Erfassungszeit" von 5 us eine Fehlbezeichnung sein könnte, diese Verzögerung ist da, damit sich der Haltekondensator nach dem Wechseln der ADC-Kanäle aufladen kann. Das Datenblatt zeigt ein Beispiel für eine Signalimpedanz von 10 kOhm, die eine Ladezeit von 7,4 us benötigt. Meine Signalimpedanz beträgt nur 700 Ohm, also dachte ich, dass 5 us mehr als genug sein sollten. An der Schaltung hat sich nichts geändert, nur die Software. Und das Signal, das ich messe, ist ein leicht verrauschtes digitales Signal, das aus einem MSGEQ7-Filter-IC kommt.

Antworten (2)

Dies ist ein gutes Beispiel für die Probleme, auf die Sie stoßen, wenn Sie vorgefertigte Bibliotheken verwenden.

Wenn Sie ursprünglich 10% Rauschen im Signal hatten, liegt das Problem möglicherweise an der Schaltung. Was für ein Signal misst du? Was ist seine obere Frequenz? Wie oft proben Sie? Es wäre nützlich, den Schaltplan zu zeigen.

Sie scheinen 5 µs für die Erfassung zuzulassen, aber woher wissen Sie, dass das ausreicht? Welche Impedanz hat das Signal, das dem A/D zugeführt wird? Eine mögliche Erklärung für Ihre Symptome ist, dass die Signalimpedanz zu hoch ist und der vorherige Code eine längere Erfassungszeit verwendet hat, wodurch sich Sample und Hold näher auf den richtigen Wert einstellen konnten.

Eine bessere Antwort ist jedoch wahrscheinlich, die gesamte A/D-Strategie von vornherein zu überdenken. Basieren Sie es nicht darauf, welche Bibliotheksroutinen gerade verfügbar sind, oder auf ähnlichen Unsinn. Lesen Sie den Datenblattabschnitt zum A/D und denken Sie darüber nach, wie Sie ihn am besten verwenden können, möglicherweise in Verbindung mit anderer Hardware, wie z. B. Timern, um das gesamte Messproblem zu lösen.

Eine Strategie, die ich oft verwende, besteht darin, A/D-Messwerte in einem periodischen Interrupt zu nehmen. Sie führen dies so schnell aus, wie es der A/D zulässt, das Signal zu erfassen und umzuwandeln, und innerhalb der Grenzen, genügend Vordergrundzyklen für den Rest des Systems zu lassen. Dieser A/D-Interrupt tastet den A/D viel schneller ab, als Sie wirklich brauchen, und filtert dann die Ergebnisse tiefpass. Wenn der Hauptcode den letzten Messwert haben möchte, geht er nicht aus und nimmt einen einzigen A/D-Messwert vor. Es verwendet nur den aktuellen Wert des Tiefpassfilterausgangs. Ich habe so etwas schon oft gemacht. Tatsächlich ist es meine normale Art, A/D-Messungen vorzunehmen, es sei denn, es gibt einen bestimmten Grund, es anders zu machen.

Bei einem kleinen Mikrocontroller gibt es keinen Ersatz dafür, die Hardware tatsächlich zu verstehen und sich bewusst zu sein, wie genau sie verwendet wird, sei es durch Ihren eigenen Code oder "Bibliotheks" -Routinen.

Über periodische A/D-Interrupts hinzugefügt

Sie sagen jetzt, dass Sie periodische Interrupts verwenden, um den A / D zu lesen, aber dann macht Ihr Code noch weniger Sinn als zuvor. Wenn Sie nur einen einzigen Kanal lesen, würden Sie die A/D-Einstellung auf diesem Kanal belassen und ihn während des normalen Betriebs nicht ändern. Wenn Sie mehrere Kanäle lesen, würde der Interrupt sie durchlaufen. In diesem Fall würde die A/D-Konvertierungsunterbrechung die Hardware direkt nach dem Erfassen der Konvertierungsergebnisse auf den neuen Kanal umschalten. Auf diese Weise wird die meiste Zeit, die keine Konvertierung ist, verwendet, um das nächste Signal zu erfassen. Selbst wenn Sie den A/D ziemlich schnell laufen lassen, wie zum Beispiel 100 kHz, bleiben immer noch die meisten 10 µs für die Erfassung.

Sie würden im Allgemeinen sowieso keine A / D-Konvertierungsroutine von einem Interrupt aufrufen, und selbst wenn Sie dies tun würden, würde sie nicht den Kanal ändern und dann auf die Erfassung und Konvertierung warten, während der Vordergrundcode vom Prozessor gesperrt ist . Das macht keinen Sinn und ist unnötig.

Dann gibt es das Problem, den vorzeichenlosen 10-Bit-Wert linksbündig in eine vorzeichenbehaftete Ganzzahl zurückzugeben. Es macht keinen Sinn, Werte ab 512 als negativ zu interpretieren.

Noch einmal, was ist der obere Frequenzinhalt des Signals? Wie oft braucht die Firmware ihren Wert? Ich stelle diese Fragen aus guten Gründen, und ich erwarte, dass Sie sie beantworten, unabhängig davon, ob Sie sie für relevant halten oder die Gründe verstehen oder nicht. Schließlich ist dies Ihr Problem. Wir sind Freiwillige, die versuchen zu helfen, aber wenn Sie sich weigern zu kooperieren, werden wir andere Orte finden, an denen wir unsere begrenzte Zeit hier verbringen können.

Ich habe meinen Beitrag basierend auf Ihrer Antwort bearbeitet. Ich verwende tatsächlich eine ähnliche Technik, bei der der ADC bei periodischen Interrupts abgetastet wird und ein einfacher komplementärer Filter zum LPF des Signals verwendet wird. Trotzdem erklärt es immer noch nicht, warum der ADC ohne Eingabe viel höhere Werte lesen würde als zuvor.
@Shub: Das beantwortet immer noch nicht die anderen Fragen. Der von Ihnen angezeigte Code macht für einen Interrupt keinen Sinn, da er den Kanal nur auf Anfrage ändert und dann ein beschäftigtes Warten ausführt. Ein periodischer Interrupt würde den Kanal im Interrupt für die vorherige Umwandlung ändern. Dann erhält der A/D den größten Teil der Unterbrechungsperiode für die Erfassung.

Keine der Bibliotheken ist inhärent, was sich auf das Grundrauschen auswirken sollte. Der Standardzustand für viele PIC-ADCs ist 8 Bit, und Sie müssen die Dinge konfigurieren, um die vollen 10 Bit zu erhalten (ich weiß nicht, wie das in MPLAB gemacht wird). Dies wurde möglicherweise in MikroC für Sie erledigt. Außerdem müssen Sie sicherstellen, dass Ihre Daten in der 16-Bit-Ganzzahl richtig ausgerichtet sind. Wenn Sie es linksbündig haben und es früher rechtsbündig war, würde Ihr Grundrauschen groß aussehen