电机控制程序设计经验

  这边总结了一些电机程序编写中的经验,很多经验也来源于别人的博客或者和一些前辈的交流,在此贴出。

设计流程

  平台的搭建需要考虑标准化问题。像dsp实验的模块化、各种标准协议采用、仿真验证到算法实现的流程等,都是属于最基本的要求。而多项工作的多人合力完成,关键在于标准化。标准化的接口设计,使得每个人都专注于实现各自模块中的核心功能。
  先对算法进行系统级别仿真,工具有matlab等软件,而后进行半实物级别仿真,验证算法在控制器上实现的准确性,最后进行实物的实验。实验又可以分为理想环境实验和工况下进行试验。

代码版本控制

  这是软件开发中一个十分重要的工程手段,几乎是必须的一个Process(过程)。很多作坊式的开发团队在采用软件工程的一些方法的时候,第一个要进行改进或增加的,往往就是这个过程。对初学者学习而言,这个过程也应该学习,因为未来总归会走向工作岗位。
  在初期阶段,可能是手动进行,如建立日期为标号的压缩包等等。很多人进行了较长时间的软件开发或者程序设计,都有了备份和版本控制的概念,但是没有掌握合适的工具。推荐代码管理工具用git,这是主流工具,可同步至云端托管平台有gitee、github等。
  在电机控制的几个开发环境中,CCS带有git的功能,可以选择同步代码至github、gitee等,而 据说KEIL5.15才有对git、svn的支持,因为平时主要用CCS所以对keil的代码版本控制不够了解。

软件架构

前后台系统裸机

概念(摘自百度百科)

  前后台系统,即计算机前后台系统,早期的嵌入式系统中没有操作系统的概念,程序员编写嵌入式程序通常直接面对裸机及裸设备,在这种情况下,通常把嵌入式程序分成两部分,即前台程序和后台程序。   应用程序是一个无限的循环,循环中调用相应的函数完成相应的操作,这部分可以看成后台行为。前台程序通过中断来处理事件;后台程序则掌管整个嵌入式系统软、硬件资源的分配、管理以及任务的调度,是一个系统管理调度程序。这就是通常所说的前后台系统。一般情况下,后台程序也叫事件处理任务,前台程序也叫中断级任务。在程序运行时,后台程序检查每个任务是否具备运行条件,通过一定的调度算法来完成相应的操作。对于实时性要求特别严格的操作通常由中断来完成,仅在中断服务程序中标记事件的发生,不再做任何工作就退出中断,经过后台程序的调度,转由前台程序完成事件的处理,这样就不会造成在中断服务程序中处理费时的事件而影响后续和其他中断。
  实际上,前后台系统的实时性比预计的要差。这是因为前后台系统认为所有的任务具有相同的优先级别,即是平等的,而且任务的执行又是通过FIFO队列排队,因而对那些实时性要求高的任务不可能立刻得到处理。另外,由于后台程序是一个无限循环的结构,一旦在这个循环体中正在处理的任务崩溃,使得整个任务队列中的其他任务得不到机会被处理,从而造成整个系统的崩溃。由于这类系统结构简单,几乎不需要RAM/ROM的额外开销,因而在简单的嵌入式应用被广泛使用。

评价

  尽管缺点较多,但是我在电机控制中经常用这一架构,因为电机算法主要执行在PWM中断或者采样中断,其余部分程序如通讯等,基本主循环中执行,属于辅助程序。

状态机

  思想广泛应用于硬件控制电路设计,也是软件上常用的一种处理方法(软 件上称为FMM–有限消息机)。它把复杂的控制逻辑分解成有限个稳定状态,在每个状态上判断事件,变连续处理为离散数字处理,符合计算机的工作特点。同时,因为有限状态机具有有限个状态,所以可以在实际的工程上实现。但这并不意味着其只能进行有限次的处理,相反,有限状态机是闭环系统,有限无穷,可以用有限的状态,处理无穷的事务。在具体的电机控制中,可以通过分析电机控制的几个过程,在ST、TI的电机控制demo中,将电机的运行分为init、start、run、stop、fault等几个状态。这些不同的状态在运行的位置也是不同的。如init状态通常是包含了各类控制的初始化过程,因此,这些代码执行在主循环中;而start、run状态为电机运行时的代码,将执行在AD采样中断中。

