基于FreeRTOS下的ADC采样实现在Steam buffer里存储数据

目录

目录

1.关于stream buffer介绍

2.关于ADC的配置:

2.1配置使能ADC:

​编辑2.2 任意位置按 Ctrl+S 将开始自动生成代码。

 3.关于FreeRTOS的配置:

3.1引入头文件

3.2创建流缓冲区​编辑 

3.3在任务里面获取ADC采样数据并存储:

 3.4在另一个任务里面获取stream buffer里面的数据:

 4.通过串口打印工具,打印出数据在PC端显示


1.关于stream buffer介绍

         流缓冲区是FreeRTOSV10.0.0新增的一个功能,一种优化的进程间通信机制,专门用于只有一个写入者和一个读取者的场景,能够通过流缓冲区写入和读取任意字节长度的字节数据流。用户需要先创建一个流缓冲区,然后才可以使用它。使用原理如图1-1所示,有一个任务向流缓冲区写入数据,称为写入者(writer),有一个任务向流缓冲区读出数据,称为读取者(reader)

        创建流缓冲区时,用户需要设定其存储容量,例如1024字节。使用流缓冲区时,写入者一次可以写入任意长度的字节数据流,但是不能超过流缓冲区的存储容量,(本人在实现的时候没有考虑流缓冲和我所设置任务栈的存储容量,导致在读取数据的时候出现栈溢出,数据乱码的情况和任务发生阻塞的情况,通过调用printf不断调试打印,最终找到问题所在)。读取者一次可以读出任意长度的字节数据流,字节数据流没有起始符和结束符。使用流缓冲区在进程间传输数据时,使用的是复制数据的方式,即写入者将数据复制到流缓冲区,读取者从流缓冲区复制出数据。流缓冲区就像是一个管道,字节数据流在其中流动。

        流缓冲与队列有点像,但两者是有区别的:队列的数据分为基本的项(item),项的格式是固定的,例如uint32_t类型的项,每次写入或读取一个项;流缓冲区的数据只是字节数据流,写入和读出的数据长度是任意的。

2.关于ADC的配置:

从原理图和CPU管脚图上可以看出,环境光传感器使用ACD1_IN15,而声音传感器则使用ACD1_IN116。

2.1配置使能ADC:

配置 ADC1,使能通道 IN15 和 IN16,选择 Single-ended(Differential 为差分信号),这时候
PA4和PA6两个管脚就设置为ADC输入模式了。

 

ADC 的时钟最好不要设置得太高,这里调整为 12MHz:

2.2 任意位置按 Ctrl+S 将开始自动生成代码。

修改 adc.c 文件,添加环境光强传感器和的声音传感器实现:

/* USER CODE BEGIN 1 */
enum
{
	ADCCHN_NOISY,
	ADCCHN_LUX,
	ADCCHN_MAX,
};
int adc_sample_lux_noisy(uint32_t *lux, uint32_t *noisy)
{
	uint8_t i;
	uint32_t timeout = 0xffffff;
for(i=0; i<ADCCHN_MAX; i++)
{
	HAL_ADC_Start(&hadc1);
	HAL_ADC_PollForConversion(&hadc1, timeout);
if( ADCCHN_NOISY == i )
{
	*noisy = HAL_ADC_GetValue(&hadc1);
}
else if( ADCCHN_LUX == i )
{
	*lux = HAL_ADC_GetValue(&hadc1);
}
	HAL_Delay(10);
}
	HAL_ADC_Stop(&hadc1);
return 0;
}
/* USER CODE END 1 */

 3.关于FreeRTOS的配置:

在FreeRTOS里面创建两个任务,一个任务负责采样存储,将采样的数据存储到Steam buffer里面

在创建任务的时候,要修改任务栈空间的大小,如果栈空间过小,任务执行的时候会出现堵塞。我在这里将128大小的栈空间改成256。使用以上方法创建两个任务,任务的优先级相同,用 ospriorityNormal,以下是创建好的任务。

3.1引入头文件

 定义一个宏来制定流缓冲区大小,和触发水平。在这里聊一聊触发水平:当流缓冲区中的可用数据量达到或超过要求的字节数时,任务将被唤醒并继续执行。这意味着只有当有足够的数据可供读取时,任务才会继续执行。

3.2创建流缓冲区 

3.3在任务里面获取ADC采样数据并存储:

 3.4在另一个任务里面获取stream buffer里面的数据:

 4.通过串口打印工具,打印出数据在PC端显示

 上面的代码中设置触发水平为20,那么一个任务在读取流缓冲区时,当流缓冲区里的数据达到20字节时,就会解除读取者的阻塞状态,触发水平可以设置为1,但是不能超过流缓冲区大小。


  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的使用FreeRTOS实现ADC信号采集的步骤: 1. 确定需要采集的ADC通道和采样频率。 2. 在FreeRTOS中创建一个ADC任务,用于定期读取ADC值并将其发送到队列。 3. 在任务中初始化ADC,并设置采样频率和通道。 4. 使用FreeRTOS提供的延时函数等待ADC转换完成。 5. 读取ADC值,并将其发送到队列。 6. 在另一个任务中接收队列中的ADC值,并进行处理。 下面是一个简单的代码示例: ``` /* ADC任务 */ void vADCTask(void *pvParameters) { TickType_t xLastWakeTime; const TickType_t xFrequency = 100; /* 采样频率为100Hz */ QueueHandle_t xQueue; int adc_value; /* 创建队列 */ xQueue = xQueueCreate(10, sizeof(int)); /* 初始化ADC */ HAL_ADC_Start(&hadc1); /* 循环读取ADC值 */ while (1) { /* 等待ADC转换完成 */ vTaskDelayUntil(&xLastWakeTime, xFrequency); /* 读取ADC值 */ adc_value = HAL_ADC_GetValue(&hadc1); /* 将ADC值发送到队列 */ xQueueSend(xQueue, &adc_value, 0); } } /* 处理ADC值的任务 */ void vProcessTask(void *pvParameters) { QueueHandle_t xQueue; int adc_value; /* 获取队列句柄 */ xQueue = *((QueueHandle_t *) pvParameters); /* 循环接收队列中的ADC值 */ while (1) { /* 等待队列有数据可读 */ xQueueReceive(xQueue, &adc_value, portMAX_DELAY); /* 处理ADC值 */ printf("ADC value: %d\n", adc_value); } } /* 主函数 */ int main(void) { /* 创建ADC任务 */ xTaskCreate(vADCTask, "ADC", 100, NULL, 1, NULL); /* 创建处理任务 */ QueueHandle_t xQueue; xTaskCreate(vProcessTask, "Process", 100, (void *) &xQueue, 1, NULL); /* 启动调度器 */ vTaskStartScheduler(); /* 永远不会运行到这 */ return 0; } ``` 注意,以上代码仅为示例,您需要根据您的具体应用场景进行修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值