嵌入式分享合集156

一、某简洁易用的STM32嵌入式操作系统内核

  现在,嵌入式操作系统已经越来越多了,如大家都熟知的uCOS、FreeRTOS、RT-Thread等。这些操作系统都各有各的特点

    本篇笔记再来给大家介绍一个简洁易用的嵌入式操作系统内核 —— KLite。

KLite源码

    源码链接:https://gitee.com/kerndev/klite

    KLite的作者是jiangxiaogang。

KLite简介

    KLite以MIT协议开放源代码。它是一款入门级的小型抢占式操作系统内核,以简洁易用为设计目标,旨在降低学习嵌入式操作系统编程和入门的难度。

    简洁的API风格,简洁的调用方式,简单的移植方法,可能是目前最简单易用的嵌入式操作系统内核。

  • 支持优先级抢占

  • 支持相同优先级的线程

  • 支持线程同步互斥

  • 支持动态内存管理

  • 支持多编译器GCC, IAR, MDK

KLite移植

    KLite目前已经为ARM Cortex-M0/M3/M4做好了底层适配,如果你的CPU平台是基于以上平台的,如STM32,GD32,NRF51,NRF52,Freescale K40等系列单片机,那么可以直接使用预编译的库文件进行开发。

    只需要修改template.c里面几个简单的函数即可开始编程。否则可能需要自行移植CPU底层的汇编代码。

KLite使用

1、KLite编译

    在build目录下面有预设的工程文件,选择你要使用的编译器和目标CPU平台,  编译完成后,会生成kernel.lib文件,将kernel.lib,kernel.h,emplate.c复制到你的项目源码中,使用lib文件可以减少重复编译时间,当然你也可以选择把全部源码添加到你的工程中。

2、修改template.c

    根据目标CPU的编程手册,实现template.c里面的2个空函数。

void cpu_sys_init(void);

    这个函数被kernel_init调用,为用户提供一个接口,用于实现那些必须在系统初始化之前的准备工作,例如初始化CPU的时钟,设置FLASH等。

void cpu_sys_idle(uint32_t time);

    这个函数被kernel_idle调用,为用户提供一个接口,用于实现系统休眠.例如调用WFI指令,或者什么都不做。

void SysTick_Handler(void);

    这个函数是平台相关的滴答时钟中断函数,需要在滴答时钟中断中调用kernel_tick(n),n表示一次中断的毫秒数。

3、在main函数里面添加初始化代码

    main函数的推荐写法如下:

//只需要包含这一个头文件即可
#include "kernel.h"

//用于初始化应用程序的线程
void init(void *arg)
{

}

//空闲线程,只需调用kernel_idle即可
void idle(void *arg)
{
    kernel_idle();
}

//C语言程序入口
void main(void)
{
    static uint8_t heap[HEAP_SIZE];
    kernel_init((uint32_t)heap, HEAP_SIZE);
    thread_create(init, 0, 0);
    thread_create(idle, 0, 0);
    kernel_start();
}

    说明:

  • kernel_init 用于初始化内核;

  • thread_create 创建主线程init和idle;

  • kernel_start 用于启动内核;

  • init是一个线程函数,在该函数中实现你的其它初始化代码.

  • 更多函数参数说明请参考API文档。

二、深入理解缓存 TLB 原理

  TLB是translation lookaside buffer的简称。首先,我们知道MMU的作用是把虚拟地址转换成物理地址。虚拟地址和物理地址的映射关系存储在页表中,而现在页表又是分级的。64位系统一般都是3~5级。常见的配置是4级页表,就以4级页表为例说明。分别是PGD、PUD、PMD、PTE四级页表。在硬件上会有一个叫做页表基地址寄存器,它存储PGD页表的首地址。

    MMU就是根据页表基地址寄存器从PGD页表一路查到PTE,最终找到物理地址(PTE页表中存储物理地址)。这就像在地图上显示你的家在哪一样,我为了找到你家的地址,先确定你是中国,再确定你是某个省,继续往下某个市,最后找到你家是一样的原理。一级一级找下去。这个过程你也看到了,非常繁琐。如果第一次查到你家的具体位置,我如果记下来你的姓名和你家的地址。下次查找时,是不是只需要跟我说你的姓名是什么,我就直接能够告诉你地址,而不需要一级一级查找。四级页表查找过程需要四次内存访问。延时可想而知,非常影响性能。

    页表查找过程的示例如下图所示,这里了解下即可。TLB 的本质是什么

    TLB 其实就是一块高速缓存。

    数据 cache 缓存地址(虚拟地址或者物理地址)和数据。TLB 缓存虚拟地址和其映射的物理地址。TLB 根据虚拟地址查找 cache,它没得选,只能根据虚拟地址查找。

    所以 TLB 是一个虚拟高速缓存。硬件存在 TLB 后,虚拟地址到物理地址的转换过程发生了变化。虚拟地址首先发往 TLB 确认是否命中 cache,如果 cache hit 直接可以得到物理地址。

    否则,一级一级查找页表获取物理地址。并将虚拟地址和物理地址的映射关系缓存到 TLB 中。既然 TLB 是虚拟高速缓存(VIVT),是否存在别名和歧义问题呢?如果存在,软件和硬件是如何配合解决这些问题呢?

TLB 的特殊

    虚拟地址映射物理地址的最小单位是 4KB。所以 TLB 其实不需要存储虚拟地址和物理地址的低 12 位(因为低 12 位是一样的,根本没必要存储)。

    另外,我们如果命中 cache,肯定是一次性从 cache 中拿出整个数据。所以虚拟地址不需要 offset 域。index 域是否需要呢?这取决于cache的组织形式。

    如果是全相连高速缓存。那么就不需要 index。如果使用多路组相连高速缓存,依然需要index。

    下图就是一个四路组相连 TLB 的例子。现如今 64 位 CPU 寻址范围并没有扩大到 64 位。64 位地址空间很大,现如今还用不到那么大。

    因此硬件为了设计简单或者解决成本,实际虚拟地址位数只使用了一部分。这里以 48 位地址总线为例说明。TLB 的别名问题

    我先来思考第一个问题,别名是否存在。我们知道 PIPT 的数据 cache 不存在别名问题。物理地址是唯一的,一个物理地址一定对应一个数据。但是不同的物理地址可能存储相同的数据。

    也就是说,物理地址对应数据是一对一关系,反过来是多对一关系。由于 TLB 的特殊性,存储的是虚拟地址和物理地址的对应关系。

    因此,对于单个进程来说,同一时间一个虚拟地址对应一个物理地址,一个物理地址可以被多个虚拟地址映射。

    将 PIPT 数据 cache 类比 TLB,我们可以知道TLB 不存在别名问题。而 VIVT Cache 存在别名问题,原因是 VA 需要转换成PA,PA 里面才存储着数据。中间多经传一手,所以引入了些问题。

