导图社区 嵌入式知识点学习思维导图
这是一篇关于嵌入式知识点学习思维导图的思维导图,,由于初次接触嵌入式系统, 感觉蛮难的,所以收获不是很大,很多的概念都比较模糊,等到学期结束开始做嵌 入式课程设计时,真是茫然无从...
编辑于2022-05-30 09:42:25嵌入式
C语言
关键字/常量/变量
数据类型
输入/输出/格式化
运算符
表达式
语句
判断
循环
结构体/共同体/枚举/位操作
内存大小计算:结构体:32位操作系统1.先找最大的数据类型最大数据类型>=4字节 整个结构体按照4字节对齐最大数据类型<4字节 整个结构体按照最大数据类型对齐2.当遇到不够4个字节,可能需要合并数据 共用体:1.先找最大的数据类型最大数据类型>=4字节 整个联合体按照4字节对齐最大数据类型<4字节 整个联合体按照最大数据类型对齐2.按照最大成员同时满足字节对齐,共用体共用同一片内存
数组与指针
数组指针
int (*p)[3];//指针优先级高,相当于声明了一个指针,这个指针很特别,指向了一个数组
指针数组
int *p[3];//数组优先级高,声明了一个数组,数组的每一个元素都是指针,相当于声明了多个指针
函数指针
int (*p)(int a);//指向函数的指针变量,本质是一个指针变量,可以通过它来调用函数
指针函数
int *p(int a);//本质是一个函数,函数返回值类型是int类型的指针,参数是int类型
函数指针数组
int (*p[3])(int a);//本质是一个数组,数组中每个元素都是指针,每一个指针指向一个函数的地址
函数指针数组指针
int (*(*p)[3])(int a);//本质是一个指针,指向一个数组,数组中每个元素又都是指针,每一个指针指向又指向一个函数的地址
函数
C++
命名空间
命名空间的定义使用关键字 namespace,后跟命名空间的名称,它可作为附加信息来区分不同库中相同名称的函数、类、变量等。使用了命名空间即定义了上下文,本质上命名空间就是定义了一个范围。
类和对象
C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++的核心特性,通常被称为用户定义的类型。类用于指定对象的形式,它包含了数据表示法和用于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类中被称为类的成员
类成员函数
类的成员函数是指那些把定义和原型写在类定义内部的函数,就像类定义中的其他变量一样。
类访问修饰符
类成员可以被定义为 public、private 或 protected
构造函数 & 析构函数
类的构造函数是一种特殊的函数,在创建一个新的对象时调用。类的析构函数也是一种特殊的函数,在删除所创建的对象时调用。
拷贝构造函数
拷贝构造函数,是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象
友元函数
友元函数可以访问类的 private 和 protected 成员
内联函数
通过内联函数,编译器试图在调用函数的地方扩展函数体中的代码
this 指针
每个对象都有一个特殊的指针 this,它指向对象本身
静态成员
类的数据成员和函数成员都可以被声明为静态的
继承
面向对象程序设计中最重要的一个概念是继承。继承允许我们依据另一个类来定义一个类,这使得创建和维护一个应用程序变得更容易。这样做,也达到了重用代码功能和提高执行效率的效果。当创建一个类时,您不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。
公有继承
当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
保护继承
当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
私有继承
当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。
多继承
一个子类可以有多个父类,它继承了多个父类的特性。
重载
函数重载
在同一个作用域内,可以声明几个功能类似的同名函数,但是这些同名函数的形式参数(指参数的个数、类型或者顺序)必须不同。您不能仅通过返回类型的不同来重载函数
运算符重载
重载的运算符是带有特殊名称的函数,函数名是由关键字 operator 和其后要重载的运算符符号构成的。与其他函数一样,重载运算符有一个返回类型和一个参数列表
多态
多态按字面的意思就是多种形态。当类之间存在层次结构,并且类之间是通过继承关联时,就会用到多态。C++ 多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数
虚函数
虚函数 是在基类中使用关键字 virtual 声明的函数。在派生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数。我们想要的是在程序中任意点可以根据所调用的对象类型来选择调用的函数,这种操作被称为动态链接,或后期绑定。
纯虚函数
想要在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是在基类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数,纯虚函数没有主体,等于0
数据封装
数据封装是面向对象编程中的把数据和操作数据的函数绑定在一起的一个概念,这样能避免受到外界的干扰和误用,从而确保了安全。数据封装引申出了另一个重要的 OOP 概念,即数据隐藏
数据抽象
数据抽象是指只向外界提供关键信息,并隐藏其后台的实现细节,即只表现必要的信息而不呈现细节。是一种依赖于接口和实现分离的编程(设计)技术
接口
接口是使用抽象类来实现的,抽象类与数据抽象互不混淆,数据抽象是一个把实现细节与相关的数据分离开的概念。如果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类。纯虚函数是通过在声明中使用 "= 0" 来指定的。
文件和流
我们已经使用了iostream 标准库,它提了 cin 和 cout 方法分别用于从标准输入读取流和向标准输出写入流
异常处理
C++ 异常是指在程序运行时发生的特殊情况,比如尝试除以零的操作。异常提供了一种转移程序控制权的方式。C++ 异常处理涉及到三个关键字:try、catch、throw
动态内存
模板
模板是泛型编程的基础,泛型编程即以一种独立于任何特定类型的方式编写代码。
数据结构与算法
数组
链表
单链表
双链表
内核链表
栈
队列
堆
树
哈希
图
查找
排序
单片机
STC
STC8G系列
STC8H系列
STC15系列
STM32
STM32G0系列
STM32F1系列
STM32F4系列
GPIO
浮空输入
在芯片内部既没有接上拉,也没有接下拉电阻,经由触发器输入。配置成这个模式直接用电压表测量其引脚电压为1点几伏,这是个不确定值。由于其输入阻抗较大,一般把这种模式用于标准的通信协议如I2C,USART的接收端。
模拟输入
关闭了施密特触发器,不接上,下拉电阻,经由另一线路把电压信号传送到片上外设模块。如传送至ADC模块,由ADC采集电压信号。所以使用ADC外设时,必须设置为模拟输入模式
上拉输入
若GPIO引脚配置为上拉输入模式,在默认情况下(GPIO引脚无输入),读取得的GPIO引脚数据位1,高电平
下拉输入
若GPIO引脚配置为下拉输入模式,在默认情况下(GPIO引脚无输入),读取 得的GPIO引脚数据位0,低电平。
推挽输出
在输出高电平时,P-MOS管导通,低电平时,N-MOS管导通。两个管子轮流导通,一个负责灌电流,一个负责拉电流,使其负载能力和开关速度都比普通的方式有很大的提高。推挽输出的低电平为0V,高电平为3.3V
复用推挽输出
可以理解为把GPIO配置为第二功能使用的时候的配置,并非单纯的用作IO输入或输出。比如使用外设IIC时,我们需要把GPIO配置为复用推挽输出,用于数据通信功能。再比如串口通信的TX、以及SPI外设的GPIO使用就要把引脚设置为复用开漏输出。
开漏输出
如果我们控制输出为0,低电平,则使N-MOS管导通,使输出接地,若控制输出为1,则既不输出高电平,也不输出低电平,为高阻态。要正常使用必须在外部接一个上拉电阻。它具有线与特性,即多个开漏模式引脚连接到一起时,只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,此高电平的电压为外部上拉电阻所接电源的电压。若其中一个引脚为低电平,那线路就相当于短路接地,使得整条线路都为低电平,0V。
复用开漏输出
可以理解为把GPIO配置为第二功能使用的时候的配置,并非单纯的用作IO输入或输出。比如使用外设IIC时,我们需要把GPIO配置为复用推挽输出,用于数据通信功能。再比如串口通信的TX、以及SPI外设的GPIO使用就要把引脚设置为复用开漏输出。
中断
1、中断请求
2、中断响应
3、保护现场
4、中断处理
5、清除中断标志
6、恢复现场
7、中断返回
定时器
UART
1、串口时钟和GPIO时钟使能
2、设置引脚复用器映射
3、串口GPIO配置参数初始化(五大参数)
4、串口参数初始化(六大参数)
5、使能串口
6、开启中断
7、配置NVIC中断(四大参数)
8、编写中断处理函数
9、串口数据收发
10、串口传输状态获取
PWM
1、使能相关时钟(定时器和GPIO)
2、初始化GPIO
3、初始化定时器
4、初始化输出比较参数
5、使能自动重装载的预装载寄存器
6、使能定时器
7、不断改变比较值CCRx,达到不同的占空比效果
ADC/DAC
FLASH
IIC
空闲状态
I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。此时各个器件的输出级场效应管均处在截止状态,即释放总线,由两条信号线各自的上拉电阻把电平拉高。
起始信号
时钟线SCL为高电平期间,数据线SDA由高电平向低电平变化
停止信号
时钟线SCL为高电平期间,数据线SDA由低电平向高电平变化
应答信号
如果需要检测应答信号“0”,得先置高数据线SDA,如果数据线后来检测到应答信号“0”,则是应答信号存在的最好说明!如果需要检测非应答信号“1”,得先拉低数据线SDA,如果数据线后来检测到非应答信号“1”,也是非应答信号存在的最好说明!
非应答信号
如果需要检测应答信号“0”,得先置高数据线SDA,如果数据线后来检测到应答信号“0”,则是应答信号存在的最好说明!如果需要检测非应答信号“1”,得先拉低数据线SDA,如果数据线后来检测到非应答信号“1”,也是非应答信号存在的最好说明!
SPI
CS
SCLK
MISO
MOSI
单总线1-wire
复位和应答
主机通过拉低单总线480 ~ 960 us产生复位脉冲,然后释放总线,进入接收模式。主机释放总线时,会产生低电平跳变为高电平的上升沿,单总线器件检测到上升沿之后,延时15 ~ 60 us,单总线器件拉低总线60 ~ 240 us来产生应答脉冲。主机接收到从机的应答脉冲说明单总线器件就绪,初始化过程完成。
写信令
当数据线拉低后,在15 ~ 60 us的时间窗口内对数据线进行采样。如果数据线为低电平,就是写0,如果数据线为高电平,就是写1。主机要产生一个写1时间隙,就必须把数据线拉低,在写时间隙开始后的15 us内允许数据线拉高。主机要产生一个写0时间隙,就必须把数据线拉低并保持60 us。
读信令
读时序最少需要拉低总线1us,然后释放总线,从设备会在15-45us操作总线,主机进行采样读取数据。
USB
CAN
数据帧
帧起始
仲裁段
控制段
数据段
CRC段
ACK段
帧结束
摇控帧
错误帧
过载帧
帧间隔
bxCAN初始化流程
1、引脚配置以及使能时钟(APB1),其中CAN_RX引脚为上拉输入,CAN_TX为复用输出
2、设置bxCAN模式
3、设置波特率(tsjw,tb1,tb2,brp)
4、设置滤波器
bxCAN设置滤波器流程
1、选择筛选器组号
2、使用哪个FIFO关联到筛选器号(即用哪个FIFO进行接收消息)
3、设置筛选器模式以及需要筛选的ID
bxCAN发送流程
1、选用哪种帧类型(标准数据帧,扩展数据帧,遥控帧)
2、设置标准帧(StdId),扩展帧(ExtId)的ID,以及需要一次性发送的数据长度(字节数)
3、将要发送的数据赋值给结构体成员(最多只能赋值8个字节的数据,每个数据1字节),并发送
bxCAN接收流程
1、等待有消息到达
2、将接收的消息(消息为结构体类型)存于指定FIFO(有2个FIFO,每个FIFO下有3个邮箱)
3、把消息的数据提出
4、将FIFO里的消息释放,避免堆积
以太网
ENc28j60
DM9000
W5500
无线通信
wifi
蓝牙
zigbee
4G
433MHz
RF
显示
数码管
1602液晶屏
OLED
LCD
传感器
温度
湿度
光照强度
红外
加速度计/陀螺仪
压力
......
RTOS
任务调度
抢占式调度
当有新的任务就绪(ready),且优先级大于等于当前任务的优先级时,当前任务就会被抢占;需要用户通过configUSE_PREEMPTION配置。
时间片调度
同处于ready态的最高优先级的任务会轮流运行固定的时间片;通过configUSE_TIME_SLICING配置,默认开启。
任务管理
任务状态
运行态
就绪态
阻塞态
挂起态
任务切换
1、保存当前任务上下文环境
2、更新当前处于运行状态的任务的任务控制块的内容
3、把任务的任务控制块移到相应的队列
4、选择另一个任务进行执行,调度
5、改变需要投入运行的任务的任务控制块的内容,把任务的状态变为运行状态
6、根据任务控制块,恢复需要投入运行的任务的上下文环境
任务管理机制
创建任务
删除任务
挂起任务
解挂任务
任务延时
中断管理
中断配置宏
configPRIO_BITS
设置 MCU 使用几位优先级,STM32 使用的是 4 位,因此此宏为 4
configLIBRARY_LOWEST_INTERRUPT_PRIORITY
设置系统的最低优先级,不同MUC值不一样,STM32F103是15
configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY
设置系统可管理的最高中断优先级是5,小于5的优先级RTOS不能管理
开关中断
开中断portENABLE_INTERRUPTS() vPortSetBASEPRI(0)
关中断portDISABLE_INTERRUPTS() vPortRaiseBASEPRI()
临界段代码
任务级临界段代码保护
#define taskENTER_CRITICAL() portENTER_CRITICAL()#define taskEXIT_CRITICAL() portEXIT_CRITICAL()#define portENTER_CRITICAL() vPortEnterCritical()#define portEXIT_CRITICAL() vPortExitCritical()
中断级临界段代码保护
#define taskENTER_CRITICAL_FROM_ISR() portSET_INTERRUPT_MASK_FROM_ISR()#define taskEXIT_CRITICAL_FROM_ISR( x ) portCLEAR_INTERRUPT_MASK_FROM_ISR( x )#define portSET_INTERRUPT_MASK_FROM_ISR() ulPortRaiseBASEPRI()#define portCLEAR_INTERRUPT_MASK_FROM_ISR(x) vPortSetBASEPRI(x)
时间管理
延时函数
绝对延时vTaskDelayUntil()
相对延时vTaskDelay()
系统时钟节拍
内存管理
heap_1.c
只能申请内存,不能释放
heap_2.c
可以调用函数pvPortMalloc()和vPortFree()来申请和释放内存,但是heap_2.c会导致内存碎片的产生
heap_3.c
是标准C库中的函数malloc()和free()的简单封装,并且提供了线程保护
heap_4.c
提供了内存合并功能,可以降低内存碎片的产生,我们移植FreeRTOS的时候就选择了heap_4.c
heap_5.c
支持内存堆使用不连续的内存块
信号量
用于控制对共享资源的访问和任务同步
二值信号量
创建信号量
获取信号量
释放信号量
计数信号量
互斥信号量
消息队列
队列创建
xQueueCreate()
xQueueGenericCreate()
xQueueCreateStatic()
xQueueGenericCreateStatic()
入队
任务级入队
xQueueSend()后向入队
xQueueSendToBack()后向入队
xQueueSendToFront()前向入队
xQueueOverwrite()覆写入队
中断级入队
xQueueSendFromISR()后向入队
xQueueSendToBackFromISR()后向入队
xQueueSendToFrontFromISR()前向入队
xQueueOverwriteFromISR()覆写入队
出队
任务级出队
xQueueReceive()读取完删除数据
xQueuePeek()读取完不删除数据
中断级出队
xQueueReceiveFromISR()读取完删除数据
xQueuePeekFromISR()读取完不删除数据
队列上锁和解锁
prvLockQueue()
prvUnlockQueue()
事件标志组
创建时间标志组
xEventGroupCreate()动态创建
xEventGroupCreateStatic()静态创建
设置事件位
XEventGroupClearBits()任务中指定事件清零
xEventGroupSetBits()任务中指定事件置1
xEventGroupClearBitsFromISR()中断中指定事件清零
xEventGroupSetBitsFromISR()中断中指定事件置1
获取事件标志组值
xEventGroupGetBits()任务中获取当前事件标志组值
xEventGroupGetBitsFromISR()中断中获取当前事件标志组值
等待指定的事件位
低功耗管理
睡眠模式sleep()
停止模式stop()
待机模式Standby()
Linux
shell命令
ls命令
cd命令
cp命令
rm命令
mv命令
mkdir命令
file命令
vim命令
cat命令
touch命令
tree命令
chmod命令
find命令
tar命令
ps命令
ifconfig命令
pwd命令
rmdir命令
which命令
mount 命令
gdb调试
help命令
查看命令帮助,具体命令查询在gdb中输入help + 命令,简写h
run命令
重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件),简写r
start命令
单步执行,运行程序,停在第一执行语句
list命令
查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函数),简写l
set命令
设置变量的值
next命令
单步调试(逐过程,函数直接执行),简写n
step命令
单步调试(逐语句:跳入自定义函数内部执行),简写s
backtrace命令
查看函数的调用的栈帧和层级关系,简写bt
frame命令
切换函数的栈帧,简写f
info命令
查看函数内部局部变量的数值,简写i
finish命令
结束当前函数,返回到函数调用点
continue命令
继续运行,简写c
print命令
打印值及地址,简写p
quit命令
退出gdb,简写q
break命令
设置断点,简写b
delete命令
删除断点,简写d
linux应用编程
编译步骤
预处理
编译
汇编
链接
文件IO编程
open()
read()
write()
close()
lseek()
ioctl()
select()
stat()
opendir()
readdir()
closedir()
标准IO编程
fopen()
fread()
fwrite()
fclose()
fseek()
ftell()
feof()
ferror()
clearerr()
fsync()
多任务编程
多进程
多进程优点:1、每个进程互相独立,不影响主程序的稳定性,子进程崩溃没关系2、通过增加CPU,就可以容易扩充性能 3、可以尽量减少线程加锁/解锁的影响,极大提高性能,就算是线程运行的模块算法效率低也没关系4、每个子进程都有2GB地址空间和相关资源,总体能够达到的性能上限非常大多进程缺点:1、逻辑控制复杂,需要和主程序交互2、需要跨进程边界,如果有大数据量传送,就不太好,适合小数据量传送、密集运算 3、多进程调度开销比较大
进程创建与退出
僵尸进程与孤儿进程
进程状态
就绪态
运行态
僵尸态
阻塞态
暂停态
进程间通信
无名管道pipe()
有名管道mkfifo()
信号
消息队列
信号量
共享内存
套接字
多线程
多线程优点:1、无需跨进程边界2、程序逻辑和控制方式简单 3、所有线程可以直接共享内存和变量 4、线程方式消耗的总资源比进程方式好多线程缺点:1、每个线程与主程序共用地址空间,受限于2GB地址空间 2、线程之间的同步和加锁控制比较麻烦 3、一个线程的崩溃可能影响到整个程序的稳定性 4、到达一定的线程数程度后,即使再增加CPU也无法提高性能 5、线程能够提高的总性能有限,而且线程多了之后,线程本身的调度也是一个麻烦事儿,需要消耗较多的CPU
创建线程pthread_create()
终止线程pthread_exit()
回收线程pthread_join()
取消线程pthread_cancel()
分离线程pthread_attr_setdetachstate()
线程同步
互斥锁
条件变量
自旋锁
读写锁
信号量
全局变量
线程池
网络编程
4层模型
应用层
传输层
网络层
数据链路层
TCP
tcp面向连接的,可靠的通信方式 面向连接:表面上理解connect() accept()深层次理解tcp连接过程中的三次握手(tcp协议的底层原理),tcp断开连接的时候:四次挥手三次握手是发生在客户端连接服务器的时候,双方通过三次握手,相互确认了连接关系可靠:支持错误重传,不会丢包tcp可以一口气发送的字节数远远大于udp,100万字节都行用途:用于通信质量要求高的场合
客户端
1、创建tcp类型套接字socket()
2、绑定bind()
3、连接服务器connect()
4、收发数据send()和recv()
5、关闭close()
服务端
1、创建tcp类型套接字socket()
2、绑定bind()
3、监听listen()
4、接受连接请求accept()
5、收发数据send()和recv()
6、关闭close()
三次握手
第一次:客户端发送请求到服务器,服务器知道客户端发送,自己接收正常。第二次:服务器发给客户端,客户端知道自己发送、接收正常,服务器接收、发送正常。第三次:客户端发给服务器,服务器知道客户端发送,接收正常,自己接收,发送也正常。
四次挥手
第一次:客户端请求断开第二次:服务器确认客户端的断开请求第三次:服务器请求断开第四次:客户端确认服务器的断开
UDP
udp无连接的,不可靠的通信方式(相对于tcp) 不可靠:丢失数据包,出错了也不会重传,udp一口气大概5万个字节左右用途:视频点播
单播
客户端
1、创建udp套接字socket()
2、绑定bind()
3、收发数据recvfrom()和sendto()
4、关闭close()
服务端
1、创建udp套接字socket()
2、绑定bind()
3、收发数据recvfrom()和sendto()
4、关闭close()
组播
广播
MQTT
一种基于发布/订阅(publish/subscribe)模式的"轻量级"通讯协议,该协议构建于TCP/IP协议上,作为一种低开销、低带宽占用的即时通讯协议,使其在物联网、小型设备、移动应用等方面有较广泛的应用
发布者(Publish)
客户端既可以是发布者也可以是订阅者发布其他客户端可能会订阅的信息;订阅其它客户端发布的消息;退订或删除应用程序的消息;断开与服务器连接。
代理(Broker)
接受来自客户的网络连接;接受客户发布的应用信息;处理来自客户端的订阅和退订请求;向订阅的客户转发应用程序消息
订阅者(Subscribe)
客户端既可以是发布者也可以是订阅者发布其他客户端可能会订阅的信息;订阅其它客户端发布的消息;退订或删除应用程序的消息;断开与服务器连接。
主题(Topic)
可以理解为消息的类型,订阅者订阅(Subscribe)后,就会收到该主题的消息内容(payload)
负载(payload)
可以理解为消息的内容,是指订阅者具体要使用的内容
客户端实现步骤
1、创建一个客户端对象MQTTClient_create()
2、设置连接MQTT服务器的参数
3、设置回调函数MQTTClient_setCallbacks()
4、连接服务器MQTTClient_connect()
5、订阅客户端需要接收数据的主题MQTTClient_subscribe()
6、loop循环发布消息和处理接收到的消息
7、断开客户端连接MQTTClient_disconnect()
8、释放客户端使用的所有内存MQTTClient_destroy()
数据库编程
数据库sqlite3移植
创建数据文件
创建表格
往表格中插入数据
删除表格中的数据
删除整个表格
查询表格中的数据内容
修改表格中的数据
常用的修饰语句
串口编程
打开串口
配置串口
1、保存原先串口的配置
2、设置串口工作在本地模式
3、设置波特率
4、设置数据位
5、设置奇偶校验
6、设置停止位
7、设置等待时间
8、刷新缓冲
9、配置生效
数据收发
关闭串口
音视频编程
音频
移植ALSA库
ADC采样
量化
编码
视频
1、移植jpeg库
2、设置摄像头通道
3、获取摄像头当前的采集格式
4、申请缓冲块
5、分配申请的缓冲块
6、将对应的缓冲块映射到用户空间
7、将帧数据存放到缓存(入队)
8、开始摄像头数据采集
9、将缓冲块中的帧数据拿出来(出队)
10、将获取的该帧信息写入文件
11、关闭摄像头数据采集
GUI界面编程
Qt
信号与槽
控件
文本读写
绘图与图表
多线程
网络编程
多媒体
数据库
LVGL
linux驱动编程
字符设备驱动
指只能一个字节一个字节进行读写操作的设备,不能随机读取设备中的某一数据、读取数据要按照先后数据。字符设备是面向流的设备,常见的字符设备有鼠标、键盘、串口、控制台和LED
驱动初始化
为cdev分配内存
初始化cdev
注册cdev
硬件初始化
实现设备操作
open()
read()
write()
lseek()
close()
驱动注销
释放cdev内存
释放设备号
块设备驱动
块设备将数据按照固定块大小的块中,每个块的大小通常在512字节到32768字节之间,磁盘、SD卡都是常见的块设备。
注册块设备
register_blkdev()创建块设备
blk_init_queue()分配申请队列
alloc_disk()分配gendisk结构体
设置gendisk结构体的成员
kzalloc()来获取缓存地址,用做扇区
add_disk()注册gendisk结构体
块设备IO请求
elv_next_request()获取申请队列中每个未处理的申请
rq_data_dir()获取每个申请的读写命令标志,为 0(READ)表示读, 为1(WRITE)表示写
memcpy()来读或者写扇区
end_request()来结束获取的每个申请
销毁块设备
put_disk()和del_gendisk()来注销,释放gendisk结构体
kfree()释放磁盘扇区缓存
blk_cleanup_queue()清除内存中的申请队列
unregister_blkdev()卸载块设备
网络设备驱动
网络设备面向数据包的发送而设计,它并不对应于文件系统的节点。即不对应 /dev 目录下的设备文件,应用程序最终通过套接字 socket 完成与网络设备的数据交互。常见的网络设备有网卡(无线网卡、有线网卡)。
网络协议接口层
dev_queue_xmit()数据包发送
netif_rx()数据包接收
网络设备接口层
net_device统一接口名称
设备驱动功能层
hard_start_xmit()数据包发送
中断处理(数据包接收)
网络设备与媒介层
完成数据包发送和接收的物理实体
总线设备驱动
串口设备驱动
IIC设备驱动
SPI设备驱动
IIS设备驱动
PCI设备驱动
USB设备驱动
CAN设备驱动
RS-232设备驱动
RS-485设备驱动
linux内核编程
bootloader
bootloader编译烧写
bootloader移植
bootloader启动流程
汇编阶段
1、设置SVC
2、关闭看门狗、中断、cache、mmu
3、初始化时钟、串口、flash、内存等(基本硬件初始化)
4、自搬移bootloader到内存RAM中运行
5、准备栈空间
C语言阶段
1、大部分硬件初始化(SD卡、网卡等)
2、系统的内存映射检测
3、将内核映像从 Flash 读到 RAM 中
4、设置内核启动参数
5、运行内核
u-boot源代码目录结构
api
存放u-boot向外提供的接口函数
arch
与体系结构相关的代码,核心文件夹
board
此文件夹是根据不同的具体开发板而定制的代码,代码也不少
common
通用代码,涵盖各个方面,以命令行处理为主
disk
磁盘分区相关代码
doc
常见功能和问题的说明文档,一堆README开头的文件
drivers
常用的设备驱动程序,每个类型的设备驱动占用一个子目录
examples
示例程序
fs
文件系统,支持嵌入式开发常见的fs
include
全局需要的头文件定义在这儿
lib
通用库文件
net
网络相关的代码,小型的协议栈
post
Power On Self Test,上电自检
Tools
辅助程序,用于编译和检查uboot目标文件
Linux Kernel
内核编译烧写
内核移植
内核启动流程
1、内核自解压
压缩格式的内核zImage、uImage、bzImage自解压得到vmlinux
2、内核引导stage1
汇编代码通过查找处理器内核类型和机器码类型调用对应的初始化函数,再建立页表,最后跳转到start_kernel()函数開始内核的初始化
3、内核初始化stage2
1、调用setup_arch()函数进行与体系结构相关的第一个初始化工作
对于ARM平台而言。它首先通过检測出来的处理器类型进行处理器内核的初始化,然后进行内存结构的初始化,最后开启MMU,创建内核页表,映射全部的物理内存和IO空间。
2、创建异常向量表和初始化中断处理函数
3、初始化系统核心进程调度器和时钟中断处理机制
4、初始化串口控制台
5、创建和初始化系统cache,为各种内存调用机制提供缓存,动态内存分配,虚拟文件系统及页缓存
6、初始化内存管理,检測内存大小及被内核占用的内存情况
7、初始化系统的进程间通信机制(IPC)
4、挂载根文件系统rootfs
5、启动init
1、启动udev
2、设置内核參数
3、设置系统时间
4、启用交换内存空间
5、检查并挂载全部文件系统
6、初始化硬件设备
7、初始化串行port设备
8、清除过期的锁定文件与IPC文件
9、建立用户接口
10、建立虚拟控制台
内核源代码目录结构
arch
包含和硬件体系结构相关的代码,每种平台占一个相应的目录,如 i386、arm、arm64、powerpc、mips 等。Linux 内核目前已经支持30种左右的体系结构。在 arch 目录下,存放的是各个平台以及各个平台的芯片对 Linux 内核进程调度、内存管理、中断等的支持,以及每个具体的 SoC 和电路板的板级支持代码
block
块设备驱动程序 I/O 调度
crypto
常用加密和散列算法(如AES、SHA等),还有一些压缩和 CRC 校验算法
documentation
内核各部分的通用解释和注释
drivers
设备驱动程序。每个不同的驱动占用一个子目录,如 char、block、net、mtd、 i2c 等
fs
所支持的各种文件系统,如EXT、FAT、NTFS、JFFS2等
include
内核 API 级別头文件,与系统相关的头文件放置在 include/linux 子目录下
init
内核初始化代码。著名的 stait_kemel() 就位于 init/main.c 文件中
ipc
进程间通信的代码
kernel
内核最核心的部分,包括进程调度、定时器等,而和平台相关的一部分代码放在 arch/*/kemel 目录下
lib
库文件代码
mm
内存管理代码,和平台相关的一部分代码放在arch/*/mm目录下
net
网络相关代码,实现各种常见的网络协议
scripts
用于配置内核的脚本文件
security
主要是一个 SELinux 的模块
sound
ALSA、OSS 音频设备的驱动核心代码和常用设备驱动
usr
实现用于打包和压缩的 cpio 等
根文件系统
常用开发工具
vmware
ubuntu
shell
Git/SVN
vim
SecureCRT
RaiDrive
MobaXterm
FTP/SFTP工具
makefile
gcc
交叉编译工具
Source Insight
FileZilla
wifi
AP\STA模式
AT指令
配网模式
一键配网
设备热点配网
手机热点配网
蓝牙
低功耗蓝牙
经典蓝牙
GAP
GATT
Mesh
BLE Profiles
OSAL
低功耗管理