打印
[8/16-bit MCU]

单片机之串口数据处理

[复制链接]
777|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
Beckham_Owen|  楼主 | 2015-12-31 08:27 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
随着硬件系统的模块化发展,很多电子产品都做出模块并采用串口进行数据通信。例如:GPRS模块、GPS模块、语音模块、热敏微型打印机、串口摄像头等等。在与这些模块进行数据通信都离不开串口,而对于串口的操作,由于串口本身没有标准的通信协议,所以很难做到非常统一的操作过程。一般来说,不同的模块其有着特殊的通信协议,我们只能根据其协议进行数据解码。

      虽然说串口没有标准协议,但是我们却可以把它们的相似部分提取出来,做成模块化的程序,方便代码的移植和理解。下面我们简单谈到串口数据的处理方法。。。。。

相关帖子

沙发
Beckham_Owen|  楼主 | 2015-12-31 08:30 | 只看该作者
这部分代码为应用代码

为了保证数据的相对独立和模块化,下面代码将写入应用代码中,和上面的程序不能放在相同的文件中。

1. 数据定义

     首先需要定义一个缓冲区,这个缓冲区的大小根据实际应用定义,其大小一般为数据帧的最大值的2倍。之后需要定义一个DF_RCV数据,在这个数据中需要初始化这个结构图的参数。特别需要注意,缓冲的大小,和缓冲区指针赋值。
u8 AU_Buf[AU_BUF_ZISE] = {0};
DF_RCV AU_Rvc = {0, 0, AU_BUF_ZISE, AU_Buf};

使用特权

评论回复
板凳
Beckham_Owen|  楼主 | 2015-12-31 08:31 | 只看该作者
2. 编写数据接收函数

    本函数把串口数据放入缓冲区中,此函数必须在串口中断中调用。
/**************************************************************************************
* FunctionName   : AURcvDat()
* Description    : 串口数据接收(串口中断服务调用)
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
void AURcvDat(u8 dat)
{
    DFWriteByte(dat, &AU_Rvc);
}

使用特权

评论回复
地板
Beckham_Owen|  楼主 | 2015-12-31 08:32 | 只看该作者
3. 数据处理函数

    本函数判断缓冲区中是否有数据,如果有,逐个读取并处理。
/**************************************************************************************
* FunctionName   : AUTaskCtrl()
* Description    : 通信数据处理
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
void AUTaskCtrl(void)
{
    u8  tmpDat;
    u16 i, len = 0;
    static u8 sendMark = 0;

    len = DFGetLen(&AU_Rvc);                                                    // 获取未读数据长度
    for (i=0; i < len; i++)
    {
        tmpDat = DFReadByte(&AU_Rvc);                                           // 读一字节数据
        AU_PrcRcvDat(tmpDat);
    }
}

使用特权

评论回复
5
Beckham_Owen|  楼主 | 2015-12-31 08:32 | 只看该作者
一般来说,串口数据的接收都是采用中断方式,中断中只复制把串口发送的数据放入数据缓冲区中。而发送一般都是采用查询方式比较方便。不管是与什么设备通信,这一点完全是一致的。所以,我们完全可以把这部分代码独立起来。

定义数据结构如下:
typedef struct 
{
    u16 WtCnt; // 写指针
    u16 RdCnt;// 读指针
    u16 BufLen;缓冲尺寸
    u8  *RwBuf;// 读写缓冲

} DF_RCV;

使用特权

评论回复
6
Beckham_Owen|  楼主 | 2015-12-31 08:33 | 只看该作者
对于这个结构来说非常简单,参数1是用于结束数据计数,参数2为处理数据计数,参数3为缓冲的大小,参数4为缓冲区指针,这里用指针是为了保证这个结构的独立,否则无法满足各种需求。
实现函数:

1. 初始化函数

    本函数用于对串口结构体中的各种数据进行初始化。

使用特权

评论回复
7
Beckham_Owen|  楼主 | 2015-12-31 08:34 | 只看该作者
/**************************************************************************************
* FunctionName   : DFInit()
* Description    : 初始化
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
void DFInit(DF_RCV *pRcv)
{
    u16 i;
   
    pRcv->WtCnt = 0x0000;
    pRcv->RdCnt = 0x0000;
   
    for (i=0; iBufLen; i++)
    {
        pRcv->RwBuf[i] = 0x00;
    }
}

使用特权

评论回复
8
Beckham_Owen|  楼主 | 2015-12-31 08:35 | 只看该作者
2. 接收一字节数据

    本函数用于把串口中断接收的数据放入数据缓冲区中,并且接收计数器加1.
/**************************************************************************************
* FunctionName   : DFWriteByte()
* Description    : 数据接收(接收中断调用)
* EntryParameter : None
* ReturnValue    : None
**************************************************************************************/
void DFWriteByte(u8 dat, DF_RCV *pRcv)
{
    pRcv->RwBuf[pRcv->WtCnt] = dat;                                                    // 数据存入
   
    if (++(pRcv->WtCnt) >= pRcv->BufLen)                                            // 缓冲判断
    {
        pRcv->WtCnt = 0;
    }
}

使用特权

评论回复
9
Beckham_Owen|  楼主 | 2015-12-31 08:36 | 只看该作者
3. 读取一字节数据

    本函数用于从接收缓冲区中读取未处理的一字节数据,读计数器加1.
/**************************************************************************************
* FunctionName   : DFReadByte()
* Description    : 从接受缓冲中读取一字节数据
* EntryParameter : None
* ReturnValue    : 返回读取数据
**************************************************************************************/
u8 DFReadByte(DF_RCV *pRcv)
{
    u8 val = 0x00;
   
    val = pRcv->RwBuf[pRcv->RdCnt];                                             // 读取一字节
    if (++(pRcv->RdCnt) >= pRcv->BufLen)
    {
        pRcv->RdCnt = 0;                                                        // 清零
    }
   
    return val;                                                                   // 返回数据
}

使用特权

评论回复
10
Beckham_Owen|  楼主 | 2015-12-31 08:37 | 只看该作者
4. 获取缓冲区中未处理数据的长度

    本函数用于读取串口缓冲区中还未处理的数据的大小。
/**************************************************************************************
* FunctionName   : DFGetLen()
* Description    : 获取缓冲区中未读数据长度
* EntryParameter : None
* ReturnValue    : 返回数据长度
**************************************************************************************/
u16 DFGetLen(DF_RCV *pRcv)
{
    return ((pRcv->WtCnt >= pRcv->RdCnt) ? ((pRcv->WtCnt - pRcv->RdCnt)) :
           ((pRcv->WtCnt + pRcv->BufLen) - pRcv->RdCnt));
}

使用特权

评论回复
11
Beckham_Owen|  楼主 | 2015-12-31 08:37 | 只看该作者
有了以上几个函数,串口的处理就非常简单了。这几个函数可以应用到任何串口中,也可以应用到任务微处理器上,一致非常简单,应用也非常方便。下面我们说说实际的应用。
函数AU_PrcRcvDat(tmpDat)是数据处理函数,首先是数据帧判断,如果是一帧数据,就进行相应操作,并把操作结果返回。了解了这个过程,串口的编程就变得非常简单。而且我们在读程序时,只要看懂一个串口处理过程,其他串口的程序就自然懂了,非常方便吧。

使用特权

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

本版积分规则

32

主题

234

帖子

1

粉丝