TLB的歧义问题

    我们知道不同的进程之间看到的虚拟地址范围是一样的,所以多个进程下,不同进程的相同的虚拟地址可以映射不同的物理地址。这就会造成歧义问题。

    例如,进程A将地址 0x2000 映射物理地址 0x4000。进程 B 将地址 0x2000 映射物理地址 0x5000。当进程 A 执行的时候将 0x2000 对应0x4000 的映射关系缓存到 TLB 中。当切换 B 进程的时候,B 进程访问 0x2000 的数据,会由于命中 TLB 从物理地址0x4000取数据。

    这就造成了歧义。如何消除这种歧义,我们可以借鉴 VIVT 数据 cache 的处理方式,在进程切换时将整个 TLB 无效。切换后的进程都不会命中 TLB,但是会导致性能损失。

如何尽可能地避免 flush TLB

    首先需要说明的是,这里的 flush 理解成使无效的意思。我们知道进程切换的时候,为了避免歧义,我们需要主动 flush 整个 TLB。如果我们能够区分不同的进程的 TLB 表项就可以避免 flush TLB。

    我们知道 Linux 如何区分不同的进程,每个进程拥有一个独一无二的进程 ID。如果 TLB 在判断是否命中的时候,除了比较 tag 以外,再额外比较进程 ID 该多好呢!这样就可以区分不同进程的TLB表项。whaosoft aiot http://143ai.com  

    进程 A 和 B 虽然虚拟地址一样,但是进程 ID 不一样,自然就不会发生进程 B 命中进程 A 的 TLB 表项。所以,TLB 添加一项 ASID(Address Space ID) 的匹配。

    ASID 就类似进程 ID 一样,用来区分不同进程的 TLB 表项。这样在进程切换的时候就不需要 flush TLB。但是仍然需要软件管理和分配 ASID。如何管理 ASID

    ASID 和进程 ID 肯定是不一样的,别混淆二者。进程 ID 取值范围很大。但是ASID 一般是 8 或 16  bit。所以只能区分 256 或 65536 个进程。我们的例子就以 8 位ASID说明。

    所以我们不可能将进程 ID 和 ASID 一一对应,我们必须为每个进程分配一个ASID,进程 ID 和每个进程的 ASID 一般是不相等的。

    每创建一个新进程,就为之分配一个新的 ASID。当 ASID 分配完后,flush 所有 TLB,重新分配 ASID。

    所以,如果想完全避免 flush TLB的话,理想情况下,运行的进程数目必须小于等于 256。然而事实并非如此,因此管理 ASID 上需要软硬结合。

    Linux kernel 为了管理每个进程会有个 task_struct 结构体,我们可以把分配给当前进程的 ASID 存储在这里。页表基地址寄存器有空闲位也可以用来存储ASID。当进程切换时,可以将页表基地址和 ASID (可以从 task_struc t获得)共同存储在页表基地址寄存器中。

    当查找 TLB 时,硬件可以对比 tag 以及 ASID 是否相等(对比页表基地址寄存器存储的 ASID 和 TLB 表项存储的 ASID)。如果都相等,代表 TLB hit。否则TLB miss。当 TLB miss 时,需要多级遍历页表,查找物理地址。然后缓存到TLB 中,同时缓存当前的 ASID。

多个进程共享

    我们知道内核空间和用户空间是分开的,并且内核空间是所有进程共享。既然内核空间是共享的,进程 A 切换进程 B 的时候,如果进程 B 访问的地址位于内核空间,完全可以使用进程 A 缓存的 TLB。但是现在由于 ASID 不一样,导致 TLB miss。

    我们针对内核空间这种全局共享的映射关系称之为 global 映射。针对每个进程的映射称之为 non-global 映射。

    所以,我们在最后一级页表中引入一个 bit (non-global (nG) bit)代表是不是 global 映射。当虚拟地址映射物理地址关系缓存到 TLB 时,将 nG bit 也存储下来。

    当判断是否命中 TLB 时,当比较 tag 相等时,再判断是不是 global 映射,如果是的话,直接判断 TLB hit,无需比较 ASID。当不是 global 映射时,最后比较 ASID 判断是否 TLB hit。什么时候应该flush TLB

    我们再来最后的总结,什么时候应该 flush TLB。

    当 ASID 分配完的时候,需要 flush 全部 TLB,ASID 的管理可以使用 bitmap 管理,flush TLB 后 clear 整个 bitmap。

    当我们建立页表映射的时候,就需要 flush 虚拟地址对应的 TLB 表项。

    第一印象可能是修改页表映射的时候才需要 flush TLB,但是实际情况是只要建立映射就需要 flush TLB。

    原因是,建立映射时你并不知道之前是否存在映射,例如,建立虚拟地址 A 到物理地址 B 的映射,我们并不知道之前是否存在虚拟地址 A 到物理地址 C 的映射情况,所以就统一在建立映射关系的时候 flush TLB。

三、几种分析三极管电路的方法

    三极管有静态和动态两种工作状态。未加信号时三极管的直流工作状态称为静态,此时各极电流称为静态电流;给三极管加入交流信号之后的工作电流称为动态工作电流,这时三极管是交流工作状态,即动态。

    一个完整的三极管电路分析有四步:直流电路分析、交流电路分析、元器件和修理识图。

直流电路分析方法

    直流工作电压加到三极管各个电极上,主要通过两条直流电路:一是三极管集电极与发射极之间的直流电路,二是基极直流电路。

    通过这一步分析可以搞清楚直流工作电压是如何加到集电极、基极和发射极上的。如下图所示,是放大器直流电路分析示意图。对于一个单级放大器而言,其直流电路分析主要是图1中所示的三个部分。

    分析三极管直流电路时,由于电路中的电容具有隔直流特性,所以可以将它们看成开路,这样上图所示电路就可以画成如下图所示的直流等效电路,再用这一等效电路进行直流电路分析就相当简洁了。

