§1.7 I/O 口
PIC12C5XX只有一个I/O口,对应的映像寄存器为GPIO(地址:06h),其中GPIO< 5:0> 对应GP5:GP0,GPIO<7:6>未用,永为“0”。注意,GP3仅可作为输入,是单向I/O口线。另外,GP5、GP4、GP3及GP2还可以由用户定义成各种特殊功能口线,一旦它们被用作特殊用途,则永远读为“0”。GP0、GP1和GP3还带有可编程的弱上拉和“电平变化唤醒功能”(即唤醒正处于睡眠状态下的芯片),关于这点请参阅OPTION寄存器的描述。如果GP3被用户定义为复位输入端(MCLR),则它的弱上拉自动有效,但“电平变化唤醒”特性被自动关闭。
GPIO口线的方向由TRIS寄存器控制,详情参见§1.6.1中有关TRIS寄存器的描述。
§1.7.1 I/O 口结构
一根I/O口线的结构如下图所示:
图1.12 I/O口结构
除了GP3只能单向作为输入口外,其余的GPIO口皆可由用户定义为输入/输出态。作为输入口时没有锁存,外部信号必须保持到让CPU读入为止(例如:MOVF GPIO,W)。作为输出则有锁存,可以保持直到被新的值取代为止。
I/O端的输入/输出态由TRIS寄存器的值控制,当TRIS将“1”置入I/O控制器时Q1和Q2 都处于截止态,所以I/O端即呈高阻态(输入态)。当执行I/O读指令(如MOVF 6,W),把当前I/O端的状态读入数据总线。当TRIS将“0”置入I/O控制器时,Q1和Q2的导通情况将要由数据锁存器Q端的状态来决定。当写入数据为“1”时,Q端为低电平0,则Q1导通,I/O输出为高电平。反之,当写入数据为“0”时,Q端为“1”,则Q2导通,I/O端输出为低电平。I/O读写时序如图1.13所示。
§1.7.2 I/O口使用注意事项
1、I/O方向转置的问题
某时候可能需要一个I/O口一会做输入,一会又做输出。这就是I/O方向的转置。在编写这种I/O转置程序时必须注意,有些指令如位设置指令(BSF、BCF)写I/O口时是先从I/O读入其状态,执行位操作后再将结果写回去覆盖原来的内容(输出的结果放在I/O口的数据锁存器)。
举个例子来说:“BSF 6,5” 这条指令的目的是要把B口的第6位置为高电平“1”。执行这条指令时,先把整个B口当前的状态内容读入到CPU,把第6位置成“1”后再把结果(8个位)重新输出到B口。如果B口中的有一个I/O端是需要方向转置的(比如说bit1),而这时是处于输入态,那么B口的状态值重新写入后,B口的数据锁存器1的锁存值就是当前B口Bit1的状态。 这可能和先前Bit1作为输出时所锁存的值不同,所以当Bit1 再转置成输出态时,出现在Bit1 端的状态就可能和先前的输出态不同了。
2、I/O的“线或”和“线与”
从图1.12看出PIC I/O端输出电路为CMOS互补推挽输出电路。因此与其他这类电路一样,当某个PIC I/O端设置为输出状态时,不能与其他电路的输出端接成“线或”或“线与”的形式,否则可能引起输出电流过载,烧坏PIC。如需要与其他电路接成“线或”电路时,PIC I/O 端必须置于“1”状态或输入状态,并外接下拉电阻。电阻的阻值根据实际电路和PIC I/O 端最大电流来决定。
3、I/O口的连续操作
一条写I/O的指令,对I/O真正写操作是发生在指令的后半周期(参照图1.13)。而读I/O的指令却是在指令的周期开始就读取I/O端状态。所以当你连续对一个I/O端写入再读出时,必须要让I/O端上的写入电平有一个稳定的时间,否则读入的可能是前一个状态,而不是最新的状态值。一般推荐在两条连续的写,读I/O口指令间至少加一条NOP指令。
例:
MOVWF 6 ;写I/O
NOP ;稳定I/O电平
MOVF 6,W ;读I/O
4、噪声环境下的I/O操作
在噪声环境下(如静电火花),I/O控制寄存器可能因受干扰而变化。比如I/O口可能会从输入态自己变成输出态,对于这种情形,WDT也是无法检测出来的。因此如果你的应用环境是较恶劣的,建议你每隔一定的间隔,都重新定义一下I/O控制寄存器。最保险的方法当然是对I/O读写前都定义一下I/O控制寄存器(但是实践证明对于大多数的应用都不必做到这样,只是提请你注意噪声干扰)。
图1.13 I/O口连续读/写时序
§1.8 定时器/计数器TIMER0
TIMER0是一个8位的定时器/计数器,其对应的映像寄存器是TMR0(地址:01h),可由用户程序直接读写,并且可带有8位的预分频器。它用于对外加在GP2/T0CKI引脚上的外部信号进行计数(计数器)或对内部指令时钟进行计时(定时器),在PIC16C5X中它被称为RTCC。
TIMER0及其相关电路如图1.14所示。从图中可看出TIMER0工作状态由OPTION寄存器控制,其中OPTION寄存器的T0SC位用来选择TIMER0的计数信号源,当T0SC为“1”时,信号源为内部时钟,T0SC为“0”时,信号源为来自T0CKI引脚的外部信号。OPTION寄存器的PSA位控制预分频器(Prescaler)分配对象,当PSA位为“1”, 分配给TIMER0,即外部或内部信号经过预分频器分频后再输出给TIMER0。 预分频器的分频比率由OPTION内的PS0~PS2决定。这时涉及写TMR0寄存器的指令均同时将预分频器清零,OPTION 寄存器内容保持不变,即分配对象、分频比率等均不变。OPTION的T0SE 位用于选择外部计数脉冲触发沿。当T0SE为“1”时为下降沿触发,为“0”时则上升沿触发。
图1.14 TIMER0 方块图
TIMER0计数器采用递增方式计数,当计数至FFH时,在下一个计数发生后,将自动复零,重新开始计数,从此一直循环下去。TIMER0对其输入脉冲信号的响应延迟时间为2个机器周期,不论输入脉冲是内部时钟、外部信号或是预分频器的输出。响应时序见图1.15。
TIMER0对外部信号的采样周期为2个振荡周期,因此当不用预分频器时,外加在T0CKI 引脚上的脉冲宽度不得小于2个振荡周期即1/2指令周期。同时,当使用预分频器时,预分频器的输出脉冲周期不得小于指令周期,因此预分频器最大输入频率可达N,fosc/4,N 为预分频器的分频比,但不得大于50MHz。
图1.15a. TIMER0时序图:内部时钟/无预分频器
图1.15b. TIMER0时序图:内部时钟/预分频比1:2
应注意的是尽管PIC对外部加于T0CKI信号端上的信号宽度没有很严格的要求,但是如果高电平或低电平的维持时间太短,也有可能使TIMER0检测不到这个信号。一般要求信号宽度要大于10ns。
§1.9 预分频器
预分频器是一个分频倍数可编程的8位计数器。其结构如图1.14 所示上节对预分频参数已有描述,这里不再赘述。
预分预器的分配对象完全由程序控制,可以在程序中改变Prescaler分配对象。
1、从TIMER0到WDT的改变
MOVLW B'XX0X0XXX' ;选择内部时钟和新的预分频值
OPTION ;如果新的预分频值='000'或者
CLRF 1 ;='001',则暂时先选一个另外的值
MOVLW B'XXXX1XXX' ;清零TMR0和预分频器
OPTION ;选择WDT为对象,但不要改变预分频值
CLRWDT ;清WDT和预分频器
MOVLW B'XXXX1XXX' ;选择新的预分频器
OPTION
2、从WDT到TIMER0的改变
CLRWDT ;清WDT 及Prescaler
MOVLW B'XXXX0XXX' ;选择TIMER0
OPTION
图1.16 预分频器方块图
注意,预分频器只能分配给TIMER0或WDT其中之一使用,而不能同时分配给二者。
§1.10 看门狗WDT
看门狗计时器(Watch Dog Timer)是一个片内自振式的RC振荡计时器,无需任何的外接元件。这意味着即使芯片振荡停止了(例如执行指令SLEEP后),WDT照样保持计时。WDT计时溢出将产生RESET。在PIC12C5XX芯片内有一个特殊的谓之“系统定义字”(Configuration EPROM)的单元,其中的一个位是用于定义WDT的,可以将其置“0”来抑制WDT使之永远不起作用。这将在第六章的烧写器介绍部分详细说明。
1、WDT周期
WDT有一个基本的溢出周期18ms(无预设倍数),如果需要更长的WDT周期,可以把预分频器分配给WDT,最大分频比可达1:128,这时的WDT溢出周期约为2.5S。WDT溢出周期和环境温度、VDD等参数有关系,请参阅附录的图表。
“CLRWDT”和“SLEEP”指令将清除WDT计时器以及预分频器(当预分频器分配给WDT时)。WDT一般用来防止系统失控或者说防止单片机程序“失控”。在正常情况下,WDT应在计时溢出前被CLRWDT指令清零,以防止产生RESET。如果程序由于某种干扰而失控,那么不能在WDT溢出前执行一条CLRWDT指令,就会使WDT溢出而产生RESET,使系统重新启动运行而不至失去控制。若WDT溢出产生RESET,则状态寄存器F3的“TO”位会被清零,用户可藉此判断复位是否由WDT溢时所造成。
2、WDT编程注意事项
如果使用WDT,一定要仔细在程序中的某些地方放一条“CLRWDT”指令,以保证在WDT在溢出前能被清零,否则会造成芯片不停地产生RESET,使系统无法正常工作。
在噪声工作环境下,OPTION寄存器可能会因受干扰而改变,所以最好每隔一段时间就将其重新设置一下。
§1.11 振荡
PIC12C5XX可以运行在以下四种振荡方式下:
a、LP 低功耗低速晶体振荡
b、XT 标准晶体/陶瓷振荡
c、INTRC 内部4MHz RC振荡
d、EXTRC 外部RC振荡
以上四种振荡方式可由“系统定义字”中的Fosc1:Fosc2 两位来选择,请读者参阅后面§1.12.9的详述。
§1.11.1 晶体/陶瓷振荡
这种振荡包括XT和LP,其电路连接是在GP5/OSC1/CLKIN和GP4/OSC2两端加一晶体/陶瓷振荡,如下图所示:
图1.17 晶体/陶瓷振荡电路
下表是使用各种频率的晶体和陶瓷振荡所需的C1、C2电容值。
振荡类型 |
频率 |
C1 |
C2 |
|
振荡类型 |
频率 |
C1 |
C2 |
XT |
455KHz |
68-100P |
68-100P |
LP |
32KHz |
15P |
15P |
|
2MHz |
15-33P |
15-33P |
XT |
100KHz |
15-30P |
200-300P |
||
200KHz |
15-30P |
100-200P |
||||||
4MHz |
10-22P |
10-22P |
1MHz |
15-30P |
15-30P |
|||
2MHz |
15P |
15P |
||||||
4MHz |
15P |
15P |
a. 陶瓷振荡 b.晶体振荡
表1.3 各种振荡下的C1和C2值
§1.11.2 外部RC振荡
这种振荡类型成本最低,但频率的精确性较差,适用于时间精确度要求不高的应用场合。RC振荡的频率是VDD、RC值以及环境温度的函数。请参阅附录的RC频率函数图。RC 振荡的连接如图1.18所示。
图1.18 RC振荡电路
RC振荡是在OSC1端连接一个串联的电阻电容。这个电阻如果低于2.2K,振荡不稳定,甚至不能振荡,但是电阻高于1M时,则振荡又易受干扰。所以电阻值最好取5K~100K之间。尽管电容C为0时,电路也能振荡,但也易受干扰且不稳定,所以电容值应取20P以上。RC值和频率关系如表1.4所示。RC振荡时OSC2端输出一OSC1的4分频脉冲(f=1/4OSC1)。
Rest | Cext | VDD | Fosc/25℃ |
5kΩ | 0PF | 5.0 | 4.0MHz |
5kΩ | 20PF | 6.0 | 2.2MHz |
5kΩ | 20PF | 3.5 | 2.5MHz |
10kΩ | 130PF | 5.0 | 480MHz |
10kΩ | 290PF | 5.0 | 245MHz |
100kΩ | 300PF | 3.5 | 30MHz |
表1.4 RC与频率的关系
§1.11.3 外部振荡
PIC12C5XX也可以接受外部振荡源(仅适合于XT和LP类型振荡),连接时将外部振荡接入GP5/OSC1/CLKIN端,见下图:
图1.19 外部振荡源输入电路
§1.11.4 内部RC振荡
PIC12C5XX内部提供有4MHz的RC振荡源供用户选择使用,选择振荡方式和振荡源的方法见§1.12.9详介。
在PIC12C5XX的程序区最顶端(12C508:1FFh,12C509:3FFh)放了一条MOVLW XX的指令, XX是内部RC振荡的校正系数。芯片上电后,PC指针指向程序区最顶端,执行完这条指令后PC 值加1变为000h。这时W寄存器中存放即是内部RC振荡的校正系数,用户可以把这个系数置入OSCCAL寄存器(05h)以便使其起校正作用,也可以忽略不管它。
例:
0 ;定义存储区地址0
MOVWF OSCCAL ;把W中的校正系数置入OSCCAL。
§1.12 复 位(RESET)
PIC12C5XX有各种各样原因造成的芯片复位:
1、芯片上电
2.、MCLR端加低电平
3、看门狗WDT超时溢出
4、睡眠中某些I/O口线电平发生变化
当芯片处于复位状态时,所有I/O口线都处于输入状态(高阻态),看门狗WDT和预分频器都被清零。
图1.20 片内复位电路(暂缺)
§1.12.1 复位定时器(DRT)
复位定时器DRT(在PIC16C5X 中我们称其为OST)是为了使芯片的复位可靠安全而设计。在PIC12C5XX中,对于XT和LP振荡方式,上电后它们还需要一定的时间来建立稳定的振荡。有鉴于此,PIC12C5XX内部设计了一个复位定时器DRT。DRT在MCLR端到达高电平(VIHMC)后,即启动计时18ms,这样可以使芯片保持在复位状态约18ms以便让振荡电路起振及稳定下来,然后芯片即脱离复位状态进入正常运行状态。DRT的振荡源是芯片内专有的RC振荡电路,所以外围电路并不能改变其18ms的计时时间。
当WDT计时溢出后,DRT也是启动18ms使芯片保持在复位状态,然后再重新开始运行程序。
注意,在振荡方式是外部RC或内部RC时,DRT都关闭不起作用。
§1.12.2 芯片上电复位(POR)
PIC12C5XX在芯片内集成有上电复位电路,见图1.20所示。当芯片电源电压VDD上升到一定值时(1.5V-2.1V),检测电路即会发出复位脉冲使芯片复位。
§1.12.3 MCLR复位
PIC12C5XX的GP3/MCLR端可以由用户定义为普通输入口GP3或复位端MCLR,如下图:
图1.21 GP3/MCLR端电路(暂缺)
具体方法参见§1.12.9有关描述。
一旦用户选择MCLR功能,则该端输入低电平会使芯片进入复位状态。
§1.12.4 外部复位电路
在某种情况下,DRT计时18ms后,芯片的振荡电路还不能稳定或供电电压(VDD)还不能达到标准值,这时如果芯片脱离复位状态进入运行,则芯片就有可能失控或运行不正常。为了使芯片脱离复位状态时各部分都处于正常,可以在MCLR端上加外部RC复位电路来延长复位时间,如下图:
图1.22 外部复位电路
这个电路可以使VDD上升到标准值一段时间后,MCLR才会上升到高电平,从而启动DRT计时18ms后才进入运行。这样可以延长整个复位过程,保障芯片复位后进入正常运行。
§1.12.5 掉电复位锁定
当单片机的供电电压掉到最小标准值以下后,可能会使芯片的运行出现异常,从而扰乱整个控制系统,所以在某些应用中,我们希望一旦VDD掉到某个值时使芯片自动进入复位状态(所有I/O口都变成高阻态)以免扰乱系统,下面是一个PIC12C5XX掉电复位锁定的电路:
图1.23 掉电复位锁定
当VDD电压恢复上升到标准值以上后,MCLR端恢复为高,从而使芯片恢复正常运行。
§1.12.6 复位对寄存器的影响
对于通用寄存器来说,上电复位后它们的值是随机不定的,其他类型的复位后则保持原值不变。
对于特殊寄存器,各种复位后它们都会等于一个固定的复位值,见以下二表:
寄存器 |
地址 |
上电复位值 |
MCLR复位 |
W |
— |
qqqq xxxx(注1) |
qqqq uuuu(注1) |
INDF |
00h |
xxxx xxxx |
uuuu uuuu |
TMR0 |
01h |
xxxx xxxx |
uuuu uuuu |
PC |
02h |
1111 1111 |
1111 1111 |
STATUS |
03h |
0001 1xxx |
?00? ?uuu(注2) |
FSR(12C508) |
04h |
111x xxxx |
111u uuuu |
FSR(12C509) |
04h |
110x xxxx |
11uu uuuu |
OSCCAL |
05h |
0111 ---- |
Uuuu ---- |
GPIO |
06h |
--xx xxxx |
--uu ----- |
OPTION |
— |
1111 1111 |
1111 1111 |
TRIS |
— |
--11 1111 |
--11 1111 |
u: 未变; x: 随机值; -: 未用; ?: 其值取决于复位方式
注1:由于在复位向量处存放着MOVLW XX指令,其中XX为内部RC振荡校正系数,所以复位后W<7:4>即会等于这个值。
注2:参见表1.6。
a. 各特殊寄存器复位后的值
复 位 类 型 |
状态寄存器STATUS |
程序计数器PC |
芯片上电复位 |
0000 1xxx |
1111 1111 |
运行时MCLR端加低电平复位 |
000u uuuu |
1111 1111 |
睡眠时MCLR端加低电平复位 |
0001 0uuuu |
1111 1111 |
睡眠时看门狗WDT超时复位 |
0000 0uuu |
1111 1111 |
运行时看门狗WDT超时复位 |
0000 1uuu |
1111 1111 |
睡眠时I/O脚电平变化唤醒复位 |
1001 0uuuu |
1111 1111 |
u:未变; x:随机.
b. 复位对STATUS和PC的影响
表1.5 各种复位对特殊寄存器的影响
§1.12.7 复位的鉴别
PIC12C5XX有多种原因都可引起芯片复位。在程序中判断芯片复位的原因有时是非常必要的,例如上电复位后程序一般都要做一些寄存器初始化工作,而别的复位后则可以不做初始化而直接进入控制运行。
在状态寄存器STATUS有三个位(GRWUF、TO、PD)可用来标识各种复位状态,见下表:
GPWUF |
TO |
PD |
复 位 原 因 |
0 |
0 |
0 |
睡眠中WDT超时溢出 |
0 |
0 |
1 |
运行时WDT超时溢出 |
0 |
1 |
0 |
睡眠中MCLR拉低 |
0 |
1 |
1 |
芯片上电 |
0 |
u |
u |
运行时MCLR拉低 |
1 |
1 |
0 |
睡眠中GP0,GP1或GP3电平变化 |
u:未变
a. 复位后TO、PD及GPWUF的状态
事 件 |
GRWUF |
TO |
PD |
注 |
芯片上电 |
0 |
1 |
1 |
|
WDT超时溢出 |
0 |
0 |
u |
不影响PD位 |
执行Sleep指令(进入睡眠) |
u |
1 |
0 |
|
执行CLRWDT指令(清看门狗) |
u |
1 |
1 |
|
睡眠中GP0,GP1或GP3电平发生变化 |
1 |
1 |
0 |
|
u:未变
b. 影响TO、PD及GPWUF位状态的事件
表1.6 复位对STATUS的影响
例:要判断是否芯片上电。
BTFSS STATUS,TO ;TO=1 ?
GOTO NO_POWERUP
BTFSS STATUS,PD ;PD=1 ?
GOTO NO_POWERUP
INIT … ;TO=1,PD=1。芯片上电,做初始化。
§1.12.8 睡眠模式(Sleep)
1、进入SLEEP
执行一条“SLEEP”指令即可进入低功耗睡眠模式。当进入SLEEP后,WDT被清零,然后重新开始计数。状态寄存器STATUS中的PD位被置成“0”,TO位置成“1”,同时振荡停止(指OSC1端的振荡电路)。所有的I/O口保持原来的状态。这种工作模式功耗最低。为使耗电流最小,进入SLEEP前,应使所有的I/O口处于高电平VDD或低电平VSS,而不应使其处于高阻态,以免产生开关电流损耗。可以在I/O口加上拉或下拉电阻,或者把I/O口都置成输出态来避免其处于高阻态(浮态)。
RTCC端亦应置为VDD或VSS(通过上拉或下拉)。
MCLR必须处于高电平状态。
2、唤醒SLEEP
SLEEP可被WDT溢出唤醒,或在MCLR端加低电平唤醒SLEEP或GP0、GP1、GP3电平发生变化。第二种唤醒方法经常用在以下应用场合:在系统主电源掉电,并由后备电源(电池)供电后,执行“SLEEP”指令进入低功耗模式,这样电池就可长时间保持系统数据。当主电源恢复供电时,让其在MCLR产生一低电平唤醒SLEEP,并重新复位。这样需在MCLR端加一外部复位电路。第三种方法则在需要使用系统时唤醒睡眠中的单片机,它常通过按键输入来实现。系统上电时,STATUS的PD被置为“1”,而执行“SLEEP”指令后,PD位被置成“0”。所以通过PD位可以判断系统是从SLEEP模式唤醒而复位,还是上电后的复位。STATUS中的TO位则可判断当处于SLEEP状态的系统是由WDT溢时唤醒或是由外界给MCLR端一个低电平唤醒。这些区别有时是很重要的,特别是对系统的一些初始化工作来说。
§1.12.9 系统定义字(Configuration)
在PIC12C5XX中有一个12位长的系统定义字单元,其中只用了前5位(bit0~bit4),用来定义单片机的一些系统性能选择,如下图:
图1.24 系统定义字
系统定义字属特殊的空间,不占用芯片的程序存储器,不能由程序指针(用户程序)访问,用户可以用烧写器对其进行编程,参见烧写器章节中的描述。
程序保密位被置为“0”后,程序存储区中的程序代码(12位)中的高8位将被遮没。具体地说,就是加密后再用烧写器读该芯片的程序区时,每一个程序代码都呈现00X的形式,这样别人就无法恢复这些被加密的代码,因此也就无法进行复制拷贝。加密后的单片机的功能不会受任何影响,加密后的程序代码并不影响其在芯片内的运行,而只是不能再被还原读出来。
§1.12.10 ID码
PIC12C5XX芯片中有一个16位的标识码(称为ID码),用来作芯片标识。ID码仅起芯片识别作用,用户可在烧写器上将其烧入和读出作芯片识别(如烧入日期等),但不会对芯片功能产生任何影响,即不使用它也没有关系。