|
本帖最后由 skyxjh 于 2015-3-31 22:21 编辑
看了坛子里几位大侠写的环形FIFO,觉得太复杂了,于是自己写了一个。
SLIP(Serial Line Interenet Protocol)协议是串行线路网际协议,它实现了在串行通信线路上运行TCP/IP协议及其应用服务的功能,应用非常广泛。
本人写了一个SLIP协议解码函数,支持断点续传,作为环形FIFO应用实例。
全部源代码都有详细注释,保证言简意赅,通俗易懂,好用,管用。
废话少说,上代码:
- #include <iom128v.h>
- #include <macros.h>
- #define true 1
- #define false 0
- #define FifoSize 64 //fifo原型数组大小(单位:字节)
- typedef struct fifo //定义fifo结构体
- {
- unsigned char Data[FifoSize]; //原型数组
- unsigned char *IndexIn; //入队游标
- unsigned char *IndexOut; //出队游标
- unsigned char Empty; //空标志
- unsigned char Full; //满标志
- unsigned int Len; //队列有效数据长度
- } FIFO; //定义fifo结构体类型FIFO
- #define SlipSize 64 //slip原型数组大小(单位:字节)
- typedef struct slip //定义slip结构体
- {
- unsigned char Data[SlipSize]; //原型数组
- unsigned int Index; //当前解码数据游标
- unsigned int Len; //解码出来的有效数据包长度
- } SLIP; //定义slip结构体类型SLIP
- unsigned char startrxd[] = "rxd:"; //字符串在内存里以0x00结尾,便于调试时查找变量位置
- unsigned char rxd[] = //模拟接收到的数据流
- {1,0xDB,0xDC,3,4,0xDB,0xDD,6,0xC0,0xC0,9,0,1,0xDB,0xDC,3,4,0xDB,0xDD,6,7,8,9,0xC0,0xC0,1,2,0xC0,0xC0,1,2};
- unsigned char startrxbuf[] = "rxfifo:"; //字符串在内存里以0x00结尾,便于调试时查找变量位置
- FIFO rxbuf = {{0},0}; //定义接收fifo并初始化,在内存里固定位置(紧跟"rxfifo:"字符串后),便于调试时查找
- unsigned char startdatbuf[] = "datbuf:"; //字符串在内存里以0x00结尾
- SLIP datbuf= {{0},0}; //定义解码数据区并初始化,在内存里固定位置(紧跟"datbuf:"字符串后),便于调试时查找
- void fifoInit(FIFO *Fifo) //fifo初始化(fifo必须初始化才能使用)
- {
- CLI(); //关中断
- Fifo->IndexIn = Fifo->Data; //入队游标指向原型数组起始地址
- Fifo->IndexOut = Fifo->Data; //出队游标指向原型数组起始地址
- Fifo->Empty = true; //设置fifo空标志
- Fifo->Full = false; //清除fifo满标志
- Fifo->Len = 0; //设置fifo有效数据长度为0字节
- SEI(); //开中断
- }
- unsigned char fifoIn(FIFO *Fifo,unsigned char x) //fifo写入
- {
- CLI(); //关中断
- if(Fifo->Full == true) return false; //fifo满则返回(写入失败)
- *(Fifo->IndexIn) = x; //写入1字节数据
- (Fifo->Len)++; //fifo有效数据长度计数
- if(Fifo->IndexIn < (Fifo->Data + FifoSize - 1)) (Fifo->IndexIn)++; //写入游标调整
- else Fifo->IndexIn = Fifo->Data; //写入游标向上越界则回到起点
- if(Fifo->IndexIn == Fifo->IndexOut) Fifo->Full = true; //写游标追上读游标则置fifo满标志
- Fifo->Empty = false; //清除fifo空标志
- SEI(); //开中断
- return true; //返回(写入成功)
- }
- unsigned char fifoOut(FIFO *Fifo,unsigned char *x) //fifo读出
- {
- CLI(); //关中断
- if(Fifo->Empty == true) return false; //fifo空则返回(读出失败)
- *x = *(Fifo->IndexOut); //读出1字节数据
- (Fifo->Len)--; //fifo有效数据长度计数
- if(Fifo->IndexOut < (Fifo->Data + FifoSize - 1)) (Fifo->IndexOut)++; //读出游标调整
- else Fifo->IndexOut = Fifo->Data; //读出游标向上越界则回到起点
- if(Fifo->IndexOut == Fifo->IndexIn) Fifo->Empty = true; //读游标追上写游标则置fifo满标志
- Fifo->Full = false; //清除fifo满标志
- SEI(); //开中断
- return true; //返回(读出成功)
- }
- //SLIP帧格式:帧头尾0xC0,转义字符0xDB,(0xDB 0xDC):0xC0,(0xDB 0xDD):0xDB
- unsigned char slipDecode(FIFO *rbuf,SLIP *dbuf) //SLIP协议解码
- {
- static unsigned char findhead = false; //首次运行,设置未找到帧头(支持断点续传)
- unsigned char tmp; //数据缓存
- if(findhead == false) dbuf->Index = 0; //未找到帧头时游标复位(支持断点续传)
- dbuf->Len = 0; //每次运行时数据包长度复位
- while(1) //遍历已接收数据,直到解码出一帧数据或处理完全部数据
- {
- if(fifoOut(rbuf,&tmp) == false) return false; //读取1字节数据
- if(tmp == 0xC0) //找到帧头或帧尾
- {
- if(findhead == false) findhead = true; //找到帧头
- else if(dbuf->Index == 0) ; //找到帧头(连续两个0xC0)
- else //找到帧尾
- {
- dbuf->Len = dbuf->Index; //解码出来的数据长度
- dbuf->Index = 0; //游标复位
- findhead = false; //准备找下一帧数据
- return true; //返回一帧数据
- }
- }
- else if(findhead == true) //找到帧头则解码数据
- {
- if(tmp == 0xDB) //找到转义字符
- {
- if(fifoOut(rbuf,&tmp) == false) return false; //读下1字节数据
- if(tmp == 0xDC) //转义数据0xC0
- {
- *(dbuf->Data + dbuf->Index) = 0xC0; //记录1字节数据
- (dbuf->Index)++; //游标调整
- }
- else if(tmp == 0xDD) //转义数据0xDB
- {
- *(dbuf->Data + dbuf->Index) = 0xDB; //记录1字节数据
- (dbuf->Index)++; //游标调整
- }
- else //收到非法字符(数据无效)
- {
- dbuf->Index = 0; //游标复位
- findhead = false; //重新找帧头
- }
- }
- else //找到普通字符
- {
- *(dbuf->Data + dbuf->Index) = tmp; //记录1字节数据
- (dbuf->Index)++; //游标调整
- }
- }
- else ; //没找到帧头则继续找帧头
- }
- return false; //意外返回
- }
- void rx(unsigned char *rxd,unsigned int n,FIFO *rxbuf) //模拟接收数据,用于调试
- {
- while(n--) //一次接收n字节数据
- {
- fifoIn(rxbuf,*rxd++); //将接收到的数据写入fifo
- }
- }
- void main(void) //调试程序,用PROTEUS查看器件内存
- {
- fifoInit(&rxbuf); //fifo初始化
- rx(rxd,9,&rxbuf); //接收9字节数据
- slipDecode(&rxbuf,&datbuf); //SLIP解码
- rx(rxd+9,9,&rxbuf); //接收9字节数据
- slipDecode(&rxbuf,&datbuf); //SLIP解码
- rx(rxd+18,9,&rxbuf); //接收9字节数据
- slipDecode(&rxbuf,&datbuf); //SLIP解码,断点续传后解码出第1帧数据11字节
- rx(rxd+27,4,&rxbuf); //接收4字节数据
- //slipDecode(&rxbuf,&datbuf); //SLIP解码,解码出第2帧数据2字节
- }
复制代码
本实例在PROTEUS软件上验证通过。方法是运行PROTEUS软件,添加ATMEGA128器件,设置M128的program file为本实例编译出来的slip.hex文件,点击运行后点暂停,再点Debug菜单里的AVR Data Memory就可以看到内存数据。
断点续传解码出第1帧数据,请看下图:
将主函数里最后一条注释取消后,解码出第2帧数据,请看下图:
有任何不当之处请批评指正!
欢迎交流使用心得!
转载请注明出外!
编辑原因:调整代码缩进。 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
你熬了10碗粥,别人一桶水倒进去,淘走90碗,剩下10碗给你,你看似没亏,其实你那10碗已经没有之前的裹腹了,人家的一桶水换90碗,继续卖。说白了,通货膨胀就是,你的钱是挣来的,他的钱是印来的,掺和在一起,你的钱就贬值了。
|