- 博客(63)
- 收藏
- 关注
原创 进程及相关概念
PCB就是进程控制块,我们可以在这里看到进程的所有信息,就像身份证一样,通过身份证可以了解一个人的主要信息,姓名,年龄,性别等。但是具体的比如个人喜好,个人理想等就需要深入了解,这里的PCB就是了解进程的主要信息,其中进程号就像身份证号一样,每个进程都有自己独一无二的进程号,是唯一确认一个进程的。是不是就是一个进程,答案是否定的,就像我们可以多次大开浏览器页面一样,每次打开时,都是各种独立的进程,那么操作系统又是怎么区分这些进程呢?它是由操作系统分配的,内存的申请与回收都由OS管理。
2025-02-22 16:11:57
464
原创 计算机网络基础知识(网络硬件连接 IP地址 TCP/UDP协议)
假设我们不知道网络的情况下,A电脑要发送信息給B电脑,我们可以直接用网一根线将两个电脑连接起来就行,这样AB直接可以使用网线传输数据。那么如果我们要加入第三个电脑呢?可以在两个电脑之间再连接网线。网络小白对计算机网络的通俗理解。我们首先通俗的讲解这个部分。
2025-02-17 17:09:12
134
原创 C语言学习 auto和decltyoe
auto可以自动判断所定义变量的类型,但是这个变量必须进行初始化,因为自动推断必须给点线索,如果不给线索那就没法玩了,比如 auto x;前者是错误的,因为没初始化,可以是任何类型,后者将x置为100,会自动判断为int型。auto可以和函数重载+模板联合使用。如下图的代码,定义了一个函数模板add(),当函数的返回类型是整数时,自动推断x为int;当函数返回的类型是double时,x是double。如果使用auto定义函数,会根据函数return的类型自动推断。++x是左值 x++是右值。
2024-12-25 17:39:42
355
原创 C语言学习 函数参数
这个函数的执行流程是这样的,会在执行的时候自动创建一个变量a和b,并且这两个变量的作用域或者生命周期仅仅限定在函数的内部,当执行完毕之后,会自动的销毁这两个变量。在函数中也可以使用引用参数。注意引用参数必须填入,因为引用必须进行初始化,引用是个别名,就必须指出是谁的别名。但是我们规定传入指针就不一样了,操作指针就是实际的一块内存,更改了就实际的更改了,这个函数在执行时,自动创建了两个指针,传值是把a,b的内存地址传给了这两个变量,那么我们实际操作的就是a,b的内存,直接操作内存,那么更改就是实际的更改了。
2024-12-19 20:25:47
294
原创 C语言学习 引用
这里的a和la是一样的,内存地址一样,值也一样,并且引用不可更改。并且一旦初始化引用之后,是不可修改的。引用是创建了一个变量的别名。例如 int& la{a};数据类型& 变量名称{引用的对象名称}
2024-12-18 17:29:30
94
原创 C语言学习 动态内存分配
我们可以使用malloc函数向系统申请内存,void* malloc(size_t ),在这个函数的参数中,我们传入的参数是要申请的内存大小,以字节为单位,并且是一个常量值,不能是变量值,例如malloc(10*sizeof(int)),这里int是4个字节,所以就是申请40个字节。但是这种写法还是有问题的,因为malloc申请了一块空内存,返回的只是一个内存地址,而我们接收的指针这里是int型,当然也可以是float,char等,等号左边是int*,右边是woid*,这不正确,所以还要进行类型转换。
2024-12-17 20:26:19
131
原创 C语言学习 if和switch
每个case后面有break是在执行完当前case的语句之后跳出break,如果没有的话会继续执行下一个case选项的语句,直到遇到break。根据switch的值来判断执行那个case,如果都不符合条件,那么就会执行default的语句,就是默认的情况。switch里面是数值,根据数值来判断执行哪个选项,会从符合某个选项的那个case语句开始执行,注意是开始执行。switch的执行逻辑。
2024-12-09 20:05:14
242
原创 C语言学习 位运算
对于int型的变量进行位移,也就是带符号的类型进行位移 计算机保存数字都是补码的形式保存,所以左移右移都是补码。填充空出来的低位,同时会影响原数字的符号,因为左移相当于乘以。对于unsigned 型不带符号的数据,左移还是右移都是补0。:如果你对一个正整数进行右移操作,空出的高位用。:如果你对一个负数进行右移操作,空出的高位用。(在补码表示法中,负数的符号位总是。:无论正数还是负数,左移操作都用。这是因为正数的符号位是。这是因为负数的符号位是。
2024-12-05 15:02:17
352
原创 STM32学习-段的概念_散列文件_重定位
ZI-data:Zero Initialie data,即0初始化数据,它指初始化为“0值”的可读写数据域,它与RW-data的区别是程序刚运行时这些数据初始值全都为0,而后续运行过程与RW-data的性质一样,它们也常驻在RAM区,因而应用程序可以更改其内容。:Read Write data,即可读写数据域,它指初始化为“非0值”的可读写数据,程序刚运行时,这些数据具有非0的初始值,且运行的时候它们会常驻在RAM区,因而应用程序可以修改其内容。
2024-11-08 11:49:20
1100
原创 STM32学习-Map文件分析
这个就是移除掉没有使用到的东西,比如我们为了方便,会把所有的库函数都加入到工程中,但可能有的库函数模块没有使用掉,对这部分进行移除,最后是一段总结性的文字,总计501未调用的模块共21820字节从映像文件中移除。ARM处理器是32位的,如果定义一个8位或者16位变量就会剩余一部分,这里就是指的“补充”的那部分,会发现后面的其他几个选项都没有对应的值。大概包含:RESET、.ARM、 .text、 i、 .data、 .bss、 HEAP、 STACK等。要翻译的话,只能说的“补充类型”。
2024-11-01 16:30:15
1267
原创 STM32学习-keil的编译过程
若编译过程无误,即可把工程生成前面对应的*.axf文件,而在MDK中使用下载器(DAP/JLINK/ULINK等)下载程序或仿真的时候,MDK调用的就是*.axf文件,它解释该文件,然后控制下载器把*.axf中的代码内容下载到STM32芯片对应的存储空间,然后复位后芯片就开始执行代码了。那么回到前面的框图中,我们可以看到很多文件都使用ARMCC进行编译,就是把我们编写的各种.c文件编译成.o目标文件 那么看最后,还会使用一个ARMLink,他是一个链接器,会把前面生成的各种.o目标文件链接起来。
2024-11-01 12:23:11
1227
原创 IMX6ULL裸机-汇编_反汇编_机器码
第一条指令,伪指令将这个数据加载到sp寄存器中,在反汇编文件中,使用到了pc,实际上,是keil在链接程序时,在pc+4这个位置保存了这个值,读到该指令时,会把这个数值加载到sp寄存器中,前面是对应这条指令的机器码 f8dfd004。下面这个指令是在A系列上的机器码,可以看到,相似的指令对应的机器码相差很多,这是因为不同系列平台上使用指令集对应的机器码不同,也就是不同架构使用的指令集的机器码可能会不同,同样,查看使用什么样的指令集就可以知道使用什么样的架构。下面是LDR指令对应的机器码。
2024-10-30 15:40:01
572
原创 STM32学习-启动文件详解
因此, 在地址 0 (即FLASH 地址0,相对有的地址0,不一定真是0,如果STM32从Flash启动,则此中断向量表的地址为0x0800 0000)处必须包含一张向量表,用于初始时的异常分配。无论是是何种MCU,从简单的51,MSP430,到ARM9,ARM11,A7 都必须有启动文件,因为对于嵌入式开发,绝大部分情况都是使用C语言,而C语言一般都是从main 函数开始,但是对于MCU来说,他是如何找到并执行main函数的,就需要用到“启动文件”,就是各种 startup_xxxx.s 文件。
2024-10-29 17:10:36
954
原创 IMX6ULL裸机-ARM汇编
C语言中的函数调用涉及到出栈入栈,这里解释一下,函数调用就是在使用函数栈,比如A函数调用B函数,在调用B函数执行完毕后,必须返回A函数对应的位置,需要对现场进行保护,而此处说的现场,就是指CPU运行的时候, 用到了一些寄存器,比如R0~R3,LR 等等,对于这些寄存器的值,如果你不保存而直接跳转到函数中去执行,那么很可能会被破坏了,因为函数执行需要用到这些寄存器。所以要进行入栈,把内部寄存器的数据存入栈中,在执行完B函数之后就需要恢复现场,把栈的数据进行出栈,继续执行。
2024-10-27 21:02:21
821
原创 IMX6ULL裸机-ARM内部寄存器
但是用户模式是不能直接进行切换的,用户模式下需要借助异常来完成模式切换,当要切换模式 的时候,应用程序可以产生异常,在异常的处理过程中完成处理器模式切换。所谓“运行模式”,可以这样简单理解: ① 板子上电时,CPU处于SVC模式,它用的是SVC模式下的寄存器 ② 程序运行时发生了中断,CPU进入IRQ模式,它用的IRQ模式下的寄存器 ③ CPU处理完中断,它切换回SVC模式,继续使用SVC模式下的寄存器 ④ CPU发生某种异常时,比如读取内存出错,它会进入ABT模式,使用ABT 模式下的寄存器来处理错误。
2024-10-25 16:29:00
349
原创 IMX6ULL裸机-地址空间
但是在X86的CPU中,内存和IO空间是不同的,比如下图内存的空间是0-4G,IO空间的地址是0-64K,两个地方都含有0-64K,但是内存的0-64K和IO空间的0-64K完全是两回事,CPU使用MOV这样的指令去访问内存空间,使用IN AL这样的指令去访问IO空间。对于X86CPU来说,你使用相同的地址但使用不同的指令会访问到不同地址空间的地址,可能会访问内存空间的地址,也可能会访问IO空间的地址,根据CPU发出的指令选择不同的设备。
2024-10-25 15:47:30
251
原创 数据结构-顺序栈
栈:是一种特殊的线性表,其只允许在表尾进行插入和删除元素操作。进行数据插入和删除操作的一端称为栈顶,另一端称为栈底。栈中的数据元素遵守后进先出LIFO(Last In First Out)的原则。压栈:栈的插入操作叫做进栈 / 压栈 / 入栈,入数据在栈顶。出栈:栈的删除操作叫做出栈。
2024-10-15 11:32:31
250
原创 数据结构-单链表
前面学习的顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,而链表是一种物理存储结构上不连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的,可以实现更加灵活的动态内存管理。可以看到,4个节点的地址并不是连续的,链表在物理结构上不一定是线性的,而在逻辑结构上是线性的。链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成。2、指针域:存储下一个结点地址。1、数据域:存储数据元素。
2024-10-14 20:02:38
356
原创 数据结构-顺序表
静态顺序表:使用定长数组存储元素.缺点是 动态顺序表:使用动态开辟的数组存储元素.依次存储数据元素的线性结构,一般情况下采用数组存储。在数组上完成数据的增删查改。顺序表: 顺序表是用一段。顺序表的指定位置插入。顺序表指定位置的删除。
2024-10-13 20:11:47
344
原创 Linux用户和用户组
从文件中我们可以看到,/etc/passwd中一行记录对应着一个用户,每行记录又被冒号(:)分隔为7个字段,其格式和具体含义如下:第一列为账户名称,第二列为密码占位符(x表示该账户需要密码才能登录,为空时,账户无须密码即可登录,第三列为账户UID,第四列为GID(就是用户组ID),第五列为账户附加基本信息,一般存储账户名全称,联系方式等信息,第六列为账户家目录位置,第七列为账户登录Shell,/bin/bash为可登录系统Shell,/sbin/nologin表示账户无法登录系统。
2024-10-08 16:22:35
468
原创 Linux基础知识-1
Linux采用的是挂在的方式,并且使用的是树状结构来表示文件,下图是Linux的磁盘管理,可以看到磁盘的第一个分区挂载到了Root文件(根目录)下,也就是说,访问根目录下的任意一个文件,就是在访问/dev/sda1。/dev/下的设备文件面向的是设备本身,你虽然可以打开、读取、写入一个存储设备,但是你面向的终究是一个存储设备,不是文件系统。说白了,就是根目录和Windows的C盘一个样。在Windows中,磁盘是被分成了很多区的,比如C盘,D盘,不同的文件放在不同的盘下面。
2024-09-24 11:22:01
228
1
原创 计算机基础知识-3
顺序执行的方式就是一条一条串行执行,但是存在缺点,比如第一条指令取指阶段完毕后,进入第一条指令的分析阶段,此时负责完成取指阶段的硬件是空闲的,如果采用顺序执行,很明显存在空闲状态,利用率不高。那么可以这样进行设计,在第一条指令取指完毕进入第一条指令分析阶段后,由于负责取指阶段的硬件处于空闲态,可以让其执行第二条指令的取指,那么同理,当第一条指令的分析阶段完成,进入执行阶段时,此时负责分析的硬件是空闲态,可以让其执行第二条指令的分析,依次类推,代价就是硬件设计复杂。
2024-09-10 17:03:32
235
原创 计算机基础知识-2
高级语言的函数调用,首先执行main函数,会创建main函数的栈帧用来保存一些局部变量和一些相关信息,在main函数中又调用了Q函数,同时也会创建Q函数的栈帧来保存Q函数的局部变量和别的信息,同理,随着更深层的函数调用,会一次次的创建函数栈帧放到栈顶,最栈顶的位置就是当前执行的函数,执行完毕后会出栈,继续执行。完一条指令,PC会自动+"1",指向下一条要被执行的指令。当前执行的是108地址的指令,PC为112,但是108是无条件转移指令JMP,所以PC跳转导128地址的指令。PSW程序状态子寄存器。
2024-09-06 22:13:11
255
原创 机算机基础知识-1
机器字长就是CPU一次能处理的数据位数。比如机器字长是64位,那么64位的加法运算运算一次就行,如果是32位或者更少,完成64位的加法要进行多次。而且字长越长,表示数的精度和范围也就越高,当然,硬件实现的成本也会增加。计算机的运算速度和很多因素都有关系,机器的主频,执行什么指令,以及不同指令所需要耗费的时间等,MIPS和CPI是通常使用的衡量标准。所有指令的操作码长度相同,称为定长操作码;指令的操作码长度可变,称为可变长操作码。
2024-09-06 16:40:45
205
原创 FreeRTOS 低功耗模式
前面说的很明白,FreeRTOS的低功耗模式实际上还是基于STM32的低功耗模式指令进入睡眠模式来实现的,并且只要中断来临,就会退出低功耗,FreeRTOS的系统时钟是最底层的中断,会频繁的触发,所以在进入低功耗模式时必须关闭中断。前面说过了,低功耗模式实际上是本该在进行空闲任务期间进入低功耗模式,可以在空闲任务中找到。正如STM32的裸机编程一样,FreeRTOS通用提供了低功耗模式。
2024-08-29 18:06:56
213
原创 FreeRTOS 信号量
信号量是操作系统中重要的一部分,信号量是任务间同步的一种机制,信号量可以用在多 任务访问同一资源时的资源管理。FreeRTOS 提供了多种信号量,按信号量的功能可分为。
2024-07-21 23:06:38
422
原创 FreeRTOS 队列
因为同一个队列可以被多个任务读取,因此可能会有多个任务因等待同一个队列,而被阻 塞,在这种情况下,如果队列中有可用的消息,那么也只有一个任务会被解除阻塞并读取到消 息,并且会按照阻塞的先后和任务的优先级,决定应该解除哪一个队列读取阻塞任务。当想某一个队列写入数据时,如果此时的队列已经满了,就是没有空位置了,这时任务实际上是阻塞住了,因为想要写入但是无法写入,我们可以设定一个等待阻塞时间,等待的时间在设定范围内,任务就会被添加到阻塞列表中进行等待,等待队列中有空位置。uxItemSize就是队列项目的大小。
2024-07-11 17:56:49
1809
原创 FreeRTOS 列表和列表项
通常情 况下,处于阻塞态的任务都有一个阻塞的超时时间,在任务阻塞达到或超过这个超时时间后, 即使任务等待的外部事件还没有发生,这里所说的列表和列表项,是 FreeRTOS 源码中 List 和 List Item 的 直译,事实上,FreeRTOS 中的列表和列表项就是数据结构中的链表和节点。实际上,当FreeRTOS有很多列表,包括就绪列表,阻塞列表,挂起列表等,结合上面的解释就知道了,处于就绪态的若干任务放在就绪列表,处于挂起态的若干任务放在挂起列表等。四种任务状态之间的转换图如下图所示。
2024-07-08 18:55:25
203
原创 FreeRTOS 任务
通过前面的图可以知道,任务是相互切换完成执行的,A任务切换到B任务的时候,CPU从接管A任务的状态切换到接管B任务的装填,那么就需要对A任务的当前现场进行保护,在下次再进行A任务的时候再恢复现场,这里说的保护和恢复,实际上是针对A任务中的一些变量进行的,所以A任务需要一个堆栈,同理,B任务也需要一个自己的堆栈。注意,任务的堆栈这里给的是Depth也就是深度,个人理解实际的大小是深度×宽度,宽度就是事先定义好的字的长度,,那么实际的堆栈大小就是usStackDepth*一个字的字节。
2024-07-06 10:10:36
685
原创 STM32学习-HAL库 定时器
HAL_XXX_MspInit()这种是外设硬件相关的初始化函数,包括GPIO,NVIC,CLOCK等,一般会在HAL_XXX_Init()中调用。定时器涉及的结构体主要有两个,TIM_HandleTypeDef和TIM_Base_InitTypeDef具体参数如下,使用HAL_TIM_Base_Init()函数初始化定时器,并且在该函数内部会调用HAL_TIM_Base_MspInit()初始化外设硬件。开启定时器也有很多方式,轮询方式,更新方式,DMA方式等,HAL库中有相对应的开启和停止函数。
2024-06-25 19:11:21
537
原创 STM32学习-HAL库 串口通信
串口的主要功能就是接收和发送HAL_UART_Transmit和HAL_UART_Receive都是阻塞方式发送和接收,执行完之后就不再执行,还阻碍了其他代码的运行。一般使用中断方式进行收发,涉及的比较复杂,HAL_UART_Receive_IT()和HAL_UART_Transmit_IT()这里给出接收的图解。学完标准库之后,本来想学习freertos的,但是看了很多教程都是移植的HAL库程序,这里再学习一些HAL库的内容,有了基础这里直接学习主要的外设。发送和接收类似,不再赘述。
2024-06-25 11:39:49
1287
原创 STM32学习 修改系统主频
可以看到这个文档里面给出了一些宏定义,这个就是系统的频率,选定哪个,就是设定哪个频率,这里就以72MHZ为例子看是如何配置时钟的,在文档中搜索一些使用到72MHZ的地方。前面时钟树的学习说明单片机的主频是可以修改的,那么怎么更改系统的主频,这里做一个简单的介绍。最终调用SystemInit()完成时钟的配置,所以只要在宏定义处使用官方配置好的一些就行,如果想要自己定义,就要重新编写寄存器相关的操作。使用的F103系列的引脚是GPIOD,所以可以看到使用寄存器的方式配置了相关的引脚,能够使用外部晶振。
2024-06-23 20:18:03
2488
原创 STM32学习 时钟树
下面在HSE和其2分频中选一个通入到上面,再和HSI 的2分频进行选择,之后PLLMUL就是倍频,为什么要倍频,可以看到后面的SYSCLK最大是72Mhz,但是HSI和HSE最大也就是8Mhz,倍频就是把频率增加,可以看到PLLMU有多种选择,x2,x4最多是16倍倍频,具体使用哪一个需要我们在代码里面配置。再来看后面的框图,可以看到AHB,AHB就是先进高性能总线,在AHB总线上有一条时钟线HCLK,这条时钟线就连接到DMA,内存,CPU等,其中系统时钟就是系统滴答时钟。这是最底层的时钟来源。
2024-06-18 17:51:51
889
原创 STM32学习 BKP
下面是手册当中的描述。后面两句话是在设定TPE位之前如果TPAL的引脚电平并不符合所设定的侵入条件(比如选定上升沿侵入但此时引脚已经是高电平无法产生上升沿),那么在设定TPE位之后会自动产生一个侵入事件,这个就会直接复位备份寄存器的内容,所以在启动前要保持正确的TAMPER电平你,防止启动之后自动触发。这里可以看到,TPAL=0,就是上升沿为侵入事件,TPAL=1,就是下降沿为侵入事件。在引脚图上可以看到,TAMPE,RTC都是在PC13引脚上,VBAT也就是备份电源是单独的引脚,这个就是芯片的1号引脚。
2024-06-16 13:26:22
524
原创 STM32学习 SPI通信
同时,从机也会把从机的移位寄存器中的数据一位一位的通过MISO线发送给主机,也就是收发是一起的,在发送的同时也在接收,如图所示。在指定地址读时,先是主机向从机进行有效字节的交换,从机可以拿无效字节进行交换,也就是指令+地址,之后就是从机向主机进行有效字节(读入的数据)的交换,主机可以拿无效字节进行交换。CPOL=0,空闲模式时SCLK为低电平,也就是说,当开始传数据时,SCLK发出脉冲信号时,要从低电平先变为高电平,那么第一个边沿就是上升沿,第二个边沿就是下降沿。这个地址和数据可能是多个字节,分多次传输。
2024-06-14 18:19:27
745
原创 Linux 安装QT踩坑-填坑
这里使用的是Ubuntu的16.04.7的系统,在这里搜到到了QT4,于是安装了qt4.6.0的远古版本。不同版本的LINUX系统安装不同版本的QT会出现差异性,最好只安装对应的版本。权限不够就切换到root下.注意,不使用QT的账户就必须先断开网再进行安装。ps:也试了最新的,查了很多博客也还是不会,干脆使用旧的版本吧。下载对应的安装包,选linux的X86_64的安装包。此时的安装包没有安装权限,在终端里按顺序执行以下命令。下面这个文章是对官网的一个说明。首先进入QT 的官网。
2024-06-02 14:58:55
363
原创 STM32学习 I2C通信
I2C通信很常用,是同步的半双工通信,一根SCL(时钟线),一根SDA(数据线)。多主多从的模式,任何一个模块都可以主动跳出来担当主机的角色,当然,首先该模块能才行(比如单片机可以当从机也可以当主机),但是同一时刻只能有一个主机,当冲突时,会进行仲裁,多主机的情况下,要进行时钟同步。这里通俗的理解一下,个人理解时钟的控制权就是只有主机才能决定在哪一个时刻进行通信,从机只能等待,当进行通信时的时刻到来时,从机就会被动的在这个时刻接收来自主机的指令,并且接收到以后需要进行应答。重复8次就能完成一个字节的。
2024-06-01 20:12:26
436
原创 STM32学习 串口通信
中间这一块是发送控制和接收控制,下面还有中断控制,通向NVIC,最下面是波特率发送器,可以看到fpclk,这个就是挂载的时钟总线的时钟,选定之后除一个分频系数USARTDIV,这个实在右边进行设置的,分为整数部分和小数部分,具体看数据手册中的描绘。起始位的检测是在一位的时间长度内进行多次采样,当经过3个采样时钟为3个1,后一个为0时,即检测到了下降沿,之后在一位的时间内进行16次采样,如果发现多个0(这里详细看手册的描述)那么便认为是起始位0,如果条件不符合那么就抛弃前面的数据,等待新一轮的起始位检测。
2024-05-28 16:48:17
910
原创 STM32学习 通信相关基本概念
这里通俗的解释一下码元,码元就是一个脉冲信号,但是这个脉冲信号可能携带多个bit的数据,可能1,可能2等。官方点就是4种不同的振幅或者频率或者相位,因为实际的信息传输都是用振幅,频率,相位等来表示信息的。码元说白了就是你以怎样的形式去定义你要发的信息,传输多个bit,还是一个码元。比特率=波特率*log2(M),这个公示也就很好解释了,每秒传输的码元数*每个码元的bit数=每秒传输的bit数。异步通信:没有时钟信号,他通过在数据前后加入起始位或者终止位,通过纠错编码,解码等方式保证数据正确性。
2024-05-24 14:16:08
309
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人