📄 the01.htm
字号:
图1.12 I/O口结构</p>
<p class="lh15" >除了GP3只能单向作为输入口外,其余的GPIO口皆可由用户定义为输入/输出态。作为输入口时没有锁存,外部信号必须保持到让CPU读入为止(例如:MOVF
GPIO,W)。作为输出则有锁存,可以保持直到被新的值取代为止。</p>
<p class="lh15" >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所示。</p>
<p class="lh15" ><b>§1.7.2 I/O口使用注意事项</b></p>
<p class="lh15" >1、I/O方向转置的问题</p>
<p class="lh15" >某时候可能需要一个I/O口一会做输入,一会又做输出。这就是I/O方向的转置。在编写这种I/O转置程序时必须注意,有些指令如位设置指令(BSF、BCF)写I/O口时是先从I/O读入其状态,执行位操作后再将结果写回去覆盖原来的内容(输出的结果放在I/O口的数据锁存器)。</p>
<p class="lh15" >举个例子来说:“BSF 6,5” 这条指令的目的是要把B口的第6位置为高电平“1”。执行这条指令时,先把整个B口当前的状态内容读入到CPU,把第6位置成“1”后再把结果(8个位)重新输出到B口。如果B口中的有一个I/O端是需要方向转置的(比如说bit1),而这时是处于输入态,那么B口的状态值重新写入后,B口的数据锁存器1的锁存值就是当前B口Bit1的状态。
这可能和先前Bit1作为输出时所锁存的值不同,所以当Bit1 再转置成输出态时,出现在Bit1 端的状态就可能和先前的输出态不同了。</p>
<p class="lh15" >2、I/O的“线或”和“线与”</p>
<p class="lh15" >从图1.12看出PIC I/O端输出电路为CMOS互补推挽输出电路。因此与其他这类电路一样,当某个PIC
I/O端设置为输出状态时,不能与其他电路的输出端接成“线或”或“线与”的形式,否则可能引起输出电流过载,烧坏PIC。如需要与其他电路接成“线或”电路时,PIC
I/O 端必须置于“1”状态或输入状态,并外接下拉电阻。电阻的阻值根据实际电路和PIC I/O 端最大电流来决定。</p>
<p class="lh15" >3、I/O口的连续操作</p>
<p class="lh15" >一条写I/O的指令,对I/O真正写操作是发生在指令的后半周期(参照图1.13)。而读I/O的指令却是在指令的周期开始就读取I/O端状态。所以当你连续对一个I/O端写入再读出时,必须要让I/O端上的写入电平有一个稳定的时间,否则读入的可能是前一个状态,而不是最新的状态值。一般推荐在两条连续的写,读I/O口指令间至少加一条NOP指令。</p>
<p class="lh15" >例:
<br>
MOVWF
6
;写I/O<br>
NOP
;稳定I/O电平<br>
MOVF
6,W ;读I/O</p>
<p class="lh15" >4、噪声环境下的I/O操作</p>
<p class="lh15" >在噪声环境下(如静电火花),I/O控制寄存器可能因受干扰而变化。比如I/O口可能会从输入态自己变成输出态,对于这种情形,WDT也是无法检测出来的。因此如果你的应用环境是较恶劣的,建议你每隔一定的间隔,都重新定义一下I/O控制寄存器。最保险的方法当然是对I/O读写前都定义一下I/O控制寄存器(但是实践证明对于大多数的应用都不必做到这样,只是提请你注意噪声干扰)。</p>
<p align="center" > <span class="lh15"><img src="image/the01.9.jpg" v:shapes="_x0000_s1027" width="594" height="229"><br>
</span>图1.13 I/O口连续读/写时序</p>
<p class="lh15" ><b><font size="2">§1.8 定时器/计数器TIMER0</font></b></p>
<p class="lh15" >TIMER0是一个8位的定时器/计数器,其对应的映像寄存器是TMR0(地址:01h),可由用户程序直接读写,并且可带有8位的预分频器。它用于对外加在GP2/T0CKI引脚上的外部信号进行计数(计数器)或对内部指令时钟进行计时(定时器),在PIC16C5X中它被称为RTCC。</p>
<p class="lh15" >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”时则上升沿触发。</p>
<p align="center" > <span class="lh15"><img src="image/the01.10.jpg" v:shapes="_x0000_s1028" width="595" height="207"><br>
</span>
图1.14 TIMER0 方块图</p>
<p class="lh15" >TIMER0计数器采用递增方式计数,当计数至FFH时,在下一个计数发生后,将自动复零,重新开始计数,从此一直循环下去。TIMER0对其输入脉冲信号的响应延迟时间为2个机器周期,不论输入脉冲是内部时钟、外部信号或是预分频器的输出。响应时序见图1.15。</p>
<p >
<p><span class="lh15">TIMER0对外部信号的采样周期为2个振荡周期,因此当不用预分频器时,外加在T0CKI
引脚上的脉冲宽度不得小于2个振荡周期即1/2指令周期。同时,当使用预分频器时,预分频器的输出脉冲周期不得小于指令周期,因此预分频器最大输入频率可达N,fosc/4,N
为预分频器的分频比,但不得大于50MHz。 </span> </p>
<p align="center" class="lh15" ><span class="lh15"><img src="image/the01.11.jpg" v:shapes="_x0000_s1029" width="592" height="168"></span><br>
图1.15a. TIMER0时序图:内部时钟/无预分频器</p>
<p align="center" >
<p align="center" class="lh15" ><img src="image/the01.12.jpg" v:shapes="_x0000_s1030" width="590" height="156"><br>
图1.15b. TIMER0时序图:内部时钟/预分频比1:2</p>
<p class="lh15" >应注意的是尽管PIC对外部加于T0CKI信号端上的信号宽度没有很严格的要求,但是如果高电平或低电平的维持时间太短,也有可能使TIMER0检测不到这个信号。一般要求信号宽度要大于10ns。</p>
<p class="lh15" ><b><font size="2">§1.9 预分频器</font></b></p>
<p class="lh15" >预分频器是一个分频倍数可编程的8位计数器。其结构如图1.14 所示上节对预分频参数已有描述,这里不再赘述。</p>
<p class="lh15" >预分预器的分配对象完全由程序控制,可以在程序中改变Prescaler分配对象。</p>
<p class="lh15" >1、从TIMER0到WDT的改变</p>
<p class="lh15" >
MOVLW
B'XX0X0XXX' ;选择内部时钟和新的预分频值<br>
OPTION
;如果新的预分频值='000'或者<br>
CLRF
1
;='001',则暂时先选一个另外的值<br>
MOVLW
B'XXXX1XXX' ;清零TMR0和预分频器<br>
OPTION
;选择WDT为对象,但不要改变预分频值<br>
CLRWDT
;清WDT和预分频器<br>
MOVLW
B'XXXX1XXX' ;选择新的预分频器<br>
OPTION</p>
<p class="lh15" >2、从WDT到TIMER0的改变</p>
<p class="lh15" >
CLRWDT
;清WDT 及Prescaler<br>
MOVLW
B'XXXX0XXX' ;选择TIMER0<br>
OPTION</p>
<p class="lh15" align="center" ><img src="image/the01.13.jpg" v:shapes="_x0000_s1031" width="590" height="414"><br>
图1.16 预分频器方块图</p>
<p class="lh15" >注意,预分频器只能分配给TIMER0或WDT其中之一使用,而不能同时分配给二者。</p>
<p class="lh15" ><font size="2"><b>§1.10 看门狗WDT</b></font></p>
<p class="lh15" >看门狗计时器(Watch Dog Timer)是一个片内自振式的RC振荡计时器,无需任何的外接元件。这意味着即使芯片振荡停止了(例如执行指令SLEEP后),WDT照样保持计时。WDT计时溢出将产生RESET。在PIC12C5XX芯片内有一个特殊的谓之“系统定义字”(Configuration
EPROM)的单元,其中的一个位是用于定义WDT的,可以将其置“0”来抑制WDT使之永远不起作用。这将在第六章的烧写器介绍部分详细说明。</p>
<p class="lh15" >1、WDT周期</p>
<p class="lh15" >WDT有一个基本的溢出周期18ms(无预设倍数),如果需要更长的WDT周期,可以把预分频器分配给WDT,最大分频比可达1:128,这时的WDT溢出周期约为2.5S。WDT溢出周期和环境温度、VDD等参数有关系,请参阅附录的图表。</p>
<p class="lh15" >“CLRWDT”和“SLEEP”指令将清除WDT计时器以及预分频器(当预分频器分配给WDT时)。WDT一般用来防止系统失控或者说防止单片机程序“失控”。在正常情况下,WDT应在计时溢出前被CLRWDT指令清零,以防止产生RESET。如果程序由于某种干扰而失控,那么不能在WDT溢出前执行一条CLRWDT指令,就会使WDT溢出而产生RESET,使系统重新启动运行而不至失去控制。若WDT溢出产生RESET,则状态寄存器F3的“TO”位会被清零,用户可藉此判断复位是否由WDT溢时所造成。</p>
<p class="lh15" >2、WDT编程注意事项</p>
<p class="lh15" >如果使用WDT,一定要仔细在程序中的某些地方放一条“CLRWDT”指令,以保证在WDT在溢出前能被清零,否则会造成芯片不停地产生RESET,使系统无法正常工作。</p>
<p class="lh15" >在噪声工作环境下,OPTION寄存器可能会因受干扰而改变,所以最好每隔一段时间就将其重新设置一下。</p>
<p class="lh15" ><b><font size="2">§1.11 振荡</font></b></p>
<p class="lh15" >PIC12C5XX可以运行在以下四种振荡方式下:<br>
<br>
a、LP
低功耗低速晶体振荡<br>
b、XT
标准晶体/陶瓷振荡<br>
c、INTRC
内部4MHz RC振荡<br>
d、EXTRC
外部RC振荡</p>
<p class="lh15" >以上四种振荡方式可由“系统定义字”中的Fosc1:Fosc2 两位来选择,请读者参阅后面§1.12.9的详述。</p>
<p > </p>
<p class="lh15" ><b>§1.11.1 晶体/陶瓷振荡</b></p>
<p ><span class="lh15">这种振荡包括XT和LP,其电路连接是在GP5/OSC1/CLKIN和GP4/OSC2两端加一晶体/陶瓷振荡,如下图所示:
</span> </p>
<p class="lh15" align="center" >
<img src="image/the01.14.jpg" v:shapes="_x0000_s1032" width="259" height="207"><br>
图1.17 晶体/陶瓷振荡电路</p>
<p class="lh15" >下表是使用各种频率的晶体和陶瓷振荡所需的C1、C2电容值。</p>
<table border="0" cellspacing="1" cellpadding="3" width="100%" bgcolor="#000000" >
<tr bgcolor="#F2F2F2">
<td > <p align="center" class="lh15" >振荡类型</p></td>
<td > <p align="center" class="lh15" >频率</p></td>
<td > <p align="center" class="lh15" >C1</p></td>
<td > <p align="center" class="lh15" >C2</p></td>
<td width="21" rowspan="7"> <p align="center" > </p></td>
<td > <p align="center" class="lh15" >振荡类型</p></td>
<td > <p align="center" class="lh15" >频率</p></td>
<td> <p align="center" class="lh15" >C1</p></td>
<td > <p align="center" class="lh15" >C2</p></td>
</tr>
<tr bgcolor="#FFFFFF" >
<td> <p align="center" class="lh15" >XT</p></td>
<td > <p class="lh15" >455KHz</p></td>
<td > <p class="lh15" >68-100P</p></td>
<td> <p class="lh15" >68-100P</p></td>
<td > <p align="center" class="lh15" >LP</p></td>
<td > <p class="lh15" >32KHz</p></td>
<td > <p class="lh15" >15P</p></td>
<td > <p class="lh15" >15P</p></td>
</tr>
<tr bgcolor="#FFFFFF">
<td rowspan="2" > </td>
<td rowspan="2" > <p class="lh15" >2MHz</p></td>
<td rowspan="2" > <p class="lh15" >15-33P</p></td>
<td rowspan="2" > <p class="lh15" >15-33P</p></td>
<td rowspan="2" > <p align="center" class="lh15" >XT</p></td>
<td valign="top" > <p class="lh15" >100KHz</p></td>
<td valign="top" > <p class="lh15" >15-30P</p></td>
<td valign="top" > <p class="lh15" >200-300P</p></td>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -