PIC16F18855 ADC 寄存器的行为方式与我期望的不同(C、CCS 编译器)

PIC16F18855 ADC registers aren't behaving the way I expect them to (C, CCS compiler)

我正在使用带有 CCS 的 PIC16F18855 微型计算机作为编译器,我正在尝试让 ADC 工作。从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

这表现得很奇怪,读数完全独立于引脚上的实际电压(对于 10 位读数,读数在 9 到 18 之间随机变化)。

一位同事查看了 C 编译成的程序集,告诉我编译器在尝试使用内置 read_adc() 函数读取 adc 时正在写入错误的寄存器。具体来说,当它应该写入 ADGO 位以开始转换时,它会写入不存在的 ADCON0 之前的寄存器。

为了解决这个问题,我尝试实现自己的函数来设置和读取 ADC:

#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
}

我的代码有两个主要问题:

如果我在调用 adc_setup(); 后立即调用 fprintf(HOST, "0x%x", ADC_CON_0);,我会在预期 0x84 时得到 0x80。这意味着 10 位 adc 值在 2 个 8 位寄存器中左对齐,而不是右对齐。我不知道为什么它写不正确。我检查过的所有其他寄存器(ADCON1-3 和 ADCLK)都是正确的。

当我调用 read_adc_custom_implementation(); 时,它在 while 循环中永远等待,表明 ADGO 位永远不会像数据表指示的那样被重置。

有谁知道为什么我的 adc_setupread_adc_custom_implementation 实现不起作用?或者,如果有人知道为什么 CCS 提供的功能无法正常工作,我会很高兴,如果我可以使用那些代替。

PIC16F18855 datasheet,ADCON0 在第 357 页。

user from the CCS forums.

的帮助下,我找到了解决问题的办法

我遇到的错误是硅错误 - 如果您设置 ADGO 位然后在下一个时钟周期读取它,ADC 永远不会重置 ADGO 位。这意味着我的 while 循环将永远等待。 errata 中有关于此错误的更多详细信息。我实际上事先已经阅读过这篇文章,但将其误解为不适用于我,因为我的项目中发生的事情与文档中描述的内容不一样。

解决方法是在设置 ADGO 位和检查它之间包含一个时钟周期的延迟,即:

int16 read_adc_custom_implementation(void){
    ADC_CON_0 |= 0x01;                      //set ADGO bit to start conversion
    delay_cycles(1);                        //workaround
    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
}

此解决方法包含在 CCS 5.069 及更高版本中内置的 read_adc() 函数中,但我使用的是 5.065,这是支持 18855 的第一个编译器版本。我首先尝试了解决方法它解决了我的一个问题,但我仍然遇到许多其他错误。 我没有尝试解决它们,而是更新到 5.075 并使用了内置的 read_adc() 函数。一切开始完美运行。

长话短说,如果您有同样的问题,请更新编译器。