?开篇语:
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 所以,把这句话屏蔽后,在通过串口助手测试,发现,接收正常
?以上,第一段串口程序,测试完毕。
?
|