技术热线: 4007-888-234

PIC微控制器的设计窍门

更新时间: 2019-03-23
阅读量:1839

PIC微控制器的设计窍门

       除了可在广泛应用的Microchip公司PIC微控制器芯片中挤出更多特性外,本文探讨的诸如增加额外串口以及在8位芯片上进行32位运算等技巧,也可适用于其它微控制器。

 
 
   

       尽管Microchip公司不断为其日益扩大的PIC微控制器产品线增加更多功能,但有时设计工程师只需其中一小部分功能。也许设计工程师还需要目前尚不存在的一组特性,或者继承了一种设计但不能升级,或者可能只想进行试验并打破以往传统限制。本文将介绍一些挖掘各种PIC产品极限的应用方法,其中一些技巧也适用于其它微控制器,但这里只介绍用于PIC的源代码与具体示例。本文还将分析一些方法,它们是关于如何增加另一个异步串口、更容易地处理精度扩展(32位或更高)算法、增强并行从端口以及如何使用一些异步串口常被忽略的特性。

 

异步串口

 

       许多PIC都具有一个或两个异步串口,但如果它们不够用,那么位拆裂(Bit-banging)剩余I/O管脚是一种常用的解决方案,且适用于整个PIC系列。但这种方案是软件密集型的,它在保持可靠通信所需的关键时序的同时,将难以进行其它任何操作。另一种选择方案是检测起始位的上升沿,并采用定时器中断来读取数据。这种方法在位拆裂方法的基础上有了很大改进,但仍需要大量的软件开销以处理每一位的中断,而面向任何中断的延迟都可能导致同步问题。

    

       大多数PIC还提供一个串行外围接口(SPI)。仅需很小开销,普通的同步SPI就可被设计成能够接收标准的异步传输。

 

       一个典型的异步数据流包括一个起始位(总为0)、8个数据位(最低有效位在前)以及一个终止位(总为1)。图1给出了一个接收ASCII码字母“Q”(16进制为51)的例子,也可采用更少的数据位或者增加一个奇偶校验位或额外的终止位。

 

       SPI端口也采用8位数据,但它同步在两个不同管脚上发送和接收字节。数据时钟可消除对起始位或终止位的需要,且最高有效位在前。图2显示由SPI端口发送的一些数据,SPI端口在每个时钟的下降沿接收数据,在上升沿发送数据。

 

开始启动

 

       一旦被接收,数据肯定被翻转,但如果SPI时钟的下降沿与每一个异步数据位的中心同步,那么数据也可能保持原样。起始位的下降沿提供最初的同步记号,其它同步记号则利用PIC的一个SPI选项。这里有好几种定时选项,包括使用定时器TMR2等。TMR2计数直到其值等于特殊函数寄存器PR2的值,然后TMR2触发SPI时钟并复位为0,接着再继续计数。如果TMR2从大于PR2的值开始计数,则第一个时间间隔将比平常的时钟周期要长,因为它首先要复位到0(如图3所示)。

 
 

    

       SPI端口接管产生同步记号的任务后,它将用所有的8个数据位进行计时而无需其它开销。但它会占用从起始位上升沿到TMR2与SPI端口正确初始化这段时间,从而导致中断延迟,如果启用优先级更高的中断,延迟时间将更长。不过不用担心这种中断延迟,因为PIC还有另一个秘密武器。许多PIC都具有两个或多个捕获/比较/PWM模块,I/O管脚可在下降沿上捕获定时器的值,在起始位的上升沿则将TMR1值存储在一个CCPRx特殊函数寄存器中,并产生一次中断。中断服务程序将带有TMR1-CCPRx-PR2值的TMR2初始化,以消除掉任何延迟。列表1给出的是一个典型的中断程序。

 

       可选的“if(!CCP1)”行可确认输入管脚是否仍为低,以避免将瞬间毛刺读成串行数据。由于-PR2(未标出)必须大于PR2,所以应仔细选择TMR2的预定标器的值,并使TMR1的预定标器的值与之一样。在上面例子中,dTim2PR2为52。最坏情况下的中断延迟应该小于串行数据速率,例如在9,600波特上,该值大约为104微秒或16MHz PIC上416条指令的执行时间。SPI中断正好能够隐藏数据并启用下一个字节的CCP1中断,但切记在某些时刻翻转数据位。

 

       尽管设计工程师通常不能控制输入数据的到达时间,且两个接收器必须时刻保持警惕,但设计者通常能交替使用两个发送器。有很多方法可用来处理硬件路由,仅需少数几个逻辑门或晶体管以及一个输出位就可进行这种选择。图4显示采用一个含4个NAND门的74HC00的方法。可在“串口1”上“选择”高速发送,在“串口2”上“选择”低速发送,这两种路径的“数据输入”都来自TX管脚。

    

