打印

单片机和pc串口助手字符串通信

[复制链接]
3453|12
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
cellagent|  楼主 | 2014-1-9 09:53 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
单片机采用串口中断接收字符串,串口助手发送特殊字符'#'作为字符串结束标志,当单片机串口中断函数中收到'#'时表示接收完成。这种想法,能够轻松编程实现。但是当串口助手想给单片机传'#'时,原程序出现bug,所以尝试串口助手发送字符串以连续的两个#作结束标志,这种想法,通过判断串口中断函数中缓存数组的索引,也能够轻松编程实现。但是,这种情况对不是连续出现的两个#出现了bug。所以,我觉得在字符串结束加特殊字符而通信中又要出现该字符时这种方法不可取。c语言中讲到字符串默认都是以'\0'结束,是自动加的,串口助手发送字符串时是没有加'\0',我想通过自己编写上位机串口助手软件,发送字符串时自动加上'\0',然后单片机串口中断函数通过判断 SBUF == '\0'来作结束。请问这种方式行得通吗? 或者有别的更好的方式。请各位指教一下,谢谢!

相关帖子

沙发
南宫云明| | 2014-1-9 10:04 | 只看该作者
你可以用超时来判断,每当接收到一个字节后,从0开始计数,当计到一定时间(比如20ms),还没有新的字节接收到,就认为超时,判断一帧数据接收完成。

记住,每个字节接收到后腰重新开始计数。。

使用特权

评论回复
板凳
cellagent|  楼主 | 2014-1-9 10:10 | 只看该作者
南宫云明 发表于 2014-1-9 10:04
你可以用超时来判断,每当接收到一个字节后,从0开始计数,当计到一定时间(比如20ms),还没有新的字节接 ...

嗯,我刚想补充的。我有超时判断的程序,能够顺利实现,但是这种方式与在字符串后加特殊字符的方式比起来,反应没那么迅速,而且占用定时器资源,所以我才重新考虑用加特殊字符的方式。谢谢你的回复。:)

使用特权

评论回复
地板
cellagent|  楼主 | 2014-1-9 10:16 | 只看该作者
cellagent 发表于 2014-1-9 10:10
嗯,我刚想补充的。我有超时判断的程序,能够顺利实现,但是这种方式与在字符串后加特殊字符的方式比起来 ...

为了省去每次发送字符串时都主动加#,考虑自己编写上位机软件,将#自动加入到字符串结尾。这样会导致程序的移植性变差,在其它电脑上运行时,必须用自己编写的上位机软件。看来自己想得太简单了,也可见要做到十全十美是多么艰难的事。

使用特权

评论回复
5
cellagent|  楼主 | 2014-1-9 10:30 | 只看该作者
我用的单片机型号是stc12c5a60s2,它具有双串口。串口1使用定时器1作为波特率发生器,串口2使用独立波特率发生器。如果单片机接收字符串用定时器做超时判断,则定时器不够,就算勉强够用,那么其它需要定时器的情况就得不到定时器资源。所以,比较麻烦。

使用特权

评论回复
6
南宫云明| | 2014-1-9 10:47 | 只看该作者
cellagent 发表于 2014-1-9 10:30
我用的单片机型号是stc12c5a60s2,它具有双串口。串口1使用定时器1作为波特率发生器,串口2使用独立波特率 ...

有些功能可以用pca定时器来做

还有如果两个串口的波特率一致的话,两个串口都用独立波特率发生器来做也是可以的

使用特权

评论回复
7
cellagent|  楼主 | 2014-1-9 10:51 | 只看该作者
南宫云明 发表于 2014-1-9 10:47
有些功能可以用pca定时器来做

还有如果两个串口的波特率一致的话,两个串口都用独立波特率发生器来做也 ...

谢谢你的回复,我试试。

使用特权

