Estoy tratando de leer una entrada analógica con mi PIC18F66K22 usando ADC. Pero el valor supuestamente de 10 bits a menudo llega a valores como 63.241. Descubrí que un valor negativo (imprimir como sin firmar) da como resultado el mismo comportamiento.
Creo que podría haber algún problema con la configuración de mi ADC. Mi PIC tiene una frecuencia de reloj predeterminada (8Mhz). El rango de ADC debe ser de 0v a 2,5v, pero no tiene que ser tan preciso.
Parece que no puedo encontrar la configuración correcta de ADC, creo. Estoy usando el compilador XC8 con la adc.h
biblioteca que lo acompañaba en MPLAB X IDE.
A continuación se muestra el código (hice una nueva prueba de proyecto, con código simplificado). Primero, el adc.c, creo que la configuración es incorrecta y un error en la lectura debería ser fácil de ver.
#include <adc.h>
#include "adc.h"
void adcSetup()
{
OpenADC (
ADC_FOSC_8 &
ADC_RIGHT_JUST &
ADC_20_TAD,
ADC_CH4 &
ADC_INT_OFF &
ADC_REF_VDD_VDD &
ADC_REF_VDD_VSS,
ADC_CH4
);
ENABLE_AN4_ANA();
SetChanADC(ADC_CH4);
}
//TODO ADC with interrupts
unsigned int adcGet(void)
{
ConvertADC();
while(BusyADC()){}
return ReadADC();
}
también mi main.c, los otros archivos xport no son tan interesantes y parecen funcionar bien. No estoy tan seguro de mi conversión de uint a 'c-string' en la funciónvoid buttonHandle(void)
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <p18f66k22.h>
#include <delays.h>
#include <usart.h>
#include "defines.h"
#include "configuration-bits.h"
#include "xport.h"
#include "adc.h"
#define __delay_us(x) _delay((unsigned long)((x)*(8000000/4000000UL)))
#define __delay_ms(x) _delay((unsigned long)((x)*(8000000/4000UL)))
volatile char RxBuf[] = " ";
volatile int RxI = 0;
volatile bool RxMessage = false;
volatile bool ButtonPressed = false;
void SetupRegisters(void);
void SetupInterrupts(void);
void interrupt HighISR(void);
void interrupt low_priority LowISR(void);
void delay_ms(unsigned int x);
void buttonHandle(void);
void messageHandle(void);
void SetupInterrupts(void)
{
INTCONbits.GIE = 1; //Global interrupt enable
RCONbits.IPEN = 1; //Enable priority interrupts
INTCONbits.GIEH = 1; //Global interrupt enable High
INTCONbits.GIEL = 1; //Global interrupt enable Low
INTCONbits.PEIE = 1; //Peripheral Interrupt Enable bit
INTCONbits.PEIE_GIEL = 1; //Peripheral Interrupt Enable?
INTCON3 = 0b00000000; //Clear intcon. INT1 and INT2 are now low priority
INTCON3bits.INT1E = 1; //Enable int1 (BUTTON)
}
void SetupRegisters(void)
{
//76543210
TRISA = 0b10101110; //7:RFID en2 6:x 5:POWER_LEVEL(analog) 4:PWRKEY 3:SW_CHRG 2:SW_FAULT 1:EXT_INP
TRISBbits.TRISB1 = 1; //BUTTON INPUT
TRISEbits.TRISE3 = 0; //XPort RESET
TRISGbits.TRISG3 = 1; //LDO pwrgd (input)
TRISGbits.TRISG4 = 0; //LDO shdn (ldo to toggle xport)
}
/* Main */
int main() {
//---Set up Registers/interrupts of PIC---
//See defines.h for al macros for LED_IN and other pin-renames.
SetupRegisters(); //Registers...
SetupInterrupts(); //Interrupts (button/uart)
adcSetup(); //ADC for power-detection (POWER-LEVEL)
//---Set up peripherals---
xportSetup(); //Using xport as debugging help.
xportEnable(); //Switch ldo to enable it.
while(true){
if(RxMessage){
messageHandle();
}else if(ButtonPressed){
buttonHandle();
ButtonPressed = false;
}
}
return 0;
}
void interrupt high_priority HighIsr(void) //High priority interrupt
{
if(PIR3bits.RC2IF){//USART INTERRUPT
RxBuf[RxI] = RCREG2;
if(RxBuf[RxI] == ';'){//TODO or full
RxMessage = true;
}
RxI++;
}else{
xportSendText("High - unhandled interrupt");
}
}
void interrupt low_priority LowIsr(void) //Low priority interrupt
{
if(INT1IF){ //Button interrupt
ButtonPressed = true; //Set flag (handled in main)
INT1IF = false; //clear interrupt flag afterwards to avoid hardware bounce re-interrupt
}else{ //Warning for unhandled interrupt
xportSendText("[ERROR] Low - unhandled interrupt!");
}
}
void delay_ms(unsigned int xc)
{
do
{
xc--;
__delay_ms(1);
}
while(xc > 0);
}
void buttonHandle(void){
delay_ms(100);
if(!BUTTON){
xportSendText("Button pressed");
//ADC DEBUG
char buffer[] = " ";
sprintf (buffer, "ADC: %u", adcGet());
xportSendText(buffer);
//RX DEBUG
xportSendText("RxBuf: ");
xportSendText(RxBuf);
//XPORT debug
xportDebug();
}
}
void messageHandle(void){
xportSendText(RxBuf); //Send/Handle the buffer
strcpy(RxBuf, " "); //Empty the buffer!
RxI = 0; //Start buffer at pos 0 again;
RxMessage = false; //Reset the flag
}
Básicamente estoy recibiendo texto uart en una interrupción. E imprimiendo el debug/adc cuando se ha establecido un indicador de botón (por la interrupción del botón)
Este es mi resultado después de presionar el botón varias veces: Como puede ver, el adc no es muy persistente. Aunque lo tenía conectado a la fuente de alimentación (que no debería (y no) caer tanto).
Sé que existen ejemplos y bibliotecas para tratar de ahorrar trabajo, pero a menudo encuentro útil no usarlos al principio mientras verifico que mi comprensión y la hoja de datos son correctas y que el chip no está roto. (Por lo general, el problema es mi comprensión).
Entonces, sin usar la biblioteca:
Probablemente encontrará que la biblioteca es correcta y que se está perdiendo algo que se vuelve obvio en ese momento, pero de vez en cuando, hay una biblioteca que está mal o al menos mal escrita/documentada.
Todavía no entiendo por qué no funcionó en primer lugar... Podría haber sido la forma en que lo imprimí. Podría haber sido la biblioteca.
Aunque lo hice configurando los registros manualmente, esto funciona (mejor) para mí.
static unsigned int result = 0;
ANCON0bits.ANSEL4 = 1; //AN4 to analog channel.
ADCON2 = 0b10111110; //Select channel
ADCON1 = 0b00110000;
ADCON0 = 0b00010011; //Start AN4 conversion
while(ADCON0 & 2){} //ADC busy
result = ADRESH;
result = result<<8;
result = result | ADRESL;
ADCON0 &= 0b11111110; // Turn converter off
return (result/85);
Reid
Pablo
ENABLE_AN4_ANA();
debería hacer ese truco. Pero sí, realmente podría ser una pequeña cosa como esa.aarond
Pablo