RTOS

概念(摘自百度百科)

  在嵌入式应用领域,很多场合对系统的实时性要求严格,因此操作系统的选择要基于实时系统。实时多任务操作系统(Real Time Operating System,简称RTOS)是根据操作系统的工作特性而言的,实时是指物理进程的真实时间。实时操作系统是指具有实时性,能支持实时控制系统工作的操作系统。其首要任务是调度一切可利用的资源完成实时控制任务,其次才着眼于提高计算机系统的使用效率,重要特点是要满足对时间的限制和要求。
  通常对于分时操作系统,软件的执行在时间上的要求并不严格,时间上的错误一般不会造成灾难性的后果。但对于实时操作系统,主要任务是要求对事件进行实时的处理,虽然事件可能在无法预知的时刻到达.但是软件上必须在事件发生时能够在严格的时限内做出响应(系统响应时间),即使能够响应,但是如果超出了时限,系统时间响应的超时就意味着致命的失败。实时操作系统的重要特点是具有系统的可确定性,即系统能对运行情况的最好和最坏等情况能做出精确的估计。
  实时多任务操作系统(RTOS)是嵌入式应用软件的基础和开发平台。目前大多数嵌入式开发还是在单片机上直接进行,没有RTOS,但仍要有一个主程序负责调度各个任务。RTOS是一段嵌入在目标代码中的程序,系统复位后首先执行,相当于用户的主程序,用户的其他应用程序都建立在RTOS之上。不仅如此,RTOS还是一个标准的内核,将CPU时间、中断、I/O、定时器等资源都包装起来,留给用户一个标准的API(系统调用),并根据各个任务的优先级,合理地在不同任务之间分配CPU时间。
RTOS是针对不同处理器优化设计的高效率实时多任务内核,RTOS可以面对几十个系列的嵌入式处理器MPU、MCU、DSP、SOC等提供类同的API接口,这是RTOS基于设备独立的应用程序开发基础。因此,基于RTOS的C语言程序具有极大的可移植性。据专家测算,优秀RTOS上跨处理器平台的程序移植只需要修改1%~4%的内容。在RTOS基础上可以编写出各种硬件驱动程序、专家库函数、行业库函数、产品库函数,和通用性的应用程序一起,可以作为产品销售,促进行业的知识产权交流。因此,RTOS又是一个软件开发平台。

评价

  一般情况下,考虑上下文切换等情况,RTOS系统的时钟周期最小为1ms。因此,RTOS里适用于构建ms级别的任务,不适合实时性很强的us级别任务。针对us级别的任务,应该在中断执行,而不是在RTOS创建的任务中执行。因为,电机控制这种us级别控制中,rtos使用需要慎重,针对双核芯片可以考虑采用。

针对硬件考虑算法效率

  ARM内核的芯片在通讯等控制上胜过DSP C28X内核,目前dsp28M35这样的arm和c28x混合内核很适合用于高性能的控制系统。
  在C28X内核的dsp中,有一类用于CLA模块的dsp存在,此类dsp可以独立运行算法程序,让C28X内核用于实现通讯和保护的功能。根据TI官网的介绍,CLA 是一款独立的 32 位浮点处理器,运行速度与主 CPU 相同。该 CLA 会对外设触发器作出响应,并与主 C28x CPU 同时执行代码。这种并行处理功能可有效加倍实时控制系统的计算性能。通过利用 CLA 执行时间关键型功能,主 C28x CPU可以得到释放,以便用于执行通信和诊断等其他任务。

数据结构

  首先需要注意芯片中数据类型的占用空间大小,以28335为例,28335单位中最小长度为是16bit,如果执行下面程序

