nome 发表于 2014-4-21 11:37:52

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

本帖最后由 nome 于 2014-4-21 13:55 编辑

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

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


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

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


        author:nome
        date:2014/4/18


*/


#include "string.h"
#include "queue.h"


#define Q_LEN 100         //队列长度

#define TIMEOUT 900000      

char strqueue;       //队列数组



int write = 0;               //写偏移
int read = 0;                                                                //读偏移




/*
* 功能:从队列中读取一个字节
* 失败:返回-1
* 成功:返回0
*/
char read_queue(char *pdata)
{
        if(write==read)
                return -1;               
        *pdata = strqueue;
        read = (read+1)%Q_LEN;
        return 0;
}
/*
* 功能:往队列中写入一个字节
* 失败:返回-1
* 成功:返回0
*/
char write_queue(char data)
{
        if((write+1)%Q_LEN==read)
                return -1;
        strqueue = data;
        write = (write+1)%Q_LEN;
        return 0;
}


/*
* 功能:从队列中取出一个完整的字符串命令。
* 失败:返回-1
* 成功:返回0
*cmd 存放命令的指针,param 存放参数的指针。
*/
int get_q_string(char *cmd,char *param)
{
        int i = 0;
        int timeout = 0;
        char data;
        if(read_queue(&data)) //查看队列中是否有数据,没有数据返回,有数据等待接收完整命令。
                return -1;
        cmd = data;
        for(;;){
                if(0==read_queue(&cmd))
                        i++;
                if(cmd==' ')
                        break;
                if(timeout>TIMEOUT)
                        return -1;
                timeout++;
        }
        cmd = 0; //提供一个cmd结束符
        timeout = 0;
        i = 0;
        for(;;){
                if(0==read_queue(&param))
                        i++;
                if(param=='\r')
                        break;
                if(timeout>TIMEOUT)
                        return -1;
                        timeout++;               
        }
        param = 0; //去掉\r 换成结束符
        return 0;
}


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




struct _cmd_list{
        char *cmd;
        void (*func)(char *param);
};

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



#endif

#include "queue.h"
#include "string.h"
#include "math.h"
#include "stdio.h"
#include "usart_cmd.h"


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

//字符串转int
int str_to_int(char *str)
{
        int i = 0,j = 0;
        int ret = 0;
        for(;;){
        if(str==0||i>20)
                break;
        }
        j = i = i-2;
        for(;i>=0;i--)
        {
                ret += (str-'0')*(pow(10,(j-i)));
        }
        return ret;
}

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

extern int send_receive_flag ;
extern int packet_num ;

void send(char *param)
{
        send_receive_flag = 0;
        packet_num = str_to_int(param);
}

void receive(char *param)
{
        send_receive_flag = 1;
}

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

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

CMD_CALLBACK("setfreq",setfreq)
CMD_CALLBACK("send",send)
CMD_CALLBACK("receive",receive)



CMD_CALLBACK_LIST_END






char cmd;
char param;
int get_cmd(void)
{
        int i = 0;
        if(get_q_string(cmd,param))
                return 0;
        for(;;){
                if(strcmp(cmd,cmd_list.cmd)==0)
                        return i;       
                if(cmd_list[++i].cmd==NULL)
                        return 0;
        }
}



//这个函数需要在main函数中轮询调用
void dispose_cmd(void)
{
        cmd_list.func(param);
}

jiwx2011 发表于 2014-4-21 12:38:27

学习一下。。

机器人天空 发表于 2014-4-21 12:59:01

谢谢楼主,很有用{:lol:}

yayagepei 发表于 2014-4-21 12:59:57

学习学习

shangyu60104 发表于 2015-10-7 11:54:06

学习一下

一杯茶2009 发表于 2016-4-22 16:08:00

学习,感谢分享

zyw19987 发表于 2016-4-24 06:25:26

格式定义太死吧,协议中就会有0x20怎么搞?

nome 发表于 2016-4-24 17:47:54

zyw19987 发表于 2016-4-24 06:25
格式定义太死吧,协议中就会有0x20怎么搞?

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

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

Excellence 发表于 2016-4-24 18:47:23

{:victory:}{:victory:}{:victory:}

e1ki0lp 发表于 2016-4-24 19:22:56

短小精湛,可读性好,收藏。

想不到 发表于 2016-4-24 19:52:06

谢谢分享         

mypear 发表于 2018-1-10 18:11:50

楼主,这么早就搞LoRa了?

lijg8421 发表于 2018-1-13 18:56:54

学习了,实用。

Lyndon.Sun 发表于 2019-5-26 13:11:53

write和read是不是应该加volatile修饰。

oooios 发表于 2019-6-10 16:23:49

lihai xxxxx
页: [1]
查看完整版本: 分享一个平时用的接收缓冲+缓冲处理回调函数的结构