一楼做目录
2楼: 一、智能车的组装
3楼:二、用NUCLEO或者Discovery板上带的st-link调试小车
4楼:三、程序目录说明
6楼:五、电机驱动控制分析
10楼:七、电机编码器的数据获取
11楼:八、蓝牙通讯实验
12楼:九、基于模型的两轮平衡车设计
13楼:十、两轮平衡车基于模型的设计流程
14楼:十一、基于模型的两轮车典型案例
15楼:十二、两轮平衡车的建模
18楼:十五、走8字算法仿真
19楼:十六、自动代码生成
一楼做目录
2楼: 一、智能车的组装
3楼:二、用NUCLEO或者Discovery板上带的st-link调试小车
4楼:三、程序目录说明
6楼:五、电机驱动控制分析
10楼:七、电机编码器的数据获取
11楼:八、蓝牙通讯实验
12楼:九、基于模型的两轮平衡车设计
13楼:十、两轮平衡车基于模型的设计流程
14楼:十一、基于模型的两轮车典型案例
15楼:十二、两轮平衡车的建模
18楼:十五、走8字算法仿真
19楼:十六、自动代码生成
一、智能车的组装
上周就收到包裹了,可惜没在单位,今天终于回来了
拆开包装发现每个零件都包的很严实,还是不错的。
打开每个零件之后感觉东西没有想的那么多啊,主要是都集成在电路板上了。
安装过程还是很简单的,将电池夹在电路板和车轮中间,用铜柱固定就好了。不过要主意电池的安装方向,避免不好接线。调试的时候可以考虑把亚克力板拿掉方便调试。
但是电机不像是新的,这点不太满意。
上电之后按一下按键,小车就可以立起来了,但是感觉不太平稳,需要再调整。
小车视频:
视频地址:http://player.youku.com/player.php/sid/XOTYzODA5NzM2/v.swf
二、用NUCLEO或者Discovery板上带的st-link调试小车
因为手里有nucleo和discovery板,上面已经集成了stlink v2,所以可以用来调试小车,而不需要额外再买下载器。
首先看nucleo的文档,断开写有st-link/nucleo的两个跳帽(下图cn2),此时nucleo就可以用来调试其他板子了。
这里我们只需用cn4的第二(SWCLK)、第三(GND)、第四(SWDIO)根线。
我们在看小车的原理图:
小车的stlink为J7,分别为PA13(SWDIO,板子正面写的IO),GND,PA14(SWCLK,板子正面的SCK)
将这三根线与nucleo进行连接:
就可以进行调试了。
在mdk中打开程序,点击options for target:
然后选Debug,ST-Link Debugger,Settings:(记得把前边的use点上)
就可以看到已经连接上板子了(SWDIO中有IDCODE和Name):
之后就可以进行调试并下载程序了。
三、程序目录说明(个人看法,欢迎大家讨论提问)
选择的资料文件是“Mini Balance V2.5 标准版源码(集成DMP 卡尔曼滤波 互补滤波)”
文件目录说明:
打开Project--STM32F10x_StdPeriph_Template--MDK-ARM--Project.uvproj就是项目的工程了。
打开工程,看左边的文件列表,这里的文件夹并不是和目录里的文件夹一一对应的(所以说比较乱,要是我们自己建工程的话,尽量做成一一对应的)。
工程目录说明:
User:main程序,也就是程序的入口点主程序;stm32f10x_it.c:写中断程序的文件,这里中断函数都是空,应该是分别写在了drivers中的各个文件中;实际上目录下还有stm32f10x_conf.h文件,这是用来筛选包含的头文件的,我们打开它可以看到:
就是将需要使用的头文件前边的注释符去掉;这个程序用到了exit(外部中断),gpio(io口),rcc(时钟),usart(串口),misc(中断)。
StdPeriph_Driver:st官方标准库,用到哪个就包含哪个,具体的设置在上边提到的stm32f10x_conf.h文件中,这里放的是从官方库中复制过来具体文件;
CMSIS:ARM Cortex™ 微控制器软件接口标准,是arm内核的通用程序,具体可以百度。
MDK-ARM:其实应该命名为Startup文件夹,因为放的是启动时最先加载的汇编文件,小车的芯片应该用的是其中的startup_stm32f10x_md.s;
Drivers:用户驱动,就是自己定义的关于led、串口、定时器等的驱动函数;
Mini-Balance:放的应该是滤波,oled显示,电机控制函数,也是小车能平衡和移动的重点。
另:点击keil上的这个按钮:
可以看到添加到工程的文件(自己添加时也是这么添加)
四、陀螺仪MPU6050简单分析
首先,网上关于mpu6050的帖子还是很多的,比如这篇加速度计和陀螺仪指南 ,详细的讲解了加速度计和陀螺仪的知识。
板上的mpu6050是通过I2C的方式与芯片进行连接的,关于i2c的介绍网上有很多,stm32芯片中集成了硬件i2c,在官方驱动库中也可以直接使用。看了一下示例程序,好像都是用位绑定和寄存器开发的程序,感觉不太容易看得懂,所以分享一下我用库函数写的简单的mpu6050的程序。(注:我这个工程里只是用了MPU6050的数据采集,没有其他功能)
首先,要使用st官方的i2c库,需要在stm32f10x_conf.h中将#include "stm32f10x_i2c.h"一行的注释取消:
在user目录下建立了mpu6050.c和mpu6050.h,
其中头文件内容为,地址可以通过查数据手册得到:
#ifndef __MPU6050_H #define __MPU6050_H #include "stm32f10x.h" /* MPU6050 Register Address ------------------------------------------------------------*/ #define SMPLRT_DIV 0x19 //陀螺仪采样率,典型值:0x07(125Hz) #define CONFIG 0x1A //低通滤波频率,典型值:0x06(5Hz) #define GYRO_CONFIG 0x1B //陀螺仪自检及测量范围,典型值:0x18(不自检,2000deg/s) #define ACCEL_CONFIG 0x1C //加速计自检、测量范围及高通滤波频率,典型值:0x01(不自检,2G,5Hz) #define ACCEL_XOUT_H 0x3B #define ACCEL_XOUT_L 0x3C #define ACCEL_YOUT_H 0x3D #define ACCEL_YOUT_L 0x3E #define ACCEL_ZOUT_H 0x3F #define ACCEL_ZOUT_L 0x40 #define TEMP_OUT_H 0x41 #define TEMP_OUT_L 0x42 #define GYRO_XOUT_H 0x43 #define GYRO_XOUT_L 0x44 #define GYRO_YOUT_H 0x45 #define GYRO_YOUT_L 0x46 #define GYRO_ZOUT_H 0x47 #define GYRO_ZOUT_L 0x48 #define PWR_MGMT_1 0x6B //电源管理,典型值:0x00(正常启用) #define WHO_AM_I 0x75 //IIC地址寄存器(默认数值0x68,只读) #define SlaveAddress 0xD0 //IIC写入时的地址字节数据 void MPU6050_Init(void); void InitMPU6050(void); unsigned int GetData(unsigned char REG_Address); #endif
在mpu6050.c中添加需要使用的函数,包括:
外部调用的:
void MPU6050_Init(void);//调用I2C_GPIO_Config()和I2C_Mode_Config()进行初始化
void InitMPU6050(void);//写入初始化命令
unsigned int GetData(unsigned char REG_Address);//获得数据
内部调用的:
void I2C_GPIO_Config(void)
void I2C_Mode_Config(void)
void I2C_ByteWrite(uint8_t REG_Address,uint8_t REG_data)//写一个字节
uint8_t I2C_ByteRead(uint8_t REG_Address)//读一个字节
具体函数请参见工程,主要就是配置I2C所使用的GPIO口和I2C本身的配置,然后调用I2C的官方库函数进行控制命令的写入和数据的接收。
主函数中,将获得的数据通过串口发送出来(串口是用的现成的驱动,包含了usart1.c和usart1.h):
int main(void) { /* Add your application code here */ USART1_Config(); MPU6050_Init(); InitMPU6050(); /* Infinite loop */ while (1) { printf("\r\n---------加速度X轴原始数据---------%d \r\n",GetData(ACCEL_XOUT_H)); printf("\r\n---------加速度Y轴原始数据---------%d \r\n",GetData(ACCEL_YOUT_H)); printf("\r\n---------加速度Z轴原始数据---------%d \r\n",GetData(ACCEL_ZOUT_H)); printf("\r\n---------陀螺仪X轴原始数据---------%d \r\n",GetData(GYRO_XOUT_H)); printf("\r\n---------陀螺仪Y轴原始数据---------%d \r\n",GetData(GYRO_YOUT_H)); printf("\r\n---------陀螺仪Z轴原始数据---------%d \r\n",GetData(GYRO_ZOUT_H)); delay_ms(1000); } }
五、电机驱动控制分析
直流电机是利用通电线圈在磁场中受到磁场力矩的作用后会发生转动的原理。通常直径越大,电机扭力也越强。由于直流电极转速高、扭力小,用于控制时通常增加减速装置,就是小车用的减速电机。
通常用的直流电机驱动电路是H桥电路,一般包括4个场效应管和一个电机。如图。要使电机转动,必须导通对角线上的一对场效应管,根据不同的导通情况,电流可能会从左至右或从右至左流过电机,从而实现电机不同方向的转动。
电流方向只能实现电机的正转和反转,但不能实现电机的速度控制,这时就需要采用PWM技术(脉宽调制),是利用处理器的数字输出来控制模拟电路的一种技术,它实质上是把恒定的直流电源电压调制成频率一定,宽度可变的脉冲电压序列,从而改变平均输出电压的大小,达到控制电机转速的目的。
小车的驱动芯片采用的是TB6612FNG芯片,具有大电流MOSFET-H桥结构,双通道电路输出,可同时驱动2个电机。
根据原理图,电机分别由PB1(PWMA),PB14(AIN1),PB15(AIN2)和PB0(PWMB),PB12(BIN2),PB13(BIN1)来控制,其他引脚已接好。按照下图真值表可以进行控制的设计。
经过以上说明,其实电机的控制并不难,就是需要产生合适的PWM输出进行控制。
下一贴将学习stm32芯片的PWM的产生方式~
六、使用STM32定时器产生PWM输出
以前也不太会使用定时器,正好借这个机会学习一下~
stm32芯片一共有8个16位定时器:TIM6和TIM7是基本定时器;TIM2,3,4,5是通用定时器;TIM1,8是高级定时器;定时器具有定时、信号频率测量、PWM输出、步进电机、编码器接口等功能。
它们的区别是:
基本定时器:只具有基本功能,即累加的时钟脉冲超过预定值时,触发中断或者DMA请求,可以作为其他通用定时器的始 终基准;时钟源是TIMxCLK,时钟源经过PSC分频输入至TIMx_CNT,基本定时器只能工作在向上计数模式,在TIMx_ARR中保存溢出值,工作时, 脉冲计数器 TIMx_CNT由时钟触发进行计数,当其值达到TIMx_ARR中的值时,产生溢出,触发中断,然后TIMx_CNT清零,重新向上计数
通用定时器:除了基本定时期的功能,还具有测量输入脉冲频率、脉宽,输出PWM,编码器接口等功能。它相比于基本定时器,多出了一个捕获/比较寄存器TIMx_CCR,在输入时捕获脉冲在电平翻转时TIMx_CNT中的值,实现频率测量;在输出时可以存储一个值,把这个值与TIMx_CNT中的值比较,从而输出不同的高低电平;
(根据新版的程序,应该使用TIM3的CH3和CH4产生的PWM输出)
PWM输出过程:TIMx_CCR被用作比较寄存器;若TIMx_CNT被配置为向上记数模式,值为X,将TIMx_ARR的值配置为N,则TIMx_CNT的X值不断累加,达到N时会置0并重新计数;计数的同时,TIMx_CNT中的值会与TIMx_CCR的值A进行比较,X小于A时输出高电平(或低),X大于A时输出低电平(或高),如此循环,就可以得到周期由TIMx_ARR的值所控制的(N+1乘以时钟周期),脉冲宽度由A所控制的,占空比为A/(N+1)的PWM输出。
高级定时器:除了有基本、通用定时器的所有功能,还有三相6步点击接口,PWM驱动电路的死区时间控制等功能。
要配置PWM输出,需要一下2个步骤:
1设置GPIO口
2设置定时器TIM3
在版主发的程序中设置程序在motor.c文件中,采用寄存器操作(可惜不会。。。),有详细的注释,可以看一看;我之前都是用库函数写的,所以再用库函数写一个试试吧。
电机接口应该是GPIOB12,13,14,15,输出用的是TIM3的CH4和CH3;
先配置GPIO口:
void MiniBalance_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB, ENABLE); //使能端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;//PB0和PB1的默认复用功能对应CH3和CH4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
设置完端口就可以设置定时器模式,产生PWM:
void MiniBalance_PWM_Init(u16 arr,u16 psc)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;//时基初始化结构体
TIM_OCInitTypeDef TIM_OCInitStructure;//模式配置结构体
TIM_TimeBaseStructure.TIM_Period =aar; //定时周期,存储到TIMx_ARR的值
TIM_TimeBaseStructure.TIM_Prescaler = psc; //预分频的值,对TIMxCLK分频
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1 ;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC3Init(TIM3, &TIM_OCInitStructure);
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OC4Init(TIM3, &TIM_OCInitStructure);
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable);
TIM_ARRPreloadConfig(TIM3, ENABLE);
TIM_Cmd(TIM3, ENABLE);
}
另外:库函数中
void TIM_SetCompare3 | ( | TIM_TypeDef * | TIMx, |
uint16_t | Compare3 | ||
) |
七、电机编码器的数据获取
电机的编码器其实就是一种传感器,可以把旋转位移转换成一串数字脉冲信号,MCU可以读取这段脉冲信号通过计数来获取电机的转速。
小车的原理图中显示编码器的接口分别为PA0和PA1,PB6和PB7:
查询datasheet:
PA0和PA1对应着TIM2,PB6和PB7对应着TIM4.所以系统应该采用定时器2和4分别对编码器结果进行计数。
参考数据手册中定时器用作编码器接口模式的内容:选择编码器接口模式的方法是:如果计数器只在TI2的边沿计数,则置TIMx_SMCR寄存器中的SMS=001;如果只在TI1边沿计数,则置SMS=010;如果计数器同时在TI1和TI2边沿计数,则置SMS=011。 通过设置TIMx_CCER寄存器中的CC1P和CC2P位,可以选择TI1和TI2极性;如果需要,还可以对输入滤波器编程。 两个输入TI1和TI2被用来作为增量编码器的接口。参看表77,假定计数器已经启动(TIMx_CR1寄存器中的CEN=’1’),计数器由每次在TI1FP1或TI2FP2上的有效跳变驱动。TI1FP1和TI2FP2是TI1和TI2在通过输入滤波器和极性控制后的信号;如果没有滤波和变相,则TI1FP1=TI1,TI2FP2=TI2。根据两个输入信号的跳变顺序,产生了计数脉冲和方向信号。依据两个输入信号的跳变顺序,计数器向上或向下计数,同时硬件对TIMx_CR1寄存器的DIR位进行相应的设置。不管计数器是依靠TI1计数、依靠TI2计数或者同时依靠TI1和TI2计数。在任一输入端(TI1或者TI2)的跳变都会重新计算DIR位。 编码器接口模式基本上相当于使用了一个带有方向选择的外部时钟。这意味着计数器只在0到TIMx_ARR寄存器的自动装载值之间连续计数(根据方向,或是0到ARR计数,或是ARR到0计数)。所以在开始计数之前必须配置TIMx_ARR;同样,捕获器、比较器、预分频器、触发输出特性等仍工作如常。
可以看出需要配置定时器的CCMR,CCER,SMCR和CR1寄存器。定时器2的配置为:
void Encoder_Init_TIM2(void) { RCC->APB1ENR|=1<<0; RCC->APB2ENR|=1<<2; GPIOA->CRL&=0XFFFFFF00;//PA0 PA1 GPIOA->CRL|=0X00000044; TIM2->PSC = 0x0; TIM2->ARR = ENCODER_TIM_PERIOD-1; TIM2->CCMR1 |= 1<<0; TIM2->CCMR1 |= 1<<8; TIM2->CCER |= 0<<1; TIM2->CCER |= 0<<5; TIM2->SMCR |= 3<<0; //SMS='011' TIM2->CR1 |= 0x01; }
最后,读取编码器数据的函数按照示例为:
int Read_Encoder(u8 TIMX) { int Encoder_TIM; switch(TIMX) { case 2: Encoder_TIM= (short)TIM2 -> CNT; TIM2 -> CNT=0;break; case 3: Encoder_TIM= (short)TIM3 -> CNT; TIM3 -> CNT=0;break; case 4: Encoder_TIM= (short)TIM4 -> CNT; TIM4 -> CNT=0;break; default: Encoder_TIM=0; } return Encoder_TIM; }
从CNT寄存器中读取数据。
八、蓝牙通讯实验
通过原理图来看,小车与蓝牙模块的通信应该是通过串口来进行的:
所用引脚为PB10和PB11,查芯片手册可以看出是USART3的接收和发送口。
所以蓝牙控制的原理就是蓝牙模块接收手机客户端发送的指令,通过串口把规定好的指令发送给mcu,产生串口中断,然后mcu控制电机进行相应的动作。查看相关串口程序,串口的初始化:
void uart3_init(u32 pclk2,u32 bound) { float temp; u16 mantissa; u16 fraction; temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV mantissa=temp; //得到整数部分 fraction=(temp-mantissa)*16; //得到小数部分 mantissa<<=4; mantissa+=fraction; RCC->APB2ENR|=1<<3; //使能PORTB口时钟 RCC->APB1ENR|=1<<18; //使能串口时钟 GPIOB->CRH&=0XFFFF00FF; GPIOB->CRH|=0X00008B00;//IO状态设置 GPIOB->ODR|=1<<10; RCC->APB1RSTR|=1<<18; //复位串口1 RCC->APB1RSTR&=~(1<<18);//停止复位 //波特率设置 USART3->BRR=mantissa; // 波特率设置 USART3->CR1|=0X200C; //1位停止,无校验位. //使能接收中断 USART3->CR1|=1<<8; //PE中断使能 USART3->CR1|=1<<5; //接收缓冲区非空中断使能 MY_NVIC_Init(3,3,USART3_IRQn,2);//组2,最低优先级 }
串口的中断程序:
void USART3_IRQHandler(void) { if(USART3->SR&(1<<5))//接收到数据 { static int uart_receive=0;//蓝牙接收相关变量 uart_receive=USART3->DR; if(uart_receive<10) mode_data[0]=uart_receive; if((mode_data[0]==six_data_2[0] &&mode_data[1]==six_data_2[1] &&mode_data[2]==six_data_2[2] &&mode_data[3]==six_data_2[3]) ||(mode_data[0]==six_data_1[0] &&mode_data[1]==six_data_1[1] &&mode_data[2]==six_data_1[2] &&mode_data[3]==six_data_1[3])) { Flag_Stop=!Flag_Stop; mode_data[0]=0; mode_data[1]=0; mode_data[2]=0; mode_data[3]=0; } if(uart_receive==0x00) Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////刹车 if(uart_receive==0x01) Flag_Qian=1,Flag_Hou=0,Flag_Left=0,Flag_Right=0;//////////////前 if(uart_receive==0x05) Flag_Qian=0,Flag_Hou=1,Flag_Left=0,Flag_Right=0;//////////////后 else if(uart_receive==0x02||uart_receive==0x03||uart_receive==0x04) Flag_Qian=0,Flag_Hou=0,Flag_Left=0,Flag_Right=1; else if(uart_receive==0x06||uart_receive==0x07||uart_receive==0x08) Flag_Qian=0,Flag_Hou=0,Flag_Left=1,Flag_Right=0; mode_data[7]=mode_data[6]; mode_data[6]=mode_data[5]; mode_data[5]=mode_data[4]; mode_data[4]=mode_data[3]; mode_data[3]=mode_data[2]; mode_data[2]=mode_data[1]; mode_data[1]=mode_data[0]; } }
可以看出,通过蓝牙指令可以修改以下几个值,就可以控制小车做出动作。
Flag_Qian,Flag_Hou,Flag_Left,Flag_Right
九、基于模型的平衡车设计概述
概述
本文作为技术贴,主要是以两轮自平衡车为研究对象,介绍采用先进的“基于模型的设计”方法进行机电控制系统的开发,讲解“基于模型的设计”的理念和优势、开发工具,涉及到机电系统建模、控制算法设计、自动代码生成等关键技术。
由于时间和水平有限,本文更多的是作为知识普及和原理介绍,为控制系统开发人员提供思路,故下面的内容多少会有很多不足和纰漏之处,请大家谅解和多多指导。
基于模型的设计概述下面简单介绍下:什么是模型?什么是基于模型的设计?为什么要用基于模型的设计?
什么是模型本文提到的模型主要是指数学模型。以控制系统为例,可分为被控对象和控制器。通常,被控对象可以通过数学建模方法得到,如下图中的直流电机,可以通过物理原理分析,建立系统方程,再通过建模工具建立模型;控制器模型根据系统任务、要求及被控对象模型特性进行设计,可以通过图形化的方法进行搭建,再通过仿真、优化等方法进行参数调节。
基于模型的设计,即Model-Based Design,简称MBD,是一种采用模型仿真来开发、测试软件的设计技术,包括:可执行的规范、仿真与设计、自动代码生成和持续不断的测试和验证4部分要点。与传统的开发方式不同,基于模型的设计是以数学模型为核心,将前期的方案验证、详细设计、软件实现和系统测试都贯穿起来,不断地复用模型,细化模型。
以控制系统的开发为例,进行说明。首先,设计人员根据设计方案来搭建系统仿真模型,并进行仿真,验证方案是否合理;然后,通过各种仿真设计工具对控制系统进行详细设计;其次,将经过仿真验证的控制算法模型,自动生成代码,集成到实际的控制器中;最后,进行系统集成,如果发现问题,则可追溯到模型的某个部分,进行修改和迭代。
为什么用基于模型的设计
基于模型的设计是在当前控制系统的发展趋势和传统开发流程越来越不满足要求的情形下才产生的。在当今,控制系统已经融入到我们的生活、工作各个方面,出现越来越多的智能控制系统,算法的作用和软件的功能越来越重要。以一个商用车为例,目前的代码量已经达到了几千万行。所以对开发人员的要求和挑战越来越高。
传统的开发流程采用瀑布式,包括方案、设计、实现和测试,即前期根据经验来做设计方案,通过手写代码实现,当系统完成后才能进行充分的测试,这时难免会发现很多问题,而需要不断地返工,使得开发周期长、人力成本高。
基于模型的设计为了弥补传统流程的缺陷,提供了一系列的工具,使得:
(1)在开发的早期发现错误;
(2)通过模型验证提高了测试效率;
(3)提高了开发者之间的沟通效率;
(4)自动生成代码减少了编码时间和编码错误。
工具的选用
目前,对于控制系统的开发来说,主流的工具是美国Mathwork公司推出的MATLAB软件。MATLAB从2006年开始,每年有2个版本更新,目前最新版本是R2015b。在大多数人眼里,可能MATLAB就是个做数学运算的软件。但其实MATLAB可以作为一个产品开发工具来使用。从下图可以看出,MATLAB包含很多工具箱,主要分成MATLAB、Simulink两大部分。MATLAB是所有模块的基础,通过M代码进行运算、画图、分析等,在此基础上针对不同领域有不同的toolbox,如控制、图像、信号等;Simulink是MATLAB基础上的用于系统建模仿真的图形化工具,同样有不同应用领域的扩展模型库;而作为连接仿真研究和实际应用的桥梁,MATLAB推出了一系列的代码生成工具,如MATLAB coder、Embedded coder可分别将M函数、mdl模型自动生成C源代码,这样免去了手写代码的麻烦和可能出现的问题。
小结
想进一步了解“基于模型的设计”,可以看mathwork官网上的视频短片和相关案例,推荐看刘杰老师的相关书籍。
再提一点,学习MATLAB的方法,一定要重视MATLAB的help,里面有很多资源和例程,还有mathwork官网上定期录制的网络研讨会视频可作为入门学习材料。
打赏帖 | |
---|---|
【S32K146】S32DS watchdog 配置使用被打赏20分 | |
【Zephyr】使用 IAR 调试 Zephyr 镜像被打赏20分 | |
【Zephyr】MCXN947 Zephyr 开发入门适配shell被打赏20分 | |
【我要开发板】6.联合MATLAB记录数据被打赏50分 | |
【瑞萨RA2E1开发板】:使用ADC功能实现位移传感器采集方案被打赏20分 | |
【nRF7002DK】基于sht30的温湿度计被打赏20分 | |
【nRF7002DK】日志打印被打赏20分 | |
【换取手持示波器】RGB屏幕移植ARM-2D库被打赏35分 | |
【分享开发笔记,赚取电动螺丝刀】分享一下如何解决瑞萨RA2E1使用printf编译报错问题被打赏27分 | |
rtthread硬件加密-5hash加密分析被打赏10分 |