当前位置: 首页 > wzjs >正文

学做招投标的网站有哪些网络营销的模式有哪些

学做招投标的网站有哪些,网络营销的模式有哪些,网站注册,怎么做原创短视频网站目录 一、消息缓冲区功能概述 二、消息缓冲区操作相关函数 1、相关函数概述 2、部分函数详解 (1)创建消息缓冲区 (2)写入消息 (3)读取消息 (4)消息缓冲区状态查询 三、消息…

目录

一、消息缓冲区功能概述

二、消息缓冲区操作相关函数

1、相关函数概述

2、部分函数详解

(1)创建消息缓冲区

(2)写入消息

(3)读取消息

(4)消息缓冲区状态查询

三、消息缓冲区使用示例

1、示例功能与CubeMX项目设置

(1)RCC、SYS、Code Generator、USART3、TIM6

(2)RTC的设置

(3)FreeRTOS的设置

(4)NVIC

2、程序功能实现

(1)主程序

(2)FreeRTOS对象初始化

(3)RTC的唤醒中断

(4)任务Task_Show的功能

3、运行调试


一、消息缓冲区功能概述

        消息缓冲区(message buffer)是基于流缓冲区实现的,也就是它的实现使用了流缓冲区的技术,如同信号量是基于队列实现的。与流缓冲区的差异在于:消息缓冲区传输的是可变长度的消息,如10字节、20字节或35字节的消息。写入者向消息缓冲区写入一个10字节的消息,读取者也必须以10字节的消息读出,而不是像流缓冲区那样,按字节流读出。

        每个消息都有一个消息头,就是消息数据的字节数。在STM32 MCU上,消息头就是一个uint32_t类型的整数。消息头的写入和读取是由FreeRTOS的API函数自动处理的,例如,向消息缓冲区写入一个长度为20字节的消息,实际占用空间是24字节。

        消息缓冲区没有触发水平,写入和读取都是以一条消息为单位的,操作要么成功,要么失败。

        消息缓冲区的其他特性与流缓冲区一样。例如:在只有一个写入者和一个读取者的情况下,可以安全操作消息缓冲区;如果有多个写入者或多个读取者,读写消息缓冲区的代码必须在临界代码段内,且等待时间必须设置为0。

二、消息缓冲区操作相关函数

1、相关函数概述

        消息缓冲区相关函数的头文件message_buffer.h,源程序都在文件stream_buffer.c里,因为消息缓冲区是基于流缓冲区实现的,要在程序中使用消息缓冲区,需包含头文件message_buffer.h。

分组

函数

功能

创建


删除

xMessageBufferCreate()

创建一个消息缓冲区,只需设置缓冲区大小

xMessageBufferCreateStatic()

创建一个消息缓冲区,静态分配内存

vMessageBufferDelete()

删除一个消息缓冲区

xMessageBufferReset()

复位一个消息缓冲区,清空数据。只有没有任务在阻塞状态下读或写消息缓冲区时,才可以复位消息缓冲区

写入

xMessageBufferSend()

向消息缓冲区发送一个消息

xMessageBufferSendFromISR()

xMessageBufferSend()的ISR版本

读取

xMessageBufferReceive()

从消息缓冲区接收一条消息

xMessageBufferReceiveFromISR()

xMessageBufferReceive()的ISR版本

状态

查询

xMessageBufferIsEmpty()

查询消息缓冲区是否为空,返回值pdTRUE表示无任何消息

xMessageBufferIsFull()

查询消息缓冲区是否满了,返回值pdTRUE表示不能
再写入任何消息

xMessageBufferSpacesAvailable()

查询消息缓冲区的剩余存储空间

        与流缓冲区不同的是:消息缓冲区无须设置触发水平,在写入或读取消息超时的时候,实际写入或读取的数据字节数为0,不会只写入或读取部分数据。

2、部分函数详解

(1)创建消息缓冲区

        用于创建消息缓冲区的函数是xMessageBufferCreate(),这是个宏函数,其原型定义如下:

/**
* \defgroup xMessageBufferCreate xMessageBufferCreate
* \ingroup MessageBufferManagement
*/
#define xMessageBufferCreate( xBufferSizeBytes ) ( MessageBufferHandle_t ) xStreamBufferGenericCreate( xBufferSizeBytes, ( size_t ) 0, pdTRUE )

        调用函数xMessageBufferCreate()时,只需传递缓冲区大小xBufferSizeBytes。这个函数实际上调用了函数xStreamBufferGenericCreate(),传递的触发水平参数为0,因为消息缓冲区没有触发水平,最后的参数pdTRUE表示要创建的是消息缓冲区。

        函数xMessageBufferCreate()的返回值是MessageBufferHandle_t类型的,就是所创建的消息缓冲区对象指针。

(2)写入消息

        用于向消息缓冲区写入消息的函数是xMessageBufferSend(),这是个宏函数,其原型定义如下:

/**
* \defgroup xMessageBufferSend xMessageBufferSend
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSend( xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait ) xStreamBufferSend( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, xTicksToWait )

        实际上,它是执行了流缓冲区写入数据的函数xStreamBufferSend()。函数中各参数的意义如下。

  • xMessageBuffer,所操作的消息缓冲区的句柄。
  • pvTxData,准备写入的数据缓冲区指针。
  • xDataLengthBytes,消息数据的字节数,不包括消息头的4字节。
  • xTicksToWait,等待的节拍数,如果消息缓冲区没有足够的空间用于写入这条消息,任务可以进入阻塞状态等待。若设置为0,则表示不等待;若设置为portMAX_DELAY,则表示一直等待。

        函数xStreamBufferSend()内部会判断传递来的缓冲区对象的类型。如果是消息缓冲区,就在实际写入数据前面加上一个uint32_t类型的整数,表示消息的字节数;如果是流缓冲区,就直接写入数据。

        函数xMessageBufferSend()的返回值是实际写入消息的字节数,不包括消息头的4字节。如果函数是因为等待超时而退出的,则返回值为0;如果写入成功,返回值就是写入的消息数据的字节数。这是与流缓冲区不同的一个地方,使用函数xStreamBufferSend()向流缓冲区写入数据时,如果因等待超时而退出,仍然可能向流缓冲区写入了一些数据。

        在ISR中,向消息缓冲区写入消息的函数是xMessageBufferSendFromISR(),它是个宏函数,实际就是执行了函数xStreamBufferSendFromISR(),其原型定义如下:

/**
* \defgroup xMessageBufferSendFromISR xMessageBufferSendFromISR
* \ingroup MessageBufferManagement
*/
#define xMessageBufferSendFromISR( xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferSendFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvTxData, xDataLengthBytes, pxHigherPriorityTaskWoken )

(3)读取消息

        用于从消息缓冲区读取消息的函数是xMessageBufferReceive(),其原型定义如下:

/**
* \defgroup xMessageBufferReceive xMessageBufferReceive
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReceive( xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait ) xStreamBufferReceive( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, xTicksToWait )

        它就是执行了函数xStreamBufferReceive()。函数中各参数的意义如下。

  • xMessageBuffer,所操作的消息缓冲区的句柄。
  • pvRxData,保存读出数据的缓冲区指针。
  • xBufferLengthBytes,缓冲区pvRxData的长度,也就是最大能读取的字节数。
  • xTicksToWait,等待的节拍数。如果消息缓冲区里没有消息,任务可以进入阻塞状态等待。若设置为0,则表示不等待;若设置为portMAX_DELAY,则表示一直等待。

        函数xStreamBufferReceive()会自动区分参数xMessageBuffer是流缓冲区,还是消息缓冲区。如果是消息缓冲区,它会先读取表示消息长度的4字节消息头,然后按照长度读取后面的消息数据。

        函数xMessageBufferReceive()返回的是实际读取的消息的字节数,不包括消息头的4字节。如果函数是因为等待超时而退出的,则返回值为0。

        在ISR中从消息缓冲区读取消息的函数是xMessageBufferReceiveFromISR(),它是个宏函数,实际就是执行了函数xStreamBufferReceiveFromISR(),其原型定义如下:

/**
* \defgroup xMessageBufferReceiveFromISR xMessageBufferReceiveFromISR
* \ingroup MessageBufferManagement
*/
#define xMessageBufferReceiveFromISR( xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken ) xStreamBufferReceiveFromISR( ( StreamBufferHandle_t ) xMessageBuffer, pvRxData, xBufferLengthBytes, pxHigherPriorityTaskWoken )