评论回复
8
cellagent|  楼主 | 2014-1-9 16:50 | 只看该作者
问题解决,谢谢 南宫云明。公司装了加密软件,所以就贴出来了。
time_serial2.h
///////////////////////////////////////////////////////////
/******************************
1) zigbee和单片机通信使用串口2,引脚P1.2-->Rx,P1.3-->Tx,
接收字符串采用定时器1判断是否完成

2) pc和单片机通信使用串口1,引脚P3.0-->Rx,P3.1-->Tx,
接收字符串采用定时器0判断是否完成

3) zigbee和pc串口通信时,引脚对应,
zigbee和单片机串口通信是,引脚交叉

*******************************/
#ifndef        TIME_UART2_H
#define _TIME_UART2_H
#include <stc12c5a60s2.h>
#include <string.h>

#define S2RI 0x01        //串口2接收中断请求标志位
#define S2TI 0x02        //串口2发送中断请求标志位

#define NUMBERS  100

BYTE idata UARTSeflag = 0; //主程序中判断接收完成标志
BYTE idata UARTReflag = 0;
BYTE idata UARTCount = 0;

BYTE idata UART2Seflag = 0; //串口2接收完成
BYTE idata UART2Reflag = 0; //串口2接收完成
BYTE idata UART2Count = 0;



BYTE idata recvs[NUMBERS] = {0};  //串口1缓存数组
BYTE idata recvs2[NUMBERS] = {0};  //串口2缓存数组

void UartInit()           
{
    //尝试两个串口共用独立波特率发生器 可行
        SCON = 0x50;    //串口1工作在方式1  10位异步收发 REN=1允许接收
    S2CON = 0x50;   //串口2工作在方式1  10位异步收发 S2REN=1允许接收

    BRT = 0xF1;           //独立波特率发生器初值        18.432MHz  38400
    AUXR = 0x15;    //BRTR=1 独立波特率发生器开始计数
}

/*************作为超时判断的两定时器初始化********************/
void TimerInit()
{
TMOD = 0x00;//定时器0、1工作于方式1,16位
TH0 = 0x00;
TL0 = 0x00;

TH1 = 0x00;
TL1 = 0x00;
}

/*************定时器和串口初始化********************/
void CpuInit()
{
UartInit();
TimerInit();
//优先级控制  T0 > S1 > T1 > S2
IPH = 0x12; //PSH = 1, PT0H = 1,PT1H = 0
IPH2 = 0x00; //PS2H = 0
//IPH = 0x08;
PT0 = 1;
PS = 0;
PT1 = 1;
IP2        = 0x00; //PS2 = 0


//启动
ET0 = 1;        //开定时0中断
ET1 = 1;        //开定时1中断
ES = 1;         //开串口中断
IE2 = 0x01;        //开串口2中断  ES2=1
EA = 1;  //开启总中断

}

/****************串行口1发送单字符****************/
void UART_1SendOneByte(BYTE c)
{
    SBUF = c;
    while(!TI);           //若TI=0,在此等待
    TI = 0;         
}

/****************串行口1发送字符串****************/   //pc和单片机通信
void UART_1SendString(BYTE * p)
{
BYTE i = 0,n = 0;
ES = 0;
n = strlen(p);
while(i<n)
        {
        UART_1SendOneByte(*p++);
        i++;
        }
ES = 1;
}
/****************串行口2发送单字符****************/
void UART_2SendOneByte(BYTE c)
{
    S2BUF = c;
    while(!(S2CON&S2TI));  //若S2TI=0,在此等待
    S2CON&=~S2TI;          //S2TI=0
}

/****************串行口2发送字符串****************/          //模块和单片机通信
void UART_2SendString(BYTE * p)
{
BYTE i = 0,n = 0;
n = strlen(p);
IE2 =0x00; //关串口2中断
while(i<n)
        {
        UART_2SendOneByte(*p++);
        i++;
        }
//UART_2SendOneByte('#'); //模拟串口助手发送字符串以'#'结束
IE2 =0x01; //开串口2中断
}


/************串行口1中断处理函数*************/
void Uart_ISR() interrupt 4        //仅接收字符会产生中断
{
ES = 0;          //关闭串口中断
TR0 = 1;         //启动定时器0,判断接受是否超时
while(1)
{       
if(RI)            //用查询法接收字符
        {
        RI=0;      //清除中断标志
        recvs[UARTCount] = SBUF;
        UARTCount++;
        TH0 = TL0 = 0x00;
        }
if(UARTReflag)//定时器已经在计时
        {
        UARTSeflag = 1;      //置位串口发送标志,用于主程序中判断接收完成,可以进行发送了
        UARTReflag = 0;     //清除串口接受完成中断标志
        break;
        }
}
ES = 1;      //开启串口中断
}

