×
单片机 > 单片机程序设计 > 详情

PIC单片机C语言程序设计(14)

发布时间:2020-06-08 发布时间:
|
  十五、Pic单片机的A/D转换

  在电子技术中,传感器是一种很重要的器件,传感器的种类也有多种,如温度传感器、光敏传感器、压力传感器……,其特点是能把非电量,如温度、光度、压力等转换成相关的电量(电流或电压)。这些电量都是模拟量,可用Pic 单片机的A/D 转换,将上述的模拟量转换成数字量,再将数字量进行各种处理,如LED、LCD 显示。

  Pic16F87X 系列单片机, 具有A/D 转换的功能。Pic16F876/873 芯片为28 引脚, 有5 个模拟输入端的10 位A/D 转换(5 通道);Pic16F877 为40 引脚,有8 个模拟输入端的10位A/D 转换(8 通道)。Pic16F876/873 芯片的模拟输入端为AN0~AN3,其引脚是② ~ ⑤脚和⑦脚AN4,几乎占用了Pic16F876/873 所有的A 口。由于Pic 单片机的端口具有复用功能,所以上述的模拟输入口不会影响I/O 端口的通用特性。

  上述芯片的A/D 转换,都已模块化,具有10 位(二进制的)分辨率,所以完全可以满足大多数测量精度的要求,此外,还可利用Pic 单片机睡眠状态下进行A/D 转换(利用内部自带的RC 振荡作时钟),因在睡眠模式下,部分数字电路的开关噪声已停止,所以可获得更高的A/D 转换精度。

  Pic 单片机的A/D 转换功能的操作,远比本连载1~13 中介绍的各种功能的C 程序要复杂些,学会编写A/D 转换的C 程序,也是进一步学习Pic 单片机C 程序设计的重要内容之一。因为在编辑A/D 转换的C 程序时,会用到芯片内部多个专用寄存器(控制模块),学会相关模块的使用方法,可为编辑其它复杂功能的C 程序建立良好的思维方法。

  1.Pic16F87X 的 A/D 转换必备知识

  ⑴ A/D 转换控制寄存器ADCON1

  ADCON1 是8 位的可读写的寄存器,如图59 所示,其功能是A/D 转换时,选择芯片引脚输入信号的类型(模拟量A 或数字量D),以及A/D 转换结果存放的格式(见下文)。

图59

  ADCON1 的第6、5、4 位,在A/D 转换中未派上用场,读作“0”。 ADCON1 的第3、2、1、0 位(Bit3、Bit2、Bit1 和Bit0), 是管理Pic16F87X 引脚功能(A 或D)的选择(可参看相关书藉的A/D 转换引脚功能选择表,因该表占用版面多,这里略去),例如在下文C 程序中,设ADCON1=0x8a 时, 选择Pic16F873A 的AN0(RA0)、AN1(RA1)RA4(AN4)、RA5(AN5)为模拟量输入、(AN6、AN7 为数字量输入),AN3、AN2 参考电压设置端(十、一)。

  ⑵ A/D 转换结果寄存器ADRESH、ADRESL。因Pic16F87X 的A/D 转换值是10 位的二进制数(代码),而A/D 转换的结果是存放在指定的结果寄存器中,因结果寄存器是8 位的,所以A/D 转换结果的10 位数, 利用ADRESH存放A/D 的高字节;利用ADRESL 存放A/D的低字节。存放方法是利用前述的ADCON1( 图59) 的第7 位(bit)ADFM 进行选择, 当令ADFM=1 时,A/D 转换结果的低8 位存放在ADREL 中;高两位存放在ADRESH 中;当令ADFM=0 时,A/D 转换结果的低两位存放在ADRESL 中,余下的高8 位存放在ADRESH 中,这由C 语言设计者自由选择。若对A/D 转换代码的分辨率要求不高(如实验程序),可取A/D转换的高8 位而舍去低2 位,以使C 程序简化。

  ⑶ A/D 转换控制寄存器ADCON0

  ADCON0 的功能是用于控制A/D 转换的操作,其相关位的功能如图60 所示。

