天天招生网
您的位置:首页 >> 职业技能 >> 单片机 >> 名师讲堂 >> C51串口应用详解

C51串口应用详解


东哥单片机学习网 2010-7-23 16:13:10 点击: 次  发表评论

串口是C51单片机的一个重要应用.结合我自己的经验和参考书,把串口的应用做一个详细的整理.借此加深对串口应用的理解.

8051 有一个可通过软件控制的内置全双工串行通讯接口.发送时数据由TXD端送出,接收时数据由RXD端输入.有两个缓冲器SBUF,一个做发送缓冲器,一个做接收缓冲器.波特率必须从内部定时器1或定时器2获得.

一、串行口相关SFR

   1、串口控制寄存器SCON

SM0

SM1

SM2

REN

TB8

RB8

TI

RI

 

SM0、SM1 串行模式选择

SM0       SM1

工作方式

说明

波特率

0           0

方式0

同步移位寄存器

Fosc/12

0           1

方式1

10位异步收发

由定时器控制

1           0

方式2

11位异步收发

Fosc/32或fosc/64

1           1

方式3

11位异步收发

由定时器控制

 

SM2 多机通讯允许位

1-     只有接收到第9位(RB8)为1,RI才置位

0- 接收到字符RI就置位

REN 串行接收允许位

1-允许串行口接收   0-禁止串行口接收

TB8 在模式2 和模式3 中是被发送的第9位数据,也可以作奇偶校验位

RB8 在模式0 中该位不起作用,在模式1 中该位为接收数据的停止位,在模式2和模式3中为接收数据的第9位

TI 串行中断标志位,由软件清零

RI 接收中断标志位,由软件清零

   2、电源控制寄存器PCON

SMOD

 

 

 

GF1

GF0

PD

IDL

SMOD:串口波特率加倍位

SMOD为1时,波特率加倍

二、串行口工作方式

    1、方式0

    方式0时,UART作为一个8 位的移位寄存器,使用波特率为fosc/12, 数据由RXD 从低位开始收发。TXD 用来发送同步移位脉冲,因此方式0不支持全双工。这种方式可用来和像某些具有8位串行口的EEPROM 之类的器件通讯。当向SBUF写入字节时开始发送数据数据,发送完毕时TI位将置位。置位REN 时,将开始接收数据,接收完8位数据时RI位将置位。

2、方式1

方式1是10位异步通信方式,1为起始位(0),8为数据位和1位停止位(1)。其中起始位和停止位是在发送时自动插入的。这种方式可和包括PC 机在内的很多器件进行通讯,这种方式中波特率是可调的,而用来产生波特率的定时器的中断应该被禁止。PCON 的SMOD 位为1 时可使波特率翻倍。发送完成后TI置位,接收完成后RI置位。

3、方式2和方式3

方式2的数据以11 位方式发送,1位起始位,8位数据位,第九位,1位停止位。发送数据时,第九位为SCON 中的TB8 ,接收数据的第九位保存在RB8中。第九位一般用来多

机通信。仅在第九位为1时单片机才接收数据。多机通信用SCON的SM2来控制,当SM2

置位时仅当数据的第九位为1 时才引发通讯中断。当SM2为0时只要接收完11位就产生一次中断。第九位可在多机通讯中避免不必要的中断。在传送地址和命令时第九位置位,串行

总线上的所有处理器都产生一个中断,处理器将决定是否继续接收下面的数据。如果继续

接收数据就清零SM2, 否则,SM2置位,以后的数据流将不会使他产生中断。

SMOD=0 时方式2 的波特率为1/64Osc, SMOD=1 时波特率为1/32Osc 。因此,使用方式2,当晶振频率为11.059M时,将有高达345K的波特率。方式3和方式2的差别在于可变的波特率。

三、波特率计算公式

SMOD=0时

波特率=fosc/(32*12*(256-x))

SMOD=1时

波特率=2*fosc/(32*12*(256-x))       x为定时器初值

例如:osc=22.1184MHz,要得到115200的波特率。

把SMOD设为1,T1工作在模式2,8位自动装入的计数器。根据公式计算出定时器初值=ff

既TH1=TL1=FF

四、串口的应用

    串口主要用于和包括PC 机在内的很多器件进行通讯。也可以用来扩展I/O口。

1、  用串口扩展的矩阵键盘

8051单片机的串口工作于方式0时,可作为移位寄存器用于扩展I/O口。下图为接口电路。74LS164是串入/并出移位寄存器,它将来自8051串行口线RXD的串行数据转换成8位并行数据,P3.4和P3.5定义为输入口线,可实现一个2*8矩阵键盘接口。

 

 

 

 

