stm32 freertos C++ 学习笔记

1.系统时钟计算公式:SYSCLK = HSE*N/(M*P)

2.定时器中断/PWM频率计算公式:TIMXPWM/INT = TIMXCNT/ARR

3.中断优先级:数字越小,优先级越高

4.NVIC_PRIORITYGROUP_4:4位抢占优先级,0位响应优先级

5.任务优先级:数字越大,优先级越高

6.定时器:PWM模式1下,TIMx_CCR1大时有效;PWM模式2下,TIMx_CCR1小有效。默认向上计数,高电平有效。CCRX的值决定占空比,CCRX的值越大,占空比越大。定时器功能强大,用于全局定时,用于PWM控制电机、LED、蜂鸣器,用于传感器固定周期读取数据,用于捕获遥控信号

7.任务状态:运行<-就绪,就绪<-挂起,就绪<-阻塞

8.任务调度:新创建的任务默认就是就绪态的,如果当前没有比它更高优先级的任务运行那么此任务就会立即进入运行态开始运行。任务进入阻塞有多种方式,有延时阻塞,有获取信号量阻塞,有等待通知阻塞。调度器总是选择所有能够进入运行态的任务中具有最高优先级的任务。一个高优先级但不能够运行的任务意味着不会被调度器选中,而代之以另一个优先级虽然更低但能够运行的任务。大多数应用程序中都不会用到挂起状态。高优先级的任务一旦就绪就能及时运行。

9.中断:ISR不改变当前任务的状态。尽管IRQ发生以后,当前运行着的任务执行被暂停,CPU转而执行ISR的代码,但当前任务的状态仍然是Running,并不是变成其它状态——这与任务被抢占明显不同。

10.信号量:使用信号量的目的是为了保护资源,创建一个信号量相当于创建一个队列,创建一个队列相当于分配内存。不管是创建信号量还是释放信号量本质上都是对队列进行操作。主要用于任务之间的资源管理。信号量(semaphores)是 20 世纪 60 年代中期 Edgser Dijkstra 发明的。使用信号量的最初目的是为了给共享资源建立一个标志,该标志表示该共享资源被占用情况。这样,当一个任务在访问共享资源之前,就可以先对这个标志进行查询,从而在了解资源被占用的情况之后,再来决定自己的行为。

11.缓冲区:StreamBuffer也是一种数据结构,类似队列

12.USB:USB也是一种外设,用于通信,类似串口

13.文件系统:文件系统是为了存储和管理数据,而在存储介质上建立的一种组织结构

14.SPI:传感器采用SPI通信,SPI支持一主多从模式,通过片选管脚进行从机选择

15.static:

函数内部的static:函数内的static变量和全局变量从汇编的角度看本质上是一样的。

静态全局变量:全局静态变量是显式用 static 修饰的全局变量,作用域是声明此变量所在的文件,其他的文件即使用 extern 声明也不能使用。对于编程来说,使用静态全局变量的一个优点就是:本变量只能在本文件里面进行修改,不用担心在别的文件中有操作

静态函数:使用static用于函数定义时,对函数的连接方式产生影响,使得函数只在本文件内部有效,对其他文件是不可见的。这样的函数又叫作静态函数。使用静态函数的好处是,不用担心与其他文件的同名函数产生干扰,另外也是对函数本身的一种保护机制。static函数是不能直接被其他文件直接调用的

16.inline:函数调用是有时间和空间开销的。程序在执行一个函数之前需要做一些准备工作,要将实参、局部变量、返回地址以及若干寄存器都压入栈中,然后才能执行函数体中的代码;函数体中的代码执行完毕后还要清理现场,将之前压入栈中的数据都出栈,才能接着执行函数调用位置以后的代码。

如果函数体代码比较多,需要较长的执行时间,那么函数调用机制占用的时间可以忽略;如果函数只有一两条语句,那么大部分的时间都会花费在函数调用机制上,这种时间开销就就不容忽视。

为了消除函数调用的时空开销,C++ 提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数。

当函数比较复杂时,函数调用的时空开销可以忽略,大部分的 CPU 时间都会花费在执行函数体代码上,所以我们一般是将非常短小的函数声明为内联函数。

