- 2025-03-04
-
发表了主题帖:
RainbowLink USB 协议转换器 测评二:TTL 电平通信丢波率测试
本帖最后由 我的学号 于 2025-3-4 21:26 编辑
1.RainbowLink USB 协议转换器 上带有 TTL*2, 232 *1 和485 *1,先复习 TTL 电平的概念:
按答案,主要区别在于输入输出电平,以及通过 MCU 的 GPIO 输出可以得到 TTL 电平
2.本次测试TTL 通信,基本思路是利用 MCU 的 UART 接口发送固定次数通信数据,数据采集由 RainbowLink 实现,并在PC 上位机中显示;
通过 上位机接收到的数据总量/理论数据总量,即可得到通信丢波率。一次测试完成后,修改MCU 通信波特率,继续测试;连接示意图如下:
为得到高波特率的 UART 通信,MCU 本身的频率必须高
结合手头板卡,选用了 TI 的 28377s. 其时钟可达 200MHz, 通过修改相关寄存器可得到不同波特率
3,初始化设置串口发送每帧格式为 8bit 数据位,奇校验,1 bit 停止位;理论上MCU 发送1w 帧后上位机可以收到 8w数据
分别测试 115200 波特率
256000 波特率
512000 波特率
1M 波特率
2.5M 波特率
4.数据统计及分析
由统计数据可以发现,随着通信波特率提高,丢波率上升;按产品宣传 RainbowLink USB 最高通信波特率可到 6M;这个丢波率的提高估计是杜邦线连接、终端阻抗不匹配带来的影响
另一个有意思的情况是,115200 波特率和 512000 波特率 通信基本不丢波,256000 为什么就丢波严重了?
将寄存器数值带回原公式可发现:
256000 实际波特率是 257731,理论与实际偏差较大造成数据丢失严重
- 2025-02-20
-
加入了学习《机器人学》,观看 机器人学导论
-
加入了学习《机器人学:建模、控制与视觉》,观看 第1章:概述;第2章:机器人机构
-
加入了学习《 ESP32教程(基于ESP-IDF)ESP32入门级开发课程》,观看 ESP32开发内容介绍
-
加入了学习《自己动手写嵌入式操作系统》,观看 自己动手写操作系统
- 2025-02-17
-
回复了主题帖:
机器人开发话题征集:写啥你来定!
很想知道,如何把AI 应用在机器人上
- 2025-02-16
-
发表了主题帖:
《Hello 算法》学习笔记之哈希表 (第6章)
本帖最后由 我的学号 于 2025-2-16 11:52 编辑
第六章 哈希表
6.1 哈希表是这样的一种数据结构:通过建立键(KEY) 和数值(VALUE) 之间的映射关系,实现元素数据的高效查找 ;举个例子,在学校时我们会用座位号代替学生名,当老师点名到 9527 时,就知道该站起来回答问题的是自己了。
和数组/链表 结构相比,哈希表对数据的查找、添加,删除 操作,其效率都是 O(1)
哈希表中存储 键-数值 的单元称为 桶(bucket)
理论上每输入一个键只能得到唯一对应的数值,但由于输入数据和哈希映射算法问题,存在输入不同键得到相同数值的情况,这种情况称为 哈希冲突
通过扩容哈希容量可以减少哈希冲突,这种方法称为 扩容;哈希扩容和数组扩容一致,属于耗时的存在
哈希元素除以桶数量,其比值称为负载因子,程序中常用其作为哈希表扩容的触发条件
6.2 解决哈希冲突除了扩容,还可以通过改进哈希表结构的方法实现;常见的方法有:
链式寻址:将引发哈希冲突的数值存储在链表结构中,当外部输入键值时,就在该链表中查找出需要的数值
该方式可以实现数据的查找添加和删除,代价是占用空间增大、查询效率降低
另一种方式为 开放寻址,实现的方式有 线性探测、平方探测和多次哈希等。
线性探测的实现原理为:检测到有哈希冲突时,按一定的步长遍历表格直到找到空桶并存储
线性探测容易产生 聚集现象,且实现后不能在哈希表中直接删除元素
引入 懒删除 的机制解决哈希元素不能直接删除的问题:用常量 TOMBSTONE 标记不起作用的桶,与空桶标记 NONE 区分开来
平方探测即将探测步长修改为 x 的平方,如 1,4,9,16 等数据
多次哈希则是采用 哈希函数 f(x) 进行探测
不同编程语言的策略选择:
6.3 通过改进哈希算法,可以达到减少哈希冲突的目标;哈希算法具有如下特点:
哈希算法除了制作哈希表,还可以用于密码存储和数据完整性检查
简单的哈希算法包括有:加法哈希、乘法哈希、异或哈希和旋转哈希
如果用取模的方式实现哈希算法,求余的数值选择大质数。这样能减少哈希冲突
更高级的哈希算法包括 MD5 SHA-1 SHA-2 SHA-256 等
不同数据类型计算哈希数值时,表现有所不用;以 python 语言自带的 hash() 函数为例:
其他:可以直观查看哈希表的可视化网页
- 2025-02-12
-
发表了主题帖:
《Hello 算法》学习笔记之栈 (第5章)
本帖最后由 我的学号 于 2025-2-11 20:52 编辑
第五章 栈与队列
5.1 栈
定义一组数据,数据结构可以是数组也可以是链表,规定数据都从栈顶存入,从栈顶取出,即“先入后出”
栈的典型应用有 浏览器中的后退与前进、软件中的撤销与反撤销
此外还有程序内存管理,在嵌入式开发中例如中断处理
5.2 队列
如果数据的存取规则为 先入先出,即先进来的数据先被取出,这样的数据结构称为 队列
队列的典型应用有 淘宝订单、各类代办事项
5.3 双向列表
如果结合队列和栈存取数据的特点,队列的头尾皆可以存入和取出数据,这样的数据结构称为双向队列
- 2025-02-09
-
发表了主题帖:
《Hello 算法》学习笔记之数组和链表 (第4章)
本帖最后由 我的学号 于 2025-2-12 21:03 编辑
第四章 数组和链表
在评论里大家都说这图片选得好,数组相当于砖头主打一个整整齐齐,而藤曼是链表,体现了数据之间的跳跃和节点连接关系
4.1 数组
通过数组的定义,可知道数组具有如下几个特点:线性结构、相同数据类型、连续存储在内存中
常见的数组操作方式:
数组数据初始化:定义时顺便声明;
访问数组数据:用组数元素的 index 做访问;C 语言里数组名可以当作数组的首地址使用;在嵌入式编程里,用库函数操作寄存器,也是使用了 首地址+偏移量 这种方式;
插入元素:在数组中特定位置插入新元素,其后的元素都得往后挪动,处理时间长,且需保证数组长度足够;
删除元素:在数组中特定位置删除某元素,其后的元素都得往前挪动,处理时间长,且最后位置空缺无释放;
遍历数组:通过对 索引得操作可以很快遍历所有数据
查找数据:通过对 索引的操作可以很快筛选出目标数据
扩容数组:需要重新定义更大的数组,并将原有数组放入新数组中, 不够灵活
使用数组的优点:空间效率高、支持随机访问、缓存局部性;缺点:插入删除效率低,长度不可变,空间浪费
数组的典型应用:样本随机访问,排序和搜索算法、表数据查找、数学计算中的向量和矩阵表示、其他数据结构的实现等。
4.2 链表
与数组的定义相对应的,链表是一种分散的线性数据结构;数组中每个单元称为 元素, 在链表中则称为 节点
每个节点由 数值 和指向下一个节点的 指针 组成,首个节点称为首指针,最后的节点称为 尾指针,单向链表中尾指针一般为 null
和数组只存储数据相比,链表多了位置指向的内存,占用了更多空间;换来的效果也很明显,添加删除节点比数组更方便
常见的链表结构操作如下:
初始化:链表节点数据赋值+节点引用关系建立;通常用头节点作为链表代称;
插入节点:将左边节点的指针指向新节点,新节点的指针指向原右节点;
/* 在链表的节点 n0 之后插入节点 P */
void insert(ListNode *n0, ListNode *P) {
ListNode *n1 = n0->next;
P->next = n1;
n0->next = P;
}
删除节点:修改左边节点的指针指向即可
/* 删除链表的节点 n0 之后的首个节点 */
// 注意:stdio.h 占用了 remove 关键词
void removeItem(ListNode *n0) {
if (!n0->next)
return;
// n0 -> P -> n1
ListNode *P = n0->next;
ListNode *n1 = P->next;
n0->next = n1;
// 释放内存
free(P);
}
访问节点:链表中访问节点需要从头节点开始往后遍历,相对数组来说效率较低
查找节点:同样需要遍历操作
链表和数组的比较:
常见链表有 单向链表、环形链表和双向链表三种形式
链表典型应用:
4.3 列表
C 语言中并无列表的概念,这里用 python 中的 list 做理解
书中提到列表属于一种动态数组;个人理解是数组在声明时不定义其长度,如此可以实现元素随时添加
对列表的操作,如插入删除,拼接,排序等,都可以通过高级语言提供的函数直接实现
其他:
-
发表了主题帖:
《Hello 算法》学习笔记之数据结构 (第3章)
本帖最后由 我的学号 于 2025-2-9 17:29 编辑
第三章 数据结构
3.1 按数据和数据之间的逻辑结构,数据结构可分为 线性 和 非线性 两种,常见的数据结构及其特征如下表所示:
物理结构上,数组(数据连续存储) 和链表(数据分散存储) 属于两种最基本的数据结构,其他类型的结构都由这两种演化而来
数组在定义后其长度不可改变,是为 静态数据结构,而链表初始化完成后长度可更改,因此称为 动态数据结构
3.2 计算机中基本数据类型如下所示:
需要注意的是,不同的编程语言对数据长度的解释可能不一样;
数据类型的定义也不是越大越好,在资源受限的场合如嵌入式编程,甚至会用 Q 格式代表浮点数据;数据的精度和长度同样是需要权衡的对象
数据结构和数据类型之间的关系是,打个比方,数据类型相当于砖的个头和材质,数据结构则相当于用什么方式使用这堆砖
3.3 数字编码
原码,反码和补码的概念,想起数字电路里边对加法器的介绍
反码补码的出现,本质上是为了从二进制层面解决带符号数据的计算问题
浮点数在计算机内存中的存储方式,属于牺牲数据精度换来存储长度
3.4 字符编码
常见的字符编码有 ASCII、GBK、 Unicode、 UTF-8 等
-
回复了主题帖:
《Hello 算法》学习笔记1 基本概念介绍(第1~2 章)
Jacktang 发表于 2025-2-9 09:28
当评估一个算法的时间复杂度时,由于时间执行的长短和输入数据密切相关,所以一般不考虑最优时间;稳妥应该 ...
共同学习
- 2025-02-07
-
发表了主题帖:
《Hello 算法》学习笔记1 基本概念介绍(第1~2 章)
本帖最后由 我的学号 于 2025-2-7 22:08 编辑
收到 hello 算法这本书已经是去年的事了;感谢作者在 githup 上的开源,网页电子版还提供了多种编程语言的算法动画演示,十分适合数据结构与算法这门课程的学习;有条件的同学纸质版尽量支持一波;闲话休多絮,1-2 章属于基本概念的介绍,奉上读书记录:
第一章 初识算法
全书编排:
1.1 算法在日常生活无处不在,很多时候体现在我们对日常生活的处理上;例如按字母排列翻查字典就属于二分法,排列扑克牌大小则是插入排序,超市货币找零则是使用了贪心算法。运行在 CPU 或 GPU 上的程序,只是这种思维逻辑的一种体现方式。
1.2 记得初学编程时,教科书里对 程序 的定义是 数据结构+算法;用我自己的体会来说就是:程序是为实现特定的目的而产生的,算法和数据结构是我们达到这个目的的工具; 打个比方假如爬到山顶属于我们的目标,算法就属于各条登山道;登山道可以是大路也可以是小径,甚至是缆车; 可以选择登山靴运动鞋甚至是凉鞋,反正最后都能到达山顶;但在一些场合下,能用多快的速度爬到山顶,或者要求穿着凉鞋到达山顶,完成这一目标需要既定条件(数据结构)也需要实现方法(算法)。一般程序开发的要求是需要的时间越短越好、占用的资源越少越好;但世间安有双全法,诚如书中所言,如何在有限资源下找到最优解,这是一个需要权衡彼此的过程。
第二章 复杂度分析
2.1 评估算法的优劣,可以用复杂度分析理论估算的方式进行;复杂度分析可以从时间复杂度和空间复杂度两方面进行评估。
2.2 编程语言中,重复执行的语句对复杂度分析影响较大;常见的重复性语言结构有 迭代 和 递归;
迭代操作可以用 for 语句 或 while 语句实现,基本逻辑为:在达到某种条件前不断执行某段语句
当循环的条件维度为1 时,复杂度和条件执行次数 n 成线性关系
当使用二重嵌套时,复杂度和执行次数 n*m 成线性关系
另一种方式 递归,感觉在嵌入式开发中使用比较少,书中举例一个 1+2+...+n 的函数作为说明:
/* 递归 */
int recur(int n) {
// 终止条件
if (n == 1)
return 1;
// 递:递归调用
int res = recur(n - 1);
// 归:返回结果
return n + res;
}
函数每次运行后的结果,又将作为参数传入函数中,直到条件被满足停止运作;
从编程的角度看,它利用了 return 这个关键字的机制,决定程序继续运行还是停止
嵌入式编程少用递归也很合理,函数每次开启时都需要内存存储变量/运行地址等信息,而mcu 的资源是有限的,递归长度增加则消耗更多空间,效率低下
递归和迭代的比较如下所示:
尾递归:如果函数在返回前的最后一步才进行递归调用,则该函数可以被编译器或解释器优化,使其在空间效率上与迭代相当;举例:
/* 尾递归 */
int tailRecur(int n, int res) {
// 终止条件
if (n == 0)
return res;
// 尾递归调用
return tailRecur(n - 1, res + n);
}
通过可视化代码运行可以发现,尾递归和普通递归的不同处在于, return (归) 操作前完成了数据计算
递归树:不断递归产生的树分支结构,例如求斐波那契数列
2.3 时间复杂度
时间复杂度分析指 算法运行时间随数据量变大时的增长趋势;时间复杂度分析本质上是计算 操作数量 T(n) 的渐进上限,其数学定义为:
计算这个渐进上限时,可按如下步骤进行:
时间复杂度类型有按所需时间排列如下:
阶数名称
输入数据特征
说明
常数阶O(1)
操作数量与输入数据大小 n 无关,即不随着 n 的变化而变化
循环次数固定
线性阶O(n)
操作数量相对于输入数据大小 n 以线性级别增长
通常出现在单层循环中,如遍历数组或链表
平方阶O(n的平方)
输入数据大小 n 以平方级别增长
通常出现在嵌套循环中,如冒泡排序
指数阶O(2的n次方)
循环次数按2 的阶乘进行
常出现于递归函数中,在穷举法(暴力搜索、回溯等)中比较常见
对数阶O(log n)
输入数据大小为 n ,每轮缩减到一半
常出现于递归函数中. 增长缓慢,是仅次于常数阶的理想的时间复杂度
线性对数阶O(n logn)
嵌套循环中,两层循环的时间复杂度分别为 O(logn) 和 O(n)
主流排序算法的时间复杂度,例如快速排序、归并排序、堆排序等
阶乘阶O(n!)
给定 n 个互不重复的元素,求其所有可能的排列方案
当 n≥4 时恒有 n!>2n ,所以阶乘阶比指数阶增长得更快
当评估一个算法的时间复杂度时,由于时间执行的长短和输入数据密切相关,所以一般不考虑最优时间;稳妥应该使用平均时间,最保险的做法是考虑其运行的最差时间
2.4 空间复杂度
空间复杂度用于衡量随数据增加,算法占用内存空间的情况;一般关注的内容有:
统计最差空间复杂度时,需要用到最差的数据输入和以算法运行时的峰值内存为准,这同样时考虑最差情况
由于递归计算运行到最后才释放内存,因此统计时需要加上栈顶空间
常见空间复杂类型:
阶数名称
输入数据特征
说明
常数阶O(1)
常见于数量与输入数据大小 n 无关的常量、变量、对象
在循环中初始化变量或调用函数而占用的内存,在进入下一循环后就会被释放,空间复杂度仍为 O(1)
线性阶O(n)
常见于元素数量与 n 成正比的数组、链表、栈、队列等
n 层递归,空间复杂度同样为 O(n)
平方阶O(n的平方)
常见于矩阵和图,元素数量与 n 成平方关系
包含n 个数组的 n 层递归,空间复杂度同样为 O(n的平方)
指数阶O(2的n次方)
常见于二叉树
对数阶O(log n)
输入长度为 n 的数组,每轮递归将数组从中点处划分为两半
常见于分治算法,例如归并排序
- 2025-01-24
-
回复了主题帖:
【B-G431B-ESC1-无刷电机板】4-Hall测速,电角度估算,电流闭环
一般定义正对电机转轴时逆时针方向为电机运动的正方向,可以用手拖动转轴旋转,观察此时程序里的电角度计算是递增还是递减
-
回复了主题帖:
【B-G431B-ESC1-无刷电机板】4-Hall测速,电角度估算,电流闭环
Q 轴给正电流电机却反转的情况,先确认下电机的 UVW 功率线的线序有没接错
- 2025-01-22
-
回复了主题帖:
祝福2025!回帖即有奖!选取最有心的送5块国产开发板!
CW32L0 刚出来做活动时,同样入手了核心板、无刷电调板和电流表板,后续也在淘宝上囤了好几片芯片,1.6 大洋的价格是真的香;定时器、ADC、PWM、UART、SPI、IIC 等常用外设一个不少,还支持3v3~5V 的宽供电范围;24年很多大厂都推出了带 NPU 的芯片,期待后续国产芯片继续发力,卷低端路线的同时也向高端发展,国产芯片崛起,你我都有幸作为历史的见证人
-
回复了主题帖:
【颁奖】 【回顾2024,展望2025】新年抢楼活动来啦!
个人信息已确认
- 2025-01-21
-
加入了学习《得捷电子专区》,观看 Arduino Nano RP2040 Connect 坐姿检测应用
- 2025-01-17
-
加入了学习《手把手教你学LittleVGL》,观看 环境搭建
-
加入了学习《自己动手写嵌入式操作系统》,观看 时间片轮转和上下文切换
- 2025-01-16
-
加入了学习《电机控制系统硬件设计培训教程》,观看 电机控制硬件设计