精简通用环形fifo
#ifndef __MY_FIFO_H__#define __MY_FIFO_H__
/*
*单一FIFO_IN线程和单一FIFO_OUT线程,可并发操作(即无需定义MY_FIFO_LOCK和MY_FIFO_UNLOCK)
*牺牲一个type的FIFO单元提高队列维护的简洁性
*/
/* 重新定义以下宏,请在include my_fifo.h前定义 */
#ifndef MY_FIFO_FULL
#define MY_FIFO_FULL(fifo)
#endif
#ifndef MY_FIFO_EMPTY
#define MY_FIFO_EMPTY(fifo)
#endif
#ifndef MY_FIFO_LOCK
#define MY_FIFO_LOCK(fifo)
#endif
#ifndef MY_FIFO_UNLOCK
#define MY_FIFO_UNLOCK(fifo)
#endif
/* 创建FIFO */
#define CREAT_MY_FIFO(fifo,type,size) \
typefifo; \
type *fifo##_in = fifo; \
type *fifo##_out = fifo;
/* 声明FIFO */
#define DECLARE_MY_FIFO(fifo,type,size) \
extern typefifo; \
extern type*fifo##_in; \
extern type*fifo##_out
/* 初始化FIFO */
#define INIT_MY_FIFO(fifo,size) \
do { \
fifo##_in = fifo; \
fifo##_out = fifo; \
} while(0)
/* 写入FIFO */
#define MY_FIFO_IN(fifo,data,type) \
do { \
MY_FIFO_LOCK(fifo); \
*(fifo##_in++) = data; \
if (fifo##_in >= fifo + sizeof(fifo) / sizeof(type)) \
fifo##_in = fifo; \
if (fifo##_in == fifo##_out) { \
MY_FIFO_FULL(fifo); \
if (fifo##_in-- == fifo) \
fifo##_in = fifo + sizeof(fifo) / sizeof(type) - 1; \
} \
MY_FIFO_UNLOCK(fifo); \
} while(0)
/* 读出FIFO */
#define MY_FIFO_OUT(fifo,data,type) \
do { \
MY_FIFO_LOCK(fifo); \
if (fifo##_in == fifo##_out) { \
MY_FIFO_EMPTY(fifo); \
} \
else { \
*data = *(fifo##_out++); \
if (fifo##_out >= fifo + sizeof(fifo) / sizeof(type)) \
fifo##_out = fifo; \
} \
MY_FIFO_UNLOCK(fifo); \
} while(0)
/*
*测试例程
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;
CREAT_MY_FIFO(test_fifo0,u8,7);
CREAT_MY_FIFO(test_fifo1,u16,7);
CREAT_MY_FIFO(test_fifo2,u32,7);
struct fifo_offset{
u8 a0;
u8 a1;
u8 a2;
u8 a3;
};
union fifo_test{
struct fifo_offset offset;
u32 data32;
u16 data16;
};
void check_fifo (void)
{
u8 i;
union fifo_test fifo;
for (i = 0;i < 8;i++) {
fifo.offset.a0 = (i+'0');
fifo.offset.a1 = (i+1+'0');
fifo.offset.a2 = (i+2+'0');
fifo.offset.a3 = (i+3+'0');
MY_FIFO_IN(test_fifo0,fifo.offset.a0,u8);
MY_FIFO_IN(test_fifo1,fifo.data16,u16);
MY_FIFO_IN(test_fifo2,fifo.data32,u32);
}
puts("u8u16 u32\r\n");
for (i = 0;i < 8;i++) {
fifo.data32 = 0X40404040;
MY_FIFO_OUT(test_fifo0,&(fifo.data32),u8);
putchar((fifo.offset.a0));
puts(" ");
fifo.data32 = 0X40404040;
MY_FIFO_OUT(test_fifo1,&(fifo.data32),u16);
putchar((fifo.offset.a0));
putchar((fifo.offset.a1));
puts("");
fifo.data32 = 0X40404040;
MY_FIFO_OUT(test_fifo2,&(fifo.data32),u32);
putchar((fifo.offset.a0));
putchar((fifo.offset.a1));
putchar((fifo.offset.a2));
putchar((fifo.offset.a3));
putchar('\r');
putchar('\n');
}
putchar('\r');
putchar('\n');
}
*/
#endif /* __MY_FIFO_H__ */
本帖最后由 Gorgon_Meducer 于 2013-1-12 18:34 编辑
顶啊~我也粘贴一个,捧个场
/***************************************************************************
* Copyright(C)2009-2012 by Gorgon Meducer<Embedded_zhuoran@hotmail.com> *
* *
* This program is free software; you can redistribute it and/or modify*
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA02111-1307, USA. *
***************************************************************************/
#ifndef _USE_TEMPLATE_QUEUE_H_
#define _USE_TEMPLATE_QUEUE_H_
/*============================ INCLUDES ======================================*/
/*============================ MACROS ========================================*/
#define END_DEF_QUEUE
#define END_DEF_QUEUE_U8
#define END_DEF_QUEUE_U16
#define END_DEF_QUEUE_U32
#define END_DEF_SAFE_QUEUE
#define END_DEF_SAFE_QUEUE_U8
#define END_DEF_SAFE_QUEUE_U16
#define END_DEF_SAFE_QUEUE_U32
/*============================ MACROFIED FUNCTIONS ===========================*/
#define NONE_ATOM_ACCESS(__CODE) {__CODE;}
#define QUEUE_MUTEX(__NAME, __QUEUE) \
__NAME##_queue_mutex(__QUEUE)
#define QUEUE_INIT(__NAME, __QUEUE, __BUFFER, __SIZE) \
__NAME##_queue_init((__QUEUE), (__BUFFER), (__SIZE))
#define DEQUEUE(__NAME, __QUEUE, __ADDR) \
__NAME##_dequeue((__QUEUE),(__ADDR))
#define ENQUEUE(__NAME, __QUEUE, __VALUE) \
__NAME##_enqueue((__QUEUE), (__VALUE))
#define PEEK_QUEUE(__NAME, __QUEUE, __ADDR) \
__NAME##_queue_peek((__QUEUE),(__ADDR))
#define QUEUE(__NAME) __NAME##_queue_t
#define DEF_QUEUE_EX(__NAME, __TYPE, __PTR_TYPE, __MUTEX_TYPE, __ATOM_ACCESS)\
DEF_CLASS \
__TYPE *ptBuffer; \
__PTR_TYPE tSize; \
__PTR_TYPE tHead; \
__PTR_TYPE tTail; \
__PTR_TYPE tCounter; \
__MUTEX_TYPE tMutex; \
END_DEF_CLASS(__NAME##_queue_t) \
\
__MUTEX_TYPE *__NAME##_queue_mutex(__NAME##_queue_t *ptQueue) \
{ \
CLASS(__NAME##_queue_t) *ptQ = (CLASS(__NAME##_queue_t) *)ptQueue; \
if ( NULL == ptQueue){ \
return NULL; \
} \
return &(ptQ->tMutex); \
} \
\
bool __NAME##_queue_init(__NAME##_queue_t *ptQueue, __TYPE *ptBuffer, __PTR_TYPE tSize) \
{ \
CLASS(__NAME##_queue_t) *ptQ = (CLASS(__NAME##_queue_t) *)ptQueue; \
if (NULL == ptQueue || NULL == ptBuffer || 0 == tSize) { \
return false; \
} \
\
ptQ->ptBuffer = ptBuffer; \
ptQ->tSize = tSize; \
ptQ->tHead = 0; \
ptQ->tTail = 0; \
ptQ->tCounter = 0; \
\
return true; \
} \
\
bool __NAME##_enqueue(__NAME##_queue_t *ptQueue, __TYPE tObj) \
{ \
bool bResult = false; \
CLASS(__NAME##_queue_t) *ptQ = (CLASS(__NAME##_queue_t) *)ptQueue; \
if (NULL == ptQ) { \
return false; \
} \
\
__ATOM_ACCESS( \
do { \
if ((ptQ->tHead == ptQ->tTail) && (0 != ptQ->tCounter)) { \
break; \
} \
\
ptQ->ptBuffer = tObj; \
if (ptQ->tTail >= ptQ->tSize) { \
ptQ->tTail = 0; \
} \
ptQ->tCounter++; \
bResult = true; \
} while (false); \
) \
\
return bResult; \
} \
\
bool __NAME##_queue_peek(__NAME##_queue_t *ptQueue, __TYPE *ptObj) \
{ \
bool bResult = false; \
CLASS(__NAME##_queue_t) *ptQ = (CLASS(__NAME##_queue_t) *)ptQueue; \
if (NULL == ptQ) { \
return false; \
} \
\
__ATOM_ACCESS( \
do { \
if ((ptQ->tHead == ptQ->tTail) && (!ptQ->tCounter)) { \
break; \
} \
if (NULL != ptObj) { \
*ptObj = ptQ->ptBuffer; \
} \
bResult = true; \
} while (false); \
) \
\
return bResult; \
} \
bool __NAME##_dequeue(__NAME##_queue_t *ptQueue, __TYPE *ptObj) \
{ \
bool bResult = false; \
CLASS(__NAME##_queue_t) *ptQ = (CLASS(__NAME##_queue_t) *)ptQueue; \
if (NULL == ptQ) { \
return false; \
} \
\
__ATOM_ACCESS( \
do { \
if ((ptQ->tHead == ptQ->tTail) && (!ptQ->tCounter)) { \
break; \
} \
if (NULL != ptObj) { \
*ptObj = ptQ->ptBuffer; \
} \
ptQ->tHead++; \
if (ptQ->tHead >= ptQ->tSize) { \
ptQ->tHead = 0; \
} \
ptQ->tCounter--; \
bResult = true; \
} while (false); \
) \
\
return bResult; \
} \
#define DEF_SAFE_QUEUE(__NAME, __TYPE, __PTR_TYPE, __MUTEX_TYPE) \
DEF_QUEUE_EX(__NAME, __TYPE, __PTR_TYPE, __MUTEX_TYPE, SAFE_ATOM_CODE)
#define DEF_SAFE_QUEUE_U8(__NAME, __PTR_TYPE,__MUTEX_TYPE) \
DEF_SAFE_QUEUE(__NAME, uint8_t, __PTR_TYPE, __MUTEX_TYPE)
#define DEF_SAFE_QUEUE_U16(__NAME, __PTR_TYPE, __MUTEX_TYPE) \
DEF_SAFE_QUEUE(__NAME, uint16_t, __PTR_TYPE, __MUTEX_TYPE)
#define DEF_SAFE_QUEUE_U32(__NAME, __PTR_TYPE, __MUTEX_TYPE) \
DEF_SAFE_QUEUE(__NAME, uint32_t __PTR_TYPE, __MUTEX_TYPE)
#define DEF_QUEUE(__NAME, __TYPE, __PTR_TYPE, __MUTEX_TYPE) \
DEF_QUEUE_EX(__NAME, __TYPE, __PTR_TYPE, __MUTEX_TYPE, NONE_ATOM_ACCESS)
#define DEF_QUEUE_U8(__NAME, __PTR_TYPE,__MUTEX_TYPE) \
DEF_QUEUE(__NAME, uint8_t, __PTR_TYPE, __MUTEX_TYPE)
#define DEF_QUEUE_U16(__NAME, __PTR_TYPE, __MUTEX_TYPE) \
DEF_QUEUE(__NAME, uint16_t, __PTR_TYPE, __MUTEX_TYPE)
#define DEF_QUEUE_U32(__NAME, __PTR_TYPE, __MUTEX_TYPE) \
DEF_QUEUE(__NAME, uint32_t __PTR_TYPE, __MUTEX_TYPE)
/*============================ TYPES =========================================*/
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*============================ PROTOTYPES ====================================*/
/*============================ IMPLEMENTATION ================================*/
#endif
支撑宏
#define EXTERN_CLASS typedef struct {\
uint8_t chMask[sizeof(struct {
#define END_EXTERN_CLASS(__NAME) })];\
}__NAME;
#define DEF_CLASS typedef struct {
#define END_DEF_CLASS(__NAME) }__##__NAME;\
typedef struct {\
uint8_t chMask;\
}__NAME;
#define CLASS(__NAME) __##__NAME
...
#define PRIVATE static
//! 以IAR为例子
#define NO_INIT __no_init
使用范例:
/*============================ TYPES =========================================*/
//! 定义了一个专门的byte队列类型,这个队列用uint16_t作为计数器类型,所以,可以处理0~65535个元素, 用bool作为临界区变量类型
DEF_SAFE_QUEUE_U8(byte_queue, uint16_t, bool)
END_DEF_SAFE_QUEUE_U8
/*============================ GLOBAL VARIABLES ==============================*/
/*============================ LOCAL VARIABLES ===============================*/
/*! 用刚刚定义的新类型byte_queue来定义一个队列s_tBLQIn, 这里s表示static,说明变量是静态的,_t表示这是自定义数据类
型, BL是Bootloader的缩写, Q是Queue的缩写 In表示这是一个输入队列
*/
NO_INIT PRIVATE QUEUE(byte_queue) s_tBLQIn;
//! 这是它的缓冲
NO_INIT PRIVATE uint8_t s_chInBuffer;
//! 用刚刚定义的新类型byte_queue来定义一个队列s_BLQOut;
NO_INIT PRIVATE QUEUE(byte_queue) s_tBLQOut;
//! 这是它的缓冲
NO_INIT PRIVATE uint8_t s_chOutBuffer;
//! 用两个队列,In和Out封装成一个管道pipe, 后面的两个函数是管道的一端,
static bool pipe_out_write_byte(vsf_uint8_t chByte)
{
return ENQUEUE(byte_queue, &s_tBLQOut, chByte);
}
static bool pipe_in_read_byte(uint8_t *pchByte)
{
return DEQUEUE(byte_queue, &s_tBLQIn, pchByte);
}
/*! \note initialize application
*\param none
*\retval true hal initialization succeeded.
*\retval false hal initialization failed
*/
ROOT bool app_init(void)
{
...
//! 初始化两个队列,没啥好说的
QUEUE_INIT(byte_queue, &s_tBLQIn, s_chInBuffer, sizeof(s_chInBuffer));
QUEUE_INIT(byte_queue, &s_tBLQOut, s_chOutBuffer, sizeof(s_chOutBuffer));
...
}
/*! 这是一个不折不扣如何使用队列的例子,亮点是 ENAQUEUE, PEEK_QUEUE和DEQUEUE, SERIAL_IN
和SERIAL_OUT是串行输入输出设备的接口,你直接认为是串口就好了
*/
...
PRIVATE STATE(BootLoader_Task) BEGIN
do {
uint8_t chByte;
if (SERIAL_IN(&chByte)) {
ENQUEUE(byte_queue, &s_tBLQIn, chByte);
}
} while (false);
do {
uint8_t chByte;
if (PEEK_QUEUE(byte_queue, &s_tBLQOut, &chByte)) {
if (SERIAL_OUT(chByte)) {
DEQUEUE(byte_queue, &s_tBLQOut, &chByte);
}
}
} while (false);
...
REFLEXIVE_STATE;
END
我来标记一下。 喝两口甘泉{:victory:} 本帖最后由 chencc8 于 2013-1-11 20:48 编辑
哈哈我也有,这是最近公司给新员工办的科技论文大赛的产品,前几天为了攒车费 我也凑热闹参加了,因为时间紧迫和论文篇幅限制,
否决了没时间写的<优化变送器程序架构以提高通讯速率>的论文方案和我没能力写的<C语言面向对象应用>的论文后,选择将后篇论文的一个小例子扩充成一片小论文~~
但感觉我这篇自己写的使用面向对象技术的小体悟,估计PK不过八仙过海各用奇招的选手,公司也没说不让上传到网上,所以共享给大家好了。
由于写论文写到半夜三点半,脑子迷糊的很,现在看来最大的不满意就是:
结构体Queue中用Size代表“缓冲区有多少个元素”,Leng代表“缓冲区元素的长度”,这个名字没起好~
用num来代表“缓冲区有多少个元素”,size代表“缓冲区元素的尺寸长度”会好点,但是为了和前几个例子一致,这里就不改了。
哈哈,忘了说的就是,这个queue4的例子是刚写的,前几天半夜写完论文后,一直懒得写最后一个例子,今天为了捧场就补上了。
PS:刚才将宏CREAT_Queue里的type static QueueName##Buff【Size】(用【】 是因为正确的括号会被网页忽略掉); \写错成
type static QueueName##Buff; \了,虽然运行看起来没有错误,
但是事实上入侵到别的内存了,还是名字起错 惹的祸~
这个是错的例子
这是修改后的例子
工程使Dev C++在电脑上编译通过
首先是队列模块头文件
//queue.h
#ifndef _queue_h_
#define _queue_h_
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef void (* Copy_t)(void *A, void *B);
typedef struct {
void *pBuff; /*指向缓冲区的指针*/
Copy_t pCopy; /*拷贝函数的指针*/
uint8_t Size; /*缓冲区有多少个元素*/
uint8_t Leng; /*缓冲区元素的长度*/
uint8_t Head; /*队列的头指针,读取数据的指针*/
uint8_t Tail; /*队列的尾指针,将要写入数据的指针*/
uint8_t Empty; /*0:队列不空 1:队列为空*/
}Queue;
/*创建队列并初始化*/
#define CREAT_QUEUE(QueueName, type, pCopy, Size, Leng) \
type static QueueName##Buff【Size】; \
Queue static QueueName = { \
QueueName##Buff, pCopy, Size, Leng, 0, 0, 1 \
}
void InsertQueue(Queue *me, void *data);/*往队列中插入数据*/
uint8_t GetQueue(Queue *me, void *data);/*从队列中获取数据,队列空时返回0*/
uint8_t QueueIsEmpty(Queue *me); /*判断队列是否为空*/
/*提供几个常用的数据类型的拷贝函数,别的用户定义吧*/
void Copy_uint8(void *A, void *B); /*字符型的拷贝函数*/
void Copy_uint16(void *A, void *B); /*短整形的拷贝行数*/
void Copy_uint32(void *A, void *B); /*长整形的拷贝函数*/
void Copy_float(void *A, void *B); /*单精度浮点型的拷贝函数*/
void Copy_double(void *A, void *B); /*双精度浮点型的拷贝函数*/
#endif
//
这个是队列模块的源文件#include "queue.h"
void InsertQueue(Queue *me, void *data)/*往队列中插入数据*/
{
if(me->Empty != 0)/*如果队列为空*/
{
me->Empty = 0; /*队列不空*/
}
else
{
if(me->Head == me->Tail)/*头尾指针重叠,并且队列不为空,即说明队列满*/
{
if(++(me->Head) >= me->Size)/*头指针+1*/
{
me->Head = 0;
}
}
}
me->pCopy(&((uint8_t *)me->pBuff), data);
if(++(me->Tail) >= me->Size)
{
me->Tail = 0;
}
}
uint8_t GetQueue(Queue *me, void *data)/*从队列中获取数据,队列空时返回0*/
{
if(me->Empty != 0)/*如果队列为空*/
{
return 0;
}
/*me->Leng是队列中元素的尺寸*/
me->pCopy(data, &((uint8_t *)me->pBuff));
if(++(me->Head) >= me->Size)/*头指针+1*/
{
me->Head = 0;
}
if(me->Head == me->Tail)/*取出一个数后,头尾指针重叠,即队列为空*/
{
me->Empty = 1; /*队列为空*/
}
return 1;
}
uint8_t QueueIsEmpty(Queue *me) /*判断队列是否为空*/
{
return me->Empty;
}
/*提供几个常用的数据类型的拷贝函数,别的用户定义吧*/
void Copy_uint8(void *A, void *B) /*字符型的拷贝函数*/
{
*(uint8_t *)A = *(uint8_t *)B;
}
void Copy_uint16(void *A, void *B) /*短整形的拷贝行数*/
{
*(uint16_t *)A = *(uint16_t *)B;
}
void Copy_uint32(void *A, void *B) /*长整形的拷贝函数*/
{
*(uint32_t *)A = *(uint32_t *)B;
}
void Copy_float(void *A, void *B) /*单精度浮点型的拷贝函数*/
{
*(float *)A = *(float *)B;
}
void Copy_double(void *A, void *B) /*双精度浮点型的拷贝函数*/
{
*(double *)A = *(double *)B;
}
//应用例子如下#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include "queue.h"
struct TYPE/*测试用的结构体*/
{
uint16_t Temperature;
uint16_t Force;
};
void CopyQueue4(void *A, void *B) /*用户自定义的复制函数*/
{
*(struct TYPE *)A = *(struct TYPE *)B;
}
/*创建队列并初始化*/
CREAT_QUEUE(Queue4, TYPE, CopyQueue4, 5, sizeof(struct TYPE));
int main(int argc, char *argv[])
{
uint8_t i;
/*FIFO队列的值从这个数组中赋值*/
struct TYPE Array = {{0,0},{0,1},{0,2},{0,3},{0,4},{0,5},{0,6},{0,7},{0,8},{0,9}};
struct TYPE tmp; /*临时保存从FIFO队列中获取值*/
/*示范给队列压入值,通过调整i的边界取值1~10,来观察效果*/
for(i = 0; i < 8; i++)
{
InsertQueue(&Queue4, &Array);
}
/*示范从队列中取值*/
for(i = 0; i < 10; i++)
{
if(GetQueue(&Queue4, &tmp))/*队列空时返回0,非空返回1*/
{
printf("%d \n",tmp.Force); /*在屏幕上打印从FIFO队列中获取的值*/
}
else
{
printf("%d \n",0);/*队列为空的时候在屏幕上显示0*/
}
}
printf("sizeof Queue4Buff = %d \n",sizeof(Queue4Buff));
printf("sizeof Queue4 = %d \n",sizeof(Queue4));
printf("Press ENTER to continue...\n");
getchar();
return 0;
}
// 和傻孩子大哥的比 我的例子的没有那么多奇奇怪怪的宏定义,可读性好那么一丁点,并且同样实现了可复用性,而且代码量小。
缺点是运行效率……{:funk:}悲催,以后还是用傻孩子的方式好了 MARK,众位大神都出手了,记号备用 做个记号,好好学习 请问type *fifo##_in = fifo的“##”符号怎样用?能解释一下 ffbiao 发表于 2013-1-11 20:39 static/image/common/back.gif
请问type *fifo##_in = fifo的“##”符号怎样用?能解释一下
##宏定义中用作连接符。
比如#define CREAT_BUFF(name,max) uint8_t name##_BUFF
CREAT_BUFF(key,100);
等于 uint8_t key_BUFF;
在上面的##就连接了name和_BUFF
之所以要用##是因为如果直接用name_BUFF的话,编译器不会知道你的name指的是参数宏中的参数name
需要用##将name和_BUFF分离开来(也就连接起来) 看上去很NB的样子,有空要看看! 学习了! chencc8 发表于 2013-1-11 20:55 static/image/common/back.gif
##宏定义中用作连接符。
比如#define CREAT_BUFF(name,max) uint8_t name##_BUFF
CREAT_BUFF(key,10 ...
谢谢,明白了,大概意思是用于定义宏中的内部定义和外部定义的连接作用,使得编译器识别到参量的定义 mark{:lol:} 本帖最后由 Gorgon_Meducer 于 2013-1-12 18:34 编辑
chencc8 发表于 2013-1-11 20:07 static/image/common/back.gif
和傻孩子大哥的比 我的例子的没有那么多奇奇怪怪的宏定义,可读性好那么一丁点,并且同样实现了可复用性, ...
哪里奇怪了?{:titter:} 说出来,我给你解释!我顺便在自己代码应用例子里面加入了注释。
顺便吐个槽:队列空不空的犯不着专门弄个变量来保存吧……浪费粮食是不对的!
关于你的类型转换函数,我一般不这么用,我会用另外一个宏:
#define TYPE_CONVERT(__ADDR,__TYPE) (*((__TYPE *)(__ADDR)))
你应该一看就懂~是不是一个宏顶好几个函数啊? {:smile:}BIANJI A 标记啊 队列FIFO,好东西 好帖!用到的时候参考! mark,{:biggrin:} 大大的MARK 本帖最后由 bygreencn 于 2013-1-15 17:38 编辑
挑个次,好像楼主的两个地方的定义有问题,编译不过,应该是这样才对
/* 创建FIFO */
#define CREAT_MY_FIFO(fifo,type,size) \
typefifo【size】; \ /*这里正常的贴不进去,用了全码字符*/
type *fifo##_in = fifo; \
type *fifo##_out = fifo;
/* 声明FIFO */
#define DECLARE_MY_FIFO(fifo,type,size) \
extern typefifo【size】; \ /*这里正常的贴不进去,用了全码字符*/
extern type*fifo##_in; \
extern type*fifo##_out mark fifo code 用得上的时候慢慢看。 Gorgon_Meducer 发表于 2013-1-12 18:23 static/image/common/back.gif
哪里奇怪了? 说出来,我给你解释!我顺便在自己代码应用例子里面加入了注释。
顺便吐个槽:队 ...
傻孩子大侠,为什么你的程序看上去这么复杂,你的环形队列有什么好的地方,因为我感觉环形队列本身挺简单的,你的这种写法我真的是很难琢磨透阿,哈 这东西越搞越复杂,看着看痛 好东西,这个很实用 NIC 发表于 2013-1-21 20:35 static/image/common/back.gif
傻孩子大侠,为什么你的程序看上去这么复杂,你的环形队列有什么好的地方,因为我感觉环形队列本身挺简单 ...
他用上了掩码技术~
http://www.amobbs.com/forum.php?mod=viewthread&tid=5505499
你手动将他的代码还原成正常的语言就OK了 正在搞这个 谢谢啦 NIC 发表于 2013-1-21 20:35 static/image/common/back.gif
傻孩子大侠,为什么你的程序看上去这么复杂,你的环形队列有什么好的地方,因为我感觉环形队列本身挺简单 ...
环形队列虽然原理简单,其实有很多细节的地方需要注意,都是我无数次磕破了头才总结出来的。
因为代码是我写的,所以我很难再从你的视角了解到哪些内容可能让你困惑的,所以你直接具体问
那些东西你觉得是“多出来的”,“有点不明白的”。问得越具体,我这里能做的解释越详细。 有个lib cstl,有些常用的数据结构,动态数组,列表,二叉树之类的,就是有点复杂了
一直想找一个好用的fifo,不过好像都是一个一个字节读,写的,没有批量写入读取,比如一次写入1K字节,就要判断1K次头尾指针,实际上最多判断两次就可以直接memcpy,这样效率却提高很多。还有如果缓冲满了,是直接覆盖,还是丢弃,还是等待延时写入,读取的时候,能否一次读多个字节,如果字节不够,能否等待延时再读。主要是OS支持了,各方面的情况就多了 Gorgon_Meducer 发表于 2013-1-22 13:46 static/image/common/back.gif
环形队列虽然原理简单,其实有很多细节的地方需要注意,都是我无数次磕破了头才总结出来的。
因为代码是 ...
{:lol:}
少了 __ATOM_ACCESS这个宏的定义规范 本帖最后由 NIC 于 2013-1-23 21:09 编辑
Gorgon_Meducer 发表于 2013-1-22 13:46 static/image/common/back.gif
环形队列虽然原理简单,其实有很多细节的地方需要注意,都是我无数次磕破了头才总结出来的。
因为代码是 ...
那我要先领会了你讲的那篇有关掩码结构体了之后再说,不然也不知道觉得哪不对 各路大仙过场,小弟每天不来膜拜一遍睡不踏实 这个要标记,有空了好好学习 first_blood 发表于 2013-1-22 14:45 static/image/common/back.gif
有个lib cstl,有些常用的数据结构,动态数组,列表,二叉树之类的,就是有点复杂了
一直想找一个好用的fif ...
有支持多字节写入的fifo的,具体可参考KFIFO,linux下的一段代码。 我自己改了,加了互斥,读写阻塞,这个跟OS很紧密,应该是不通用了 first_blood 发表于 2013-1-28 11:35 static/image/common/back.gif
我自己改了,加了互斥,读写阻塞,这个跟OS很紧密,应该是不通用了
你可以看看我提供的方式,里面定义了两种方式可以用来加入互斥,__ATOM_ACESS是一种,专门的MUTEX类型也是一种。 学习了,标记一下 Gorgon_Meducer 发表于 2013-1-11 13:13 static/image/common/back.gif
顶啊~我也粘贴一个,捧个场
支撑宏
是否有C语言模块化及如何封装的文档或书籍,可否借阅,傻孩子? sochen1987 发表于 2013-1-29 11:41 static/image/common/back.gif
是否有C语言模块化及如何封装的文档或书籍,可否借阅,傻孩子?
老生常谈了:UML+OOPC 学习, mark mark一下 这个必须学习下 学习学习...... mark 本帖最后由 ZL88 于 2013-2-22 17:54 编辑
chencc8 发表于 2013-1-11 20:55 static/image/common/back.gif
##宏定义中用作连接符。
比如#define CREAT_BUFF(name,max) uint8_t name##_BUFF
CREAT_BUFF(key,10 ...
在Keil里面调试到这里后就进入硬件错误中断了,是什么原因啊?
void CopyQueue3(void *A, void *B) /*用户自定义的复制函数*/
{
*(struct TYPE *)A = *(struct TYPE *)B;
}
//解决了,是初始化队列的时候和后面使用的Queue不是同一个
//Queue4不是static的话会有什么后果? 惊闻各位高手在此斗技,精彩纷呈,赶紧拜读研究研究 mark一下 ZL88 发表于 2013-2-22 16:04 static/image/common/back.gif
在Keil里面调试到这里后就进入硬件错误中断了,是什么原因啊?
void CopyQueue3(void *A, void *B) ...
还真有人试了啊,static是不能加的,这是个错误
加了static后队列就只能在这个文件内使用了,这明显不对~ chencc8 发表于 2013-2-24 12:17 static/image/common/back.gif
还真有人试了啊,static是不能加的,这是个错误
加了static后队列就只能在这个文件内使用了,这明显不对~ ...
这个没人用过吗?
ZL88 发表于 2013-2-24 22:55 static/image/common/back.gif
这个没人用过吗?
我只是用来验证技术的,刚开始尝试过将项目的一个拷贝中使用这个这个方法将按键的FIFO修改了一遍,后来发觉需要变动的东西有点多,就没再继续将整个项目都换成这个方法,
因为我的单片机的ROM换成了64K的了,不需要为了缩小体积这样折腾了,不过为了写文档方便倒是写了一个兼容以前函数的FIFO宏,为每个FIFO生成独立的函数和数据结构。
这样的话就只需要测试这个宏就行了,免得每个FIFO都测试一遍~ 学习了,不知道要看多久才能明白 Gorgon_Meducer 发表于 2013-1-11 13:13 static/image/common/back.gif
顶啊~我也粘贴一个,捧个场
支撑宏
你这个代码怎么编辑的
看起来很舒服
请问如何搞的 好东西,mark hotwind 发表于 2013-2-27 14:55 static/image/common/back.gif
你这个代码怎么编辑的
看起来很舒服
请问如何搞的
论坛提供了一个方法叫做[ code ] [ / code ]为了让你看到,所以我特别加入了空格。 /***************************************************************************
* Copyright(C)2009-2012 by Gorgon Meducer<Embedded_zhuoran@hotmail.com> *
* *
* This program is free software; you can redistribute it and/or modify*
* it under the terms of the GNU Lesser General Public License as *
* published by the Free Software Foundation; either version 2 of the *
* License, or (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU Lesser General Public *
* License along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA02111-1307, USA. *
***************************************************************************/
#ifndef _USE_TEMPLATE_QUEUE_H_
#define _USE_TEMPLATE_QUEUE_H_
/*============================ INCLUDES ======================================*/
/*============================ MACROS ========================================*/
#define END_DEF_QUEUE
#define END_DEF_QUEUE_U8
#define END_DEF_QUEUE_U16
#define END_DEF_QUEUE_U32
#define END_DEF_SAFE_QUEUE
#define END_DEF_SAFE_QUEUE_U8
#define END_DEF_SAFE_QUEUE_U16
#define END_DEF_SAFE_QUEUE_U32
/*============================ MACROFIED FUNCTIONS ===========================*/
#define NONE_ATOM_ACCESS(__CODE) {__CODE;}
#define QUEUE_MUTEX(__NAME, __QUEUE) \
__NAME##_queue_mutex(__QUEUE)
#define QUEUE_INIT(__NAME, __QUEUE, __BUFFER, __SIZE) \
__NAME##_queue_init((__QUEUE), (__BUFFER), (__SIZE))
#define DEQUEUE(__NAME, __QUEUE, __ADDR) \
__NAME##_dequeue((__QUEUE),(__ADDR))
#define ENQUEUE(__NAME, __QUEUE, __VALUE) \
__NAME##_enqueue((__QUEUE), (__VALUE))
#define PEEK_QUEUE(__NAME, __QUEUE, __ADDR) \
__NAME##_queue_peek((__QUEUE),(__ADDR))
#define QUEUE(__NAME) __NAME##_queue_t
#define DEF_QUEUE_EX(__NAME, __TYPE, __PTR_TYPE, __MUTEX_TYPE, __ATOM_ACCESS)\
DEF_CLASS \
__TYPE *ptBuffer; \
__PTR_TYPE tSize; \
__PTR_TYPE tHead; \
__PTR_TYPE tTail; \
__PTR_TYPE tCounter; \
__MUTEX_TYPE tMutex; \
END_DEF_CLASS(__NAME##_queue_t) \
\
__MUTEX_TYPE *__NAME##_queue_mutex(__NAME##_queue_t *ptQueue) \
{ \
CLASS(__NAME##_queue_t) *ptQ = (CLASS(__NAME##_queue_t) *)ptQueue; \
if ( NULL == ptQueue){ \
return NULL; \
} \
return &(ptQ->tMutex); \
} \
\
bool __NAME##_queue_init(__NAME##_queue_t *ptQueue, __TYPE *ptBuffer, __PTR_TYPE tSize) \
{ \
CLASS(__NAME##_queue_t) *ptQ = (CLASS(__NAME##_queue_t) *)ptQueue; \
if (NULL == ptQueue || NULL == ptBuffer || 0 == tSize) { \
return false; \
} \
\
ptQ->ptBuffer = ptBuffer; \
ptQ->tSize = tSize; \
ptQ->tHead = 0; \
ptQ->tTail = 0; \
ptQ->tCounter = 0; \
\
return true; \
} \
\
bool __NAME##_enqueue(__NAME##_queue_t *ptQueue, __TYPE tObj) \
{ \
bool bResult = false; \
CLASS(__NAME##_queue_t) *ptQ = (CLASS(__NAME##_queue_t) *)ptQueue; \
if (NULL == ptQ) { \
return false; \
} \
\
__ATOM_ACCESS( \
do { \
if ((ptQ->tHead == ptQ->tTail) && (0 != ptQ->tCounter)) { \
break; \
} \
Gorgon_Meducer 发表于 2013-3-7 17:06 static/image/common/back.gif
论坛提供了一个方法叫做[ code ] [ / code ]为了让你看到,所以我特别加入了空格。 ...
试了下
谢谢
高级模式右端的添加代码 gghhhjcg咯路 标记,FIFO Gorgon_Meducer 发表于 2013-1-11 13:13 static/image/common/back.gif
顶啊~我也粘贴一个,捧个场
支撑宏
打扰 【傻孩子】了;
关于 FIFO的使用;我也使用很久了;
我发现你的代码中;函数遇到被中断嵌套后,极端情况下,会发生bug;
不知道,我的描述正确否。
希望交流交流
例如:FIFO添加“队员”
92.bool __NAME##_enqueue(__NAME##_queue_t *ptQueue, __TYPE tObj) \
93.{ \
94. bool bResult = false; \
95. CLASS(__NAME##_queue_t) *ptQ = (CLASS(__NAME##_queue_t) *)ptQueue; \
96. if (NULL == ptQ) { \
97. return false; \
98. } \
99. \
100. __ATOM_ACCESS( \
101. do { \
102. if ((ptQ->tHead == ptQ->tTail) && (0 != ptQ->tCounter)) { \
103. break; \
104. } \
105. \
106. ptQ->ptBuffer = tObj; \
107. if (ptQ->tTail >= ptQ->tSize) { \
108. ptQ->tTail = 0; \
109. } \
110. ptQ->tCounter++; \
111. bResult = true; \
112. } while (false); \
113. ) \
114. \
115. return bResult; \
116.}
设想,主程序中,需要添加一个“队员A”入队,
并且此处判断为 非,属于队列未满,可以添加“队员A”
do { \
102. if ((ptQ->tHead == ptQ->tTail) && (0 != ptQ->tCounter)) { \
103. break; \
104. }
运行完毕上述判断代码后,被中断;而且,中断服务函数里面的操作,仍然为向该队列内添加“队员B”。
那么,在中断里面,上述判断仍然为 非,并且,成功添加 “队员B”
中断正常退出,恢复主程序,继续运行下列代码
106. ptQ->ptBuffer = tObj; \
107. if (ptQ->tTail >= ptQ->tSize) { \
108. ptQ->tTail = 0; \
109. } \
这时,就会发生问题:
ptQ->ptBuffer = tObj;
直接增加了一个“队员A” ,并且将 ptQ->tTail++ ;
乃至以后的ptQ->tCounter++;
这样就会出现极端情况下
如果中断添加“队员B” 完毕后,正好 tTail == tHead ;那么 返回到添加“队员A”的时候,就会出现把之前已经存在,尚未取走的tHead所指向的“队员C”干掉;
同时ptQ->tCounter++; 也就不准了
另:从队列中取“队员”同样会出现这类冲突;
==============================================
==============================================
我的做法是,在进行关键的判断性操作之前,
101. do { \
102. if ((ptQ->tHead == ptQ->tTail) && (0 != ptQ->tCounter)) { \
103. break; \
104. } \
判断中断是否即将到来(我的程序里面只有一个定时器中断,其他全部用查询,故可以知道什么时候来中断),就等待中断完毕后在进行判断;
if (非中断操作该代码)//有个全局变量用来表面是否在中断中运行该代码。在中断服务函数中,会首先置起该变量,指明,该操作是在中断内进行的。
{
while(TimerCount>250);//假设 TimerCount==270时发生中断;那么就等待中断的到来,等他完毕后再运行下面的操作
}
101. do { \
102. if ((ptQ->tHead == ptQ->tTail) && (0 != ptQ->tCounter)) { \
103. break; \
104. } \
或者 干脆在这段时间内 关闭中断。
不知道。我叙述的清楚否。
=================================================
=================================================
另:
我写单片机程序,一直用状态机来操作,switch,case模式;
我喜欢只开一个定时器中断;
里面来查询各个外设接口的状态:UART IO 等。只要定时器的时间设置为 外设接口的动作时间。这种结构是不会出现问题的。也用这个方式做过 4硬件UART + 4软件模拟UART的项目;还是很理想的。
但对于 超过定时器的动作时间的外设接口:SPI、CAN接口接收数据时 (发送还是无所谓的,反正他们本身就快)。我还是放在 主函数里面去查询。对于这方面,我还没有更好的办法。
我不太喜欢用多个中断(当然,不是说多个中断、多个优先级没用)。只是发现,在中断多了,优先级多了的情况下,代码的维护工作量会很大。
mark一下 zy473551 发表于 2013-3-29 15:29 static/image/common/back.gif
打扰 【傻孩子】了;
关于 FIFO的使用;我也使用很久了;
主要针对单片机构架问题谈一些个人的看法,之前我也觉得类似时间触发的机制是一个不错的构架。我也使用了将近2年多的时间,即一个定时器设为共享时钟,其余代码均靠定时器内的时间信息调度。但最近一年多来,觉得面向事件驱动的设计更符合设计本身。因为就时间来说本身就是系统的一个事件。其实大多数系统都可以抽象成状态机 + 事件驱动的模型。假设是平面状态机(分层先不说),其实系统就是一个表 状态数 * 事件数,最极端的情况每种状态面对的事件都是一样的。所以因此引出了switch-case的一些看法,个人不太建议使用。switch本身就是一个不公平的策略,其次维护极为困难。个人建议用函数数组指针做一个 事件 + 状态的表。有什么事件做什么样的状态下该事件的具体事务,但面向事件的驱动更考验设计者划分任务模块的功底以及大量的互斥问题。 本帖最后由 Gorgon_Meducer 于 2013-3-29 18:55 编辑
zy473551 发表于 2013-3-29 15:29 static/image/common/back.gif
打扰 【傻孩子】了;
关于 FIFO的使用;我也使用很久了;
你的分析很正确,唯一漏掉的就是那个__ATOM_ACCESS()的宏,你分析的
问题就是它存在的意义。
你仔细看定义里面,实际上有一类SAFE_QUEUE,里面用了SAFE_ATOM_ACCESS
来替换这个宏,而SAFE_ATOM_ACCESS就是一个支持嵌套的中断保护宏。
至于你等待系统中断是否发生的做法,不作评论。 sochen1987 发表于 2013-3-29 16:44 static/image/common/back.gif
主要针对单片机构架问题谈一些个人的看法,之前我也觉得类似时间触发的机制是一个不错的构架。我也使用了 ...
你说的很对,而且有一点我想补充:划分模块的功底以及大量的互斥操作(其实是多任务
间的通信同步)无论用哪种方法都是一样存在的,并不是 事件驱动模型 本身的特点或者
说难点。 Gorgon_Meducer 发表于 2013-1-11 13:13 static/image/common/back.gif
顶啊~我也粘贴一个,捧个场
支撑宏
好东东,谢谢楼主贡献 mark…… mark{:sad:}{:smile:} chencc8 发表于 2013-1-11 20:55 static/image/common/back.gif
##宏定义中用作连接符。
比如#define CREAT_BUFF(name,max) uint8_t name##_BUFF
CREAT_BUFF(key,10 ...
原来如此,万分感谢分享。 mark~~~~~~~~~~~~~~ 只想说大神好多,我还得好好学习。。。 MARK个,FIFO 经典{:smile:}{:smile:} Gorgon_Meducer 发表于 2013-3-29 18:48 static/image/common/back.gif
你的分析很正确,唯一漏掉的就是那个__ATOM_ACCESS()的宏,你分析的
问题就是它存在的意义。
你仔细看定 ...
SAFE_ATOM_CODE能提供下吗? jtj203 发表于 2013-4-27 11:52 static/image/common/back.gif
SAFE_ATOM_CODE能提供下吗?
这个要自己定义的,定义方法如下,假设我们已经有三个宏:
DISABLE_GLOBAL_INTERRUPT()
GET_GLOBAL_INTERRUPT_STATE()
RESTORE_GLOBAL_INTERRUPT_STATE(__STATE)
那么SAFE_ATOM_CODE的定义如下:
//! \note Please do not use do {} while(0) structure in macro SAFE_ATOM_CODE()
#define SAFE_ATOM_CODE(__CODE) \
{\
uint32_t wInterruptState = GET_GLOBAL_INTERRUPT_STATE();\
DISABLE_GLOBAL_INTERRUPT();\
__CODE;\
RESTORE_GLOBAL_INTERRUPT_STATE(wInterruptState);\
}
#define EXIT_SAFE_ATOM_CODE() \
do {\
RESTORE_GLOBAL_INTERRUPT_STATE(wInterruptState);\
} while(0)
我回来了,环形FIFO如果读写速相差太大时,而FIFO容量不够大时会丢数据。 FIFO要加互斥量才有实用意义……典型的如用户往FIFO打印数据,串口中断自动读取FIFO…… 必须收藏,好东西 太帮了,必须好好研究研究。 MARK....... 看看,学习一下 马克,mark,学习 可以用在串口 厉害,标记一下,后面研究 mark 卧槽,这一帖捡到宝了 好东西,收藏了。 果断收藏 chencc8 发表于 2013-1-11 20:07
和傻孩子大哥的比 我的例子的没有那么多奇奇怪怪的宏定义,可读性好那么一丁点,并且同样实现了可复用性, ...
freebsd 的 queue.h和Linux 的list 是不是就是这些?{:tongue:} kalo425 发表于 2014-1-1 00:46
freebsd 的 queue.h和Linux 的list 是不是就是这些?
没看过linux的代码,应该不会那么蛋疼。他们OS队列存放的是空指针,所以要和堆一起使用。
我现在折中性的做法是,
使用一个空闲队列(用队列而不用栈,是因为我没有时间写栈的宏)来管理二维数组的第一维索引,
上层程序申请到索引后,往里面填充数据后,调用底层的接口将它和别的信息打包压入新的应用队列中,
最后底层用完数据后,通过打包数据中的函数指针将索引归还到上层的空闲队列中。
这种用法同样也要用到继承和多态,和OS的队列一样,不需要将实际的数据填入到队列中,之所以这样做
只是因为我的项目中没有OS中的堆而已,用空闲队列管理数组索引,作用和UCOS的定长堆类似吧。
Gorgon_Meducer 发表于 2013-1-29 12:15
老生常谈了:UML+OOPC
有PDF文档吗? zxc2769 发表于 2014-1-1 12:17
有PDF文档吗?
我这里没有,论坛上好像有的,蛮大的,是扫描的。 mark...................
mark...................
好东西,收藏 MARK FIFO队列 mark一下···· 好帖!!! FIFO mark一个,慢慢看 好好参考。 mark.....收藏了
页:
[1]
2