搜索
bottom↓
回复: 7

原创环形FIFO及其应用实例SLIP协议解码源码,有图有真相

[复制链接]

出0入0汤圆

发表于 2015-3-31 22:10:46 | 显示全部楼层 |阅读模式
本帖最后由 skyxjh 于 2015-3-31 22:21 编辑

看了坛子里几位大侠写的环形FIFO,觉得太复杂了,于是自己写了一个。
SLIP(Serial Line Interenet Protocol)协议是串行线路网际协议,它实现了在串行通信线路上运行TCP/IP协议及其应用服务的功能,应用非常广泛。
本人写了一个SLIP协议解码函数,支持断点续传,作为环形FIFO应用实例。
全部源代码都有详细注释,保证言简意赅,通俗易懂,好用,管用。

废话少说,上代码:


  1. #include <iom128v.h>
  2. #include <macros.h>

  3. #define true  1
  4. #define false 0
  5. #define FifoSize  64 //fifo原型数组大小(单位:字节)
  6. typedef struct fifo //定义fifo结构体
  7. {
  8.   unsigned char Data[FifoSize]; //原型数组
  9.   unsigned char *IndexIn; //入队游标
  10.   unsigned char *IndexOut; //出队游标
  11.   unsigned char Empty; //空标志
  12.   unsigned char Full; //满标志
  13.   unsigned int Len; //队列有效数据长度
  14. } FIFO; //定义fifo结构体类型FIFO

  15. #define SlipSize 64 //slip原型数组大小(单位:字节)
  16. typedef struct slip //定义slip结构体
  17. {
  18.   unsigned char Data[SlipSize]; //原型数组
  19.   unsigned int Index; //当前解码数据游标
  20.   unsigned int Len; //解码出来的有效数据包长度
  21. } SLIP; //定义slip结构体类型SLIP

  22. unsigned char startrxd[] = "rxd:"; //字符串在内存里以0x00结尾,便于调试时查找变量位置
  23. unsigned char rxd[] = //模拟接收到的数据流
  24.   {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};
  25. unsigned char startrxbuf[] = "rxfifo:"; //字符串在内存里以0x00结尾,便于调试时查找变量位置
  26. FIFO rxbuf = {{0},0}; //定义接收fifo并初始化,在内存里固定位置(紧跟"rxfifo:"字符串后),便于调试时查找
  27. unsigned char startdatbuf[] = "datbuf:"; //字符串在内存里以0x00结尾
  28. SLIP datbuf= {{0},0}; //定义解码数据区并初始化,在内存里固定位置(紧跟"datbuf:"字符串后),便于调试时查找

  29. void fifoInit(FIFO *Fifo) //fifo初始化(fifo必须初始化才能使用)
  30. {
  31.   CLI(); //关中断
  32.   Fifo->IndexIn = Fifo->Data; //入队游标指向原型数组起始地址
  33.   Fifo->IndexOut = Fifo->Data; //出队游标指向原型数组起始地址
  34.   Fifo->Empty = true; //设置fifo空标志
  35.   Fifo->Full = false; //清除fifo满标志
  36.   Fifo->Len = 0; //设置fifo有效数据长度为0字节
  37.   SEI(); //开中断
  38. }

  39. unsigned char fifoIn(FIFO *Fifo,unsigned char x) //fifo写入
  40. {
  41.   CLI(); //关中断
  42.   if(Fifo->Full == true) return false; //fifo满则返回(写入失败)
  43.   *(Fifo->IndexIn) = x; //写入1字节数据
  44.   (Fifo->Len)++; //fifo有效数据长度计数
  45.   if(Fifo->IndexIn < (Fifo->Data + FifoSize - 1)) (Fifo->IndexIn)++; //写入游标调整
  46.   else Fifo->IndexIn = Fifo->Data; //写入游标向上越界则回到起点
  47.   if(Fifo->IndexIn == Fifo->IndexOut) Fifo->Full = true; //写游标追上读游标则置fifo满标志
  48.   Fifo->Empty = false; //清除fifo空标志
  49.   SEI(); //开中断
  50.   return true; //返回(写入成功)
  51. }

  52. unsigned char fifoOut(FIFO *Fifo,unsigned char *x) //fifo读出
  53. {
  54.   CLI(); //关中断
  55.   if(Fifo->Empty == true) return false; //fifo空则返回(读出失败)
  56.   *x = *(Fifo->IndexOut); //读出1字节数据
  57.   (Fifo->Len)--; //fifo有效数据长度计数
  58.   if(Fifo->IndexOut < (Fifo->Data + FifoSize - 1)) (Fifo->IndexOut)++; //读出游标调整
  59.   else Fifo->IndexOut = Fifo->Data; //读出游标向上越界则回到起点
  60.   if(Fifo->IndexOut == Fifo->IndexIn) Fifo->Empty = true; //读游标追上写游标则置fifo满标志
  61.   Fifo->Full = false; //清除fifo满标志
  62.   SEI(); //开中断
  63.   return true; //返回(读出成功)
  64. }

  65. //SLIP帧格式:帧头尾0xC0,转义字符0xDB,(0xDB 0xDC):0xC0,(0xDB 0xDD):0xDB
  66. unsigned char slipDecode(FIFO *rbuf,SLIP *dbuf) //SLIP协议解码
  67. {
  68.   static unsigned char findhead = false; //首次运行,设置未找到帧头(支持断点续传)
  69.   unsigned char tmp; //数据缓存
  70.   if(findhead == false) dbuf->Index = 0; //未找到帧头时游标复位(支持断点续传)
  71.   dbuf->Len = 0; //每次运行时数据包长度复位
  72.   while(1) //遍历已接收数据,直到解码出一帧数据或处理完全部数据
  73.   {
  74.     if(fifoOut(rbuf,&tmp) == false) return false; //读取1字节数据
  75.     if(tmp == 0xC0) //找到帧头或帧尾
  76.     {
  77.       if(findhead == false) findhead = true; //找到帧头
  78.       else if(dbuf->Index == 0) ; //找到帧头(连续两个0xC0)
  79.       else //找到帧尾
  80.       {
  81.         dbuf->Len = dbuf->Index; //解码出来的数据长度
  82.         dbuf->Index = 0; //游标复位
  83.         findhead = false; //准备找下一帧数据
  84.         return true; //返回一帧数据
  85.       }
  86.     }
  87.     else if(findhead == true) //找到帧头则解码数据
  88.     {
  89.       if(tmp == 0xDB) //找到转义字符
  90.       {
  91.         if(fifoOut(rbuf,&tmp) == false) return false; //读下1字节数据
  92.         if(tmp == 0xDC) //转义数据0xC0
  93.         {
  94.           *(dbuf->Data + dbuf->Index) = 0xC0; //记录1字节数据
  95.           (dbuf->Index)++; //游标调整
  96.         }
  97.         else if(tmp == 0xDD) //转义数据0xDB
  98.         {
  99.           *(dbuf->Data + dbuf->Index) = 0xDB; //记录1字节数据
  100.           (dbuf->Index)++; //游标调整
  101.         }
  102.         else //收到非法字符(数据无效)
  103.         {
  104.           dbuf->Index = 0; //游标复位
  105.           findhead = false; //重新找帧头
  106.         }
  107.       }
  108.       else //找到普通字符
  109.       {
  110.         *(dbuf->Data + dbuf->Index) = tmp; //记录1字节数据
  111.         (dbuf->Index)++; //游标调整
  112.       }
  113.     }
  114.     else ; //没找到帧头则继续找帧头
  115.   }
  116.   return false; //意外返回
  117. }

  118. void rx(unsigned char *rxd,unsigned int n,FIFO *rxbuf) //模拟接收数据,用于调试
  119. {
  120.   while(n--) //一次接收n字节数据
  121.   {
  122.     fifoIn(rxbuf,*rxd++); //将接收到的数据写入fifo
  123.   }
  124. }

  125. void main(void) //调试程序,用PROTEUS查看器件内存
  126. {
  127.   fifoInit(&rxbuf); //fifo初始化
  128.   rx(rxd,9,&rxbuf); //接收9字节数据
  129.   slipDecode(&rxbuf,&datbuf); //SLIP解码
  130.   rx(rxd+9,9,&rxbuf); //接收9字节数据
  131.   slipDecode(&rxbuf,&datbuf); //SLIP解码
  132.   rx(rxd+18,9,&rxbuf); //接收9字节数据
  133.   slipDecode(&rxbuf,&datbuf); //SLIP解码,断点续传后解码出第1帧数据11字节
  134.   rx(rxd+27,4,&rxbuf); //接收4字节数据
  135.   //slipDecode(&rxbuf,&datbuf); //SLIP解码,解码出第2帧数据2字节
  136. }
