您现在所在的是:

单片机论坛

回帖:3个,阅读:541 [上一页] [1] [下一页]
1000
sunsoncheng
文章数:109
年度积分:50
历史总积分:1000
注册时间:2010/5/25
发站内信
发表于:2012/2/23 14:23:30
#0楼
附件:
[本地下载]
这是在STC89C51学习板下写的一个学习程序


1\利用中断与PC机通讯,
2\当PC机发送的适当的命令时做指定的工作并回传

出现的问题:
1\多次测试,得用串口测试工具,发送51 01 00 00 00 01到单片机时,由单片机的显示灯,显示只收到1个数(每次均是如此)

2\为验证相关的数据,将数据发送回PC机,一个是时间中断的次数及接收中断的两个时间间隔,不可能为0的,

3\每次发回的数据应是三个,但在串口助手中却有6到9个数回来不等

我已检查多次了,真没发现问题的原因,请各位大大帮忙检查一下?
谢谢

;串口1与PC联通
;适用于是STC stc89C51
;在伟福6000中用仿真器POD-8051(8031)编译

auxr      equ 08eh ;串口2的辅助寄存器,用于控制brt的开关,是否翻倍,及计数的模式

;用50 ~59 放置PC发回来的6(8)个数字要对数字测试防止错误数据回来
PCdatasit       equ 5AH   ;数据放置开始位的前一位如开始放在60H由此数为5FH
PCallNo         equ 5BH ;按协议该PC应收回的数据的个数
PCdataNo equ 5CH ;记录PC收回来的顺序数,

PCanswer equ 39H ;对PC数据检查后的回应值方便程序一次性将数据发回PC
PCdataXRL equ 3AH ;放置异或的结果,检测时的异或与发送时的异或同在一个中断中,故共用
;====================================================
tempL   equ  37H ;放置回收温度数据的低位
tempH     equ  38H ;放置温度数据的高位,用于计算最高值
sendPCsit equ  36H ;发送数据的开始位

FirsTime        equ  45H ;记录时间中断的次数用于控制接收数据时的时间间隔
NextTime        Equ  46H ;与上面的一同使用
;50H~58H用于记录收到的PC数据,
;====================================================

MyControl equ P2.5 ;检测控制位用于确定PC程序的设置
CallSheet bit P1.3 ;控制某个磁吸吸合

;====================================================
;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
ORG 0000H
LJMP MAIN
org     000BH         ;T0溢出产生的中断,会较串口中断高级,先执行
LJMP   T0_ISR         ;中断程序名

ORG 0023H
LJMP    comreti ;串口中断

ORG 0050H

MAIN:
mov sendPCsit,#37H ;发送数据的开始位
       mov PCdatasit,#4FH      ;equ 5AH   ;数据放置开始位的前一位如开始放在60H由此数为5FH
       mov PCallNo,#06H        ;equ 5BH ;按协议该PC应收回的数据的个数
       mov PCdataNo,#00H ;equ 5CH ;记录PC收回来的顺序数,

clr ea ;关闭中断总开关
       MOV SP,#5FH ;设置堆栈指针,即堆栈放在60H后面
      MOV TH0,#00H ;定时器0以FFFF为一次溢出,用于计时
      MOV TL0,#00H
mov tmod, #21H        ;T0的工作方式1(16位),T1为自动重装的方式
;没有这个中断的次数算出的总时间会错误!
;串口1初始化,与PC进行通讯,
lcall UARTINIT ;stc串口1的初始化代码用于与USB模块通讯

setb ea ;CPU开中断
setb et0     ;计时器0可中断
SETb TR0 ;启用定时器0用于记录单片机运行的时间长度

clr P0.0
       Ajmp $
ret
;**********************************************
;;主循环形成
;**********************************************

;$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
;此为STC自己的代码,初始化波特率发生器
;请用实际行动支持宏晶STC大陆本土MCU统一全球市场差0.16%
UARTINIT: ;9600bps@12MHz
ANL PCON,#7FH ;波特率不倍速
MOV SCON,#50H ;8位数据,可变波特率
ORL AUXR,#40H ;定时器1时钟为Fosc,即1T
ANL AUXR,#0FEH ;串口1选择定时器1为波特率发生器
ANL TMOD,#0FH ;清除定时器1模式位
ORL TMOD,#20H ;设定定时器1为8位自动重装方式
MOV TL1,#0D9H ;设定定时初值
MOV TH1,#0D9H ;设定定时器重装值
CLR ET1 ;禁止定时器1中断
SETB TR1 ;启动定时器1
setb ES ;允许串行中断
RET

