矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
查看: 32937|回复: 36

建议先这样下刀,用uVision 3切入。。。

[复制链接]
发表于 2007-7-31 12:41:35 | 显示全部楼层 |阅读模式
还没有下载安装?再罗嗦一遍,去伟纳电子下载51编程集成软件uVision3,并且安装起来:
地址:http://www.mcusj.com/down_view.asp?id=413
还要到平凡工作室去下他们开发的两个单片机实验仿真板软件备用:
http://www.mcustudio.com/download/soft.asp?id=36:8个led4个按键
http://www.mcustudio.com/download/soft.asp?id=45:数码管编码
http://www.mcustudio.com/down/simboard.rar :8个数码管,4x4按键阵列

       现在我们要用Atmel的AT89C51做实验,目标是用接在单片机P3.2  P3.3  P3.4  P3.5上的4个按钮控制P1口P1.0 ... P1.7上的8个发光管,注意:某个按钮按下,相应引脚P3.x为0,而发光管是共阳极接法:只有P1.x引脚为0时,相应的LED点亮,而单片机加电启动复位后,各口均为1,所有LED熄灭。怎么个控制法,还是一步步地来。
1。先打开nVision3,结果如下:
uv2.jpg
2。顺次点开Project-->New-->u Vision Project,弹出对话框,建立1个新项目,选择或创建1个文件夹保存项目文件,如下:

把项目文件M51SAMP1保存到MY51文件夹,点保存,随后弹处对话框,选择单片机型号:
uv3.jpg
选择ATMEL的AT89C51:
uv4.jpg
确定。这时弹出对话框,问是否需要把标准8051启动代码复制添加到系统文件夹中,选否:
uv5.jpg
3。点开File-->New,打开新的文本编辑框,以后就在其中写汇编程序。
uv6.jpg
uv7.jpg

[ 本帖最后由 wey05 于 2007-7-31 16:41 编辑 ]
 楼主| 发表于 2007-7-31 19:06:18 | 显示全部楼层
接着对我们的项目设置一下:
菜单选 Project-->Options for Target  'Target1':
TARGET0.jpg
从弹出的选项卡,选Target进行一些设置,例如把晶振设置为12MHz,用片内RAM(Small模式),2k 片内ROM,确定如下:
TARGET.jpg
现在我们可以在编辑器中写程序了,例如我们写如下句子,注意用英文输入法:(大小写不重要)
ORG  0000H     
        LJMP    MAIN


ORG   0030H

MAIN:  NOP


END
说明:ORG 0000H    指示程序指针最开始是从ROM的0000H开始,在此处放一条转移指令,用标号MAIN表示跳转目的地址,而这个地址的具体位置,由ORG 0030H指出。第一条必须是跳转,因为51规定在0003H,000BH,0012H,001BH...必须留给中断程序的跳转入口,不要占用。
    主程序仅仅1条NOP空操作,什么也没干。END标志程序结束。先把它保存为M51SAMP1.ASM,以后就在这和基础上修改扩充。
下面,打开左面项目窗口的Target 1文件夹下面的Source Group1文件夹右键弹出菜单:
TARGET1.jpg
选Add  Files to Group 'Source Group1'  打开项目源文件夹MY51,现象显示所有文件选M51SAMP1.ASM确定,就把这个汇编文件添加到了项目中:
TARGET2.jpg
编辑器字体,背景色等可以通过菜单:Edit-->Configrations-->Colors & Fonts -->8051:Editor Asm Files在右面窗口设置。

[ 本帖最后由 wey05 于 2007-7-31 22:40 编辑 ]
     
发表于 2007-7-31 20:40:25 | 显示全部楼层
这两天正在捣鼓这个软件
 楼主| 发表于 2007-8-1 21:40:36 | 显示全部楼层
