基于STC98C52RD+的51MCU学习流水账--->串口通讯学习(汇编版)

 开篇语:

1-收集-->整理-->消化-->分享,收集多年,开始迈出分享这步。

2-从点灯-->到数码管-->撸到串口,目前卡在串口。无法实现基本串口通讯。

为了便于后期解决问题后,能回头复盘过程,特此开始记录后期一切解决过程

(自用的同时各位过客如可参考一二,甚是开心。如有不当之处亦可提出指正,不胜感激!)

先上图

问题:PC发送45H,串口助手接收到的确是 BAH(图中2个BA,是因为我按了两次“发送数据”)

首先:对源代码进行注释(汇编)

        ;初始化
        ORG   0000H      ;上电&复位入口地址0000H             
        LJMP  MAIN       ;从0000H跳到标号MAIN处,进行主程序任务    
        ORG   0023H      ;串行口中断入口地址      
        LJMP  UART_INT   ;从0023H跳到标号UART_INT处,进行串行口中断任务
        ORG   0100H      ;下列程序从入口地址0100H开始 
        
        ;主程序
MAIN:   
        MOV  SP,#70H     ;堆栈指针SP指向的栈底地址        
        MOV  IE,#90H     ;#90H=#10010000B,EA=1(开总中断),ES=1(开串口中断),        
        MOV  TMOD,#20H   ;#20H=#00100000B,高四位,GATE=0(软件控制TR1启动定时或计数),
                         ;C/T=0(定时方式), M1M0=10(模式2),           
        MOV  TH1,#0FDH   ;载入TH初值(怎么算)           
	    MOV  TL1,#0FDH   ;载入TL初值(怎么算)         
        MOV  PCON,#00H   ;#00H=#00000000B,SMOD=0(不增倍)          
	    MOV  SCON,#50H   ;#50H=#01010000B,SM0SM1=01(方式1,10位UART,8位数据,波特率可变),
                         ;REN=1(允许接受)         
	    SETB TR1         ;TR1=1,开定时器
	    SETB ES          ;ES=1,开串口中断
	    SETB EA          ;EA=1,开总中断
	    SJMP $           ;动态待机(循环跳转此行)

        ;串口中断程序
UART_INT: 
         JNB   RI,SENT   ;RI=0?是(没接收完一帧数据),跳到标号SENT处,
                         ;RI=0? 不是(即RI=1,接受完一帧数据),往下执行
                         ;通知CPU从SBUF取走接收到的数据

         MOV   A,SBUF    ;SBUF接收到数据,先放入A
		 XRL   A,#0FFH   ;与FFH异或后的值,存A(不明白为啥这么做)
		 MOV   SBUF,A    ;A的值,再送到SBUF等待输出
		 CLR   RI        ;RI清0(简单理解:RI接受中断使能)
    SENT:       
         CLR   TI        ;TI清0 (简单理解:TI发送中断使能)  
         RETI            ;返回主程序

         END             ;程序到此结束

然后,分段分析
        第一段: 初始化,没啥纰漏。

       ORG   0000H                      ;上电&复位入口地址0000H             
        LJMP  MAIN                       ;从0000H跳到标号MAIN处,进行主程序任务    
        ORG   0023H                      ;串行口中断入口地址      
        LJMP  UART_INT               ;从0023H跳到标号UART_INT处,进行串行口中断任务
        ORG   0100H                      ;下列程序从入口地址0100H开始 

 第二段:设置各个寄存器,看完也没啥纰漏。

MAIN:   
        MOV  SP,#70H       

;设置堆栈指针SP指向的栈底地址;【串口通信也是中断的一种,中断必须保护现场】

因为8051单片机在复位后,堆栈的底部就在07H,使得堆栈实际上是从08H开始的。但我们从RAM的结构分布中可知,08H—1FH隶属1—3工作寄存器区,若编程时需要用到这些数据单元,必须对堆栈指针SP进行初始化,原则上设在任何一个区域均可,但一般设在30H—7FH之间较为适宜。如图

 那现在设在70H ,则实际可用堆栈会再70H-7FH范围,用来暂存数据,保护现场。

(任何程序在运行过程中都需要使用堆栈,堆栈就是维护当前线程中运行状态的一个数据结构,这种状态包括:需要传递的变量,函数的返回地址,局部变量等等)

        MOV  IE,#90H    
        
