为您推荐:
精华内容
最热下载
问答
  • 5星
    2KB GJZGRB 2021-02-19 15:22:54
  • 5星
    108.34MB guoruibin123 2021-04-27 06:03:44
  • 5星
    6.75MB qq_41934573 2021-05-14 23:24:44
  • 30KB weixin_38651812 2020-08-20 06:16:42
  • 30KB weixin_38723236 2020-10-20 02:53:20
  • 89KB weixin_38631599 2020-07-14 03:42:17
  • 223KB weixin_38499336 2020-07-13 12:33:31
  • 方式0是外接串行移位寄存器...每当发送接收完一个字节,硬件置TI=1或RI=1,申请中断,但必须用软件清除中断标志。实际应用在串行I/O与并行I/O之间的转换。2)方式1方式1是点对点的通信方式。8位异步串行通信...

    方式0是外接串行移位寄存器方式。工作时,数据从RXD串行地输入/输出,TXD输出移位脉冲,使外部的移位寄存器移位。波特率固定为fosc/12(即,TXD每机器周期输出一个同位脉冲时,RXD接收或发送一位数据)。每当发送或接收完一个字节,硬件置TI=1或RI=1,申请中断,但必须用软件清除中断标志。

    实际应用在串行I/O口与并行I/O口之间的转换。

    2)方式1

    方式1是点对点的通信方式。8位异步串行通信口,TXD为发送端,RXD为接收端。一帧为10位,1位起始位、8位数据位(先低后高)、1位停止位。波特率由T1或T2的溢出率确定。

    在发送或接收到一帧数据后,硬件置TI=1或RI=1,向CPU申请中断;但必须用软件清除中断标志,否则,下一帧数据无法发送或接收。

    1f5f3d71343cc36382425a987cedd5f6.png

    (1)发送:CPU执行一条写SBUF指令,启动了串行口发送,同时将1写入输出移位寄存器的第9位。发送起始位后,在每个移位脉冲的作用下,输出移位寄存器右移一位,左边移入0,在数据最高位移到输出位时,原写入的第9位1的左边全是0,检测电路检测到这一条件后,使控制电路作最后一次移位,/SEND和DATA无效,发送停止位,一帧结束,置TI=1。

    (2)接收:REN=1后,允许接收。接收器以所选波特率的16倍速率采样RXD端电平,当检测到一个负跳变时,启动接收器,同时把1FFH写入输入移位寄存器(9位)。由于接、发双方时钟频率有少许误差,为此接收控制器把一位传送时间16等分采样RXD,以其中7、8、9三次采样中至少2次相同的值为接收值。接收位从移位寄存器右边进入,1左移出,当最左边是起始位0时,说明已接收8位数据,再作最后一次移位,接收停止位。此后:

    A、若RI=0、SM2=0,则8位数据装入SBUF,停止位入RB8,置RI=1。

    B、 若RI=0、SM2=1,则只有停止位为1时,才有上述结果。

    C、若RI=0、SM2=1,且停止位为0,则所接数据丢失。

    D、若RI=1,则所接收数据丢失。

    无论出现那种情况,检测器都重新检测RXD的负跳变,以便接收下一帧。

    3)方式2、方式3

    方式2和方式3是9位异步串行通信,一般用在多机通信系统中或奇偶校验的通信过程。在通讯中,TB8和RB8位作为数据的第9位,位SM2也起作用。方式2与方式3的区别只是波特率的设置方式不同。

    (1)发送

    向SBUF写入一个数据就启动串口发送,同时将TB8写入输出移位寄存器第9位。开始时,SEND和DATA都是低电平,把起始位输出到TXD。DATA为高,第一次移位时,将‘1’移入输出移位寄存器的第9位,以后每次移位,左边移入‘0’,当TB8移到输出位时,其左边是一个‘1’和全‘0’。检测到此条件,再进行最后一次移位,/SEND=1,DATA=0,输出停止位,置TI=1。

    (2)接收

    置REN=1,与方式1类似,接收器以波特率的16倍速率采样RXD端。

    起始位0移到输入寄存器的最左边时,进行最后一次移位。在RI=0,SM2=0或接收到的第9位=1时,收到的一字节数据装入SBUF,第9位进入RB8,置RI=1;然后又开始检测RXD端负跳变。

    3、 多机通信

    在这里,多机系统是指‘一主多从’。51系列单片机中,利用第9位TB8/RB8来区分地址与数据信息,用位SM2确定接收方是否对地址或数据帧敏感。其原则是:

    1)发送方用第9位TB8=1标志地址帧,TB8=0标志数据帧。

    2)接收方若设置SM2=1,则只能接收到地址信息,若设SM2=0,则不管是地址还是数据帧,都能接收到。

    利用方式2、3的特点,在点对点的通讯中,在发送方可以用第9位TB8作为奇偶校验位。在接收方,SM2位必须清0。

    4、波特率

    1)方式0的波特率=fosc/12

    2)方式2的波特率=2^smod*fosc/64

    3)方式1、3的波特率由T1或T2的溢出率和SMOD位确定:

    (1)用T1:波特率=2^smod*T1定时器的溢出率/32,T1为方式2T1定时器溢出率=1/((12/fosc)*(256-X))例:已知fosc=6MHz,SMOD=0,设置波特率为2400,求T1的计数初值X。

    波特率=1/((12/fosc)*(256-X))/32=fosc/12*32(256-X)(256-X)=fosc/2400/384=6M/2400/384;256-X~=6.5104X~=250=FAH 只能近似计算。

    若fosc=11.0592MHz, 则256-X=11.0592M/2400/384=4068/384=12 X=F4H;可精确算出,对其它常用的标准波特率也是能正确算出。所以这个晶振频率是最常用的。

    如果SMOD=1,则同样的X初值得出的波特率加倍。

    (3)用T2:

    在52型单片机中,串口方式1、3的波特率发生器选择由TCLK、RCLK位确定是T1还是T2。若TCLK=1,则发送器波特率来自T2,否则来自T1。若RCLK=1,则接收器波特率来自T2,否则来自T1。

    由T2产生的波特率与SMOD无关。T2定时的最小单元=2/fosc。T2的溢出脉冲16分频后作为串口的发送或接收脉冲。

    波特率=(1/((2/fosc)(65536-X)))/16=fosc/(32(65536-X))例:已知fosc=11.0592MHz,求波特率=2400时的X2400=11059200/(32(65536-X)) 65536-X=144 X=65392=FF70H计数器初值寄存器:RCAP2H=0FFH,RCAP2L=70H。

    展开全文
    weixin_39943383 2020-10-19 19:03:19
  • 139KB weixin_38719643 2021-01-19 18:18:35
  • 本文主要给出一个实用的java 串口通信程序,供大家讨论学习./******************************************* 程序文件名称:SendComm.java* 功能:从串行口COM1发送数据****************************************...

    本文主要给出一个实用的java 串口通信程序,供大家讨论学习.

    /******************************************

    * 程序文件名称:SendComm.java

    * 功能:从串行口COM1中发送数据

    ******************************************/

    import java.awt.*;

    import java.awt.event.*;

    import java.io.*;

    import java.util.*;

    import javax.comm.*;

    class S_Frame extends Frame implements Runnable,ActionListener

    {

    /*检测系统中可用的通讯端口类 */

    static CommPortIdentifier portId;

    /*Enumeration 为枚举型类,在util中 */

    static Enumeration portList;

    OutputStream outputStream;

    /*RS-232的串行口 */

    SerialPort serialPort;

    Thread readThread;

    Panel p=new Panel();

    TextField in_message=new TextField("打开COM1,波特率9600,数据位8,停止位1.");

    TextArea out_message=new TextArea();

    Button btnOpen=new Button("打开串口, 发送数据");

    Button btnClose=new Button("关闭串口, 停止发送数据");

    byte data[]=new byte[10240];

    /*设置判断要是否关闭串口的标志*/

    boolean mark;

    /*安排窗体*/

    S_Frame()

    { super("串口发送数据");

    setSize(200,200);

    setVisible(true);

    add(out_message,"Center");

    add(p,"North");

    p.add(btnOpen);

    p.add(btnClose);

    add(in_message,"South");

    btnOpen.addActionListener(this);

    btnClose.addActionListener(this);

    } //R_Frame() end

    /*点击按扭打开串口.*/

    public void actionPerformed(ActionEvent event) {

    if (event.getSource()==btnClose){

    serialPort.close(); //关闭串口

    mark=true; //用于中止线程的run()方法

    in_message.setText("串口COM1已经关闭,停止发送数据.");

    }

    else { mark=false;

    /*从文本区按字节读取数据*/

    data=out_message.getText().getBytes();

    /*打开串口*/

    start();

    in_message.setText("串口COM1已经打开,正在每2秒钟发送一次数据.....");

    }

    } //actionPerformed() end

    /*打开串口,并调用线程发送数据*/

    public void start(){

    /*获取系统中所有的通讯端口 */

    portList=CommPortIdentifier.getPortIdentifiers();

    /* 用循环结构找出串口 */

    while (portList.hasMoreElements()){

    /*强制转换为通讯端口类型*/

    portId=(CommPortIdentifier)portList.nextElement();

    if(portId.getPortType() == CommPortIdentifier.PORT_SERIAL){

    if (portId.getName().equals("COM1")) {

    /*打开串口 */

    try {

    serialPort = (SerialPort) portId.open("ReadComm", 2000);

    }

    catch (PortInUseException e) { }

    /*设置串口输出流*/

    try {

    outputStream = serialPort.getOutputStream();

    }

    catch (IOException e) {}

    } //if end

    } //if end

    } //while end

    /*调用线程发送数据*/

    try{

    readThread = new Thread(this);

    //线程负责每发送一次数据,休眠2秒钟

    readThread.start();

    }

    catch (Exception e) { }

    } //start() end

    /*发送数据,休眠2秒钟后重发*/

    public void run() {

    /*设置串口通讯参数*/

    try {

    serialPort.setSerialPortParams(9600,

    SerialPort.DATABITS_8,

    SerialPort.STOPBITS_1,

    SerialPort.PARITY_NONE);

    }

    catch (UnsupportedCommOperationException e) { }

    /*发送数据流(将数组data[]中的数据发送出去)*/

    try {

    outputStream.write(data);

    }

    catch (IOException e) { }

    /*发送数据后休眠2秒钟,然后再重发*/

    try { Thread.sleep(2000);

    if (mark)

    {return; //结束run方法,导致线程死亡

    }

    start();

    }

    catch (InterruptedException e) { }

    } //run() end

    } //类S_Frame end

    public class SendComm

    {public static void main(String args[])

    { S_Frame S_win=new S_Frame();

    S_win.addWindowListener(new WindowAdapter()

    {public void windowClosing(WindowEvent e)

    {System.exit(0); }

    });

    S_win.pack();

    }

    }

    /******************************************

    * 程序文件名称:ReadComm.java

    * 功能:从串行口COM1中接收数据

    ******************************************/

    import java.awt.*;

    import java.awt.event.*;

    import java.io.*;

    import java.util.*;

    import javax.comm.*;

    class R_Frame extends Frame implements Runnable,ActionListener,SerialPortEventListener

    {

    /* 检测系统中可用的通讯端口类 */

    static CommPortIdentifier portId;

    /* Enumeration 为枚举型类,在java.util中 */

    static Enumeration portList;

    InputStream inputStream;

    /* 声明RS-232串行端口的成员变量 */

    SerialPort serialPort;

    Thread readThread;

    String str="";

    TextField out_message=new TextField("上面文本框显示接收到的数据");

    TextArea in_message=new TextArea();

    Button btnOpen=new Button("打开串口");

    /*建立窗体*/

    R_Frame()

    {

    super("串口接收数据");

    setSize(200,200);

    setVisible(true);

    btnOpen.addActionListener(this);

    add(out_message,"South");

    add(in_message,"Center");

    add(btnOpen,"North");

    } //R_Frame() end

    /*点击按扭所触发的事件:打开串口,并监听串口. */

    public void actionPerformed(ActionEvent event)

    {

    /*获取系统中所有的通讯端口 */

    portList=CommPortIdentifier.getPortIdentifiers();

    /* 用循环结构找出串口 */

    while (portList.hasMoreElements()){

    /*强制转换为通讯端口类型*/

    portId=(CommPortIdentifier)portList.nextElement();

    if(portId.getPortType() == CommPortIdentifier.PORT_SERIAL){

    if (portId.getName().equals("COM1")) {

    try {

    serialPort = (SerialPort) portId.open("ReadComm", 2000);

    out_message.setText("已打开端口COM1 ,正在接收数据..... ");

    }

    catch (PortInUseException e) { }

    /*设置串口监听器*/

    try {

    serialPort.addEventListener(this);

    }

    catch (TooManyListenersException e) { }

    /* 侦听到串口有数据,触发串口事件*/

    serialPort.notifyOnDataAvailable(true);

    } //if end

    } //if end

    } //while end

    readThread = new Thread(this);

    readThread.start(); //线程负责每接收一次数据休眠20秒钟

    } //actionPerformed() end

    /*接收数据后休眠20秒钟*/

    public void run() {

    try {

    Thread.sleep(20000);

    }

    catch (InterruptedException e) { }

    } //run() end

    /*串口监听器触发的事件,设置串口通讯参数,读取数据并写到文本区中*/

    public void serialEvent(SerialPortEvent event) {

    /*设置串口通讯参数:波特率、数据位、停止位、奇偶校验*/

    try {

    serialPort.setSerialPortParams(9600,

    SerialPort.DATABITS_8,

    SerialPort.STOPBITS_1,

    SerialPort.PARITY_NONE);

    }

    catch (UnsupportedCommOperationException e) {   }

    byte[] readBuffer = new byte[20];

    try {

    inputStream = serialPort.getInputStream();

    }

    catch (IOException e) {}

    try {

    /* 从线路上读取数据流 */

    while (inputStream.available() > 0) {

    int numBytes = inputStream.read(readBuffer);

    } //while end

    str=new String(readBuffer);

    /*接收到的数据存放到文本区中*/

    in_message.append(str+"/n");

    }

    catch (IOException e) { }

    } //serialEvent() end

    } //类R_Frame end

    public class ReadComm

    {

    public static void main(String args[])

    {

    /* 实例化接收串口数据的窗体类 */

    R_Frame R_win=new R_Frame();

    /* 定义窗体适配器的关闭按钮功能 */

    R_win.addWindowListener(new WindowAdapter()

    {public void windowClosing(WindowEvent e)

    {System.exit(0); }

    });

    R_win.pack();

    }

    }

    展开全文
    weixin_39603492 2021-02-12 23:05:21
  • 3KB qq_42379698 2020-12-21 21:03:04
  • 185KB weixin_38659622 2021-02-03 17:44:21
  • 99KB weixin_38676851 2020-08-15 10:51:40
  • 373B u010979134 2013-06-06 16:03:50
  • 串行口通信就被发明出来,下面来了解串行口通信(uart)。 几个概念 为了能更好理解串行口通信,在介绍它之前,先来看看几个概念,补充知识,方便深入明白uart工作原理。 通信方式 通信方式 通信方式有两种,...

    前言

    人类生存于世,少不了沟通。沟通使人类互相认知,传递信息,提升生活品质。但然单片机也需要,不然单单一个机器,无法构成一个系统,发挥更大的力量。只有单片机与外围设备传递信息,互相反馈才会有一个完美的系统。串行口通信就被发明出来,下面来了解串行口通信(uart)。

    几个概念

    为了能更好理解串行口通信,在介绍它之前,先来看看几个概念,补充知识,方便深入明白uart工作原理。

    通信方式

    通信方式通信方式
    通信方式有两种,分别是并行通信串行通信
    并行通信:并行是指多比特数据同时通过并行线进行传送,这样数据传送速度大大提高,但并行传送的线路长度受到限制,因为长度增加,干扰就会增加,数据也就容易出错。
    串行通信:串行通信是指 使用一条数据线,将数据一位一位地依次传输,每一位数据占据一个固定的时间长度。其只需要少数几条线就可以在系统间交换信息,特别适用于计算机与计算机、计算机与外设之间的远距离通信。
    拿汽车通道来说,并行通信就是多车道,多辆车一起行驶,而串行通信就是单车道,只能一辆一辆车通过。

     

    串行通信制式

    串行通信制式串行通信制式
    串行通信制式有单工通信,半双工通信,双工通信三种。
    单工通信:单工通信信道是单向信道,发送端和接收端的身份是固定的,发送端只能发送信息,不能接收信息;接收端只能接收信息,不能发送信息,数据信号仅从一端传送到另一端,即信息流是单方向的。
    半双工通信:半双工数据传输指数据可以在一个信号载体的两个方向上传输,但是不能同时传输。例如,在一个局域网上使用具有半双工传输的技术,一个工作站可以在线上发送数据,然后立即在线上接收数据,这些数据来自数据刚刚传输的方向。像全双工传输一样,半双工包含一个双向线路(线路可以在两个方向上传递数据)。
    双工通信:双工通信是指在同一时刻信息可以进行双向传输,和打电话一样,说的同时也能听,边说边听。这种发射机和接收机分别在两个不同的频率上(两个频率差有一定要求)能同时进行工作的双工机也称为异频双工机。
    三种通信制式很容易理解,对照上图看,单工通信不就是单方面通信,只能发出指令或接收指令。半双工通信就是能接收又能发送,但是不能同时进行。双工就最厉害,可以同时发送和接收指令。

     

    串行通信分类

    串行通信有两种,一位异步串行通信,二为同步串行通信。
    异步串行通信:异步串行通信是指通信双方以一个字符(包括特定附加位)作为数据传输单位且发送方传送字符的间隔时间不一定,具有不规则数据段传送特性的串行数据传输。
    同步串行通信:所谓同步通信是指在约定的通信速率下,发送端和接收端的时钟信号频率和相位始终保持一致(同步),这就保证了通信双方在发送和接收数据时具有完全一致的定时关系。
    两种串行通信不同就只有时间,在发送字符时,异步可以是不同时间间隔发送,但同步只能以固定的时间间隔发送。

    波特率

    波特率:波特率表示每秒钟传送的二进制位数,是衡量数据传送速率的指标,它用单位时间内载波调制状态改变的次数来表示。
    相互通信的甲乙双方必须具有相同的波特率,不然无法成功完成串行通信。

    概述

    52单片机具有一个全双工串行通信口。一个全双工UART(通用异步接收发送器)的串行I/O口,用于实现单片机之间或单片机与微机之间的串行通信;片内振荡器和时钟产生电路,石英晶体和微调电容需要外接。最佳振荡频率为6M—12M。管脚RXD( P3.0),TXD(P3.1)与串口通信有关。波特率可以设置。

    内部结构

    串行口内部结构逻辑图串行口内部结构逻辑图
    串行口通信与三个寄存器有关,分别是:

     

     1. PCON寄存器
     2. SCON寄存器
     3. SBUF特殊功能寄存器
    

    寄存器

    PCON电源管理寄存器

    电源管理寄存器电源管理寄存器
    SMOD:该位与串口通信有关。
    SMOD=0; 串口方式1,2,3时,波特率正常。
    SMOD=1; 串口方式1,2,3时,波特率加倍
    LVDF:低电压检测标志位,同时也是低电压检测中断请求标志位
    GF1,GF0:两个通用工作标志位,用户可以自由使用。
    PD:掉电模式设定位。
    PD=0 单片机处于正常工作状态。
    PD=1 单片机进入掉电(Power Down)模式 ,可由外部中断或硬件复位模式唤醒,进入掉电模式后,外部晶振停振,CPU、定时器、串行口全部停止工作,只有外部中断工作。在该模式下,只有硬件复位和上电能够唤醒单片机。
    IDL:空闲模式设定位。
    IDL=0 单片机处于正常工作状态。
    IDL=1 单片机进入空闲(Idle)模式,除CPU不工作外,其余仍继续工作,在空闲模式下可由任一个中断或硬件复位唤醒。

     

    这个寄存器只有SMOD位与串行口通信有关。系统复位默认为SMOD=0。当为用52单片机的定时器2产生波特率时,波特率不受SMOD影响。用定时器1产生波特率时,不去设置,就默认为0,波特率正常,设置为1时,波特率加倍。

    SCON串行口控制寄存器

    串行口控制寄存器串行口控制寄存器
    SM0,SM1:共同决定串行口工作模式。
    SM2:多机通信控制位。在方式0中,SM2一定要等于0。在方式1中,当SM2为1时则只有接收到有效停止位时,RI才置1。在方式2或3中,当SM2为1且接收到的第9位数据RB8为0时,RI才置1。
    REN:接收允许控制位。由 软件置位以允许接收,又由 软件清零来禁止接收。
    TB8:要发送数据的第9位。在方式2或3中,要发送的第9位数据,根据需要由软件置1或清零软件置1或清零。例如,可约定作为奇偶校验位,或在多机通信中作为区别地址帧或数据帧的标志位。(很少用)
    RB8:接收到的数据的第9位。在方式0中不使用RB8。在方式1中,若SM2为0,RB8为接收到的停止位。在方式2或3中,RB8为到的第9位数据。(很少用)
    TI:发送中断标志。在方式0中,第8位发送结束时,由 硬件置位。在其它方式的发送停止位前,由 硬件置位。TI置位既表示一帧信息发送结束,同时也向CPU申请中断。可根据需要,用软件查询的方法获得数据已发送完毕的信息,或用中断的方式来发送下一个数据。TI必须用 软件清零
    RI:接收中断标志位。在方式0中,当接收完第8位数据后,由 硬件置位。在其它方式中,在接收到停止位的中间时刻由硬件置位(例外情况见对SM2的说明)。RI表示一帧数据接收完毕,可用查询的方法获知或者用中断的方法获知。RI也必须用 软件清零
    串行口工作模式串行口工作模式
    由于52单片机内部有一个硬件模块,让它自动接收数据,接收完了,通知我们一下就可以了,就不需要再手动配置TB8,RB8。只要配置好SCON,内部就自动帮弄好了。

     

    SBUF特殊功能寄存器

    特殊功能寄存器特殊功能寄存器
    SBUF是指串行口中的两个缓冲寄存器,一个是发送寄存器,一个是接收寄存器,在物理结构上是完全独立的,但地址是重叠的。它们都是字节寻址的寄存器,字节地址均为99H。只要在编写程序时,用不同指令即可操作两个寄存器。
    比如,SBUF=A;这个是指将A的数据移入发送寄存器,然后发送寄存器再把数据发送出去。A=SBUF;则是指将接受寄存器中的数据赋值给A。

     

    串行口方式1

    方式1逻辑图方式1逻辑图
    串行口为10位通用异步接口。发送或接收一帧数据信息为10位,包括1位起始位“0”、8位数据位、1位停止位“1”。发送数据:数据从TXD端口输出,当数据写入发送缓冲器SBUF时,就启动发送器发送。发送完一帧数据后,置中断标志TI=1,申请中断,通知CPU可以发送下一个数据了。接收数据:首先使REN=1(允许接收数据),串行口从RXD接收数据,当采样到1至0跳变时,确认是起始位“0”,就开始接收一帧数据,当接收完一帧数据时,置中断标志RI=1,申请中断,通知CPU从SBUF取走接收到的数据 。

     

    计算波特率

    方式1波特率计算方式1波特率计算
    溢出速率即溢出频率,只要算出定时器每溢出一次所需要的时间T,那溢出率就是1/T。计算在没有波特率加倍(SMOD=0)的情况下,波特率为9600bps时怎样赋值计数器。这里说明一下,由于波特率是需要很精确的,不然通信会出错。如果采用定时器工作模式1,采用人工重载,会有较大误差,因为进入中断函数也需要时间,累积时间就会出错。所以这里运用工作模式2,8位自动重装。计数器自动重装不需人工干预,减少误差。
    对照上面公式,波特率不加倍,SMOD=0,工作模式2,那n=8,波特率=9600,就可以算出x=253,十六进制为fd。

     

    编写步骤

    1. 设置串行口方式
    2. 设置定时器工作模式
    3. 计数器寄存器赋值
    4. 中断寄存器控制
    5. 启动定时器中断
    6. 发送函数
    7. 接收函数

    范例1

    #include<reg52.h>
    unsigned char date;    //定义变量数据中断
    bit flag;  //定义变量标志
    void send (); //声明发送函数
    void receive (); //声明接收函数
    void initialize ();    //声明初始化函数
    main()
    {        
        initialize();  //调用初始化函数
        while(1)
        {
            send();    //调用发送函数
            receive(); //调用接收函数
        }
    }
    void initialize()  //初始化函数
    {
        SCON=0X50;     //0011 0000 串行口工作模式1
        TMOD = 0X20;    //定时器1工作模式2,8为自动重装
        TH1 = 0xFD;     //设定定时初值        波特率为9600
        TL1 = 0xFD;     //设定定时器重装值
        TR1 = 1;        //启动定时器1
        IE=0;
    }
    void send()         //发送函数
    {
        if(flag==1)    //证明已经接收数据
        {   
            SBUF=date;    //将接收的数据发送出去
            while(!TI);   //等待发送中断
            TI=0;         //软件置0
            flag=0;       //清零
        }
    
    }
    void receive()       //接收函数
    {
        while(!RI);   //等待接收中断
        date=SBUF;    //将收到的数据存进接收缓冲寄存器
        RI=0;        //软件置0
        flag=1;      //将标志位置1
    }
    

    范例1是将接受的数据原封不动发送出去。采用查询法,故不需要打开串口中断,不用中断函数。只需不断查询TI,RI的值,就知道数据接收发送情况。

    范例2

    #include<reg52.h>
    unsigned char date;
    bit flag;
    main ()
    {
        SCON=0X50;      //初始化
        TMOD=0X20;
        TH1=0XFD;                                   
        TL1=0XFD;
        IE=0X90;
        TR1=1;
        while(1);
    }
    void interrupt_uart() interrupt 4     //中断函数
    {
        if(RI==1)        //判断有无数据接收
        {
            date=SBUF;     //将寄存器的值赋给变量
            RI=0;          //置0
            flag=1;        //标志位置1
        }
        if(flag==1)             //已接收数据
        {
            SBUF=date;        //将数据发出
            while(!TI);
            TI=0;
            flag=0;
        }
    }
    

    与范例1如出一撤,就不详细注释。

    总结

    在串口通信中,方式1是最常用的,要认真理解方式1。串行数据一位一位的已经不用处理了,52单片机已经有一个模块处理完了。只要知道接收一个数据,产生一次接收中断,要软件置0.,发送一个数据会产生一次发送中断,也要软件置0。自行置0,处理好数据就OK。

    展开全文
    weixin_44643510 2021-01-06 13:59:07
  • 20KB pjfabsent 2011-04-25 14:09:25
  • 串行通信有单工通信、半双工通信和全双工通信3种方式。 单工通信:数据只能单方向地从一端向另一端传送。例如,目前的有线电视节目,只能单方向传送。 半双工通信:数据可以双向传送,但任一时刻只能向一个方向...

    数据通信的基本概念

    串行通信有单工通信、半双工通信和全双工通信3种方式。

    单工通信:数据只能单方向地从一端向另一端传送。例如,目前的有线电视节目,只能单方向传送。

    半双工通信:数据可以双向传送,但任一时刻只能向一个方向传送。也就是说,半双工通信可以分时双向传送数据。例如,目前的某些对讲机,任一时刻只能一方讲,另一方听。

    全双工通信:数据可同时向两个方向传送。全双工通信效率最高,适用于计算机之间的通信。

    此外,通信双方要正确地进行数据传输,需要解决何时开始传输,何时结束传输,以及数据传输速率等问题,即解决数据同步问题。

    实现数据同步,通常有两种方式,一种是异步通信,另一种是同步通信。

    异步通信

    在异步通信中,数据一帧一帧地传送。每一帧由一个字符代码组成,一个字符代码由起始位、数据位、奇偶校验位和停止位4部分组成。每一帧的数据格式如图7-1所示。

    一个串行帧的开始是一个起始位“0”,然后是5〜8位数据(规定低位数据在前,高位数据在后),接着是奇偶校验位(此位可省略),最后是停止位“1”。

    1. 起始位
      起始位"0”占用一位,用来通知接收设备,开始接收字符。通信线在不传送字符时,一直保持为“1”。接收端不断检测线路状态,当测到一个“0”电平时,就知道发来一个新字符,马上进行接收。起始位还被用作同步接收端的时钟,以保证以后的接收能正确进行。
    2. 数据位
      数据位是要传送的数据,可以是5位、6位或更多。当数据位是5位时,数据位为D0〜D4;当数据位是6位时,数据位为D0〜D5;当数据位是8位时,数据位为D0〜D7。
    3. 奇偶校验位
      奇偶校验位只占一位,其数据位为D8。当传送数据不进行奇偶校验时,可以省略此位。此位也可用于确定该帧字符所代表的信息类型,“1"表明传送的是地址帧,“0”表明传送的是数据帧。
    4. 停止位
      停止位用来表示字符的结束,停止位可以是1位、1.5位或2位。停止位必须是高电平。接收端接收到停止位后,就知道此字符传送完毕。

    图7-1 (a)表示一个字符紧接一个字符的传送情况,图7-1 (b)表示两个字符之间有空闲位的情况,空闲位为“1”,线路处于等待状态。空闲位是异步通信的特征之一。

    同步通信

    在同步通信中,发送端首先发送同步字符,紧接着连续传送数据(即数据块),并由时钟来实现发送端与接收端的同步。同步传送时,字符与字符之间没有间隙,仅在数据块开始时用同步字符(SYNC)来指示,其数据格式如图7-2所示。

    同步通信传送速度较快,但硬件结构比较复杂;异步通信的特点是硬件结构较简单,但传送速度较慢。

    MCS-51单片机釆用异步通信方式。

    波特率

    波特率是数据传送的速率,指每秒传送二进制数据的位数,单位是位/秒(bps)。假设数据传送速率是240字符/秒,而每个字符包含10个数据位

    则传送的波特率为10x240=2400bps

    每一位代码的传送时间几为波特率的倒数:

    T=1/2400=0.4165ms

    异步通信的波特率一般在50〜64000bps之间。

    串行口的结构

    MCS-51有一个可编程的全双工串行通信接口,可作为通用异步接收/发送器UART,也可作为同步移位寄存器。

    它的帧格式有8位、10位和11位,可以设置为固定波特率和可变波特率,给使用者带来很大的灵活性。

    80C51串行口的内部简化结构如图7-3所示。

    图中有两个物理上独立的接收、发送缓冲器SBUF,它们占用同一地址99H,可同时发送、接收数据。发送缓冲器只能写入,不能读出;接收缓冲器只能读出,不能写入。

    串行发送与接收的速率与移位时钟同步,定时器T1作为串行通信的波特率发生器,T1溢出率经2分频(或不分频)又经16分频作为串行发送或接收的移位时钟。移位时钟的速率即波特率。

    MCS-51单片机串行接口内部有一个发送数据缓冲器和一个接收数据缓冲器,简称串行数据缓冲器,共用一个地址99H;

    一个串行口控制寄存器SCON,用来选择串行口工作方式、控制数据接收和发送,并标示串行口的工作状态等。

    当串行口接收数据时,外界的串行信号通过单片机的引脚RXD (P3.0串行数据接收端),进入串行口的接收数据缓冲器。

    当串行口发送数据时,CPU将数据写入发送数据缓冲器,由发送数据缓冲器将数据通过引脚TXD (P3.1串行数据发送端),发送至外部的通信设备。

    特殊功能寄存器PCON控制串行口的波特率。PCON中有一位是波特率倍增位。

    串行口控制寄存器SCON

    串行口控制寄存器SCON决定串行口通信工作方式,控制数据的接收和发送,并标示串行口的工作状态等,其位格式为:

    SMO、SM1:串行口工作方式控制位,对应4种工作方式,如表7-1所示(fosc是晶振频率)。

    SM2:多机通信控制位,主要用于工作方式2和工作方式3。

    若SM2=1,则允许多机通信。

    多机通信规定:第9位数据位为1 (即TB8=1),说明本帧数据为地址帧:第9位数据为0(即TB8=0),则本帧数据为数据帧。

    当从机接收到的第9位数据(在RB8中)为1时,数据才装入接收缓冲器SBUF,并置RI=1向CPU申请中断;如果接收到的第9位数据(在RB8中)为0,则不置位中断标志RL信息丢失。

    当SM2=0时,则不管接收到第9位数据是否为1,都产生中断标志RI,并将接收到的数据装入SBUF。应用这一特点可以实现多机通信。

    串行口工作在方式0时,SM2必须设置为0;工作在方式1时,如SM2=1,则只有接收到有效的停止位时才会激活RI。

    REN:允许接收控制位。当REN=1时,允许接收;当REN=0时,禁止接收。此位由软件置1或清零。

    TB8:在方式2和方式3中,此位为发送数据的第9位,在多机通信中作为发送地址帧或数据帧的标志。TB8=1,说明该发送帧为地址帧;TB8=0,说明该发送帧为数据帧。在许多通信协议中,它可作为奇偶校验位。此位由软件置1或清零。在方式0和方式1中,此位未使用。

    RB8:接收数据的第9位。在方式2和方式3中,接收到的第9位数据放在RB8中。它或是约定的奇/偶校验位,或是约定的地址/数据标志位。在方式2和方式3多机通信中,若SM2=1且RB8=1,说明接收到的数据为地址帧。

    TI:发送中断标志位。在一帧数据发送完时置位。TI=1,申请中断,说明发送缓冲器SBUF已空,CPU可以发送下一帧数据。中断被响应后,TI不能自动清零,必须由软件清零。 ,

    RI:接收中断标志位。在接收到一帧有效数据后,由硬件置位。RI=1.申请中断,表示一帧数据接收结束,并已装入接收缓冲器SBUF中,CPU响应中断,取走数据。RI不能自动清零,必须由软件清零。

    串行口发送中断标志TI和接收中断标志RI共为一个中断源。因此,CPU接收到中断请求后,不知道是发送中断TI还是接收中断RI,必须用软件来判别。单片机复位后,控制寄存器SCON的各位均清零。

    特殊功能寄存器PCON

    电源控制寄存器PCON中只有一位SMOD与串行口工作有关,它的位格式为:

    SMOD:波特率倍增位。串行口工作在方式1、方式2、方式3时,若SMOD=1,则波特率提高一倍;
    若SMOD=0,则波特率不提高一倍。单片机复位时,SMOD=0。

    串行口的四种工作方式

    MCS-51单片机串行口可设置4种工作方式,由SCON中的SMO、SM1进行定义。

    方式0

    方式0时,串行口为同步移位寄存器的输入/输出方式。主要用于扩展并行输入或输出口。数据由RXD (P3.0)引脚输入或输出,同步移位脉冲由TXD (P3.1)引脚输出。发送和接收均为8位数据,低位在先,高位在后。波特率固定为focs/12。

    方式0输出

    方式0时输出时序如图7-4所示。

    对发送数据缓冲器SBUF写入一个数据,就启动了串行口的发送过程。内部的定时逻辑在SBUF写入数据之后,经过一个完整的机器周期,输出移位寄存器中输出位的内容送RXD引脚输出。移位脉冲由TXD引脚输出,它使RXD引脚输出的数据移入外部移位寄存器。当数据的最高位D7移至输出移位寄存器的输出位时,再移位一次后就完成了一字节的输出,中断标志TI置1。如要再发送下一字节数据,必须用软件先将TI清零。

    方式0输入

    方式0时输入时序如图7-5所示。

    当SCON中的接收允许位REN=1,用指令使SCON中的RI为0时,就会启动串行口接收过程。TXD引脚为串行输入引脚,移位脉冲由TXD引脚输出。当接收完一帧数据后,由硬件将输入移位寄存器中的内容写入SBUF,中断标志RI置1。如要再接收数据,必须用软件将RI清零。

    方式0输出时,串行口可以外接串行输入并行输出的移位寄存器,如74LS164、CD4094等,其接口逻辑如图7-6所示。TXD引脚输出的移位脉冲将RXD引脚输出的数据(低位在先)逐位移入74LS164或CD4094。

    方式0输入时,串行口外接并行输入串行输出的移位寄存器,如74LS165,其接口逻辑如图7-7所示。

    方式1

    串行口定义为方式1时,是10位数据的异步通信口。TXD为数据发送引脚,RXD为数据接收引脚,传送一帧数据的格式如图7-8所示。其中1位起始位、8位数据位、1位停止位。

    方式1输出

    当执行一条写SBUF的指令时,就启动了串行口发送过程。在发送移位时钟(由波特率确定)的同步下,从TXD引脚先送出起始位,然后是8位数据位,最后是停止位。一帧10位数据发送完后,中断标志TI置1。方式1的发送时序如图7-9所示。方式1的波特率由定时器1的溢出率决定。

    方式1输入

    方式1的接收时序如图7-10所示。

    当用软件置REN为1时,接收器以所选择波特率的16倍速率釆样RXD引脚电平,检测到RXD引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。

    在接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。当RI=0,且SM2=0 (或接收到的停止位为1)时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置RI=1,向CPU请求中断。

    方式2和方式3

    串行口工作于方式2或方式3时,为11位数据的异步通信口。TXD为数据发送引脚,RXD为数据接收引脚,传送一帧数据的格式如图7-11所示。

    由图可见,串行口工作于方式2和方式3时起始位1位,数据位9位(含1位附加的第9位,发送时为SCON中的TB8,接收时为RB8)、停止位1位,一帧数据为11位。方式2的波特率固定为晶振频率的1/64或1/32,方式3的波特率由定时器T1的溢出率决定

    方式2和方式3输出

    CPU向SBUF写入数据时,就启动了串行口的发送过程。SCON中的TB8写入输出移位寄存器的第9位,8位数据装入SBUF。方式2和方式3的发送时序如图7-12所示。

    发送开始时,先把起始位0输出到TXD引脚,然后发送移位寄存器的输出位(D0)到TXD引脚。每一个移位脉冲都使输出移位寄存器的各位右移一位,并由TXD引脚输出。

    第一次移位时,停止位“1”移入输出移位寄存器的第9位上,以后每次移位,左边都移入0。当停止位移至输出位时,左边其余位全为0,检测电路检测到这一条件时,使控制电路进行最后一次移位,并置TI=1,向CPU请求中断。

    方式2和方式3输入

    软件使接收允许位REN为1后,接收器就以所选频率的16倍速率开始取样RXD引脚的电平状态,当检测到RXD引脚发生负跳变时,说明起始位有效,将其移入输入移位寄存器,开始接收这一帧数据。方式2和方式3的接收时序如图7-13所示。

    接收时,数据从右边移入输入移位寄存器,在起始位。移到最左边时,控制电路进行最后一次移位。当RI=0,且SM2=0 (或接收到的第9位数据为1)时,接收到的数据装入接收缓冲器SBUF和RB8 (接收数据的第9位),置RI=1,向CPU请求中断。如果条件不满足,则数据丢失,且不置位RI,继续搜索RXD引脚的负跳变。

    多机通信的工作原理

    MCS-51单片机具有多机通信功能。

    串行口工作在方式2、方式3均可实现多机通信。串行控制寄存器SCON中的SM2和TB8、RB8相配合可以完成主从式多机通信。

    多机通信规定:第9位数据位为1 (即TB8=1),说明本帧数据为地址帧;第9位数据为0 (即TB8=0)时,则本帧数据为数据帧。

    若SM2=1,则仅当从机接收到的第9位数据为1时,数据才装入接收缓冲器SBUF,并置RI=1,向CPU申请中断;如果接收到的第9位数据为0,则不置位中断标志RI,该帧信息丢弃。

    主从式多机通信中,一台是主机,其余为从机,从机要服从主机的调度和支配。

    在多机通信时,一台为主机,其他为从机,所有从机的SM2都必须置1。主机首先发送一帧地址数据中断所有从机。从机接收到地址后,判断主机发送地址是否为本机地址,若是本机地址,则将SM2清零,进入正式通信状态,把本机的地址发送回主机作为应答信号,然后开始接收主机发来的数据或命令信息。其他从机由于地址不符,其SM2=1保持不变,不与主机通信,从中断返回。

    主从式多机通信遵循的通信协议为:

    • 使所有从机的SM2=1,处于只接收地址帧的状态。
    • 主机向从机发送一帧地址信息,其中包括8位地址,且第9位为1,表示发送的是地址,中断所有从机。
    • 从机接收。
    • 主机接收从机发回的应答地址信号后,与其发送的地址信息进行比较,如果相符,则使TB8=0,正式发送数据;如果不符,则发送错误信息。
    • 通信的各机之间必须以相同的帧格式及波特率进行通信。

    波特率的及算方法

    在串行通信中,收发双方对发送或接收的数据的波特率要有一个约定。

    MCS-51单片机串行口有4种工作方式:方式0和方式2的波特率固定不变;方式1和方式3的波特率可以变化,由定时器T1的溢出速率决定。

    下面介绍串行口 4种工作方式对应的波特率。

    方式0的波特率

    釆用工作方式0时,移位脉冲由机器周期的第6个状态周期S6给出,每个机器周期产生一个移位脉冲,发送或接收一位数据。因此,波特率是固定的,为振荡频率的1/12,不受PCON寄存器中SMOD的影响。用公式表示为

    工作方式0的波特率 = fosc/12

    方式2的波特率

    釆用工作方式2时,移位脉冲由振荡频率fosc的第二节拍P2时钟(即fosc/2)给出,所以,方式2波特率取决于PCON中的SMOD位的值,当SMOD=0时,波特率为fosc/64;当SMOD=1时,波特率为人fosc/32。用公式表示为

    工作方式2的波特率=(2^SMOD/64) * fosc

    方式1和方式3的波特率

    方式1和方式3的移位脉冲由定时器T1的溢出速率决定。因此,方式1和方式3的波特率由定时器T1的溢出速率与SMOD值同时决定。用公式表示为

    方式1、方式3的波特率=(2*SMOD/32) x T1的溢出速率

    其中,T1的溢出速率取决于T1的计数速率(在定时方式时,计数速率 = fosc/12)和T1的预置初值。

    定时器T1作为波特率发生器时,通常选用定时器T1工作在方式2,并使其工作在定时方式(即C/T=0)。

    此时,T1的计数速率为fosc/12 (这时应禁止T1中断)。设定时器初值为X,则每过“256-X”个机器周期,定时器T1产生一次溢出。用公式表示为

    T1 的溢出速率=(fosc/12) / (256-X)

    当给出波特率后,可用下式计算出定时器T1工作在方式2的初始值为

    X=256-(fosc * (SMOD+1) / (384*波特率)

    当T1作为波特率发生器时,最典型的用法是使T1工作在自动再装入的8位定时器方式(即方式2,且TCON的TR1=1,以启动定时器)。这时溢出速率取决于TH1中的计数值。

    在单片机应用中,常用的晶振频率为12MHz和11.0592MHz。所以,选用的波特率也相对固定。常用的串行口波特率与各参数的关系如表7-2所示。

    在使用串行口之前,应对其进行初始化,主要是设置产生波特率的定时器1、串行口控制和中断控制。具体步骤如下。

    1. 确定T1的工作方式(编程TMOD寄存器);
    2. 计算T1的初值,装载TH1、TL1;
    3. 启动T1 (编程TCON中的TR1位);
    4. 确定串行口控制(编程SCON寄存器);
    5. 串行口在中断方式工作时,要进行中断设置(编程IE、IP寄存器)。

    image-20200602010518784

    展开全文
    weixin_44643510 2021-01-05 22:37:07
  • llllll_llllllP 2018-12-14 00:18:44
  • qq_17017545 2018-09-30 21:35:22
  • qq_30251505 2016-12-21 20:09:47
  • 386KB m0_52957036 2020-03-17 18:04:40
  • qq_41838541 2019-12-18 21:51:06
  • 107KB weixin_38559866 2020-07-14 02:42:32
  • weixin_42164931 2021-05-23 10:16:12
  • 202KB qq_43353985 2021-02-03 13:10:11
  • 274KB xiaofeige567 2014-04-12 21:37:00
  • 1.1MB weixin_39841882 2019-07-23 18:29:21
  • kafmws 2019-03-05 17:56:22
  • m0_46573394 2020-12-28 10:58:35
  • howardhaowang 2020-04-11 19:53:07
  • weixin_39807352 2020-12-21 10:46:29

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 21,196
精华内容 8,478
关键字:

串行口方式1的发送和接收