这是我们使用MPLAB和XC8学习PIC单片机的第9个教程 。到目前为止,我们已经涵盖了许多基础教程,例如MPLABX入门,PIC指示灯闪烁,PIC中的计时器,LCD接口,7段接口等。如果您是绝对的初学者,请在此处访问PIC教程的完整列表。然后开始学习。
在本教程中,我们将学习如何在PIC单片机PICF877A中使用ADC。大多数微控制器项目将在其中涉及ADC(模数转换器),因为它是从现实世界读取数据的最常用方法之一。几乎所有传感器(例如温度传感器,磁通传感器,压力传感器,电流传感器,电压传感器,陀螺仪,加速计,距离传感器)以及几乎每个已知的传感器或传感器都会根据传感器的读数产生0V至5V的模拟电压。例如,温度传感器在温度为25°C时可发出2.1V的电压,而在温度为60°C时可发出4.7V的电压。为了了解现实世界的温度,MCU必须读取该温度传感器的输出电压,并将其与现实世界的温度关联起来。因此,ADC是MCU项目的重要工作工具,让我们了解如何在PIC16F877A上使用它。
还要查看我们以前在其他微控制器中使用ADC的文章:
- 如何在Arduino Uno中使用ADC?
- Raspberry Pi ADC教程
- ADC0808与8051单片机的接口
PIC单片机PIC16F877A中的ADC:
有许多类型的ADC,每种类型都有自己的速度和分辨率。ADC的最常见类型是闪存,逐次逼近和sigma-delta。所述ADC的在PIC16F877A使用的类型被称为逐次逼近ADC在短或SAR。因此,在开始使用SAR ADC之前,请先对其进行一些了解。
逐次逼近型ADC: SAR ADC在比较器和一些逻辑对话的帮助下工作。这种类型的ADC使用参考电压(可变),并使用比较器将输入电压与参考电压进行比较,并从最高有效位(MSB)中保存将作为数字输出的差值。比较的速度取决于PIC工作的时钟频率(Fosc)。
既然我们已经了解了ADC的一些基础知识,那么请打开数据表,学习如何在PIC16F877A MCU上使用ADC。我们使用的PIC具有10位8通道ADC。这意味着我们的ADC的输出值为0-1024(2 ^ 10),并且我们的MCU上有8个引脚(通道)可以读取模拟电压。由于我们的ADC是10位,因此2 ^ 10可以得到值1024。数据手册中提到了可以读取模拟电压的八个引脚。让我们看下面的图片。
模拟通道AN0至AN7为您突出显示。只有这些引脚才能读取模拟电压。因此,在读取输入电压之前,我们必须在代码中指定必须使用哪个通道读取输入电压。在本教程中,我们将使用带有电位计的通道4来读取该通道上的模拟电压。
A / D模块具有四个寄存器,必须将其配置为从输入引脚读取数据。这些寄存器是:
•A / D结果高位寄存器(ADRESH)
•A / D结果低位寄存器(ADRESL)
•A / D控制寄存器0(ADCON0)
•A / D控制寄存器1(ADCON1)
ADC编程:
将ADC与PIC单片机配合使用的程序非常简单,我们只需要了解这四个寄存器,然后读取任何模拟电压便很简单。与往常一样,初始化配置位,让我们从 void main()开始。
在 void main() 内部,我们必须使用ADCON1寄存器和ADCON0寄存器初始化ADC。ADCON0寄存器具有以下位:
在该寄存器中,我们必须通过使ADON = 1来打开ADC模块,并通过使用ADCS1和ADCS0位来打开A / D转换时钟,其余部分暂时不会设置。在我们的程序中,将A / D转换时钟选择为Fosc / 16,您可以尝试自己的频率并查看结果如何变化。有关完整的详细信息,请参见数据表的第127页。因此,ADCON0将按以下方式初始化。
ADCON0 = 0b01000001;
现在,ADCON1寄存器具有以下位:
在该寄存器中,我们必须通过ADFM = 1将A / D结果格式选择位设为高电平,并使ADCS2 = 1,以再次选择Fosc / 16。当我们计划使用内部参考电压时,其他位保持为零。有关完整的详细信息,请参见第128页的数据表。因此,我们将ADCON1设置如下。
ADCON1 = 0x11000000;
现在,在我们主要功能中的ADC模块初始化之后,进入while循环并开始读取ADC值。要读取ADC值,必须遵循以下步骤。
- 初始化ADC模块
- 选择模拟通道
- 通过将Go / Done设置为高电平来启动ADC
- 等待Go / DONE位变低
- 从ADRESH和ADRESL寄存器获取ADC结果
1.初始化ADC模块:我们已经学习了如何初始化ADC,因此我们只需要调用下面的函数即可初始化ADC
的 空隙ADC_Initialize() 函数是如下所示。
无效ADC_Initialize(){ADCON0 = 0b01000001; //选择ADC ON和Fosc / 16 ADCON1 = 0b11000000; //选择内部参考电压}
2.选择模拟通道:现在,我们必须选择将用于读取ADC值的通道。让我们为此创建一个函数,以便我们在 while 循环内的每个通道之间轻松切换。
unsigned int ADC_Read(unsigned char channel){// ****选择通道** /// ADCON0&= 0x11000101; //清除通道选择位ADCON0-= channel << 3; //设置所需的位// **通道选择完成*** ///}
然后在可变通道内接收要选择的通道。在行中
ADCON0&= 0x1100101;
先前的通道选择(如果有)被清除。这是通过使用按位和运算符“&”来完成的。位3、4和5被强制为0,而其他位保留为先前值。
然后,通过左移三次通道号并使用按位或运算符“-”设置位来选择所需的通道。
ADCON0-=通道<< 3; //设置所需的位
3.通过将Go / Done位设置为高电平来启动ADC :一旦选择了通道,我们仅需通过将 GO_nDONE 位设置为高电平来启动ADC转换:
GO_nDONE = 1; //初始化A / D转换
4.等待Go / DONE位变低: GO / DONE位将保持高电平,直到ADC转换完成为止,因此我们必须等待直到该位再次变低。这可以通过使用 while 循环来完成。
while(GO_nDONE); //等待A / D转换完成
5.从ADRESH和ADRESL寄存器获取ADC结果:当Go / DONE位再次变低时,表明ADC转换已完成。ADC的结果将是一个10位的值。由于我们的MCU是8位MCU,因此结果分为高8位和低2位。高8位结果存储在寄存器ADRESH中,低2位结果存储在寄存器ADRESL中。因此,我们必须将它们加到寄存器中以获得10位ADC值。该结果由函数返回,如下所示:
返回((ADRESH << 8)+ ADRESL); //返回结果
此处显示用于选择ADC通道,触发ADC并返回结果的完整功能。
无符号整数ADC_Read(无符号字符通道){ADCON0&= 0x11000101; //清除通道选择位ADCON0-= channel << 3; //设置所需的位__delay_ms(2); //获取充电保持电容GO_nDONE = 1的时间;//在(GO_nDONE)初始化A / D转换;//等待A / D转换完成返回((ADRESH << 8)+ ADRESL); //返回结果}
现在我们有了一个将通道选择作为输入并向我们返回ADC值的函数。因此,我们可以在 while 循环内直接调用此函数,因为在本教程中,我们是从通道4中读取模拟电压的,因此函数调用如下。
i =(ADC_Read(4)); //将adc的结果存储在“ i”中。
为了可视化我们ADC的输出,我们将需要某种显示模块,例如LCD或7段显示器。在本教程中,我们使用7段显示器来验证输出。如果您想知道如何将7段与pic结合使用,请按照此处的教程进行操作。
将 完整的代码 下面给出,过程也是在解释 影片 的结尾。
硬件设置和测试:
与通常在实际使用我们的硬件之前使用Proteus进行代码仿真一样,该项目的示意图如下所示:
4位七段显示模块与PIC微控制器的连接与之前的项目相同,我们刚刚在引脚7(即模拟通道4)上添加了一个电位计。通过改变电位计,可变电压将被发送到MCU ADC模块将读取并显示在7段显示模块上。请查看上一教程,以了解有关4位7段显示器及其与PIC MCU接口的更多信息。
在这里,我们使用了与 LED闪烁教程中创建的PIC单片机相同的 板。确保连接后,将程序上载到PIC中,您应该会看到类似以下的输出
在这里,我们从电位器中读取了ADC值,并将0-1024输出映射为0-5伏,将其转换为实际电压(如程序所示)。然后,该值将显示在7段显示器上,并使用万用表进行验证。
就是这样,现在我们准备好使用市场上所有可用的模拟传感器,继续尝试一下,如果您像往常一样遇到任何问题,请使用注释部分,我们将竭诚为您服务。