首页 > 技术文章 > 51单片机串口通信(通用异步收发传输器)

Brimon-zZY 2020-12-19 22:21 原文

有关通信接口:

RS232:

 

MAX232 这个芯片起到的就是中间人的作用,它 把 UART 电平转换成 RS232 电平,也把 RS232 电平转换成 UART 电平,从而实现标准 RS232 接口和单片机 UART 之间的通信连接。

 

USB转串口通信:

 

关于程序烧录和冷启动:

CH340T 的电路里 3 脚位置加了个 4148 的二极管,是一个小技巧。因为 STC89C52 这个 单片机下载程序时需要冷启动,就是先点下载后上电,上电瞬间单片机会先检测需要不需要 下载程序。虽然单片机的 VCC 是由开关来控制,但是由于 CH340T 的 3 脚是输出引脚,如 果没有此二极管,开关后级单片机在断电的情况下,CH340T 的 3 脚和单片机的 P3.0(即 RXD) 引脚连在一起,有电流会通过这个引脚流入后级电路并且给后级的电容充电,造成后级有一 定幅度的电压,这个电压值虽然只有两三伏左右,但是可能会影响到正常的冷启动。加了二 极管后,一方面不影响通信,另外一个方面还可以消除这种不良影响。

 

 

 

 

 

 

 

串口工作前需要配置相关寄存器:

1、设置T1的工作方式(通过设置TMOD)

2、计算比特率,设置TH1和TL1

3、启动T1(TCON中的TR1位)

4、确定串行口控制(SCON寄存器)

5、串口在中断工作时还要设置IE

 

 

在中断下的串口通信:

配置IE寄存器:

EA = 1;

ES = 1;

配置SCON寄存器:(单机通讯)

SM0 = 0;

SM1 = 1;//配置为方式1

REN = 1;//允许接收

 

TI(发送中断标志位)由硬件置1,由软件置0

RI(接收中断标志位)同上

 

要用到定时器T1(方式2),需要配置TCON

TR1 = 1;

设置TH1和TL1;(比特率)

 

即:

void UARTInit()
{
    EA = 1;    //打开总中断
    ES = 1; //打开串口中断
    SM0 = 0;    SM1 = 1;//串口工作方式1,8位UART波特率可变
    REN = 1;//串口允许接收
    TR1 = 1;//启动定时器1
    TMOD |= 0x20;//定时器1,工作模式2 8位自动重装
    TH1 = 0xfd;
    TL1 = 0xfd;//设置比特率9600
}

因为定时器中断和串口中断,都要用到定时器,所以都要设置TMOD,所以用“|”号设置。

中断服务函数:

void UART() interrupt 4
{
    uchar temp;
    if(RI)//判断接收是否完成
    {
        num = SBUF;//读SBUF,读出串口接收到的数据
        RI = 0;//软件清零接收标志位   
        temp = num;//
        SBUF = ++temp;//写SBUF,把要发送的数据送给发送缓存器
    }
    if(TI)//判断是否发送完成
        TI = 0;//清零发送完成标志位   
}

上位机设置:

hex模式

如果是文本格式,则传回对应的ASCLL码。

 

发送汉字:

调用stdio.h库

用查询方式:

while(1)

{

  TI = 1;

  puts("hello");//printf("hello");

  while(!TI){

    TI = 0;

    delay():

  }

}

完整可用代码:

#include <reg52.h>
#include <intrins.h>

#define uint unsigned int
#define uchar unsigned char

sbit DU = P2^6;//数码管段选
sbit WE = P2^7;//数码管段选
uchar num;//数码管显示的值

//共阴数码管段选表0-9
uchar code SMGduan[]= {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F,};
//数码管位选码
uchar code SMGwei[] = {0xfe, 0xfd, 0xfb};

/*====================================
函数    : delay(uint z)
参数    :z 延时毫秒设定,取值范围0-65535
返回值    :无
描述    :12T/Fosc11.0592M毫秒级延时
====================================*/
//void delay(uint z)
//{
//    uint x,y;
//    for(x = z; x > 0; x--)
//        for(y = 114; y > 0 ; y--);         
//} 

/*====================================
函数    :display(uchar i)
参数    :i 显示数值,取值范围0-255
返回值    :无
描述    :三位共阴数码管动态显示
====================================*/
void display(uchar i)
{
    static uchar wei;         
    P0 = 0XFF;//清除断码
    WE = 1;//打开位选锁存器
    P0 = SMGwei[wei];
    WE = 0;//锁存位选数据
    switch(wei)
    {
        case 0: DU = 1; P0 = SMGduan[i / 100]; DU = 0; break;
        case 1: DU = 1; P0 = SMGduan[i % 100 / 10]; DU = 0; break;    
        case 2: DU = 1; P0 = SMGduan[i % 10]; DU = 0; break;        
    }
    wei++;
    if(wei == 3)
        wei = 0;
}




//定时器0初始化
void timer0Init()
{
    EA = 1;    //打开总中断
    ET0 = 1;//打开定时器0中断
    TR0 = 1;     //启动定时器0
    REN = 1;//允许串口接收
    TMOD |= 0X01; //定时器工作模式1,16位定时模式
    TH0 = 0xED;
    TL0 = 0xFF; //定时5ms
}
//串口初始化
void UARTInit()
{
    EA = 1;    //打开总中断
    ES = 1; //打开串口中断
    SM0 = 0;    SM1 = 1;//串口工作方式1,8位UART波特率可变
    REN = 1;//串口允许接收
    TR1 = 1;//启动定时器1
    TMOD |= 0x20;//定时器1,工作模式2 8位自动重装
    TH1 = 0xfd;
    TL1 = 0xfd;//设置比特率9600
}
void main()//main函数自身会循环
{    
    timer0Init();//定时器0初始化
    UARTInit();//串口初始化
    while(1);    
} 

//定时器0中断函数
void timer0() interrupt 1
{
    TH0 = 0xED;
    TL0 = 0xFF; //定时5ms
    display(num); //数码管显示函数    
}
//串口中断函数
void UART() interrupt 4
{
    uchar temp;
    if(RI)//判断接收是否完成
    {
        num = SBUF;//读SBUF,读出串口接收到的数据
        RI = 0;//软件清零接收标志位    
        temp = num;//
        SBUF = ++temp;//写SBUF,把要发送的数据送给发送缓存器
    }
    if(TI)//判断是否发送完成
        TI = 0;//清零发送完成标志位    
} 

 

推荐阅读