现在,把前面下载的ledkey.rar解压,把得到的ledkey.dll复制到文件夹..\keil\c51\bin\中,(我们的项目文件位于..\keil\MY51\中)。
    然后点开菜单Project-->Options for Target 'Target1',弹出的选项卡选Debug,在做下方的Parameter文字框中加入-dlefkey,如下:
TARGET3.jpg
这样,就可以在调试运行时利用软件模拟的单片机最小系统:P1口有8个LED,P3.2..P3.5有4个接地按键。

然后,把这个什么也不干的程序改写一下,加点东西,让P3.2和 P3.3两个按键控制P1.0相连的LED亮-灭,实际问题就是,P3.2为0--按下时,P1.0输出地电位(0),LED亮;P3.3按下时P1.0输出高电位,LED灭:原有程序改成:
ORG  0000H
        AJMP   MAIN

ORG  0030H

MAIN:NOP
         MOV  SP,#30H
POS1:JB P3.2 , $
         MOV A , #11111110B
         MOV P1,A
         JB P3.3 , $  
         SETB P1.0
         AJMP  POS1
   
         END      
      解释:以上 MOV SP,#30H倒不是这里必须的,而是个通用句子,用途是程序运行先把堆栈放到31H,因为默认复位后栈针为7,把工作区做堆栈使得以后如果用2--3区会不便,所以干脆把它移到RAM区去。
    JB P3.2 ,$   ;是说按照P3.2电位高低--是否按键,决定转移。如果未按,P3.2为1,转移:注意这个$表示转移到本条指令地址,换句话说如果未按键,程序就在此处原地踏步,一旦按键就继续往下走:
    通过A的最低位为0,使P1.0为0,点亮LED。接着程序在等待P3.3按下,未按,原地踏步,按下,用位指令SETB P1.0使得P1.0为1,LED灭。
    现在点开Project -->Rebuild  all target files,如果正常无误,这个.asm文件会转换 为一系列目标文件,就可以调试运行了。如果有错误,会发出提示,以便修正。

[ 本帖最后由 wey05 于 2007-8-1 22:42 编辑 ]
     
发表于 2007-8-1 23:17:21 | 显示全部楼层
感谢楼主的帖子。不过在周坚的轻松入门2版里面,已经是-p52 -dledkey

[ 本帖最后由 yzhkpli 于 2007-8-1 23:19 编辑 ]
     
发表于 2007-8-2 02:39:26 | 显示全部楼层
进来学习的!
 楼主| 发表于 2007-8-2 08:34:00 | 显示全部楼层
回yzhkpli,这个插件本来就是周先生开发的,我们感谢他为初学者提供了这么个好东西!如您所说就更方便了,可以把注意力集中到编程上去。keil使用入门不难,真要全部清楚也要花功夫的。好了。。。
    下来把刚才些好的汇编,进入Project-->Rebuild all target  files,生成可执行文件:

build1.jpg

       然后用下面所示的按钮或Debug菜单进入调试模式,这时左框是单片机里面的寄存器等资源状态,右面跳出来提示说智能2K大小的程序什么,不管他。。。,确定。

debug1.jpg
下面就可以运行我们的小小程序了,怎么样?单片机出来了吧?如果单片机没出来在图中菜单选最下的那项,就会出来:

debug2.jpg
下面点run按钮(也可在Debug菜单中选),开始运行:

debug3.jpg
没有变化?用你的鼠标点击P3.2按键,怎么样?
debug4.jpg

[ 本帖最后由 wey05 于 2007-8-2 08:35 编辑 ]
 楼主| 发表于 2007-8-2 11:58:11 | 显示全部楼层
好了,现在把程序MAIN以后做一些修改如下:
MAIN:    NOP
             MOV  SP,#30H
POS1:    JB P3.2 , $
             JB F0,POS2
              MOV A , #11111110B
               MOV P1,A
               CPL F0
                AJMP POS3
POS2:      SETB P1.0
               CPL F0
POS3:    JNB P3.2 , $  
             AJMP  POS1
   
              END  