交流电路分析方法

    交流电路分析主要是交流信号的传输路线分析,即信号从哪里输入到放大器中,信号在这级放大器中具体经过了哪些元器件,信号最终从哪里输出。如下图所示,是交流信号传输路线分析示意图。

 另外还要分析信号在传输过程中受到了哪些处理,如信号在哪个环节放大、在哪个环节受到衰减、哪个环节不放大也不衰减、信号是否受到了补偿等。

    上图电路中的信号经过了C1、VT1、C2、VT2和C3,其中C1、C2和C3是耦合电容,对信号没有放大和衰减作用,只是起着将信号传输到下级电路中的耦合作用,VT1和VT2对信号起了放大作用。

元器件作用分析方法

▶元器件特性是电路分析关键

    分析电路中元器件的作用时,应依据该元器件的主要特性来进行。例如,耦合电容让交流信号无损耗的通过,而同时隔断直流通路,这一分析的理论根据是电容隔直通交特性。

▶元器件在电路中具体作用

    电路中的每个元器件都有它的特定作用,通常一个元器件起一种特定的作用,当然也有一个元器件在电路中起两个作用的。在电路分析中要求搞懂每一个元器件在电路中的具体作用。

▶元器件简化分析方法

    对元器件作用的分析可以进行简化,掌握了元器件在电路中的作用后,不必每次对各个元器件都进行详细分析。例如,掌握耦合电容的作用之后,不必对每一个耦合电容都进行分析。如下图所示,是耦合电容分析示意图。

修理识图方法

    修理识图为检修电路故障服务,这一识图要求在完全搞懂电路工作原理之后进行,否则没有意义。因为故障现象明确,故障检修过程中的修理识图可以有针对性的选择电路中的元器件进行,而不需要对电路中的每个元器件都进行故障分析。

    分析时,找出电路中的主要元器件,并分别假设它们出现开路、短路、阻值变大和变小等故障,分析这种故障对直流电路和交流电路的影响,从而推理出可能的故障根源。

    修理识图的关键是找出电路中关键测试点:

▶单级放大器关键测试点

    如下图所示,单级放大器主要是三极管的关键测试点。

  三极管的关键测试点用来测量三个电极的直流工作电压,其中集电极是第一测试点,其次是基极,第三是发射极。

▶集成电路关键测试点

    集成电路关键测试点最重要的是电源引脚,还有输入信号引脚和输出信号引脚。

基极偏置电路分析方法

    三极管基极偏置电路分析最为困难,掌握一些电路分析方法可以方便基极偏置电路的分析。

▶第一步

    电路分析的第一步是在电路中找出三极管的电路符号,如下图所示。然后在三极管电路符号中后找出基极,这是分析基极偏置电路的关键一步。

▶第二步

    从基极出发,将与基极和电源端相连的所有元器件找出来。如下图所示,电路中的RB1,再将基极与地端相连的所有元器件找出来,如电路中的RB2,这些元器件构成基极偏置电路的主体电路。

上述与基极相连的元器件中,要区别哪些元器件可能是偏置电路中的元器件。电阻器有可能构成偏置电路,电容器具有隔直作用而视为开路,所以在分析基极直流偏置电路时,不必考虑电容器。

▶第三步

    确定偏置电路中的元器件后,进行基极电流回路的分析。如上图所示,基极电流回路是:直流工作电压VCC→偏置电阻RB1→VT1基极→VT1发射极→VT1发射极电阻RE→地端。

四、步进电机

介绍步进电机的基础知识,包括其工作原理、构造、控制方法、用途、类型及其优缺点。

步进电机基础知识

步进电机是一种通过步进(即以固定的角度移动)方式使轴旋转的电机。其内部构造使它无需传感器,通过简单的步数计算即可获知轴的确切角位置。这种特性使它适用于多种应用。

步进电机工作原理

与所有电机一样,步进电机也包括固定部分(定子)和活动部分(转子)。定子上有缠绕了线圈的齿轮状突起,而转子为 永磁体或可变磁阻铁芯。稍后我们将更深入地介绍不同的转子结构。图1显示的电机截面图,其转子为可变磁阻铁芯。

图1: 步进电机截面图

步进电机的基本工作原理为:给一个或多个定子相位通电,线圈中通过的电流会产生磁场,而转子会与该磁场对齐;依次给不同的相位施加电压,转子将旋转特定的角度并最终到达需要的位置。图2显示了其工作原理。首先,线圈A通电并产生磁场,转子与该磁场对齐;线圈B通电后,转子顺时针旋转60°以与新的磁场对齐;线圈C通电后也会出现同样的情况。下图中定子小齿的颜色指示出定子绕组产生的磁场方向。图2: 步进电机的步进

步进电机的类型与构造

步进电机的性能(无论是分辨率/步距、速度还是扭矩)都受构造细节的影响,同时,这些细节也可能会影响电机的控制方式。实际上,并非所有步进电机都具有相同的内部结构(或构造),因为不同电机的转子和定子配置都不同。

转子

步进电机基本上有三种类型的转子:

  • 永磁转子:转子为永磁体,与定子电路产生的磁场对齐。这种转子可以保证良好的扭矩,并具有制动扭矩。这意味着,无论线圈是否通电,电机都能抵抗(即使不是很强烈)位置的变化。但与其他转子类型相比,其缺点是速度和分辨率都较低。图3显示了永磁步进电机的截面图。

 

图3: 永磁步进电机

  • 可变磁阻转子:转子由铁芯制成,其形状特殊,可以与磁场对齐(请参见图1和图2)。这种转子更容易实现高速度和高分辨率,但它产生的扭矩通常较低,并且没有制动扭矩。

  • 混合式转子:这种转子具有特殊的结构,它是永磁体和可变磁阻转子的混合体。其转子上有两个轴向磁化的磁帽,并且磁帽上有交替的小齿。这种配置使电机同时具有永磁体和可变磁阻转子的优势,尤其是具有高分辨率、高速度和大扭矩。当然更高的性能要求意味着更复杂的结构和更高的成本。图3显示了这种电机结构的简化示意图。线圈A通电后,转子N磁帽的一个小齿与磁化为S的定子齿对齐。与此同时,由于转子的结构,转子S磁帽与磁化为N的定子齿对齐。尽管步进电机的工作原理是相同的,但实际电机的结构更复杂,齿数要比图中所示的更多。大量的齿数可以使电机获得极小的步进角度,小至0.9°。