;**************************************************
;T0定时器中断;
T0_ISR:
;记录中断的次数,用于比较两个接收周期的间隔,确定两个接收周期
inc  45H ;45H记录中断的次数加一
    RETI ;中断返回

;****************************************************
chk4546: ;用于将两个收数时间的判断,两者间差300MS 则为新的一周期
;已测试,利用自动借位因时间是在前进的,得出结果,并自动改变收数的起始位
;4个或以上的表示4*70Ms=280Ms
MOV A,firstime
clr c ;否则会产生不知道的结果
subb a,nexttime ;自动借位
cjne A,#05H,noequ04 ;再将A与2比较不同的转
cpl P0.5            ;=5
;mov r6,#5
Ajmp ithi
   noequ04:
jc exitchk4546 ;itequ >1的转移(即不够减);A<02作当前一个
   ithi:
mov PCdataNo,#00H ;时间足够,已是下一个了重新收数吧
   exitchk4546:
   ret


;将串口的数据变量化!希望以后的通用化
;用50 ~59 放置PC发回来的6(8)个数字要对数字测试防止错误数据回来
;PCdatasit       equ 5AH          ;数据放置开始位的前一位如开始放在50H由此数为4FH
;PCallNo         equ 5BH ;按协议该PC应收回的数据的个数
;PCdataNo equ 5CH ;记录PC收回来的顺序数,
;====================================================
;为什么一个周期只中断一次?
comreti:
clr  ES   ;不允许串行中断

jnb  ri,exitcom1 ;ri=1表示为接收中断
;产生接收中断
push acc
push psw
       mov  4FH,r0 ;因为其它中断会用到R0,怕出错,先送出
       push 4FH
;以时间来衡量是否下一个开始,如果是则将记录指针回0
;lcall chk4546 ;检查否一段时间内的开始数据,如果是,已将指针回到PCdataNo 00

;防止如接口问题不断有数回来的情况一旦FF以后,不再理会
mov  A,PCdataNo ;中断回来的次数有关!
clr c
add A,#1
jc  sriexit ;超过FFH,不处理

;记录每个周期收数的次数并判定是否大于指定的数量
inc  PCdataNo ;用于记录第几次收到数!
mov  A,PCallNo ;应该回来的总数
cpl  A     ;求反即#FFH-PCallNo
CLR  C
ADD  A, PCdataNo   ;有没有可能 不断发来
JC   sriexit ;超过PCallNo个就不再处理直接退出

;即收到的6个数据按顺序放在50H~55H中,
mov  a, PCdatasit ;指定的放置数据的初始位置
       add  a, PCdataNo             ;开始地址+1也是新的放置地址,前面有了加1操作
       mov  r0,a ;将新的地址装入R0用于新的寻址方式
       mov  @r0,sbuf           ;放入相对的地址中
       mov A,PCdataNo ;准备对比已收到的数量
cjne A,PCallNo,sriexit ;查是否收到了所有的指定数量的数据
;cjne A,#01H,sriexit ;查是否收到了所有的指定数量的数据

;已是6位数接着检查数据是不是合理,不管是否合理也会发送数,只是不全时发的数不一样
lcall chkPCdata ;检查数据是否合理并发送
       mov PCdataNo,#00H ;因为关了中断,不会再有中断了,不用担心有干扰!
   sriexit: ;其它的收数不理会!并清空标收数标志
       mov NextTime,FirsTime ;用46H记录上次的接收时间
pop  4FH
       mov  r0,4FH
pop  psw
pop  acc
   exitcom1:
lcall chkNoFromPC               ;查到底收了几个数
clr ri
SETB   ES   ;允许串断
   reti


;**************************************************
chkNoFromPC: ;此为测试程序,用于测试,到底接收了多少个数据
mov A,PCdataNo
cjne A,#01H,PC1
cpl P0.1
ajmp exitCHKNoFromPC
   Pc1:
cjne A,#02H,PC2
cpl P0.2
ajmp exitCHKNoFromPC
   Pc2:
cjne A,#03H,PC3
cpl P0.3
ajmp exitCHKNoFromPC
   Pc3:
cjne A,#04H,PC4
cpl P0.4
ajmp exitCHKNoFromPC
   Pc4:
cjne A,#05H,PC5
cpl P0.5
ajmp exitCHKNoFromPC
   Pc5:
cjne A,#06H,PC6
cpl P0.6
ajmp exitCHKNoFromPC
   Pc6:
       cpl P0.0
   exitCHKNoFromPC :
   ret

;================================================
chkPCdata: ;检查PC发来的数据放在50H~5AH间50H为指针
;pc会发来6位数,最前数据号,四位为数据,最后一个为异或验证码
;要在发送数据之后回传
;51A必须是51H作为命令前导
;第一位数据,01表示手动降温,
;02表示重设保温时间,按保温执行后面三位是新的保温时间
;没有数据来根本没有不会触发!

mov A,PCdataNo ;前面已检查过回来的数字,但为了程序的严谨性加入
cjne A,#00H,PCSENDED ;不为0表示PC有数据发送过来
mov PCanswer,#00H ;在发回PC的数据中记录
Ajmp errfromPC ;没有数据来也要发回去

;在中断里产生会对各个R有影响,所以不用!除中断时用POP了的R0

   PCSENDED:
mov A,PCdatasit
add a,#01H
mov R0,A
mov A,@R0 ;第一个前导数
cjne A,#51H,errfromPC           ;第一个数不是前导数51H的为错误的数据
;对四个数据进行异或操作XRL A,direct  按位‘异或',结果送入A 中

mov A,PCdatasit
add a,#02H
mov R0,A
mov A,@R0 ;第一个真正的数据
mov PCdataXRL,A

mov A,PCdatasit
add a,#03H
mov R0,A
mov A,@R0 ;第二个真正的数据
XRL PCdataXRL,A

mov A,PCdatasit
add a,#04H
mov R0,A
mov A,@R0 ;第三个真正的数据
XRL PCdataXRL,A

mov A,PCdatasit
add a,#05H
mov R0,A
mov A,@R0 ;第四个真正的数据
XRL PCdataXRL,A

mov A,PCdatasit
add a,#06H
mov R0,A
mov A,@R0 ;第PC发来的校验码


cjne A,PCdataXRL,errfromPC ;异或验证不成功
;已收到合格的数据
mov A,PCdatasit
add a,#02H
mov R0,A
mov A,@R0 ;第一个真正的数据

cjne a,#01H,notCHKControl ;要求测量是否有控制的要求

mov A,MyControl ;将我的控制位回到A中
cjne A,#00H ,notcontrol                 ;脚为低电平
;低电平,为闭合,要求不要切割
;发送00回去PC

mov templ,#00H
ajmp exitchkpc
  notcontrol:
;高电平,可以切割了
;发送01回PC
mov templ,#01H
ajmp exitchkpc

  notCHKControl:
mov A,@R0 ;第一个真正的数据
cjne a,#02H,errfromPC ;要求打开开关
;打开callsheet ;300MS按下
lcall callmysheet
;发送02回PC
mov templ,#02H
ajmp exitchkpc
   errfromPC:
mov templ,#04H
;发送04回PC

   exitchkpc:
lcall sendTempToPc ;;只要收到数就应向PC发回,不论对与否
   ret
;================================================
send1bit: ;单个发送数据回PC机
clr ti
MOV SBUF,A

;如何加入时间?防止进入死循环
mov r6,#05H ;这里约为0.3S
  sendloop33:
MOV R5,#0ffH
  sendLOOP23:
MOV R4,#0ffH
  sendLOOP13:
jb ti ,exitsendtemp3 ;0.5S内完成的都算完成
DJNZ R4,sendLOOP13 ;两周期
DJNZ R5,sendLOOP23
Djnz r6,sendloop33

  exitsendtemp3:
clr ti

; 每个字间隔点点时间
MOV R4,#10
DJNZ R4,$
   ret


;利用 正常 串口1将37H(tempL),38H(tempH) 39H 发送到PC
sendTempToPc:
;测试是否进入了此处,并将相关的数据发送到PC机中用于检测
cpl P0.7
mov A,firstime
lcall send1bit

