用户登陆 用户注册
您的位置:首页>
技术文章>内容正文
PIC系列单片机程序设计基础
[正文]:1、程序的基本格式 先介绍二条伪指令: equ ——标号赋值伪指令 org ——地址定义伪指令 pic16c5x在reset后指令计算器pc被置为全“1”,所以pic16c5x几种型号芯片的复位地址为: pic16c54/55:1ffh pic16c56:3ffh pic16c57/58:7ffh 一般来说,pic的源程序并没有要求统一的格式,大家可以根据自己的风格来编写。
但这里我们推荐一种清晰明了的格式供参考。
title this is …… ;程序标题 ;-------------------------------------- ;名称定义和变量定义 ;-------------------------------------- f0 equ 0 rtcc equ 1 pc equ 2 status equ 3 fsr equ 4 ra equ 5 rb equ 6 rc equ 7 ┋ pic16c54 equ 1ffh ;芯片复位地址 pic16c56 equ 3ffh pic16c57 equ 7ffh ;----------------------------------------- org pic16c54 goto main ;在复位地址处转入主程序 org 0 ;在0000h开始存放程序 ;----------------------------------------- ;子程序区 ;----------------------------------------- delay movlw 255 ┋ retlw 0 ;------------------------------------------ ;主程序区 ;------------------------------------------ main movlw b‘00000000’ tris rb ;rb已由伪指令定义为6,即b口 ┋ loop bsf rb,7 call delay bcf rb,7 call delay ┋ goto loop ;------------------------------------------- end ;程序结束 注:main标号一定要处在0页面内。
2、程序设计基础 1) 设置 i/o 口的输入/输出方向 pic16c5x的i/o 口皆为双向可编程,即每一根i/o 端线都可分别单独地由程序设置为输入或输出。
这个过程由写i/o控制寄存器tris f来实现,写入值为“1”,则为输入;写入值为“0”,则为输出。
movlw 0fh ;0000 1111(0fh) 输入 输出 tris 6 ;将w中的0fh写入b口控制器, ;b口高4位为输出,低4位为输入。
movlw 0c0h ; 11 000000(0c0h) rb4,rb5输出0 rb6,rb7输出1 2) 检查寄存器是否为零 如果要判断一个寄存器内容是否为零,很简单,现以寄存器f10为例: movf 10,1 ;f10→f10,结果影响零标记状态位z btfss status,z ;f10为零则跳 goto nz ;z=0即f10不为零转入标号nz处程序 ┋ ;z=1即f10=0处理程序 3) 比较二个寄存器的大小 要比较二个寄存器的大小,可以将它们做减法运算,然后根据状态位c来判断。
注意,相减的结果放入w,则不会影响二寄存器原有的值。
例如f8和f9二个寄存器要比较大小: movf 8,0 ;f8→w subwf 9,0 ;f9—w(f8)→w btfsc status,z ;判断f8=f9否 goto f8=f9 btfsc status,c ;c=0则跳 goto f9>f8 ;c=1相减结果为正,f9>f8 goto f9<
下例以f10做计数器,使程序循环8次。
count equ 10 ;定义f10名称为count(计数器) ┋ movlw 8 movwf count loop ;循环体 loop ┋ decfsz count,1 ;count减1,结果为零则跳 goto loop ;结果不为零,继续循环 ┋ ;结果为零,跳出循环 5)“if……then……”格式的程序 下面以“if x=y then goto next”格式为例。
movf x,0 ;x→w subwf y,0 ;y—w(x)→w btfsc status,z ;x=y 否 goto next ;x=y,跳到next去执行。
┋ ;x≠y 6)“for……next”格式的程序 “for……next”程序使循环在某个范围内进行。
下例是“for x=0 to 5”格式的程序。
f10放x的初值,f11放x的终值。
start equ 10 daend equ 11 ┋ movlw 0 movwf start ; 0→start(f10) movlw 5 movwf daend ;5→daend(f11) loop ┋ incf start,1 ;start值加1 movf start,0 subwf daend,0 ;start=daend ?(x=5否) btfss status,z goto loop ;x<5,继续循环 ┋ ;x=5,结束循环 7)“do while……end”格式的程序 “do while……end”程序是在符合条件下执行循环。
下例是“do while x=1”格式的程序。
f10放x的值。
x equ 10 ┋ movlw 1 movwf x ;1→x(f10),作为初值 loop ┋ movlw 1 subwf x,0 btfss status,z ;x=1否? goto loop ;x=1继续循环 ┋ ;x≠1跳出循环 8) 查表程序 查表是程序中经常用到的一种操作。
下例是将十进制0~9转换成7段led数字显示值。
若以b口的rb0~rb6来驱动led的a~g线段,则有如下关系:
点击查看大图片
设led为共阳,则0~9数字对应的线段值如下表: 十进数 线段值 十进数 线段值 0 c0h 5 92h 1 c9h 6 82h 2 a4h 7 f8h 3 b0h 8 80h 4 99h 9 90h pic的查表程序可以利用子程序带值返回的特点来实现。
具体是在主程序中先取表数据地址放入w,接着调用子程序,子程序的第一条指令将w置入pc,则程序跳到数据地址的地方,再由“retlw”指令将数据放入w返回到主程序。
下面程序以f10放表头地址。
movlw table ;表头地址→f10 movwf 10 ┋ movlw 1 ;1→w,准备取“1”的线段值 addwf 10,1 ;f10+w =“1”的数据地址 call convert movwf 6 ;线段值置到b口,点亮led ┋ convert movwf 2 ;w→pc table retlw 0c0h ;“0”线段值 retlw 0f9h ;“1”线段值 ┋ retlw 90h ;“9”线段值 9)“read……data,restore”格式程序 “read……data”程序是每次读取数据表的一个数据,然后将数据指针加1,准备取下一个数据。
下例程序中以f10为数据表起始地址,f11做数据指针。
pointer equ 11 ;定义f11名称为pointer ┋ movlw data movwf 10 ;数据表头地址→f10 clrf pointer ;数据指针清零 ┋ movf pointer,0 addwf 10,0 ;w =f10+pointer ┋ incf pointer,1 ;指针加1 call convert ;调子程序,取表格数据 ┋ convert movwf 2 ;数据地址→pc data retlw 20h ;数据 ┋ retlw 15h ;数据 如果要执行“restore”,只要执行一条“clrf pointer”即可。
10) 延时程序 如果延时时间较短,可以让程序简单地连续执行几条空操作指令“nop”。
如果延时时间长,可以用循环来实现。
下例以f10计算,使循环重复执行100次。
movlw d‘100’ movwf 10 loop decfsz 10,1 ;f10—1→f10,结果为零则跳 goto loop ┋ 延时程序中计算指令执行的时间和即为延时时间。
如果使用4mhz振荡,则每个指令周期为1μs。
所以单周期指令时间为1μs,双周期指令时间为2μs。
在上例的loop循环延时时间即为:(1+2)*100+2=302(μs)。
在循环中插入空操作指令即可延长延时时间: movlw d‘100’ movwf 10 loop nop nop nop decfsz 10,1 goto loop ┋ 延时时间=(1+1+1+1+2)*100+2=602(μs)。
用几个循环嵌套的方式可以大大延长延时时间。
下例用2个循环来做延时: movlw d‘100’ movwf 10 loop movlw d‘16’ movwf 11 loop1 decfsz 11,1 goto loop1 decfsz 10,1 goto loop ┋ 延时时间=1+1+[1+1+(1+2)*16-1+1+2]*100-1=5201(μs) 11) rtcc计数器的使用 rtcc是一个脉冲计数器,它的计数脉冲有二个来源,一个是从rtcc引脚输入的外部信号,一个是内部的指令时钟信号。
可以用程序来选择其中一个信号源作为输入。
rtcc可被程序用作计时之用;程序读取rtcc寄存器值以计算时间。
当rtcc作为内部计时器使用时需将rtcc管脚接vdd或vss,以减少干扰和耗电流。
下例程序以rtcc做延时: rtcc equ 1 ┋ clrf rtcc ;rtcc清0 movlw 07h option ;选择预设倍数1:256→rtcc loop movlw 255 ;rtcc计数终值 subwf rtcc,0 btfss status,z ;rtcc=255? goto loop ┋ 这个延时程序中,每过256个指令周期rtcc寄存器增1(分频比=1:256),设芯片使用4mhz振荡,则: 延时时间=256*256=65536(μs) rtcc是自振式的,在它计数时,程序可以去做别的事情,只要隔一段时间去读取它,检测它的计数值即可。
12) 寄存器体(bank)的寻址 对于pic16c54/55/56,寄存器有32个,只有一个体(bank),故不存在体寻址问题,对于pic16c57/58来说,寄存器则有80个,分为4个体(bank0-bank3)。
在对f4(fsr)的说明中可知,f4的bit6和bit5是寄存器体寻址位,其对应关系如下:bit6 bit5 bank 物理地址 0 0bank0 10h~1fh 0 1bank1 30h~3fh 1 0bank2 50h~5fh 1 1bank3 70h~7fh 当芯片上电reset后,f4的bit6,bit5是随机的,非上电的reset则保持原先状态不变。
下面的例子对bank1和bank2的30h及50h寄存器写入数据。
例1.(设目前体选为bank0) bsf 4,5 ;置位bit5=1,选择bank1 movlw data movwf 10h ; data→30h bcf 4,5 bsf 4,6 ;bit6=1,bit5=0选择bank2 movwf 10h ;data→50h 从上例中我们看到,对某一体(bank)中的寄存器进行读写,首先要先对f4中的体寻址位进行操作。
实际应用中一般上电复位后先清f4的bit6和bit5为0,使之指向bank0,以后再根据需要使其指向相应的体。
注意,在例子中对30h寄存器(bank1)和50h寄存器(bank2)写数时,用的指令“movwf 10h”中寄存器地址写的都是“10h”,而不是读者预期的“movwf 30h”和“movwf 50h”,为什么? 让我们回顾一下指令表。
在pic16c5x的所有有关寄存器的指令码中,寄存寻址位都只占5个位:fffff,只能寻址32个(00h—1fh)寄存器。
所以要选址80个寄存器,还要再用二位体选址位pa1和pa0。
当我们设置好体寻址位pa1和pa0,使之指向一个bank,那么指令“movwf 10h”就是将w内容置入这个bank中的相应寄存器内(10h,30h,50h,或70h)。
有些设计者第一次接触体选址的概念,难免理解上有出入,下面是一个例子: 例2:(设目前体选为bank0) movlw 55h movwf 30h ;欲把55h→30h寄存器 movlw 66h movwf 50h ;欲把66h→50h寄存器 以为“movwf 30h”一定能把w置入30h,“movwf 50h”一定能把w置入50h,这是错误的。
因为这两条指令的实际效果是“movwf 10h”,原因上面已经说明过了。
所以例2这段程序最后结果是f10h=66h,而真正的f30h和f50h并没有被操作到。
建议:为使体选址的程序清晰明了,建议多用名称定义符来写程序,则不易混淆。
例3:假设在程序中用到bank0,bank1,bank2的几个寄存器如下:bank0 地址 bank1 地址 bank2 地址 bank3 地址 a 10h b 30h c 50h · 70h · · · · · · · · · · · · · · · · a equ 10h ;bank0 b equ 10h ;bank1 c equ 10h ;bank2 ┋ fsr equ 4 bit6 equ 6 bit5 equ 5 data equ 55h ┋ movlw data movwf a bsf fsr,bit5 movwf b ;data→f30h bcf fsr,bit5 bsf fsr,bit6 movwf c ;data→f50h ┋ 程序这样书写,相信体选址就不容易错了。
13) 程序跨页面跳转和调用 下面介绍pic16c5x的程序存储区的页面概念和f3寄存器中的页面选址位pa1和pa0两位应用的实例。
(1)“goto”跨页面 例:设目前程序在0页面(page0),欲用“goto”跳转到1页面的某个地方key(page1)。
status equ 3 pa1 equ 6 pa0 equ 5 ┋ bsf status,pa0 ;pa0=1,选择page页面 goto key ;跨页跳转到1页面的key ┋ key nop ;1页面的程序 ┋ (2)“call”跨页面 例:设目前程序在0页面(page0),现在要调用——放在1页面(page1)的子程序delay。
┋ bsf status,pa0 ;pa0=1,选择page1页面 call delay ;跨页调用 bcf status,pa0 ;恢复0页面地址 ┋ delay nop ;1页面的子程序 ┋ 注意:程序为跨页call而设了页面地址,从子程序返回后一定要恢复原来的页面地址。
(3)程序跨页跳转和调用的编写 读者看到这里,一定要问:我写源程序(.asm)时,并不去注意每条指令的存放地址,我怎么知道这个goto是要跨页面的,那个call是需跨页面的? 的确,开始写源程序时并知道何时会发生跨页面跳转或调用,不过当你将源程序汇编时,就会自动给出。
当汇编结果显示出: x x x(地址)“goto out of range" x x x(地址)“call out of range" 这表明你的程序发生了跨页面的跳转和调用,而你的程序中在这些跨页goto和call之前还未设置好相应的页面地址。
这时应该查看汇编生成的.lst文件,找到这些goto和call,并查看它们要跳转去的地址处在什么页面,然后再回到源程序(.asm)做必要的修改。
一直到你的源程序汇编通过(0 errors and warnnings)。
(4)程序页面的连接 程序4个页面连接处应该做一些处理。
一般建议采用下面的格式: 即在进入另一个页面后,马上设置相应的页面地址位(pa1,pa0)。
页面处理是pic16c5x编程中最麻烦的部分,不过并不难。
只要做了一次实际的编程练习后,就能掌握了。
网站首页
培训课程
维修指南
技术文章
家电专栏
供应信息
求购信息
培训资讯
展会信息
电脑专栏
教程下载
资料下载
常用软件
PLC教程
PLC资料
变频伺服
低压电器
维修资料
人机界面
自控仪表
工控机类
文章标题:
中国工控资源网手机版 2012
电话:010-67577139 13811659603
培训咨询QQ:657167934 471895637 销售咨询QQ:623769457
联系邮箱:zggkzyw@163.com
京ICP备11002135号
报时(2026-04-06 13:08:46)