图4: 混合式步进电机

定子

定子是电机的一部分,负责产生转子与之对齐的磁场。定子电路的主要特性与其相数、极对数以及导线配置相关。相数是独立线圈的数量,极对数则表示每相占用的主要齿对。两相步进电机最常用,三相和五相电机则较少使用(请参见图5和图6)。图5: 两相定子绕组(左)和三相定子绕组(右) 图6:两相单极定子(左)和两相双极定子(右)。在A +和A-之间施加正电压时产生的磁场用字母N和S表示。

步进电机的控制

从上文我们知道,电机线圈需要按特定的顺序通电,以产生转子将与之对齐的磁场。可以向线圈提供必要的电压以使电机正常运行的设备有以下几种(从距离电机更近的设备开始):

    • 晶体管桥:从物理上控制电机线圈电气连接的设备。晶体管可以看作是电控断路器,它闭合时线圈连接到电源,线圈中才有电流通过。每个电机相位都需要一个晶体管电桥。

    • 预驱动器:控制晶体管激活的设备,它由MCU控制以提供所需的电压和电流。

    • MCU:通常由电机用户编程控制的微控制器单元,它为预驱动器生成特定信号以获得所需的电机行为。

图7为步进电机控制方案的简单示意图。预驱动器和晶体管电桥可以包含在单个设备中,即驱动器。图7: 电机控制基本方案

步进电机驱动器类型

市面上有各种不同的步进电机驱动器,它们针对特定应用具有不同的功能。但其最重要的特性之一与输入接口有关,最常见的几种输入接口包括:

  • Step/Direction (步进/方向) –在Step引脚上发送一个脉冲,驱动器即改变其输出使电机执行一次步进,转动方向则由Direction引脚上的电平来决定。

  • Phase/Enable(相位/使能) –对每相的定子绕组来说,Enable决定该相是否通电, Phase决定该相电流方向,。

  • PWM – 直接控制上下管FET的栅极信号。

步进电机驱动器的另一个重要特性是,除了控制绕组两端的电压,它是否还可以控制流过绕组的电流:

  • 拥有电压控制功能,驱动器可以调节绕组上的电压,产生的扭矩和步进速度仅取决于电机和负载特性。

  • 电流控制驱动器更加先进,因为它们可以调节流经有源线圈的电流,更好地控制产生的扭矩,从而更好地控制整个系统的动态行为。

单极/双极电机

另一个可能对电机控制产生影响的特性是其定子线圈的布置,它决定了电流方向的变化方式。为了实现转子的运动,不仅要给线圈通电,还要控制电流的方向,而电流方向决定了线圈本身产生的磁场方向(见图8)。

步进电机可以通过两种不同的方法来控制电流的方向。图8: 根据线圈电流方向控制磁场方向

在单极步进电机中,线圈的中心点连有一根引线(请参见图9),这样可以通过相对简单的电路和组件来控制电流方向。该中央引线(AM)连接输入电压VIN(见图8)。如果MOSFET 1导通,则电流从AM流向A +。如果MOSFET 2导通,则电流从AM流向A-,在相反方向上产生磁场。如上所述,这种方法可以简化驱动电路(仅需要两个半导体),但缺点是一次仅使用了电机中铜导体的一半,这意味着如果线圈中流过相同的电流 ,则磁场强度仅为使用全部铜导体时的一半。另外,由于电机输入引线更多,这类电机较难构造。图9: 单极步进电机驱动电路

在双极步进电机中,每个线圈只有两条引线,而且为了控制方向,必须使用H桥(请参见图10)。如图8所示,如果MOSFET 1和4导通,则电流从A +流向A-;如果MOSFET 2和3导通,则电流从A-流向A +,产生相反方向的磁场。这种方案需要更复杂的驱动电路,但可以最大限度利用电机铜量而实现最大扭矩。图10: 双极步进电机驱动电路

随着技术的不断进步,单极电机的优势逐步弱化,双极步进电机成为目前最流行的电机类型。

步进电机驱动技术

步进电机主要有四种不同的驱动技术:

  • 波动模式:一次仅一个相位通电(见图11)。为简单起见,如果电流从某相的正引线流向负引线(例如,从A +到A-),则我们称为正向流动;否则,称为负向流动。从下图左侧开始,电流仅在A相中正向流动,而用磁体代表的转子与其所产生的磁场对齐。接着,电流仅在B相中正向流动,转子顺时针旋转90°以与B相产生的磁场对齐。随后,A相再次通电,但电流负向流动 ,转子再次旋转90°。最后,电流在B相中负向流动,而转子再次旋转90°。

图11: 波动模式步进

  • 全步模式:两相始终同时通电。图12显示了该驱动模式的步进步骤。其步骤与波动模式类似,最大的区别在于,全步模式下,由于电机中流动的电流更多,产生的磁场也更强,因此扭矩也更大。

图12: 全步模式步进

  • 半步模式是波动模式和全步模式的组合(请参见图12)。这种模式可以将步距减小一倍(旋转45°,而不是90°)。其唯一的缺点是电机产生的扭矩不是恒定的,当两相都通电时扭矩较高,只有一相通电时扭矩较小。

 

图13: 半步模式步进

  • 微步模式:可以看作是半步模式的增强版,因为它可以进一步减小步距,并且具有恒定的扭矩输出。这是通过控制每相流过的电流强度来实现的。与其他方案相比,微步模式需要更复杂的电机驱动器。图14显示了微步模式的工作原理。假设IMAX是一个相位中可以通过的最大电流,则从图中左侧开始,在第一个图中IA = IMAX,IB = 0。下一步,控制电流以达到IA = 0.92 x IMAX,IB = 0.38 x IMAX,它产生的磁场与前一个磁场相比顺时针旋转了22.5°。控制电流达到不同的电流值并重复此步骤,将磁场旋转45°、67.5°和90°。与半步模式相比,它将步距减少了一半;但还可以减少更多。使用微步模式可以达到非常高的位置分辨率,但其代价是需要更复杂的设备来控制电机,并且每次步进产生的扭矩也更小。扭矩与定子磁场和转子磁场之间的夹角正弦成正比;因此,当步距较小时,扭矩也较小。这有可能会导致丢步,也就是说,即使定子绕组中的电流发生了变化,转子的位置也可能不改变。

