8051单片机串口复杂命令接收与解析

下面程序是为了实现二自由度自动进样检测器的控制而编写的. 在程序执行过程中, 我发现, 在发送Start.E再发送Stop.E后, 串口助手接收缓存区并未显示一连串"00": 这说明在输入Start.E后, 虽然又收到Stop.E时执行了"en = 0"这个表达式, 但是回到第一层中断处理程序后, 这里的en还是"1"(并未变为我们希望的"0"). 这说明, 以串口中断实现对二自由度自动进样检测仪的控制, 还是有一定难度的. 接下来我将致力于解决这一难题.

#include <STC89C5xRC.H>

char buf[30];//存放串口传来的数据

int i = 0;

int en;

void UART_INT() interrupt 4//串行通信中断处理程序
{
    int len = 0;
    int j = 0;
    if(RI == 1)//如果收到数据
    {
        if(i == 30)
        {
            i = 0;//防止越界访问
        }
        RI = 0;
        buf[i++] = SBUF;//将数据接收下来
        if(buf[i - 1] == 'E')//到达结尾
        {
            len = i - 1;//记录数据长度
            i = 0;
            if(len == 6)
            {
                if(buf[0] == 'S' && buf[1] == 't' && buf[2] == 'a' && buf[3] == 'r' && buf[4] == 't' && buf[5] == '.')
                {
                    //Start命令(开机)
                    en = 1;
                    while(1)
                    {
                        SBUF = 1;
                        while(TI == 0);
                        TI = 0;
                        while(en == 0)
                        {
                            SBUF = 0;
                            while(TI == 0);
                            TI = 0;
                        }
                    }

                }
                else if(buf[0] == 'R' && buf[1] == 'e' && buf[2] == 's' && buf[3] == 'e' && buf[4] == 't' && buf[5] == '.')//主转盘回到原始位置,针臂抬到最高位置
                {
                    //Reset命令(复位命令)
                    while(j < len)
                    {
                        SBUF = buf[j];
                        while(TI == 0);//等待数据发送
                        TI = 0;
                        j++;
                    }
                    j = 0;
                    en = 0;
                }
            }
            else if(len == 5)//停机命令
            {
                if(buf[0] == 'S' && buf[1] == 't' && buf[2] == 'o' && buf[3] == 'p' && buf[4] == '.')
                {
                    //Stop命令(停机命令)
                    en = 0;
                }
            }
            else if(len == 18)//要求主转盘转动相应格数
            {
                if(buf[0] == 'M' && buf[1] == 'a' && buf[2] == 'i' && buf[3] == 'n' && buf[4] == ' ' && buf[5] == 'm' && buf[6] == 'o' && buf[7] == 't' && buf[8] == 'o' && buf[9] == 'r' && buf[10] == ' ' && buf[11] == 'r' && buf[12] == 'u' && buf[13] == 'n' && buf[14] == ' ')
                {
                    //Main motor run命令,比如Main motor run 22.
                    if(buf[15] >= '1' && buf[15] <= '9' && buf[16] >= '1' && buf[16] <= '9')//确定发来的步数是数字
                    {
                        while(j < len)
                        {
                            SBUF = buf[j];
                            while(TI == 0);//等待数据发送
                            TI = 0;
                            j++;
                        }
                        j = 0;
                    }
                }
            }
        }
    }
}

int main()
{
    RI = 0;
    TI = 0;
    TMOD = 0x21;
    SCON = 0x50;
    TH1 = 0xe6;
    TL1 = 0xe6;
    TR1 = 1;
    IE = 0x90;
    while(1)
    {
        ;//采用前后台系统架构
    }
}
 

我将上述程序中的轮询部分去除, 并分别以D8/D7/D6/D5的点亮对应Start./Reset./Stop.E/Main motor run steps.命令.

在运行后发现, 四种命令完美对应四盏灯的亮灭.

#include <STC89C5xRC.H>

char buf[30];//存放串口传来的数据

int i = 0;

int en = 0;

