单片机程序开发中常用的数据结构
对于程序员来说,数据结构真的很重要,但是对于单片机程序员来说,很多人可能都是非计算机科班出生,数据结构都是自学的。至少我自动化本科的课程是没有数据结构的课程的,如果说有的话,便是我已经还给老师了,哈哈哈。
队列,链表,类,结构体,联合体,二叉树等等都是嵌入式常用的数据结构。
在毕业后的工作岗位上,我也get到了一个非常好用的数据结构使用方法:联合体+结构体的方式,具体定义如下。
#define SIZE (28U)
typedef union
{
INT8U buf[SIZE];
struct
{
INT32U a[3];
INT16S b[3];
INT8U res[8];
INT16U cs;
}bits;
}MY_PARM;
这么定义的好处是,如果我想一次性赋值给所有变量,可以直接MY_PARM.buf,如果单独修改某一个参数,可以MY_PARM.bits. a[2],可以说是超级方便。大家说说这么定义还有什么好处?
另外,在单片机程序开发中经常使用的数据结构还有环形队列。这个网上资料也超多,这里不多说,索性这里学以致用,写一个使用联合体+结构体实现的环形队列。
#define EVENT_SIZE (12U)
typedef union
{
INT8U val8[EVENT_SIZE];
struct
{
INT8U type;
INT8U idxL;
INT8U idxH;
INT8U value;
INT8U time[8];
}bits;
}RECORD;
#define MaxBufferSize 64
typedef struct
{
RECORD record[MaxBufferSize];
INT8U Put;
INT8U Get;
}RECORD _BUFF;
RECORD _BUFF record_buff;
RECORD info[MAX_CHANNEL];
/**********************************************/
/*判断缓冲区是否为空*/
//参数:无
//返回值:空返回TRUE,非空返回FALSE
/**********************************************/
INT8U BufferEmpty( void )
{
RECORD _BUFF *buff;
buff = record_buff;
if( buff->Put==buff->Get )
{
return TRUE;
}
return FALSE;
}
/**********************************************/
/*判断缓冲区是否为满*/
//采用牺牲一个元素空间的方式
//参数:无
//返回值:满返回TRUE,未满则返回FALSE
/**********************************************/
INT8U BufferFull(void)
{
RECORD _BUFF *buff;
buff = record_buff;
if( ( buff->Put+1 )%MaxBufferSize==buff->Get )
{
return TRUE;
}
return FALSE;
}
/**********************************************/
/*从缓冲区中读信息函数*/
//参数:无
/* 从环形缓冲区中取元素 */
/* 有几个元素取几个元素 */
//返回值:无
/**********************************************/
void ReadBuffer(void)
{
RECORD _BUFF *buff;
buff = & record_buff;
if( FALSE==BufferEmpty( ) )
{
memcpy( &data,&buff->record[buff->Get], 12U );
buff->Get=( INT8U ) ( ( buff->Get+1 )%MaxBufferSize );//读指针后移
}
}
/**********************************************/
/*把ID号为i的信息写到缓存里面*/
//参数:ID号
/* 向环形缓冲区buff中放入一个元素*/
//返回值:无
/**********************************************/
void WriteBuffer(INT8U i)
{
RECORD _BUFF *buff;
RECORD *temp;
buff = & record_buff;
temp = & info[i];
memcpy( &buff->record[buff->Put], temp, 12U );//
buff->Put=( INT8U ) ( ( buff->Put+1 )%MaxBufferSize );
}
51单片机串口通信 环形缓冲区队列(FIFO)
最近在做毕业设计刚好涉及到51单片机,简单的研究一下发现51单片机串口只有一个字节的缓存,如果遇到单片机串口中断没有及时处理SBUF的值或者串口中断长时间未退出很容易照成数据丢失,于是就自己写了个缓冲区,代价就是消耗一部分内存空间,时间-空间本来就是一对矛盾体,想减少串口通信中数据丢失问题只能牺牲部分空间,来减少数据通信过程中的丢失问题。
核心代码如下所示:
/**********************************************************/
#define BUFFER_MAX 16 //缓冲区大小
typedef struct _circle_buffer{
unsigned char head_pos; //缓冲区头部位置
unsigned char tail_pos; //缓冲区尾部位置
unsigned char circle_buffer[BUFFER_MAX]; //缓冲区数组
}circle_buffer;
circle_buffer buffer;
void bufferPop(unsigned char* _buf)
{
if(buffer.head_pos==buffer.tail_pos) //如果头尾接触表示缓冲区为空
*_buf=0xFF;
else
{
*_buf=buffer.circle_buffer[buffer.head_pos]; //如果缓冲区非空则取头节点值并偏移头节点
if(++buffer.head_pos>=BUFFER_MAX)
buffer.head_pos=0;
}
}
void bufferPush(const unsigned char _buf)
{
buffer.circle_buffer[buffer.tail_pos]=_buf; //从尾部追加
if(++buffer.tail_pos>=BUFFER_MAX) //尾节点偏移
buffer.tail_pos=0; //大于数组最大长度 制零 形成环形队列
if(buffer.tail_pos==buffer.head_pos) //如果尾部节点追到头部节点 则修改头节点偏移位置丢弃早期数据
if(++buffer.head_pos>=BUFFER_MAX)
buffer.head_pos=0;
}
考虑到看到此博文的人可能有很多小白并不知道如何使用,在此简单的说一下,假设你已经能进行简单的串口发送接收了,然后串口中断部分可以这样写
void serial1(void) interrupt 4
{
if(RI)
{
bufferPush(SBUF);
RI=0;
}
if(TI)
{
TI=0;
}
}
在主程序中我们只需要调用函数就行了如:
void main()
{
unsigned char dat ;
//读取缓冲区一个字符,如果dat=0xff表示缓冲区为空,所以接收的字符不能有0xff。
bufferPop(&dat);
}
bufferPop函数中没调用一次,便从缓冲区取出一个字符,头部指针就会进行偏移,具体看源码并不是很复杂 只是一个数组类型的环形FIFO缓冲区。
有一点要注意的是,如果缓冲区满的话,后面的数据会覆盖最前面的数据。
你可以把缓冲区设置大些,就可以尽可能的减少数据覆盖问题,但是带来的额外问题就是51或者其他系列的单片机RAM是非常小的,并不像PC中缓冲区动不动就1024KB。所以缓冲区设置多大,根据自己需求调整就行了。
相关问答
单片机 中的显示 缓冲区 是什么,有什么用?据我推测这个应该是用8位数码管显示时间的格式为:hh-mm-ss,16也就代表数码管显示'-',你应该把显示函数贴出来据我推测这个应该是用8位数码管显示时间的格式为...
什么是显示 缓冲区 ?单片机中的显示缓冲区就是几个变量或者一个数组而已,用于保存需要显示出来的数据。程序将需要显示的数据计算出来后保存在这里面,然后当数码管扫描函数运行时...
单片机 中pos和buf什么意思?这个问题我来回答。可以肯定的是,单片机写程序时都需要用到变量来永久或临时存放数据,有时单片机中的程序中会用到pos和buf单词来表示一定含义的变量。一般情...
buf是什么意思?buf的意思是缓冲区,它本质上就是一段存储数据的内存。1、在C语言编程中一般用数组来表示一个缓冲区。如下:charbuf[256]={0};//定义一个数组作为缓冲...b...
sgp30怎么发送数据到 单片机 ?SGP30是一种用于检测室内空气质量的传感器模块。要将SGP30传感器模块的数据发送到单片机,您可以按照以下步骤进行操作:1.连接硬件:将SGP30模块连接到单片机...
8051 单片机 内RAM低128字节划分为哪三个部分,有什么作用-ZOL问答8051单片机内部RAM低128单元划分为工作寄存器组、位寻址区、堆栈与数据缓冲区。它们的特点如下:(1)工作寄存器组(00H——1FH)这是一个用寄存器直接寻址的区域...
单片机 是如何控制步进电机扎旋转的?voidKeyDriver(){unsignedchari,j;staticunsignedcharbackup[4][4]={//按键值备份,保存前一次的值{1,1,1...
单片机 刷屏幕怎么避免闪烁?单片机刷屏幕出现闪烁的问题通常是由于刷新频率不高或者刷新方式不正确引起的。为了避免闪烁,可以通过提高刷新频率、尽可能减少刷新区域、使用交叉刷新或者使...
msc-51的程序存储器用于?程序存储器用来存放编制好的始终保留的固定程序和表格常数;数据存储器用以存放数据或中间运行结果。8051单片机内部设置有256字节的RAM,其中有128字节的内部R...
51 单片机 接收不到数据?关于这个问题,有多种原因可能导致51单片机接收不到数据,以下是一些可能的原因和解决方法:1.串口配置错误:检查串口的波特率、数据位、停止位和校验位是否与...