图14: 微步模式步进

步进电机的优缺点

现在我们已了解了步进电机的工作原理,再总结一下各类电机的优缺点将非常有帮助。

优点:

  • 得益于其内部结构,步进电机不需要传感器来检测电机位置。步进电机是通过执行“步进”来运动的,因此只需简单地计算步数就可以获得给定时间的电机位置。

  • 此外,步进电机的控制非常简单。它也需要驱动器,但不需要复杂的计算或调整即可正常工作。与其他电机相比,其控制工作量通常很小。而且,如果采用微步模式,还可以实现高达0.007°的位置精度。

  • 步进电机在低速时可提供良好的扭矩,也可以很好的保持位置,而且使用寿命长。

缺点:

  • 当负载扭矩过高时可能会失步。由于无法获知电机的实际位置,因此会对控制产生负面影响。采用微步模式时更易产生此问题。

  • 步进电机即使在静止时也总是消耗最大电流,因此会降低效率并可能导致过热。

  • 步进电机扭矩小,在高速下会产生很大的噪音。

  • 步进电机具有低功率密度和低扭矩惯性比。

五、常见电机控制算法

市面上常见的电机有很多种,按照工作电源分类,可分为交流电机和直流电机,直流电机又可大致分为有刷直流电机和无刷直流电机。按照结构和工作原理划分则可将电机分为异步电动机和同步电动机等等。这些电机的控制算法是怎样的?跟着我们一起盘点下吧!

BLCD电机控制算法

无刷电机属于自换流型(自我方向转换),因此控制起来更加复杂。

BLDC电机控制要求了解电机进行整流转向的转子位置和机制。对于闭环速度控制,有两个附加要求,即对于转子速度/或电机电流以及PWM信号进行测量,以控制电机速度功率。

BLDC电机可以根据应用要求采用边排列或中心排列PWM信号。大多数应用仅要求速度变化操作,将采用6个独立的边排列PWM信号。这就提供了最高的分辨率。如果应用要求服务器定位、能耗制动或动力倒转,推荐使用补充的中心排列PWM信号。

为了感应转子位置,BLDC电机采用霍尔效应传感器来提供绝对定位感应。这就导致了更多线的使用和更高的成本。无传感器BLDC控制省去了对于霍尔传感器的需要,而是采用电机的反电动势(电动势)来预测转子位置。无传感器控制对于像风扇和泵这样的低成本变速应用至关重要。在采有BLDC电机时,冰箱和空调压缩机也需要无传感器控制。

空载时间的插入和补充

大多数BLDC电机不需要互补的PWM、空载时间插入或空载时间补偿。可能会要求这些特性的BLDC应用仅为高性能BLDC伺服电动机、正弦波激励式BLDC电机、无刷AC、或PC同步电机。

控制算法

许多不同的控制算法都被用以提供对于BLDC电机的控制。典型地,将功率晶体管用作线性稳压器来控制电机电压。当驱动高功率电机时,这种方法并不实用。高功率电机必须采用PWM控制,并要求一个微控制器来提供起动和控制功能。

控制算法必须提供下列三项功能:

  • 用于控制电机速度的PWM电压

  • 用于对电机进整流换向的机制

  • 利用反电动势或霍尔传感器来预测转子位置的方法

脉冲宽度调制仅用于将可变电压应用到电机绕组。有效电压与PWM占空度成正比。当得到适当的整流换向时,BLDC的扭矩速度特性与一下直流电机相同。可以用可变电压来控制电机的速度和可变转矩。

功率晶体管的换向实现了定子中的适当绕组,可根据转子位置生成最佳的转矩。在一个BLDC电机中,MCU必须知道转子的位置并能够在恰当的时间进行整流换向。

BLDC电机的梯形整流换向

对于直流无刷电机的最简单的方法之一是采用所谓的梯形整流换向图1:用于BLDC电机的梯形控制器的简化框架

在这个原理图中,每一次要通过一对电机终端来控制电流,而第三个电机终端总是与电源电子性断开。

嵌入大电机中的三种霍尔器件用于提供数字信号,它们在60度的扇形区内测量转子位置,并在电机控制器上提供这些信息。由于每次两个绕组上的电流量相等,而第三个绕组上的电流为零,这种方法仅能产生具有六个方向共中之一的电流空间矢量。随着电机的转向,电机终端的电流在每转60度时,电开关一次(整流换向),因此电流空间矢量总是在90度相移的最接近30度的位置。

图2:梯形控制:驱动波形和整流处的转矩

因此每个绕组的电流波型为梯形,从零开始到正电流再到零然后再到负电流。

这就产生了电流空间矢量,当它随着转子的旋转在6个不同的方向上进行步升时,它将接近平衡旋转。

在像空调和冰霜这样的电机应用中,采用霍尔传感器并不是一个不变的选择。在非联绕组中感应的反电动势传感器可以用来取得相同的结果。

这种梯形驱动系统因其控制电路的简易性而非常普通,但是它们在整流过程中却要遭遇转矩纹波问题。

BDLC电机的正弦整流换向

梯形整流换向还不足以为提供平衡、精准的无刷直流电机控制。这主要是因为在一个三相无刷电机(带有一个正统波反电动势)中所产生的转矩由下列等式来定义:

转轴转矩= Kt [IRSin(o) + ISSin(o+120) +ITSin(o+240)]
  其中:
      o为转轴的电角度
      Kt为电机的转矩常数
      IR, IS和IT为相位电流

如果相位电流是正弦的:IR   = I0Sino; IS = I0Sin (+120o); IT   = I0Sin (+240o)
 将得到:

转轴转矩= 1.5I0*Kt(一个独立于转轴角度的常数)

