记录机械臂关节FOC开发全流程
文章目录
概要
机械臂关节开发完整步骤,本例程将持续进行更新
记录一下工作中的开发机械臂关节的FOC流程,此次主控芯片采用stm32g431,预驱芯片是TI的8353,编码器有两款,均采用MBS的磁编码器,分单编和双编两版,和MCU的通信采用RS485通信进行。外加一路PWM驱动刹车盘来进行电机刹车控制。通信采用CAN和EtherCat进行配置。本次会一步一步进行实现外设驱动、电机控制FOC算法,应用层状态机进行配置,应用层软件直接调用HAL库接口,最后则是一些常见的踩坑细节,也会详细进行记录。顺便记录一下各种好用的工具使用,例如Sourceinsight进行代码阅读和编写等(比Keil等IDE更好用)。
整体架构流程
会一部分一部分进行修改
1.工程搭建以及使用Free RTOS实现LED点灯
本次工程采用CubeMX进行底层Hal库的生成,目前来说手写驱动不太现实,我相信也没人会这么干。由于之前的工程采用IAR,本次为了进行不一样的实现,采用keil IDE来进行代码的编译、烧录以及仿真。Free RTOS可用也可不用,只是因为cubemx可直接集成FreeRTOS所以才使用FreeRTOS,一般来说裸机跑也是可以的。
1.1 工程搭建
打开Cube MX后选择stm32g431cbu6芯片,也是本次开发所采用的主控芯片,然后保存到自己创建的工程文件夹(tips:保存的文件夹名后续也会成为工程名,所以创建文件夹时最后见名知义工程名可在project manager中更改),工程搭建就以及完成了。
1.2 烧录和时钟配置
首先依次点击System Core->SYS,然后在Debug处选择Serial Wire(Serial Wire表示SWD接口,对应两线的SWD接口调试,也可选JTAG调试,根据自己的原理图进行选择)。此时芯片会有两个引脚被占用,对应SWDIO和SWCLK。
然后点击System Core->RCC,HSE选择Crystal/Ceramic Resonator(外部无源晶振)。另一个是外部有源晶振,Disable是使用内部时钟,一般不使用,会影响主频精度。
最后是时钟树的配置了,主要是产生主频来给内核和外设提供同步时钟频率,如果没主频输出MCU不会工作。在Clock Configuration中进行配置,设置input frequency为24Mhz(根据原理图配置如果不配置会程序会进入HardFaultHandle,时钟配置错误),然后从左到右勾选HSE和PLLCLK,此时HSE经过PLL倍频后就到了SYSCLK了,然后在HCLK处输入170(G431最大主频)即可设置主频为170MHz。
至此烧录和时钟设置完成
1.3 LED及FreeRTOS配置
在Pinout View中选择PC13,设置其为GPIO_OUTPUT。IO输出即可驱动外部LED亮灭。然后设置其User Label为LED,由于外部电路设计是高电平点亮LED,为了上电后LED处于灭的状态,因此设置GPIO Output Level为low,设置模式为推挽输出,不上拉也不下拉,PC13的输出速度只能选择Low.至此,LED配置完成.
在MiddleWare and software中选择Free RTOS,在Interface中选择Free RTOS版本,V1更基础但资源消耗更小,V2更强大但资源消耗过多.这里先择V1,其他配置先不动,后续有需要再变更.这里要设置Task,点击Tasks and Queues,然后修改Task,将Task Name和Entry Function中的Default更改为LED,这个看个人喜好,一个是任务名,一个是入口函数.将stack size改为64words(最小),因为LED不需要太多的资源,很多时候都可以不创建这个Task的,不过是个人认为资源够用以及可以用LED监控程序有没有正常运行,启到一个看门狗的作用,所以任务优先级设置为Low,至此,LED和FreeRTOS设置完成.
1.4 代码生成
点击Project Manager,在Toolchain/IDE中选择MDK-ARM,min version选择V5即可,其余先不进行设置.
然后在code generator中选择copy only the necessary library file,这样可以减少代码文件大小,只拷贝需要的文件.
在Generate files中勾选Generate peripheral…这个选项,可以生成对应的.c和.h文件,方便调用.
Advanced setting选择Hal库就行,LL库太晦涩难懂了,之前有用过,可以在关键代码中使用LL库.
然后点击Generate Code生成代码和工程文件即可.
备注:这时候还需要更改一个东西,由于使用了FreeRTOS,占用了systemTick,因此需要将sys中的Timebase Source 更改为其他定时器,这里更改为暂时用不到的TIM17.这样就避免了时钟冲突,之前调试过程中发现如果不更改的话Hal_Delay就会和FreeRTOS的delay冲突,造成程序卡死在Hal_Delay中.
1.5 编译烧录及认证
打开keil MDK工程,点击编译即可完成编译.
烧录需要更改相应的烧录配置,这里使用Jlink和之前配置的SWD接口.点击Option for target,在Debug的setting中选择use选项选择J-link/j-trace cortex,然后点击setting,进去之后在Port中选择SWD(默认是JTAG).如果在SW Device中出现相关内容,则说明接线这些都正确,如果未出现,那大概率是识别失败,要检查硬件连接和烧录器以及板子是否是好的.然后确定退出.
接下来要编写测试代码,这里测试LED每1s亮灭各一次.在FreeRTOS的app_freertos.c文件中,有一个startLedTask函数,就是之前cubemx中配置的entry function函数名,在函数体中输入如下代码:
TickType_t xLastWakeTime;
xLastWakeTime = xTaskGetTickCount(); // 获取当前时间
while (1)
{
// 执行任务
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_SET);
vTaskDelayUntil(&xLastWakeTime, 500);
HAL_GPIO_WritePin(GPIOC,GPIO_PIN_13,GPIO_PIN_RESET);
vTaskDelayUntil(&xLastWakeTime, 500);
}
在此处使用绝对延时函数,这里是个人习惯,比较加入FreeRTOS就是为了让代码在对应的时间执行相应的事件.这里是500ms亮,500ms灭.
这里编译会报错undefined symbol vTaskDelayUntil,这是因为Free RTOS配置时没包含生成vTaskDelayUntil函数,此时返回cubemx中在Free RTOS的Include Parameters中使能vTaskDelayUntil即可编译通过.
在flash download中勾选reset and run,否则代码不会造成运行,然后点击下载即可看到LED1s一次亮灭,也可用示波器量LED两边的电压,会是500ms高电平,500ms低电平.
至此,第一章配置完成,后续所有代码均基于此工程进行配置.
2.制动器(PWM)
制动器会涉及到一些硬件的内容.
正常来说,制动器由永磁体和线圈组成,和电磁阀是很类似的.正常断电状态下处于常闭状态,工作时需要给线圈通电,抵消永磁体产生的磁力,保证电机转子处于可以自由转动的状态.
即:通电->电机轴可正常活动.断电->电机轴锁死,以保证断电状态下电机轴不会偏离,保存上一次的运转角度.
而对制动器的打开和关闭操作需要对线圈进行通电或者断电,根据制动器的手册可以得到其通电所需电压,然后通过PWM调制生成对应的电压,即
占空比 = 所需电压/母线电压
而其频率一般设置为20Khz,也有其他设置方法,或者根据制动器手册进行设置,这里设置为20Khz.
进入cubemx继续进行相关设置.相关引脚为PB9,对应TIM4_CH4,则在Timers->TIM4->channel4中设置其为PWM Generation CH4.
然后配置PWM频率:
PWM频率 = TIM频率 / ((PSC + 1) * (ARR+1))
根据时钟树可知TIM频率为170Mhz,PSC设置为0,即不进行分频,然后ARR设置为4250(和4249没有太多差别,为了方便计算).可设置频率为20Khz
设置CounterMode为向上对齐,auto-reload preload设置为Enable.其余配置默认即可.
点击Generate code即可完成配置代码生成.
然后再tim.c文件中找到MX_Tim4_Init函数,在函数最后加上使能PWM输出即:
HAL_TIM_PWM_Start(&htim4,TIM_CHANNEL_4);
然后定义宏
#define BRAKEDUTY (3187) //暂时只有32V下占空比 = 24/32 * 4250,后续有测得电压再继续更改
#define BRAKEON __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, BRAKEDUTY);
#define BRAKEOFF __HAL_TIM_SetCompare(&htim4, TIM_CHANNEL_4, 0);
然后就可以在之前的FreeRTOS的task中进行测试了,测试时采用5s开,5s关的模式,打开时电机轴可正常转动,关闭时电机轴无法转动.而且一般开关制动器是可以听到声音的.可根据实际情况调节频率和占空比.
至此,制动器调试完成,用到stm32的简单PWM模块.
3.FDCAN
正常机械臂是需要和外界进行通信的,此产品有两种通信方式,一种是FDCAN,一种是Ethercat,CAN通信采用自定义通信协议,Ethercat采用CIA402协议,这种后续再进行讨论.
本章节主要讨论CAN通信,发送CAN报文使用周期报文或者回复报文,接收在中断中进行接收.
在cubemx中依次点击Connectivity->FDCAN1->Activated即可使能FDCAN.这时Pinout View中即可看到FDCAN的Tx和Rx两个引脚,只需要再接一个CAN收发器即可正常完成CAN通信的外部电路,因为STM32的CAN控制器已经集成在芯片中了.接下来需要对FDCAN进行配置.配置如下:
| 名称 | 参数 | 说明 |
|---|---|---|
| FD Format | Classic mode | 采用经典CAN,不使用FDCAN |
| Auto Transmission | Disable | FDCAN特性不使用 |
其余先不进行设置,最主要的是要配置FDCAN的波特率,由于是经典CAN,数据域和仲裁域的波特率是一致的,以Nominal为准,此时需要修改三个参数Nominal prescaler , Nominal time seg1和2,调整这三个参数让Nominal Baud rate为1Mbps.这里设置为5,10,23,波特率就等于1Mbps了.(有计算公式,但是懒得算了).然后再NVIC setting中使能FDCAN中断,并设置其中断优先级,Free RTOS设置后中断优先级最高设置为5,为了保证电机相关外设的优先级最高,通信的优先级处于中间位置,所以FDCAN的抢占优先级设置为10,子优先级设置为0即可,这是用到的第一个用户中断,其余均为系统中断,后续根据需求再进行更改.然后生成代码.
这时候需要写三个配置,第一是CAN过滤器(接收过滤),看需要接收哪些ID,需要屏蔽哪些ID,第二是发送函数,第三是接收函数(中断接收).
过滤器配置如下:
FDCAN_FilterTypedef filter;
filter.IdType = FDCAN_STANDARD_ID;
filter.FilterType = FDCAN_FILTER_RANGE;
filter.FilterID1 = 0x0;
filter.FilterID1 = 0x7FF;
filter.FilterIndex = 0;
if(HAL_FDCAN_ConfigFilter(&hfdcan1, &filter) != HAL_OK)
{
Error_Handle();
}
if(HAL_FDCAN_start(&hfdcan1) != HAL_OK)
{
Error_Handle();
}
if(HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, 0) != HAL_OK)
{
Error_Handle();
}
然后是发送代码,发送需要发送ID和数据,长度先固定八字节:
FDCAN_TxHeaderTypeDef txHeader;
uint8_t TxData[8] = {0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08};
void CAN_SendMessage(void)
{
TxHeader.StdId = 0x123;
TxHeader.RTR = CAN_RTR_DATA;
TxHeader.IDE = CAN_ID_STD;
//根据需要进行配置,这里先不写全部代码了
TxHeader.DLC = 8;
if (HAL_CAN_AddTxMessage(&hcan, &TxHeader, TxData, &TxMailbox)!= HAL_OK)
{
Error_Handler();
}
}
然后是接收代码:
利用weak的接收函数:
FDCAN_RxHeaderTypeDef RxHeader;
uint8_t RxData[8];
void CAN_ReceiveMessage(void)
{
if (HAL_CAN_GetRxMessage(&hcan, CAN_RX_FIFO0, &RxHeader, RxData) == HAL_OK)
{
CAN_SendMessage();
}
}
最后进行收发测试即可.这里有点踩坑,在收发的时候一定要每个参数都去检查,下来就是波特率的计算,很容易导致出错,收发测试时ZCanpro经常出现丢失在位错误,一般都是由于波特率设置错误导致的.
至此,CAN通信也开发完成.具体的通信协议可以自己决定.
这块很多我自己也没搞明白,有时候波特率设置对了还是会出错,可能是芯片本身原因,然后要自己写,每个参数都是要弄懂是什么意思,这样写出来的代码才不会出现这样或者那样的问题,最后是一定要自己学会调试,写代码远比调试要简单很多,调试的时候才会踩很多坑。这里我就遇到了很多坑,最明显的就是关于波特率的设置,这个还是得去了解其具体原理,还要就是stm32的can只有三个mailbox,1ms只能发送三帧报文,这个在后续的读取三相电流时间是不够的,如果还有多余的串口,可以考虑用VOFA+。
4.DRV芯片配置(SPI进行配置)
此章开始就开始涉及正式的FOC算法的外设搭建了。
首先是关于DRV芯片的配置,DRV芯片和MCU的12个IO有连接,分别是:1组SPI(4pin),1个Enable脚,三相PWM和1相INL,采用DRV8353芯片的3PWM模式进行驱动,即MCU的INL脚连接DRV芯片的INLA,INLB,INLC引脚,然后INHA、INHB、INHC连接DRV的这三个引脚,控制模式可理解为INL为低时,INH不管输入什么GH和GL都为低电平,当INL为高时,根据INHABC的输入,GHX和GLX会正常输出互补的电平,所以控制就比较简单了,由于物理层面的限制,只能使用3PWM模式,所以MCU在上电时给INL高电平,使能,然后INH三相先全部输出0占空比的PWM,后续让电机转动时再输出相应PWM(FOC算法最终结果)。
4.1Enable脚和INL脚配置
DRV芯片要使能,首先要让Enable和INL均输出高电平,后续也可根据需求重新使能DRV芯片(例如DRV芯片失效需要重新使能),所以两个的配置均要推挽输出高电平,配置就可正常完成了。至此,两个使能引脚就算配置完成了,但是,根据DRV芯片手册,Enable使能后1ms才能正常进行SPI通信,因此需要在使能Enable之后delay 1ms。
4.2SPI配置
配置SPI需要了解以下几个参数,可查阅DRV芯片手册进行补全。
| 参数 | 值 |
|---|---|
| 时钟极性 | 低 |
| 相位 | 第二个时钟沿 |
| 数据位序 | MSB First |
| 数据帧大小 | 16位 |
| 最大时钟频率 | 10Mbps |
根据上面的参数先配置物理层的SPI,在cubemx中配置。
设置SPI2模式为Full-Duplex Master模式。
设置Hardware NSS output signal。
Frame Format设置为Motorola。
Data Size设置为16bits。
First Bit配置为MSB first。
波特率根据频偏来分频,设置为5Mbps左右,不超过10M应该都可以。
其余按上述表格配置,然后生成代码,至此SPI配置完成。
注意如果SPI的CS脚如果没有外部上拉,则需要配置成普通IO来充当CS脚,需要进行手动管理。还需要注意这里波特率不能设置过高,正常1Mbps到2Mbps就可以,实际没办法达到理论的10M,甚至5M都不行,这个是在后边测试过程中发现的。
4.3SPI接口代码编写和测试
SPI配置完成后需要了解SPI的接口函数,能用到的有以下两个:初始化和发送接收,初始化在main函数中已经调用,那就需要在while(1)或者其他地方来进行对传输函数的测试了,由于从机使用的是DRV芯片,在这里顺便编写好DRV芯片的接口。
由于DRV芯片采用16位的传输,第一位为读写位,接下来4bit为地址位,最后11位为读写数据,为uint16_t格式,采用MSB格式,读写位在最高位,因此为了简化操作,可用共用体来实现,这样方便进行数据编写,共用体结构如下:
typedef union
{
uint16_t data;
struct{
uint16_t spiData : 11;
uint16_t addr : 4;
uint16_t cmd : 1;
};
}DrvConfig_u;
cmd为0或者1进行读写,addr为4位地址,spiData为写入或者读取的数据信息。
此处keil需要勾选GNU extension 选项,因为匿名结构体需要GUN -c
然后调用spi读写函数进行读写操作。
例如,往0x4地址写入0xA的操作如下:
DrvConfig_u sendData, recvData;
sendData.cmd = 0;
sendData.addr = 0x4;
sendData.spiData = 0xA;
HAL_SPI_TransmitReceive(&hspi2, (uint8_t *)(&sendData.data), (uint8_t *)(&recvData.data), 2, HAL_MAX_DELAY);
这样即可往0x4地址写入0xA数据,读取同理。
SPI需要大量调试经验,有测试点或者硬件水平比较好可以飞线出来用示波器或者逻辑分析仪看波形正确与否,一般来说如果没有波形就是配置哪里漏了,可以用软件SPI(IO模拟)先测试,然后就可能是CS脚高低和帧间隔以及速度的问题了,最后则可能是时钟频率过快的原因,可适当缩短硬件SPI的波特率了,目前为止,我的CS引脚都是直接用IO进行控制的,因为SPI的hardware控制还是有些许问题,这里是目前位置踩坑比较多的地方,其实嵌入式就是一直重复踩坑的过程,哪怕你经验很足,该踩的坑还是要踩的,因为有的不一定是你自己的问题,也可能是硬件电路或者芯片本身的缺陷造成的。
4.4DRV芯片的配置
DRV芯片配置并不难,但是需要了解几个特点的名词,比如死区,PWM模式,OCP,还有放大倍数等,这些都是根据实际的硬件进行调整的,DRV8353的芯片寄存器不多,总共8个,也不太难看懂,想快速开发就可以先按默认配置进行就可以,都是PWM模式必须根据硬件原理图进行配置,不然驱动的PWM波形就可能是紊乱的。
后续可根据实际工程测试数据进行调整。当然,我一般比较懒,基本不会去调整,除非真的有很大问题,因为嵌入式这一行一般不要去动能跑的代码,不然你不知道有多少坑等着你,哪怕代码是你自己写的。
目前位置DRV芯片配置就以及完成了。
5.编码器配置(RS485)
原本打算开始配置PWM+ADC的,即FOC算法部分的,但是我个人习惯先将外围全部打通再去配置最主要的部分,因为算法部分我打算用matlab生成来进行调试的,但是这部分我还没写,之前的代码手写有很多问题,不想再手写一次了,所以把最重要的放在最后,先配置编码器。
编码器采用RS485通信,有固有的通信协议,波特率为2.5M,后期是可以放在ADC中断中进行的,既可以保证实时性,也不会占用过多中断时间,后续会用IO口来测量代码的运行时间。
RS485通信是半双工通信,发送时DE低电平,接收时DE高电平,一般发送完即将DE置高即可。收发芯片和MCU的三个IO相连,其中两根连接MCU的USART的Tx和Rx引脚,De、Re两根引脚连接MCU的一个IO,即DE脚,stm32g431是支持RS485通信的,因此在cubemx中直接配置即可usart为异步通信,然后选择RS485模式。然后波特率等根据编码器手册进行配置即可,因为后续打算直接在ADC中断中直接进行收发,所以不配做DMA和中断这些。
但是需要注意编码器上电后需要一段时间才能初始化USART,这是在实际调试过程中发现的BUG,否则485通信将接收不到数据,因此需要在初始化USART之前先进行Delay,具体时间后续查阅数据手册需要15ms,为了确保一定没问题,所以在初始化前加上20ms的Delay延时。
然后就是收发测试了,编码器的协议是发送一个字节,接收6个字节,因此先调用发送函数后调用接收函数即可,经测,收发的数据是对的。
此时可以用IO口的高低电平对代码运行时间进行测试,在代码执行前拉高IO,执行完拉低IO,测量高电平时间即为代码运行时间。
经测试,执行时间为33us,可以接收。
利用Keil的internal的sec计算也是35us,基本不会相差太多。
可能有人觉得用LL库会缩短时间,但是实际测试LL库也消耗了32us的时间,不会相差太多。因为通信的大部分时间都消耗在了通信的时钟上,正常的通信时间都会占据大约28us的时间(理论计算)。
至此,编码器外设配置和收发接口开发完毕。
tips:介绍一个很好用的上位机,FreeScale的freemaster,具体配置步骤参考:
freemaster通过Jlink连接stm32芯片
用这个就可以用来监控MCU的变量信息了,例如上面的位置信息就可以在上位机用图形化界面进行显示了。
6.PWM和ADC
目前为止,该配置的外设基本已经完全配置完成,EtherCat留到最后再做。
在这部分,最主要的就是配置PWM和ADC了,其中包含控制电机所需的三路PWM(3PWM模式经过DRV芯片后会自动转换为3路互补PWM),三路电流采样ADC,以及一路ADC采样母线电压,电机温度和PCB温度两路ADC采样。
6.1三路PWM配置
FOC控制需要中心对齐PWM,并不是边沿对齐不能用,只是网上说采样效果不好,这样也更方便采样。
三路PWM配置需要用到高级定时器,这里使用高级定时器1,采用1、2、3三路分别控制电机的A、B、C三相,第四路使用无输出的PWM触发ADC采样。
首先将三路通道123配置成pwm generation channel模式.并在GPIO中将三相的IO口中重新命名为ABC三相(防止后续给PWM给错,也要和ADC通道对应起来)。
然后是参数配置:
将prescaler配置为0,然后counter period设置为4250,则PWM频率为:
频率 = 170 000 000 / (0 + 1) / 4250 = 40 000
即PWM频率为40K,而因为要采用中心对齐,所以PWM的频率将缩小一倍,为20Khz,即50us.后续的一次ADC中断就是要在50us内执行完成.
counter mode选择center aligned mode 1,
auto-reload precload选择enable.其余先默认.
至此三路PWM配置完成.接下来就需要用示波器参数发波正确与否了,这时候最好不要接电机.
测试发波正常后就可以设置PWM的触发源了,一般下桥臂采样会在PWM正确结束时进行ADC采样,比如PWM周期是4250,那么就可以在4240处等进行触发ADC采样,因此根据FOC采样规则需要多设置一路PWM来触发ADC采样。
设置pwm通道4为PWM Generation No Output,然后在Trigger Event Selection TRGO处选择OC4REF,最后设置pulse为4240,即在4240处触发ADC采样。
至此,三路PWM外加一路触发PWM均配置完成。
最后初始化的时候记得加上开启PWM通道4,即
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);
这样即可开启第四路PWM,前三路也是一样的.
6.2三相电流ADC采样配置
由于硬件设计的一些原因,三相电流的采样分布在两个不同的ADC中,分别是ADC1的12,14通道,以及ADC2的12通道.
这里先进行三路ADC的采样,其余的采样在下一节进行配置说明.
三相电流的采样要采取注入通道采样(可以理解为比规则通道优先级更高的中断采样).这样可以保证ADC采样的实时性和准确性,
由于分布在两个不同的ADC中,采样independent mode可能会出现采样不同步的问题(之前我用的是这种模式,好像也没出现过什么问题,这里想尝试一下新东西),这里采用dual injected simultaneous mode only模式,不启用DMA.分别将这三个通道使能为single-ended模式.接下来其余配置自行选取,调不通就试一下另一个,然后在注入组中分布将三个通道添加,并设置触发源为定时器1触发事件,其余先不修改,使能ADC中断并设置优先级为最高,因为本身板子最主要的作用就是电机控制,所有的FOC算法实现都在这个ADC中断中.
6.3电流测试验证
ADC配置算是完成了.接下来就要进行测试了.在初始化过程中,先进行两个ADC的校准.delay后开启ADC.
HAL_ADCEx_Calibration_Start(&hadc1,ADC_SINGLE_ENDED);
HAL_ADCEx_Calibration_Start(&hadc2,ADC_SINGLE_ENDED);
HAL_ADCEx_InjectedStart(&hadc2);
HAL_ADCEx_InjectedStart_IT(&hadc1);
此处ADC1开启中断,ADC2会同步触发采用,因此不需要进行ADC2中断.
至此代码完成,接下来需要写测试代码了,先在ADC1和2的中断中进行IO翻转,看ADC触发周期是否是20Khz.代码可自行编写.
经测试,刚好50us触发一次ADC中断.因此ADC中断触发是正确的,后边还要进行ADC的准确性核验,采取三相电流值,看看三相电流值是否和实际ADC口的电压值相等.
在ADC中断函数中,可以获取三相电流值,正常情况下,如果三相均不通电,那么三相电流应该是0,即三路ADC采样到的电压值均为1.65V,这时应先进行这个测试.正常三个ADC值约莫在2048上下,因为有ADC的采样误差以及原本的物理误差,说明是对的.
tips:这里需要注意要先开启ADC2转换后再开启ADC1转换,因为ADC2依赖于ADC1的转换,这两个如果颠倒ADC2将会没有具体的值.或者在两个开启之前失能中断,之后在开启中断.
然后是动态测试,开启三相电机之中的其中一路的PWM,然后看看ADC值会不会变化,如果变化就说明配置是正确的.经测试,ADC值正常变化,说明ADC配置完全正确,其实到这里就以及可以进行FOC算法的编写了,但是此处只想配置底层相关软件,其余的FOC算法我打算放弃之前的手写代码,打算用simulink来仿真生成对应的代码.实现一个完整的FOC流程,后续所有的仿真结果和实际生成的代码测试将另开一篇文章来编写.所有simulink生成的代码将在此ADC中断中执行.
至此,PWM和ADC触发中断已经完全配置完成.
技术名词解释
提示:这里可以添加技术名词解释
技术细节
提示:这里可以添加技术细节
技术细节会记录一些常见的小问题记录
小结
提示:这里可以添加总结
后续再继续记录。
更多推荐



所有评论(0)