做一个接收的缓冲,cup空闲时刻处理缓冲数据

来源:互联网 发布:淘宝制作假护照 编辑:程序博客网 时间:2024/05/18 00:52

功能简介: 

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


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


使用环境示例:

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

/*queue.c--实现功能:定义一个环形消息队列,实现1.读一个字节 2.插入一个字节 3.取出一条命令。----------  命令格式定义:cmd prama\r    获取命令依照" "区分命令和参数,依照"\r"区分结尾。author:nomedate  :2014/4/18*/#include "string.h"#include "queue.h"#define Q_LEN 100           //队列长度#define TIMEOUT 900000       char strqueue[Q_LEN];       //队列数组int write = 0;               //写偏移int read = 0;//读偏移/* * 功能:从队列中读取一个字节 * 失败:返回-1 * 成功:返回0*/char read_queue(char *pdata){if(write==read)return -1;*pdata = strqueue[read];read = (read+1)%Q_LEN;return 0;}/* * 功能:往队列中写入一个字节 * 失败:返回-1 * 成功:返回0*/char write_queue(char data){if((write+1)%Q_LEN==read)return -1;strqueue[write] = 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[i++] = data;for(;;){if(0==read_queue(&cmd[i]))i++;if(cmd[i-1]==' ')break;if(timeout>TIMEOUT)return -1;timeout++;}cmd[i] = 0; //提供一个cmd结束符timeout = 0;i = 0;for(;;){if(0==read_queue(&param[i]))i++;if(param[i-1]=='\r')break;if(timeout>TIMEOUT)return -1;timeout++;}param[i-1] = 0; //去掉\r 换成结束符return 0;}

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

#ifndef _USART_CMD_H#define _USART_CMD_Hstruct _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); //定义一个串口发送字符串的函数//字符串转intint str_to_int(char *str){int i = 0,j = 0;int ret = 0;for(;;){if(str[i++]==0||i>20)break;}j = i = i-2;for(;i>=0;i--){ret += (str[i]-'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_BEGINCMD_CALLBACK("setfreq",setfreq)CMD_CALLBACK("send",send)CMD_CALLBACK("receive",receive)CMD_CALLBACK_LIST_ENDchar cmd[10];char param[32];int get_cmd(void){int i = 0;if(get_q_string(cmd,param))return 0;for(;;){if(strcmp(cmd,cmd_list[i].cmd)==0)return i;if(cmd_list[++i].cmd==NULL)return 0;}}//这个函数需要在main函数中轮询调用void dispose_cmd(void){cmd_list[get_cmd()].func(param);}



0 0