Ich verwende derzeit einen PIC16f1826, um zu versuchen, die Spannung der 3,7-V-Batterie zu messen, die den Mikrocontroller mit Strom versorgt.
Nach meinem Verständnis kann der ADC von 0 V bis zur in 1024 Teile geteilten Referenzspannung messen, sodass ich die Batterie nicht als Referenzspannung verwenden kann. Stattdessen verwende ich eine feste Spannungsreferenz bei 2,048 V, die im Mikrocontroller generiert wird.
2,048 liegt jedoch unter der 3,7-V-Batterie, die ich zu messen versuche, also verwende ich einen Spannungsteiler, um den Eingang zu halbieren, damit ich aussagekräftige Messwerte erhalten kann. Wenn ich dies jedoch tue und versuche, meinen Messwert zu erhalten, erhalte ich einen Wert von 6-5/1023, was einfach falsch erscheint. Wenn ich die Batterie ohne Spannungsteiler anschließe bekomme ich die volle 1023/1023.
Meine Schaltung sieht wie folgt aus:
Simulieren Sie diese Schaltung – Mit CircuitLab erstellter Schaltplan
Ich habe die UART-Verbindung weggelassen, da sie für die Frage nicht relevant ist. Mein Code für den ADC ist folgender:
#include <xc.h>
#include <stdlib.h>
// CONFIG1
#pragma config FOSC = INTOSC // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)
// CONFIG2
#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)
// Define Oscillator Frecuency to use in delay_ms calculations.
#define _XTAL_FREQ 4000000 // 4MHz
// Function that initializes ADC parameters.
void initADC(void) {
// Enable Fixed Voltage Reference.
FVRCONbits.FVREN = 1;
// Set Fixed Voltage Reference to 2.048V.
FVRCONbits.ADFVR = 0b10;
// Enable Analog input on RA1.
TRISA1 = 0;
ANSELAbits.ANSA1 = 0;
// Define Conversion Clock to use FOSC/4.
ADCON1bits.ADCS = 0b100;
// Configure ADC Positive Reference Voltage to use FVR buffer.
ADCON1bits.ADPREF = 0b11;
// Configure ADC Negative Reference Voltage to use VSS.
ADCON1bits.ADNREF = 0;
// Output format as right justified.
ADCON1bits.ADFM = 1;
// Select Pin AN1 as Channel.
ADCON0bits.CHS = 0b00001;
// Start ADC Module.
ADCON0bits.ADON = 1;
// Start conversion.
ADCON0bits.GO_nDONE = 1;
}
// Main function.
void main(void) {
// Setup Internal Oscillator to run at 4MHz.
OSCCONbits.IRCF = 0b1101;
// Initialize ADC.
initADC();
while(1) {
if(!ADCON0bits.GO_nDONE) {
sendString("Ready: ");
// Read ADC Result Register High and
// Register Low for full 10 bit scope.
int adcResult = ((ADRESH)<<8)|(ADRESL);
char percentToChar[5];
itoa(percentToChar, adcResult, 10);
sendString(percentToChar);
sendString("\n");
ADCON0bits.GO_nDONE = 1;
} else {
sendString("Not ready \n");
}
__delay_ms(300);
}
}
Das Handbuch für den Mikrocontroller finden Sie unter: http://ww1.microchip.com/downloads/en/DeviceDoc/41391D.pdf Seite 135 behandelt die Festspannungsreferenz und Seite 140 behandelt ADC.
Warum erhalte ich den Messwert, den ich im ADC erhalte? Es ergibt für mich keinen Sinn, mache ich vielleicht etwas im Code falsch? Sollte ich dazu das Komparatormodul anstelle des ADC verwenden? Jede Hilfe, die Sie leisten können, um mir bei der Lösung dieses Problems zu helfen, wird sehr geschätzt!
Das ist nicht meine Antwort, aber diese Frage sitzt seit Monaten hier mit der Antwort in den Kommentaren.
Wie Wouter van Ooijen in den Kommentaren feststellt, wird die interne Referenz als A / D-Eingang und Vdd als Referenz verwendet
Das Ablesen von N entspricht einer Vdd von 1023 * Vref/N
ADCON0bits.CHS = 0b11111;
dem FVR als ADC-Kanal auszuwählen, ADCON1bits.ADPREF = 0b00;
Vdd als positive Referenz zu verwenden und dannVdd = 2.048*1023/adcResult
Eugen Sch.
itoa
richtig verwenden. Das erste Argument sollte der zu konvertierende Wert sein, das zweite ist der Puffer.Wouter van Ooijen
patrickdamery
patrickdamery
Wouter van Ooijen
Russell McMahon
patrickdamery
patrickdamery
Wouter van Ooijen
patrickdamery