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 发明的。使用信 量的最初目的是为了给共享资源建立一个标志,该标志表示该共享资源被占用情况。这样,当一个任务在访问共享资源之前,就可以先对这个标志进行查询,从而在了解资源被占用的情况之后,再来决定自己的行为。
互斥信 量:与一般信 量不同的是互斥信 量可以改变优先级,使得高优先级也无法打断低优先级的任务
递归互斥信 量:递归互斥信 量可以看作是一个特殊的互斥信 量,已经获取了互斥信 量的任务就不能再次获取这个互斥信 量,但是递归互斥信 量不同,已经获取了递归互斥信 量的任务可以再次获取这个递归互斥信 量,而且次数不限!一个任务使用函数 xSemaphoreTakeRecursive()成功的获取了多少次递归互斥信 量就得使用函数 xSemaphoreGiveRecursive()释放多少次!比如某个任务成功的获取了 5 次递归信 量,那么这个任务也得同样的释放 5 次递归信 量。
11.缓冲区:StreamBuffer也是一种数据结构,类似队列,在使用外设与外界进行通信时,不管是发送还是接收,数据都需要经过缓冲区,为什么需要缓冲区数据是不停发送和接收的,程序不应随数据进行改变,而是在它想进行处理时就从缓冲区里拿出来进行处理
12.USB:USB也是一种外设,用于通信,类似串口
13.文件系统:文件系统是为了存储和管理数据,而在存储介质上建立的一种组织结构,这些结构主要包括系统引导区,目录和文件。在使用文件系统前,需要先对存储介质进行格式化,格式化之后,存储介质会创建一个文件分配表和目录。这样,文件系统就可以记录数据存放的物理地址和剩余空间。使用文件系统时,数据都以文件的形式存储。写入新文件时,先在目录中创建一个文件索引,它指示了文件存放的物理地址,再把数据存储到该地址中。当需要读取数据时,可以从该目录中找到该文件的索引,进而在相应的地址中读取数据。文件系统的存在使我们在存储数据时,不再是简单的向某个物理地址直接读写,而是要遵循它的读写格式。如经过逻辑转换,一个完整的文件可能被分成多段并存储到不连续的物理地址,以及使用目录或链表的方式来获知下一段的位置。在SPI方式读写SD卡的试验中只完成了向物理地址读写数据的工作,而根据文件系统格式的逻辑转换部分则需要额外的代码来完成。实质上,这个转换部分可以理解为,当我们需要写入一段数据时,由它来求解向什么物理地址写入数据、以什么格式写入,以及写入一些原始数据以外的信息(如目录)。这个逻辑转换部分代码我们也习惯称之为文件系统。
14.SPI:传感器采用SPI通信,SPI支持一主多从模式,通过片选管脚进行从机选择
15.static:
面向过程:
静态局部变量:该变量在全局数据区分配内存;静态局部变量在程序执行到该对象的声明处时被首次初始化,即以后的函数调用不再进行初始化;静态局部变量一般在声明处初始化,如果没有显式初始化,会被程序自动初始化为 0;它始终驻留在全局数据区,直到程序运行结束。但其作用域为局部作用域,当定义它的函数或语句块结束时,其作用域随之结束。
面向对象:
静态成员变量:静态成员变量是该类的所有对象所共有的。对于普通成员变量,每个类对象都有自己的一份拷贝。而静态成员变量一共就一份,无论这个类的对象被定义了多少个,静态成员变量只分配一次内存,由该类的所有对象共享访问。所以,静态数据成员的值对每个对象都是一样的,它的值可以更新;
静态成员函数:静态成员函数为类服务而不是为某一个类的具体对象服务。静态成员函数与静态成员变量一样,都是类的内部实现,属于类定义的一部分。普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。与普通函数相比,静态成员函数属于类本身,而不作用于对象,因此它不具有this指针。
什么时候用+里如果需要调一个在类里,但跟类的实例无关的函数,就需要
16.inline:函数调用是有时间和空间开销的。程序在执行一个函数之前需要做一些准备工作,要将实参、局部变量、返回地址以及若干寄存器都压入栈中,然后才能执行函数体中的代码;函数体中的代码执行完毕后还要清理现场,将之前压入栈中的数据都出栈,才能接着执行函数调用位置以后的代码。
如果函数体代码比较多,需要较长的执行时间,那么函数调用机制占用的时间可以忽略;如果函数只有一两条语句,那么大部分的时间都会花费在函数调用机制上,这种时间开销就就不容忽视。
为了消除函数调用的时空开销,C++ 提供一种提高效率的方法,即在编译时将函数调用处用函数体替换,类似于C语言中的宏展开。这种在函数调用处直接嵌入函数体的函数称为内联函数(Inline Function),又称内嵌函数或者内置函数。
当函数比较复杂时,函数调用的时空开销可以忽略,大部分的 CPU 时间都会花费在执行函数体代码上,所以我们一般是将非常短小的函数声明为内联函数。
使用内联函数的缺点也是非常明显的,编译后的程序会存在多份相同的函数拷贝,如果被声明为内联函数的函数体非常大,那么编译后的程序体积也将会变得很大,所以再次强调,一般只将那些短小的、频繁调用的函数声明为内联函数。
我觉得内联函数之所以能work,是因为它本身是内联于它所在的cpp文件的,编译的时候不会去链接外部
如果你想inline某个函数,这个函数可以是写在cpp里面,但是如果我想在别的cpp里面实现这个函数呢以用头文件声明去做吗p>
编译是对一个cpp文件讲的,编译过程你的函数都不在cpp上面怎么inline,那就是在头文件上面写函数了,才能Inline
总结:inline必须是通过头文件的方式做
首先要说明的是一个inline函数具有静态链接(static linkage),不会被文件以外者看到。
18.MAVLink:Mavlink是为小型飞行器和地面站(或者其他飞行器)通讯时常常用到的那些数据制定一种发送和接收的规则并加入了校验(checksum)功能,本质上是一个通讯协议。
大家可以在Mavlink的官 上找到它们的定义。简单的说MavLink协议上传输的都是各种消息(Message),消息其实就是一种数据包格式,是为了通信而准备的,消息的格式多种多样。而命令(Command)是一种数据,格式完全统一,通过命令 来解释不同的意义,这也就方便在飞行任务中定义、存储、解释、执行。
19.函数指针:本质上是一个指针,指向函数的指针。函数存放在内存的代码区域内,它们同样有地址。如果我们有一个函数,那么,它的地址就是函数的名字,这一点如同数组一样,数组的名字就是数组的起始地址。函数指针的定义方法为:函数类型 (*指针变量名)(形参列表)。调用方式与一般函数一样。
函数指针数组:函数指针数组是一个其元素是函数指针的数组。那么也就是说,此数据结构是是一个数组,且其元素是一个指向函数入口地址的指针。调用方式与一般函数一样。
20.vTaskDelayUntil:用于以固定周期去执行任务,调用时会阻塞任务。任务中第一次调用函数vTaskDelayUntil的话需要将 pxPreviousWakeTime初始化进入任务的 while()循环体的时间点值。在以后的运行中函数vTaskDelayUntil()会自动更新 pxPreviousWakeTime。
应用例子:
vTaskDelayUntil( &xLastWakeTime, 0.01*configTICK_RATE_HZ ); //延时10ms
void vTaskDelayUntil( TickType_t *pxPreviousWakeTime, const TickType_t xTimeIncrement );
参数 xTimeIncrement 用于设置延迟的时钟节拍个数
第二个参数是定时节拍数
21.如何退出当前任务使用延时函数将任务阻塞掉,让出CPU使用权。
22.如何进入别的任务:延时时间到后,任务进入就绪态,系统根据优先级选择任务执行。
23.空闲任务:空闲任务的优先级是最低的,系统空闲的时候才会执行。空闲任务的主要工作是释放内存,被删除任务的堆栈和TCB立即释放。
24.构造函数:构造函数是类的一种特殊成员函数,构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。创建类类型对象时由编译器自动调用,保证每个数据成员都有 一个合适的初始值,并且在对象的生命周期内只调用一次。
在子类的构造函数中,加上一个冒 (:),然后加上父类的带参构造函数,这就是父类构造函数的显式调用。这种一般声明在类的外面
子类::子类构造函数:父类构造函数(参数)
构造函数使用:Line line(10.0);
C++中没有显式定义构造和析构函数时,编译器会自动添加一个构造函数和一个析构函数
C++中类的默认构造函数是一个空函数,什么也不做,如果用户在类中声明了构造函数,默认构造函数就不再起作用了
默认构造函数和初始化构造函数在定义类的对象的时候,完成对象的初始化工作。
25.数据类型:
unsigned char 8位 一个字节 255
unsigned short int 16位 两个字节 65535
unsigned int 32位 四个字节 4294967295
unsigned long long int 64位 八个字节
float 四个字节 double 八个字节 范围很大很大就是了。。。
26.函数重载:函数可以根据参数进行重载,构造函数也可以重载,使用哪个取决于参数
27.运算符重载:可以对运算符进行重载,通常用于对象的运算,什么时候使用重载的运算符也是取决于参数,运算符连同操作数可以看成一个函数调用。
28.双冒 运算符:用于引用类的静态函数成员,调用命名空间里的成员
29.静态成员数据:静态成员数据并不属于任何一个对象,它属于类,因此引用它时要用类去用
30.静态函数成员:和静态成员数据是一样的,不属于任何一个对象,属于类,引用时要用双冒 运算符
31.联合体:联合体的成员共用一块内存空间,当对某个成员赋值时,别的成员的值会被覆盖掉
32.this:this是一个指针,指向当前对象,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一样外部不可访问,不一样的是派生类可以访问。
之所以有这么多修饰符也是使程序更加健壮,比如说有些函数就是不能被随便被外界使用的就应该用protected保护起来,以免程序出现错误
36.virtual:虚函数,可在派生类中对函数进行重写
37.__DSB():汇编指令,目前没搞懂它的具体作用,对于MCU是空指令p>
38.Cache:高速缓存,I-Cache是指令高速缓冲存储器,D-Cache是数据高速缓冲存储器,没体会到Cache的作用
高速缓存就是高速存储器块,包括地址信息和相关联的数据,它的目的主要是为了提高对存储器的平均访问速度。
执行代码的时候CPU每次都要去访问FLASH,而我们知道FLASH的读取速度是远远低于CPU的主频的,所以需要设置一个等待周期来保证能够正确地从FLASH中把数据读出来。
有了Cache之后,第一次访问FLASH读取出需要的指令和数据之后,可以把指令和数据先放到Cache里,当下次再需要这部分内容的时候就不需要再去访问FLASH,而是直接从Cache中把这部分内容读出来,这样就可以提高存储器的平均访问速度和程序的执行速度。
如果每次CPU要读写SRAM区的数据,都能够在Cache里面进行,自然是最好的,实现了200MHz到400MHz的飞跃,实际是做不到的,因为数据Cache只有16KB大小,总有用完的时候。
因为DMA是直接与SRAM交换数据的,而CPU与SRAM之间隔了一个Cache,如果DMA更新了某个数据到SRAM,CPU要去访问,而恰好Cache中有,那么CPU就不会去SRAM中拿,就会拿到Cache中已经过时的数据。
因此使用了DMA的内存区要配置为无Cache或者拿数据前清一次Cache。
39.MPU:内存保护单元,保护不需要用到Cache的内存
40.RTC:实质是一个掉电后还继续运行的定时器,要有后备电池给stm32供电
41.__packed:__packed 限定符将所有有效类型的对齐边界设置为 1。这就意味着:
1、不会插入填充以对齐压缩对象
2、使用未对齐的访问读取或写入压缩类型的对象。
使用 __packed 限定符声明结构或联合后,__packed 将应用于该结构或联合的所有成员。成员之间或结构末尾均没有填充。必须使用 __packed 声明压缩结构的所有子结构。
若要将结构映射到外部数据结构或访问未对齐数据,__packed 限定符非常有用;
42.template:模板T,定义模板的固定格式,比如你想求2个int float 或double型变量的值,只需要定义一个函数就可以了
43.HardFault_Handler:硬件错误中断函数,STM32出现硬件错误可能有以下原因:(1)数组越界操作;(2)内存溢出,访问越界;(3)堆栈溢出,程序跑飞;(4)中断处理错误;
44.using namespace std:C++标准程序库中的所有标识符都被定义于一个名为std的namespace中。使用STL需要添加这句语句。
45.指针:指针初始化赋值为0表示其不指向任何地址,*ptr表示指针ptr指向的值,&i表示i的地址,对于结构体类型的指针,想引用其成员,使用指针变量名->成员名。
指针的作用非常大,在程序里面我们只需要记录变量或函数的地址就可以进行操作了
如果一个指针定义了没有赋值,那就是个野指针,不知指向何处,如果赋值为0,那就是空指针,不指向任何变量
函数参数是指针的时候要传地址,而不是变量本身
46.信 量获取:
函数原型:BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xBlockTime)
参数:xSemaphore :要获取的信 量句柄。xBlockTime: 阻塞时间。
返回值:pdTRUE: 获取信 量成功。 pdFALSE: 超时,获取信 量失败。
在嵌入式操作系统中互斥型信 量是任务间资源保护的重要手段。调用函数xSemaphoreTake获取信 量资源,如果信 量没有被任务占用,将直接获取资源。如果信 量被占用,任务将由运行态转到阻塞状态,等待资源可用。一旦获取了资源并使用完毕后会通过函数xSemaphoreGive释放掉资源。
一般我们会设置阻塞时间,如果资源不可用,任务会进入阻塞态,相当于延时。如果阻塞时间设为0,那就直接返回,不会阻塞。在阻塞时间内,当资源可用时,系统会有中断触发,任务会进入就绪态,返回pdTRUE,超过阻塞时间,任务也会进入就绪态,返回pdFALSE
47.xTimerPendFunctionCallFromISR():函数将一个普通函数作为参数“提交”给系统服务,让系统自带的Daemon Task执行这个函数。提交时一并指定两个参数传递给这个函数。Daemon Task 受调度器管理,它的任务优先级由 configTIMER_TASK_PRIORITY 指定。Daemon Task 何时执行提交的函数,就要看系统是否空闲了,当它获得执行机会时,就会从命令队列里面取出要执行的函数入口地址和参数去执行。
什么时候会用到这个函数处理中断延迟
所谓集中处理中断延迟,是使用API将接下来的处理函数作为回调函数提供给RTOS的内核守护任务。通过传递处理函数的指针,在中断服务函数退出后,相应的处理函数会得到执行。从中断退出,到相应的处理函数得到执行,在时间上是连续的,好像这个函数直接由中断调用一样。
48.new:new int[5];//仅仅是分配了空间,并没有生成对象。开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针),可以类比其他变量类型使用
new int[5] 仅仅分配了空间, 但是 new A(),不仅仅为对象obj在队上分配了空间, 而且还调用了 A的构造函数,生成了这个对象。
49.map:map是C++标准库里的一个类,也叫做容器,它提供搜索和插入的数据结构,有一一对应的功能。从数据结构来说,map是标准库里写好的一个类。使用时要#include