/***********定时器0中断*****************/
void Timer0_ISR() interrupt 1
{
TR0 = 0;          //关闭定时器0
TH0 = 0x00;
TL0 = 0x00;
UARTReflag = 1;   //置位串口接受完成标志
}

/************串行口2中断处理函数*************/
void UART_2Interrupt(void) interrupt 8
{
IE2 = 0x00;
TR1 = 1;
while(1)
{
if(S2CON&S2RI)         //产生接收中断
        {
        S2CON&=~S2RI;        //清除串口2接收中断标志
        recvs2[UART2Count] = S2BUF;
        UART2Count++;
        TH1 = TL1 = 0x00;
        }
if(UART2Reflag)//定时器已经在计时
        {
        UART2Seflag = 1;      //置位串口发送标志,用于主程序中判断接收完成,可以进行发送了
        UART2Reflag = 0;     //清除串口接受完成中断标志
        break;
        }
}
IE2 = 0x01;
}

/***********定时器1中断*****************/
void Timer1_ISR() interrupt 3
{
TR1 = 0;          //关闭定时器0
TH1 = 0x00;
TL1 = 0x00;
UART2Reflag = 1;   //置位串口接受完成标志
}

void myclean1()
{
UARTSeflag = 0;
UARTCount = 0;
memset(recvs,0,strlen(recvs));
}

void myclean2()
{
UART2Seflag = 0;
UART2Count = 0;
memset(recvs2,0,strlen(recvs));
}
#endif

main.c
//////////////////////////////////////////////////////////
#include "time_serial2.h"

void main(void)
{
CpuInit();
while(1)
        {
        if(UARTSeflag && strcmp(recvs,"from com4") == 0)
                {
                UART_2SendString("com4 to MCU to com1\n");
                myclean1();
                }
        if(UART2Seflag && strcmp(recvs2,"from com1") == 0)
                {
                UART_1SendString("com1 to MCU to com4\n");
                myclean2();
                }       
        }
}

使用特权

评论回复
9
cellagent|  楼主 | 2014-1-9 16:55 | 只看该作者
调试的时候可以不用zigbee模块,直接用串口助手模拟两个串口com1,com4。我应用的场景是:pc+单片机+zigbee模块作为主机,其余单片机+zigbee做从机,只用主机才用到两个串口,从机仅用串口1。

使用特权

评论回复
10
jjjkkk00| | 2014-1-10 09:05 | 只看该作者
用帧头+字节量的帧格式,不就可以解决了么。
其实最好的还是用超时机制,这样相比其他更通用。

使用特权

评论回复
11
cellagent|  楼主 | 2014-1-10 11:46 | 只看该作者
jjjkkk00 发表于 2014-1-10 09:05
用帧头+字节量的帧格式,不就可以解决了么。
其实最好的还是用超时机制,这样相比其他更通用。 ...

对的,最好的方式是超时机制。像其它加输入限制或者指定帧格式都带入了麻烦,而且不通用。:)

使用特权

评论回复
12
cardwell| | 2014-4-11 17:02 | 只看该作者
你好,我在论坛上看到你发的帖子了,我现在想做一个单片机接收字符串的程序,就是用串口助手发送特殊字符作为结束标志的,但是单片机总是多收到一个结束符,而且个人感觉这种方法也缺乏通用性,如果方便的话,你能把超时判断方法的程序给我传一份吗?谢谢了哦,我的邮箱gaotianyu555@163.com

使用特权

评论回复
13
mlmbcsz| | 2015-8-7 11:17 | 只看该作者
关于串口助手的调试总是有问题,用超时也试过好多次 2ms 500us 1ms但都没有成功。我也用过用LCD1602显示从串口助手发送的数据,但顺序不对比喻发送的是的123 显示231,是串口助手问题!请发给我一份超时的程序,我再调试一下!谢谢!邮箱mlmbcsz@163.com

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

19

主题

171

帖子

3

粉丝