C语言实现的环形FIFO队列,用于线程异步通信,数据发送非常方便,比如GPRS发送数据,一个线程将数据写入到FIFO,发送线程不停的从FIFO中读取数据,然后发送,又比如上位机中,数据接收线程不停的接收数据,写入到FIFO,另一个异步的处理线程不停的读取数据,进行处理。
-
/*************************************************************************************************************
-
* 文件名: SendDataFIFO.c
-
* 功能: 实时数据发送缓冲区
-
* 作者: cp1300@139.com
-
* 创建时间: 2015-08-09
-
* 最后修改时间: 2017-08-26
-
* 详细: 用于数据发送缓冲区
-
2017-08-26:增加溢出回调函数,可以对溢出的数据进行处理,用于FIFO嵌套
-
*************************************************************************************************************/
-
#include "system.h"
-
#include "usart.h"
-
#include "led.h"
-
#include "main.h"
-
#include "SendDataFIFO.h"
-
#include "SYSMalloc.h"
-
-
#define FIFO_INIT_STATUS_ID 0x354789d //用于标示是否初始化
-
-
-
-
-
//初始化缓冲区
-
bool FIFO_Init(FIFO_HANDLE *pHandle,u16 OneSize, u16 MaxCnt, void (*FullCallBack)(void *pData), bool isExtSRAM)
-
{
-
-
if(pHandle ==
NULL)
return FALSE;
-
if(isExtSRAM == TRUE)
//是否使用外部缓冲区
-
{
-
pHandle->pFifoBuff = (u8 *)mymalloc(SRAMEX, OneSize*MaxCnt);
//缓冲区指针,申请内存
-
pHandle->pByteCntBuff = (u16 *)mymalloc(SRAMEX,
sizeof(u16)*MaxCnt);
//数据大小记录缓冲区,申请内存
-
}
-
else
-
{
-
pHandle->pFifoBuff = (u8 *)mymalloc(SRAMIN, OneSize*MaxCnt);
//缓冲区指针,申请内存
-
pHandle->pByteCntBuff = (u16 *)mymalloc(SRAMIN,
sizeof(u16)*MaxCnt);
//数据大小记录缓冲区,申请内存
-
}
-
-
//uart_printf("pHandle->pFifoBuff=0x%X\r\n", (u32)pHandle->pFifoBuff);
-
//uart_printf("pHandle->pByteCntBuff=0x%X\r\n", (u32)pHandle->pByteCntBuff);
-
if(pHandle->pFifoBuff==
NULL)
-
{
-
DEBUG(
"pHandle->pFifoBuff申请内存出错\r\n");
-
}
-
if(pHandle->pByteCntBuff==
NULL)
-
{
-
DEBUG(
"pHandle->pByteCntBuff申请内存出错\r\n");
-
}
-
pHandle->InitStatus =
0;
//初始化成功状态无效
-
if((pHandle->pFifoBuff==
NULL)||(pHandle->pByteCntBuff==
NULL))
return FALSE;
-
pHandle->OneSize = OneSize;
//单条数据大小
-
pHandle->Cnt = MaxCnt;
//缓冲区总数据容量(条数)
-
pHandle->ReadCnt =
0;
//读取位置
-
pHandle->WriteCnt =
0;
//写位置
-
pHandle->NotReadCnt =
0;
//未读取数量
-
pHandle->FullCallBack = FullCallBack;
//溢出回调函数
-
pHandle->InitStatus = FIFO_INIT_STATUS_ID;
//初始化成功状态有效
-
-
-
return TRUE;
-
}
-
-
-
//写入一条数据
-
//当缓冲区满了后,缓存最新的数据,丢掉最早的数据
-
bool FIFO_Write(FIFO_HANDLE *pHandle,u8 *pBuff, u16 ByteCnt)
-
{
-
u16 cnt;
-
#ifdef _UCOS_II_
-
OS_CPU_SR cpu_sr;
-
#endif
-
-
if(pHandle ==
NULL)
return FALSE;
-
if(pHandle->InitStatus != FIFO_INIT_STATUS_ID)
return FALSE;
//没有初始化
-
if (pHandle->NotReadCnt >= pHandle->Cnt)
//发送溢出
-
{
-
cnt = pHandle->WriteCnt;
//先将写指针后移,占位,防止多线程写冲突
-
-
if(pHandle->FullCallBack!=
NULL) pHandle->FullCallBack(&pHandle->pFifoBuff[cnt * pHandle->OneSize]);
-
if (ByteCnt > pHandle->OneSize) ByteCnt = pHandle->OneSize;
//限制单条数据大小
-
-
pHandle->WriteCnt++;
-
if (pHandle->WriteCnt >= pHandle->Cnt) pHandle->WriteCnt =
0;
//环形FIFO
-
pHandle->ReadCnt++;
//读取数量增加
-
if (pHandle->ReadCnt >= pHandle->Cnt) pHandle->ReadCnt =
0;
//环形FIFO,把读写指针都增加,但是剩余数据数量不变
-
pHandle->pByteCntBuff[cnt] = ByteCnt;
//记录数据大小
-
memcpy(&pHandle->pFifoBuff[cnt * pHandle->OneSize], pBuff, ByteCnt);
//拷贝数据到缓冲区
-
-
return FALSE;
//数据已经满了
-
}
-
else
-
{
-
if (ByteCnt > pHandle->OneSize) ByteCnt = pHandle->OneSize;
//限制单条数据大小
-
//先将写指针后移,占位,防止多线程写冲突
-
cnt = pHandle->WriteCnt;
-
pHandle->WriteCnt++;
-
if (pHandle->WriteCnt >= pHandle->Cnt) pHandle->WriteCnt =
0;
//环形FIFO
-
pHandle->pByteCntBuff[cnt] = ByteCnt;
//记录数据大小
-
-
memcpy(&pHandle->pFifoBuff[cnt * pHandle->OneSize], pBuff, ByteCnt);
//拷贝数据到缓冲区
-
/*{
-
u16 i;
-
printf("\r\n写入的数据测试[读%d/写:%d]:\r\n",pHandle->ReadCnt,pHandle->WriteCnt);
-
for(i = 0;i < ByteCnt;i ++)
-
{
-
pHandle->pFifoBuff[cnt * pHandle->OneSize+i] = pBuff[i];
-
printf("%02X\t",pBuff[i]);
-
if(pHandle->pFifoBuff[cnt * pHandle->OneSize+i] != pBuff[i])
-
{
-
printf("拷贝检测错误,数据丢失了\r\n");
-
}
-
}
-
printf("\r\n检测写入的数据测试:\r\n");
-
for(i = 0;i < ByteCnt;i ++)
-
{
-
printf("%02X\t",pHandle->pFifoBuff[cnt * pHandle->OneSize+i]);
-
}
-
printf("\r\n");
-
}*/
-
-
#ifdef _UCOS_II_
-
OS_ENTER_CRITICAL();
//关闭系统中断
-
#endif
-
-
pHandle->NotReadCnt ++;
//没有读取的数量增加
-
-
#ifdef _UCOS_II_
-
OS_EXIT_CRITICAL();
//开启系统中断
-
#endif
-
-
return TRUE;
-
}
-
-
-
-
}
-
-
-
-
-
//读取一条数据,返回指针,无需复制数据
-
bool FIFO_ReadNotCopy(FIFO_HANDLE *pHandle,u8 **pBuff, u16 *pByteCnt)
-
{
-
u16 cnt;
-
-
printf(
"\r\n读取数据[读%d/写:%d]:\r\n",pHandle->ReadCnt,pHandle->WriteCnt);
-
if(pHandle ==
NULL)
return FALSE;
-
if(pHandle->InitStatus != FIFO_INIT_STATUS_ID)
return FALSE;
//没有初始化
-
if (pHandle->NotReadCnt ==
0)
return FALSE;
//数据为空
-
cnt = pHandle->pByteCntBuff[pHandle->ReadCnt];
//获取数据大小
-
if (cnt > pHandle->OneSize) cnt = pHandle->OneSize;
//限制单条数据大小
-
*pBuff = &pHandle->pFifoBuff[pHandle->ReadCnt * pHandle->OneSize];
//数据缓冲区指针
-
*pByteCnt = cnt;
-
-
-
return TRUE;
-
}
-
-
//未读取数据减少一次,用于读取数据返回指针后调用
-
u16 FIFO_ReduceOne(FIFO_HANDLE *pHandle)
-
{
-
#ifdef _UCOS_II_
-
OS_CPU_SR cpu_sr;
-
#endif
-
-
if(pHandle ==
NULL)
return FALSE;
-
if(pHandle->InitStatus != FIFO_INIT_STATUS_ID)
return FALSE;
//没有初始化
-
if (pHandle->NotReadCnt ==
0)
return FALSE;
-
pHandle->ReadCnt++;
//读取数量增加
-
if (pHandle->ReadCnt >= pHandle->Cnt) pHandle->ReadCnt =
0;
//环形FIFO
-
-
-
-
#ifdef _UCOS_II_
-
OS_ENTER_CRITICAL();
//关闭系统中断
-
#endif
-
-
pHandle->NotReadCnt--;
//没有读取的数量减少
-
#ifdef _UCOS_II_
-
OS_EXIT_CRITICAL();
//开启系统中断
-
#endif
-
-
-
-
return pHandle->NotReadCnt;
//返回没有读取的数据数量
-
}
-
-
-
//清除FIFO
-
bool FIFO_Clear(FIFO_HANDLE *pHandle)
-
{
-
if(pHandle ==
NULL)
return FALSE;
-
if(pHandle->InitStatus != FIFO_INIT_STATUS_ID)
return FALSE;
//没有初始化
-
pHandle->ReadCnt =
0;
//FIFO读取位置
-
pHandle->WriteCnt =
0;
//FIFO写入位置
-
pHandle->NotReadCnt =
0;
//FIFO内没有读取的数据数量为0
-
return TRUE;
-
}
-
-
-
//获取FIFO中数据数量
-
u16 FIFO_GetDataNumber(FIFO_HANDLE *pHandle)
-
{
-
if(pHandle ==
NULL)
return
0;
-
if(pHandle->InitStatus != FIFO_INIT_STATUS_ID)
return
0;
//没有初始化
-
-
return pHandle->NotReadCnt;
//FIFO内没有读取的数据数量
-
}
-
/*************************************************************************************************************
-
* 文件名: SendDataFIFO.h
-
* 功能: 实时数据发送缓冲区
-
* 作者: cp1300@139.com
-
* 创建时间: 2015-08-09
-
* 最后修改时间: 2017-08-26
-
* 详细: 用于数据发送缓冲区
-
2017-08-26:增加溢出回调函数,可以对溢出的数据进行处理
-
*************************************************************************************************************/
-
#ifndef __SEND_DATA_FIFO_H__
-
#define __SEND_DATA_FIFO_H__
-
-
#include "system.h"
-
-
-
typedef
struct
-
{
-
u8 *pFifoBuff;
//缓冲区指针
-
u16 *pByteCntBuff;
//记录数据大小的缓冲区
-
u16 OneSize;
//单条数据大小
-
u16 Cnt;
//缓冲区总数据容量(条数)
-
u16 ReadCnt;
//读取位置
-
u16 WriteCnt;
//写位置
-
u16 NotReadCnt;
//未读取数量
-
u32 InitStatus;
//初始化状态
-
void (*FullCallBack)(
void *pData);
//缓冲区满回调函数
-
}FIFO_HANDLE;
-
-
-
-
bool FIFO_Init(FIFO_HANDLE *pHandle,u16 OneSize, u16 MaxCnt, void (*FullCallBack)(void *pData), bool isExtSRAM);
//初始化缓冲区
-
bool FIFO_Write(FIFO_HANDLE *pHandle,u8 *pBuff, u16 ByteCnt);
//写入一条数据
-
bool FIFO_ReadNotCopy(FIFO_HANDLE *pHandle,u8 **pBuff, u16 *pByteCnt);
//读取一条数据,返回指针,无需复制数据
-
u16 FIFO_ReduceOne(FIFO_HANDLE *pHandle);
//未读取数据减少一次,用于读取数据返回指针后调用
-
bool FIFO_Clear(FIFO_HANDLE *pHandle);
//清除FIFO
-
u16 FIFO_GetDataNumber(FIFO_HANDLE *pHandle);
//获取FIFO中数据数量
-
-
#endif //__SEND_DATA_FIFO_H__
-
示例,比如定时发送数据,将数据定时拷贝到FIFO中,另一个线程定时启动,发送数据:
-
//拷贝实时数据到发送缓冲区中,进行立即发送数据(注意功能码必须为8位)
-
void CopyTempDataToFIFO(u8 Fun)
-
{
-
u8 i;
-
-
//写入需要发送的数据的功能码
-
g_TempRealData.Fun = Fun;
//功能码
-
g_TempRealData.SerialNumber =
0;
//流水号设置为0,自动分配
-
g_TempRealData.Time[
0] = timer.w_year
-2000;
//拷贝实时时间
-
g_TempRealData.Time[
1] = timer.w_month;
//拷贝实时时间
-
g_TempRealData.Time[
2] = timer.w_date;
//拷贝实时时间
-
g_TempRealData.Time[
3] = timer.hour;
//拷贝实时时间
-
g_TempRealData.Time[
4] = timer.min;
//拷贝实时时间
-
g_TempRealData.Time[
5] =
0;
//拷贝实时时间
-
-
//循环将数据写入到4个中心站的发送FIFO中(如果中心站端口为0,则认为中心站无效,不进行发送)
-
for(i=
0;i<
4;i++)
-
{
-
//服务器配置有效才写入数据到缓冲区
-
if(g_SYS_Config.ServerPort[i] >
0)
-
{
-
FIFO_Write(&g_SendFifoBuff[i], (u8 *)&g_TempRealData,
sizeof(REAL_DATA));
//写入数据到发送缓冲区
-
}
-
else
-
{
-
FIFO_Clear(&g_SendFifoBuff[i]);
//不用发送的站点,清除缓冲区
-
FIFO_Clear(&g_SendCacheFifoBuff[i]);
//不用发送的站点,清除Cache缓冲区
-
}
-
}
-
}
发送数据,从FIFO中读取
-
isFifoStatus = FIFO_ReadNotCopy(pFifoHandle, (u8 **)&pTempRealData, &ByteLen);
-
if(isFifoStatus==TRUE)
//有数据要发送 //实时缓冲区中没有数据,检查Cache中是否有数据
-
{......
/*发送数据逻辑*/ FIFO_ReduceOne(pFifoHandle);
//发送结束后,清除当前读取过的数据
-
}