EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
单片机的通信一般有并行通信和串行通信。并行通讯是数据的各位同时发送或接收,并行通信控制简单,传输速度快,传输线较多。0 i- n* c% e$ u7 G x' a
参看下图: ' t3 U9 B. D- R1 l1 r+ ]) r
, u9 A: c- Y: u* W! K, r5 h
串行通讯传输线少,可利用电话网,但传送控制复杂。数据一位一位顺序发送或接收。 0 Y: M' ~! @' H
0 `+ M# |6 \2 Q- Q( k
串行通讯中有一种是异步通信,即我们通常所说的串口通信。这是我们今天要分享的内容: 异步通讯用一个起始位表示字符的开始,用停止位表示字符的结束。其每帧的格式如下:在一帧格式中,先是一个起始位0,然后是8个数据位,规定低位在前,高位在后,接下来是奇偶校验位(可以省略),最后是停止位1。用这种格式表示字符,则字符可以一个接一个地传送。 - I. S7 U; F9 \1 u; z& p
一、在异步通讯中,CPU与外设之间必须有两项规定,即字符格式和波特率。 1、字符格式的规定是双方能够在对同一种0和1的串理解成同一种意义,即我们所说的通信协议。 2、波特率即数据传送的速率,其定义是每秒钟传送的二进制数的位数。例如,数据传送的速率是120字符/s,而每个字符如上述规定包含10数位,则传送波特率为1200波特。 N2 W. M9 j. L: ~
. @3 O# D; ~' d+ c, X二、通讯方向。 1、在串行通讯中,把通讯接口只能发送或接收的单向传送方法叫单工传送。 2、把数据在甲乙两机之间的双向传递,称之为双工传送。在双工传送方式中又分为半双工传送和全双工传送。半双工传送是两机之间不能同时进行发送和接收,任一时该,只能发或者只能收信息。
: G, M7 X5 ?( r8 Q+ v+ d. r+ C 接下来我们分享下单片机串口的结构和寄存器相关的知识。* _& K2 V9 F! f* P+ P# `
51单片机通过引脚RXD(P3.0,串行数据接收端)和引脚TXD(P3.1,串行数据发送端)与外界通讯。SBUF是串行口缓冲寄存器,包括发送寄存器和接收寄存器。它们有相同名字和地址空间,但不会出现冲突,因为它们两个一个只能被CPU读出数据,一个只能被CPU写入数据。9 n% S8 ]! e) `% T b
$ I3 U8 I$ C3 A* l4 n9 k
, N5 C7 {# [# Q8 j& L; k* J* t
1 B9 n0 n' I+ }
. w1 ?0 a& q3 m: H! ^; \# Z- h2 I3 i. V' L3 x1 m8 S% m
TH1和TL1是装计数初值的计数器,用于产生波特率。TI是发送标志位,RI是接收标志位,具体作用我们会在下面的分享中接触到。 下面我们看看单片机串口相关的寄存器:
, e& H$ C; } x H一、工作方式寄存器SCON 位 D7 D6 D5 D4 D3 D2 D1 D0 功能 SM0 SM1 SM2 REN TB8 RB8 TI RI
+ G1 J% F w1 @) ~7 s1 Q' Y; X8 S1 ^# R
9 m: B6 V1 k6 ^' k) x其中fosc为晶振频率
* S+ X$ }' \' k8 a! a3 b: n4 xSM2:多机通讯控制位。在方式0时,SM2一定要等于0。在方式1中,当(SM2)=1则只有接收到有效停止位时,RI才置1。在方式2或方式3当(SM2)=1且接收到的第九位数据RB8=0时,RI才置1。 REN:接收允许控制位。由软件置位以允许接收,又由软件清0来禁止接收。 TB8:是要发送数据的第9位。 RB8:接收到的数据的第9位。 TI:发送中断标志。在方式0中,第8位发送结束时,由硬件置位。TI置位既表示一帧信息发送结束,同时也是申请中断,可根据需要,用软件查询的方法获得数据已发送完毕的信息,或用中断的方式来发送下一个数据。TI必须用软件清0。 RI:接收中断标志位。在方式0,当接收完第8位数据后,由硬件置位。RI置位表示一帧数据接收完毕,可用查询的方法获知或者用中断的方法获知。RI也必须用软件清0。
6 u7 \5 v' ?% N* W" ?7 u/ a5 V
" q2 ?) Q" B: R波特率的概念: 波特率的定义:串行口每秒钟发送的位数称为波特率。比如说2400的波特率就是每秒钟发送2400个位数。串行口的波特率是用定时器T1作为波特率发生器的,这是定时器自动设置在工作方式2(可自动重装初值)。
% s) f- G9 I1 O% _+ T. k5 V
* `3 K3 l5 b6 H M8 R- C
2 n. _& ?/ v5 u( r7 q: _3 G' Z接下来我们分享下怎样通过编程实现串口通信,串口的操作步骤:
4 g ]0 m8 y) Q; O
/ x% M) e, y: c一、先设置波特率:: X- I9 q# P$ M7 ]6 }7 A
% C2 z" L& T1 \8 x: g; t& t1 s( X; o
设置定时器T1为工作方式2(设置TMOD寄存器)
, k) V/ }0 a q! A! {7 l
) A7 s; z# {* h5 Q* `) y/ q 给计数器赋初值(工作方式2会自动重装)
4 }; L5 T" `" u' N2 C二、设置串口工作方式:
( z( {) d- x" h% E# P! j. T) y4 Q
7 I6 t( ?. Y, R9 D( T& m5 _ 设置SCON
7 {1 l3 }1 m% `9 B+ K' I4 q9 R* q
: P! d7 z( R$ { 如果使用中断方式,那么打开相应的中断和总中断。
* }; L; {: X; {4 x4 E" H三、打开定时器T1,开始产生波特率。
/ }# s/ w+ E/ c+ `9 y四、设置TRx1 ~2 T# S8 N! d, E d
. x/ }9 q* A1 b: C' v
下面我们看个例程:2 f# P9 e; Z. X$ r8 v; l
- #include <reg52.h>
- //FOSC=11.0592MHz,12T模式,SMOD=0
- #define 1200bps 0xe8
- //1200波特率计数初值宏定义
- #define 2400bps 0xf4
- //2400波特率计数初值宏定义
- #define 4800bps 0xfa
- //4800波特率计数初值宏定义
- #define 9600bps 0xfd
- //9600波特率计数初值宏定义
- unsigned char zifu='a';
- //待显示字符。
- sbit SWITCH_S7 = P3^4;
- void delay(int In,int Out)
- {
- int i,j;
- for(i=0;i<In;i++)
- {
- for(j=0;j<Out;j++)
- {;}
- }
- void serial_port_initial(char TH,char TL)
- //串口初始化函数
- {
- SCON = SCON | 0x50;
- //8位可变波特率,无奇偶校验位
- TMOD = TMOD | 0x20;
- //设置定时器1为8位自动重装记数器
- PCON = PCON | 0x00;
- TH1 = TH;
- //设置定时器1自动重装数
- TL1 = TL;
- //设置定时器1自动重装数
- ES = 1;
- //允许串口中断 EA = 1;
- //开总中断 TR1 = 1;
- //开定时器1
- }
- void send_UART(unsigned char i)
- //发送一节函数
- {
- ES = 0;
- //关串口中断
- TI = 0;
- //清零串口发送完成中断请求标志
- SBUF = i;
- //发送数据
- while(TI==0);
- //等特数据传送
- TI = 0;
- //清除数据传送标志
- ES = 1;
- }
- void main()
- {
- serial_port_initial(1200bps,1200bps);
- while(1)
- {
- if(SWITCH_S7 == 0)
- //判断按键是否按下
- {
- delay(5,200);
- if(SWITCH_S7 == 0)
- //消抖
- {
- while(SWITCH_S7 == 0);
- //等待按键松开
- send_UART(zifu);
- //发送字符a
- }
- }
- }
- }
5 F- m3 A9 ^2 A! D: d6 [ ) Q: {; L u% E$ b* C9 B) i+ P/ }6 k3 f
+ j! X' A2 `2 v; G+ j5 s, [( H8 t4 O) }4 M3 l% X0 d) W+ ^
|