帧错误(FERR)标记

 

       PIC异步串口的状态位包括FERR标记。FERR表示终止位为低而不是所要求的高,这表明发送方的波特率低于接收方的波特率,并且预期的终止位的确是一个数据位。也可用FERR来检测RS-232的“中断”条件。中断通常包括一个低起始位、全0数据以及一个0终止位。如果FERR被设置且数据为0,则将有一次中断,但一般需对输入做较长时间的观察,以确认它保持为低。“中断” 条件是一种向系统发送秘密“蝙蝠信号”并启用特殊配置或测试模式的方法。有些终端能发送各种长度的中断,或者设计工程师可将串口的RX输入缩短为正电压,其确切电平取决于硬件,但它可低到3V。如果是RS-232状态输出(如DTR),则其有效电平为正,且将能提供接收器所需的电压电平。

 

       TX9及TX9D是两个经常被忽略的特殊函数寄存器位,可对TX9设置进行设置,使TX9D作为第9个数据位被发送。额外数据位的一种传统用法是将其作为错误检查的奇偶校验位。如果错误检查对应用很关键,那么只进行简单的奇偶校验还不够,因为错误检查位可能出错。

 

       曾经有一种采用RS-485的系统通过电线在数百英尺的距离上进行通信。该系统采用具有故障自恢复功能的RS-485芯片,即使电线是开路的,它也能保证有效输出。电线开路在半双工通信时经常出现,因为数据在同一对电线的两个方向上传输,每次只有一边能发送,而在间歇期间两边都在侦听,这使电线上没有驱动信号。该系统可靠工作了数年时间,直到客户想采用其它外来的RS-485设备。

 

 

       这些外来设备没有使用具有故障自恢复功能的器件,系统在PIC的TRMT状态位表明所有的位都被发送后才释放线路。TRMT不对终止位进行计数,因此PIC在另一端收到终止位之前释放线路。这并没有选择修改硬件,而是将PIC配置成发送9个数据位,并使TX9D为高以发送在另一端看起来为终止位的一个额外数据位。这样,这两种系统从此都工作得很好。

 

       如果正在设计一种新系统,合适的终端将非常有用;并且如果硬件允许使用这种终端,则可在发送时使接收器有效。一旦侦听到自己的发送,设计工程师就知道包括终止位在内的所有数据位都已安全地抵达另一端。

 

参数堆栈

 

       尽管多年以前人们为8位微处理器编写了一些图形函数,但设计工程师还需要32位定点运算。由于存储器有限,所以在进行复杂计算时,复用临时存储空间来存储中间值是很有吸引力的。知道何时能安全地复用特定的临时存储位置将带来更多复杂性。

 

       Forth语言采用参数堆栈与RPN。计算时,先从参数堆栈中弹出参数,然后再将计算结果推入参数堆栈。临时存储空间总是位于参数堆栈的顶部,当从堆栈中弹出一个参数后,该临时存储空间被自动释放并可再被使用。

 

       使用参数堆栈是处理复杂表达式及中间结果的一种便利方法,尤其是当编译器不支持最佳数据大小的时候。如果没有参数堆栈,则“add”函数就可能会将两个参数相加,然后再将结果返回至某一个地方;而有了参数堆栈,则算术函数不需要任何参数,也不用返回任何结果。Add() 函数可能会先从堆栈中弹出两个数,将它们相加后再将结果推入堆栈中。数据可以是32位、24位或任何所需的位数,也不必考虑数据大小,除非需要在堆栈与其它位置之间转移数据。以这种方式使用参数堆栈,要求重新考虑数学运算与函数,而RPN则提供一种简单的解决方案。

    

