我也是在百度,单片机论坛,很多地方找帖子,最后在自己电脑上成功了,之后我教我同学设置联调,出现了一些问题,和我电脑不一样的地方,下面进行解答。写的不好,望大家见谅。
我学的单片机的课程教材是以STC15W4K32S4系列的单片机讲的,所以下面将以STC15的为例
我遇到了两种情况,先说共有的地方,遇到情况不一样的时候将分开说明。
STC15是51单片机的增强型,也是用51的keil来写程序,下面是keil5 C51安装应用程序,KEIL_LIC,Proteus7.8安装包(我是之前安装的Proteus7,老师课程里说用Proteus8,我感觉哪个都行,不过最新版的Proteus8.9有点问题,最后调试的时候问题就出现,所以尽量不要安装最新版的Proteus)
安装Keil5 C51,Protues,这里就不再详细说安装步骤了,不过要注意的是Keil5 C51最好用英文版的,尽量不要汉化,汉化有时会出现问题。
可以在STC官网上下载stc-isp-15xx-v6.87B,双击打开就行,在左侧的单片机型号里找STC15W4K32S4–>IAP15W4K58S4,如下图
之后在右侧Keil仿真设置选项,下面有个添加型号和头文件到Keil…选项,单击
找到Keil5 C51的安装路径我的安装路径是Keil5_Load,我是之前将MDK和C51兼容了,所以下面有ARM,这点可以不用在意,与联调没有任何关系。
比如我这个,就放到Keil5_Load就行,点Keil5_Load即可,再点确定,其实就放到C51这个文件夹的上一层文件夹即可,下图Keil5_Load里有个C51文件夹。点确定后,会提示安装成功,这样STC15的库就安好了。
之后打开Keil5 C51,可以新建一个工程文章最后有完整代码,可以复制下来,注意建一个asm文件,打开魔法棒,习惯这样称呼了,长得像而已,如下图
在Device下面,找到刚刚装的STC15的库
这样就能在Keil里选择STC15的芯片了。
网上下载VDM51.dll文件,找到Keil5 C51的安装路径,里面C51->BIN,放着这里面。
打开Keil5 C51的安装路径,里面有个TOOLS.INI文件,如下图,我把ARM和C51兼容了,所以多了一些东西,这些可以不用管。
双击打开即可
找到TDRV9,在这一行后面添加
TDRV10=BIN\VDM51.DLL (" Proteus Debug ")
你会发现,前面前面几行都是按顺序写的,我这里是TDRV9,所以我紧跟着是TDRV10,如果前面不是TDRV9,那么前面是几,在后面跟着加一就可。
注意:在最后一行,是刚刚添加STC库的时候自动在这个文件里修改的,这一行可以剪切到刚刚咱们添加的Protues Debug的那一行后面,同样,也需要注意顺序来写.
保存,关闭即可。
首先,没有问题的情况,就是0 Error(s), 0 Warning(s)。恭喜!!!第4点的东西就不用看了!!
代码是没有问题的,是一些Keil配置的问题,下面来说解决办法
1.打开魔法棒(Options for Target)->Device->右侧以第一个方框勾选
2.打开魔法棒(Options for Target)->LX51 Misc->写REMOVEUNUSED
之后再编译一下,应该就没问题了。
按照下面的图,选择Proteus Debug,如果没有的话,返回第4步查看哪里出了问题。
一般修改了Keil的设置,要把所有的Keil窗口都关了,再打开。
在魔法棒->Output里勾选Create HEX File,一定要勾选!!!!,之后Protues要用到这个文件。
可以自己连接电路。
启动远程调试,如果是英文版的,找一下对应的意思即可,很容易找到的。
注意!!!再次点调试里面看看对勾打上没有!! 如果没有,Proteus没装好,重新装一下,或者换个版本的Protues。
双击单片机,或者点击右键编辑属性,在Program File 后面有个打开文件的图标,点开,找到刚刚创建的Hex文件。
将Keil 和Proteus的页面在桌面各占半壁江山,在Keil里点放大镜一样的东西。可以看前面有一张图。
点运行
哇!!!成功啦!!
去打盘游戏放松一下,嘻嘻嘻!!
如果出现下面,说明Proteus没有打开远程调试,返回看第8步
联调好啦!!!终于能面对汇编为所欲为啦!!操练起来!!!
;程序名称:interrupt.asm
;程序说明:74HC595驱动数码管动态显示例,通过按键触发外部中断,P3.2进行计数,P3.3清零,实验箱上完成
;算法说明:由两片74HC595芯片分别驱动段和位,数码管动态扫描显示:修改延时子程序,可以改变扫描频率,达到不同显示效果
; 按键触发外部中断,下降沿有效
; R5,R4存放计数的结果,R5存放计数的千位和百位,R4存放计数的十位和个位
; 为了明显看到实验结果,R5R4初始化为9990,从此计数,每次加1,计数超过9999后会回到0000重新计数
; 实现正常的计数操作,只需要把102行,103行的R5,R4的初值改为0即可
;
;*******************************************************************
;*******************************************************************
;软件设置:可能电脑配置不同,该工程的设置可能不同
;打开keil文件,protues工程,编译,仿真,如果出现错误,则按下方的步骤设置
;1.打开魔法棒(Options for Target)->Device->右侧以第一个方框勾选
;2.打开魔法棒(Options for Target)->LX51 Misc->写REMOVEUNUSED
;*******************************************************************
;*******************************************************************
P0M1 DATA 0x93 ; P0M1.n,P0M0.n =00--->Standard, 01--->push-pull
P0M0 DATA 0x94 ; =10--->pure input, 11--->open drain
P1M1 DATA 0x91 ; P1M1.n,P1M0.n =00--->Standard, 01--->push-pull
P1M0 DATA 0x92 ; =10--->pure input, 11--->open drain
P2M1 DATA 0x95 ; P2M1.n,P2M0.n =00--->Standard, 01--->push-pull
P2M0 DATA 0x96 ; =10--->pure input, 11--->open drain
P3M1 DATA 0xB1 ; P3M1.n,P3M0.n =00--->Standard, 01--->push-pull
P3M0 DATA 0xB2 ; =10--->pure input, 11--->open drain
P4M1 DATA 0xB3 ; P4M1.n,P4M0.n =00--->Standard, 01--->push-pull
P4M0 DATA 0xB4 ; =10--->pure input, 11--->open drain
P5M1 DATA 0xC9 ; P5M1.n,P5M0.n =00--->Standard, 01--->push-pull
P5M0 DATA 0xCA ; =10--->pure input, 11--->open drain
P6M1 DATA 0xCB ; P6M1.n,P6M0.n =00--->Standard, 01--->push-pull
P6M0 DATA 0xCC ; =10--->pure input, 11--->open drain
P7M1 DATA 0xE1 ;
P7M0 DATA 0xE2 ;
P4 DATA 0C0H
P5 DATA 0C8H
KEY EQU R3 ;R3 用于存储按键的编号:0~F
XSP DATA 40H
YSP DATA 50H
;************* IO口定义 **************/
SER BIT P0.6 ; //pin 14 SER data input
STCLK BIT P0.7 ; //pin 12 RCLk store (latch) clock
SHCLK BIT P0.5 ; //pin 11 SRCLK Shift data clock
ORG 0000H ;程序起始地址
LJMP MAIN
ORG 0003H
LJMP EX0_INT
ORG 0013H
LJMP EX1_INT
ORG 0030H
MAIN:
//初始化单片机
MOV SP, #60H ;设堆栈指针 ,远离工作区
//显示缓冲区,初始化全显示“-”
MOV 20H, #17 ;左第1位数码管要显示字符
MOV 21H, #17 ;左第2位数码管要显示字符
MOV 22H, #17 ;左第3位数码管要显示字符
MOV 23H, #17 ;左第4位数码管要显示字符
MOV 24H, #17 ;左第5位数码管要显示字符
MOV 25H, #17 ;左第6位数码管要显示字符
MOV 26H, #17 ;左第7位数码管要显示字符
MOV 27H, #17 ;左第8位数码管要显示字符
// 显示位码缓冲区 ,零有效
MOV 30H, #0FEH ;选中第1个数码管
MOV 31H, #0FDH ;选中第2个数码管
MOV 32H, #0FBH ;选中第3个数码管
MOV 33H, #0F7H ;选中第4个数码管
MOV 34H, #0EFH ;选中第5个数码管
MOV 35H, #0DFH ;选中第6个数码管
MOV 36H, #0BFH ;选中第7个数码管
MOV 37H, #07FH ;选中第8个数码管
// 端口初始化
CLR A
MOV P0M1, A ;设置为准双向口
MOV P0M0, A
MOV P1M1, A ;设置为准双向口
MOV P1M0, A
MOV P2M1, A ;设置为准双向口
MOV P2M0, A
MOV P3M1, A ;设置为准双向口
MOV P3M0, A
MOV P4M1, A ;设置为准双向口
MOV P4M0, A
MOV P5M1, A ;设置为准双向口
MOV P5M0, A
MOV P6M1, A ;设置为准双向口
MOV P6M0, A
MOV P7M1, A ;设置为准双向口
MOV P7M0, A
//MOV KEY, #17 ; 按键编号初始化为横线的编号17
//MOV PSW, #0
MOV P3, #0FFH ;P3口接独立按键:P32-》SW17 P33-》SW18,外部中断0 和外部中断1,
;可以采用中断编程识别,也可以独立按键扫描识别,本例子采用扫描法
MOV DPTR, #SEGCODE ;DPTR指向显示码存储区
MOV R4, #90
MOV R5, #99 ;方便检测,从9990开始每次加1
//中断初始化
SETB EX0 ;打开外部中断0
SETB IT0 ;外部中断0下降沿触发
CLR PX0 ;
SETB EX1 ;打开外部中断1
SETB IT1 ;外部中断1下降沿触发
SETB PX1
SETB EA ;打开总中断开关
LCALL REBUFFER ;显示R5R4里的数值
MAINLOOP: ;主程序死循环
LCALL DISPLAY ;动态显示8位数字
LJMP MAINLOOP
//扫描动态显示子程序:先写段码,再写位码
DISPLAY:
MOV R0, #20H ; R0指向显示缓冲区,全部数码管扫描完毕后,重新循环扫描
MOV R1, #30H ;R1指向第一个数码管
DISPLAYi:
MOV A, @R1 ; 取位码
LCALL WR595 ; 位码送入595
MOV A, @R0 ;取段码
MOV DPTR, #SEGCODE ;DPTR指向显示码存储区
MOVC A, @A+DPTR ;
LCALL WR595 ; 段码送入595
LCALL LH595 ; 锁存发送到595的数据
INC R0 ;
INC R1 ;
CJNE R0, #28H, DISPLAYi
RET
//写入595子程序:串行发送累加器A中的8位数据到74HC595,R2作为移位次数计数器
WR595:
MOV R2, #08H
WR595i:
RLC A //带进位左环移
MOV SER, C //赋值
// 产生一个移位脉冲,将P2.1上数据移入595
CLR SHCLK
NOP
NOP
SETB SHCLK //方波,上升沿有效
DJNZ R2, WR595i //减一不为零跳转,等于零则说明8位数据移入完毕
RET
//数据锁存子程序:将接收到的8位数据送到并行输出端
LH595:
CLR STCLK
NOP
NOP
SETB STCLK //方波,上升沿有效,将移入的8位数据送到并行输出端
RET
//延时400ms子程序,用于数码管闪烁显示报警
DELAY400MS: ;@12.000MHz
NOP
NOP
NOP
PUSH 30H
PUSH 31H
PUSH 32H
MOV 30H, #15
MOV 31H, #152
MOV 32H, #82
NEXT0:
DJNZ 32H, NEXT0
DJNZ 31H, NEXT0
DJNZ 30H, NEXT0
POP 32H
POP 31H
POP 30H
RET
;//延时1ms子程序:修改R7可以改变延时时间的长短,控制扫描速度,12MHz时钟,延时约1ms
;DELAY1ms:
;MOV R7, #2
;DEL2:
;MOV R6, #248
;NOP
;DEL3:
;DJNZ R6, DEL3
;DJNZ R7, DEL2
;RET ; 子程序返回
//延时4ms子程序:用于按键消除抖动,实际应用时可以根据按键灵敏度修改
DELAY4ms: ;@12.000MHz
MOV 40H, #38
MOV 41H, #85
NEXT:
DJNZ 41H, NEXT
DJNZ 40H, NEXT
RET
//外部中断0中断处理服务函数
EX0_INT:
PUSH ACC ;现场保护
INC R4 ;R5R4一开始设置的初值为9990,每次加1,可以较快地看到到达9999后归零的现象
CLR C ;清除CY
MOV A, R4 ;判断R4是否到达100,溢出后向R5进位
SUBB A, #100
JC JR5 ;C=1,跳转,不进位,C=0,不跳转,向下向R5进位
R4_OV_100:
MOV R4, #0
INC R5
JR5:
CLR C ;清除CY
MOV A, R5 ;判断R5是否到达100,溢出后R5R4归零
SUBB A, #100
JC SEGSHOW ;C=1,跳转,刷新数码管缓存区,C=0,不跳转,向下R5R4归零
R5R4_OV_10000:
MOV R4, #0
MOV R5, #0
SEGSHOW:
LCALL REBUFFER
POP ACC
RETI
//外部中断1中断处理服务程序;数码管归零
EX1_INT:
PUSH ACC ;保护现场
MOV R4, #0 ;R5R4归零
MOV R5, #0
LCALL REBUFFER
POP ACC
RETI
REBUFFER:
MOV A, R4
MOV B, #10
DIV AB
MOV 27H, B ;得到个位
MOV 26H, A ;得到十位
MOV A, R5
MOV B, #10
DIV AB
MOV 25H, B ;得到百位
MOV 24H, A ;得到千位
RET
SEGCODE: ;标准字库
; 0 1 2 3 4 5 6 7 8 9 A B C D E F
DB 03FH,006H,05BH,04FH,066H,06DH,07DH,007H,07FH,06FH,077H,07CH,039H,05EH,079H,071H
; black - H J K L N o P U t G Q r M y
DB 000H,040H,076H,01EH,070H,038H,037H,05CH,073H,03EH,078H,03dH,067H,050H,037H,06EH
; 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
DB 0BFH,086H,0DBH,0CFH,0E6H,0EDH,0FDH,087H,0FFH,0EFH,046H
END ;