搜索
bottom↓
回复: 14

分享一个平时用的接收缓冲+缓冲处理回调函数的结构

  [复制链接]

出0入0汤圆

发表于 2014-4-21 11:37:52 | 显示全部楼层 |阅读模式
本帖最后由 nome 于 2014-4-21 13:55 编辑

功能简介:
        实现一个数据流(笔者用于串口)的接收缓冲,然后在cpu空闲的时候处理这些数据流,一般数据流有特定的格式,以便于程序分割命令和参数。

本文使用的是类似linxu shell的可见字符串。实际使用中也可以更改为16进制数据。


使用环境示例:
        串口接收函数调用write_queue();插入上位机输入的数据。程序通过调用read_queue()获取数据。

  1. /*
  2.         queue.c
  3.         --实现功能:定义一个环形消息队列,实现1.读一个字节 2.插入一个字节 3.取出一条命令。
  4.         ----------  命令格式定义:cmd prama\r    获取命令依照" "区分命令和参数,依照"\r"区分结尾。


  5.         author:nome
  6.         date  :2014/4/18


  7. */


  8. #include "string.h"
  9. #include "queue.h"


  10. #define Q_LEN 100           //队列长度

  11. #define TIMEOUT 900000      

  12. char strqueue[Q_LEN];       //队列数组



  13. int write = 0;               //写偏移
  14. int read = 0;                                                                //读偏移




  15. /*
  16. * 功能:从队列中读取一个字节
  17. * 失败:返回-1
  18. * 成功:返回0
  19. */
  20. char read_queue(char *pdata)
  21. {
  22.         if(write==read)
  23.                 return -1;               
  24.         *pdata = strqueue[read];
  25.         read = (read+1)%Q_LEN;
  26.         return 0;
  27. }
  28. /*
  29. * 功能:往队列中写入一个字节
  30. * 失败:返回-1
  31. * 成功:返回0
  32. */
  33. char write_queue(char data)
  34. {
  35.         if((write+1)%Q_LEN==read)
  36.                 return -1;
  37.         strqueue[write] = data;
  38.         write = (write+1)%Q_LEN;
  39.         return 0;
  40. }


  41. /*
  42. * 功能:从队列中取出一个完整的字符串命令。
  43. * 失败:返回-1
  44. * 成功:返回0
  45. *cmd 存放命令的指针,param 存放参数的指针。
  46. */
  47. int get_q_string(char *cmd,char *param)
  48. {
  49.         int i = 0;
  50.         int timeout = 0;
  51.         char data;
  52.         if(read_queue(&data)) //查看队列中是否有数据,没有数据返回,有数据等待接收完整命令。
  53.                 return -1;
  54.         cmd[i++] = data;
  55.         for(;;){
  56.                 if(0==read_queue(&cmd[i]))
  57.                         i++;
  58.                 if(cmd[i-1]==' ')
  59.                         break;
  60.                 if(timeout>TIMEOUT)
  61.                         return -1;
  62.                 timeout++;
  63.         }
  64.         cmd[i] = 0; //提供一个cmd结束符
  65.         timeout = 0;
  66.         i = 0;
  67.         for(;;){
  68.                 if(0==read_queue(&param[i]))
  69.                         i++;
  70.                 if(param[i-1]=='\r')
  71.                         break;
  72.                 if(timeout>TIMEOUT)
  73.                         return -1;
  74.                         timeout++;               
  75.         }
  76.         param[i-1] = 0; //去掉\r 换成结束符
  77.         return 0;
  78. }
复制代码


下面一个.c和一个.h用于处理上面.c取出的字符串。
  1. #ifndef _USART_CMD_H
  2. #define _USART_CMD_H




  3. struct _cmd_list{
  4.         char *cmd;
  5.         void (*func)(char *param);
  6. };

  7. #define CMD_CALLBACK_LIST_BEGIN struct _cmd_list cmd_list[] = {NULL,null,
  8. #define CMD_CALLBACK_LIST_END NULL,NULL};
  9. #define CMD_CALLBACK(cmd_string,callback)        cmd_string,callback,



  10. #endif
