【发布时间】:2018-06-01 07:47:35
【问题描述】:
我正在使用带有 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 页。
【问题讨论】:
-
read_adc()返回什么类型?贴出read_adc()的定义。 -
来自 CCS 手册:8 位或 16 位 int 取决于 #DEVICE ADC= 指令。因为我使用的是 #device adc=10 它的 int16。
-
用
long代替l,使用fprintf(HOST, "%d", (int) read_adc()); -
刚试过这个。我得到完全相同的结果 - 9-18 中的数字与引脚上的电压无关。当我第一次尝试时,我使用的是 #device adc=8 并且所有内容都设置为 8 位整数。结果是相同的,除了我得到的不是 9-18 的值,而是 2-4 的值,计算 10 位值中增加的精度与左移 2 的读数相同
-
如果右对齐,结果寄存器的其余部分是什么?试试
(int)(read_adc() & (1<<10 - 1))。此外,右对齐是指“将数据存储在数据 LSB 及以上”还是意味着“将数据从第 n 位存储到第 15 位”?鉴于 PIC 是小端,这些是不同的东西。