Я использую микроконтроллер PIC16F18855 с CCS в качестве компилятора и пытаюсь заставить работать АЦП. Начиная с функций, предоставляемых CCS, я написал:
#device ADC=10
...
setup_adc_ports(sAN21);
setup_adc(ADC_CLOCK_DIV_8);
set_adc_channel(21);
...
fprintf(HOST, "%ld", read_adc()); //I have RS232 implemented elsewhere
Это вело себя странно, с показаниями, которые были полностью независимы от фактического напряжения на выводе (случайным образом между 9 и 18 для 10-битного чтения).
Сотрудник просмотрел сборку, в которую был скомпилирован C, и сказал мне, что компилятор записывает в неправильный регистр, когда пытается прочитать adc, используя встроенную функцию read_adc()
. В частности, когда он должен записать бит ADGO для начала преобразования, он записывает в регистр до ADCON0, которого не существует.
Чтобы обойти это, я попытался реализовать свои собственные функции для настройки и чтения АЦП:
#byte ADC_CON_0 = getenv("SFR:ADCON0")
#byte ADC_CON_1 = getenv("SFR:ADCON1")
#byte ADC_CON_2 = getenv("SFR:ADCON2")
#byte ADC_CON_3 = getenv("SFR:ADCON3")
#byte ADC_CLK = getenv("SFR:ADCLK")
#byte ADC_RES_H = getenv("SFR:ADRESH")
#byte ADC_RES_L = getenv("SFR:ADRESL")
#byte AN_SEL_C = getenv("SFR:ANSELC")
#byte ADC_PCH = getenv("SFR:ADPCH")
void adc_setup(void){
//setting the mode and clock
ADC_CON_0 = 0x84; //turn on ADC and right justify it
ADC_CON_1 = 0x00;
ADC_CON_2 = 0x00;
ADC_CON_3 = 0x00;
ADC_CLK = 0x03; //gives Fosc/8, for 1us T_AD with 8MHz clock
//setting the input channel and telling the pin to be analogue
AN_SEL_C = 0x20; //set pin C5 to analogue input
ADC_PCH = 0x15; //0x15 = 21, analogue channel 21 is pin C5
}
int16 read_adc_custom_implementation(void){
ADC_CON_0 |= 0x01; //set ADGO bit to start conversion
while(ADC_CON_0 & 0x01){} //wait till conversion is finished (indicated by hardware reset of ADGO bit)
return make16(ADC_RES_H, ADC_RES_L); //read the result registers and return them combined into a 16bit integer
}
В моем коде есть две основные проблемы:
Если я позвоню fprintf(HOST, "0x%x", ADC_CON_0);
сразу после звонка adc_setup();
, я получу 0x80
, когда я ожидал 0x84
. Это означает, что 10-битное значение АЦП выравнивается по левому краю в 2 8-битных регистрах, а не по правому краю. Понятия не имею, почему он пишет неправильно. Все остальные регистры, которые я проверил (ADCON1-3 и ADCLK), верны.
Когда я вызываю read_adc_custom_implementation();
, он вечно ждет в цикле while, показывая, что бит ADGO никогда не сбрасывается, как указано в таблице данных.
Кто-нибудь знает, почему мои реализации adc_setup
и read_adc_custom_implementation
не работают? В качестве альтернативы, если кто-нибудь знает, почему не работают поставляемые функции CCS, я был бы счастлив, если бы мог использовать их вместо них.
Таблица данных PIC16F18855, ADCON0 находится на странице 357.
read_adc()
? Разместите определениеread_adc()
. - person chux - Reinstate Monica   schedule 19.12.2017l
дляlong
, используйтеfprintf(HOST, "%d", (int) read_adc());
- person chux - Reinstate Monica   schedule 19.12.2017(int)(read_adc() & (1<<10 - 1))
. Кроме того, оправдано ли правильное выравнивание означает хранить данные в младшем разряде данных и выше или это означает хранить данные от бита n до бита 15? Учитывая, что PIC имеет прямой порядок байтов, это разные вещи. - person Lundin   schedule 19.12.2017read_adc
все это следует учитывать. Все примеры кода показывают то, что было в моем первом фрагменте кода. - person Escape   schedule 19.12.2017