复制代码

  1. #include "queue.h"
  2. #include "string.h"
  3. #include "math.h"
  4. #include "stdio.h"
  5. #include "usart_cmd.h"


  6. extern void usart_sendstring(char *str); //定义一个串口发送字符串的函数

  7. //字符串转int
  8. int str_to_int(char *str)
  9. {
  10.         int i = 0,j = 0;
  11.         int ret = 0;
  12.         for(;;){
  13.         if(str[i++]==0||i>20)
  14.                 break;
  15.         }
  16.         j = i = i-2;
  17.         for(;i>=0;i--)
  18.         {
  19.                 ret += (str[i]-'0')*(pow(10,(j-i)));
  20.         }
  21.         return ret;
  22. }

  23. /********************一些回调函数 不必在意*****************************/
  24. void setfreq(char *param)
  25. {
  26. SX1276LoRaSetRFFrequency(str_to_int(param));   
  27.                                                                                                 memset(param,0,32);
  28.                                                                                                 sprintf(param,"setfreq ok! freq=%d\r\n",SX1276LoRaGetRFFrequency());   
  29.                                                                                                 usart_sendstring(param);         
  30. }

  31. extern int send_receive_flag ;
  32. extern int packet_num ;

  33. void send(char *param)
  34. {
  35.         send_receive_flag = 0;
  36.         packet_num = str_to_int(param);
  37. }

  38. void receive(char *param)
  39. {
  40.         send_receive_flag = 1;
  41. }

  42. void null(char *param)
  43. {}
  44. /********************一些回调函数 不必在意*****************************/       

  45. //在此处添加你的命令字符串和回调函数
  46. CMD_CALLBACK_LIST_BEGIN

  47. CMD_CALLBACK("setfreq",setfreq)
  48. CMD_CALLBACK("send",send)
  49. CMD_CALLBACK("receive",receive)



  50. CMD_CALLBACK_LIST_END






  51. char cmd[10];
  52. char param[32];
  53. int get_cmd(void)
  54. {
  55.         int i = 0;
  56.         if(get_q_string(cmd,param))
  57.                 return 0;
  58.         for(;;){
  59.                 if(strcmp(cmd,cmd_list[i].cmd)==0)
  60.                         return i;       
  61.                 if(cmd_list[++i].cmd==NULL)
  62.                         return 0;
  63.         }
  64. }



  65. //这个函数需要在main函数中轮询调用
  66. void dispose_cmd(void)
  67. {
  68.         cmd_list[get_cmd()].func(param);
  69. }
复制代码

出0入0汤圆

发表于 2014-4-21 12:38:27 | 显示全部楼层
学习一下。。

出0入0汤圆

发表于 2014-4-21 12:59:01 | 显示全部楼层
谢谢楼主,很有用

出0入0汤圆

发表于 2014-4-21 12:59:57 | 显示全部楼层
学习学习

出0入0汤圆

发表于 2015-10-7 11:54:06 | 显示全部楼层
学习一下

出0入10汤圆

发表于 2016-4-22 16:08:00 | 显示全部楼层
学习,感谢分享

出0入0汤圆

发表于 2016-4-24 06:25:26 | 显示全部楼层
格式定义太死吧,协议中就会有0x20怎么搞?

出0入0汤圆

 楼主| 发表于 2016-4-24 17:47:54 | 显示全部楼层
zyw19987 发表于 2016-4-24 06:25
格式定义太死吧,协议中就会有0x20怎么搞?

  这个是借鉴的 linux 命令行,   格式是    命令+空格+参数

字符串 默认空格是个分节符, 一般不会有别的使用吧

出0入0汤圆

发表于 2016-4-24 18:47:23 | 显示全部楼层

出0入0汤圆

发表于 2016-4-24 19:22:56 | 显示全部楼层
短小精湛,可读性好,收藏。

出0入0汤圆

发表于 2016-4-24 19:52:06 | 显示全部楼层
谢谢分享         

出0入0汤圆

发表于 2018-1-10 18:11:50 | 显示全部楼层
楼主,这么早就搞LoRa了?

出0入8汤圆

发表于 2018-1-13 18:56:54 来自手机 | 显示全部楼层
学习了,实用。

出0入0汤圆

发表于 2019-5-26 13:11:53 | 显示全部楼层
write和read是不是应该加volatile修饰。

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-4-19 06:28

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

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