- 博客(101)
- 收藏
- 关注
原创 IWDG—独立看门狗
IWDG(Independent Watchdog)= 独立看门狗,本质是一个12位递减计数器。计数器从重装载值开始往下减减到0 → 产生复位(IWDG_RESET),系统重启减到0之前刷新计数器 → 不复位,这个动作叫:防止程序跑飞。程序正常运行时定期喂狗,跑飞了就不喂狗→超时→复位重启。
2026-11-10 09:34:19
149
原创 ADC—电压采集
ADC(Analog-to-Digital Converter)= 把模拟电压转换成数字值。F407有3个ADC(ADC1/2/3),每个:12位分辨率(可选10/8/6位),12位输出范围0~409516个外部通道(对应16个GPIO引脚)+ 3个内部通道(温度传感器、Vrefint、Vbat)3种模式:独立模式、双重模式、三重模式输入电压范围:0~3.3V(VREF+=3.3V,VREF-=GND)。实际电压 = 3.3 × ADC数值 / 4096。
2026-11-10 09:33:36
175
原创 基本定时器(TIM6/TIM7)
基本定时器最简单,就干一件事:到点了触发中断。定时器本质就是计数器,每个时钟脉冲加1,数到ARR就溢出、产生中断、清0重来。三个核心寄存器:PSC(预分频器):对输入时钟分频CNT(计数器):从0往上数ARR(自动重装载值):数到这个值就溢出,CNT清0,产生更新中断公式: 定时周期 = (PSC+1) × (ARR+1) / 定时器时钟 更新事件频率 = 定时器时钟 / ((PSC+1) × (ARR+1))例:TIM6时钟84MHz,要定时0.5秒(2
2026-11-10 09:32:37
224
原创 DMA—直接存储器访问
DMA(Direct Memory Access)= 不经过CPU,直接在存储器和外设之间搬数据。CPU只负责启动DMA,搬数据的过程CPU完全不参与,搬完DMA触发中断通知CPU。:CPU死等每个字节发完,115200发100字节约8ms,这8msCPU啥也干不了:调用立刻返回,DMA自动搬,CPU这8ms可以干别的。
2026-11-09 15:53:06
144
原创 SysTick 系统滴答定时器
Cortex-M4的 24 位递减计数器,不是片上外设定时器(TIM)。所有 Cortex-M4 芯片都有,可移植。:产生固定周期中断,当系统时基。裸机给用,FreeRTOS 给操作系统当心跳。
2026-11-09 15:52:36
59
原创 EXTI 外部中断(GPIO)
按键按下(引脚高→低)→ EXTI 检测到下降沿,置PR标志→ NVIC 开门允许→ CPU 跳 EXTI0_IRQHandler()→ HAL_GPIO_EXTI_IRQHandler() 清标志→ 自动调 HAL_GPIO_EXTI_Callback()→ 你在回调里写处理逻辑。
2026-11-09 15:52:04
171
原创 中断(NVIC)
类型例子谁调CubeMX 生成中断来了 CPU 自动跳HAL 库自带ISR 里调HAL 库自带,你调main 里调HAL 空壳,你重写HAL 自动调。
2026-10-09 21:22:06
129
原创 STM32F407 时钟
┌─ /M ──→ VCO 输入 1MHz├──→〔PLL〕────┼─ ×N ──→ VCO 输出 336MHz ─┬─ /P ──→ PLLCLK 168MHz ──→ SYSCLK│ └─ /Q ──→ 48M 域:USB OTG FS / SDIO / RNG(≤48MHz)└─ PLLI2S(独立的一条,给 I2S 用)SYSCLK ──→ AHB分频(HPRE) ──→ HCLK 168MHz(内核、存储器、DMA)
2026-10-09 21:21:23
187
原创 启动文件
启动文件里所有中断服务函数都是空实现,标了[WEAK]B .;死循环ENDP规则你在 C 文件里写了同名函数(比如)→ 用你的。没写 → 用这个空的死循环。后果:开了中断但忘了写中断服务函数 / 函数名拼错 → 中断来了直接跳进这个死循环,程序卡死。你自己写中断函数时,名字必须和向量表里的完全一致(如),错一个字母就等于没写。
2026-10-09 21:20:53
72
原创 GPIO 的基本功能与分组
(RCC,Reset and Clock Control)外设的时钟使能寄存器打开对应外设的时钟,才能访问该外设的寄存器。上拉 / 下拉电阻在引脚无外部驱动时提供确定的默认电平:上拉时引脚默认为高电平,下拉时默认为低电平,消除浮空状态下电压不确定的问题。输出速度越高,引脚电平切换的上升沿和下降沿越陡,开关速度越快,但同时功耗和电磁干扰(EMI)也越大。每个引脚在 MODER 中占 2 位,OTYPER 中占 1 位,OSPEEDR 中占 2 位,PUPDR 中占 2 位,配置时注意移位的起始位号。
2026-10-09 21:19:18
253
原创 认识HAL库
* 内部即 CMSIS 的 NVIC_EnableIRQ */HAL_NVIC_SetPriority(USART1_IRQn, 2, 0);/* 抢占优先级 2,子优先级 0 */│ └── STM32F4xx_HAL_Driver/ ← HAL 源码(Inc + Src)/* 恢复到进入前的状态,而不是无条件开 *//* 没事就睡觉,等按键/串口中断唤醒 *//* 临界区:这几行必须一口气执行完,不能被中断打断 */:数字越小越优先,高的能打断低的(中断嵌套)
2026-10-09 21:18:07
131
原创 11. Qt事件系统
窗口相关事件:closeEvent(关闭事件,close() 是槽函数,窗口没有关闭信号只有关闭事件)、resizeEvent(改大小,event->size()/oldSize())、showEvent(显示)、paintEvent(重绘)。key() 获取具体按键(如 Qt::Key_A、Qt::Key_Return 回车、Qt::Key_F5),modifiers() 获取修饰键(Qt::ControlModifier Ctrl、Qt::ShiftModifier Shift)。
2026-08-21 20:02:33
177
原创 10. ODBC
用 QSqlQuery(SQL 查询类)执行 SQL 语句:conn.exec("select * from user") 返回查询结果对象,query.next() 逐行移动,query.value(索引/列名) 取值。query.value("列名") 按列名取值(更可读)。setDatabaseName("test_odbc") 指定的是 ODBC 管理器中配置的数据源名字,不是数据库名(这是最常见的坑)。qDebug() << "打开失败" << conn.lastError();
2026-08-21 20:01:10
167
原创 5. 读Qt 5 开发及实例(第5版)笔记
一般设置流程:创建 QDockWidget → 调用 setFeatures() 与 setAllowedAreas() 设置属性 → 新建要插入的控件 → 调用 setWidget() 将控件插入停靠窗体 → 调用 addDockWidget() 将停靠窗体加入主窗口。综合使用分割窗口、堆栈窗体与基本布局,实现"左侧导航 + 右侧多页内容"的典型界面骨架:最外层是水平分割窗体,左侧是 QListWidget 导航,右侧是包含堆栈窗体(多个页面、每页用基本布局)和按钮布局的垂直布局。
2026-08-21 19:46:35
184
原创 4. 读Qt 5 开发及实例(第5版)笔记
tableWidget->setItem(0, 0, new QTableWidgetItem("姓名"));// ========== QTableWidget(简单数据) ==========// ========== QTableView(模型绑定) ==========model->setData(model->index(0, 0), "张三");child2->setText(0, "子目录2");
2026-08-21 19:44:49
192
原创 2. 读Qt 5 开发及实例(第5版)笔记
提供默认构造、拷贝构造和赋值运算符。),因为它们没有拷贝构造和赋值运算符。存储在Qt容器中的数据类型必须。,需要自定义数据模型用。// ✅ 正确:存指针。,可存储多种Qt类型。
2026-08-20 19:45:40
118
原创 1. 读Qt 5 开发及实例(第5版) 笔记
/ toDouble() / toFloat() 类似。// 一步到位:x, y, w, h。window->setWindowTitle("我的应用");// 与 += 等价。// 窗口默认不可见,必须调用 show()connect(发送者, SIGNAL(信号), 接收者, SLOT(槽));ui->label->setText("你好");
2026-08-20 19:45:05
177
原创 9. 多线程
关键成员:run()(线程体函数/任务函数,定义线程执行什么)、start()(启动线程,入口设为 run)、quit()(通知线程事件循环退出)、QThread::sleep(秒)(当前线程休眠)、isRunning()/isFinished()(状态查询)。方式 2 六步:①工作类继承 QObject ②定义槽函数当线程任务 ③创建线程对象+工作对象 ④moveToThread(线程) ⑤connect(线程 started 信号 → 工作类的槽)⑥start()。// 槽函数 = 线程任务。
2026-08-20 19:42:48
205
原创 8. 界面跳转
方式 3(信号槽跳转):在 Form 里声明 signals: void send_show();,外部用 connect(login_gui, &Form::send_show, &main_gui, &MainWindow::show) 把信号连到目标界面的 show()。②创建新界面对象跳转——点按钮槽里 new 目标界面并 show,当前界面 close/hide;// 方式3:信号槽方式(form.h 声明 signals: void send_show();
2026-08-20 19:42:14
200
原创 7. JSON
解析流程:QJsonDocument::fromJson(收到的字节) → .object() 还原对象 → obj["键"].toString() 取值。取值要按类型转换:obj["name"].toString()(字符串)、obj["age"].toInt()(整数)。QJsonArray 用 append() 加元素,遍历时每个元素用 toInt()/toString() 转类型。qDebug() << robj["name"].toString() // 按类型取值。// —— 数组 ——
2026-08-20 19:41:35
177
原创 6. Qt网络编程
connectToHost(服务器地址, 端口):发起连接,如 connectToHost(QHostAddress("127.0.0.1"), 8000)。客户端信息:cli->peerAddress().toString()(客户端 IP)、cli->peerPort()(客户端端口)。file.write(ui->textEdit->toPlainText().toUtf8().data(), // 写内容。
2026-08-19 19:17:46
197
原创 5. 控件学习
三种类型:临时信息(showMessage(文字, 毫秒),超时消失)、正常信息(addWidget(控件),显示在左半区)、永久信息(addPermanentWidget(控件),固定最右侧,不被临时信息覆盖)。文件操作主要用三个类:QFile(文件读写)、QFileInfo(文件信息)、QDir(目录操作)。QMessageBox:warning()/information()/critical()/question()/about(),参数是 (父窗口, 标题, 文字)。// 永久信息(右侧)
2026-08-19 17:57:09
163
原创 4. 控件学习2
currentIndex() 当前索引(0 开始)、itemText(i) 取指定索引文字、setCurrentIndex(i) 设当前项、count() 项数、clear() 清空、setEditable(true) 可手动输入。写单元格:setItem(行, 列, new QTableWidgetItem("内容"));增删行/列:insertRow(rowCount()) 末尾加行、insertColumn(columnCount())、removeRow(currentRow()) 删当前行。
2026-08-18 21:15:03
173
原创 3. 控件学习1
addItem() 添加一项(可 addItems(QStringList) 一次加多个)、clear() 清空、count() 项数、currentIndex() 当前索引(从 0 开始)、currentText() 当前选中的内容、itemText(index) 取某索引内容、setCurrentIndex(index) 设置当前项、setEditable(true) 可编辑、setEditText() 设置编辑框内容。QCheckBox(复选框),可独立选中/取消(不互斥,多个可同时选中)。
2026-08-18 20:54:58
191
原创 1. 了解Qt
/ toDouble() / toFloat() 类似。// 一步到位:x, y, w, h。window->setWindowTitle("我的应用");// 与 += 等价。// 窗口默认不可见,必须调用 show()connect(发送者, SIGNAL(信号), 接收者, SLOT(槽));
2026-08-17 13:27:34
212
原创 页面置换算法
其中Linux使用的页面置换算法就是Clock的变种,业内称为“两手时钟”,具体实现方法是创建两个链表——活跃链表和不活跃链表。不活跃链表中的页面根据方向的不同会被替换到活跃链表被或淘汰/换出链表,活跃链表中的页面只能被替换到不活跃链表。具体的实现思路是,将一部分正在使用的数据映射到内存中,暂时不使用的数据存储到备后备储中(一般是磁盘)。内存中接收映射的空间叫页框。常见的页面置换算法有:最佳置换算法(OPT)、先进先出置换算法(FIFO)、最近最久未使用置换算法(LRU)、时钟置换算法(Clock)。
2026-08-13 16:33:08
679
原创 27. 其他库
为解决这个问题,C++11 提供了接受 valarray 对象作为参数的模板函数 begin() 和 end()——使用 begin(vad) 而不是 vad.begin(),这些函数返回的值满足 STL 区间需求。它表示长度固定的数组,因此不支持 push_back() 和 insert(),但提供了多个 STL 方法(包括 begin()、end()、rbegin()、rend()),使得很容易将 STL 算法用于 array 对象。
2026-08-12 15:30:02
215
原创 26. 算法下
各容器提供不同级别的迭代器:vector/deque 为随机访问,list/set/multiset/map/multimap 为双向,stack/queue/priority_queue 不支持迭代器;// 统计 6 的个数。
2026-08-12 15:28:37
732
原创 25. 算法上
有些算法有两个版本:就地版本和复制版本,STL 的约定是复制版本的名称以 copy 结尾,并接受一个额外的输出迭代器参数指定结果的放置位置。前 3 组在头文件 <algorithm>(以前为 <algo.h>)中描述,第 4 组专用于数值数据,有自己的头文件 <numeric>(以前它们也位于 <algo.h> 中)。复制算法统一的约定是返回一个迭代器,该迭代器指向复制的最后一个值后面的一个位置(如 replace_copy() 的返回类型为 OutputIterator)。// 键(单词)→ 值(次数)
2026-08-11 08:56:14
732
原创 24. 函数符
预定义函数符是“运算符的‘函数对象’包装器”。因为STL 算法的参数是“对象”,而不是“符号”。分类函数符名称对应的运算符中文含义算术plus<T>加法minus<T>减法乘法divides<T>除法modulus<T>取模(余数)negate<T>(一元)取负(如-5比较(关系)==等于!不等于greater<T>大于less<T>小于>=大于等于<=小于等于逻辑&&逻辑与||逻辑或!逻辑非。
2026-08-11 08:54:57
152
原创 23.泛型编程下
map 提供 find(key)(返回迭代器,找不到返回 end())、count(key)(返回键出现次数,map 中为 0 或 1)、erase(key/迭代器/区间)、lower_bound(key)(第一个键不小于 key 的位置)、upper_bound(key)(第一个键大于 key 的位置)、equal_range(key)(返回匹配区间的迭代器对)等操作。与 set 相似,multimap 也是可反转的、经过排序的关联容器,但键和值的类型不同,且同一个键可能与多个值相关联。
2026-08-11 08:53:28
202
原创 22.泛型编程中
头文件 <iterator> 还提供了其他一些专用的预定义迭代器类型:reverse_iterator、back_insert_iterator、front_insert_iterator 和 insert_iterator。反向迭代器(reverse_iterator):执行递增操作将导致它被递减;rbegin() 返回指向超尾的反向迭代器,rend() 返回指向第一个元素的反向迭代器”。
2026-08-11 08:53:18
160
原创 21. 泛型编程上
struct Node { // 链表节点// 节点数据// 指向下一节点class iterator { // 链表迭代器类Node* pt;// 当前节点指针public:iterator(Node* pn = nullptr) : pt(pn) {} // 构造函数} // 解除引用:返回节点数据。
2026-08-11 08:52:59
180
原创 标准模板库(STL)
容器是与数组类似的单元,可以存储若干个值,STL 容器是同质的(存储的值的类型相同);即使有执行相同任务的非成员函数,STL 有时仍会定义成员函数,因为对有些操作而言类特定算法的效率比通用算法高——如 vector 的成员 swap() 效率比非成员 swap() 高,但非成员函数能交换两个不同类型容器的内容。规则(限制):for_each() 接受 3 个参数(前两个是定义区间的迭代器,最后是指向函数的指针或函数对象),把函数应用于区间中的各个元素,被指向的函数不能修改容器元素的值;
2026-08-10 21:54:18
307
原创 19. 智能指针下
这种随情况而异的行为也是“禁止(只是建议,编译器并不禁止)在容器对象中使用 auto_ptr,但允许使用 unique_ptr”的原因——容器算法对包含 unique_ptr 的容器执行类似左值赋值的操作将导致编译错误,执行类似右值赋值的操作则没问题。必须将 delete 与 new 配对、将 delete[] 与 new[] 配对:模板 auto_ptr 使用 delete 而不是 delete[],因此只能与 new 一起使用,不能与 new[] 一起使用;// 左值 unique_ptr。
2026-08-10 21:52:30
181
原创 17. 智能指针上
auto_ptr、unique_ptr 和 shared_ptr 都定义了类似指针的对象,可以将 new 获得(直接或间接)的地址赋给这种对象;shared_ptr 通过 use_count() 查看引用计数,计数随操作按以下规则变化:初始化 0 → 1,拷贝构造 +1,赋值左操作数 -1 右操作数 +1,作为函数参数传递 +1,作为函数返回值 +1,析构或 reset() -1。weak_ptr 是配合 shared_ptr 使用的"弱引用"智能指针:它指向对象但不增加引用计数,也不拥有所有权。
2026-08-10 21:51:36
201
空空如也
空空如也
TA创建的收藏夹 TA关注的收藏夹
TA关注的人
RSS订阅