PIC MCU: Contador disparado de ADC

Básicamente, estoy buscando programar un PIC16F917, de modo que un int particular aumente en uno cada vez que presione un botón.

Ahora tengo el ADC en funcionamiento, tengo bucles para contar, pero parece que me falta el conocimiento y la experiencia para ponerlo todo junto, y bloquear la entrada a cero antes de que int aumente en un número mayor que uno.

El siguiente código es lo que he escrito hasta ahora. El problema con esto es que aumenta varias veces por pulsación (tantos ciclos de retraso durante los que se mantuvo pulsado el botón), y me encantaría que solo cuente por uno. Estaba pensando en crear una nueva función e int, pero parece que no puedo armarlo, se necesita mucha ayuda.

Gracias por ayudar, Ezra

#include <xc.h>
#include "config-bits.h"

#define _XTAL_FREQ 4000000

int result;
int output;

void delay()
{
    int i;

    for(i=0; i<100; i++)
    {
        /*Timer Stuff*/
    }
}

int main()
{
    TRISA=1;                    //Set all pins to input
    TRISB=1;
    TRISC=1;
    TRISD=1;
    TRISE=1;

    TRISDbits.TRISD0 = 0;       //LED output
    ANSELbits.ANS0 = 1;         //Select ADC input

    ADCON0bits.ADFM = 1;        //ADC result is right justified
    ADCON0bits.VCFG = 0;        //Vdd is the +ve reference
    ADCON1bits.ADCS = 0b001;    //Fosc/8 is the conversion clock
                                //This is selected because the conversion
                                //clock period (Tad) must be greater than 1.5us.
                                //With a Fosc of 4MHz, Fosc/8 results in a Tad
                                //of 2us.
    ADCON0bits.CHS =  0;        //select analog input, AN2
    ADCON0bits.ADON = 1;        //Turn on the ADC

    while(1)
    {
        delay();                        //Wait the acquisition time (about 5us).

        ADCON0bits.GO = 1;              //start the conversion
        while(ADCON0bits.GO==1){};      //wait for the conversion to end

        result = (ADRESH<<8)+ADRESL;    //combine the 10 bits of the conversion

        if(result > 512)
        {
            PORTD=output++;
            delay();
        }
        else
        {
            NOP();
        }
    }
}
Tal vez haya entendido mal algo, pero ¿puede explicar por qué está usando ADC para leer una pulsación de botón?
Pensé que esa era la forma de hacer que el PIC reconociera la entrada externa, además de usar el ISR. ¿No? ¿Cómo lo haces/cuál es la mejor manera y la más eficiente?
@ezra_vdj ¿Dónde está conectado el botón al otro lado del PIC?
Tal vez haga una búsqueda rápida en el sitio y vea qué aparece. También puede buscar técnicas antirrebote porque sospecho que esa es la raíz de su problema.
@Golaž El botón está conectado a VDD en un lado, tirado hacia abajo mientras está conectado a AN0
@RogerRowland saludos, lo haré. ¿Alguna pista y consejo?
Google es tu amigo. Esta es una pregunta muy común .

Respuestas (2)

Utilice una variable para recordar si el último resultado fue < 512. Antes de incrementar la variable de salida, compruebe si el resultado anterior fue < 512. ¿Podría haber utilizado una entrada digital en lugar de una analógica?