会有什么名堂:注意上面的F0是“程序状态字“寄存器PSW中的一个可由我们置位1或清0的标志位,启动复位后为0。现在的过程是P3.2未按下,踏步,P3.2按下,下一步根据F0标志的状态确定走向,若F0为0,接着走,使P1.0低,点灯,然后CPL F0:F0取反,现在是0变1,转到POS3位置;若F0不为0(意味着P3.2已经被按下点灯),转到POS2位置,把P1.0置位1,灭灯,再把F0取反,为下次按键点灯创造盘点条件。最后两种执行都到POS3,踏步一旦按键P3.2释放,立即跳到循环起始POS1。于是。。。这就是用1个按键轮流开关灯的试验。把他引申一下,如果在硬件上P3.2的外接按键石由10个按钮并联而成,那不是用10个按钮任意控制1个灯?如果单纯用机电手段例如继电器,需要用记忆元件,否则不好解决,可是单片机却很容易处理了。
     
发表于 2007-8-2 15:44:55 | 显示全部楼层
请问楼主:peripherals下没有“键盘LED仿真板”是怎么回事?
 楼主| 发表于 2007-8-2 18:54:15 | 显示全部楼层
原帖由 zxhb 于 2007-8-2 15:44 发表
请问楼主:peripherals下没有“键盘LED仿真板”是怎么回事?

检查下你的uVision安装目录:
例如:我是这样:
ANSER.jpg
下载解压后的ledkey.dll复制到 BIN 文件夹
项目文件都在MY51文件夹,然后设置projict-->Options for Target  ' Target1'-->Debug选项卡parameter中原有-p51,再加上-dledkey
在debug状态peripherals最下面就有了。见前面说明图示
     
发表于 2007-8-3 08:14:33 | 显示全部楼层
谢谢,再按照您的要求作一次。
 楼主| 发表于 2007-8-3 13:24:29 | 显示全部楼层
今天试验以下小程序:
ORG 0000H
        AJMP MAIN

ORG    0030H

MAIN:  MOV SP,#30H
POS1:  MOV A,#1
           JB P3.2,$
            MOV P1,A
           JB P3.3,$
POS2:  RL A
           ACALL DELAY
           MOV P1,A
           JB P3.4,POS2
           AJMP POS1

DELAY: MOV R7,#250
DELAY1:MOV R6,#200
            DJNZ R6,$
            DJNZ R7, DELAY1
            RET

            END
      把它搞进去加工一番,运行:按P3.2,再按P3.3,看见什么?动起来了?再按P3.4回到开始。这里关键是用了A左环移指令加上延时子程序:RL A----最开始A内容为1,也就是0000 0001,P1也是00000001,所以只有P1.0不亮其余7个均亮,RL A 一次,A变成 0000 0010延时后P1.1灭,只要不按P3.4就一直循环:成了“跑马灯”
      延时子程序是用的很多的,要点是设立了2个递减计数器R6和R7,查指令表,知道执行DJNZ需要2个周期,现在12MHzj晶振,每个周期1微秒,R6由200递减到0,需要400微秒,然后R7递减1再次R6置初值200递减。。。全部循环需要400*500 =200000微秒=200毫秒=0.2秒。显然用2套循环最大延时是255*2*255*2=260.1毫秒,要求更长的延时,就得用3套循环了。
 楼主| 发表于 2007-8-4 14:49:20 | 显示全部楼层
