优秀的编程知识分享平台

网站首页 > 技术文章 正文

传感器前期编程_系统时间与环型缓冲区

nanyue 2024-09-20 21:55:18 技术文章 3 ℃



来源:百问网_嵌入式Linux wiki_jz2440 新1期视频维基教程 (视频文字版)

作者:韦东山

本文字数:2091,阅读时长:2分钟

这节课实现两个小功能:系统时间环形缓冲区

在上一课的基础上添加代码,打开timer.c,前面的设置的定时器,每10ms产生一次中断,这里定义一个全局变量,来记录产生次数,

static unsigned int g_system_time_10ms_cnt = 0;

这里的类型选择使用unsigned int类型,2^32*10/1000/3600/24=497天,也就是说如果运行497天后,计数溢出,将会导致一些问题。

改为unsigned long long类型的话,2^64*10/1000/3600/24/365=5849424173年,这个时间就不怕溢出了,因此这里计数变量的类型为unsigned long long:

static unsigned long long g_system_time_10ms_cnt = 0;

在定时器中断timer_irq()函数里面让这个计数值每次加1:

g_system_time_10ms_cnt++;

以后我们就可以读取这个计数值,知道系统时间。

现在开始编写获取系统时间的函数,精度要求是us级别的,读取TCNTO0的值,再加上g_system_time_10ms_cnt的计数:

unsigned long long get_system_time_us(void)
{
	unsigned long long us = (50000 - TCNTO0)/5;
	return g_system_time_10ms_cnt * 10 * 1000 + us;
}

通过这个函数就知道上电到之后任何一个时刻,过去了多久。

再写一个函数计算两段时间之间的差值:

unsigned int delta_time_us(unsigned long long pre, unsigned long long now)
{
	return (now - pre);
}

到此,系统时间相关函数就完成了。

首先介绍一下环形缓冲区,假设有一个数组char Buf[6],它的结构如下:

定义一个读指针r=0,一个写指针w=0。

  • 写数据:

buf[w] = val;

w = (w+1)%LEN = (w+1)%6;

  • 读数据:

val = buf(r);

r = (r+1)%LEN;

如何判断buf是空: r == w; //为空

如何判断buf是满: (w+1)%LEN == r; //为满

读写指针,每到达最后面,就从0开始,就像一个圆环一样,因此得名环形缓冲区。

对于我们红外数据,保存的数据并不是char,而是一个结构体,里面含有脉冲宽度,引脚极性等。

在sensors文件下创建一个irda文件夹,里面创建irda_raw.h和circle_buffer.c,在irda_raw.h里定义一个数据结构体,包含极性和脉冲宽度:

#ifndef _IRDA_RAW_H
#define _IRDA_RAW_H

typedef struct irda_raw_event {
	int pol; /* 极性 */
	int duration;  /* 脉冲宽度, us */
}irda_raw_event, *p_irda_raw_event;

#endif /* _IRDA_RAW_H */

然后在circle_buffer.c实现环形缓冲区。

先定义个irda_raw_event类型的g_events[]数组,这里大小设置为1024,

之前介绍过,每传一次irda,至少会传67次数据,因此这个buf要至少大于67行,再定义两个读写指针位置。

static irda_raw_event g_events[1024];
static int g_r = 0;
static int g_w = 0;

判断buf是否是空的函数:

static int is_ir_event_buf_empty(void)
{
	return g_r = g_w;
}

判断buf是否是满的函数:

static int is_ir_event_buf_full(void)
{
	return NEXT_PLACE(g_w) == g_r;
}

其中,(w+1)%LEN使用宏NEXT_PLACE(i)代替,宏的定义如下:

#define NEXT_PLACE(i) ((i+1)&0x3FF)

%的操作使用位&操作实现一样的效果。

然后是把数据放入缓冲区:

int ir_event_put(p_irda_raw_event pd)
{
	if (is_ir_event_buf_full())
		return -1;
	g_events[g_w] = *pd;
	g_w = NEXT_PLACE(g_w);
	return 0;
}

先判断的缓冲区是否已满,没满的话就在写的位置放入数据,然后写位置再移动到下一个。

最后是读数据:

int ir_event_get(p_irda_raw_event pd)
{
	if (is_ir_event_buf_empty())
		return -1;
	*pd = g_events[g_r];
	g_r = NEXT_PLACE(g_r);
	return 0;
}

先判断的缓冲区是否是空,没空的话就在读的位置读出数据,然后读位置移到到下一个。

修改Makefile,添加本次写的新文件。

「新品首发」STM32MP157开发板火爆预售!首批仅300套

Tags:

最近发表
标签列表