×
单片机 > 单片机程序设计 > 详情

51单片机-串口

发布时间:2020-08-21 发布时间:
|
单片机通信是指单片机与计算机或单片机与单片机之间的信息交换,通常单片机与计算机之间的通信我们用的较多。通信有并行和串行两种方式。串行通信又有两种方式:异步串行通信和同步串行通信。
异步通信是以字符(构成的帧)为单位进行传输,字符与字符之间的间隙(时间间隔)是任意的,但每个字符中的各位是以时间传送的,即字符之间不一定有“位间隔”的整数倍关系,但同一字符内的各位之间的距离均为“位间隔”的整数倍。
 
DB25与DB9:
80C51串行口的结构:
有两个物理上独立的接受,发送寄存器SBUF,它们占用同一地址99H;接收器是双缓冲结构;发送
缓冲器,因为发送时CPU是主动的,不会产生重叠错误。
RS232C标准接口主要引脚定义:
串行口控制寄存器SCON是一个特殊功能的寄存器,用以设定串行口的工作方式,接受发送控制及设
置状态标志。[page]
SM0,SM1工作方式选择位,SM2多机通信控制位,REN允许串行接收位,TI发送中断标志位,RI接
收中断标志位。串行发送停止位的开始时,由内部硬件使TI置1,向CPU发出中断申请。在中断服务
程序中,必须用软件将其清0,取消此中断申请。
电源管理寄存器PCON也是一个特殊功能寄存器,字节地址为87H,不能位寻址,PCON用来管理单片
机的电源部分,包括上电复位检测,掉电模式,空闲模式等。单片机复位时PCON全部被清0。
SMOD该位与串口波特率有关,SMOD=0,串口方式1,2,3时,波特率正常。SMOD=1,串口方式1,2,3时,波特率加倍。
 
用软件置REN为1时,接收器会以所选择波特率的16倍速采样RXD引脚电平,检测到RXD引脚输入电平发生
负跳变时,则说明起始位有效,将其移入输入移位寄存器,并开始接受这一帧信息的其余位。接受过
程中,数据从输入移位寄存器的右边输入,起始位移至输入移位寄存器最左边时,控制电路进行最后
一次移位。当RI = 0,且SMOD = 0(或接受到的停止位为1)时,将接收到的9位数据的前8位数据
装入接受SBUF,第9位进入RB8,并置RI=1,向CPU中断请求。
 
在具体操作串行口之前,需要对单片机一些与串行口有关的特殊功能寄存器进行初始化设置:
 
确定T1的工作方式(编程TMOD寄存器) 
计算T1的初值,装载TH1,TL1 
开启T1(编程TCON中的TR1位) 
设置串口的工作方式(编程SCON寄存器) 
串行口工作在中断方式下,要进行中断设置(IE寄存器) 
 
波特率计算公式:
方式0的波特率=fosc/12。 
方式1的波特率=(2^smod/32)*(T1溢出率)。 
方式2的波特率=(2smod/64)*fosc。 
方式3的波特率=(2smod/32)*(T1溢出率)。 
T1溢出率=fosc/{12*[256-(TH1)]} 
 
fosc为系统晶振频率,通常为12MHZ或11.05926MHZ
异步串口通信两种方式:轮询和中断
下面是一个中断程序,使用串口调试工具发出什么返回什么。
 
 
#include <reg52.h>
 
unsigned char a,flag;
 
void main(){
        TMOD = 0x20;         //工作方式2,8位自动重装定时/计数器
        TH1 = 0xfd;          //波特率为9600bps,系统晶振频率为11.0592MHZ时需要装入的
        TL1 = 0xfd;          //TH1,TL1的值可以通过公式 T1溢出率=fosc/{12*[256-(TH1)]}
        EA = 1;              //开启CPU中断允许位
        ES = 1;              //开始串口中断允许位
        SM1 = 1;             //设置串口的工作方式为01即方式1,10位异步收发(8位数据)
        TR1 = 1;             //T1开启
        REN = 1;             //允许串行接受位
        while(1){
                 if(flag == 1){                              
                        ES = 0;             //关闭串口中断,防止发送数据时产生中断
                        SBUF = a;    //将数据送到发送缓冲寄存器
                        while(!TI);         //发送当停止位开始时,会产生中断,把TI置1
                        TI = 0;                 
                        flag = 0;
                        ES = 1;                 //允许中断
                }
        }
}
 