Entonces, ¿almacenar el resultado anterior en una variable? ¿La entrada digital simplificaría las cosas? (porque no tengo idea) Supongo que porque ya es digital, ¿no necesita ADC?
¿Realmente creaste este código? ¿Hubiera pensado que habrías entendido lo que dije si lo hubieras escrito tú mismo?
Sí, lo escribí, y entiendo lo que está pasando. Sin embargo, como soy bastante nuevo, no estoy seguro de si lo que estoy haciendo es la forma más efectiva. Por lo que entiendo en su respuesta, está diciendo que cree una nueva variable que almacene si la variable de salida es <512, y antes de contar verifique si el resultado anterior es <512. Esto ayuda porque si es> 512, creo que detiene el conteo. ¿Puedes aclarar por favor? Gracias por ayudar por cierto
Tiene una variable llamada 'resultado' que se actualiza cada vez que lee el ADC. Debe almacenar eso en otra variable para que la próxima vez que realice el ciclo pueda verificar el 'resultado' anterior para ver si es diferente al 'resultado' actual, es decir, el botón se ha soltado y presionado nuevamente. Debido a que está utilizando el ADC, el valor cambiará ligeramente constantemente, por lo que en lugar de almacenar un valor, deberá almacenar si el 'resultado' es mayor o menor que 512, es decir, un valor booleano. (Estoy tratando de describir esto sin escribir el código para usted).

Bien, primero algunas cosas. TRISA=1no pone todo el PORTA como entrada como está escrito en el comentario, es equivalente a 0b00000001poner todo el puerto como entrada que tiene que hacer TRISA=255o TRISA=0xFFque es igual a 0b11111111.

No sé cómo conectaste el botón al microcontrolador, pero mirando tu programa debería ser algo como esto:

esquemático

simular este circuito : esquema creado con CircuitLab

De esta manera debería funcionar, obtienes 5V cuando se presiona el botón y 0V cuando está abierto. Sin embargo, aún puede obtener un voltaje inestable en el momento en que se presiona el botón (llamado rebote), se ve así:

ingrese la descripción de la imagen aquí

Entonces, puede parecer que el botón se presiona varias veces debido a este efecto de rebote, para resolver esto, debe tomar más muestras y promediarlas, luego use el resultado promedio para decidir qué hacer.

Pero hay otra forma, que es más fácil en este caso, solo quiere leer si el interruptor está presionado ('1') o no ('0') para que no necesite y ADC, puede hacerlo solo con una entrada digital, no necesitas una analógica. El esquema sería el mismo, pero el programa C sería algo como esto (supongamos que el interruptor está conectado a RA0):

int main() {
    TRISA=1;                    // Set RA0 as input
    TRISD=0x00;
    PORTD=0x00;

    while(1){
        if(TRISAbits.RA0) {
            PORTD += 1;
            delay();     // We use the delay to avoid the bouncing effect (some milliseconds)
            while(TRISAbits.RA0);
        }
    }
}

Las entradas analógicas a veces son útiles cuando tiene que leer muchos botones y desea guardar algunas entradas de MCU:

ingrese la descripción de la imagen aquí

En este circuito cada botón produce un voltaje diferente en la entrada del ADC. Entonces, con la entrada analógica, lee ese voltaje y determina qué botón se presionó.

Dulce gracias montones! No sabía que solo estaba efectuando un pin, wow. Con su código de muestra, ¿qué sucede con la instrucción if? Habría pensado que necesita alguna operación, o comparadores o algo así? En lugar de si (TRISAbits.RA0)?
if(TRISAbits.RA0)es lo mismo que if(TRISAbits.RA0 == 1)de la misma manera if(!TRISAbits.RA0)es lo mismo que if(TRISAbits.RA0 == 0). Eso es solo algunas cosas de C :)
¡Fantástico! El uso de entradas digitales significaría que cualquier cosa que no sea VDD o VSS se consideraría flotante, por lo tanto, ¿la resistencia desplegable?
No es estrictamente Vdd y Vss. Con Vdd como 5 V, un 1 lógico es aproximadamente cualquier cosa por encima de 2,7 V y un 0 lógico por debajo de 1,5 V (consulte la hoja de datos del microcontrolador, solo estoy poniendo algunos números), por lo que hay un umbral entre un 1 lógico y un 0 lógico, si el voltaje está allí se puede leer como 0 o 1, es un comportamiento indefinido, por lo que necesita el menú desplegable para asegurarse de que tiene un 0 lógico. Debe leer algunos conceptos básicos sobre circuitos digitales, eso lo ayudará mucho.
Cuando filtre picos, nunca use el promedio . El promedio se usa para reducir el ruido constante, equivalente a un filtro RC.