代数表达式“5+3” 可用RPN编码成“5 3 +”,其程序代码如下:


  Push(5);


  Push(3);


  Add();

 

代数表达式“(2*3)+(4*7)” 可用RPN表示为“2 3 * 4 7 * +”,其程序代码为:


  Push(2);


  Push(3);


  Multiply();


  Push(4);


  Push(7);


  Multiply();


  Add();

 

       如同Add() 函数一样,Multiply()函数先从参数堆栈中弹出两个参数,将它们相乘,然后再将结果推入堆栈中。

 

       除了支持通常的算术运算,Forth语言还有几种操作堆栈中的值的方法。Dup()函数复制推入栈顶(TOS)的最后值;Over() 函数复制栈顶以下的第二个值;Swap() 函数交换两个栈顶值;Drop() 函数将值推入栈顶。Pick(n) 函数复制栈顶以下第N个值。图6显示Over() 函数如何将两个值保持在栈上并对它们求和。

 
 

 

       当将数字堆砌到堆栈上时,只需调用少数几个函数即可进行复杂运算,而无需参数或返回值。

 

       笔者用这些从Forth及RPN借用来的概念开发出一个精度扩展数学库。有了PIC,函数调用常常编译为单个操作码,可以从ftp://ftp.embedded.com/pub/2005/04rowe下载PicMath.c ,该版本适用于CCS PCM编译器,其配置最小为:

 

1.将StackDataSize栈数据大小定义为以字节来表示的数据大小(例如32位为4个字节等);


2.分配栈存储空间并将MathPtr初始化为栈的最低地址;


3.MathCarry数据位存储计算后的PIC进位标志;


4.MathDouble配置位在非零时可进行双精度乘、除操作。

 

PicMath还提供用于无栈运算的函数,该函数利用指针指示源及目的参数,并用计算结果覆盖目的参数。

 

并行从端口

 

       以往,快速数据传输总是以并行来进行。现在有了每秒数百万位的串行数据速率,串行传输可能是一种更好选择,但除各种串行端口外,很多较大的PIC还提供一个并行从端口(PSP)。当在所有串行端口都用于其它事情后还需要另一个通信通道时,PSP可能相当有用。虽有几条用于片选及读/写8位数据的控制线,但没有标准方法来知道数据何时能读或者PIC是否已处理完写入的最后值,等等。

 

       PIC在内部拥有输入缓冲器满(IBF)及输出缓冲器满(OBF)状态位。IBF表示有人对并行端口进行写操作,而OBF则表示PIC输出的最后值仍在等待被读取。图7显示这些过程是如何进行的。

 

       尽管可以只用现有功能、某些固件以及非常严格的协议来进行通信,但设计工程师可能还需要额外的握手线以再造内部IBF和OBF状态位的等效值。这通常至少需要一个额外的输出管脚与一个额外的输入管脚来监视信号。可用快脉冲来指示发送方与接收方准备就绪。可直接将一个握手输出连接至一个边沿触发中断管脚。一些管脚可根据变化来产生一次中断,但如果它是快脉冲,则读该端口管脚将正好显示当前逻辑电平。

 

       电平激励握手存在使两边失去同步的危险。发送方可能会看到接收方“READY”握手线,发送一个字节,并在接收方响应前再检查“READY”信号。而接收方可能会看到发送方的“READY”握手线,读一个字节,并在发送方响应前再检查“READY”信号,并再一次读同一数据。

 

       PLD或其它外部逻辑器件可产生模仿内部IBF及OBF状态位的外部握手信号。发送方的/WR信号可设置XIBF(外部IBF),并可由接收方的输出握手管脚来清除。发送方通过监视XIBF来确定接收方何时准备就绪。发送方的握手管脚可将XOBF(外部OBF)设置为数据已做好读准备的信号。接收方的/RD信号清除XOBF。发送方不需要监视XOBF,因其内部OBF会复制该信号并产生中断。

 

       处理器能提供满足所有需要的内置硬件支持当然最好,但如果不能,且设计不得不尽快完成,则上述技巧中的一项可能就够用。这些技巧可用于各种处理器,包括16Cxx、16Fxx及18Fxx PIC等。只要了解其潜在优势与局限,它们就能成为您工具箱中的有用选项。