(4)消息缓冲区状态查询

        以下几个查询消息缓冲区状态的函数,只需使用消息缓冲区的句柄作为函数的输入参数。

  • xMessageBufferIsEmpty()查询一个消息缓冲区是否为空,若返回pdTRUE,则表示缓冲区不包含任何消息。
  • xMessageBufferIsFull()查询一个消息缓冲区是否已满,若返回pdTRUE,则表示不能再写入任何消息。
  • xMessageBufferSpacesAvailable()查询一个消息缓冲区剩余的存储空间字节数,返回值类型为uint32_t。

三、消息缓冲区使用示例

1、示例功能与CubeMX项目设置

        本示例演示消息缓冲区的使用,实例的功能和使用流程如下。

  • 创建一个消息缓冲区和一个任务Task_Show。
  • 使用RTC的唤醒中断,唤醒周期为1s。在RTC的唤醒中断里读取当前时间,转化为字符串后,作为消息写入消息缓冲区,每次写入的消息长度不一样。
  • 在任务Task_Show里读取消息缓冲区的消息,并在串口助手上显示。
  • 继续使用旺宝红龙开发板STM32F407ZGT6 KIT V1.0。

  • 一些设置可以参考本文作者写的其他文章:

        细说STM32单片机FreeRTOS流缓冲区及其应用实例-CSDN博客  https://wenchm.blog.csdn.net/article/details/148168854?spm=1011.2415.3001.5331

(1)RCC、SYS、Code Generator、USART3、TIM6

        配置时钟树,将APB1定时器时钟频率设置为84MHz,APB2定时器时钟频率设置为168MHz ;设置TIM6作为基础时钟源;其它设置可见参考文章。

(2)RTC的设置

        启用LSE,启用RTC,在时钟树上将LSE作为RTC的时钟源。启用周期唤醒功能,设置唤醒周期为1s,其他参数用默认值即可。

 

(3)FreeRTOS的设置

        设置FreeRTOS接口为CMSIS_V2,所有“Config”和“Include”参数保持默认值。在FreeRTOS里创建一个任务Task_Show,其主要参数如图所示。

(4)NVIC

        在NVIC里开启RTC唤醒中断,设置其中断优先级为5,因为要在其ISR里使用FreeRTOS API函数。

2、程序功能实现

(1)主程序

        完成设置后,CubeMX自动生成代码。在CubeIDE中打开项目,添加用户功能代码后,主程序代码如下:

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "rtc.h"
#include "usart.h"
#include "gpio.h"/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void MX_FREERTOS_Init(void);/*** @brief  The application entry point.* @retval int*/
int main(void)
{/* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* Configure the system clock */SystemClock_Config();/* Initialize all configured peripherals */MX_GPIO_Init();MX_RTC_Init();MX_USART3_UART_Init();/* USER CODE BEGIN 2 *///Start Menuuint8_t startstr[] = "Demo9_2:Using Message Buffer.\r\n\r\n";HAL_UART_Transmit(&huart3,startstr,sizeof(startstr),0xFFFF);/* USER CODE END 2 *//* Init scheduler */osKernelInitialize();/* Call init function for freertos objects (in cmsis_os2.c) */MX_FREERTOS_Init();/* Start scheduler */osKernelStart();/* We should never get here as control is now taken by the scheduler *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */}/* USER CODE END 3 */
}

(2)FreeRTOS对象初始化

        自动生成的函数MX_FREERTOS_Init()只创建了任务,在CubeMX里不能可视化地创建消息缓冲区,需要在CubeMX生成的CubeIDE初始代码的基础上,编程创建消息缓冲区。在文件freertos.c中定义两个常量和消息缓冲区对象,在函数MX_FREERTOS_Init()中增加创建消息缓冲区对象的代码。完成后的代码如下:

        自动生成includes,并手动添加私有includes: 