void UART_INT() interrupt 4//串行通信中断处理程序
{
    int len = 0;
    int j = 0;
    if(RI == 1)//如果收到数据
    {
        if(i == 30)
        {
            i = 0;//防止越界访问
        }
        RI = 0;
        buf[i++] = SBUF;//将数据接收下来
        if(buf[i - 1] == 'E')//到达结尾
        {
            len = i - 1;//记录数据长度
            i = 0;
            if(len == 6)
            {
                if(buf[0] == 'S' && buf[1] == 't' && buf[2] == 'a' && buf[3] == 'r' && buf[4] == 't' && buf[5] == '.')
                {
                    //Start命令(开机)
                    en = 1;
                    P27 = 0;//D8亮
                    P26 = 1;
                    P25 = 1;
                    P24 = 1;
                }
                else if(buf[0] == 'R' && buf[1] == 'e' && buf[2] == 's' && buf[3] == 'e' && buf[4] == 't' && buf[5] == '.')//主转盘回到原始位置,针臂抬到最高位置
                {
                    //Reset命令(复位命令)
                    en = 0;
                    P27 = 1;
                    P26 = 0;//D7亮
                    P25 = 1;
                    P24 = 1;
                }
            }
            else if(len == 5)//停机命令
            {
                if(buf[0] == 'S' && buf[1] == 't' && buf[2] == 'o' && buf[3] == 'p' && buf[4] == '.')
                {
                    //Stop命令(停机命令)
                    en = 0;
                    P27 = 1;
                    P26 = 1;
                    P25 = 0;//D6亮
                    P24 = 1;
                }
            }
            else if(len == 18)//要求主转盘转动相应格数
            {
                if(buf[0] == 'M' && buf[1] == 'a' && buf[2] == 'i' && buf[3] == 'n' && buf[4] == ' ' && buf[5] == 'm' && buf[6] == 'o' && buf[7] == 't' && buf[8] == 'o' && buf[9] == 'r' && buf[10] == ' ' && buf[11] == 'r' && buf[12] == 'u' && buf[13] == 'n' && buf[14] == ' ')
                {
                    //Main motor run命令,比如Main motor run 22.
                    if(buf[15] >= '1' && buf[15] <= '9' && buf[16] >= '1' && buf[16] <= '9')//确定发来的步数是数字
                    {
                        en = 0;
                        P27 = 1;
                        P26 = 1;
                        P25 = 1;
                        P24 = 0;//D5亮
                    }
                }
            }
        }
    }
    else if(TI == 1)//如果发送数据完毕
    {
        TI = 0;
    }
}

int main()
{
    RI = 0;
    TI = 0;
    TMOD = 0x21;
    SCON = 0x50;
    TH1 = 0xe6;
    TL1 = 0xe6;
    TR1 = 1;
    IE = 0x90;
    while(1)
    {
        ;//采用前后台系统架构
    }
}

我将程序的功能更进一步后, 每次接收到命令时都会将en的值发送回缓冲区PC端(接收). 

#include <STC89C5xRC.H>

char buf[30];//存放串口传来的数据

int i = 0;

int en = 0;

void UART_INT() interrupt 4//串行通信中断处理程序
{
    int len = 0;
    int j = 0;
    if(RI == 1)//如果收到数据
    {
        if(i == 30)
        {
            i = 0;//防止越界访问
        }
        RI = 0;
        buf[i++] = SBUF;//将数据接收下来
        if(buf[i - 1] == 'E')//到达结尾
        {
            len = i - 1;//记录数据长度
            i = 0;
            if(len == 6)
            {
                if(buf[0] == 'S' && buf[1] == 't' && buf[2] == 'a' && buf[3] == 'r' && buf[4] == 't' && buf[5] == '.')
                {
                    //Start命令(开机)
                    en = 1;
                    P27 = 0;//D8亮
                    P26 = 1;
                    P25 = 1;
                    P24 = 1;
                    //再将en的值传回去
                    SBUF = en + 48;
                }
                else if(buf[0] == 'R' && buf[1] == 'e' && buf[2] == 's' && buf[3] == 'e' && buf[4] == 't' && buf[5] == '.')//主转盘回到原始位置,针臂抬到最高位置
                {
                    //Reset命令(复位命令)
                    en = 0;
                    P27 = 1;
                    P26 = 0;//D7亮
                    P25 = 1;
                    P24 = 1;
                    SBUF = en + 48;
                }
            }
            else if(len == 5)//停机命令
            {
                if(buf[0] == 'S' && buf[1] == 't' && buf[2] == 'o' && buf[3] == 'p' && buf[4] == '.')
                {
                    //Stop命令(停机命令)
                    en = 0;
                    P27 = 1;
                    P26 = 1;
                    P25 = 0;//D6亮
                    P24 = 1;
                    SBUF = en + 48;
                }
            }
            else if(len == 18)//要求主转盘转动相应格数
            {
                if(buf[0] == 'M' && buf[1] == 'a' && buf[2] == 'i' && buf[3] == 'n' && buf[4] == ' ' && buf[5] == 'm' && buf[6] == 'o' && buf[7] == 't' && buf[8] == 'o' && buf[9] == 'r' && buf[10] == ' ' && buf[11] == 'r' && buf[12] == 'u' && buf[13] == 'n' && buf[14] == ' ')
                {
                    //Main motor run命令,比如Main motor run 22.
                    if(buf[15] >= '1' && buf[15] <= '9' && buf[16] >= '1' && buf[16] <= '9')//确定发来的步数是数字
                    {
                        en = 0;
                        P27 = 1;
                        P26 = 1;
                        P25 = 1;
                        P24 = 0;//D5亮
                        SBUF = en + 48;
                    }
                }
            }
        }
    }
    else if(TI == 1)//如果发送数据完毕
    {
        TI = 0;
    }
}

int main()
{
    RI = 0;
    TI = 0;
    TMOD = 0x21;
    SCON = 0x50;
    TH1 = 0xe6;
    TL1 = 0xe6;
    TR1 = 1;
    IE = 0x90;
    while(1)
    {
        ;//采用前后台系统架构
    }
}
 

但是由于老师指出该种程序架构不可取, 故以串口中断为主线的控制思路便宣告破产. 虽然该种方案最终未能成功实现, 但是在分析过程中所遇到的问题以及相应的解决方案是值得我们推敲的.

猜你喜欢

转载自blog.csdn.net/weixin_42048463/article/details/93633981