void uart() interrupt 4{
        a = SBUF;             //当产生RI中断时说明数据接收完毕,把数据赋给变量a  
      RI = 0;                    //软件方法把RI置0
        flag = 1;
}
 
轮询方式,如果有数据输入发送给串口,当停止位开始时,蜂鸣器响起。
#include <reg52.h>
#define uchar unsigned char    
sbit buzzer=P3^4;
                      
void delay(uchar z)
{
        uchar x,y;
        for(x=1000;x>1;x--)
                for(y=z;y>1;y--);
}
[page]
void main(){
        TMOD = 0x20;         //工作方式2,8位自动重装定时/计数器
        TH1 = 0xfd;          //波特率为9600bps,系统晶振频率为11.0592MHZ时需要装入的
        TL1 = 0xfd;          //TH1,TL1的值可以通过公式 T1溢出率=fosc/{12*[256-(TH1)]}
        EA = 1;              //开启CPU中断允许位
        ES = 1;              //开始串口中断允许位
        SM1 = 1;             //设置串口的工作方式为01即方式1,10位异步收发(8位数据)
        TR1 = 1;             //T1开启
        REN = 1;             //允许串行接受位
        while(1){
                 if(RI == 1){    //大循环进行轮询,如果串行发送停止位开始,则RI会被硬件置1
                        RI = 0;
                        buzzer=0;
                        delay(10);
                        buzzer=1;
                        delay(10);
                }
        }
}
 
 
 
 
两个纠结的程序:
 
 
 
由上位机发送1给单片机时,蜂鸣器以400ms频率发声,发2时以200ms频率发声,发3时以100ms频率发声,发4时关闲蜂鸣器。
 
 
#include<reg52.h>
unsigned char flag,a,num,benum;
sbit beep=P3^4;
void main()
{
 
        TMOD=0x21;//设置定时器1为工作方式2
        TH1=0xfd;
        TL1=0xfd;
        TH0=(65536-50000)/255;
        TL0=(65536-50000)%255;
        TR1=1;
        ET0=1;
        SM0=0;
        SM1=1;
        REN=1;
        EA=1;
        ES=1;
        while(1)
        {
                if(flag==1)
                {
                        EA=0;
                        flag=0;
                        TR0=1;
                        if(a==1)
                                benum=4;
                        if(a==2)
                                benum=2;
                        if(a==3)
                                benum=1;
                        if(a==4)
                        {
                                TR0=0;
                                beep=1;        
                        }
                        EA=1;
                }
        }
}
 
void ser() interrupt 4
{
        RI=0;
        a=SBUF;
        flag=1;
}
 
void time0() interrupt 1
{
        TH0=(65536-50000)/255;
        TL0=(65536-50000)%255;
        num++;
        if(num>=benum)
        {
                num=0;
                beep="beep;
        }        
}
 
 
以2400bps从计算机发送任一字节数据,当单片机收到该数据后,在此数据前加上一序号然后连同此数据一起发送至计算机,当序号超过255时归零。
 
#include<reg52.h>
unsigned char flag,a,num,num1;
sbit beep=P3^4;
void main()
{
 
        TMOD=0x20;//设置定时器1为工作方式2
        TH1=0xf4;
        TL1=0xf4;
        TR1=1;
        SM0=0;
        SM1=1;
        REN=1;
        EA=1;
        ES=1;
        while(1)
        {
                if(flag==1)
                {
                        ES=0;
                        flag=0;
                        num1++;
                        if(num1==255)
                                num1=0;
                        SBUF=num1;
                        while(!TI);
                        TI=0;
                        SBUF=a;
                        while(!TI);
                        TI=0;
                        ES=1;
                }
        }
}
 
void ser() interrupt 4
{
        RI=0;
        a=SBUF;
        flag=1;
}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
ARM 汇编的必知必会