-
什么是多线程? 在单片机上学习RT-Thread的多线程之前,要先把“进程”这个概念先放一边,因为单片机是没有多进程概念的。单片机运行操作系统,不管多少个任务,他们都是多个(或单个)线程之间进行处理这些任务,单片机一般不涉及多进程。 什么是多线程?在哪些情况下要用到多线程?先来举一个音乐播放器的例子,这个音乐播放器要做以下这些基本的工作:读取音乐文件并播放、读取歌词并显示、读取MV文件并播放。 如果这三个基本的工作不用多线程来完成,单片机使用裸机的方式去做这三个工作的话,必然会造成音乐播放卡顿,歌词显示不同步,MV视频播放与音乐不同步。 因为单片机做这三件事情的时候,是Step by Step的,必须完成一件事情之后,再去做下一件事情,这三件事情是有先后顺序的,并且不断循环重复,如下图所示。 而如果采用多线程这种方式来完成这个工作,这个过程就变得相对简单了,比如针对音乐播放器这个场景,可以设计这几个线程来处理:音乐文件读取线程,歌词文件读取线程,MV文件读取线程,音视频和歌词显示线程。 (此处只为举例描述多线程的概念,不考虑音视频编解码的复杂过程,不考虑线程同步,实际上音乐播放器的实现比此处描述更复杂) 音乐文件读取线程只负责从磁盘读取音乐文件,歌词文件读取线程和MV文件读取线程也是同样的道理,它们只做文件读取工作,而音视频和歌词显示线程,是负责把读取到的数据进行显示。这几个线程的工作过程,如下图所示。 如上图所示,这几个任务看上去是“同时”进行的,每个任务都只完成自己的事情,通过多线程,就可以把原本串行完成的任务改为并行完成,大大提高了工作效率。 所以,通俗地对多线程进行理解,就是把一个比较大型的任务,拆分为多个小型的任务,然后通过合理的调度方式,让这几个小型的任务“同时”运行,当这几个小型任务完成后,大型的任务也随之完成,这样可以大大提高任务的完成效率。多线程的几种状态 对于运行RT-Thread操作系统,线程都处于以下五种状态的其中一种(初始状态、就绪状态、运行状态、挂起状态、关闭状态),通过调用操作系统提供的接口函数,可以让线程在这五种状态中进行来回切换。 关于这五种线程状态的描述,如下表所示:多线程的API函数 如上图的状态机所示,多线程可以通过调用系统提供的函数接口,在多个状态之间进行切换。这些API函数在官方提供的参考文档里面都有详细的说明描述,以下列举一些比较常用的函数接口。多线程的应用示例 多线程的应用示例,主要是为了验证以上的多线程API接口函数,并且通过实验现象观察多线程的运行情况,主要有以下三个示例: 示例源码下载链接:https://github.com/embediot/rtthread_study_notes1、线程动态创建与静态创建、线程退出示例。 这个示例主要是通过动态方式创建线程1,,通过静态方式创建线程2,线程1的优先级比线程2的优先级低,因此可以被线程2抢占。线程2运行10次后就会主动退出,初始化代码如下图所示。2、相同优先级线程的时间片轮转调度示例。 这个示例主要是通过动态方式创建线程1和线程2,这两个线程都是相同的优先级,并且共用一个线程入口函数,主要是通过传入不同的线程参数以区分线程1和线程2。线程2运行所占用的时间片比线程1要少,因此线程2运行的时间比较短,初始化代码如下图所示。3、线程调度器的钩子函数使用示例。 这个示例主要测试了线程在进行调度时,关于钩子函数的调用情况。通过线程调度器的钩子函数,打印出线程间的切换信息,初始化的代码如下图所示。多线程应用的注意事项 在使用RT-Thread实时操作系统进行多线程应用开发的时候,应该要注意以下事项:1、RT-Thread的线程调度器是抢占式的,也就是能够保证就绪队列里面,最高优先级的任务总能获得CPU的使用权,在任务设计的时候,要充分考虑好任务的优先级。2、在硬件中断服务程序运行期间,如果有高优先级的任务就绪,那么被中断的低优先级任务将被挂起,高优先级的任务将会获得CPU的使用权。3、每个线程都有独立的线程栈,用来保存线程调度时上下文的信息,因此在创建线程分配栈空间的时候,要充分考虑栈的大小。4、在线程的循环体里面,应该要设置某些条件,在必要的时候主动让出CPU的使用权,特别对于高优先级的线程,如果程序里面有死循环操作而又不主动让出CPU使用权,那么这个线程将会一直占用CPU,并且低优先级的线程永远不会被调度执行。5、对于没有一直循环执行的线程,线程执行完毕后,资源的回收情况实际上是在空闲线程里面进行的,线程变为关闭状态后,不代表资源马上被回收。6、系统空闲线程是最低优先级且永远为就绪状态的,空闲线程是一个死循环,永远不会被挂起,但可以被其他高优先级任务抢占,空闲线程主要执行僵尸线程的资源回收工作。7、空闲线程也可以设置钩子函数,用来进行功耗管理,看门狗喂狗等工作。8、通过动态方式创建的线程,需要设置好系统堆内存的大小,而通过静态方式创建的线程,线程栈和线程句柄在程序编译的时候就已经确定,不能被动态分配,也不能被释放。9、大多数线程都是在不断循环执行的,无需进行删除,一般不推荐主动删除线程。线程运行完毕后,系统调度器将会自动把线程加入僵尸队列,资源回收工作将在空闲线程里面进行。
-
HPC( High Performance Computing,高性能计算)领域主要是解决计算密集型、海量数据处理等业务的计算需求,如科学研究、气象预报、计算模拟等。如何提高计算能力、极致化应用性能成为当前 HPC 领域各大平台最关键的课题之一,编译器在其中发挥着至关重要的作用。毕昇编译器作为一款基于鲲鹏平台的高性能编译器,在编译算法、加速指令集、 Autotuner 等方面对应用场景进行了深度的优化,为开发者提供高效的性能加持。本期由毕昇编译器工程师卜乐为你介绍鲲鹏的性能优化利器——毕昇编译器如何释放鲲鹏的强劲算力。了解毕昇编译器毕昇编译器是基于 LLVM,针对鲲鹏平台进行了深度优化的高性能编译器。除支持 LLVM 通用功能之外,对以下三个方面进行了增强,使得鲲鹏平台的强劲算力能够最大限度地得到释放。高性能编译算法:编译深度优化,内存优化增强,自动矢量化等,大幅提升指令和数据呑吐量。加速指令集:结合 NEON/SVE 等内嵌指令技术,深度优化指令编译和运行时库,发挥鲲鹏架构极致算力。AI 迭代调优:内置 AI 自学习模型,自动优化编译配置,迭代提升程序性能,完成最优编译。毕昇编译器特性架构图当前毕昇编译器已广泛应用于多种 HPC 典型场景,如气象、安防、流体力学等,性能优势已初步体现。其中,SPEC CPU 2017 benchmark 跑分平均优于 GCC 20%以上,HPC 典型气象应用 WRF 优于 GCC 10%。毕昇编译器与开源编译器SPEC CPU 2017 跑分对比毕昇编译器典型优化场景及其优化原理1 结构体内存布局优化—大幅提升缓存命中率,突破访存瓶颈SPEC CPU 2017 benchmark 中的 mcf 子项是对内存要求极高的应用,它是一款叫做MCF的大规模交通规划软件的核心代码。其瓶颈代码如下图左边所示。结构体优化原理示意图可见在 struct 中,data1 的使用率极高,而 data2 是不使用的。然而由于源代码中,数据的排布是以结构体数组的形式排布。按照一般编译器的编译方式,拿数据时每次都会将整个结构体放到 cache 里面,导致大量不参与计算的 data2 也被加载到了 cache 中,造成高速内存空间的浪费和性能的损耗。毕昇编译器会通过用户标记的结构体声明,或者通过自动检查循环中适合优化的内存场景,确认优化点。然后通过将结构体数组变为数组结构体的方式(如上图右),将有效数据紧凑排布,从而提高 cache 命中率和应用性能。经测试,此优化可以对 mcf 子项带来50%的性能提升。2 自动矢量化—计算效率提升的秘诀鲲鹏平台支持 Armv8 NEON 矢量化指令集。当前支持32个128位的矢量寄存器,指令可以同时操作4*32或2*64的数据。毕昇编译器依托这种硬件优势做了大量优化,包括 SLP(superword-level parallelism) 矢量化和循环自动矢量化。例如在 SPEC CPU 2017 benchmark 中处理视频流格式转换的x264子项中,毕昇编译器会自动识别并使用 uabd 和 udot 这类高效向量指令完成计算来替换标量指令,增大单时钟周期的数据处理量, 从而大幅提升计算效率。对于 x264 子项,这项优化可有效提升其30%的计算效率。 矢量化优化示例 3 Autotuner—基于机器学习快速获取最优编译配置如何获取性能最优编译选项是编译器使用中常见的问题,往往需要长时间的手动选项调优。为了减少这其中的工作量,使得用户能快速找到最优的优化选项,毕昇编译器自研了基于 ML 的自动搜索技术(ML-based Search) 的 Autotuner 工具。Autotuner 的调优流程由两个阶段组成:初始编译阶段(initial compilation)和调优阶段(tuning process),如下图所示:Autotuner 使用流程简单来说,在初始编译阶段,编译器会通过用户指定的调优方向,对可调优的代码区间进行标记。在随后的调优阶段,Autotuner 会根据搜索算法对不同的优化区间生成不同的编译配置。然后使用此配置编译运行,并根据运行性能的反馈来迭代优化配置参数。最后经过给定迭代次数后找出最优配置供用户使用。在实践过程中,通过 Autotuner 对 Coremark Benchmark 进行调优可以获取5%以上的收益。 以上介绍的三个优化特性分别是毕昇编译器在中前端算法优化、后端指令优化、迭代调优中最具代表性、在各自领域对性能提升表现最佳的三个特性。除以上介绍的三个优化特性之外,毕昇编译器在软件预取、循环优化、分支预测、指针压缩等编译优化技术均有探索且取得了显著的收益,详情可点击官网获取毕昇编译器详细信息,快来试试吧! 原文转载自 华为计算-【鲲鹏DevKit黑科技揭秘】┃ 毕昇编译器,让你的代码快到飞起!
-
什么是引用?在 PHP 中引用意味着用不同的名字访问同一个变量内容。它不是C的指针,保存的并不是内存地址,无法进行指针运算。引用只是符号表的别名。就像 Unix 系统中的硬链接, Windows 系统中的快捷方式。上面是官方手册中的原文,怎么说呢,引用其实和我们印象中的C里面的指针并不是相同的概念。指针是针对真实内存的操作,引用是针对指向这个内存的符号表的操作。还是从操作系统的快捷方式来说,快捷方式是可以删的,这就是PHP的引用。而C不仅删了快捷方式,还把原文件也给删了,这就是C的指针操作。// 引用不是指针 $a = 1; $b = &$a; echo $a, '===', $b, PHP_EOL; unset($b); echo $a, '===', $b, PHP_EOL;上面的代码是在PHP中,我们把b变量指向b变量指向a,作为a的引用变量。然后删除a的引用变量。然后删除b,对$a没有任何影响。#include <stdio.h> #include <stdlib.h> int main() { // C 中的指针和引用 int a = 1; int* b = &a; printf("%i\n", a); // 1 free(b); // free b printf("%i\n", a); //get error: *** error for object 0x7fff6350da08: pointer being freed was not allocated return 0; }而C中的引用指针就不行了,我们把b变量删掉后,再打印a变量就直接报错了。虽然说PHP的底层也是C写得,但我们都知道C中的指针是出了名的变态,没有一定的功底非常容易出错。所以PHP的开发者没有暴露C的原始指针能力,而是采用了和Java之类的类似的引用能力。这也是现代语言的特性,不需要我们过多的关注过于底层的能力,而将更多的时间放在业务实现上。引用在数组和对象中的使用如果具有引用的数组被拷贝,其值不会解除引用。对于数组传值给函数也是如此。$arr1 = ["a", "b"]; $t1 = &$arr1[1]; $arr2 = $arr1; $arr2[1] = "c"; var_dump($arr1); // array(2) { // [0]=> // string(1) "a" // [1]=> // &string(1) "c" // } $arr1 = ["a", "b"]; $t1 = &$arr1[1]; unset($t1); // unset 掉引用 $arr2 = $arr1; $arr2[1] = "c"; var_dump($arr1); // array(2) { // [0]=> // string(1) "a" // [1]=> // string(1) "b" // }这个其实挺有意思的,我们对比这两个例子可以看出一个问题,t变量指向t变量指向arr[1]的引用。arr2直接=这个arr2直接=这个arr1,没有使用引用,然后arr2修改了arr2修改了arr2[1]的内容,arr1相应的内容也发生了改变,如果unset掉arr1相应的内容也发生了改变,如果unset掉t变量,则$arr1相应的内容就不会发生改变。对此,我在文档中找到了下面的解释:由于PHP内部工作的特殊性,如果对数组的单个元素进行引用,然后复制数组,无论是通过赋值还是通过函数调用中的值传递,都会将引用复制为数组的一部分。这意味着对任一数组中任何此类元素的更改都将在另一个数组(和其他引用中)中重复,即使数组具有不同的作用域(例如,一个是函数内部的参数,另一个是全局的)!在复制时没有引用的元素,以及在复制数组后分配给其他元素的引用,将正常工作(即独立于其他数组)。不仅仅是数组,对象的引用也会有一些好玩的问题。$o1 = new stdClass(); $o1->a = 'a'; var_dump($o1); // object(stdClass)#1 (1) { // ["a"]=> // string(1) "a" // } $o2 = &$o1; $o3 = $o1; $o2->a = 'aa'; var_dump($o1); // object(stdClass)#1 (1) { // ["a"]=> // string(2) "aa" // } var_dump($o3); // $o2修改了$a为'aa',$o3也变成了'aa' // object(stdClass)#1 (1) { // ["a"]=> // string(2) "aa" // } $o1->a = 'aaa'; $o1 = null; var_dump($o2); // $o2引用变成了null // NULL var_dump($o3); // $o3不仅引用还存在,并且$a变成了'aaa' // object(stdClass)#1 (1) { // ["a"]=> // string(3) "aaa" // }上面例子中有三个对象,o1、o1、o2、o3,其中,o3,其中,o2是对o1的引用,o1的引用,o3是直接赋值为o1。对o1。对o2属性的操作不仅会反映在o1中,也会反映到o1中,也会反映到o3中。其实我们之前专门有一篇文章就讲的这个问题,首先对象默认赋值就是引用,其次这个例子很好地证明了引用就是一个符号表的绑定。删除了快捷方式对原始对象和其他快捷方式没有任何影响。引用的传递关于引用在方法参数上的传递,最重要的是记住两点:一是方法内部修改了变量外部也会变,这是引用的特性嘛;二是只能传递变量、New 语句、从函数中返回的引用三种类型。error_reporting(E_ALL); function foo(&$var) { $var++; echo 'foo:', $var; } function bar() // Note the missing & { $a = 5; return $a; } foo(bar()); // 自 PHP 5.0.5 起导致致命错误,自 PHP 5.1.1 起导致严格模式错误 // 自 PHP 7.0 起导致 notice 信息,Notice: Only variables should be passed by reference foo($a = 5); // 表达式,不是变量, Notice: Only variables should be passed by reference // foo(5); // 导致致命错误 !5是个常量! /////////////////////////////// // 正确的传递类型 $a = 5; foo($a); // 变量 function &baz() { $a = 5; return $a; } foo(baz()); // 从函数中返回的引用 function foo1(&$var) { print_r($var); } foo1(new stdClass()); // new 表达式引用的返回引用的返回并不是经常使用的一个能力。文档中的原文是:不要用返回引用来增加性能,引擎足够聪明来自己进行优化。仅在有合理的技术原因时才返回引用!$a = 1; function &test(){ global $a; return $a; } $b = &test($a); $b = 2; echo $a, PHP_EOL;当你想要返回一个引用变量的时候,一定要给方法定义和方法调用的时候都使用&符号。这个是需要注意的点。当其他地方修改原本的变量值或者返回的变量值经过修改后,都会影响到所有调用这个值的地方。所以说,引用的返回是比较危险的,因为你不清楚什么时候在什么地方这个值可能发生了修改,对于bug的排查会非常困难。引用的取消取消引用其实就是直接unset掉变量就可以了。但是一定要记住,PHP中的引用是指向的符号表,对原始真实的值是不起作用的,所以即使unset掉了最原始的那个变量,对其它引用赋值的变量也不会有影响!!$a = 1; $b = &$a; $c = &$b; $b = 2; echo '定义引用后:', $a, '===', $b, '===', $c, PHP_EOL; unset($b); $b = 3; echo '取消$b的引用,不影响$a、$c:', $a, '===', $b, '===', $c, PHP_EOL; $b = &$a; unset($a); echo '取消$a,不影响$b、$c:', $a, '===', $b, '===', $c, PHP_EOL; // 定义引用后:2===2===2 // 取消$b的引用:2===3===2 // 取消$a,不影响$c:===3===2 $a = 1; $b = & $a; $c = & $b; // $a, $b, $c reference the same content '1' $a = NULL; // All variables $a, $b or $c are unset echo '所有引用成空:', $a, '===', $b, '===', $c, PHP_EOL;
-
就是最近我做了一个机械臂 基本功能可以实现 现在有二个问题 希望大佬们给点思路:1:首先我用了小熊派和树莓派 树莓派识别物体的颜色形状 串口通信给小熊派 然后 机械臂完成动作 现在遇到一个问题(我的摄像头是单目)就是如何让机械臂能够自适应 简单来说就是 我在摄像头能够识别的范围内 任意放一个小木块 机械臂能够大概的准确去抓取 我的思路是 摄像头 与 目标物体 在同一水平面 然后 (opencv) 得到目标物体的中心点 通过中心点与画面的X轴 差值 来计算偏转角度 问题在于 这个角度如何求 想的是 对边比斜边 目标物体的实际长度 比上摄像头到目标物体的距离 得到的度数 转化成占空比 传给小熊派 大概思路是这样 就是说这个思路或者方法是否有问题 因为我得到的度数不稳定就是与实际度数有时候相符合有时候离谱 希望大佬能给一个其他的思路来解决 自适应的问题 或者如果思路准确 方法出了什么问题2 第二个问题是 我的机械臂是用16路舵机控制板驱动 我想的是如果让小熊派去驱动6个舵机 是否有足够大的电压带动6个舵机 如果能驱动外接电池是否可能烧坏小熊派 就是说机械臂应该交给16路舵机板来控制 还是小熊派来控制 因为我想的是 如果用小熊派驱动可能会更加方便主要是还是自适应的问题 希望大佬们给点思路
-
nblot模块如何移植到其他单片机上
-
小熊派的nblot 如何移植到其他的单片机上 例如树莓派想用nblot进行两个树莓派之间的远程通信
-
**本文转自:捷配电子工程师笔记** # 01 单片机执行指令 我们来思考一个问题,当我们在编程器中把一条指令写进单片机内部,然后取下单片机,单片机就可以执行这条指令。 那么这条指令一定保存在单片机的某个地方,并且这个地方在单片机掉电后依然可以保持这条指令不会丢失,这是个什么地方呢? 这个地方就是单片机内部的只读存储器即ROM(READ ONLY MEMORY)。 为什么称它为只读存储器呢?刚才我们不是明明把两个数字写进去了吗?原来在89C51中的ROM是一种电可擦除的ROM,称为FLASH ROM,刚才我们是用的编程器,在特殊的条件下由外部设备对ROM进行写的操作,在单片机正常工作条件下,只能从那面读,不能把数据写进去,所以我们还是把它称为ROM。 # 02 单片机数的本质和物理现象 我们知道,计算机可以进行数学运算,这令我们非常难以理解,它们只是一些电子元器件,怎么可以进行数学运算呢? 我们人类做数学题如37+45是这样做的,先在纸上写37,然后在下面写45,然后大脑运算最后写出结果,运算的原材料是37和45,结果是82都是写在纸上的,计算机中又是放在什么地方呢? 为了解决这个问题,先让我们做一个实验:这里有一盏灯,我们知道灯要么亮,要么不亮,就有两种状态,我们可以用‘0’和‘1’来代替这两种状态:规定亮为‘1’、不亮为‘0’。 现在放上三盏灯,一共有几种状态呢?我们列表来看一下:000 / 001 / 010 / 011 / 100 / 101 / 110 / 111。我们来看,这个000 / 001 / 101 不就是我们学过的的二进制数吗?本来,灯的亮和灭只是一种物理现象,可当我们把它们按一定的顺序排好后,灯的亮和灭就代表了数字了。 让我们再抽象一步,灯为什么会亮呢?是因为输出电路输出高电平,给灯通了电。因此,灯亮和灭就可以用电路的输出是高电平还是低电平来替代了。这样,数字就和电平的高、低联系上了。 # 03 单片机数位的含义 通过上面的实验我们已经知道:一盏灯亮或者说一根线的电平的高低,可以代表两种状态:0和1,实际上这就是一个二进制位。 因此我们就把一根线称之为一“位”,用BIT表示。 # 04 单片机字节的含义 一根线可以表示0和1,两根线可以表达00 / 01 / 10 / 11四种状态,也就是可以表达0~3,而三根可以表达0~7,计算机中通常用8根线放在一起,同时计数,就可以表示0~255一共256种状态。 这8根线或者8位就称之为一个字节(BYTE)。 # 05 单片机存储器的构造 存储器就是用来存放数据的地方。它是利用电平的高低来存放数据的,也就是说,它存放的实际上是电平的高、低,而不是我们所习惯认为的1234这样的数字,这样,我们的一个谜团就解开了。 一个存储器就象一个个的小抽屉,一个小抽屉里有八个小格子,每个小格子就是用来存放“电荷”的,电荷通过与它相连的电线传进来或释放掉。至于电荷在小格子里是怎样存的,就不用我们操心了,你可以把电线想象成水管,小格子里的电荷就象是水,那就好理解了。存储器中的每个小抽屉就是一个放数据的地方,我们称之为一个“单元”。 有了这么一个构造,我们就可以开始存放数据了,想要放进一个数据12,也就是00001100,我们只要把第二号和第三号小格子里存满电荷,而其它小格子里的电荷给放掉就行了。 可是问题出来了,一个存储器有好多单元,线是并联的,在放入电荷的时候,会将电荷放入所有的单元中,而释放电荷的时候,会把每个单元中的电荷都放掉。这样的话,不管存储器有多少个单元,都只能放同一个数,这当然不是我们所希望的。因此,要在结构上稍作变化。 需要在每个单元上有个控制线,想要把数据放进哪个单元,就把一个信号给这个单元的控制线,这个控制线就把开关打开,这样电荷就可以自由流动了。而其它单元控制线上没有信号,所以开关不打开,不会受到影响。 这样,只要控制不同单元的控制线,就可以向各单元写入不同的数据了。同样,如果要从某个单元中取数据,也只要打开相应的控制开关就行了。 # 06 单片机存储器的译码 那么,我们怎样来控制各个单元的控制线呢?这个还不简单,把每个单元的控制线都引到集成电路的外面不就行了吗? 事情可没那么简单,一片27512存储器中有65536个单元,把每根线都引出来,这个集成电路就得有6万多个脚?不行,怎么办?要想法减少线的数量。 有一种方法称这为译码,简单介绍一下:一根线可以代表2种状态,2根线可以代表4种状态,3根线可以代表8种,256种状态又需要几根线代表?8根线,所以65536种状态我们只需要16根线就可以代表了。 # 07 单片机存储器的选片概念 至此,译码的问题解决了,让我们再来关注另外一个问题。送入每个单元的八根线是用从什么地方来的呢?它就是从计算机上接过来的,一般地,这八根线除了接一个存储器之外,还要接其它的器件。 这样问题就出来了,这八根线既然不是存储器和计算机之间专用的,如果总是将某个单元接在这八根线上,就有问题出现了:比如这个存储器单元中的数值是0FFH另一个存储器的单元是00H,那么这根线到底是处于高电平,还是低电平?怎样分辨? 办法很简单,当外面的线接到集成电路的引脚进来后,不直接接到各单元去,中间再加一组开关就行了。平时我们让开关打开着,如果确实是要向这个存储器中写入数据,或要从存储器中读出数据,再让开关接通就行了。 这组开关由三根引线选择:读控制端、写控制端和片选端。要将数据写入片中,先选中该片,然后发出写信号,开关就合上了,并将传过来的数据(电荷)写入片中。如果要读,先选中该片,然后发出读信号,开关合上,数据就被送出去了。 读和写信号同时还接入到另一个存储器,但是由于片选端不同,所以虽有读或写信号,但没有片选信号,所以另一个存储器不会“误会”而开门,造成冲突。那么会不同时选中两片芯片呢? 只要是设计好的系统就不会,因为它是由计算控制的,而不是我们人来控制的,如果真的出现同时出现选中两片的情况,那就是电路出了故障了,这不在我们的讨论之列。 # 08 单片机的总线概念 从上面的介绍中我们已经看到,用来传递数据的八根线并不是专用的,而是很多器件大家共用的。 所以我们称之为数据总线,总线英文名为BUS,总即公交车道,谁也可以走。而十六根地址线也是连在一起的,称之为地址总线。 **本文转自:捷配电子工程师笔记**
-
1. 简介I2C (Inter-Integrated Circuit),是一种串行通信总线,用于连接微控制器及其外围设备,实现主控制器和从器件间的主从双向通信,是一种同步半双工通信(两端时钟频率一致,双向通信,但不能同时进行数据收发)。2. 原理I2C通信属于串行通信,具有两根串行信号线:数据线(SDA),时钟线(SCL)。如下图所示,主控制器与从器件(一个或多个)都通过两根信号线连接,信号线上主机和从机都可以扮演发送器和接收器的角色。为确保传输过程的指向准确性,每个接到I2C总线上的器件都有唯一的地址(7位从器件专用地址码),可实现制定从机的定向传输与群发传输。图1,I2C总线物理拓扑图2.1 信号类型同时,为确保传输稳定,所有连接在同一I2C总线上的设备共用一个时钟。I2C 总线在传送数据过程中共有以下几种类型信号:(1) 开始信号/结束信号 SCL 为高电平时,SDA 由高电平向低电平跳变,开始传送数据。 SCL 为高电平时,SDA 由低电平向高电平跳变,结束传送数据。 在这里插入图片描述在这里插入图片描述(2) 应答信号/非应答信号 IIC 总线协议规定,每传送一个字节数据后(8bit),都要有一个应答信号以确定数据传送是否被对方收到。即一个字节传输的8个时钟过后的第9个时钟期间,接收器必须回一个ACK应答信号给发送器,这样才能进行数据传输。 应答信号由接受设备产生,在SCL为高电平期间,接受设备将SDA拉低为低电平,表示数据传输正确,产生应答(ACK),SDA拉高则表示数据传输失败,产生非应答位(NACK)。 在这里插入图片描述(3) 闲置状态/被占用状态 在主机发送起始信号后,且未发送终止信号期间,总线处于被占用状态。 发送终止信号后,总线处于闲置状态,SCL与SDA同时为高电平。 在这里插入图片描述2.2 总线读写流程I2C总线进行数据传送时,SCL时钟信号为高电平期间,SDA数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高电平或低电平状态才允许变化。 当一个字节按数据位从高位到低位的顺序传输完后,紧接着从机将拉低SDA线,回传给主设备一个应答位ACK, 此时才认为一个字节真正的被传输完成 ,如果一段时间内没有收到从机的应答信号,则自动认为从机已正确接收到数据。I2c总线写通信过程: 主机在检测到总线空闲的状况下,首先发送一个START信号掌管总线; 发送一个地址字节(8 bit),其中bit0-6位为从机地址,存放从机唯一地址;bit7位为读写位(R/W),0表示write主机 ->从机,1表示read 从机->主机; 主机发送地址时,总线上每个从机都会将7位地址与自己的地址进行比较,若相同,则将匹配成功,发送应答信号(ACK),确定发送器和接收器; 主机收到ACK后开始发送第一个字节(Command),对应从机中要写入的寄存器; 从机接收到Command后,从机发送ACK; 主机收到ACK后开始发送第一个数据字节:bit0-7(8bit数据,高到低),从机收到数据后,发送应答ACK; 继续发送数据,n帧; 主控发送完全部数据后,发送一个停止位STOP,结束整个通讯并且释放总线; 图2,I2C总线写通信过程 I2c总线读通信过程: 主机产生START信号,随后发送从机地址(7bit)+0(Write); *方向仍然是写,待接收到从机发送的ACK应答后,配对成功。 主机接收到ACK后,发送8bit内存地址(Command对应从机相应寄存器地址),从机接收到后,内部寻址并提取数据,返回ACK; 主机接收到ACK后,重新产生START信号,再一次发送从机内存地址,(7bit)+1(Read),从机接收到后返回ACK; *方向设置为读,主机设置为接收模式 主机接收到ACK后,做好接收从机信息的准备,现在即可接收1bit的数据。 *主机不向从机发送应答信号,接收完毕后直接发起终止信号。 主机接收全部数据后,产生STOP信号,终止通信,总线变为闲置状态。
-
>前文:通过[自制小熊派扩展板——六轴传感器扩展板](https://bbs.huaweicloud.com/forum/forum.php?mod=viewthread&tid=121171),我们在小熊派上搭建了六轴传感器模块。 本文从C语言程序出发,获取三轴加速度数据、三轴陀螺仪数据。并根据原始数据求得真实数据 # 一、实验准备 ## 1.实验环境 - 小熊派开发板,以及MicroUSB数据线 - 已经安装STM32CubeMX - 已经安装KeilMDK,并导入stm32开发板对应的芯片包(小熊派使用的是STM32L431RCT6) - 如果不使用DMP,可以用杜邦线连接MPU6050  ---- ## 2.目标效果 - 通过CubeMX创建工程并配置参数 - IIC方式通信,配置MPU6050寄存器。 - 小熊派通过IIC,获取陀螺仪、加速度计数据。 - 对获取的原始数据进行分析,获取加速度、陀螺仪值。 - 串口1重定向输出加速度、陀螺仪值。 # 二、通过CubeMX生产MDK工程 ## A.芯片选择 - **打开CubeMX,进入芯片选择:**  - **选择自己的stm32芯片(即STM32L431RCT6):**  --- ## B.时钟源RCC设置 - **更改系统时钟源** >系统时钟默认使用内部的高速时钟(HSI),选择使用HSE,时钟更精确 - 设置外部时钟对应的端口  - 配置时钟树 >STM32L431RCT6系统时钟最大可以为80MHz,我们配置到最大即可  --- ## C.参数配置(对应端口设置) ### **1)配置USART1** 使用USART,模式为异步,波特率为115200,无硬件流控制 ----  ---- ### **2)硬件IIC配置** ``` IIC(Inter-Integrated Circuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构 ``` 我们使用小熊派的I2C1,小熊派引出的引脚为**PB7->I2C1_SDA,PB6->I2C1_SCL** 其他选项我们保持默认即可  ### 3)MPU6050模块 当然,我们还需要了解MPU6050模块的电路,更好的进行配置。当然我们也可以自主制作模块 **如果AD0脚(9脚)接地,IIC地址为0X68(不包含最低位);如果AD0脚接V3.3,则IIC地址为0X69(不包含最低位).**  **可以看到,AD0引脚已经被拉低,所有默认IIC地址为0x68. ** **最后,生成代码就OK了** ## D.工程设置 一些基础的设置,包括工程名、存储位置、工程环境、工程中各个文件的组成 ----  ----  ---- ## E.生成代码  ---- # 三、编写相应代码 ## 1. 串口1输出重定向 >我们知道printf是打印函数,原理是根据传入的字符串参数格式化打印输出到stdout中。我们需要让printf打印到串口之中,只需要在usart.c文件中模仿printf写一个输出函数即可 - 在添加头文件 ```c /* USER CODE BEGIN 0 */ #include <stdarg.h> #include <string.h> #include <stdio.h> /* USER CODE END 0 */ ``` - 写输出函数 ```c /* USER CODE BEGIN 1 */ void UsartPrintf(UART_HandleTypeDef *huart, char *fmt,...) { unsigned char UsartPrintfBuf[296]; va_list ap; unsigned char *pStr = UsartPrintfBuf; va_start(ap, fmt); vsprintf((char *)UsartPrintfBuf, fmt, ap); //格式化 va_end(ap); while(*pStr != 0) { USART1->TDR = *pStr++; while((USART1->ISR & 0x40) == 0); } } //注意:在usart.h中添加void UsartPrintf(UART_HandleTypeDef *huart, char *fmt,...); //使用方法:UsartPrintf(&huart1;,"hello world\r\n"); /* USER CODE END 1 */ ``` >注意:自己添加的代码,需要在begin和end之间 ## 2.写MPU6050驱动 >我们创建两个文件,分别是mpu6050.h和mpu6050.c ### a).首先我们在mpu6050.h中宏定义相应的寄存器,方便后续使用。 >因为寄存器实在太多,就没有一一列出,可以在附件中查看哦~  ### b).配置各个寄存器 >主要的函数为:IIC读写、初始化MPU6050、设置陀螺仪和加速度计满量程、设置采样率、读取数据 代码附件中有,不一一讲解。 **初始化函数** >初始化函数中,我们必须要保证IIC读写的正确,因此可以通过读某一个有确定值的寄出去,大致判断IIC通信的准确。此方法同样在SPI等通信协议时会使用到 ```c uint8_t MPUInit(void) { uint8_t res; extern I2C_HandleTypeDef hi2c1; HAL_I2C_Init(&hi2c1;); //初始化IIC /*上电后最好有一定延时,保证数据准确*/ HAL_Delay(500); MPU_Write_Byte(MPU_PWR_MGMT1_REG,0x80); //复位MPU6050,写入1000 0000 MPU_Write_Byte(MPU_PWR_MGMT1_REG,0x00);//sleep写入0,保持唤醒状态 MPU_Set_Gyro_Fsr(3); //陀螺仪满量程±2000 MPU_Set_Accel_Fsr(1); //加速度计满量程±4g MPU_Set_Rate(50); //设置采样率=50Hz MPU_Write_Byte(MPU_INT_EN_REG,0x00);//关闭所有中断 MPU_Write_Byte(MPU_USER_CTRL_REG,0x00); //关闭从iic MPU_Write_Byte(MPU_FIFO_EN_REG,0x00); //关闭FIFO MPU_Write_Byte(MPU_INTBP_CFG_REG,0x80); //INT引脚低电平有效 res = MPU_Read_Byte(MPU_DEVICE_ID_REG); //读取地址 UsartPrintf(&huart1;,"\r\nMPU6050:0x%2x\r\n",res); UsartPrintf(&huart1;,"\r\nMPU6050:0x%2x\r\n",MPU_ADDR); if(res == MPU_ADDR) //判断地址是否正确 { MPU_Write_Byte(MPU_PWR_MGMT1_REG,0x01); //001,pll,x轴为参考系统时钟源 MPU_Write_Byte(MPU_PWR_MGMT2_REG,0x00); //都不使用待机模式 MPU_Set_Rate(50); }else return 1; return 0; } ``` 需要注意到,mpu6050上电后需要有一定延时,保证数据的稳定。重启mpu6050会有睡眠模式,写入关闭睡眠。最后检测并判断IIC地址是否正确 。 我们需要注意,我们设置的**加速度满量程和陀螺仪满量程**,后期数据分析会用到 ## 3.数据处理 ### 3.1 数据处理 - 加速度计的三轴分量ACC_X、ACC_Y和ACC_Z均为16位有符号整数,分别表示器件在三个轴向上的加速度,取负值时加速度沿座标轴负向,取正值时沿正向。 三个加速度分量均以**重力加速度g的倍数为单位**,能够表示的加速度范围,即倍率可以统一设定,有4个可选倍率:2g、4g、8g、16g。 - 以ACC_X为例,若倍率设定为2g(默认),则意味着ACC_X取最小值-32768时,当前加速度为沿X轴正方向2倍的重力加速度;若设定为4g,取-32768时表示沿X轴正方向4倍的重力加速度,以此类推。显然,倍率越低精度越好,倍率越高表示的范围越大,这要根据具体的应用来设定。 从前面初始化中,我们设置的倍率为2g,真实的加速度值ACC_Ture = ACC_X / 32767 / 2(精度),ACC_X为读取的数据。 同时,陀螺仪数据的处理也相同。 ### 3.2 main函数 >注意添加.h文件哦 ```c /* USER CODE BEGIN PV */ short aacx,aacy,aacz; //加速度传感器原始数据 short gyrox,gyroy,gyroz; //陀螺仪原始数据 char Mpu6050Data[40]; /* USER CODE END PV */ ``` ```c /* USER CODE BEGIN 2 */ MPUInit(); /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ MPU_Get_Accelerometer(&aacx,&aacy,&aacz); //得到加速度传感器数据 MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz); //得到陀螺仪数据 memset(Mpu6050Data,0,sizeof(Mpu6050Data)); sprintf(Mpu6050Data,"%.2f,%.2f,%.2f,%.2f,%.2f,%.2f\n",aacx/8200.0,aacy/8200.0,aacz/8200.0,gyrox/16.38,gyroy/16.38,gyroz/16.38); /* USER CODE BEGIN 3 */ } ``` Notes: - Mpu6050Data数据用于保存采集的数据。 - 加速度的满量程初始化设置的为±4g。 因此 实际数据 = 获取的数据 / (32767 / 4) ≈ 获取的数据/ 8200.0 - 陀螺仪的满量程初始化设置的为±2000g. 因此 实际数据 = 获取的数据 / (32767 / 2000) ≈ 获取的数据/ 16.38 # 四、编译+下载 **点击编译后,0 error,0 warning** ----  **小熊派连接在电脑上,代码下载到开发板**  ---- # 五、连接硬件 ## 1.将小熊派串口1和电脑相连,即拨到 AT-MUC,按下复位键  ## 2.连接MPU6050 将我们的“扩展板”插在小熊派上。 或者使用杜邦线连接mpu6050的SDA\SCL\GND\VCC。 即: - SDA-->PB7 - SCL-->PB6 - GND-->GND - VCC-->5V ---- ## 3.效果 打开串口调试助手,我们手动转动开发板(包括模块),看见陀螺仪和加速度数据不断变化,当静止时数据保持稳定 。  可以看到,开发板静止时,xy轴的加速度几乎为零。而Z轴受重力加速度影响,加速度为1g. **至此,我们已经可以通过小熊派以IIC获取六轴传感器原始数据信息**
-
【功能模块】【操作步骤&问题现象】1、CAN1、CAN2使用125k波特率,核心板应用层 按照10ms间隔频率,发送30000笔长度为8的can数据包;2、扩展单片机的CAN口外接CAN盒,CAN盒展示到的can数据包只有28000个左右;3、在扩展单片机CAN驱动接口做断点调试,显示扩展单片机 获取到的 CAN数据包数量 与 CAN盒展示数据包量一致;4、CAN盒接收到 包与包之间时间范围为20-40ms;5、CAN1、CAN2使用125k波特率,核心板应用层 按照30ms间隔频率,发送30000笔长度为8的can数据包,CAN盒与断点都显示无丢包情况;6、扩展单片机不接核心板,单外接CAN盒,扩展单片机CAN1、CAN2形成回路, 按照10ms间隔频率 发送接收50000笔长度为8的can数据包,CAN盒显示无丢包情况,断点调试接收包数量也显示正常;【截图信息】数据包最后两字节0x75 0x30 -- 》0x7530是核心板发送的CAN数据包数量CAN盒与扩展单片机接线如图很短【日志信息】(可选,上传日志内容或者附件)请专家给与解答……
-
编译(compile)是指将代码某一种语言转化为另一种语言,如机器码,java的字节码,甚至c代码(flex/bison)。解释(interpret)是指将按照代码所表达的逻辑进行特定的操作。编译器是指专门用来进行编译这一动作的程序或组件。解释器是指专门用来进行解释这一动作的程序或组件。从编译的行为我们会发现这通常是一个一次性的行为(有特殊情况,比如glsl,比如有JIT功能的解释器),所以并没有关闭编译器这一说法(硬要说的话是指当编译器正在编译的时候,杀掉编译器这个进程)。你在F12中打开的调试界面中会发现网页的代码主要是有3种:html、js和css。简单的说,html提供了网页的骨架,js提供了网页的交互,css提供了网页的外貌。理论上如果浏览器足够模块化,是可以禁用js或者css或者html,但是我所了解的这几乎没有意义。html、js、css由浏览器内部的解释组件解释运行,并不会将其转化为其他某种语言,因此没有它们的编译组件。前端的组成多为这3种代码。但后端可以非常多样。对于cgi来说,其既可以是c、c++、java的程序、也可以是php、python、js(nodejs)的脚本。服务器有若干条规则告诉它对于不同的文件应该如何处理,比如程序就执行,脚本就调用相应的程序解释(也可能由服务器直接解释)。注意这里的服务器完全可以在内部建立处理请求的方法(比如由nodejs中的express直接搭建的服务器),在这种情况下我们可以认为是服务器直接解释了脚本(脚本和服务器写在一起了)。一个常见的网络请求的通俗流程如下:浏览器向服务器发送请求服务器调用一个cgi程序/脚本服务器将其输出返回给浏览器浏览器显示(html/css)运行(js)而禁用某个解释器会导致第2步无法进行。注意这里的禁用其实是指去禁止服务器处理这类脚本的方法(比如删掉了处理php文件的规则,导致由php构建的网页失效),导致服务器无法处理请求。转自:https://www.zhihu.com/question/368003317/answer/987083150
-
【功能模块】模块是移远BC35G,移动NB卡,APN是CMNBIOT【操作步骤&问题现象】目前在做设备的低功耗,需要发送完数据后立即进入PSM模式,但是配置后无效,研究多天无果,希望好心人帮帮我我的操作方法如下,设备上电后自动入网,可以看到返回+QLWEVTIND:0+QLWEVTIND:3返回的3表示已经注网AT+NMGS=8,32332E3033342E30 // 发送数据OK,AT+CPSMS=1,,,01000001,00000001, //配置PSM参数OKAT+CPSMS?+CPSMS:1,,,01000001,00000001 //查询PSM参数OKAT+CEREG=5 OKAT+CEREG?+CEREG:5,1,3A13,0DB9AD20,9,,,,OK这条命令后面的几个参数都是逗号,返回值空,这是T3324和T3412的值,是配置PSM的关键,为什么我的查询返回的看不到,而且配置后模组的电流图没有任何变化,重启也没用
-
鲲鹏服务器之ARM探知鲲鹏弹性云服务器高可用性架构思维导图什么叫arm架构 ARM架构过去称作进阶精简指令集机器(Advanced RISC Machine,更早称作:Acorn RISC Machine),是一个32位精简指令集(RISC)处理器架构,其广泛地使用在许多嵌入式系统设计。由于节能的特点,ARM处理器非常适用于移动通讯领域,符合其主要设计目标为低耗电的特性。 在今日,ARM家族占了所有32位嵌入式处理器75%的比例,使它成为占全世界最多数的32位架构之一。ARM处理器可以在很多消费性电子产品上看到,从可携式装置(PDA、移动电话、多媒体播放器、掌上型电子游戏,和计算机)到电脑外设(硬盘、桌上型路由器)甚至在导弹的弹载计算机等军用设施中都有他的存在。在此还有一些基于ARM设计的派生产品,重要产品还包括Marvell的XScale架构和德州仪器的OMAP系列。 ARM架构图 下图所示的是ARM构架图。它由32位ALU、若干个32位通用寄存器以及状态寄存器、32&TImes;8位乘法器、32&TImes;32位桶形移位寄存器、指令译码以及控制逻辑、指令流水线和数据/地址寄存器组成。 1、ALU:它有两个操作数锁存器、加法器、逻辑功能、结果以及零检测逻辑构成。 2、桶形移位寄存器:ARM采用了32&TImes;32位的桶形移位寄存器,这样可以使在左移/右移n位、环移n位和算术右移n位等都可以一次完成。 3、高速乘法器:乘法器一般采用“加一移位”的方法来实现乘法。ARM为了提高运算速度,则采用两位乘法的方法,根据乘数的2位来实现“加一移位”运算;ARM高速乘法器采用32&TImes;8位的结构,这样,可以降低集成度(其相应芯片面积不到并行乘法器的1/3)。 4、浮点部件:浮点部件是作为选件供ARM构架使用。FPA10浮点加速器是作为协处理方式与ARM相连,并通过协处理指令的解释来执行。 5、控制器:ARM的控制器采用的是硬接线的可编程逻辑阵列PLA。 6、寄存器 x86架构 目前的PC架构绝大多数都是Intel的X86架构,貌似也是因为INTEL的这个X86架构早就了目前INTEL如日中天的地位。X86架构(The X86 architecture)是微处理器执行的计算机语言指令集,指一个intel通用计算机系列的标准编号缩写,也标识一套通用的计算机指令集合。 当然,这个架构图并不是所有的都是如此,根据不同的主板,平台,架构是略有差别的比如说,目前很多主板已经将北桥集成到CPU当中,将南桥集成为PCH,但大致的框架还是如此的。下面对这个架构图上的各个内容分别进行一些简介。 1:CPU,大家都不陌生的名词,中央处理器,计算机的核心大脑。 2: 北桥(North Bridge Chipset):北桥是电脑主板上的一块芯片,位于CPU插座边,起连接作用。 3:南桥芯片(South Bridge)是主板芯片组的重要组成部分,一般位于主板上离CPU插槽较远的下方,PCI插槽的附近,这种布局是考虑到它所连接的I/O总线较多,离处理器远一点有利于布线。 4: 内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。计算机中所有程序的运行都是在内存中进行的,因此内存的性能对计算机的影响非常大。 5:显卡(Video card,Graphics card)全称显示接口卡,又称显示适配器,是计算机最基本配置、最重要的配件之一。 6:显示j接口 7:网卡是工作在链路层的网络组件,是局域网中连接计算机和传输介质的接口,不仅能实现与局域网传输介质之间的物理连接和电信号匹配,还涉及帧的发送与接收、帧的封装与拆封、介质访问控制、数据的编码与解码以及数据缓存的功能等。 8:声卡的基本功能是把来自话筒、磁带、光盘的原始声音信号加以转换,输出到耳机、扬声器、扩音机、录音机等声响设备,或通过音乐设备数字接口(MIDI)使乐器发出美妙的声音。 9:SATA(Serial Advanced Technology Attachment,串行高级技术附件)是一种基于行业标准的串行硬件驱动器接口,是由Intel、IBM、Dell、APT、Maxtor和Seagate公司共同提出的硬盘接口规范。 10:硬盘是电脑主要的存储媒介之一,由一个或者多个铝制或者玻璃制的碟片组成。碟片外覆盖有铁磁性材料。 11:总线 arm架构和x86架构有什么区别 一、性能 X86结构的电脑无论如何都比ARM结构的系统在性能方面要快得多、强得多。X86的CPU随便就是1G以上、双核、四核大行其道,通常使用45nm(甚至更高级)制程的工艺进行生产;而ARM方面:CPU通常是几百兆,最近才出现1G左右的CPU,制程通常使用不到65nm制程的工艺,可以说在性能和生产工艺方面ARM根本不是X86结构系统的对手。 但ARM的优势不在于性能强大而在于效率,ARM采用RISC流水线指令集,在完成综合性工作方面根本就处于劣势,而在一些任务相对固定的应用场合其优势就能发挥得淋漓尽致。 二、扩展能力 X86结构的电脑采用“桥”的方式与扩展设备(如:硬盘、内存等)进行连接,而且x86结构的电脑出现了近30年,其配套扩展的设备种类多、价格也比较便宜,所以x86结构的电脑能很容易进行性能扩展,如增加内存、硬盘等。 ARM结构的电脑是通过专用的数据接口使CPU与数据存储设备进行连接,所以ARM的存储、内存等性能扩展难以进行(一般在产品设计时已经定好其内存及数据存储的容量),所以采用ARM结构的系统,一般不考虑扩展。基本奉行“够用就好”的原则。 三、操作系统的兼容性 X86系统由微软及Intel构建的Wintel联盟一统天下,垄断了个人电脑操作系统近30年,形成巨大的用户群,也深深固化了众多用户的使用习惯,同时x86系统在硬件和软件开发方面已经形成统一的标准,几乎所有x86硬件平台都可以直接使用微软的视窗系统及现在流行的几乎所有工具软件,所以x86系统在兼容性方面具有无可比拟的优势。 ARM系统几乎都采用Linux的操作系统,而且几乎所有的硬件系统都要单独构建自己的系统,与其他系统不能兼容,这也导致其应用软件不能方便移植,这一点一直严重制约了ARM系统的发展和应用。GOOGLE开发了开放式的Android系统后,统一了ARM结构电脑的操作系统,使新推出基于ARM结构的电脑系统有了统一的、开放式的、免费的操作系统,为ARM的发展提供了强大的支持和动力。 四、软件开发的方便性及可使用工具的多样性 X86结构的系统推出已经近30年,在此期间,x86电脑经过飞速发展的黄金时期,用户的应用、软件配套、软件开发工具的配套及兼容等工作,已经到达非常成熟甚至可以说是完美的境界。所以使用X86电脑系统不仅有大量的第三方软件可供选择,也有大量的软件编程工具可以帮助您完成您所希望完成的工作。 Arm结构的电脑系统因为硬件性能的制约、操作系统的精简、以及系统兼容等问题的制约,造成Arm结构的电脑系统不可能像X86电脑系统那样有众多的编程工具和第三方软件可供选择及使用,ARM的编程语言大多采用C和JAVA。 对这一点的比较,更直接的结论是:基于x86结构电脑系统平台开发软件比arm结构系统更容易、更简单、实际成本也更低,同时更容易找到第三方软件(免去自己开发的时间和成本),而且软件移植更容易。 从以上对比分析,给了我们的一个很清晰的感觉,ARM和X86结构的电脑根本就无法对比,ARM根本就不是X86电脑的的对手。是的,如果只考虑上述几个方面的要数,ARM确实无法与X86电脑竞争,甚至连比较的资格都没有。但是近1、2年,ARM的产品在终端应用特别是手持终端应用飞速发展(如:智能手机、平板电脑等),其销售数量已经远远超出x86结构的电脑销售数量,可见ARM是具有其与X86结构电脑不可对比的优势。该优势就是:功耗。 五、功耗X86电脑因考虑要适应各种应用的需求,其发展思路是:性能+速度。20多年来x86电脑的速度从原来8088的几M发展到现在随便就是几G,而且还是几核,其速度和性能已经提升了千、万倍,技术进步使x86电脑成为大众生活中不可缺少的一部分。但是x86电脑发展的方向和模式,使其功耗一直居高不下,一台电脑随便就是几百瓦,即使是号称低功耗节能的手提电脑或上网本,也有十几、二十多瓦的功耗,这与ARM结构的电脑就无法相比。 ARM特点(1)ARM指令都是32位定长的(2)寄存器数量丰富(37个寄存器)(3)普通的Load/Store指令(4)多寄存器的Load/Store指令(5)指令的条件执行(6)单时钟周期中的单条指令完成数据移位操作和ALU操作(7)通过变种和协处理器来扩展ARM处理器的功能(8)扩展了16位的Thumb指令来提高代码密度ARM作为RISC微处理器与CISC微处理器技术对比如下:ARM处理器工作模式(1)用户模式(usr,User Mode):ARM处理器正常的程序执行状态。(2)快速中断模式(fiq,Fast Interrupt Request Mode):用于高速数据传输或通道处理。当触发快速中断时进入此模式。(3)外部中断模式(irq,Interrupt Request Mode):用于通用的中断处理。当触发外部中断时进入此模式。(4)管理模式(svc,Supervisor Mode):操作系统使用的保护模式。在系统复位或执行软件中断指令SWI时进入。(5)数据访问中止模式(abt,Abort Mode):当数据或指令预取中止时进入该模式,可用于虚拟存储及存储保护。(6)系统模式(sys,System Mode):运行具有特权的操作系统任务。(7)未定义指令中止模式(und,Undefined Mode):当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。除了用户模式之外,其余六种模式都是特权模式。除了用户模式和系统模式之外,其余五种模式都是异常模式。在特权模式下程序可以访问所有的系统资源。非特权模式和特权模式之间的区别在于有些操作只能在特权模式下才被允许,例如直接改变模式和中断使能等。而且为了保证数据安全,一般MMU会对地址空间进行划分,只有特权模式才能访问所有的地址空间。而用户模式如果需要访问硬件,必须切换到特权模式。ARM处理器型号ARM Contex-A系列: 开放式操作系统的高性能处理器Cortex-A应用程序处理器(Application Processors)在高级工艺节点中可实现高2GHz+ 标准频率的卓越性能, 从而可支持下一代的移动 Internet 设备. 这些处理器具有单核和多核种类, 最多提供四个具有可选NEON多媒体处理模块和高级浮点执行单元的处理单元. 应用包括智能手机, 智能本和上网本, 电子阅读器, 数字电视, 家用网络, 家用网关和其他各种产品.ARM Contex-R系列: 面向实时应用的卓越性能Cortex-R系列处理器的开发则面向深层嵌入式实时应用(Embedded Real-time Applications Processors)对低功耗, 良好的中断行为, 卓越性能以及与现有平台的高兼容性这些需求进行了平衡考虑. 应用领域有汽车制动系统, 动力传输解决方案, 大容量存储控制器, 联网和打印机等.ARM Cortex-M系列: 面向具有确定性的微控制器应用的成本敏感型解决方案Cortex-M系列处理器(Embedded Microcontroller Processors)主要是针对微控制器领域开发的, 在该领域中, 既需进行快速且具有高确定性的中断管理, 又需将门数和可能功耗控制在最低. 应用领域有微控制器, 混合信号设备, 智能传感器, 汽车电子和气囊等.ARM未来浅谈稳步发展1990 年11 月27 日,苹果出资了150 万英镑,Acorn 本身则以150 万英镑的知识产权和12 名芯片工程师技术入股,另一个芯片厂商VLSI 出资25 万英镑。Acorn 公司正式被改组为ARM计算机公司,英文名是Advanced RISC Machines。在成立后的那几年,ARM业绩平平,工程师们也人心惶惶,害怕随时都会失业。于是ARM决定改变他们的产品策略——他们不再生产芯片,转而以授权的方式,将芯片设计方案转让给其他公司,即“Partnership”开放模式。所以,授权费和版税就成了ARM的主要收入来源。除此之外,就是软件工具和技术支持服务的收入。正是ARM的这种授权模式,极大地降低了自身的研发成本和研发风险。它以风险共担、利益共享的模式,形成了一个以ARM为核心的生态圈,使得低成本创新成为可能。1991年,ARM将产品授权给英国GEC Plessey半导体公司。1993年,ARM将产品授权给Cirrus Logic和德州仪器(Texas Instruments,TI)。与德州仪器的合作,给ARM公司带来了重要的突破。而且,也给ARM公司树立了声誉,证实了授权模式的可行性。此后ARM的目标一直没有改变,着重生产体积小、能耗低的芯片,并打造一个庞大而多样的生态系统。并且不遗余力地与其他企业结盟。越来越多的公司参与到这种授权模式中,与ARM建立了合作关系,包括苹果、高通、三星电子等等。抓住机遇,起飞1994年,ARM迎来了自己的黄金机遇——移动电话时代来临了。诺基亚被建议在即将推出的GSM手机上应用TI的基于ARM的系统设计。考虑到内存空间,Nokia反对使用ARM,因生产的总体系统成本有限。于是ARM专门开发出16位的定制指令集,缩减了占用的内存空间。该设计由TI授权并出售给诺基亚。诺基亚6110是第一部采用ARM处理器的GSM手机,上市后获得了极大的成功。ARM7成为了ARM的旗舰移动设计,此后被授权给超过165家公司。自1994年以来这些公司生产了超过100亿个芯片。在这一波浪潮中,ARM是赚得盆满钵满。1998年4月17日,业务飞速发展的ARM控股公司,同时在伦敦证交所和纳斯达克上市。2007年,在乔帮主的带领下,真正的划时代产品出现了,iphone 发布了。第一代iPhone,就是使用了ARM设计、三星制造的芯片。事实上,Intel曾有机会拿下iPhone。在iPhone诞生之前,苹果就和Intel达成战略合作关系,并把Intel处理器应用于苹果电脑。苹果也有意委托Intel开发iPhone的处理器。只是Intel的内部并不看好iPhone,担心收不回投资成本。又一次,ARM的开放战胜了Intel式的封闭。2008年,谷歌推出了Android(安卓)系统,也是基于ARM指令集。谷歌的加入,刺激出一众安卓手机厂商。寻求快速迭代的安卓厂商很自然地选用开放的ARM处理器。手机市场的狂飙让Intel人心不稳。苹果又一次补刀,在平板电脑iPad上再次跳过Intel,使用了ARM处理器。2016年7月18日,曾经投资阿里巴巴的孙正义和他的日本软银集团,以243亿英镑(约309亿美元)收购了ARM集团。总结可以看到ARM创业初期还是比较惨的,一直蛰伏着,等待时机成熟之后就一发不可收拾了。其实Intel也是有好几次能抓住这个机会的,但是Intel 这么多年习惯的模式是生产制造几十、几百美元的处理器,在这个价位上的生产制造毛利率高得吓人。而正是丰厚的毛利率使得 Intel 敢于付出高昂的代价研发下一代处理器技术和生产线制程,从而保持领先竞争对手至少一个代际的技术优势。比如当 Intel 的主流 Core 系列的制程是 22nm,同时期的 ARM 还处于 40nm 到 32nm 或者 32nm 到 28nm 的过渡阶段,而 Intel 已经在新建 14nm 的生产线了。反观一片 ARM 处理器才卖几美元,利润率微薄,即便出货量大不少,却也不能满足 Intel 这样的巨鳄的胃口,更不能让它保持目前的「高研发/高毛利相互驱动」的商业模式。不玩自家的游戏规则,Intel 沦为二三流厂商那是分分钟可能发生的危险。Intel 管理层不希望看到这个未来,Intel 的股东们更不希望。现在ARM主攻在移动和嵌入式市场,而Intel则主攻桌面和服务器市场,但是双方都有进入对方领域的想法和动作,看来这一场仗是迟早的事了。
-
时钟分频控制SCK线的时钟信号,由波特率发生器根据“控制寄存器 CR1”中的BR[0:2]位控制对 fpclk 时钟的分频因子,对 fpclk 的分频结果就是 SCK 引脚的输出时钟频率, fpclk频率是指 SPI 所在的 APB 总线频率,APB1 为 fpclk1,APB2 为 fpckl2。3.数据控制逻辑SPI 的 MOSI 及 MISO 都连接到数据移位寄存器上,数据移位寄存器的数据来源及目标接收、发送缓冲区以及 MISO、MOSI 线。当向外发送数据的时候,数据移位寄存器以“发送缓冲区”为数据源,把数据一位一位地通过数据线发送出去;当从外部接收数据的时候,数据移位寄存器把数据线采样到的数据一位一位地存储到“接收缓冲区”中。 通过写 SPI的“数据寄存器 DR”把数据填充到发送 F 缓冲区中,通讯读“数据寄存器 DR”,可以获取接收缓冲区中的内容数据帧长度可以通过“控制寄存器 CR1”的“DFF 位”配置成 8 位及 16 位模式;配置“LSBFIRST 位”可选择 MSB 先行还是 LSB 先行 4.整体控制逻辑整体控制逻辑负责协调整个 SPI 外设,控制逻辑的工作模式根据我们配置的“控制寄存器(CR1/CR2)”的参数而改变,基本的控制参数包括前面提到的 SPI 模式、波特率、LSB先行、主从模式、单双向模式等等。在外设工作时,控制逻辑会根据外设的工作状态修改“状态寄存器(SR)”,我们只要读取状态寄存器相关的寄存器位,就可以了解 SPI 的工作状态了。除此之外,控制逻辑还根据要求,负责控制产生 SPI 中断信号、DMA 请求及控制NSS 信号线。应用注意:实际应用中,我们一般不使用 STM32 SPI 外设的标准 NSS 信号线,而是更简单地使用普通的 GPIO,软件控制它的电平输出,从而产生通讯起始和停止信号
-
导读:精准测试是一个软件测试界最新的测试技术,它的高效与精准性为使用者所称赞,但如果公司已经有了一些开发测试管理系统,如何最大成本减少学习成本,悄无声息的进行“精准测试”技术的升级改造?本文以Jira系统为例,给出了详实可信的技术解决方案。 精准测试是目前系统级测试的一匹黑马,它比白盒测试使用起来简单,但功能更强大,普通黑盒测试工程师也能轻松掌握。另外,使用它的同时,由于测试数据收集的细致与完整性,也为用户带来一个极具价值的战略性资源--测试大数据,因此很多企业非常重视精准测试对本单位软件系统测试技术的升级作用。精准测试最核心的技术关键就是:用例和相关执行代码之间有很强的对应和追溯关系。这个强追溯关系的建立,通过精准测试专属客户端上的“软件示波器“,用人工点击开始和结束按钮来标记测试用例的执行,进而确定对应代码执行路径的边界。但是,目前很多公司内部都有开发测试管理系统或者类似于JIRA这样的通用产品来管理和执行用例,如果同步使用精准测试客户端,则有指令重复之嫌。因此,星云精准测试做了具有深远意义的客户化改进-“静默式“精准测试。它可平滑实现JIRA系统与精准测试的幕后对接方案:JIRA中的用例执行指令从后台直接传递给精准系统,测试工程师不用改变任何日常工作行为。这一里程碑式的改进办法,使得几乎全部依赖人工、数据不可见的黑盒测试,突破天花板成为具备系统质量分析高度可视化的有力抓手。实现了企业在“不知不觉中”彻底提高黑盒测试整体效能的大目标。“静默式“精准测试的创新,使系统内部可智能获取精准测试的基础数据,完成测试用例与代码覆盖的追溯关系建立。下图是精准测试(星云测试www.teststars.cc 的ThreadingTest产品系列)与JIRA系统对接的架构示意图: 现在,就“静默式“精准测试的技术原理做进一步解析阐述:由于JIRA的前端基于velocity模板技术开发,它本身也在不断升级迭代,为避免对JIRA本身运行系统造成干扰,我们采用了替换VM模版的技术方案,即通过JIRA前端页面,将用例执行数据发送给星云TT系统。对接采用异步方式,在TT后台服务链路不开启的情况下也不影响JIRA本身的运行,完全实现高靠性、静默、零干扰的精准测试目标。第一步:JIRA端定制代码将当前执行的测试用例名称,用户名,以及项目名称传递给一个对接中转平台,对接中转平台将数据转换为TTFront可识别的命令发送给TTFront,TTFront收到命令以后,会根据指令中的用户信息,得到对应用户所登录的客户端的IP地址(星云TT系统中用户登录后,其IP会自动记录在TTfront端)。第二步:将对应的命令分发到对应的用户,组织成TTC命令结构方式发送(属于TT精准测试的客户端自动化指令集),触发客户端直接执行相关操作(包括用例的自动创建),例如点击用例开始等动作。当用例开启后,便可以全自动实现原有精准测试的手动操作流程。由于程序版本和星云精准测试生成的版本需要有一个对应关系,以前是由客户端由测试人员手动选择,在静默模式下,通过活动版本的设置,自动加载版本。用例将自动在星云TT系统中创建,无需导入和同步等二次动作。Jira与星云精准测试对接的步骤展示:1) 未开始测试界面的状态:星云测试的软件示波器缩略会显示在界面上,在没有开启和执行用例之前示波器实时采集覆盖率的状态值均为0。2) 开始用例并进行数据结束:当开始执行用例后,通过JIRA 与TT系统的对接,TT系统自动创建了用例,并且处于等待数据接收状态,当用户在JIRA系统选择好要执行的用例,并到被测试系统实际执行用例时,安装在客户端的示波器浮动窗就会开始显示进行对应用例的覆盖率采集。浮动窗会默认显示在测试人员桌面的最前方,半透明的模式不会对被测试应用产生遮挡。3) 示波器数据接收展示:打开星云软件示波器窗口,可以看到示波器接收数据的波形已经创建好,当前选择的测试用例的所有信息已接收清晰而完整。 由此可以看出,使用者不用在“星云客户端”上实施任何操作,即可实现精准测试数据的静默式记录、传输与分析。星云测试“静默式精准测试“技术的发布,为各领域实现企业级精准测试技术改造和能力提升,打下坚实基础。
推荐直播
-
华为云码道 × 仓颉编程:工程化AI编码探索2026/05/27 周三 19:00-21:00
刘俊杰-华为云仓颉语言专家/李炎-华为云码道技术专家/王智鹏-OpenCangjie开源社区发起人
本场直播围绕华为云仓颉语言与华为云码道的深度结合,展示华为云智能编程从零基础到高效落地的完整生态能力。以华为云码道为引擎,仓颉语言为载体,带给大家日常提效、趣味创新到极速量产的开发体验。
回顾中
热门标签