使用内联函数的缺点也是非常明显的,编译后的程序会存在多份相同的函数拷贝,如果被声明为内联函数的函数体非常大,那么编译后的程序体积也将会变得很大,所以再次强调,一般只将那些短小的、频繁调用的函数声明为内联函数。

18.MAVLink:Mavlink是为小型飞行器和地面站(或者其他飞行器)通讯时常常用到的那些数据制定一种发送和接收的规则并加入了校验(checksum)功能,本质上是一个通讯协议。

19.函数指针:本质上是一个指针,指向函数的指针。函数存放在内存的代码区域内,它们同样有地址。如果我们有一个函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。函数指针的定义方法为:函数类型 (*指针变量名)(形参列表)。调用方式与一般函数一样。

函数指针数组:函数指针数组是一个其元素是函数指针的数组。那么也就是说,此数据结构是是一个数组,且其元素是一个指向函数入口地址的指针。调用方式与一般函数一样。

20.vTaskDelayUntil:用于以固定周期去执行任务,调用时会阻塞任务。任务中第一次调用函数vTaskDelayUntil的话需要将 pxPreviousWakeTime初始化进入任务的 while()循环体的时间点值。在以后的运行中函数vTaskDelayUntil()会自动更新 pxPreviousWakeTime。

21.如何退出当前任务?一般使用延时函数将任务阻塞掉,让出CPU使用权。

22.如何进入别的任务:延时时间到后,任务进入就绪态,系统根据优先级选择任务执行。

23.空闲任务:空闲任务的优先级是最低的,系统空闲的时候才会执行。空闲任务的主要工作是释放内存,被删除任务的堆栈和TCB立即释放。

24.构造函数:构造函数是类的一种特殊成员函数,构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。

25.数据类型:

unsigned char 8位 一个字节 255

unsigned short int 16位 两个字节 65535

unsigned int 32位 四个字节 4294967295

unsigned long long int 64位 八个字节

26.函数重载:函数可以根据参数进行重载,构造函数也可以重载,使用哪个取决于参数

27.运算符重载:可以对运算符进行重载,通常用于对象的运算,什么时候使用重载的运算符也是取决于参数,运算符连同操作数可以看成一个函数调用。

28.双冒号运算符:用于引用类的静态函数成员,调用命名空间里的成员

29.静态成员数据:静态成员数据并不属于任何一个对象,它属于类,因此引用它时要用类去用

30.静态函数成员:和静态成员数据是一样的,不属于任何一个对象,属于类,引用时要用双冒号运算符

31.联合体:联合体的成员共用一块内存空间

32.this:this一般写于类的成员函数里面,此时代表的就是当前对象,this->a,就是对该对象的成员a进行操作

33.延时:延时有好多方法,如果是在系统任务里可以直接使用系统的延时API,但这样会把任务给阻塞掉,系统延时API最小延时时间应为一个节拍数,一般freertos的时钟频率为1000HZ,就是最小延时1ms,如果延时要小于1ms,那就不能使用系统API,这时候考虑定时器延时,通过获取定时器计数值就能进行精准延时。

34.DMA:直接存储器访问,DMA传输无需经过CPU直接控制传输,减轻CPU负担。CPU需要处理从外设采集回来的数据,CPU需要先将数据从外设的寄存器读取到内存中(变量)去,然后进行运算处理,这是一般的解决方法。CPU的资源是非常宝贵的,我们可以设法把转移的工作交给其他部件来完成,CPU把更多的资源用于数据运算和中断响应上。这样我们可以看到DMA在工作的时候CPU也在工作。

35.类访问修饰符:public公有成员,随意访问;private,外部不可访问,而且派生类都不能访问,只能在原本的类里面操作,默认是private;protected,和private一样外部不可访问,不一样的是派生类可以访问。

36.virtual:虚函数,可在派生类中对函数进行重写

37.__DSB():汇编指令,目前没搞懂它的具体作用,对于MCU是空指令?

38.L1-cache:高速缓存,I-Cache是指令高速缓冲存储器,D-Cache是数据高速缓冲存储器,没体会到Cache的作用

