自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(134)
  • 收藏
  • 关注

原创 嵌入式Linux学习(1)——认识Linux

在之前我已经更新过了stm32相关的学习文章,也是我自己的学习记录过程,通过之前的项目,我们其实也对嵌入式有了一个整体的框架概念,MCU实际上就是一块资源很有限的计算单元,所以可以帮助我们做一些简单的工作,主要是读取外部信号,然后输出指令等,更多的是实现简单控制指令。当然纯裸机开发我们一般就是在main函数中写一个大的while循环,用一个个标志位,来判断下移步该执行什么命令。很显然当我们数据来源过多,控制变的复杂的时候,会需要更多的标志位和逻辑判断,则会大大提高我们编程的复杂。

2026-10-17 14:55:37 171

原创 # 网络编程(5)—— Reactor实现(v5)

v4 我们把 IO 线程和计算线程分开了,也搭好了"两个方向"的桥,但那是搭好的。回头看 v4 的main.cppgpoolonMessage是自由函数,没有this,所以要访问线程池只能靠一个全局裸指针。初始化时机、生命周期全靠人肉保证,一个进程里想同时起两个服务器就直接崩了。SocketEventLoopTcpServerThreadPool这些是我们写的"框架",本该是可复用的组件;而"收到消息回一个前缀"是。现在这两样东西住在同一个main.cpp里,框架想复用就得连业务一起抄走。接的是。

2026-10-04 19:15:05 366

原创 网络编程(5)—— Reactor实现(v4)

v3 我们把服务器封装成了TcpServer。事件循环是单线程的,onMessage也在这一条线程里跑。只要有一个业务的处理时间比较长(查库、算数据、写日志文件、甚至只是一个sleep(1)),整个反应堆就停摆——其它连接的读写全部排队。这不是"慢一点",是。

2026-10-04 19:11:35 269

原创 网络编程(5)—— Reactor实现(v3)

SocketAcceptorSocketIOEventLoopready()EventLooploop()顺带说一句,仓库里还有一个,那是加回调之前的中间版本——只有一个光秃秃的事件循环,不做任何回调。有兴趣可以翻着看,本系列不展开。所以TcpServer。这也正是 v2 结尾留下的那句话——“为了更好的使用,可以对当前进行一次封装”。

2026-10-04 19:10:12 381

原创 网络编程(5)—— Reactor实现(v2)

在上一篇文章中我们我们实现了Reactor的封装部分,把socket,listen,bind,IO等系统调用,使用C++的类进行类封装,我们要明确一点为什么要使用C++进行封装,C语言也能完成这些工作。因为使用C++类进行封装会有更好的可拓展性,方便后续的功能添加和版本迭代。

2026-08-26 20:58:00 240

原创 网络编程(5)—— Reactor实现(v1)

下面的工作就是完成核心层,事件驱动的代码,就是对epoll的封装,另外,TcpConnection是用来管理连接的,所以,当我们使用服务器采用事件驱动的形式时,TcpConnection中的数据成员和成员函数也要随之变动。我们的Reactor第一代基本完成了,当然可以把之前封装的log4cpp的代码替代perror()。在写代码之前要整理一下思绪,框架图中已经很明确的写出了有哪些类,我们在第一个版本的内容中实际上就是对系统调用的封装,下面就画一个类图,整理一下具体实现的内容。下面再开一个终端自测一下。

2026-08-17 10:28:54 245

原创 网络编程(4)—— Reactor模型介绍

Reactor是后续项目使用的框架,上述的Reactor模型可以演变出很多种类型,但是这里我们主要研究两种Reactor模型,即:基础的Reactor(本质就是socket网络编程+IO多路复用)以及Reactor与线程池结合的版本。那么我们先从基本的Reactor来研究,探究其中的原理,然后使用面向对象的设计思想将其实现出来。先回顾一下基本的Reactor模型的原理图从图例中可以看到,多个客户端可以同时向Reactor服务器发起请求,而Reactor服务器是可以同时处理这些请求的。

2026-08-08 16:52:48 176

原创 C++学习(13) ——线程池的实现

