通俗易懂讲PIC单片机:从一窍不通到入门进步
单片机入门不难------谈PIC系列(转自矿石收音机论坛---崂山)十年前的老帖子,讲得通俗易懂,分享之。
请看图1
这个8条腿的小螃蟹就是我们的第一顿饭,只要把它吃下去,以后的大餐就好办了。
第1、8条腿接电源 +5V 和 地线。头两条腿是螃蟹钳子,好吃的很。 现在剩下了 6 条腿
第2、3条腿 使用时外接一个晶振的东西 我们接一个 4 MHz的。
第4条腿是复位脚,是一个信号输入脚。单片机正常运行时接高电平。当有一个低电平脉冲输入到这个脚时单片机就复位。所谓复位就是单片机内部所有的工作部件统统回到规定的状态,程序也复位到头一句上开始逐条运行。例如,你设计的一个报警锁定的 LED红灯亮后,当需要解除报警时,用一个按钮给这个脚瞬时接地一下,相当于给它一个夫脉冲,系统就复位了,led灯就熄灭了,程序从头开始。
以上5个脚,几乎所有单片机都有,包括世界上最复杂的,和世界比较简单的单片机-----PIC12CE519
轮到底几条腿啦?奥是第5条腿,这条叫单片机的 I/O 脚。就是输入输出脚。你可通过程序动态地控制它作为输入或输出,作为输出时可以程序控制它的输出电平为高1或低0。所以,他的工作状态有四种:输入0,输入1,输出0,输出1
剩下的两条腿和第5脚功能一个样。
上边我们已经把8条腿消化掉了,其实我们要弄明白的也就3只腿,我们再简单一些,先整明白两条腿,即GP0,GP1.这两条腿低级一点的用法,可以控制继电器,LED灯,高级一些的用法可以进行I2C总线,RS232总线的通信,作为扩展输入可以模拟出来A/D转换器(6--7bit),可以测量一个电阻的粗略值。作为输出也可以直接推动扬声器奏出音乐。这是后话暂且不提。
现在要控制使用这两只腿,我这个三脚猫功夫的说书的不得不讲一下软件了,要想讲明白软件又不得不涉及到单片机的内部结构。那位说啦,你可别提这软件和结构了,以前俺就是让它们打败的,现在听到这个心里就打鼓。嘿嘿,不要紧,果真如你所说,那你就不妨跟着我再失败一次, 反正吗多一次失败又不纳税,嘿嘿。不过你也要有思想准备,彻底弄明白是个渐进的过程。
要说这程序和单片机内部结构,还真是老大难,不过蟹黄蟹肉都可都在里面。我现在要是给你说PIC单片机是哈佛结构的,51系列是冯-诺伊曼结构的,恐怕你要立马扎走人了。所以我得用点心思不让你溜号。
好在PIC系列的制造商(microchip 微芯公司 美国)理解我等苦衷,全部只有35条指令,而且有一些指令我们一般很少使用,常用的也就十几句,用的时候查手册,无需记忆。就算我们两天学习一句,也就两三个月时间,总比到老了还怕它们强啊。废话少说先看下面的两个例语:
my_name006: movlw 02h '常数2进入w
movwf GPIO 'W 的数进入 寄存器GPIO
这就是我们编的程序里的两个句子,也叫源程序。有以下特点
每行只能写一句话
每句话由四部分组成:
标号: 操作指令 操作数 '程序注释
下面我结合例子把这四部分解释一下。
第一部分 my_name006: 叫做标号,它是由字母或数字组成,由冒号结束。标号可有可无,比如第二句就没有标号。
第二部分movlw 叫做操作指令。它是必须有的,不能省略。PIC 系列的单片机共有 35 条指令。
第三部分02h 叫做操作数。有的指令没有操作数或者操作数是默认的,也不用写。
第四部分是程序注释,必须以单引号开头,主要作用是提醒和备忘。注释也是可有可无。
第二个例句中,省略了标号,当然注释也可以省略。他的指令是movwf, 操作数是GPIO。操作数不一定是数字,也可能是一个由字母组成的字符串。
知道了语句格式以后,我们下面就学习一些常用语句。我们先把这两个例句弄清楚。
这两句话的作用是把 2 这个常数写入到 GPIO 这个寄存器里。
单片机里有一些部件需要我们使用和操作,都是通过读写寄存器来实现的。每个部件都对应有操控它的寄存器,例如我们要控制使用的管脚GP0,GP1 这两个管脚对应的寄存器就叫做GPIO。对GPIO寄存器读操作,实际等效察看管脚电平的高低;对GPIO寄存器相应的位写1操作,实际等校让管脚输出高电平。写0,输出低电平。
每个寄存器可以储存一个八位的二进制数。这八个位的每个位都有名称,从左向右的名称是:
左端第首位名称叫D7,
左端第二位名称叫D6,
左端第三位名称叫D5,
左端第四位名称叫D4,
左端第五位名称叫D3,
左端第六位名称叫D2,
左端第七位名称叫D1,
最后一位叫D0,
而每一个位对应一个管脚的电平,例如当GPIO寄存器的D0位等于1时表示管脚GP0 的电平是高电平。D0位等于0时表示管脚GP0 的电平是低电平。常数2的八位二进制表示是“00000010” 所以,GPIO寄存器存放的8位2进制数的每个位的值以及管脚电平是:
D7对 应于内部总线管脚的电平 D7=0 内部总线管脚输出低电平
D6对应于内部总线管脚的电平 D6=0 内部总线管脚输出低电平
D5对应于GP5 管脚的电平 D5=0 GP5 管脚输出低电平
D4对应于GP4 管脚的电平 D4=0 GP4 管脚输出低电平
D3对应于GP3 管脚的电平 D3=0 GP3 管脚输出低电平
D2对应于GP2 管脚的电平 D2=0 GP2 管脚输出低电平
D1对应于GP1 管脚的电平 D1=1 GP1 管脚输出低电平
D0对应于GP0 管脚的电平 D0=0 GP0 管脚输出低电平
GP0---GP5管脚我们可以从上一讲的图1硬件中查出所对应的管脚。d7 d6 对应的内部时钟和数据总线我们现在暂且不要管它。以后本事大了在调教它们。在我们的例句中,向GPIO寄存器写入了2,常数2的八位二进制表示是“00000010” 因此如果此时GP0, Gp1等都已经被定义成输出的话,那么GP1输出高电平(接LED灯亮),GP0 输出低电平(所接led灯熄) 。
截止到现在,你已经学会如何控制管脚的电平高低了。尽管还有一些疑问,比如怎样定义管脚为输出脚(以后会说),我得说如果事先gp1,gp0这两个管脚处于输入状态,这两个例句无效,是控制不了电平的。
无论如何,这一会儿,你就学会了两个指令,35条我看也没啥难的。
'------------------------------------------------------------------------------
再加深一下对寄存器的认识:
要把一个常数存储到,或者说写到一个寄存器中,仅用一条指令是办不到的,必须通过一个特殊的寄存器W,把数据倒过去. 这就应该使用到两个语句。
movlw 02H 指令的意思是把一个常数存入特殊寄存器W, 这个常数是3,后面的H是表示十六进制
movwf GPIO 指令的意思是把特殊寄存器W的数值存入寄存器. 这个寄存器的名称是 GPIO
这里涉及到两个概念,常数和寄存器.
常数好说,比如说十进制数 35, 26 但要注意,在单片机系统里我们一般不用十进制,而使用十六进制. 有关数制转换方面的知识,是计算机的基础,必须会熟练地在二进制、十六进制、十进制之间转换,我就不罗索了.
寄存器也叫单片机的内存。
一个寄存器可以存储的数值范围是0--255,用十六进制表示就是 0---FFH.用二进制表示就是00000000----11111111.
以后要养成习惯用十六进制表示数.
那么,一个单片机里有多少个这样的寄存器哩,pic12ce512里面有1024个这样的寄存器可以供你使用,为了使用方便生产商已经给它们编上了号码,第一号码是000H,往下依照次序为 001H,002H........3FFH.(怎么样,开始用十六进制说事了吧,如果你不熟悉熟制转换赶紧补课来得及)
有了编号就像我们居住的房间有了房间号码,使用就方便的多了.房间号码在邮政行业叫地址,因此我们称这些号码叫做寄存器地址,或称地址数 例如 名称为 GPIO 的寄存器,他的地址,或地址数是 06H 。所以我们的两个例句完全等同于:
my_name006: movlw 02h '常数2进入w
movwf 06H 'W 的数进入 寄存器GPIO
'-----------------------------------------
有两个寄存器比较特殊,它们没有地址,一个名字叫做 W, 另一个叫做 TRIS. 所以他们两个在存储数据的时候比较快,一个指令就可以解决问题,例如: movlw 03H 一条指令就把常数3写入到W寄存器了。关于TRIS寄存器,我们以后用到它再说.
除了他们两个以外的其他所有寄存器,在写入数据时一般都要用两条指令进行。
今天就扯到这里,虽然只有两个指令,但主要目的是要同学们接触一下指令,建立寄存器的概念以及他们同硬件部件的联系。增强学习的信心。能有这些体会,这一节就算过关了。
随着以后的深入,你会发现小小单片机里面是一个大世界,兴趣也由此而生。
我们上一次讲的两个指令是是如何控制管脚电平的高低。前提是所有管脚已经被定义成输出了(OUT)如果被定义成了输入,则上次的指令虽然也能运行,但运行后丝毫不能改变管脚电平高低,因为此时管脚是输入状态,电平取决于外部输入,指令无法改变。
在PIC单片机系列中,改变I/O口的输入输出依靠写入寄存器TRIS的值,相应位写0,表示对应管脚被定义成了输出,写1,就是输入。
现在假如预把GP1、GP2管脚定义成输出,其他脚全是输入。那就应该向TRIS 寄存器写入二进制数 11111001,换算成十六进制就是
F9H.
依照以前我们学到的知识,在PIC系列单片机里,本来应该用下列的语句来完成我们的设定:
movlw 0F9H '常数进W 以字母开头的常数前面必须加0
movwf TRISA '把W内的数复制到TRIS
实际上PIC系列的单片机也都是这么写的,后面加的A,表示第一个8位的口(有的单片机不仅一个口,还有好几个8位的I/O口如TRISB TRISC TRISD等等) .
但是,记住了, PIC12系列的单片机必须改写成为:
movlw 0F9H '常数进W 以字母开头的常数前面必须加0
tris GPIO '把W内的数复制到TRIS 以后凡见到这个指令一律理解成 movwf TRISA
写法不同,意思是一样的. 这样你就又学了一个指令TRIS,不过这个指令的实质还是你曾经学过的movwf 只是写法不同罢了.
在PIC12系列里TRIS作为指令, 在其他系列(PIC161718)里把 TRIS 作为普通寄存器看待.
因为我们现在讲的就是PIC12CE519,所以我们暂时用
tris GPIO
这个格式,等以后进入PIC16C877 我们再写成 movwf TRISA , 至于理解按照后者进行.
'-----------
如果我们要控制GP1 GP2管脚的输出电平, 其他管脚作为输入.并且让GP1输出低电平,GP2输出高电平.完整的程序如下:
movlw 0F9H '常数进W
tris GPIO '把W内的数复制到TRIS ,GP1 GP2为输出,其他为输入
'此行无命令,起到的作用是容易读懂程序
movlw 04H '常数4的二进制是 00000100 ,GP1=0 GP2=1
movwf GPIO 'W内的数进GPIO 输出生效,原来定义成输入的脚的电平,不会受该句影响
上面已经学会了三条指令,但是8位寄存器的概念概念一定要建立起来,程序通过写入寄存器不同的数据
控制管脚作为输入使用还是输出使用,作为输出时是输出高电平还是低电平。
这样的操作又一个特点,就是每次写入数据,同时控制的往往不是一个管脚,而是好几个个.最多一次可
以控制8个管脚.在单片机里往往每8个脚叫做一个口,如口A, 口B,用英文表示就是GPIO PORTA PORTB PORTC 等.
更多的情况是:某个口内的某一个管脚需要改变电平,其他脚电平不变.例如我们仅需要GPIO口上的GP1
这个管脚的电平拉高,其他管脚电平不发生变化.这时候位操作指令为我们提供了方便,假如我们事先已经把GP1管脚定义过输出了(方法见前面讲过的):
bcf GPIO,GP1 '注释 GPIO口上GP1管脚电平拉低,我们行话叫 清除。
bSf GPIO,GP1 '注释 GPIO口上GP1管脚电平拉高,我们行话叫 置位。
怎么样,这样控制某一个管脚的电平就方便多了,你的编程效率大大提高啊.
记住:PIC所有单片机所有寄存器都是可以位操作的,这在51的单片机上是不能完全实现的.
不仅如此,PIC所有单片机所有管脚的单腿驱动输出电流可以高达 25mA,所以如果你驱动一个 5到10mA电流的LED发光二极管,根本不用加三极管,串个电阻直接挂在单片机上就得了,这在51的单片机上也是不能实现的,要加驱动三极管或驱动芯片.
怎么样,学PIC有好处吧. 也别急,好处还有那,且听我慢慢地白话。
一不小心,你已经会 5 个指令了,还有30个,加油啊。
继续
单片机的大部分指令,或者说单片机所做的大部分工作,多数在写入或读出寄存器。关于寄存器的初步概念我想我们已经建立起来了,它是一个能够存储8位二进制数据(最大255 = 0FFH) 的单元 每个单元都有它的编号,我们叫做它的地址,或地址编码. 地址编码也是十六进制的. 另外寄存器里的数据掉电就会丢失。
寄存器的英文是RAM 也要记住.
PIC12CE519 里面共有有48个寄存器供我们操作使用, 它们每一个都有固定的地址编码。
地址编码并不是连续的号码,而是分成了两段:
第一段: 从00H 开始, 依次是01H, 02H, 03H ....0AH, 0BH......到1FH 结束. 计32个寄存器
第二段: 从30H 开始, 依次是31H, 32H, ......................到3FH 结束 计16个寄存器
这种地址不连续编号, 而是要跳过去一段的做法, 对于我们新手来说很是不习惯. 为了让我们容易入门, 我们暂时先不管第二段RAM, 只当它不存在, 所有程序我们只涉及到第一段连续的ram 地址. 等我们熟练的掌握好了ram 的使用,再涉及第二段地址的RAM, 那时,你就会理解单片机设计者把它们分成两段的苦心了.
为了规范,我们今后一律把RAM的分段, 叫做分页. 第一地址段叫00页面, 第二地址段叫01页面.
例如: 我们学过的 I/O 口电平控制寄存器 GPIO, 它的地址编码是 06H, 属于00页面.
'-----------------
所有这32+16=48个寄存器除了在地址上分成了两个页面以外,又把它们分成两类:
一类专用寄存器,一类通用寄存器.
所谓专用,就是这个寄存器的功能已经由系统分配好了.例如 地址为06H 的名称就做GPIO寄存器的功能,是它的每个位,都对应到一个I/O脚的电平.
另一类 是通用寄存器,你可以理解成它的功能系统没有事先预定,而是由你在编程序的时候随机使用.
pic12ce519 的专用寄存器有 7 个, 位置在我们第00叶面的最前面. 这7个专用寄存器的地址编码是: 00H,01H, 02H, ----06 H
剩下的所有寄存器包括所有第01页面, 全部都是通用寄存器.
例子: 在两个通用寄存器 09H, 0AH 内, 写入常数 FC H
movlw 0FCH '常数进W
movwf 9H '复制W内的数到通用寄存器09H
movwf 0AH '复制W内的数到通用寄存器0AH 由于此时W内并没有改变,W不用再进常数.
'----------------------------------------------
下面是PIC12CE519的 寄存器ram的地址地图:
图最上端的 00 01 表示的是页面号码,或叫页面地址。
左侧 从00 --- 1FH 是00页面, 右侧是01页面。
从00H 到 06H 都已经起好了名称 ,它们是专用寄存器,用处各有不同。以后我们会逐个介绍它们
剩下的都是通用寄存器 或者叫普通寄存器 General Purpose Registers 意思是一般用途的寄存器
地址从20H 到 2FH 也不是“空洞”,也不是不能访问,只是读写它们的时候等于读写它们左侧对应的00页面。这一点我们可能有些迷惑,弄不明白也没有关系,以后随着程序理解的深入,会搞清楚的。
内存图谱,不要求记下来,但是应该有个大体印象,用的时候会察看就可以了。等编程时间一长
就那么几个字节,自然就记住了。
所谓字节是衡量二进制数据长度的一个单位。一个寄存器刚好能记住一个字节的数据。如果你要存储的数据比较大超过了255,那就要占2个存储器甚至更多。描述的时候通常我们不说这个数值占了多少个寄存器,而是说这个数据是几个字节的。
字节的英文是byte 一个二进制数的一位,叫比特 英文bit 1 byte 包含 8 bit
继续
下面我们学习一条新指令,叫做空操作指令
nop '什么事情也不做,但执行这个指令也要消耗掉一点时间。它没有操作数。
'不要理解成程序停了,实际上程序仍在正常运行。执行一连串的空操作指令,单片机
'白耗费时间,什么活也不干,往往用于延时
如果你需要一个很短时间的延时,可以采用一连串的空操作。注意每个 nop 也是占一行, 例如:
bsf GPIO,GP1 '管脚GP1输出高电平点亮LED灯(如果你已经接上灯的话)
nop
... .
bcf GPIO,GP1 '管脚GP1输出低电平关闭LED灯
...
运行的效果是接在管脚GP1上的LED灯先亮一段时间,再熄灭一段时间的闪烁。
这回再说一个程序转向的语句,goto 指令,学过basic 和 c 等语言的对它不陌生。
单片机对程序的执行是逐句自上而下进行。当它运行到某个位置,如果你不希望继续运行它下面的语句,而是希望它无条件的强行转到某一句上,就可以使用goto语句。
我们还是通过例子来说明goto 的使用方法。
已知外部晶振的频率为4 MHz, 设计程序从pic12ce512 单片机的GP1管脚上输出一个方波信号,信号频率固定并计算出频率的值。
myWAVE: bsf GPIO,GP1 '管脚GP1输出高电平点亮LED灯(如果你已经接上灯的话)
goto myWAVE 'myWAVE是标号,某行必须有这个标号,否则程序通不过
nop '由于goto的存在,以下语句得不到运行
当程序自上而下运行到goto 语句时, 不再继续运行它底下的语句, 而是让程序强行转向到标号为myWAVE的语句上,并继续运行.
这样一来的结果,程序会永远在标号myWAVE的这一句 bsf GPIO,GP1 到goto之间循环, 打转转.
关于PIC单片机的模块和功能总结
PIC 单片机的概述
PIC16F616 是一款 14 引脚、8 位的 CMOS 单片机。采用精简指令集,仅有 35 条指令,由于采用了数据总线和指令总线分离的哈佛总线结构,使得除少量指令不是单周期之外,大部分的指令都是单周期指令。这样有利于提高单片机的运行速度和执行效率。
PIC16F616 这款单片机供电电压可以在 2V 到 5。5V 之间,内部集成了一个 RC 振荡器,频率可以配置成 8MHZ 或者 4MHZ,也可以用外部晶振提供时钟。内部集成有 AD 转换、比较器等硬件模块,还具有上电复位、欠压复位、看门狗、代码保护等功能。三个定时器、PWM 发生器等可以由用户编程。下面我来一一介绍关于 PIC 单片机的这些模块和功能。
PIC16F616 分为程序存储其和数据存储器,程序存储器的大小是 2048words,数据存储器的大小是 128bytes。
程序存储器中 0000H 的地址为复位地址,当上电或者看门狗计时器等复位的时候,均会导致 PC 指针指向复位地址。地址 0004H 为中断地址,当无论发生什么中断的时候,PC 指针就会指向此地址。在地址 0005H~07FFH 可以移植程序。
数据存储器分为两个部分,分别叫做 bank0 和 bank1,其中 bank0 的地址范围为:00H-7FH,Bank1 的地址范围为 80H-FFH。一般的寄存器都放在里面。可以通过寄存器 STATUSL 里面的 RP0 位来选择 bank0 和 bank1。
在编程序的时候要注意的是,当你要操作的寄存器在 bank0 的时候,先要选择 bank0(将寄存器 STATUS 的 RP0 位置 0),然后再对你所要操作的寄存器进行操作,当你要操作的寄存器在 bank1 的时候,同理先要选择 bank1。
如果想要定义一些变量,可以在数据存储器 20H 开始的地址定义,定义的地址范围为 20H-7FH。一般这么多就够用了。
PIC 的输入输出端口
在学习这个部分的时候,曾经遇到过一些问题。PIC 单片机的引脚不多,大多都是复用引脚,例如 AD、IO、比较器、外接晶振等等,所以在配置端口的时候,一定要知道每个功能怎样设置才能实现的,在这一小节中,我要讲的是通用 IO 口的设置问题。
PIC16F616 有 12 个 IO 口,但是有一个引脚(RA3)只能作为输入引脚用,不能用作输出,另外,A 口具有电平变化中断的功能,而 C 口没有,在设计的时候要注意。
在设置的时候,一般要进行以下几项设置:
(1)设置端口是模拟端口还是数字端口,可以通过寄存器 ANSEL 来设置。例如你想用 AD,就要将相应的引脚设置为模拟输入端口。
(2)如果你选择的是数字端口,接下来就要设置端口的方向,是输入还是输出(RA3 除外),可通过寄存器 TRISA(A 口)或 TRISC(C 口)来设置。
(3)设置端口的输出电平,可以通过寄存器 PORTA(A 口)或 PORTC(C 口)来设置。
这是对 IO 口的通用设置,但是这不是全部的设置,接下来的设置要看时 A 口还是 C 口了。对于 A 口,它有几个特殊的功能:内部弱上拉、电平变化中断、RA2/INT 引脚的沿中断。如果想要这些功能,就要对相应的寄存器进行设置。
弱上拉的设置:只有当引脚为输出的时候弱上拉才有效,可以通过寄存器 WPUA 来设置相应引脚的弱上拉,值得一提的如果开启了弱上拉,会有多余的电流浪费,这样对于低功耗的设计是不可取的,但是如果在进行一些例如键盘电路设计的候,可以开启弱上拉功能,这样就不需要在键盘电路中加上拉电阻了。
电平变化中断的设置:可以通过寄存器 IOCA 来设置,但是首先要将相应引脚设置为数字端口且为输入状态。同时要将寄存器 INTCON 的 REIE 位设置为 1,总中断要允许(置寄存器 INTCON 的 GIE 位),如果设置相应引脚有这个功能,当此引脚电平发生的时候,就会产生一个中断,同时一些中断标志位被置上(INTCON 的 RAIF 位被置 1),且总中断 GIE 被置为 0。在中断服务程序中,要软件清除 RAIF 位和重新置 GIE 位才能继续开启此中断。
RA2/INT 脚的沿中断设置:同样首先要将相应引脚设置为数字端口且为输入状态,设置 INTCON 的 INTF 位为 1,表示允许 int 引脚外部中断,寄存器 OPTION_REG 的 INTEGD 位可以设置是上升沿中断还是下降沿中断。当发生中断时,INTCON 的 INTF 位被置为 1,GIE 被清零,在中断服务程序中,要软件清除 INTF 位和重新置 GIE 位才能继续开启此中断。
对于 C 口,不能产生电平变化中断和沿中断。
定时器
定时器是单片机的一个很重要的部分,用它可以产生很多不同的定时时间,来满足程序设计的不同需求。PIC16F616 有三个定时器,分别是 Timer0、Timer1、Timer2。它们的用法不是很相同,下面来分别谈谈这三个定时器的用法和设置问题。
(1)Timer0
Timer0 是一个八位的计数器,它有一个八位的计数寄存器 TMR0,八位的预分频器(与看门狗共用),可以选择内部或者是外部时钟源,有计数器溢出中断的功能。
Timer0 可以作为一个定时器或者计数器来使用,与 Timer0 有关的寄存器有:TMR0,INTCON,OPTION_REG,TRISA。
当 Timer0 作为定时器来使用的时候,要设置 OPTION_REG 的 T0CS 位为 0,表示用的是内部时钟,每一个指令周期 TMR0 的值会增加(当没有预分频的时候),当 TMR0 被赋值的时候,会有两个指令周期的延时。预分频器可以和看门狗共用,可以由 OPTION_REG 的 PSA 位来设置,当 PSA 为 0 的时候分频器选择 Timer0,当 PSA 为 1 的时候分频器选择看门狗。同时,与分频器的分频值可以通过寄存器 OPTION_REG 来设置,设置的值可以由 1:2 到 1:256。当 Timer0 的计数器 TMR0 计数从 FFH 到 00H 的时候会产生溢出,同时溢出标志位(INTCON 寄存器的 T0IF 位)会置位(无论 Timer0 的中断是否开启),如果中断已经开启了(INTCON 寄存器的 T0IE 被置位),那么就会产生溢出中断。T0IF 位需要软件对其进行清零。
当 Timer0 作为计数器来使用的时候,就要用外部时钟源(OPTION_REG 的 T0CS 置 1),每次当引脚 T0CK1 的沿到来时 Timer0 的 TMR0 会增加 1,上升沿和下降沿可以由 OPTION_REG 的 T0SE 来设置。中断和 Timer0 作为定时器使用时一样。在我们编程序的时候,可以用 Timer0 进行定时或产生定时信息,下面我来解释定时器的定时时间的计算。假设 Timer0 用的时钟源是内部的 4MHZ,那么每条指令的执行时间就是 1us,设 Timer0 的预分频系数是 1:256,TMR0 的初值是 6,那么定时时间为:
256×(256-6)×1us=64ms
在编程的时候需要注意的是 Timer0 的中断是不能把单片机从 SLEEP 的状态唤醒的。
(2)Timer1
Timer1 是一个十六位的计数器。它有一个计数寄存器对(TMR1H:TMR1L),时钟源也是内外可选的,具有一个 2bit 的预分频器,可以同步或者异步操作,具有中断功能,但是溢出中断只能在外部时钟、异步的模式才能将单片机从 SLEEP 中唤醒,Timer1 具有捕获 / 比较功能,还有被一些特殊事件触发功能(ECCP),比较器的输出可以与 Timer1 的时钟同步。下面来一一介绍这些功能。
在编程的时候也可以按照这样的步骤来进行。设置寄存器 T1CON,时钟源可以选择外部或者内部的时钟源,外部时钟源可以选择 LP 晶体。Timer1 在选择内部时钟时,可以运行在定时器的状态,选择外部时钟的时候,可以运行在定时器或者是计数器状态,工作于计数器状态时可以选择门限是高电平还是低电平计数。这些都可以通过寄存器 T1CON 来设置。
以下是 T1CON 每个位的具体功能:bit1:Timer1 是否开启位,当此位设为 1 时,Timer1 开启,设为 0 时,Timer1 关闭;bit2:时钟源选择位,置 1 时,选择外部时钟(T1CK1 引脚的上升沿),此位置 0 时,选择的是内部时钟,并且和 T1ACS(寄存器 CM2CON1 中)配合,当 T1ACS 位为 0 时,时钟为 FOSC/4,当 T1ACS 位为 1 时,时钟为 FOSC。bit2:T1SYNC:定时器 1 的外部时钟输入同步位,当 TMR1CS 位为 1、T1SYNC 位为 1,定时器 1 被设置成与外部时钟不同步,T1SYNC 位为 0 时,定时器 1 被设置成与外部时钟同步模式。Bit3:T1OSCEN:此位为 1 时 Timer1 的时钟选择 LP,为 0 时 LP 晶体被关闭。Bit5-4:T1CKPS:Timer1 时钟的预分频系数设置,通过这两位的是指,可以讲 Timer1 设置成 1:1、1:2、1:4、1:8 几种分频值。Bit6:TMR1GE:只有当 TMR1ON 位为 1 时才有效,当此位为 1 时,Timer1 计数被 Timer1 的门限控制,此位为 0 时,Timer1 正常计数。Bit7:T1GINV:此位为 1 时,Timer1 在门限为高时计数,此位为 0 时,Timer1 在门限为低时计数。
Timer1 的中断编程:当 Timer1 的计数产生溢出的时候,如果 Timer1 中断允许的话,就会产生中断。中断可以这样设置,Timer1 的中断允许位 TMR1IE(在 PIE1 寄存器中)置 1,寄存器 INTCON 的 PEIE 位置 1,同时总中断位 GIE(位于寄存器 INTCON 中)要置为 1。当定时器产生中断的时候,会把中断标志 T1IF 置为 1(位于寄存器 PIR1 中),然后 PC 指针指向 0004H 地址。T1IF 位必须软件清除。
(3)Timer2
Timer2 的功能于 Timer1 有些不同,Timer2 时一个八位的计数器,有一个八位的计数寄存器 TMR2,Timer2 具有以下功能:有两个分频器,一个是前分频器,一个是后分频器。分频可以软件进行设置,另外,Timer2 的时钟源是指令时间(FOSC/4),Timer2 有一个寄存器 PR2,此寄存器的功能是当 TMR2 增加到 PR2 的值时,将产生中断,当然,中断必须允许,然后 PR2 的值会重新变为 00H。下面来介绍 Timer2 的编程:
Timer2 的控制寄存器 T2CON 作用是设置 Timer2 的开启关闭和前后分频的分频系数,寄存器 T2CON 的 TOUTPS<3:0>位设置后分频系数,可以被设置成 1:1~1:16;位 TMR2ON 为 1 时,Timer2 开启,为 0 时,Timer2 关闭;位 T2CKPS<1:0>可以设置前分频系数,可以被设置成 1、4、16。
Timer2 的中断可以这样控制,允许 Timer2 中断位 TMR2IE(位于 PIE1 寄存器内)被置 1 时,Timer2 中断被允许,被置 0 时,Timer2 中断禁止。寄存器 INTCON 的 PEIE 位置 1,同时总中断位 GIE(位于寄存器 INTCON 中)置为 1。通过上面的设置,Timer2 就可以产生中断了。当定时器产生中断的时候,会把中断标志 T2IF 置为 1(位于寄存器 PIR1 中),然后 PC 指针指向 0004H 地址。中断标志位 T2IF 必须软件清除。
下面是三个定时器的比较:
唤醒功能
其他功能
定时器 Timer0
内部或外部时钟源,有一个预分频器。
定时器、醒功能。
计数器值溢出时发生中断预分频器与看门狗共用。
定时器 Timer1
内部或外部时钟源,有一个预分频器
定时器、计数器
外部时钟、异步模式时可唤醒 CPU
计数器值溢出时发生中断
与比较器模块、
捕获 / 比较模块共用
定时器 Timer2
有前分频器和后分频器
醒功能。
计数器值与预置值相等时发生中断
PWM 的产生需要此定时器
AD 模块
PIC16F616 有一个十位、八路的 AD 转换器。其参考电压可以为电源电压 VDD,也可以是外部参考电压(VREF 引脚),当 AD 转换完成后可以产生一个中断,此中断可以把单片机从睡眠状态中唤醒。下面来介绍一下关于 AD 转换的编程方法。
要使用一个 ADC,要做的有一下几件事情:
(1)设置端口,需要采样模拟信号的端口必须设置为模拟输入状态,如果设置为数字端口,将使转换结果不正确,端口的模拟输入可以由寄存器 ANSEL 来配置,在讲 RA 口的时候已经说到了如何配置了。
(2)通道的选择,有八路外部通道和三路内部通道,可以通过 ADCON0 寄存器的 CHS<3:0>位来设置通道的选择。
(3)参考电压的选择,参考电压可以是 VDD,也可以是外部参考电压,可以通过 ADCON0 寄存器的 VCFG 位来设置,当 VCFG=0 时,参考电压为 VDD,当 VCFG=1 时,参考电压为外部参考电压(来自 VREF 引脚)
(4)ADC 的转换格式,AD 转换后的结果保存在一个寄存器对里面:ADRESH 和 ADRESL,但是 AD 转换结果只有十位,设置 AD 转换格式可以通过设置 ADCON0 的 ADFM 位来选择,当 ADFM=1 时 10 位的 AD 结果的低八位保存在 ADRESL 内,高两位保存在 ADRESH 内;当 ADFM=0 时 10 位的 AD 结果的高八位保存在 ADRESH 内,低两位保存在 ADRESL 内。
(5)AD 时钟源的选择,寄存器 ADCON1 专门来设置 AD 的时钟源,ADCS<2:0>不同组合,可以将 AD 的时钟源设置为不同的频率,可以为 FOSC/2、FOSC/4、FOSC/8、FOSC/16、FOSC/32、FOSC/64 和 FRC(内部 RC)。
(6)AD 中断的配置,要使用 AD 的中断功能,可以先把 AD 中断使能,ADIE 位设置为 1(在寄存器 PIE1 中),PEIE 位置 1(在 INTCON 寄存器中),总中断 GIE 位置 1(INTCON 寄存器中)。
要开始一个 AD 转换,首先要使能 ADC 模块,即把寄存器 ADCON0 的 ADON 位置 1 即可,然后将 GO/DONE 位(ADCON0 中)置 1 就可以启动 AD 转换了。
AD 转换需要时间,转换 1bit 需要 Tad 的时间,Tad 与 AD 转换的时钟源和 VDD 有关,转换十位就需要 11 个 Tad 时间,如果第一个 AD 转换完成了,要进行第二个 AD 转换,必须还要等待 2*Tad 的时间才能开始。一个 AD 完成了,GO/DONE 位会被置为 0,如果中断允许的话,就会产生中断,且中断标志位 ADIF(寄存器 PIR1 内)会被置 1,在 AD 中断程序中就可以把 AD 转换结果读取出来(读 ADRESH 和 ADRESL),需要时把 AD 中断标志位清零。
AD 中断可以把单片机从睡眠中唤醒,但是要注意,使用这个功能的时候,时钟源必须设置为 FRC,否则的话在睡眠的时候就不会产生 AD 中断了。
看门狗
PIC16F616 的看门狗 WDT 其定时计数的脉冲序列由片内独立的 RC 振荡器产生,所以它不需要外接任何器件就可以工作。而且这个片内 RC 振荡器与引脚 OSC1/CLKIN 上的振荡电路无关,即使 OSC1 和 OSC2 上的时钟不工作,WDT 照样可以监视定时。例如:当 PIC16F616 在执行 SLEEP 指令后,芯片进入休眠状态,CPU 不工作,主振荡器也停止工作,但是,WDT 照样可监视定时。当 WDT 超时溢出后,可唤醒芯片继续正常的操作。而在正常操作期间,WDT 超时溢出将产生一个复位信号。如果不需要这种监视定时功能,在编程时,可关闭这个功能。
WDT 的定时周期在不加分频器的情况下,其基本定时时间是 18ms,这个定时时间还受温度、VDD 和不同元器件的工艺参数等的影响。如果需要更长的定时周期,还可以通过软件控制 OPTION 寄存器(PSA 位置 1)把预分频器配置给 WDT,这个预分频器的最大分频比可达到 1∶128。这样就可把定时周期扩大 128 倍,即达到 2。3 秒。
WDT 的预分频器是和 Timer0 所共用的,如果把预分频器配置给 WDT,用 CLRWDT 和 SLEEP 指令可以同时对 WDT 和预分频器清零,从而防止计时溢出引起芯片复位。所以在正常情况下,必须在每次计时溢出之前执行一条 CLRWDT 指令喂一次狗,以避免引起芯片复位。当系统受到严重干扰处于失控状态时,就不可能在每次计时溢出之前执行一条 CLRWDT 指令,WDT 就产生计时溢出,从而引起芯片复位,从失控状态又重新进入正常运行状态。
当 WDT 计时溢出时,还会同时清除状态寄存器中的 D4 位 T0,检测 T0 位即可知道复位是否由于 WDT 计时溢出引起的。
比较器
PIC16F616 有两个比较器:C1 和 C2,C1 的结构比 C2 的结构要简单,下面我分别对这两个比较器的用法和特性作简要说明。
(4)比较器 C1:它有一个独立的控制寄存器 CM1CON0,通过这个寄存器可以对比较器 C1 进行一些设置。位 C1ON 可以控制 C1 的开启关闭,位 C1OE 可以决定比较器的输出是从引脚输出还是内部输出,位 C1POL 可以选择比较器输出的极性,位 C1R 选择参考电压是链接到引脚 C1IN+还是连接到 C1VREF,C1CH 可以选择比较器负端从哪一个引脚输入的,位 C1OUT 存放了比较器的输出结果。
(5)比较器 C2:它的控制寄存器 CM2CON0 的操作跟 C1 一样,但是比较器 C2 比比较其 C1 功能要强,因为它与 Timer1 挂上钩了,C2 可以连接到 Timer1,而 C1 不能。当 C2 与 Timer1 相连接的时候,C2 的输出可以设置成与 Timer1 的下降沿锁定,如果 Timer1 有分频,则比较器的输出与分频后的 Timer1 下降沿锁定,可以通过相关寄存器来进行设置。
(6)两个比较还有其它的功能,都能组成滞回比较器,这样就可以对输入电压有一定的滤波功能。两个比较器还可以形成一个 SR 锁存器。
由于在本项目中没有选择用比较器这个功能,所以在这里就不详细叙述其细节设置,但要注意的是在不用此模块的时候,要能够保证此模块不能影响其他模块的正常工作,可以把比较器功能关闭(通过寄存器 CM1CON0、CM2CON0 的 CxON 位置 0 来关闭)。
捕获 / 比较 /PWM 功能
PIC16F616 具有捕获 / 比较 /PWM 的模块,下面来简单的介绍一下它们的功能。
这三个功能需要定时器的支持,捕获和比较功能需要定时器 Timer1 的支持,PWM 功能需要定时器 Timer2 的支持。都有中断的功能,选择这三种功能的某一种功能可以通过寄存器 CCP1CON 来设置。CCP1CON 的低四位 CCP1M<3:0>可以通过不同的组合来开启某项功能和关闭所有功能,当 CCP1M<3:0>=0000 的时候,捕获 / 比较 /PWM 模块的所有功能被禁止。具体其他的不同组合实现的功能,请参考 PIC16F616 的用户手册。
当选择捕获功能时,它可以捕获引脚 CCP1 发生的事件,同时把 16 位 Timer1 的计数值拷贝到 CCPR1H:CCPR1L 中来,引脚 CCP1 的发生事件可以指的是下列事件:CCP1 引脚的每个上升沿或者下降沿、第四个上升沿、第十六个上升沿。可以通过寄存器 CCP1CON 的低四位 CCP1M<3:0>来设置是哪一种事件。当事件发生的时候,单片机会置中断标志位 CCP1IF(寄存器 PIR1 上),如果中断被允许(寄存器 PEIE 的位 CCP1IE=1)的话,就会产生中断,中断标志位 CCP1IF 需要软件清零。
选择比较功能时,如果定时器 Timer1 的计数器值与寄存器 CCPR1H:CCPR1L 相等的话,将产生下面的事件:把引脚 CCP1 置 1/0、产生一个中断、触发一个事件(把定时器 Timer1 的技术器 TMR1 清零,并且如果此时 AD 是允许的话,它将触发一次 AD 转换),这些事件可以通过寄存器 CCP1CON 的低四位 CCP1M<3:0>来设置是哪一种事件。
当选择 PWM 功能时,通过设置 PR2、T2CON、CCPR1L、CCP1CON 这四个寄存器,模块可以产生不同占空比的 PWM 波形。具体的设置和占空比的计算请参考手册。
如果我们不需要这些功能,可以把这个模块关闭掉(设置 CCP1M<3:0>=0000 即可)。
复位、中断和睡眠
(1)复位
PIC16F616 包括这样的几个复位功能,上电复位(Power-on)、硬件复位、欠压复位(Brown-out)、看门狗复位。
关于上电复位 POR,大家都不陌生,单片机在上电的时候保持复位直到电压能够满足其正常的工作电压,同时你可以通过对 CONNFIG(编译器上即可设置)的设置,来开启 Power-upTime,这个时间一般为 64ms。
硬件复位可以通过 MCLR 引脚外界复位电路,即可实现硬件复位(将此引脚接低电平)。
欠压复位这个功能是可选的,也可以直接在编译环境中配置 CONFIG 寄存器来开启此功能。当此功能开启时,如果单片机在运行的时候,供电电压不足就会引起欠压复位,复位后单片机如果发现供电电压已经达到正常值的时候,会有一个 64ms 的延时,然后再运行程序。
关于看门狗的复位在看门狗部分已经说了。这里的一些复位还涉及到一些标志位。这些标志位分布在 STATUS 和 PCON 上面。STATUS 上有两个位 TO、PD,当标志位 TO=1 时,表示表示已经操作了上电复位或者是执行了 CLRWDT 或者 SLEEP 指令,当 TO=0 时,表示发生了看门狗复位。当标志位 PD=1 时表示操作了上电复位或者是执行了 CLRWDT 指令,当 PD=0 时,表示执行了 SLEEP 指令。PCON 上有两个标志位是 POR 和 BOR,分别表示的是上电复位和欠压复位标志。具体的可以参看手册。
(2)中断
PIC16F616 包括这样的几个中断源:RA2/INT 引脚外部中断、RA 端口电平变化中断、定时器 Timer0、Timer1、Timer2 溢出中断、比较器中断、AD 转换中断、捕获 / 比较 /PWM 中断。
这些中断的允许位和中断标志位分别位于 INTCON、PIE1、PIR1、IOCA 这些寄存器里面,如果要开启相应的中断,就要置相应的中断允许位,开启总中断位(INTCON 寄存器的 GIE 位),还要开启 INTCON 上的 PEIE 位(定时器 0 溢出中断、INT 引脚沿中断和 RA 端口的电平变化中断除外)。
当中断发生的时候,相应的中断标志位就会置起来,同时总中断标志位 GIE 会被清零,保证在此时间内不会相应其他的中断,然后将当前的 PC 指针值压栈保存,以用来保证中断能正确的返回到原来执行的地方。然后 PC 指针指向中断向量地址 0004H 的地方,所以在编程序的时候,你可以在 0004H 的地址存一条跳转指令跳到你定义的中断服务程序里面去就可以了。如果在中断的时候想保存一些重要的寄存器的话,可以在中断程序的起始将其保存,然后在中断服务程序的末尾将其恢复即可。
要注意的是中断标志位不会自己清零,这就需要在编程的时候在软件上对其清零,否则的话,单片机不停的执行中断服务程序。如果你想要在以后的程序中还能产生中断的话,就要把总中断允许位 GIE 重新置位。
(3)睡眠
要想让单片机睡眠的方法很简单,执行一条 SLEEP 指令就可以了,如果看门狗允许的话,WDT 就会被清零,但是还保持运行,寄存器 STATUS 的 PD 位将会置 0,TO 位将会置 1,IO 口还保持原来的状态,在睡眠状态下,不能驱动振荡器了。
有些事件可以将单片机从睡眠状态中唤醒:看门狗、RA 口电平变化中断、外部复位引脚 MCLK 被拉低、RA2/int 引脚沿中断、Timer1 中断(必须工作在异步计数模式)、ECCP 捕获模式中断、AD 转换中断(时钟源必须为内部 RC 的时候)、比较器输出有变化,这些事件能够将单片机唤醒,其他的事件不能。
如果某项能唤醒单片机的中断已经开了,当总中断允许位 GIE 为 1 的时候,单片机被唤醒后可以进入中断程序中去,而当 GIE 位为 0 的时候,单片机也可以被唤醒,但是是执行下面的语句,而不能进入中断程序中去。
为了保证在执行 SLEEP 语句后看门狗能够清零,最好在 SLEEP 语句之前加一句清看门狗的语句 CLRWDT。
相关型号资料:AT25020N-10SC2。7MUX08FPIRFI9520GTS83C51RB2-MC
PIC 单片机的一些电特性
VSS 引脚的最大输出电流和 VDD 最大的输入电流为:90mA;
每个 IO 口的输出电流可达 25mA,IO 口总共输出电流可达 90mA;
每个 IO 口是由两个保护二极管上下钳位的。当电压超过 VDD 和 VSS 的时候,二极管最大能承受 20mA 的电流;
IO 口输入漏电流最大为±1uA,引脚 MCLR 和 OSC 漏电流最大为±5uA;
PORTA 内部弱上拉(若设置了此功能)电流最大为 400uA;
IO 口输出低电平为 0。6V,输出高电压为 VDD-0。7V;
编程注意事项及技巧
在编程调试后和根据网上的一些资料和经验,我注意到了一些在编程的事项和技巧,通过这些设置,可以使系统更加稳定的工作,现在总结如下:
(1)在设置端口的时候,先将端口输出你想要预置的值,以免发生出示状态的不稳定,影响系统正常工作。虽然在当前还没有定义端口是输出还是输入状态,这样做总是好的。
(2)在开启某个中断功能的时候,最好将其中断标志位清一次零。
(3)在设计低功耗的时候,其中有些功能是比较耗电的,如果不用的话,一定要将其关掉。例如将 IO 口设置成输入并将其悬空,就会很耗电流;RA 口设置弱上拉的时候如果引脚接地,电流会很大;欠压复位也是一个耗电大户。而看门狗开启时用的时钟源为内部的 RC,不怎么耗电;AD 转换耗电也不多。
(4)单片机里面的功能很多,在有些功能不需要的时候,一定要将其关闭(可以放在初始化程序之中),这样一来有利于程序的稳定性;二来可以省电,因为开启某个功能总是要电来驱动的。
(5)如果一个寄存器被多种功能所共用,建议只对相应位进行操作,例如用 BCF、BSF、或、异或、与、非等指令,而不要整个的将其赋值,以免弄错了使其他模块受到干扰。
相关问答
通俗的介绍一下 pic单片机 - 懂得为什么要和电脑类比呢?看来你没有用过单片机吧,单片机的结构都是大同小异的。那就象征性地类比下。pic是哈佛结构的,程序存在程序存储器,也就是ROM...
Keil可以用来开发 PIC单片机 程序么?keil不能给pic单片机编程。pic有专用的编译软件,mplab和c语言编译软件picc。1、MPLABX目前还不是很成熟,如果用来做项目的话,建议用MPLAB8.86版本即可,到MIC...
PIC 的 单片机 如何实现查表功能?PIC系列单片机的查表程序可以利用子程序带值返回的特点来实现。具体是在主程序中先取出表数据地址放入W,接着调用子程序,子程序的第一条指令将W置入PC,则程序...
pic单片机 结构属于?传统的单片机采用复杂指令集(ComplexInstructionSetComputer,CISC)结构,通常有50~110条。而PIC采用精简指令集(ReducedInstruction...
plc pic ,和 单片机 有什么联系和区别啊?PLC是可编程逻辑控制器(ProgrammableLogicController)的简写,而PIC则是一款单片机的牌子,PLC类似于简单的计算机系统,通过使用专用的梯形图软件编写控制流程...
pic单片机 学的哪个芯片?PIC单片机主要使用的是MicrochipTechnology生产的PIC系列芯片。这些芯片包括低端的PIC10和PIC12系列,中端的PIC16系列,以及高端的PIC18和PIC32系列。这些芯片...
51单片机和 PIC单片机 有什么区别?区别是;它俩是不同系列的两款单片机,型号不同性能功率不一样。51单片机是一种集成电路。PIC是建立在单片机之上的产品。PIC的性能功率更加优良稳定。区别是;...
PIC单片机 串口下载软件?PIC下载通常分2种:焊接前用烧录机烧录,然后下载用下载工具,如ICD2,PICKIT3等还有一种办法,就是内置了bootload,PIC的做过功能要自己实现,可以通过诸如串...
想学会使用 PIC单片机 中的8脚单片机,是不是必须先学会使用 PIC 16F877?朋友们好,我是电子及工控技术,我来回答这个问题。对于单片机的学习我有以下体会和朋友们分享一下,我认为学习单片机要选择典型的、成熟度高的单片机。学会了一...
单片机 常见故障及处理?一些单片机常见问题的解决办法工作和生活中会遇到许许多多的问题,可能让你一时陷于其中,但是总有解决的办法。随时记下遇到的问题,并做好总结,一方面有助于积...