图60

  图中ADCONO 的第0 位(Bit0),ADON是A/D 转换允许位(俗称打开A/D 转换),当令ADON=1 时,打开的A/D 转换;AD0N=0 时,关闭A/D 转换。ADCON0 的第1 位, 未使用读作0。

  ADCON0 的第2 位也是重要的功能位:在ADON=1 时,若令=1,启动A/D 转换;若令=0,A/D 转换完成。

  ADCONO 的5~3 位(Bit5、Bit4 和Bit3)CHS2、CHS1、CHS0 是A/D 转换模拟通道的选择,对Pic16F873A 芯片,有下述关系:

  ADCONO 的第7、6 位即ADCS1和ADCS0,是A/D 转换时钟选择位,有以下关系:

  此外,在A/D 转换时,还会用到外围接口中断标志寄存器PIR1 的标志位ADIF(Bit6)和外围接口中断使能寄存器PIE1 的使能位ADIE。

  当令ADIF=1 时, 代表A/D 转换已完成;ADIF=0 时,A/D 转换未完成。

  当令ADIE=1 时, 打开A/D 转换中断;ADIE=0 时,关闭A/D 转换中断。[page]

  2.Pic16F873A 的A/D 转换电路

  图61 是一种利用Pic16F873A(28 引脚)和LCD(液晶显示模块1602)组成的A/D 转换液晶显示的主要电路。该电路的功能是先对柔性薄膜压力传感器的模拟信号进行A/D 转换,然后按所需功能进行处理,最后由LCD 显示其物理量的功能。当然,所述过程都是由C 语言程序完成的。

  LCD 按其显示方式,可分为段位式(又称笔段式)、字符式和点阵式等。段位式LCD 类似于数码管LED 的功能,只能显示0~9 的数字和简单的字符。字符式LCD 不仅可显示数字而且可显示多种字符(字符库)。点阵式LCD 不仅可以显示字符、数字,还可显示多种图形、曲线及汉字,实现屏幕的动画。图61 中的LCD 是字符型的,常用的型号是1602, 即16 字x2 行的。读者在电子市场购买1602 模块时,定向商家索取该模块的详细使用说明书。

图61

  柔性薄膜压力传感器是一种超薄性( 仅0.1mm 厚)压力传感器,常用于医学上,该传感器受压时,其输出的模拟信号很小,所以都应加运算放大器进行放大处理后,才能送到单片机的A/D 转换输入端,如图61 中的RA0/AN1 或RA1/AN2 端。

  图61 的Pic16F873A 的硬件电路, 是一种常规的A/D 转换和LCD 显示电路, 其中Pic16F873A 的①脚外接常规的Pic 单片机复位电路;⑼、⑽脚外接晶振XT 和C1、C2 的单片机时钟电路;Pic16F873A 的B 口,其位RB4、RB3 和RB2 分别与1602LCD 的E、EW 和RS的控制端相连,以便Pic 单片机控制1602LCD的基本操作。

  Pic16F873A 的C 口, 其位RC0~RC7 与1602LCD 的数据引脚D0~D7 分别相连,以便Pic 单片机控制1602LCD 的指令和数据的读写操作。LCD(1602)的③脚VL 为LCD 对比度调整端,接正电源时,对比度最低,接地时对比度最高,使用时通过外接10KΩ 电位器,调整所需的对比度。

  该电路是笔者为某医院烧伤科设计的治疗仪部分主要电路, 在这里取其A/D 转换的C程序部分, 以说明Pic 单片机的专用寄存器:

  ADCON1、ADRESH、ADRESL、ADCON0、PIR1 和PIE1 等,在A/D 转换时的使用方法和操作步骤。这里没有给出治疗仪的全部C 程序。

  以下是Pic16F873A 的A/D 转换的操作步骤和相关的程序。

  A/D 转换的初始化,如图62 所示。