从以上例子我们可以发现:
1。每个程序都是从尾到头循环;
2。根据外部条件决定程序往哪儿走,因此每次循环都要问P3.2,P3.3,P3.4是否按下,这种就是所谓“查询”方式。
     单片机还有一种非常重要的运行方式:中断方式。在中断方式,单片机在运行中,可能为外部条件打断当前的运行,转而插入另外一个过程,此过程完结后再回到原来的程序中去。
     C51有外中断0(INT0):对应P3.2引脚;(INT1),对应P3.3;定时/计数器0(C/T0)计数对应P3.4,定时内部;(C/T1),P3.5;串口中断。每个中断都有自己的中断入口和处理程序,这些中断入口位于ROM地址的0003H,000BH,0013H,001BH,0023H,要使用哪个中断就在哪个入口加一条转移指令,跳到中断程序的实际位置去执行,当然前提是程序中必须开放中断允许,这样P3.2等的低电位状态才会引发中断产生。在上面的所有例子中,因为不涉及中断,所以P3.2等只是作为普通I/O口。
    所以在程序中要使用中断功能,必须在入口加跳转指令;必须有中断子程序;必须开放中断。在C51中,有个专门控制中断开启和关闭的寄存器IE,其相应各位和]功能如下:
IE: 7      6       5        4         3        2        1        0
    EA     -       -         ES      ET1     EX1    ET0    EX0

总中断允许 -  -        串口   C/T1   INT1  C/T0   INT0
上列各位,为1允许,为0禁止。例如我们要开放INT0中断,就可以在程序中加入:
  MOV  IE,# 81H  :置IE的位7 和位0为1 ,允许INT0中断并且开放总中断。当然也可以用“位指令”直接置位:
SETB  EA
SETB  EX0
   在中断处理程序中通常
  1。关闭中断:避免在中断处理中因本中断信号未消失而反复响应,如果不想响应更高级别的中断,则关闭总中断;
  2。保存先前程序有关寄存器或RAM的状态,以便中断结束后恢复原有过程继续进行,通常用压栈PUSH指令。
  3。运行“真正的”中断处理。
  4。恢复保存的寄存器等等,通常用弹出POP指令。
  5。开启已经关闭的中断
  6。通过RETI指令,从中断子程序返回。下面是个例子:
ORG    0000H
          AJMP MAIN

ORG    0003H              ;INT0中断人口
         AJMP SUB_INT0

ORG    0030H

MAIN:  MOV SP,#30H   ;堆栈从31H单元开始
           SETB EA   ;开总中断
           SETB EX0  ;允许INT0中断
POS1:  MOV A,#1         ;按下P3.3,   P1.0灯灭。其余亮
           JB P3.3,$           ;
            MOV P1,A
            JB P3.4,$          ;按下P3.4循环灭灯
POS2:  RL A                 ;
           ACALL DELAY
           MOV P1,A
           JB P3.5,POS2     ;只有按下P3.5才停止循环灭灯(程序当然没有停止)
           AJMP POS1
DELAY: MOV R7,#250    ;延时子程序
DELAY1:MOV R6,#200
           DJNZ R6,$
           DJNZ R7, DELAY1
           RET
SUB_INT0: CLR EX0       ;INT0中断子程序,关总中断
                 CLR EA        ;关INT0中断
         PUSH PSW   ;保存原先PSW寄存器
         PUSH ACC   ;保存累加器A:注意这里ACC代表A的直接地址0E0H
         PUSH P1     ;保存P1口
         MOV A, #00110011B  ;中断处理是停止灭灯循环,而间隔两个灯亮灭
         MOV P1,A
         JNB P3.2 ,$   ;为了清楚起见只有松开P3.2才结束中断
         POP P1        ;恢复保存的各个寄存器
         POP ACC      ;
         POP PSW     ;
         SETB EA      ;重新开总中断
         SETB EX0    ;重新开INT0中断
         RETI           ;从中断返回主程序
          
          END
     汇编运行后用p3.4按键开始跑马灯,如果按下p3.2则停止,变成亮亮灭灭,直到放开p3.2继续跑马灯。如图:
debug5.jpg

[ 本帖最后由 wey05 于 2007-8-4 15:00 编辑 ]
 楼主| 发表于 2007-8-6 14:44:34 | 显示全部楼层