复制代码


本实例在PROTEUS软件上验证通过。方法是运行PROTEUS软件,添加ATMEGA128器件,设置M128的program file为本实例编译出来的slip.hex文件,点击运行后点暂停,再点Debug菜单里的AVR Data Memory就可以看到内存数据。

断点续传解码出第1帧数据,请看下图:


将主函数里最后一条注释取消后,解码出第2帧数据,请看下图:


有任何不当之处请批评指正!

欢迎交流使用心得!

转载请注明出外!

编辑原因:调整代码缩进。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

发表于 2015-3-31 22:42:37 | 显示全部楼层
对SLIP协议没有了解,但是看到在操作函数的时候有关中断和开中断,是为了防止被打断是吧,看到一些FIFO没有这样子做

出0入0汤圆

 楼主| 发表于 2015-3-31 23:50:11 | 显示全部楼层
关中断是保证数据不会出错最保险也是最简单的办法。

出0入0汤圆

 楼主| 发表于 2015-4-1 00:05:10 | 显示全部楼层
我这里简化了,实际上应该先判断中断是否是开启状态,如果是,则关中断,返回前再开中断;如果检测到中断是关闭状态,就不用关中断了。因为检测中断开关状态与MCU型号有关,所以我这里简化操作了。

出200入0汤圆

发表于 2015-4-3 10:57:37 来自手机 | 显示全部楼层
感谢分享,收藏

出0入0汤圆

发表于 2015-5-18 14:36:58 | 显示全部楼层
Line67 应该是 //读游标追上写游标则置fifo空标志

出0入0汤圆

 楼主| 发表于 2015-5-19 19:25:48 | 显示全部楼层
Lagrange1759 发表于 2015-5-18 14:36
Line67 应该是 //读游标追上写游标则置fifo空标志

谢谢,注释错了,复制上面的忘改了

出0入0汤圆

发表于 2016-3-24 22:10:57 | 显示全部楼层
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-6-1 08:27

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表