图62[page]

  对于A/D 转换程序的初始化一般要经过图62 的几个步骤。

  A/D 转换初始化函数代码如下:

  void adcsh()

  {

  TRISA=0X07;// 设定I/O 口为输入

  ADCON1=0X8a;

  //RA0~RA5 设为模拟口,RA3 接参考电压。

  ADCON0=0X81;

  // 通道0,选择系统时钟focs/32.

  ADRESH=0;

  ADRESL=0; // 清空转换结果寄存器

  GIE=1; // 打开总中断

  PEIE=1; // 打开第一外围中断屏蔽

  ADIE=1; // 打开A/D 中断

  ADIF=0; // 清除A/D 中断标志位。

  }

  以上流程图和代码是采用中断服务程序来读取A/D 转换数值的,虽然通过查询标志位方式也可以达到同样的效果,但是在实际应用中,中断服务方式因方便、可靠、节省芯片运行时间而成为常用的编程结构。对于中断服务程序,越简单越好,因PIC 单片机特殊的堆栈结构,不宜在中断服务程序内作数据运算和太多调用函数的操作,原则是取出值后立即退出中断,以保证其它的任务能及时被响应。图63 是中断服务流程图。

图63

  AD 中断C 语言的基本写法:

  void interrupt AD(void)

  // 必须用interrupt 关键词,编译器才会判定是中断服务程序

  {

  unsigned int ad_1=0;

  if(ADIF==1)

  // 判断A/D 转换中断标志位是否为1 ;

  {

  ADIF=0;// 清零中断标志位

  ad_1=(ADRESH&0X03)*256+ ADRESL;

  // 读取A/D 转换结果,并将低字 节和高字节进行整合。

  }

  }

  从以上的代码看出,C 语言比汇编要简单得多,进入中断后,标志位清零是必须的,返回指令可以不写,这是最基本的中断服务程序。

  以下提供在实际应用中的代码:

  AD 初始化函数:

  void adcsh()

  {

  OPTION=OPTION|0x80;// 关闭弱上拉

  TRISC=0X00;

  TRISB=0X03;

  PORTC=0X00;

  ADCON1=0X8a;

  // 转换结果右对齐,RA0~RA5 设为模拟口,

[page]

  RA3 可接参考电压。

  TRISA=0X07;

  ADCON0=0X81;// 打开通道0 作数据采样

  PORTA=0XFF;

  ADRESH=0;

  ADRESL=0;// 转换结果寄存器清零

  INTCON=0x00;// 关闭所有中断

  GIE=1;// 打开总中断

  PEIE=1;// 打开第一外围中断

  ADIE=1;// 打开AD 中断

  ADIF=0;// 清除AD 中断标志位

  }

  以下是中断服务函数:

  void interrupt AD(void)

  {

  unsigned int ad_1=0;

  // 定义一个ad 转换结果寄存器

  if(k<16)

  {

  ADIF=0; // 清楚AD 标志位

  ad_1=(ADRESH&0X03)*256+ ADRESL;

  // 读取AD 转换结果

  ad_sum=ad_sum+ad_1;

  k++;

  if(k<16)

  ADGO=1; // 启动AD

  }

  if(k==16)

  {

  ad_1=ad_sum/16;

  if( b>16)

  {

  if(ad_1>ad_temp)

  ad_1=ad_1-ad_temp;

  else if(ad_1

  ad_1=ad_temp-ad_1;

  else if(ad_1==ad_temp)

  ad_1=0;

  AD_

  value=(float)(ad_1);

  }

  d=1;

  ad_sum=0;

  k=0;

  if(b<32)

  {

  b++;

  ADGO=1;

  }

  if(b==15)

  ad_temp=ad_1;

  }

  }

  上述A/D 转换的C 程序,初学时有些难度,但结合A/D 转换相关的专用寄存器功能,也不难理解的,待下次连载15,笔者对A/D 转换方法,还有一些说明的,读者可以关注。




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
浅谈AVR中定时器几种工作模式