51串口通信C封装

经过各种折腾,各种实验,总结出一个结论:中断代码必须要尽可能的简短,要尽快的返回,否则的话,影响下一次中断,任何中断都应该这样,串口中断尤甚!!比如,要做一个复杂点的通信协议,如果把协议解析放到中断里来,代码倒是容易写了:

onRecvByte() interrupt 4 using 1
{
    if( RI )
    {
           UCHAR rec = SBUF;
           //  进入又穷自动状态机解析收到的数据
           parseCommand( rec );  // 耗时较长
    }
}
但是,由于parseCommand耗时较长,导致中断未处理完,下次收不到数据了!!因为上位机发来的数据很快,两次数据发送时间间隔小于中断返回的时间,所以就会丢失数据。。

研究了一阵子网上的代码,没找到什么很实用的,尤其是对缓冲区的使用,真正的大神也不屑于写这些,新手文章倒是不少,没什么参考价值,还是自己动手吧。下面是成果(经测试,最高速率,发送几K字节无一丢失),记录在此以备查:


/**
 *  serial.h
 *  CopyLeft 2017.3 HeXu
**/
#ifndef HX_SERIAL
#define HX_SERIAL 1

#include "../myInc/hxcomm.h"

#define READ_BUFFER_SIZE	32                        // 定义缓冲区大小

typedef void ( * HXCALLBACK_ONRECV ) ( BYTE uData );      // 回调函数指针

// 初始化
void hxInitSerial();

// 发送一串数据;pDatas指向一个缓冲区,uCount指明尺寸
void hxSendBytes( LPBYTE pDatas, UINT uCount );

// 发送一个字节
void hxSendByte( BYTE uData );

// 放到循环里,检查是否收到数据,如果收到数据,就会调用回调函数。
// 如果没有数据,或者数据正常,返回true,如果缓冲区满了,返回false
BOOL hxLoopReadOneByte( HXCALLBACK_ONRECV lpfnCallBack );

#endif

/**
 *  serial.c
 *  Copy Left 2017.3 HeXu
**/
#include "hxserial.h"

BYTE g_zBuff[ READ_BUFFER_SIZE ];

char g_nReadIndex;
char g_nWriteIndex;

bit	g_bBusy;
bit g_bError;

void hxInitSerial()
{
	g_nReadIndex = 0;
	g_nWriteIndex = 0;
	g_bBusy = 0;
	g_bError = 0;
	
	SCON = 0x50;	//8位数据,可变波特率
	AUXR |= 0x01;	//串口1选择定时器2为波特率发生器
	AUXR |= 0x04;	//定时器2时钟为Fosc,即1T
	T2L = 0xCC;		//设定定时初值
	T2H = 0xFF;		//设定定时初值
	AUXR |= 0x10;	//启动定时器2
	
	ES = 1;
}

void hxSendByte( BYTE uData )
{
	while( g_bBusy );   // 等待上次发送完成
	g_bBusy = 1;        // 标志正在发送
	SBUF = uData;
}

void hxSendBytes( LPBYTE pDatas, UINT uCount )
{
	while( uCount > 0 )
	{
		hxSendByte( * pDatas ++ );
		--uCount;
	}
}

void hxOnSerialRecv() interrupt 4 using 1
{
	char tIndex;
	if( RI )
	{
		RI = 0;
		tIndex = ( g_nWriteIndex + 1 ) % READ_BUFFER_SIZE;
		if( tIndex == g_nReadIndex )  // 如果缓冲区已满
		{
			g_bError = 1;
			ES = 0;
		}
		else
		{
			g_zBuff[ g_nWriteIndex ] = SBUF;
			g_nWriteIndex = tIndex;
		}
	}
	if( TI )
	{
		TI = 0;
		g_bBusy = 0;  // 标志发送已完成
	}
}

BOOL hxLoopReadOneByte( HXCALLBACK_ONRECV lpfnCallBack )
{
	if( g_bError )
		return FALSE;
	else {
		while( g_nReadIndex != g_nWriteIndex )  // 一直处理收到的数据,直到缓冲区为空。
		{
			lpfnCallBack( g_zBuff[ g_nReadIndex ] );
			g_nReadIndex = ( g_nReadIndex + 1 ) % READ_BUFFER_SIZE;
		}
		return TRUE;
	}
}

测试程序:

#include "hxserial.h"
#include <intrins.h>

void hxRecv( BYTE uData )
{
	hxSendByte( uData );
}

void main()
{
	hxInitSerial();
	EA = 1;
	
	while( 1 )
	{
		if(  ! hxLoopReadOneByte( hxRecv )) // 如果对方发送数据太快(缓冲区已满)
		{
			ES = 0;
			_nop_();
			_nop_();
			hxInitSerial();
			hxSendBytes( "哥们,你发送太快了。", 20 );
		}
	}
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

示申○言舌

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值