;#90H =  #10010000B
        EA=1(总中断允许),ES=1(串口中断允许) 
      
         MOV  TMOD,#20H    
        ;#20H=#00100000B
        ;使用高四位,即定时器1,GATE=0(软件控制TR1启动定时或计数),
        ;C/T=0(定时方式), M1M0=10(模式2)

        ;如下图,模式2:是 8位自动重置定时器/计数器       

        MOV  TH1,#0FDH   ;载入TH初值           
        MOV  TL1,#0FDH   ;载入TL初值    

【 怎么计算?】
 定时时间 =(2的8次-初值)X 12/晶振频率

  
        MOV  PCON,#00H  
        ;#00H=#00000000B,SM0D=0,不增倍。
        ;8051的PCON只看SMOD是1,还是0;SMOD=0(不增倍) ;SMOD=1(增倍) ;   

     
        MOV  SCON,#50H  
        ;#50H=#01010000B
        ;SM0SM1=01(方式1,10位UART,8位数据,波特率可变)
        有些资料写着8位UART,有些资料写着10位UART,8位数据

     方式一波特率=(2^SMOD/32)*(T1溢出率)
其中
1-当SMOD=0,波特率正常;当SMOD=1,波特率加倍。

2-T1溢出率就是 T1定时器溢出的频率。
(只要算出T1定时器每溢出一次所需的时间T,就可以算出溢出率1/T.单位为Hz)

        T1定时器使用工作方式2(TMOD=0X20),即8位初值自动重装的定时器。

其工作过程是,在TLX和THX中装好相同的初值,在时钟的作用下TLX加一计数,当TLX加满溢出后,CPU会自动将THX的值装入TLX中......如此循环。

每计一个数的时间为一个机器周期,一个机器周期为12个时钟周期。
如采用11.0592MHz的晶振,机器周期为  12*( 1/11.0592MHz )(s)
那么定时器溢出一次的时间为(256-X)*12/11.0592MHz(s),其中X为装入的初值。

取倒数即为 T1的溢出率。

如要设为波特率为9600,此处SMOD取0,则9600=( 1/32 )*11059200/ [ ( 256-X )*12 ]
解得X=253,即十六进制的0xFD.

        ;REN=1(允许接受)  
        ;REN为允许接收位。相当于串行接受的开关,由软件置位或清零;
        ;在串行通信过程中,如果满足REN=1,且RI=1,则启动一次接受过程,一帧数据就装入接收缓冲器SBUF中。        

接下来:开启各个寄存器
        SETB TR1                 ;TR1=1,开定时器
        SETB ES                   ;ES=1,开串口中断
        SETB EA                   ;EA=1,开总中断
        SJMP $                      ;动态待机(循环跳转此行)  

 第三段:串口中断,数据传输。

 UART_INT: 
         JNB   RI,SENT   

        ;JNB,直接寻址,为0转移  
        ;RI=0?是(没接收完一帧数据),跳到标号SENT处,
        ;RI=0? 不是(即RI=1,接受完一帧数据),往下执行
        ;由前面SCON,#50H  可知,SM0SM1=01,为方式二
        
;当RI接收到停止位时,RI由硬件置1,表示接收结束。【可供软件查询或请求中断】
        ;往下执行是:通知CPU从SBUF取走接收到的数据

         MOV   A,SBUF    
        ;SBUF接收到数据,先放到A


         XRL   A,#0FFH  
        ;A里的数据与0FFH,进行异或后再存入A.   
        ;XRL:逻辑异或指令,即相对应的二进制位不同该位异或后的结果是1,相同则为0
        ;如:
发送01000101B(45H), XRL 11111111B(FFH)=1011 1010B ( BAH )


         MOV   SBUF,A  
         ;A的值,再送到SBUF等待输出
        ;接上,这个时候,在异或后,A里的值是BAH,送到SBUF


         CLR   RI        
        ;RI清0(简单理解:RI接受中断使能)
        ;中断后,RI清0,表示准备下一次接收数据


    SENT:       
         CLR   TI      
         ;TI清0 (简单理解:TI发送中断使能)
         ;TI是发送中断标志,TI=1,表示发送完成,TI=0,表示准备下一次发送数据
         ;根据前面,JNB   RI,K1 ,RI≠0,即接收没结束,转到这里,使TI=0,继续发送、
         RETI            ;返回主程序

         END             ;程序到此结束

捋完之后,发现:XRL A,#0FFH; 这句话 使得A里的数据,从45H,变成了BAH
所以,把这句话屏蔽后,在通过串口助手测试,发现,接收正常


 以上,第一段串口程序,测试完毕。

 

  • 24
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

属鼠的金牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值