Эти аналоговые данные считываются, и на 7-сегментном дисплее с общим анодом отображается число 1–5 с числом 7447, но я не могу установить это число для аналогового значения, потому что не могу отображать аналоговые значения или выходные данные. Я написал этот код в MPLAB. Х IDE.
#include <xc.h>
#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // GP3/MCLR pin function select (GP3/MCLR pin function is MCLR)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF
#define _XTAL_FREQ 4000000
#define HIGH 1
#define LOW 0
unsigned int adc_value=0;
void main(void) {
TRISIObits.TRISIO0 = 1;
TRISIObits.TRISIO1 = 0;
TRISIObits.TRISIO2 = 0;
TRISIObits.TRISIO4 = 0;
TRISIObits.TRISIO5 = 0;
ANSELbits.ADCS2 = 0;
ANSELbits.ADCS1 = 0;
ANSELbits.ADCS0 = 0;
ANSELbits.ANS0 = 1;
ADCON0bits.CHS0 = 0;
ADCON0bits.CHS1 = 0;
ADCON0bits.ADON = 1;
ADCON0bits.GO = 1;
ADCON0bits.ADFM = 1;
while(1) {
ADON = 1;
GO_DONE = 1;
while(GO_DONE);
adc_value = (((unsigned int) ADRESH << 8) + ADRESL);
ADON = 0;
if (adc_value >= 0 && adc_value <= 200) {
GP4 = 0;
GP5 = 0;
GP2 = 0;
GP1 = 0;
} else if (adc_value > 200 && adc_value <= 400) {
GP4 = 0;
GP5 = 0;
GP2 = 0;
GP1 = 1;
} else if (adc_value > 400 && adc_value <= 600) {
TRISIObits.TRISIO4 = 0;
TRISIObits.TRISIO5 = 0;
TRISIObits.TRISIO2 = 1;
TRISIObits.TRISIO1 = 0;
} else if (adc_value > 600 && adc_value <= 800) {
TRISIObits.TRISIO4 = 0;
TRISIObits.TRISIO5 = 0;
TRISIObits.TRISIO2 = 1;
TRISIObits.TRISIO1 = 1;
} else if (adc_value > 800 && adc_value <= 1023) {
TRISIObits.TRISIO4 = 0;
TRISIObits.TRISIO5 = 1;
TRISIObits.TRISIO2 = 0;
TRISIObits.TRISIO1 = 0;
} else {
TRISIObits.TRISIO4 = 1;
TRISIObits.TRISIO5 = 1;
TRISIObits.TRISIO2 = 1;
TRISIObits.TRISIO1 = 1;
}
__delay_ms(100);
}
return;
}
Моя цель в этом проекте — напечатать число от 0 до 5 на 7-сегментном дисплее с общим анодом в соответствии с аналоговыми данными от 0 до 1023, но я не смог решить эту проблему.
Я не знаю, что микро, но использование разных методов (GP4 = 0;
и TRISIObits.TRISIO4 = 0;
) для доступа к контактам вашего чипа U2 выглядит очень странно.
«пока (GO_DONE);» Даже когда удаляю эту строку, ситуация та же самая, добавлял и удалял, пробовал много функций, ситуация та же самая
@Gerhardh Я попробовал, чтобы посмотреть, какой метод активирует эти контакты.
Это означает, что вы не знаете, можете ли вы получить доступ к контактам? Итак, вы не знаете, есть ли у вас проблемы с чтением аналоговых данных или с настройкой пинов, верно? Опять же, что будет, если убрать while(GO_DONE)
и просто посчитать adc_value
. Не пытайтесь решить две разные задачи одновременно. Прежде чем пытаться считать значения, убедитесь, что ваш дисплей находится под контролем.
@Gerhard Теперь я могу получить доступ к контактам, но он не дает правильный номер, что бы я ни делал, он дает номера 6 и 7.
Вы не настроили GPIO<1:5> как цифровые вводы-выводы. Вот почему вы не можете их контролировать.
Согласно паспорту устройства, их необходимо настроить с помощью регистров CMCON
и ANSEL
.
Регистр CMCON
управляет встроенными аналоговыми компараторами, которые используют несколько контактов, которые соединяют внутреннее оборудование с внешним миром через контакты GP0 (CIN+)
, GP1 (CIN-)
и GP2 (COUT)
соответственно. Поэтому вам необходимо сначала отключить аппаратное обеспечение компараторов, установив биты CM2:CM0
на 7 (111 в двоичном формате).
CMCON = 7;
Регистр ANSEL
— это место, где вы можете указать микросхеме, какие контакты вы хотите использовать для работы АЦП. В вашем случае, поскольку вы используете только AN0 (GP0)
, а все остальное должно быть настроено как цифровое. Что вам нужно сделать, так это установить соответствующий бит ANSx для контакта, который вы хотите использовать в качестве аналогового входа (вы используете AN0
, поэтому вы должны установить ANS0
), а остальные биты ANSx
должны быть установлены в 0, чтобы использовать другие контакты в качестве цифрового ввода-вывода. .
ANSEL = 1;
Итак, если мы завершим приведенную выше информацию и объединим ее с вашим кодом, а также приведем в порядок ваш код, окончательный код должен выглядеть следующим образом:
#include <xc.h>
#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-Up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = ON // GP3/MCLR pin function select (GP3/MCLR pin function is MCLR)
#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF
#define _XTAL_FREQ 4000000
#define HIGH 1
#define LOW 0
void setupInputs() {
GPIO = 0; // Clear output latches
CMCON = 7; // Turn off analog comparators
TRISIO = 1; // GP0 and GP3 (GP3 is an only input pin) are input and other pins are output
}
void setupADC() {
ANSEL = 0x21; // Set the GP0 pin as analog input and the rest is digital IO
// and use the internal RC osc for ADC
ADCON0 = 0x81; // Right justify, sample CH0, ADC turn on
}
unsigned int getAnalogValueOnCh0() {
ADCON0bits.GO = 1;
while(ADCON0bits.GO)
; // Wait for the ADC conversion to complete
return (unsigned int) ( ADRESH << 8) + ADRESL;
}
void setDisplay(char value) {
GP1 = value & 1;
GP2 = (value & 2) >> 1;
GP4 = (value & 4) >> 2;
GP5 = (value & 8) >> 3;
}
void main(void) {
setupInputs();
setupADC();
setDisplay(0);
__delay_us(20); // See datasheet 7.2 A/D ACquisition Requirements
while(1) {
unsigned int adc_value = getAnalogValueOnCh0();
if (adc_value >= 0 && adc_value <= 200) {
setDisplay(0);
} else if (adc_value > 200 && adc_value <= 400) {
setDisplay(1);
} else if (adc_value > 400 && adc_value <= 600) {
setDisplay(2);
} else if (adc_value > 600 && adc_value <= 800) {
setDisplay(3);
} else if (adc_value > 800 && adc_value <= 1023) {
setDisplay(4);
} else {
setDisplay(5);
}
__delay_ms(100);
}
}
PS: Вам следовало расположить значения в диапазоне 1024/6 = 170 примерно. Но вы разделили ценность ADC на куски по 200. Выбирайте сами.
В решении при выключенном MCLRE показывает 0 и 1 вольт правильно, но 2,3,4,5 не выводит, при включенном MCLRE не выводит с пинов. ) – CrazyProgrammer Комментарий: 12 минут назад
Когда я активировал вывод MCLRE и подключил его к плюсовой линии с 10К, та же ситуация повторилась.
Проблема была в функции setDisplay
. Я исправил это, проверьте это.
В качестве решения, согласно коду, предоставленному @Kozmotronik, проблема была решена при использовании 74hc595 вместо 7447.
Не могли бы вы объяснить свой ответ?
Где какой-либо намек на использование какого-то другого оборудования, скрытого в этом коде или во всем ответе?
Вы утверждаете, что аналоговые операции не работают. Как вы убедились, что ваша проблема не в части GPIO, связанной со светодиодами? Вы делали какую-нибудь отладку? Вы когда-нибудь переступали эту черту
while(GO_DONE);
? Предположим, чтоGO_DONE
— это какой-то аппаратный флаг, который меняется в какой-то момент времени. Если заменитьadcres
на простой счётчик, отображение изменится корректно?