FreeRTOS学习——Systick中断、SVC中断、PendSV中断 当SVC指令被执行后,处理器会根据中断向量表中的信息跳转到相应的SVC中断处理函数,执行SVC指令时,处理器会自动保存当前的上下文,并将处理器的模式切换为特权模式,从而允许执行受限的操作。ldr r3, pxCurrentTCBConst2:将pxCurrentTCBConst2的值(即pxCurrentTCB的地址)加载到寄存器r3中。配置系统的滴答定时器,以允许操作系统根据配置的频率生成定时中断,从而支持任务的调度和管理。msr psp, r0:将恢复后的任务栈指针r0存入PSP(进程栈指针)。
FreeRTOS学习——接口宏portmacro.h 原子操作是指在多线程或多任务环境中,**一个操作要么完全执行成功,要么完全不执行,不会在中间被挂起或打断。**对于时间片操作,若标识为原子,在此期间所有对时间片的修改和读取都是一个不可分割的动作。
FreeRTOS学习——链表list FreeRTOS学习——链表(列表)list,仅用于记录自己阅读与学习源码*list_t只能存储指向list_item_t的指针。每个list_item_t都包含一个数值(xItemValue)。大多数时候,列表是按项目值升序排列的。*创建的列表已包含一个列表项。此项的值是可以存储的最大值,因此它始终位于列表的末尾,并充当标记。列表成员pxHead始终指向此标记,即使它位于列表的末尾。这是因为尾部包含一个返回指针,指向列表的真正头部。
FreeRTOS学习——代码覆盖率测试宏mt 在代码中使用 mtCOVERAGE_TEST_MARKER() 时,预处理器会直接移除这个宏调用,不会留下任何代码。mtCOVERAGE_TEST_DELAY特意放在代码的一个关键部分,通常是为了确保通过操作函数时,所有逻辑判断和指针操作都能被仔细测试。#define mtCOVERAGE_TEST_MARKER() ((void)0) 表示宏展开为一个空操作,保留一个空语句。它的主要目的是确保在某些特定情况下,代码的所有可能路径都能被测试到。它确保在某些特定情况下,代码的所有可能路径都能被测试到。
使用Clion开发STM32——移植FreeRTOS 其实在STM32cubeMX中就可以直接配置FreeRTOS,rtthread等操作系统,而且使用接口封装过的,很方便。但我还是想手动一直一遍,肯定有不一样的收获。
FreeModbus学习——接收状态机xMBRTUReceiveFSM 当接收状态机状态为初始化态,接收到一个数据,进入接收状态机,不存储这个数据,而是重启定时器。再接收,再重启,直到这一帧完成(帧与帧之间会有个时间间隔),然后进入定时器中断,将接收状态机变为空闲态,并发布ready事件,代表协议栈就绪。协议栈使能后,会将接收状态机赋值为初始化态,串口接收使能,且定时器也使能(重新计数),定时器进入溢出中断,然后会将接收状态机由初始化态变为空闲态。然后再将接收状态机置为空闲态。当接收状态机为空闲态时,开始接收第一个数据作为帧首,然后将接收状态机置为接收态,重新计数定时器。
FreeModbus学习——定时器 接收状态机为空闲态时,接收到一个字符,会进入串口接收中断,串口接收中断中会将接收到的字符保存作为帧首,并且把接收状态机变为STATE_RX_RCV。但是万一这个时候串口接收寄存器已经有数据了咋办,那会进入串口接收中断函数,会调用xMBRTUReceiveFSM,当接收状态机为STATE_RX_INIT时,会清空定时器重新计数。当接收状态机为空闲态STATE_RX_IDLE,接收到第一个数据时作为帧首,然后接收状态机进入接收态STATE_RX_RCV,并且使能定时器(重新计数)。说明一帧已经接收完毕。
FreeModbus学习——读输入寄存器eMBFuncReadInputRegister 也就是说经过eMBFuncReadInputRegister这个函数处理之后,打包好的帧已经放在了pucFrame,长度放在了usLen。调用回调函数eMBRegInputCB读取寄存器数据,eMBRegInputCB这个函数会把读到的数据继续存放在pucFrameCur 帧里。就是说这个指针pucFrameCur刚开始指向pucFrame这一帧数据的起始位置,然后打包一个数据,pucFrameCur+一个。读寄存器数据,其实就是读数组嘛,寄存器是16位的,所以定义数组也是16位的SHORT型。
FreeModbus学习——xFuncHandlers功能码处理 这句话就是说,定义了一个变量,这个变量是pxMBFunctionHandler 函数指针类型。在mb.c文件中,有一个数组是static xMBFunctionHandler xFuncHandlers[MB_FUNC_HANDLERS_MAX]首先看这个数组的类型 :xMBFunctionHandler ,也就是说这个数组中的每一个元素都是xMBFunctionHandler。以读输入寄存器为例(首先要在mbconfig.h文件中打开这个功能(默认打开))那么这个读输入寄存器函数在哪?
FreeModbus学习——eMBPoll轮询 接收状态机为空闲态时(每次定时器溢出中断会将接收机状态置为空闲态),接收到一个字符,会进入串口接收中断,串口接收中断中会将接收到的字符保存作为帧首,并且把接收状态机变为STATE_RX_RCV。直到一帧结束,也就是距离下个字符超过定时器溢出时间,进入定时器中断,此时接收状态机还为STATE_RX_RCV,这就意味着接受完成了一帧。协议栈使能后,会将接收状态机赋值为初始化态,且定时器也使能,定时器进入溢出中断,会将接收状态机由初始化态变为空闲态,并且发布一个EV_READY事件。
FreeModbus学习——eMBEnable协议栈使能 先进行协议栈状态判断,若eMBState == STATE_DISABLED即初始化完成了,就激活协议栈。串口接收使能,发送禁止。在定时器第一次溢出后会将接收状态机的状态由STATE_RX_INIT变为STATE_RX_IDLE。Modbus初始化后,协议栈状态由eMBState由未初始化变成了STATE_DISABLED。先将接收状态机赋值为初始化状态 eRcvState = STATE_RX_INIT;eMBRcvState有四个状态:初始化,空闲态,接收中,帧无效(错误)
FreeModbus学习——eMBInit初始化 在调用xMBPortSerialInit进行串口初始化,这个函数在portserial.c文件中,这个函数是留给用户自己实现的,就是初始化函数,实际上串口初始化放在外面自己初始化也可以,反正只要初始化了就行。所以设置Prescaler = 11999;,这样一个时基就是12000/240000000 = 1/20000 = 1/20ms = 1000/20 us = 50us。在mb.c文件中还定义了几个回调函数指针,这里只用到了前三个,分别是字节接收,发送空,定时器溢出回调函数。
FreeModbus学习——portevent事件 如果队列中有事件,则就将队列中的事件eQueuedEvent赋值给eEvent ,事件被取走了,那么队列里就没有事件了,所以xEventInQueue = FALSE;eEvent 为要发布的事件,将xEventInQueue 置为TRUE,即队列中有事件了,然后将eEvent赋值给eQueuedEvent ,即队列中的事件为eEvent。在mbport.h文件中有事件类型的定义eMBEventType,有事件状态有四种,或者说有四种事件:就绪,帧接收完成,处理,帧发送完成。首先定义了两个静态变量。
rtt设备驱动框架学习——内核对象基类object 这个基类是内核所有对象的基类在rt-thread/include/rtdef.h文件里有对内核对象基类object的定义object属性有 内核对象名字 , 内核对象类型 , 内核对象标志,还有一个链表节点。
rtt设备驱动框架学习——链表 这个宏的作用是通过结构体成员的指针 ptr 和成员名 member,计算出包含该成员的结构体的起始地址,并将其转换为 type 类型的指针。_inline函数也称为内联函数或内嵌函数,_inline定义的类的内联函数,函数代码被放入符号调用表,使用时直接展开,不需要调用,即在编译期间将所调用的函数的代码直接嵌入到主调函数中,是一种。(type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)):将计算结果转换回 type 类型的指针。