51单片机——串口1收发

0. 序

使用串口1产生波特率,115200,使用STC-ISP波特率计算器生成

1. 修改

参考网上代码,发现无法运行,于是修改

修改串口初始化,不加这几个没法接收

    TI=0;
    RI=0;
    REN=1; //不开启这个无法接受数据
    //PS=1;   //提高串口中断优先级
    ES=1;  //开启串口中断使能
    EA=1;

2. 问题

修改后发现有不合理的地方,待后期修改,如下图,应该接收超时然后返回0,但是返回0之后就错了,如果不从这里跳出函数,发现是1个字1个字接收,无法正常收发

我对51的串口收发机制还不够熟悉,后期再来解决这个问题

3. 代码

本文参考的代码非常好,模块化帧头帧尾判断都写的很好,参考文章链接在文末。

使用如下代码,只需要把uartInit()函数放在main里面初始化即可。

#include <UART.H>
#include "intrins.h"
# include <string.h>


//------------------串口通信的数据包协议-----------------//
/*
    此程序的串口字符串通信使用到下面的一个自定义协议,每次通信都是发送或接收一个数据包,数据包格式解释如下(长度恒为15):
    例如:A01_fmq_01Off___#
    A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种)
    01-----设备代号
    fmq_01Off___--------指令(长度恒为10),指令的前4个人字符是指令头部,指令的后6个字符是指令尾部
    #---------数据包的结束标记

    例如:A02_SenT010250#
    A--------数据包的开始标记(可以为A到Z,意味着数据包可以有26种)
    02-----设备代号
    SenT010250--------指令(长度恒为10),指令的前4个人字符是指令头部,指令的后6个字符是指令尾部
    #---------数据包的结束标记
*/
char RecvString_buf[16];            //定义数据包长度为15个字符 //写15会超出字符,数组最后一位默认\0终止符号
#define deviceID_1Bit '0'                //用于串口通信时,定义本地设备ID的第1位
#define deviceID_2Bit '2'                //用于串口通信时,定义本地设备ID的第2位
#define datapackage_headflag 'A'        //用于串口通信时,定义数据包头部的验证标记

char DataPackage_DS18B20[16]= {datapackage_headflag,deviceID_1Bit,deviceID_2Bit,
                               '_','S','e','n','T','X','X','X','X','X','X','#'
                              };   //这个是曾经用来控制温度传感模块(DS18B20)的数据包
char HeartBeat[16]= {datapackage_headflag,deviceID_1Bit,deviceID_2Bit,
                     '_','B','e','a','t','X','X','X','X','X','X','#'
                    }; //我随便定义了一个数据包用来做"心跳包",比如单片机系统向电脑每2秒发送一次该数据包,如果电脑没有按时接收到,就认为单片机死掉了

//串口初始化
void uartInit(void)
{
    PCON &= 0x7F;		//波特率不倍速
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//清除定时器1模式位
	TMOD |= 0x20;		//设定定时器1为8位自动重装方式
	TL1 = 0xFD;		//设定定时初值
	TH1 = 0xFD;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
    REN=1; //不开启这个无法接受数据
    TI=0;
    RI=0;
    REN=1; //不开启这个无法接受数据
    //PS=1;   //提高串口中断优先级
    ES=1;  //开启串口中断使能
    EA=1;
    PutString("打开串口1\r\n");
}


//串口发送函数
void PutString(unsigned char *TXStr)
{
    ES=0;
    while(*TXStr!=0)
    {
        SBUF=*TXStr;
        while(TI==0);
        TI=0;
        TXStr++;
    }
    ES=1;
}


//串口接收函数
bit ReceiveString()
{
    u8 * RecStr=RecvString_buf;
    u8 num=0;
    u8 count=0;
loop:
    *RecStr=SBUF;
    count=0;
    RI=0;
    if(num<14)  //数据包长度为15个字符,尝试连续接收15个字符
    {
        num++;
        RecStr++;
        while(!RI)
        {
            count++;
            if(count>60) //只能收到1个 40接收单个 50接收2-3个 60可接收全部15个数字
                return 1;    //接收数据等待延迟,等待时间太久会导致CPU运算闲置,太短会出现"数据包被分割",默认count=130
        }
        goto loop;
    }
    return 1; //似乎执行不到这一步
}

//比较指令头部
bit CompareCMD_head(char CMD_head[])
{
    unsigned char CharNum;
    for(CharNum=0; CharNum<4; CharNum++) //指令长度为10个字符
    {
        if(!(RecvString_buf[CharNum+4]==CMD_head[CharNum]))
        {
            return 0;  //指令头部匹配失败
        }
    }
    return 1;        //指令头部匹配成功
}
//比较指令尾部(start:从哪里开始比较,quality:比较多少个字符,CMD_tail[]:要比较的字符串)
bit CompareCMD_tail(unsigned char start,unsigned char quality,char CMD_tail[])
{
    unsigned char CharNum;
    for(CharNum=0; CharNum<quality; CharNum++)
    {
        if(!(RecvString_buf[start+CharNum]==CMD_tail[CharNum]))
        {
            return 0;
        }
    }
    return 1;
}

bit Deal_UART_RecData()   //处理串口接收数据包函数(成功处理数据包则返回1,否则返回0)
{
    PutString(RecvString_buf);
    memset(RecvString_buf,0,16);
    PutString("\r\n");
    if(0)
    //if(RecvString_buf[0]==datapackage_headflag&&buf_string[14]=='#')  //进行数据包头尾标记验证
    {
        switch(RecvString_buf[1])        //识别发送者设备ID的第1位数字
        {
        case '0':
            switch(RecvString_buf[2])        //识别发送者设备ID的第2位数字
            {
            case '3':
                if(CompareCMD_head("Ligt"))    //判断指令头部是否为"Ligt"
                {
                    //下面是指令尾部分析
                    switch(RecvString_buf[8])
                    {
                    case '0':
                        switch(RecvString_buf[9])
                        {
                        case '0':

                            return 0;
                        case '1':
                            if(CompareCMD_tail(10,3,"Off"))   //判断整个数据包是否为:A03_Ligt01Off_#
                            {
                                //如果是则执行以下代码
                                return 1;
                            }
                            if(CompareCMD_tail(10,3,"On_"))    //判断整个数据包是否为:A03_Ligt01On__#
                            {
                                //如果是则执行以下代码
                                return 1;
                            }
                            return 0;
                        default:
                            return 0;
                        }
                    default:
                        return 0;
                    }
                }
                return 0;

            default:
                return 0;
            }
        default:
            return 0;
        }
    }
    return 0;
}

//串口中断服务函数-----------
void USART() interrupt 4   //标志位TI和RI需要手动复位,TI和RI置位共用一个中断入口
{
    if(ReceiveString())
    {
        //数据包长度正确则执行以下代码
        Deal_UART_RecData();
    }
    else
    {
        //数据包长度错误则执行以下代码
        //LED1=~LED1;
        PutString("接收失败\r\n");
    }
    RI=0;  //接收并处理一次数据后把接收中断标志清除一下,拒绝响应在中断接收忙的时候发来的请求
}

本文参考:https://www.cnblogs.com/weifeng727/p/5617924.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值