正弦整流换向无刷电机控制器努力驱动三个电机绕组,其三路电流随着电机转动而平稳的进行正弦变化。选择这些电流的相关相位,这样它们将会产生平稳的转子电流空间矢量,方向是与转子正交的方向,并具有不变量。这就消除了与北形转向相关的转矩纹波和转向脉冲。

为了随着电机的旋转,生成电机电流的平稳的正弦波调制,就要求对于转子位置有一个精确有测量。霍尔器件仅提供了对于转子位置的粗略计算,还不足以达到目的要求。基于这个原因,就要求从编码器或相似器件发出角反馈。图3:BLDC电机正弦波控制器的简化框图

由于绕组电流必须结合产生一个平稳的常量转子电流空间矢量,而且定子绕组的每个定位相距120度角,因此每个线组的电流必须是正弦的而且相移为120度。采用编码器中的位置信息来对两个正弦波进行合成,两个间的相移为120度。然后,将这些信号乘以转矩命令,因此正弦波的振幅与所需要的转矩成正比。结果,两个正弦波电流命令得到恰当的定相,从而在正交方向产生转动定子电流空间矢量。

正弦电流命令信号输出一对在两个适当的电机绕组中调制电流的P-I控制器。第三个转子绕组中的电流是受控绕组电流的负和,因此不能被分别控制。每个P-I控制器的输出被送到一个PWM调制器,然后送到输出桥和两个电机终端。应用到第三个电机终端的电压源于应用到前两个线组的信号的负数和,适当用于分别间隔120度的三个正弦电压。

结果,实际输出电流波型精确的跟踪正弦电流命令信号,所得电流空间矢量平稳转动,在量上得以稳定并以所需的方向定位。

一般通过梯形整流转向,不能达到稳定控制的正弦整流转向结果。然而,由于其在低电机速度下效率很高,在高电机速度下将会分开。这是由于速度提高,电流回流控制器必须跟踪一个增加频率的正弦信号。同时,它们必须克服随着速度提高在振幅和频率下增加的电机的反电动势。

由于P-I控制器具有有限增益和频率响应,对于电流控制回路的时间变量干扰将引起相位滞后和电机电流中的增益误差,速度越高,误差越大。这将干扰电流空间矢量相对于转子的方向,从而引起与正交方向产生位移。

当产生这种情况时,通过一定量的电流可以产生较小的转矩,因此需要更多的电流来保持转矩。效率降低。

随着速度的增加,这种降低将会延续。在某种程度上,电流的相位位移超过90度。当产生这种情况时,转矩减至为零。通过正弦的结合,上面这点的速度导致了负转矩,因此也就无法实现。

 AC电机算法 

标量控制

标量控制(或V/Hz控制)是一个控制指令电机速度的简单方法

指令电机的稳态模型主要用于获得技术,因此瞬态性能是不可能实现的。系统不具有电流回路。为了控制电机,三相电源只有在振幅和频率上变化。

矢量控制或磁场定向控制

在电动机中的转矩随着定子和转子磁场的功能而变化,并且当两个磁场互相正交时达到峰值。在基于标量的控制中,两个磁场间的角度显著变化。

矢量控制设法在AC电机中再次创造正交关系。为了控制转矩,各自从产生磁通量中生成电流,以实现DC机器的响应性。

一个AC指令电机的矢量控制与一个单独的励磁DC电机控制相似。在一个DC电机中,由励磁电流IF所产生的磁场能量Φ F与由电枢电流IA所产生的电枢磁通ΦA正交。这些磁场都经过去耦并且相互间很稳定。因此,当电枢电流受控以控制转矩时,磁场能量仍保持不受影响,并实现了更快的瞬态响应。

三相AC电机的磁场定向控制(FOC)包括模仿DC电机的操作。所有受控变量都通过数学变换,被转换到DC而非AC。其目标的独立的控制转矩和磁通。

磁场定向控制(FOC)有两种方法:

直接FOC: 转子磁场的方向(Rotor flux angle) 是通过磁通观测器直接计算得到的。

间接FOC: 转子磁场的方向(Rotor flux angle) 是通过对转子速度和滑差(slip)的估算或测量而间接获得的。

矢量控制要求了解转子磁通的位置,并可以运用终端电流和电压(采用AC感应电机的动态模型)的知识,通过高级算法来计算。然而从实现的角度看,对于计算资源的需求是至关重要的。

可以采用不同的方式来实现矢量控制算法。前馈技术、模型估算和自适应控制技术都可用于增强响应和稳定性。

AC电机的矢量控制:深入了解

矢量控制算法的核心是两个重要的转换: Clark转换,Park转换和它们的逆运算。采用Clark和Park转换,带来可以控制到转子区域的转子电流。这种做充许一个转子控制系统决定应供应到转子的电压,以使动态变化负载下的转矩最大化。

Clark转换:Clark数学转换将一个三相系统修改成两个坐标系统:

其中Ia和Ib正交基准面的组成部分,Io是不重要的homoplanar部分 

图4:三相转子电流与转动参考系的关系

Park转换:Park数学转换将双向静态系统转换成转动系统矢量AC电机的磁场定向矢量控制的基本结构

Clarke变换采用三相电流IA, IB 以及 IC,来计算两相正交定子轴的电流Isd和 Isq。这两个在固定座标定子相中的电流被变换成Isd 和Isq,成为Park变换d, q中的元素。其通过电机通量模型来计算的电流Isd, Isq 以及瞬时流量角θ被用来计算交流感应电机的电动扭矩。图2:矢量控制交流电机的基本原理

这些导出值与参考值相互比较,并由PI控制器更新。基于矢量的电机控制的一个固有优势是,可以采用同一原理,选择适合的数学模型去分别控制各种类型的AC, PM-AC 或者 BLDC电机。

BLDC电机的矢量控制

BLDC电机是磁场定向矢量控制的主要选择。采用了FOC的无刷电机可以获得更高的效率,最高效率可以达到95%,并且对电机在高速时也十分有效率。

 步进电机控制算法 

如下是步进电机控制示意图:

步进电机控制通常采用双向驱动电流,其电机步进由按顺序切换绕组来实现。通常这种步进电机有3个驱动顺序:

1、单相全步进驱动:

