目录
概述
本文介绍了在nRF52832开发板上使用Zephyr操作系统进行FIFO(先进先出队列)功能开发的软硬件环境及实现步骤。软件开发环境基于Nordic提供的nRF Connect SDK,集成了Zephyr平台、编译工具链和VS Code开发环境。硬件环境为nRF52832开发板,具备丰富的接口和调试功能。文章详细描述了FIFO的API函数及其使用方法,包括初始化、数据放入和获取等操作。通过生产者-消费者模型,展示了如何在Zephyr中实现FIFO功能,并提供了完整的代码示例。最后,文章介绍了使用VS Code编译和测试代码的过程,确保功能正常运行。
1. 软硬件环境
1.1 软件开发环境
nordic提供了基于zephyr平台sdk, 其提供了大量的demo可供开发者参考和使用,同时nordi还提供一个集成的软件库工具,方便开发者安装相应的SDK和编译工具链。集成环境同时包含了其他的一些软件,非常便于进行项目开发。
软件工具 | 功能 | 版本信息 |
nRF Connect SDK | nordic提供基于zephyr的代码库 | v2.9.0 |
nRF Connect SDK Toolchain | 代码编译工具 | v2.9.1 |
VS-CODE | 集成开发环境 | v1.99.3 |
nRF Connect for Desktop | nordic集成工具链 | v5.1.0 |
nRF Connect | 手机App |
手机App下载地址:
https://nav.nordicsemi.com/search?query=nRF%20Connect
1.2 硬件环境
本案例是在nRF52832开发板(nRF52-DK)上实现的,该开发板nRF52832的主要特点如下:
1)板载j-link调试接口
2)引出所有 IO接口,用户可根据实际应用,外载其他设备
3)支持4个LED
4)支持4路Key接口
5)板载UART调试接口,方便打印调试信息
2 FIFO的函数接口
zephyr OS提供了操作FIFO API,其具体函数如下:
函数 | 描述 |
---|---|
K_FIFO_DEFINE(name) | 定义并初始化FIFO |
k_fifo_init(fifo) | 运行时初始化FIFO |
k_fifo_put(fifo, data) | 向FIFO放入数据 |
k_fifo_get(fifo, timeout) | 从FIFO获取数据 |
k_fifo_is_empty(fifo) | 检查FIFO是否为空 |
具有使用方法可以参考原文:
Zephyr OS 中的 FIFO 接口应用介绍-CSDN博客
3 FIFO的应用函数实现
3.1 实现步骤
在zephyr OS使用FIFO功能的步骤如下:
Step-1: 使用K_FIFO_DEFINE初始化一个FIFO
Step-2: 使用k_fifo_put接口发送数据
Step-3: 使用 k_fifo_get 函数接收数据,同时释放内存
注意点:
在在zephyr OS使用FIFO需要包括如下头文件:#include <zephyr/kernel.h>
3.2 代码设计
1)定义User的数据格式
struct user_data_t {
void *fifo_reserved;
int value;
};
2)创建和初始化FIFO
static K_FIFO_DEFINE(fifo_tx_data);
3) 设计Producer用于生产数据
void producer_thread( void )
{
printk(" \r\n");
printk(" \r\n");
printk("Produced: run thread \r\n ");
for (int i = 0; i < 300; i++)
{
// 动态分配数据项
struct user_data_t *tx = k_malloc(sizeof(*tx));
tx->value = i;
// 放入FIFO
k_fifo_put(&fifo_tx_data, tx);
printk("Produced: %d \r\n", i);
k_sem_give(&nus_write_sem);
k_sleep(K_MSEC(100));
}
}
4)设计consumer用于使用数据
void consumer_thread( void )
{
int err;
printk(" \r\n");
printk(" \r\n");
err = k_sem_take(&nus_write_sem, K_MSEC(1000));
if (err) {
printk("Consumed: NUS send timeout \r\n");
}
struct user_data_t *item = k_fifo_get(&fifo_tx_data, K_NO_WAIT);
if (item != NULL)
{
printk("Consumed: %d \r\n", item->value);
k_free(item);
}
else
{
printk("Consumed: Timeout waiting for data \r\n");
}
}
3.3 测试代码实现
1)定义生产者线程
/**
* producer
*/
int main_producer_handler(void)
{
for (;;)
{
producer_thread();
}
}
#define STACKSIZE 1024
#define PRIORITY 7
K_THREAD_DEFINE( main_producer_id, STACKSIZE, main_producer_handler, NULL, NULL,
NULL, PRIORITY, 0, 0);
2) 定义消费者线程
/**
* consumer
*/
int main_customers_handler(void)
{
for (;;)
{
consumer_thread();
}
}
#define STACKSIZE_CUSTOMER 1024
#define PRIORITY_CUSTOMER 8
K_THREAD_DEFINE( main_customers_id, STACKSIZE_CUSTOMER, main_customers_handler, NULL, NULL,
NULL, PRIORITY_CUSTOMER, 0, 0);
3.4 源代码文件
/* USER CODE BEGIN Header */
/**
******************************************************************************
* File Name : test_fifo.h
* Description : FIFO test demo
******************************************************************************
* @attention
*
* COPYRIGHT: Copyright (c) 2025 mingfei_tang
* DATE: MAR 27th, 2025
******************************************************************************
*/
/* USER CODE END Header */
#include "test_fifo.h"
#include <zephyr/kernel.h>
#include <zephyr/sys/printk.h>
K_SEM_DEFINE(nus_write_sem, 0, 1);
// 数据项结构
struct user_data_t {
void *fifo_reserved;
int value;
};
static K_FIFO_DEFINE(fifo_tx_data);
void producer_thread( void )
{
printk(" \r\n");
printk(" \r\n");
printk("Produced: run thread \r\n ");
for (int i = 0; i < 300; i++)
{
// 动态分配数据项
struct user_data_t *tx = k_malloc(sizeof(*tx));
tx->value = i;
// 放入FIFO
k_fifo_put(&fifo_tx_data, tx);
printk("Produced: %d \r\n", i);
k_sem_give(&nus_write_sem);
k_sleep(K_MSEC(100));
}
}
void consumer_thread( void )
{
int err;
printk(" \r\n");
printk(" \r\n");
err = k_sem_take(&nus_write_sem, K_MSEC(1000));
if (err) {
printk("Consumed: NUS send timeout \r\n");
}
struct user_data_t *item = k_fifo_get(&fifo_tx_data, K_NO_WAIT);
if (item != NULL)
{
printk("Consumed: %d \r\n", item->value);
k_free(item);
}
else
{
printk("Consumed: Timeout waiting for data \r\n");
}
}
/**
* producer
*/
int main_producer_handler(void)
{
for (;;)
{
producer_thread();
}
}
#define STACKSIZE 1024
#define PRIORITY 7
K_THREAD_DEFINE( main_producer_id, STACKSIZE, main_producer_handler, NULL, NULL,
NULL, PRIORITY, 0, 0);
/**
* consumer
*/
int main_customers_handler(void)
{
for (;;)
{
consumer_thread();
}
}
#define STACKSIZE_CUSTOMER 1024
#define PRIORITY_CUSTOMER 8
K_THREAD_DEFINE( main_customers_id, STACKSIZE_CUSTOMER, main_customers_handler, NULL, NULL,
NULL, PRIORITY_CUSTOMER, 0, 0);
/** End of */
4 编译和测试
4.1 编译代码
使用Vs-code创建工程,并且编写代码,其软件架构如下:
4.2 测试
编译完成后,下载代码至MCU,运行代码,其运行结果如下:
1) 启动过程
2) 使用FIFO生产和消费数据