如果修复了上一个bug就会引出另外一个问题while(empty() && _flag){ // wakeup() 后 _flag=false,条件不满足// → 跳出循环// ← 如果队列是空的,front() 是未定义_que.pop();// ← 对空队列 pop() 也是 未定义return res;wakeup() 设 _flag=false 后,while(empty() && _flag) 条件为 false(因为 _flag 是 false),直接跳出循环。

2026-08-03 21:22:43 264

原创 数据库的使用(MySQL)

在实际的开发过程中,应用程序会有大量的数据需要持久地存储在磁盘之中,目前我们已知的持久化存储的方式就是采用文件,但是在磁盘物理的结构上,文件其实是一种顺序的字符集合。使用文件可以很方便地输入和输出数据,但是这些数据都是简单的字节流,不包含任何复杂数据结构,所以应用开发者需要花费大量的时间去解析文件的内容,并将其映射到内存的数据结构以供应用程序后续使用。除此之外,由于磁盘的顺序读写的速度要远远快于随机读写,所以为了访问位置靠后的数据,要消耗大量的时间(类似于链表的访问)。

2026-08-01 14:31:05 272

原创 C++学习(12) ——日志系统

回卷的机制是:先生成一个wd.log文件,该文件存满后接着写入日志,那么wd.log文件改名为wd.log.1,然后再创建一个wd.log文件,将日志内容写入其中,wd.log文件存满后接着写入日志,wd.log.1文件改名为wd.log.2,wd.log改名为wd.log.1,再创建一个wd.log文件,将最新的日志内容写入。能够输出到终端,还能保存到文件。如下案例中便封装了一个方法,在不同的业务模块,只需要传递不同的业务模块的名称,那么便可以在打印的日志中记录模块的信息,后续出现问题时,非常容易排查。

2026-07-28 14:55:57 188

原创 网络编程(3)—— IO多路复用

用户通过。

2026-07-18 17:16:44 181

原创 网络编程(2)—— 实现服务器与客户端通信

*服务器:**socket、bind、listen、accept、close**客户端:**socket、connect、close客户端和服务器各自执行socket方法,得到代表连接的文件描述符。然后服务器依次执行bind、listen、accept方法,然后等待客户端执行connect方法(发起建立连接的请求)。连接建立后,客户端可以执行send方法发送消息,服务器执行recv接受消息。或者服务器执行send发送消息,客户端执行recv接收消息。

2026-07-16 20:34:39 209

原创 网络编程(1)

一个完整的计算机网络主要由硬件、软件、协议三部分构成。硬件是网络互联的物理构成(双绞线/光纤/路由器/交换机/网卡/主机…);软件是硬件正常运行的驱动(操作系统/聊天软件/APP…);协议是数据传输时, 数据在硬件之间流转的约定和规范。计算机网络的构成有 广域网、城域网、局域网、…计算机中的网络节点和线路的集合关系, 有常见的总线、星型、环状、网状…IP协议是四层模型中的核心协议, TCP、UDP协议都是基于IP协议的, TCP和UDP数据都通过IP数据报传输。

2026-07-16 16:41:16 335

原创 C++学习(11) ——C++11线程库(生产者消费者模型实现)

只需要在打印日志的时候加一个专门的锁就好了,但是在这我想尝试一下另一种方法,就是在之前我在写stm32的项目时的启发,我们可以创建一个队列,将待打印的数据放入队列当中,输出任务就只需要从队列里边取数据输出就可以了,这样既可以解决打印错乱的问题,也可以正确的反应,各个线程真实的执行顺序。对于早期的C++语言而言,如果想使用线程,我们需要根据不同的平台使用不用的接口,比如:在Linux平台上,我们需要借助POSIX标准的线程库,在windows上需要借助windows线程库,因为C++自己没有独立的线程库。

2026-07-15 15:51:43 189

原创 C++学习(10) —— 面向对象设计

缺点:1、由于工厂类集中了所有产品的创建逻辑,职责过重,一旦不能正常工作,整个系统都要受到影响;2、使用简单工厂模式势必会增加系统中类的个数(引入新的工程类),增加了系统的复杂度和理解难度;(比如,如果想要创建梯形、椭圆形之类的图形,还需要改动Factory的代码)3、系统拓展困难,一旦添加了新的产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的拓展和维护4、简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。

2026-07-07 10:00:00 199

原创 C++学习(9) —— STL标准模板库

对于set而言,当Key类型是类类型的时候,那么第二个模板参数Compare默认会采用std::less,但是std::less针对的Key如果不能比较大小,就需要进行改写。模板的特化、运算符的重载、函数对象直接定义一个存放Point的set,编译一定会报错,根本原因在于默认的std::less针对Point对象并不知道该如何比较大小std::less是一个通用模板类,针对解决不了的特殊类型,可以想到特化模板。

2026-07-06 17:49:40 473

原创 C++学习(8) —— 移动语义与资源管理

可以理解为:如果显式定义了拷贝构造和移动构造,利用一个已存在的对象创建一个新对象时,会先尝试调用移动构造,如果这个对象是右值,就使用移动构造函数创建出新对象,如果这个对象是左值,移动构造使用不了,就会调用拷贝构造。总结:将拷贝构造函数和赋值运算符函数称为具有复制控制语义的函数;将移动构造函数和移动赋值函数称为具有移动语义的函数。

2026-07-06 17:48:53 265

原创 C++学习(7) —— 模板

像C/C++/Java等语言,是编译型语言,先编译后运行。它们都有一个强大的类型系统,也被称为强类型语言,希望在程序执行之前,尽可能地发现错误,防止错误被延迟到运行时。所以会对语言本身的使用造成一些限制,称之为静态语言。与之对应的,还有动态语言,也就是解释型语言。如javascript/python/Go,在使用的过程中,一个变量可以表达多种类型,也称为弱类型语言。因为没有编译的过程,所以相对更难以调试。如图,变量a表达了int数据,然后又去表达了字符串,python中允许这样的做法。

2026-07-06 17:47:40 206

原创 C++学习(6) —— 多态

(1)覆盖是在虚函数之间的概念,需要派生类中定义的虚函数与基类中定义的虚函数的形式。

2026-07-06 17:45:34 219

原创 C++学习(5) —— 继承

只有公有继承自基类的公有成员,可以通过派生类对象直接访问,其他情况一律都不可以进行访问。

2026-07-06 17:44:21 199

原创 C++学习(4) —— 运算符重载

C++ 预定义中的运算符的操作对象只局限于基本的内置数据类型,但是对于自定义的类型是没有办法操作的。当然我们可以定义一些函数来实现这些操作,但考虑到用运算符表达含义的方式很简洁易懂,当定义了自定义类型时,也希望这些运算符能被自定义类类型使用,以此提高开发效率,增加代码的可复用性。为了实现这个需求,C++提供了运算符重载。希望自定义类类型在操作时与内置类型保持一致。能够重载的运算符有42个!>=<=&&||++

2026-07-04 16:47:12 160

原创 C++学习(3) —— C++输入输出流

比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。在运行的时候会发现如果出线一次违法操作,就会直接运行结束,且下面的变量结果都是0.如果没有进行正确的输入,输入流会进入failbit的状态,无法正常工作,需要恢复流的状态。以前所用到的输入和输出,都是以终端为对象的,即从键盘输入数据,运行结果输出到显示器屏幕上。

2026-07-04 16:14:28 317

原创 C++学习(2) —— 类与对象基础

过程论认为:数据和逻辑是分离的、独立的,程序世界本质是过程,数据作为过程处理对象,逻辑作为过程的形式定义,世界就是各个过程不断进行的总体。对象论认为:数据和逻辑不是分离的,而是相互依存的。相关的数据和逻辑形成个体,这些个体叫做对象,世界就是由一个个对象组成的。对象具有相对独立性,对外提供一定的服务。所谓世界的演进,是在某个“初始作用力”作用下,对象间通过相互调用而完成的交互;在没有初始作用力下,对象保持静止。这些交互并不是完全预定义的,不一定有严格的因果关系,对象间交互是“偶然的”,对象间联系是“暂时的”。

2026-07-04 16:11:09 194

原创 C++学习(1) ——C与C++

命名空间又称为名字空间,是程序员命名的内存区域,程序员根据需要指定一些有名字的空间域,把一些全局实体分别存放到各个命名空间中,从而与其他全局实体分隔开。通俗的说,每个名字空间都是一个名字空间域,存放在名字空间域中的全局实体只在本空间域内有效。名字空间对全局实体加以域的限制,从而合理的解决命名冲突。char val2;在声明一个命名空间时,大括号内不仅可以存放变量,还可以存放以下类型:变量、常量、函数、结构体、引用、类、对象、模板、命名空间等,它们都称为实体//定义变量//定义常量。

2026-07-04 16:01:00 368

原创 stm32单片机学习(40)——关于CAN的收发实验

当然了这只是演示它的功能,正常我们还是需要配置中断来接收消息的这样会更合理,另外就是我们现在是环回模式只是用来自测,那么如果实现真正的通信需要修改什么呢?//只需要修改这个参数就好了 CAN_InitStruct . CAN_Mode = CAN_Mode_LoopBack;

2026-06-21 20:10:20 278

原创 stm32单片机学习(39)——STM32中的CAN外设

bxCAN是基本扩展CAN(Basic Extended CAN)的缩写,它支持CAN协议2.0A和2.0B。它的设计目标是,以最小的CPU负荷来高效处理大量收到的报文。它也支持报文发送的优先级要求(优先级特性可软件配置)。对于安全紧要的应用,bxCAN提供所有支持时间触发通信模式所需的硬件功能。

2026-06-20 18:22:00 478

原创 stm32单片机学习(38)——CAN通信协议

CAN 是 Controller Area Network 的缩写(以下称为 CAN),是 ISO*1 国际标准化的串行通信协议。在当前的汽车产业中,出于对安全性、舒适性、方便性、低公害、低成本的要求,各种各样的电子控制系统被开发了出来。由于这些系统之间通信所用的数据类型及对可靠性的要求不尽相同,由多条总线构成的情况很多,线束的数量也随之增加。为适应“减少线束的数量”、“通过多个 LAN,进行大量数据的高速通信”的需要,1986 年德国电气商博世公司开发出面向汽车的 CAN 通信协议。

2026-06-19 20:27:55 545

原创 stm32项目(4)——lp_node

坦白讲我没想到这个项目输出成博客,这四篇文章只有这寥寥几个字,深恶之都没有我学习外设的文章文字多,但其实也确实就是这样了,当我们具备做很多事情的基础之后,那么我们阐述的就是思路了就是一个更宏观的框架,只能是说把一些决定不错的细节讲一下不可能面面俱到,比如我怎么接收CAN的数据,怎么用联合体很巧妙的转换数据结构,如果这种问题放在专门讲CAN的章节还是可以,写在这里倒是有些违和了。依旧是CAN的数据收发,这部分不再赘述,唯一的区别就是各个节点发送的数据帧和接收的数据帧不一致,在处理上有些许不同。

2026-06-18 14:24:26 184

原创 stm32项目(3)——log_node

关于log_node节点的代码,因为一些原因变的很简单了我们先说一下当前的代码,等之后在扩展一下,最开始想要实现的效果。

2026-06-18 11:10:23 241

原创 STM32项目(2)——host_node

这里的功能不固定,我也是随用随加的。因为我的项目比较简单,帧的类型不多,我就在我所有的节点实现的代码中的这部分初始化了四种帧格式,这样就发送起来简单,另外就是不需要来回的看和翻找确认了,尽管这对于程序来讲是一个无意义且浪费资源的行为,但是可以极大的便利我们,当然注释放在这里一样可以提醒,但是这样还有另外一个好处就是,我们做环回测试的时候,可以更方便的在一个MCU配置过滤器。其实和USART的思路大差不差,同样需要两个任务,不同的是,CAN的数据收发比较固定,不需要太多的逻辑,因为他就是负责与节点的通信。

2026-06-18 10:04:15 213

原创 STM32项目(1)——项目介绍

该项目主要是博主用来练习CAN总线和低功耗设计的一个项目,如果是刚刚学习完基础外设的同学是不合适这个项目的,因为这里用CAN总线实现分布式多机通信,需要多个MCU。业务场景是智慧大棚,主要实现大棚的通风系统,通过来舵机模拟开关。host_node 主机节点作为中控系统,与用户进行数据交互,同时传达用户指令到各个节点log_node 日志节点进行日志记录,并且负责整个系统的时间同步工作。但是由于种种原因,日志非常粗糙,如果有兴趣扩展的同学可以考虑将数据存入W25Q64。

2026-06-18 10:03:56 278

原创 STM32单片机学习(37) —— PWR和BKP

这一篇内容包括两个内容,一个是PWR电源控制以及BKP备份寄存器。因为BKP的内容不多所以就合并到一起了。另外就是我与大家分享一个关于我的小插曲。在这最后我们同样还是会有个关于低功耗的小实验。原本我是不打算写在这里的。等我们学完之后就会知道stm32f103c8t6的芯片唤醒低功耗模式会有一些局限性。所以我上网查了有专门应对低功耗场景的芯片L0系列。这个芯片有一个LPUART,就是说他可以通过USART通信唤醒STOP模式(这些下面都会讲到)。

2026-06-10 19:24:07 261

原创 STM32单片机学习(36) —— RTC

实时时钟是一个独立的定时器。RTC模块拥有一组连续计数的计数器,在相应软件配置下,可提供时钟日历的功能。修改计数器的值可以重新设置系统当前的时间和日期。RTC模块和时钟配置系统(RCC_BDCR寄存器)处于后备区域,即在系统复位或从待机模式唤醒后,RTC的设置和时间维持不变。系统复位后,对后备寄存器和RTC的访问被禁止,这是为了防止对后备区域(BKP)的意外写操作。设置寄存器RCC_APB1ENR的PWREN和BKPEN位,使能电源和后备接口时钟。

2026-06-10 19:23:32 266

原创 STM32单片机学习(35) —— DMA

直接存储器存取(DMA)用来提供在外设和存储器之间或者存储器和存储器之间的高速数据传输。无须CPU干预,数据可以通过DMA快速地移动,这就节省了CPU的资源来做其他操作。两个DMA控制器有12个通道(DMA1有7个通道,DMA2有5个通道),每个通道专门用来管理来自于一个或多个外设对存储器访问的请求。还有一个仲裁器来协调各个DMA请求的优先权。上面来自官方文档对DMA的解释,从最后一句话,仲裁器协调各个DMA请求。可以推测出DMA各个通道在搬运数据时,并不是并行运行的,而是并发的。

2026-06-08 21:10:15 364

原创 FreeRTOS学习(12)——任务通知

消息队列(Queue)信号量(Semaphore)消息队列主要用于任务与任务、任务与中断之间传递数据信号量主要用于任务同步以及资源管理消息队列的作用几乎是不可替代的。如果需要在任务与任务,或者任务与中断之间传递数据,那么消息队列通常都是首选机制。但在实际应用中,很多时候并不需要传递数据。中断通知任务一个任务唤醒另一个任务某个事件发生后通知任务继续执行这种情况,本质上只是 发送通知和接收通知。二值信号量就可以完成这种任务同步工作。

2026-06-03 14:22:51 317

原创 FreeRTOS学习(11)——信号量

到这里为止,三种常见的信号量机制:二值信号量、计数信号量、互斥信号量,我们已经全部学完了。我们可以对 信号量相关的操作 API 做一个简单的总结。三种信号量的创建函数各不相同,但本质上都是创建消息队列,返回消息队列句柄。释放信号量都使用xSemaphoreGive()函数:对于二值信号量而言,释放信号量表示信号状态从无到有,从0到1。对于计数信号量和互斥信号量而言,释放信号量表示资源被释放,可用资源增加。本质上,都是uxMessagesWaiting++

2026-06-03 14:22:15 348

原创 FreeRTOS学习(10)——消息队列

经过上面文档的阅读与学习,相信大家已经对FreeRTOS的消息队列有了一定的理解。消息队列既可以用于任务之间通信,也可以用于中断与任务之间通信。具体来说:任务发 → 任务收(常见)中断发 → 任务收(很常见)任务发 → 中断收(几乎没有)在嵌入式系统中,最常见的一种模式是:外设中断 → 发送消息到队列 → 任务读取消息并处理。在这种模式下,中断只负责收集数据,任务负责处理业务逻辑。要重点学习这种消息队列的使用模式,这是实际工程中,最常见的消息队列使用方式。

2026-06-03 14:21:32 563

原创 FreeRTOS学习(9)——临界区

通过源码可以看出,vTaskSuspendAll() 并不是“停止系统运行”,而只是“暂停任务调度”。系统 Tick 仍然正常产生,全局时间持续推进。但所有与任务调度相关的行为被暂时冻结。调度器暂停后,所有“与调度相关的行为”都会被延迟处理,而不会丢失。延时阻塞任务到期 → 不立即转入就绪态,而是通过记录事件触发 → 不直接进入就绪列表,而是进入挂起就绪列表任务切换 → 不立即发生本质上:不是“不处理”,而是“暂不处理,后续统一处理”

2026-06-02 09:12:05 595 1

原创 FreeRTOS学习(8)——获取任务信息API

在前面的内容中,我们已经学习了任务的创建、删除、阻塞以及挂起恢复等操作。这些 API 主要用于“控制任务行为”。当前正在运行的是哪个任务;某个任务的优先级是多少;系统当前有多少个任务;调度器是否已经启动。也就是说,我们不仅要“控制任务”,还要“获取任务信息”。为此,FreeRTOS 提供了一组任务获取 API。这类 API 不会改变任务状态,而是用于查询系统当前运行情况,常用于调试与状态监测。接下来,我们将逐一介绍这些任务获取接口,并结合源码分析其实现机制。

2026-06-02 09:11:02 201

原创 FreeRTOS学习(7)——任务列表

Ready ↔ Running —— 解决的是 CPU 在多个任务之间如何切换;Running → Blocked → Ready —— 解决的是任务为何主动离开 CPU;Ready ↔ Suspended —— 解决的是任务如何被人为移出调度体系。调度器如何管理“就绪态任务”?因为无论是阻塞完成,还是恢复挂起,最终都会回到 Ready 状态,重新参与 CPU 竞争。也就是说:所有任务状态流转的“汇聚点”,都是——就绪态。那么问题来了:FreeRTOS 内核究竟是如何组织这些就绪任务的?

2026-05-30 19:34:36 324

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除