c51内部有2个16位定时/计数器C/T0和C/T1,正确使用这些内部资源,可以更多地发挥51的效能,例如:对外部脉冲计数--只要数出1秒有多少脉冲,不是可以做一个频率计吗?要不然对内部时钟脉冲进行计数--例如12MHz晶振产生的1微秒脉冲--不是可以做可调方波信号发生器?
       每个定时计数器都有2个8位数据暂存器THn和TLn,在其中存放初始设置值和后续计数值。
    使用定时计数器C/T0和C/T1,要点:
1。计数器:计数脉冲从单片机引脚P3.4(C/T0)或P3.5(C/T1)引入。计数值由TH1,TL1或TH0,TL0存放,当计数满,溢出就会使得标志位TF1或TF0置位,从而触发定时/计数中断。
2。定时器:计数脉冲就是单片机的时钟脉冲。通过给TH1,TL1或TH0,TL0写入预置值,就可在此值的基础上继续对时钟脉冲计数,不同的预制值就会有不同的后续计数脉冲产生溢出中断达到不同的定时要求。
3。4种不同的工作方式:
  1)方式0:13位定时计数器:用TH的8位和TL的低5位。计数值1-8192;晶振12MHz,最长定时8192微秒
  2)方式1:16位定时计数器计数值1-65536;晶振12MHz,最长定时65536微秒
  3)方式2:8位定时计数器,只用TL计数,计数值1-256,TH存设置值。计数溢出后把TH1/TH0中的预制值自动加载到TL1,TL0中。
  4)方式3:一个8位定时计数器和一个8位定时器;计数值1-256最长定时256微秒当C/T0(或C/T1)使用方式3,则另一个定时计数器只能使用没有溢出控制的方式0,1,2。
4。用控制寄存器TMOD来选择以上工作方式:
TMOD:高4位用于C/T1,低4位用于C/T0,如下:.
D7        D6        D5        D4     |        D3       D2       D1        D0
GATE   C/T       M1        M0     |       GATE    C/T      M1       M0
------------------C/T1------------|-------------------------C/T0---------------------------
其中:当C/T为1:计数器。C/T为0:定时器。
      M1  M0的4种组合,0 0,0 1,1 0, 1 1,对应上述4种工作方式。
      GATE为1时,可以由单片机的P3.2(或P3.3)引脚来允许/禁止定时或计数,1允许,0禁止(这不是起到频率计数硬件闸门的作用吗?妙!),GATE为0时,P3.2,P3.3不起作用;
TCON各位如下:
D7        D6        D5      D4         D3        D2       D1        D0
TF1        TR1     TF0     TR0       IE1       IT1      IE0       IT0
-------------------------------------------------------------------------------------------------
其中:TFn: C/Tn溢出标志:TH或TL(方式2,3)计数满溢出时自动置1。
      TRn: C/Tn的控制位!人为置1启动定时计数,清0停止定时计数。
          IE1,IT1和IE0,IT0是外部中断INT1和INT0的降沿触发标志和触发方式设置,不是C/T用的。
看来真麻烦,我们还是先举例好了:

假设我们用C/T0做16位定时器用,(方式1)定时20毫秒=20000微秒
因此TH0,TL0的预制值应该是65536-20000=45536=0B1E0H

MOV  TMOD,#0000 1001B ;高4位为0,先不管C/T1,低4位1001B:用P3.2允许禁止,模式1
MOV  TH0,# 0B1H;   TH0预制值高4位
MOV  TL0, # 0E0H ;TL0预制值低4位
MOV  IE ,# 82H    ;开总中断和C/T0中断
SETB  TR0        ;定时器TR0启动
    至于到达定时后的处理,在中断处理中进行定时计数中断的入口地址是000BH(C/T0)和001BH(C/T1)。
发表于 2007-8-6 22:23:54 | 显示全部楼层
图文并茂——非常好的文章
您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2024-5-4 08:40

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表