39.MPU:内存保护单元,好像因为要配置Cache才要用到mpu,具体也不知道是什么东西

40.RTC:实质是一个掉电后还继续运行的定时器,要有后备电池给stm32供电

41.__packed:1字节对齐

42.template:模板T,定义模板的固定格式,比如你想求2个int float 或double型变量的值,只需要定义一个函数就可以了

43.HardFault_Handler:硬件错误中断函数,STM32出现硬件错误可能有以下原因:(1)数组越界操作;(2)内存溢出,访问越界;(3)堆栈溢出,程序跑飞;(4)中断处理错误;

44.using namespace std:C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。

45.指针:指针初始化赋值为0表示其不指向任何地址,*ptr表示指针ptr指向的值,&i表示i的地址,对于结构体类型的指针,想引用其成员,使用指针变量名->成员名。

46.xSemaphoreTake(xSemaphore, portMAX_DELAY):在嵌入式操作系统中互斥型信号量是任务间资源保护的重要手段。调用函数xSemaphoreTake获取信号量资源,如果信号量没有被任务占用,将直接获取资源。如果信号量被占用,任务将由运行态转到阻塞状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数xSemaphoreGive释放掉资源。此处的等待时间为portMAX_DELAY(挂起最大时间),如果任务无法获得资源的使用权,任务会处于挂起状态。此函数是一个宏,真正获取信号量的过程是由函数xQueueGenericReceive()来完成的。要是过了阻塞时间任务会进入就绪态

47.xTimerPendFunctionCallFromISR():函数将一个普通函数作为参数“提交”给系统服务,让系统自带的Daemon Task执行这个函数。提交时一并指定两个参数传递给这个函数。Daemon Task 受调度器管理,它的任务优先级由 configTIMER_TASK_PRIORITY 指定。Daemon Task 何时执行提交的函数,就要看系统是否空闲了,当它获得执行机会时,就会从命令队列里面取出要执行的函数入口地址和参数去执行。

48.new:new int[5];//仅仅是分配了空间,并没有生成对象。开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针),可以类比其他变量类型使用

49.map:map是C++标准库里的一个类,也叫做容器,它提供搜索和插入的数据结构,有一一对应的功能。使用时要#include 。C++中map提供的是一种键值对容器,里面的数据都是成对出现的。每一对中的第一个值称之为关键字(key),每个关键字只能在map中出现一次;第二个称之为该关键字的对应值。

map的基本操作函数:

begin()               返回指向map头部的迭代器

end()                  返回指向容器尾元素的下一个位置的迭代器,也就是说end指示的是一个不存在的元素

find(k)                找到一个任意一个键为k的元素,返回该元素的迭代器,如果没有键为k的元素,则返回end()

insert( pair<>()) 插入元素 

erase(it)             删除元素

50.delete:delete ptr 代表用来释放内存,且只用来释放ptr指向的内存。

51.时间片调度:这个在freertos里面是默认打开的,而抢占式调度需要我们用户自己开启,一般在freertosconfig.h中使能。所谓时间片调度就是每个任务都有其最大的运行时间,这个时间为系统节拍,一般的任务会在时间片里面主动进行切换,如果运行时间超过系统节拍就会被动发生任务切换。

52.const:一个关键字,如果你需要这样一个变量(暂且称它变量),在声明时就赋一个初始值。之后程序在其它任何处都不会再去重新对它赋值,用const 。

在函数后加const的意义:我们定义的类的成员函数中,常常有一些成员函数不改变类的数据成员,也就是说,这些函数是"只读"函数,而有一些函数要修改类数据成员的值。已定义成const的成员函数,一旦企图修改数据成员的值,则编译器按错误处理。

53.Iterator:迭代器,迭代器是一种检查容器内元素并遍历元素的数据类型。迭代器(Iterator)是指针(pointer)的泛化,它允许程序员用相同的方式处理不同的数据结构(容器)。

54.break:C++ 中 break 语句有以下两种用法:

  1. 当 break 语句出现在一个循环内时,循环会立即终止,且程序流将继续执行紧接着循环的下一条语句。
  2. 它可用于终止 switch 语句中的一个 case。