在这种模式中,其绕组按如下顺序加电,AB/CD/BA/DC (BA表示绕组AB的加电是反方向进行的)。这一顺序被称为单相全步进模式,或者波驱动模式。在任何一个时间,只有一相加电。

2、双相全步进驱动:

在这种模式中,双相一起加电,因此,转子总是在两个极之间。此模式被称为双相全步进,这一模式是两极电机的常态驱动顺序,可输出的扭矩最大。

3、半步进模式:

这种模式将单相步进和双相步进结合在一起加电:单相加电,然后双相加电,然后单相加电…,因此,电机以半步进增量运转。这一模式被称为半步进模式,其电机每个励磁的有效步距角减少了一半,其输出的扭矩也较低。

以上3种模式均可用于反方向转动(逆时针方向),如果顺序相反则不行。

通常,步进电机具有多极,以便减小步距角,但是,绕组的数量和驱动顺序是不变的。

 通用DC控制算法 

通用电机的速度控制,特别是采用2种电路的电机:

    1、相角控制

    2、PWM斩波控制

相角控制

相角控制是通用电机速度控制的最简单的方法。通过TRIAC的点弧角的变动来控制速度。相角控制是非常经济的解决方案,但是,效率不太高,易于电磁干扰(EMI)。通用电机的相角控制

以上示图表明了相角控制的机理,是TRIAC速度控制的典型应用。TRIAC门脉冲的周相移动产生了有效率的电压,从而产生了不同的电机速度,并且采用了过零交叉检测电路,建立了时序参考,以延迟门脉冲。

PWM斩波控制

PWM控制是通用电机速度控制的,更先进的解决方案。在这一解决方案中,功率MOFSET,或者IGBT接通高频整流AC线电压,进而为电机产生随时间变化的电压。通用电机的PWM斩波控制

其开关频率范围一般为10-20 KHz,以消除噪声。这一通用电机的控制方法可以获得更佳的电流控制和更佳的EMI性能,因此,效率更高。

六、关于CPU的知识总结

不管你玩硬件还是做软件,你的世界都少不了计算机最核心的 —— CPU。   

01 CPU是什么?

    CPU与计算机的关系就相当于大脑和人的关系,它是一种小型的计算机芯片,通常嵌入在电脑的主板上。

    CPU的构建是通过在单个计算机芯片上放置数十亿个微型晶体管来实现。

    这些晶体管使它能够执行运行存储在系统内存中的程序所需的计算,所以,也可以说CPU决定了你电脑的计算能力。   

02 CPU实际做什么?

    CPU的工作核心是从程序或应用程序中获取指令并且执行计算。

    这个过程一共有三个关键阶段:提取,解码和执行。

    CPU先从系统的RAM中提取指令,随后解码该指令的实际内容,最后再由CPU的相关部分执行该指令。   

03 CPU的内部结构

    刚才提到了很多CPU的重要性,那么CPU的内部结构是什么呢?又是由什么组成的呢?

    下图展示了一般程序的运行流程(以C语言为例),一般来说,了解程序的运行流程是掌握程序运行机制的基础和前提。​​​​​​​

 在这个流程中,CPU负责解释和运行最终转换成机器语言的内容,CPU主要由两部分构成:控制单元和算数逻辑单元(ALU)。   

  • 控制单元:从内存中提取指令并解码执行;

  • 算数逻辑单元(ALU):处理算数和逻辑运算。

    CPU和内存都是由许多晶体管组成的电子部件,可以把它比作计算机的心脏和大脑。

    它能够接收数据输入、执行指令并且处理相关信息,它与输入/输出(I/O)设备进行通信,这些设备向 CPU 发送数据和从 CPU 接收数据。

    从功能上来看,CPU的内容是由寄存器、控制器、运算器和时钟四部分组成的,各个部分之间通电信号来连通。

    接下来简单介绍一下内存,为什么说到CPU需要讲一下内存呢?

    因为内存是与CPU进行沟通的桥梁,计算机中所有程序的运行都在内存中得到运行的。

    内存一般又被称为主存,它的作用是存放CPU中的运算数据,以及与硬盘等外部存储设备交换的数据。

    CPU会在计算机运转时,把需要运算的数据调到主存中进行运算。

    在运算完成之后,CPU将结果传送出来,主存的运行也决定了计算机的稳定运行。

    主存一般通过控制芯片与CPU相连,由可读写的元素构成,每个字节都有一个地址编号。

    CPU通过地址从主存中读取数据和指令,也可以根据地址写入数据,注意一点:当计算机关机时,内存中的指令和数据也会被清除。   

04 CPU是寄存器的集合体

    在CPU的四个结构中,寄存器的重要性远远高于其余三个,为什么这么说?因为程序通常是把寄存器作为对象来进行描述的。

    而说到寄存器,就不得不说到汇编语言,说到汇编语言,就不得不说到高级语言,说起高级语言也就不得不提及语言的概念。   

05 计算机语言

    人和人之间最古老和直接的沟通媒介是语言,但是和计算机沟通,就必须按照计算机指令来交换,其中就涉及到语言的问题。

    最早,为了解决计算机和人类的交流的问题,出现了汇编语言。

    但是汇编语言晦涩难懂,所以又出现了像是C、C++、Java的这种高级语言,因此计算机语言一般分为低级语言和高级语言。

    使用高级语言编写的程序,经过编译转换成机器语言后才能运行,而汇编语言经过汇编器才能转换为机器语言。   

06 汇编语言

    我们先来看一段采用汇编语言表示的代码清单:​​​​​​​这是采用汇编语言编写程序的一部分,汇编语言采用助记符来编写程序,每个原本是电信号的机器语言指令会有一个与其对应的助记符。

    比如,mov,add分别是数据的存储(move)和相加(addition)的简写。

    汇编语言和机器语言一一对应,这点和高级语言不同,我们通常把汇编语言编写的程序转换为机器语言的这个过程,称之为汇编。

    与之相反,将机器语言转化为汇编语言的过程称之为反汇编。

    汇编语言可以帮助你理解计算机做了什么工作,机器语言级别的程序通过寄存器来处理,上面代码中的eax,ebp都是表示的寄存器,它们是CPU内部寄存器的名称。

    因此,可以说 CPU 是一系列寄存器的集合体。

    一般,在内存中的存储通过地址编号来表示,寄存器的种类是通过名字来区分。

    那些不同类型的CPU,其内部寄存器的种类、数量以及寄存器存储的数值范围也都是不同的。

    不过,根据功能的不同,我们可以将寄存器划分为下面几类:​​​​​​​

