2020-03-23/串口通信

串口通信分为:并行和串行
并行通信传送速度快,但是所需线路复杂,串行通信传送速度慢,线路简单;
通信又分为:单工(单方向),半双工(不能同时发送和接收),全双工(可以同时进行半双工和全双工);
同步通信:收发双方采用的形同频率的时钟; 异步通信:收发双方采用不同时钟频率;


80c51串口通信原理图

SCON 寄存器(可以位寻址)
SCON 寄存器是特殊功能寄存器之一,用来设定串口的工作方式、收发控制及设置状态标志;


scon寄存器

PCON寄存器(可以位寻址)


PCON寄存器

SMOD(PCON.7)波特率倍增位。在串行口方式1、方式2、方式3时,波特率与SMOD有关,当SMOD=1时,波特率提高一倍。复位时,SMOD=0。

方式1的输入输出
方式1是10 位数据的异步通信口,TXD为数据发送引脚,RXD为数据接收引脚,传送一帧数据的格式如图所示。其中1位起始位,8位数据位,1位停止位。


方式1的数据

方式1输出

方式1输入

(不太理解) 用软件置REN为1时,接收器以所选择波特率的16倍速率采样RXD引脚电平,检测到RXD引脚输入电平发生负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接收这一帧信息的其余位。接收过程中,数据从输入移位寄存器右边移入,起始位移至输入移位寄存器最左边时,控制电路进行最后一次移位。当RI=0,且SM2=0(或接收到的停止位为1)时,将接收到的9位数据的前8位数据装入接收SBUF,第9位(停止位)进入RB8,并置RI=1,向CPU请求中断。

波特率计算公式:
方式0的波特率 = fosc/12
方式2的波特率 =(2SMOD/64)· fosc
方式1的波特率 =(2SMOD/32)·(T1溢出率)
方式3的波特率 =(2SMOD/32)·(T1溢出率)
当T1作为波特率发生器时,最典型的用法是使T1工作在自动再装入的8位定时器方式(即方式2,且TCON的TR1=1,以启动定时器)。这时溢出率取决于TH1中的计数值。
T1 溢出率 = fosc /{12×[256 -(TH1)]}
对于以上计算初值,通常用初值计算工具完成;

串口工作编程:
1.确定定时器的工作方式:TMOD; 一般选择定时器1;
2.计算定时器的初值;装载THn,TLn的初值;(一般选择方式1的冲转载);
3.启动定时器Tn;(变成TCON的TR1位);
4.确定串行口控制;(变成SCON);
5.串行口在中断方式工作时,要注意终端设置;(变成IE和IP寄存器);串口的中断号是4


中断源

也就是说,在串口通信时,定时器+中断+串口的要用起来的,对于相关寄存器的总结,见文章:

编程
利用51单片机和PC进行通信:

#include<reg51.h>
//利用51单片机和PC通信
void UART()
{
    TMOD=0X20;//设置定时器1工作模式为 模式2;
    TH1=0XF3;//定义定时器1寄存器高位
    TL1=0XF3; //低位
    PCON=0X80;//PCON 中为是否能设置倍频,但PCON不是可以位寻址嘛?为甚么不能用SMOD=1;
    TR1=1;//打开定时器1
    REN=1;//scon寄存器之一,由软件置1,则可以接受,清零无法接受;
    SM1=1;
    SM0=0; //设置SCON的工作模式为1,发送8位数据,包含起始位和截至位
    RI=1;//接受中断标志位
    ES=1;//IE寄存器中的,串口使能中断
    EA=1;//TCON寄存器,开总中断
    T1=1;//发送中断标志位
}
int main()
{
    UART();//调用串口函数
    while(1);
}
void usart() interrupt 4
{
    char i;
    i=SBUF;//把传送完的数据存贮在sbuf;sbuf寄存器可以位寻址;
    RI=0;//接受完后会置1,软件清0;
    SBUF=i;
    while(!TI);//当没发送完一直运行
    TI=0;
}

利用串行通信控制流水灯

#include<reg51.h>
#include<intrins.h> 
#define led P2 
char b;
void UART()
{
    TMOD=0X20;//选择8位重装
    TH1=0XF3;
    TL1=0XF3;
    PCON=0X80;
    ET1=0;//禁止T1定时器中断
    TR1=1;//打开T1中断
    REN=1;//
    SM1=1;
    SM0=0;//选择模式1模式
    RI=1;
    TI=1;
    ES=1;
    EA=1;
}
void delay(int i)
{
   while(i--);
}
//void LED()      //函数名不能和宏定义一样
void LED()
{
    int count=0,i=0;
    while(1)
    {
        for(i=0;i<=16;i++)
        {
            if(i<=8)
            {
                led=(0xfe<<count);
                delay(5000);
                count++;
                if(count>=8)
                {
                    count=0;
                }
            }
            else
            {
                led=(0x7f>>count);
                delay(5000);
                count++;
                if(count>=8)
                {
                    count=0;
                    i=0;
                }
            }
        }
    }
}
int main()
{
        UART();//调用函数
        while(1);
        return 0;    
 }
void UARTintrrupt () interrupt 4
{
    while(!RI);
    b=SBUF;//将数据暂存在SBUF
    RI=0;
    SBUF=b;
    while(!TI);
    TI=0;  
    if(b=='1')
        {
            LED();
        }
} 
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容