如果您使用的是嵌套循环(即一个循环内嵌套另一个循环),break 语句会停止执行最内层的循环,然后开始执行该块之后的下一行代码。

55.i++ 与 ++i 的主要区别有两个:
1、 i++ 返回原来的值,++i 返回加1后的值。
2、 i++ 不能作为左值,而++i 可以。

56.心跳包:心跳包由6个数据组成

第一个参数是占一个字节的飞行器类型数据(type),这个数据表示了当前发消息的是什么飞行器,比如四旋翼,固定翼等等。

第二个参数是自驾仪类型(autopilot),比如apm,ppz,Pixhawk等飞控,具体定义查找和之前查找飞行器类型时的方法一样。

第三个参数是基本模式(base mode),是指飞控现在处在哪个基本模式,对于发心跳包的地面站来说没有意义,对于发送心跳包的飞控来说是有意义的。

第四个参数是用户模式(custom mode)

第五个是系统状态(system status)

第六个是mavlink版本(mavlink version),现在是“3”版本。

57.定义:只要变量定义了就会分配内存空间,对于编程来说,定义是第一步,首先定义你的研究对象

58.memset:char型初始化函数,头文件: 或 ,函数原型:void *memset(void *s , int ch , size_t  n )

memset(结构体/数组名 , 用于替换的ASCII码对应字符 , 前n个字符 );

函数解释:将s中的前n个字节用ch替换并且返回s

函数作用:在一段内存块中填充某一个给定的值,常用于较大的对结构体和数组的清零操作。

59.拷贝构造函数:classname (const classname &obj) { // 构造函数的主体 },拷贝构造函数通常用于:(1)复制对象把它作为参数传递给函数。(2)通过使用另一个同类型的对象来初始化新创建的对象。

60.类的赋值运算符:拷贝构造函数和赋值运算符的行为比较相似,都是将一个对象的值复制给另一个对象。调用的是拷贝构造函数还是赋值运算符,主要是看是否有新的对象实例产生。如果产生了新的对象实例,那调用的就是拷贝构造函数;如果没有,那就是对已有的对象赋值,调用的是赋值运算符

61.strcat:C 库函数 char *strcat(char *dest, const char *src) 把 src 所指向的字符串追加到 dest 所指向的字符串的结尾。

62.FATFS_LinkDriver:在进行Flash和SD卡初始化的时候均使用了这个函数,从函数名可以看出这个函数用于注册磁盘驱动。

函数原型:uint8_t FATFS_LinkDriver(const Diskio_drvTypeDef *drv, char *path),第一个参数是一个结构体指针,如果是使用Flash,那就是Flash_Driver;如果是使用SD卡,那就是SD_Driver。两个结构体指针都是底层驱动写好的,直接使用即可。第二个参数是char型指针,函数实际上对这个char型指针指向的数组的内容进行了修改,也就是初始化了路径。

63.f_mount:计算机上的盘符是C: D: E: FatFS中的盘符是0: 1: 2:....f_mount是给磁盘分配盘符的

64.memcpy:C和C++使用的内存拷贝函数,void *memcpy(void *str1, const void *str2, size_t n) 从存储区 str2 复制 n 个字符到存储区 str1

65.字节对齐:现代计算机中内存空间都是按照byte划分的,牺牲空间以换取时间的效率。为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐”.。比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除。

66.DMA中断:当设置DMA_BufferSize后,只有当传送完所设的大小后,才会产生一个DMA_IT_TC中断。

67.std::numeric_limits::min/max:取类型的最小值,最大值

68.xTaskNotify:任务通知是一个事件,假如某个任务通知的接收任务因为等待任务通知而阻塞的话,向这个接收任务发送任务通知以后就会解除这个任务的阻塞状态。任务通知的发送使用函数 xTaskNotify()或者 xTaskNotifyGive()(还有此函数的中断版本)来
完成,这个通知值会一直被保存着,直到接收任务调用函数 xTaskNotifyWait()或者ulTaskNotifyTake()来获取这个通知值。假如接收任务因为等待任务通知而阻塞的话那么在接收到任务通知以后就会解除阻塞态。

你可能感兴趣的:(code)