PIC16F18855 ADC寄存器为';t按照我期望的方式运行(C,CCS编译器)

PIC16F18855 ADC寄存器为';t按照我期望的方式运行(C,CCS编译器),c,embedded,pic,adc,C,Embedded,Pic,Adc,我正在使用PIC16F18855微型计算机和CCS作为编译器,我正在尝试让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 这表现得很奇怪,读数与引脚上的实际电压完全无

我正在使用PIC16F18855微型计算机和CCS作为编译器,我正在尝试让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\u 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
}
我的代码有两个主要问题:

如果我调用fprintf(主机,“0x%x”,ADC\u CON\u 0)adc_setup()后立即执行code>当我期望
0x84
时,我得到了
0x80
。这意味着10位adc值在2个8位寄存器中左对齐,而不是右对齐。我不知道它为什么写得不对。我检查过的每个其他寄存器(ADCON1-3和ADCLK)都是正确的

当我调用
read_adc_custom_implementation()时它在while循环中永远等待,表示ADGO位永远不会按照数据表指示的方式重置

有人知道为什么我的
adc\u设置
read\u adc\u custom\u实现
不起作用吗?或者,如果有人知道为什么CCS提供的功能不起作用,我会很高兴,如果我可以用它们来代替


,ADCON0位于第357页。

我在一位工程师的帮助下找到了问题的解决方案

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

解决方法包括设置ADGO位和检查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
}
此解决方法包含在5.069及更高版本中内置于CCS的
read_adc()
函数中,但我使用的是5.065,它是支持18855的编译器的第一个版本。我首先尝试了这个变通方法,它解决了我的一个问题,但我仍然遇到许多其他的bug。 我没有尝试解决这些问题,而是更新到5.075并使用内置的
read\u adc()
函数。一切开始都很顺利


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

什么类型的
read\u adc()
返回?张贴CCS手册中的
read_adc()
。定义:根据#DEVICE adc=指令,可以是8位或16位int。因为我使用的是#设备adc=10它的int16。而不是
l
表示
long
,而是使用
fprintf(主机,“%d”,(int)read_adc())(int)(读取adc()&(1