count = sizeof(char);
count = sizeof(int);
count =  sizeof(double);
count =  (sizeof(long)
count =  (sizeof(short)
count =  (sizeof(float);

  观察变量结果可以看到

char : 1  (16bit)
int  : 1  (16bit)
double: 2  (32bit)
long: 2  (32bit)
short: 1  (16bit)
float: 2  (32bit)
long long: 4  (64bit)

结构体和共用体的通讯应用

  通讯是电机控制器的常见功能,具体有不同芯片之间的通信、芯片与上位机的通信,实现形式有IPC通讯、串口通信、can通信等,而这些通信方式往往是以字节byte为单位进行数据传输,如果只是传输8位类型数据则很好办,只需要直接发送就可以了,如果是整型数,可以通过移位函数进行处理。


	BYTE b1 =(BYTE) (word &0xff );//低八位
	BYTE b2 = (BYTE)(word << 8);//低八位
	BYTE b3 = (BYTE)(word >> 8);//高八位

  但是在float型数据时,4个字节这样处理很麻烦。C语言中,有一种称为联合体的数据类型,可以使不同的数据类型共享相同的地址空间。通过定义联合变量,将浮点数变量和对应的字节数组共享同一块内存空间———“共用体”,可以很好地解决上述问题。在TI的c2000处理器中经寄存器的位操作就是基于联合体数据类型。
  共用体定义:几种不同类型的变量存放到同一段内存单元中。也就是使用覆盖技术,几个变量互相覆盖,这种几个不同的变量共同占用一段内存的结构,所占内存长度是各最长的成员占的内存长度。
  结构体定义:把不同类型的数据组合成一个整体。所占内存长度是各成员占的内存长度的总和。
  以单精度浮点数为例进行说明,可以将一个float型数据进行如下处理

struct  FLOAT_BYTES// bytes  description
{
    Uint16    BYTE0:8;// 7:0 
    Uint16    BYTE1:8;// 15:8 
    Uint16    BYTE2:8;// 23:16
    Uint16    BYTE3:8;// 31:24
};
union FLOAT_REG
{
    float          all;
    struct FLOAT_BYTES     byte;
}CommData;

  可以看这一方式处理数据时,可以直接访问内存中浮点数以IEEE 格式存放在存储单元中的字节,通过直接读取或修改这些字节,便可以巧妙地实现浮点数与IEEE 格式的转换,这一过程无需额外计算,也不涉及浮点数的概念,只需要知道其占用多少字节。这一方法也可以用于int型数据传输。

CPU之间交互通讯

  前面位域操作将float类型数据转为了4个字节,是基于传送的数据是以字节为单位的。如果在CPU之间传送时,如28M35为例,M3和C28内核之间传送数据支持16位和32位数据传输,那么此时如果仍然按照字节为单位划分dsp时,传输效率过低,可以考虑操作上转为以字、甚至双字作为传输的最小单元。
如16位传输,传输单位是字(word)

struct  FLOAT_BYTES// bytes  description
{
    Uint16    BYTE0:16;// 15:0 
    Uint16    BYTE1:16;// 31:16 
};
union FLOAT_REG
{
    float          all;
    struct FLOAT_BYTES  word;
}CommData_Word;

  如32位传输时,传输单位是双字(Dword)

struct  FLOAT_BYTES// bytes  description
{
    Uint32    BYTE0:32;// 31:0 
};
union FLOAT_REG
{
    float          all;
    struct FLOAT_BYTES  dword;
}CommData_Dword;

  具体传输方法与以字节位传输单位类似,只是传输的最小单位变了。

结论

  利用C 语言中的union 将变量和单元数据共享同一段内存,通过直接对union 中的单元数据进行读写操作,即可实现对应原有变量的串行传输。通讯过程可以按照发送寄存器的大小建立单元数据区,传输效率高。在原有数据和单元数组之间没有复杂的数据类型转换代码存在,编程简单,数据准确。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值