PIC MCU: запускаемый счетчик от ADC

По сути, я хочу запрограммировать PIC16F917, чтобы конкретный int увеличивался на единицу каждый раз, когда я нажимаю кнопку.

Теперь я запустил и запустил АЦП, у меня есть циклы для подсчета, но мне, похоже, не хватает знаний и опыта, чтобы поставить его полностью и зафиксировать ввод обратно в ноль до того, как int увеличится на число больше единицы.

Следующий код — это то, что я написал до сих пор. Проблема с ним в том, что он увеличивается несколько раз за одно нажатие (столько циклов задержки, в течение которых удерживалась кнопка), и я бы хотел, чтобы он учитывался только на единицу. Я думал о создании новой функции и int, но я просто не могу собрать ее вместе - нужна большая помощь.

Спасибо за помощь, Эзра

#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();
        }
    }
}
Может быть, я что-то неправильно понял, но можете ли вы объяснить, почему вы используете ADC для чтения нажатия кнопки?
Я думал, что это способ заставить PIC распознавать внешний ввод, помимо использования ISR. нет? как вы это делаете/какой лучший и самый эффективный способ?
@ezra_vdj Где кнопка подключена на другой стороне PIC?
Может быть, сделать быстрый поиск по сайту и посмотреть, что всплывает. Вы также можете искать методы устранения дребезга, потому что я подозреваю, что это корень вашей проблемы.
@Golaž Кнопка подключена к VDD с одной стороны, на низком уровне при подключении к AN0
@RogerRowland ура, подойдет. Любые подсказки и советы?

Ответы (2)

Используйте переменную, чтобы запомнить, был ли последний результат < 512. Перед увеличением выходной переменной проверьте, был ли предыдущий результат < 512. Могли бы вы использовать цифровой вход, а не аналоговый?

Итак, сохранить предыдущий результат в переменной? Упростит ли цифровой ввод ситуацию? (потому что я понятия не имею) Я думаю, потому что он уже цифровой, не нужен АЦП?
Вы действительно создали этот код? Я думал, ты бы понял, что я сказал, если бы написал это сам?
Ага, я это написал и понял, что происходит. Поскольку я довольно новичок, не уверен, что то, что я делаю, является наиболее эффективным способом. Из того, что я понимаю в вашем ответе, вы говорите создать новую переменную, в которой хранится, равна ли выходная переменная <512, и перед подсчетом проверьте, равен ли предыдущий результат <512. Это помогает, потому что если это> 512, я думаю, это останавливает подсчет? можете уточнить пожалуйста? Спасибо за помощь кстати
У вас есть переменная под названием «результат», которая обновляется каждый раз, когда вы читаете АЦП. Вам нужно сохранить это в другой переменной, чтобы в следующий раз в цикле вы могли проверить предыдущий «результат», чтобы увидеть, отличается ли он от текущего «результата», то есть кнопка была отпущена и нажата снова. Поскольку вы используете АЦП, значение будет постоянно немного меняться, поэтому вместо сохранения значения вам нужно будет сохранить, является ли «результат» больше или меньше 512, т. е. логическое значение. (Я пытаюсь описать это без написания кода для вас).

Хорошо, сначала несколько вещей. TRISA=1не помещает все PORTA в качестве входных данных, как написано в комментарии, это эквивалентно тому, 0b00000001чтобы поместить все порты в качестве входных данных, которые вы должны сделать TRISA=255, или TRISA=0xFFкоторые равны 0b11111111.

Я не знаю, как вы подключили кнопку к микроконтроллеру, но, глядя на вашу программу, это должно быть примерно так:

схематический

смоделируйте эту схему - схема, созданная с помощью CircuitLab

Таким образом, это должно работать, вы получаете 5 В, когда кнопка нажата, и 0 В, когда она открыта. Однако вы все еще можете получить некоторое нестабильное напряжение в момент нажатия кнопки (называемое дребезгом), это выглядит так:

введите описание изображения здесь

Таким образом, может показаться, что кнопка нажимается несколько раз из-за этого эффекта подпрыгивания, чтобы решить эту проблему, вам нужно взять больше образцов и усреднить их, а затем использовать средний результат, чтобы решить, что делать.

Но есть и другой способ, который в этом случае проще, вы просто хотите прочитать, нажат ли переключатель ('1') или нет ('0'), поэтому вам не нужен и АЦП, вы можете сделать это просто с помощью цифровой вход, аналоговый не нужен. Схема будет такой же, но программа на C будет примерно такой (предположим, что коммутатор подключен к 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);
        }
    }
}

Аналоговые входы иногда полезны, когда вам нужно прочитать много кнопок и вы хотите сохранить некоторые входы MCU:

введите описание изображения здесь

В этой схеме каждая кнопка создает разное напряжение на входе АЦП. Таким образом, с помощью аналогового входа вы считываете это напряжение и определяете, какая кнопка была нажата.

Сладкое спасибо! Я не знал, что это действует только на одну булавку, вау. Что происходит с вашим примером кода с оператором if? Я бы подумал, что вам нужна какая-то операция, компараторы или что-то в этом роде? Вместо if(TRISAbits.RA0)?
if(TRISAbits.RA0)это то же самое, что if(TRISAbits.RA0 == 1)таким же образом, if(!TRISAbits.RA0)это то же самое, что if(TRISAbits.RA0 == 0). Это просто некоторые вещи C :)
Фантастика! Использование цифровых входов будет означать, что все, кроме VDD или VSS, будет считаться плавающим, следовательно, подтягивающий резистор?
Это не строго Vdd и Vss. Если Vdd равно 5 В, логическая 1 соответствует примерно любому напряжению выше 2,7 В, а логический 0 — любому напряжению ниже 1,5 В (проверьте техническое описание микроконтроллера, я просто ставлю некоторые цифры), поэтому существует порог между логической 1 и логическим 0, если напряжение можно прочитать как 0 или 1, это неопределенное поведение, поэтому вам нужно вытащить вниз, чтобы убедиться, что у вас есть логический 0. Вы должны прочитать некоторые основы цифровых схем, которые вам очень помогут.
При фильтрации пиков никогда не используйте среднее значение . Усреднение используется для уменьшения постоянного шума, эквивалентного RC-фильтру.