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_setup
和 read_adc_custom_implementation
实现不起作用?或者,如果有人知道为什么 CCS 提供的功能无法正常工作,我会很高兴,如果我可以使用那些代替。
PIC16F18855 datasheet,ADCON0 在第 357 页。
的帮助下,我找到了解决问题的办法
我遇到的错误是硅错误 - 如果您设置 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()
函数。一切开始完美运行。
长话短说,如果您有同样的问题,请更新编译器。
我正在使用带有 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_setup
和 read_adc_custom_implementation
实现不起作用?或者,如果有人知道为什么 CCS 提供的功能无法正常工作,我会很高兴,如果我可以使用那些代替。
PIC16F18855 datasheet,ADCON0 在第 357 页。
我遇到的错误是硅错误 - 如果您设置 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()
函数。一切开始完美运行。
长话短说,如果您有同样的问题,请更新编译器。