![3863193a4c67994894621473de51f1f9.png](https://i-blog.csdnimg.cn/blog_migrate/30fb0fe5d57c35d55b1ccda1d1d7b83d.jpeg)
来源:百问网_嵌入式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],它的结构如下:
![d61bb52efe3d8d0b40b5f245a066f960.png](https://i-blog.csdnimg.cn/blog_migrate/b9284ba49a1d419867b002b1fb8f805f.jpeg)
定义一个读指针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_Htypedef 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套