mov A,nexttime
lcall send1bit

mov A,tempL
lcall send1bit
ajmp exitsendtempret    ;退出

;后面的发送为正常程序时用到
mov PCanswer,#00H
mov tempH,#00H
;只用了templ作回答地址
       mov templ  ,45H
       mov temph,46H
       mov pcanswer ,52H

mov A,TempL
XRL A,TempH
XRL A,PCanswer
mov PCdataXRL,A ;将发送数据的异或结果送到3ah用于PC机验证

mov r0,#37H ;从37H开始发送这个没有办法的用变量?
mov r3,#4
clr ti
   myrese:
mov A, @R0 ;将R0地址中的数转到A
MOV SBUF,A

;如何加入时间?防止进入死循环
mov r6,#05H ;这里约为0.3S
  sendloop3:
MOV R5,#0ffH
  sendLOOP2:
MOV R4,#0ffH
  sendLOOP1:
jb ti ,exitsendtemp ;0.5S内完成的都算完成
DJNZ R4,sendLOOP1 ;两周期
DJNZ R5,sendLOOP2
Djnz r6,sendloop3

  exitsendtemp:
clr ti

; 每个字间隔点点时间
MOV R4,#250
DJNZ R4,$

inc r0
djnz r3,myrese
  exitsendtempret:
  ret
;============================
;****************************************************



;====================================================
; 延时子程序同样用到R456延时太长没必要!可以
;====================================================
usbDELAY: ;为了方便这个用在外面 12c5a60S2太快,约高了3倍?只是0.3S
;mov R6,#5 ;(((3*255+3)+2)*255+2)*5/1000000=0.98176S
   usbloop3: MOV R5,#0ffH
   usbLOOP2: MOV R4,#0ffH
   usbLOOP1: NOP ;一个周期
DJNZ R4,usbLOOP1 ;两周期
DJNZ R5,usbLOOP2
djnz r6,usbloop3
   RET
;****************************************************

callmysheet:
setb callsheet ;高电平
;setb P0.3

;clr  P0.3 ;亮个灯看看?
clr callsheet ;低电平有效

mov R6,#05H
lcall usbdelay ;延时0.3S后高电平
setb callsheet ;高电平
;setb P0.3
  ret


 END


3641
yueliang150
文章数:389
年度积分:50
历史总积分:3641
注册时间:2003/4/24
发站内信
发表于:2012/2/24 10:53:35
#1楼
呵呵,那么长的程序谁有时间看呢;
呵呵,那么长的程序谁有时间看呢;

还是用C语言控制吧
附件:
[本地下载]
单片机、ARM产品开发设计;
小设备、夹具、治具控制器设计开发;数码管、点阵LED电子看板开发;
1000
sunsoncheng
文章数:109
年度积分:50
历史总积分:1000
注册时间:2010/5/25
发站内信
发表于:2012/2/25 22:59:09
#2楼
$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$
;此为STC自己的代码,初始化波特率发生器
;请用实际行动支持宏晶STC大陆本土MCU统一全球市场差0.16%
UARTINIT: ;9600bps@12MHz
ANL PCON,#7FH ;波特率不倍速
MOV SCON,#50H ;8位数据,可变波特率
ORL AUXR,#40H ;定时器1时钟为Fosc,即1T
ANL AUXR,#0FEH ;串口1选择定时器1为波特率发生器
ANL TMOD,#0FH ;清除定时器1模式位
ORL TMOD,#20H ;设定定时器1为8位自动重装方式
MOV TL1,#0D9H ;设定定时初值
MOV TH1,#0D9H ;设定定时器重装值
CLR ET1 ;禁止定时器1中断
SETB TR1 ;启动定时器1
setb ES ;允许串行中断
RET

这个是STC的波特率计算器计出的结果,只是这种结果是错的

所在才会有这样的问题,
1058
zhgkwfxs
文章数:160
年度积分:50
历史总积分:1058
注册时间:2010/7/13
发站内信
发表于:2012/2/26 18:11:33
#3楼
学c吧

关于我们 | 联系我们 | 广告服务 | 本站动态 | 友情链接 | 法律声明 | 非法和不良信息举报

工控网客服热线:0755-86369299
版权所有 工控网 Copyright©2024 Gkong.com, All Rights Reserved

78.0005