其中,程序计数器、标志寄存器、累加寄存器、指令寄存器和栈寄存器只有一个,其他寄存器一般有好几个。   

07 程序计数器

    程序计数器是用来存储下一条指令所在单元的地址。

    程序在执行时,PC的初值作为程序第一条指令的地址,在顺序执行程序时,控制器先按照程序计数器所指出的指令地址,从内存中取出一条指令,随后分析和执行该指令,并同时将PC的值加1指向下一条要执行的指令。

    我们可以通过一个事例来仔细看一下程序计数器的执行过程:​​​​​​​

 这是一段进行相加的操作,程序启动,在经过编译解析后,会经由操作系统把硬盘中的程序复制到内存中。

    以上示例程序,就是将123和456执行相加的操作,随后将结果输出到显示器上,因为使用机器语言很难描述,所以这些都是经过翻译后的结果。

    事实上,每个指令和数据都有可能分布在不同的地址上,但是为了更好的说明,就把组成一条指令的内存和数据放在了一个内存地址上。

    地址0100是程序运行的起始位置,Windows等操作系统把程序从硬盘复制到内存以后,就会将程序计数器作为设定为起始位置0100,然后再执行程序,每次执行一条指令后,程序计数器的数值就会增加1,或者是直接指向下一条指令的地址。

    随后,CPU会根据程序计数器的数值,从内存中读取命令并且执行,换言之,程序计数器控制着程序的流程。   

08 条件分支和循环机制

    小伙伴们都学过高级语言,高级语言汇总的条件控制流程主要分为顺序执行、条件分支、循环判断三种。   

  • 顺序执行是按照地址的内容顺序的执行命令。

  • 条件分支是根据条件执行任意地址的指令。

  • 循环是重复执行同一地址的指令。

    一般情况下,顺序执行的情况较简单,每次执行一条指令程序计数器的值就是+1。

    条件和循环分支会使得程序计数器的值指向任意的地址,这样一来,程序就可以返回到上一个地址来重复执行同一个指令,或者跳转到其它任意指令。

    下面,我们就以条件分支举例来说明程序的执行过程:​​​​​​​​​​​​​​

程序的开始过程和顺序流程是一样的,程序的顺序流程和开始过程相同。

    CPU从0100处就开始执行命令,在0100和0101中都是顺序执行,PC的值顺序+1,执行到0102地址的指令时,判断0106寄存器的数值大于0,跳转到0104地址的指令,再将数值输到显示器中,随后结束程序,0103的指令就被跳过了。

    这和我们程序中的if()判断相同,在不满足条件的情况下,指令一般会直接跳过。

    因此,PC的执行过程没有直接+1,而是下一条指令的地址。   

09 标志寄存器

    条件和循环分支会使用到 jump(跳转指令),会根据当前的指令来判断是否跳转,上面我们提到了标志寄存器,无论当前累加寄存器的运算结果是正数、负数还是零,标志寄存器都会将其保存。

    CPU在进行运算时,标志寄存器的数值会根据当前运算的结果自动设定,运算结果的正、负和零三种状态由标志寄存器的三个位表示。

    标志寄存器的第一个字节位、第二个字节位、第三个字节位各自的结果都为1时,分别代表着正数、零和负数。

    CPU的执行机制比较有意思,假设累加寄存器中存储的XXX和通用寄存器中存储的YYY做比较,执行比较的背后,CPU的运算机制就会做减法运算。

    而无论减法运算的结果是正数、零还是负数,都会保存到标志寄存器中。

    结果为正表示 XXX 比 YYY 大,结果为零表示 XXX 和 YYY 相等,结果为负表示 XXX 比 YYY 小,程序比较的指令,实际上是在 CPU 内部做减法运算。   

10 函数调用机制

    函数的调用和条件分支,循环机制有所不同,单纯的跳转指令无法实现函数的调用。

    函数的调用需要在函数内部处理后,处理流程在返回到函数调用点(函数调用指令的下一个地址)。

    函数的调用处理是通过把程序计数器的值设定成函数的存储地址来实现的。​​​​​​​

11 通过地址和索引实现数组

    接下来是基址寄存器和变址寄存器,通过这两个寄存器,可以对主存上的特定区域进行划分,以此实现类似数组的操作。

    首先,可以用十六进制数将计算机内存上的 00000000 - FFFFFFFF 的地址划分出来。

    这样,凡是该范围的内存地址,只要有一个 32 位的寄存器,就可以查看全部地址。

    但是,要是想像数组那样,分割特定的内存区域以达到连续查看的目的的话,使用两个寄存器会更方便一些,比如,我们用两个寄存器来表示内存的值。​​​​​​​​​​​​​​

 这种表示方式很像数组的构造,数组是指同样长度的数据,在内存中进行连续排列的数据构造。

    用数组名表示数组全部的值,通过索引来区分数组的各个数据元素,例如: a[0] - a[4],[]内的 0 - 4 就是数组的下标。   

12 CPU指令执行过程

    那说了这么多,CPU到底是怎么一条条的执行指令的呢?几乎全部的冯·诺伊曼型计算机的CPU,工作都可以分为5个阶段:取指令、指令译码、执行指令、访存取数、结果写回。

    取指令阶段就是将内存中的指令读取到CPU中寄存器的过程,程序寄存器用于存储下一条指令所在的地址;   

  • 在取指令完成后,立马进入指令译码阶段,在指令译码阶段,指令编码器按照预先的指令格式,对取回的指令进行拆分和解释,识别区分出不同的指令类别和各种获取操作数的方法;

  • 执行指令阶段的任务是完成指令所规定的各种操作,具体实现指令的功能;

  • 访问取数阶段的任务是:根据指令地址码,得到操作数在主存中的地址,并从主存中读取该操作数用于运算;

  • 结果写回阶段作为最后一个阶段,把执行指令阶段的运行结果数据“写回”到某种存储形式:结果数据经常被写到CPU的内部寄存器中,以便被后续的指令快速地存取。

 

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值