/* Includes ------------------------------------------------------------------*/
#include "FreeRTOS.h"
#include "task.h"
#include "main.h"
#include "cmsis_os.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "message_buffer.h"
#include "usart.h"
#include <stdio.h>		//用到函数sprintf()
#include <string.h>		//用到函数strlen()
/* USER CODE END Includes */

        手动添加私有宏定义:

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define	MSG_BUFFER_LEN	50		//消息缓存区长度,单位:字节
#define	MSG_MAX_LEN		20		//消息最大长度,单位:字节
/* USER CODE END PD */

        手动添加创建消息缓冲区句柄变量代码;

        自动生成任务函数句柄变量代码:

/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN Variables */
MessageBufferHandle_t  msgBuffer;		//消息缓存区句柄变量
/* USER CODE END Variables */
/* Definitions for Task_Show */
osThreadId_t Task_ShowHandle;
const osThreadAttr_t Task_Show_attributes = {.name = "Task_Show",.stack_size = 256 * 4,.priority = (osPriority_t) osPriorityNormal,
};/* Private function prototypes -----------------------------------------------*/
/* USER CODE BEGIN FunctionPrototypes *//* USER CODE END FunctionPrototypes */void AppTask_Show(void *argument);void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) *//*** @brief  FreeRTOS initialization* @param  None* @retval None*/
void MX_FREERTOS_Init(void) 
{/* Create the thread(s) *//* creation of Task_Show */Task_ShowHandle = osThreadNew(AppTask_Show, NULL, &Task_Show_attributes);/* USER CODE BEGIN RTOS_THREADS *//* add threads, ... */msgBuffer=xMessageBufferCreate(MSG_BUFFER_LEN);		//创建消息缓存区/* USER CODE END RTOS_THREADS */
}

(3)RTC的唤醒中断

        在RTC的唤醒中断里读取当前时间,将其转换为字符串后写入消息缓冲区。RTC唤醒中断的回调函数是HAL_RTCEx_WakeUpTimerEventCallback()。为便于使用消息缓冲区句柄变量msgBuffer,在文件freertos.c中重新实现这个回调函数:

/* Private application code --------------------------------------------------*/
/* USER CODE BEGIN Application */
void HAL_RTCEx_WakeUpTimerEventCallback(RTC_HandleTypeDef *hrtc)
{RTC_TimeTypeDef sTime;RTC_DateTypeDef sDate;if (HAL_RTC_GetTime(hrtc, &sTime,  RTC_FORMAT_BIN) != HAL_OK)return;if (HAL_RTC_GetDate(hrtc, &sDate,  RTC_FORMAT_BIN) !=HAL_OK)return;char dtArray[MSG_MAX_LEN];   						//存储消息的数组, MSG_MAX_LEN=20if ((sTime.Seconds % 2)==0)  						//分奇偶秒,发送不同长度的消息字符串siprintf(dtArray,"Seconds = %u",sTime.Seconds);	//转换为字符串,自动加'\0'elsesiprintf(dtArray,"Minute= %u",sTime.Minutes);	//转换为字符串,自动加'\0'uint8_t bytesCount=strlen(dtArray);					//字符串长度,不带最后的结束符BaseType_t  highTaskWoken=pdFALSE;if (msgBuffer != NULL){uint16_t  realCnt=xMessageBufferSendFromISR(msgBuffer,dtArray, bytesCount+1, &highTaskWoken);  // bytesCount+1,带结束符'\0'printf("Write bytes=   %d\r\n", realCnt);		 //实际写入消息长度portYIELD_FROM_ISR(highTaskWoken);				 //申请进行一次任务调度}
}int __io_putchar(int ch)
{HAL_UART_Transmit(&huart3,(uint8_t*)&ch,1,0xFFFF);return ch;
}
/* USER CODE END Application */

        上述程序首先读取RTC的时间和日期,根据当前时间的秒数是奇数还是偶数,生成不同长度的字符串数据并保存到数组dtArray里。这里用到了C语言标准库中的两个函数siprintf()和strlen()。siprintf()与printf()类似,只是把字符串写入一个数组,并且在字符串最后自动添加结束符\0。strlen()用于得到字符串的长度,但是不包括最后的结束符。

        在使用函数xMessageBufferSendFromISR()向消息缓冲区写入消息时,执行的代码如下:

uint16_t realCnt = xMessageBufferSendFromISR(msgBuffer,dtArray,bytesCount+1,&highTaskwoken);

        这里传递的第3个参数值是bytesCount+1,也就是加上了字符串的结束符,否则,读取者读出的消息字符串将不带结束符,串口助手将无法正常显示字符串。bytesCount+1的值必须小于或等于MSG_MAX_LEN。

        函数的返回值realCnt是实际写入的消息长度,不带消息头的4个字节。如果消息写入成功,那么realCnt等于bytesCount+1。

        这里写入消息的数据是字符串,这只是为了演示方便,实际写入消息的数据可以是任意类型的数据,而不一定是字符串。

(4)任务Task_Show的功能

        在任务Task_Show里读取消息缓冲区里的消息,并在串口助手上显示,其任务函数代码如下:

/* USER CODE BEGIN Header_AppTask_Show */
/*** @brief  Function implementing the Task_Show thread.* @param  argument: Not used* @retval None*/
/* USER CODE END Header_AppTask_Show */
void AppTask_Show(void *argument)
{/* USER CODE BEGIN AppTask_Show *//* Infinite loop */uint8_t dtArray[MSG_MAX_LEN];								//读出的数据临时保存数组for(;;){uint16_t realCnt=xMessageBufferReceive(msgBuffer, dtArray,MSG_MAX_LEN, portMAX_DELAY);					//读取消息printf("Read message bytes  =  %d\r\n", realCnt);		//实际读出字节数printf("message string Read =  %s\r\n", dtArray);		//显示读出的消息字符串}/* USER CODE END AppTask_Show */
}

        上述程序用函数xMessageBufferReceive()读取消息缓冲区里的消息,然后在串口助手上显示实际读取的消息长度和消息字符串。调用函数xMessageBufferReceive()的代码如下:

uint16_t realCnt = xMessageBufferReceive(msgBuffer,dtArray,MSG_MAX_LEN,portMAX_DELAY);

        其中,dtArray是用于存储读出数据的uint8_t类型数组,传递的第3个参数是MSG_MAX_LEN,也就是最大可以读取的消息的长度。函数返回值realCnt是实际读取的消息的长度,不包括消息头的4个字节。MSG_MAX_LEN应该大于或等于realCnt,否则,会导致无法读出一条完整的消息。

3、运行调试

        构建项目后,下载到开发板上并运行测试,会发现显示的写入消息长度和读出消息长度是一致 的,串口助手上显示的消息字符串也是正确的,说明可以写入和读出不同长度的消息。在实际使用消息缓冲区时,写入者和读取者之间应该定义好消息的格式,如同串口通信一样定义通信协议。

http://www.dtcms.com/wzjs/333849.html

相关文章:

  • 珠海市网站开发公司18款禁用网站app直播
  • 办公网络建设项目商务要求描述优化方法
  • 成都学习网站建设电商培训班一般多少钱
  • 有专门做英文字幕的网站吗百度推广投诉热线
  • 东莞房价2023最新价格网站seo优化培训
  • onedrive 做网站静态网站恶意点击软件
  • 做设计英文网站av手机在线精品
  • 柳林网站建设比较靠谱的电商培训机构
  • wordpress修改站点名百度在西安的公司叫什么
  • 建设企业网站平台主要的目的是太原做网络推广的公司
  • 常州企业自助建站燕郊今日头条
  • 企业建设网站目的是什么网站建设公司业务
  • 口碑最好的装饰公司网站建设公司seo关键词
  • 垦利区建设局网站2023年10月疫情恢复
  • 黄浦做网站公司重庆seo推广
  • 什么网站做服装批发比较大google play 安卓下载
  • 订阅号怎么做免费的视频网站企拓客app骗局
  • 网站建设的发票怎么做会计分录网络营销试卷
  • 晋江网站建设费用今日腾讯新闻最新消息
  • 电脑配件经营网站的建设营销推广软件
  • 什么网站教做美食kol推广
  • 如果一个网站没有备案免费b站在线观看人数在哪
  • 能进入各种网站的浏览器app拉新一手渠道
  • 做钢管用哪个门户网站广州seo网站排名
  • 福州网站建设案例如何在百度发广告推广
  • 门户网站 建设 投入网络营销渠道可分为哪些
  • 惠来做网站广告营销包括哪些方面
  • wordpress前端投稿上传图片网站优化助手
  • 济宁网站建设_云科网络杭州市优化服务
  • 佛山网站定制开发今晚日本比分预测