程序由主函数main()、读键盘函数get_char()和延时函数delay()组成。主函数将8051串口初始化为工作方式0,采用查询式输入输出,然后调用读键盘函数读入按键的编码值,并存入以keybuf为首地址的16个内部RAM单元。读键盘函数判断是否有键按下,有按键时进行键值分析,并将按键的键值返回给主调用函数。延时函数的功能是提供一段延时时间以防止按键抖动。

程序如下:

#include <reg51.h>

    #include <intrins.h>

    sbit P34  = B4;

    sbit P35  = B5;

 

    unsigned char get_char(void);            /* 函数说明 */

    void delay(void);

 

    main() {

       unsigned char keybuf[16], count;      /* 键盘缓冲区和读键计数变量 */

       SCON=0;                               /* 将串行口设置成工作方式0 */

       ES=0;                                 /* 禁止串口中断 */

       EA=0;

       count=0;                             

       while(count<16) keybuf[count]=get_char(); /* 读入16个按键的键值 */

     }

 

    unsigned char get_char(void) {

    /* 定义表示列号、键序号和待发送数据的变量column、key_code和mask */

       unsigned char key_code, column=0, mask=00;

    /* 下列语句从串行口向74LS164移位输出8个0 */

       TI=0;

       SBUF=mask;

       while(TI==0);                         /* 等待发送完毕 */

    /* 下列语句通过检测P3.4和P3.5是否为0来判断是否有键压下, 检测到有键压下时

       延时10ms以消除桉键抖动, 然后继续检测P3.4和P3.5是否为0, 若不为0则表明

       检测到干扰信号并继续等待按键, 否则表示有一个键被可靠地按下并退出循环

    */

       while(1) {

          while((P34&P35)!=0);

          delay();

          if((P34&P35)!=0) continue;

          else break;

       }

    /* 下列语句分析被按下的键所在的列号 */

       mask=fe;

       while(1) {

          TI=0;

          SBUF=mask;

          while(TI==0);

          if((P34&P35)!=0) {

             mask=_crol_(mask,1);            /* mask的值循环左移一位 */

             column;

             if(column>=8) column=0;

             continue;

          }

          else break;

       }

    /* 下列语句分析被按下的键所在的行号并计算键序号 */

       if(P34==0)  key_code=column;

       else       key_code=8column;

       return(key_code);

     }

 

     void delay(void) {

        unsigned int i=10;                   /* 延时10ms */

        while(i--);

     }

 

2、  串行口实现多机通信

下面给出一个利用8051串口进行多机通信的程序。一个主机与多个从机进行单工通信,主机发送,从机接收。主机先向从机发送一帧地址信息,然后再发送10位数据信息。从机接收主机发来的地址,并与本机的地址比较,若不相同则仍保持SM2=1不变,自动抛弃数据帧。若地址相同,则使SM2=0,准备接收主机发来的数据信息,直到接收完10位数据。通信双方都采用11.0592MHz的晶振,用定时器/计数器1产生9600的波特率,采用中断方式传送数据。从机的地址为0~255的编码。实际通信中还应该考虑通信协议,为简单起见,下面的程序未予考虑。主机发送程序文件名为T.C,从机接收程序文件名为R.C.

发送程序:

#include <reg51.h>

    #define COUNT 10                         /* 定义发送缓冲区大小 */

    #define NODE_ADDR 64                     /* 定义目的节点地址 */

    unsigned char buffer[COUNT];             /* 定义发送缓冲区 */

    int pointer;                             /* 定义当前位置指针 */

    main() {

    /* 发送缓冲区初始化 */

       while(pointer<COUNT) {

        buffer[pointer]='A'pointer;

        pointer;

       }

    /* 初始化串行口和波特率发生器 */

       SCON=c0;

       TMOD=20;

       TH1=fd;

       TR1=1;

       ET1=0;

       ES=1;

       EA=1;

       pointer=-1;

    /* 发送地址帧 */

       TB8=1;

       SBUF=NODE_ADDR;

    /* 等待全部数据帧发送完毕 */

       while(pointer<COUNT);

          /* ...... */

    }

 

    /* 发送中断服务函数 */

    void send(void) interrupt 4 using 3 {   

    /* 清发送中断标志并修改发送缓冲区当前位置指针 */

       TI=0;

       pointer;

    /* 如果全部数据发送完毕则返回, 否则发送一帧数据 */

       if(pointer>=COUNT) return;

       else {

            TB8=0;                             /* 设置数据帧标志 */

            SBUF=buffer[pointer];              /* 启动发送 */

       }

     }

 

接收程序:

#include <reg51.h>

    #define COUNT 10                         /* 定义接收缓冲区大小 */

    #define NODE_ADDR 64                     /* 定义本节点地址 */

    /* 定义接收缓冲区和当前位置指针 */

    unsigned char buffer[COUNT];

    int p



阅读上一篇:单片机的C语言中位操作用法
阅读下一篇:Keil C51高级编程

专题推荐

三百六十行,欢迎各培训机构加盟

您想拥有一个全功能动态的独立网站吗