序言
在前面的文章中,我们已经能够通过开环的方式启动电机了,但是FOC开环控制中的电角度给定部分是用自增的方式所给定的,接下来则是通过加入编码器的方式取得电机的电角度位置,并在FOC开环程序中用该电角度值替代自增部分。
本文将分为两部分:EQEP的配置以及SPI的配置,并在文末会两项功能进行测试。
1.1-EQEP.h配置
/*
* QEP.h
*
* Created on: 2023年4月2日
* Author: 24460
*/
#ifndef USER_INC_QEP_H_
#define USER_INC_QEP_H_
void QEP_int(void);
#endif /* USER_INC_QEP_H_ */
1.2-EQEP.c配置
/*
* QEP.c
*
* Created on: 2023年4月2日
* Author: 24460
*/
#include "F28x_Project.h"
#include "user.h"
#include "QEP.h"
/*-----------------------<QEP相关函数>-------------------------------------------------------------------------*/
void QEP_int(void)
{
SysCtl_enablePeripheral(SYSCTL_PERIPH_CLK_EQEP1);
//Configure the decoder for quadrature count mode
EQEP_setDecoderConfig(EQEP1_BASE, (EQEP_CONFIG_1X_RESOLUTION |EQEP_CONFIG_QUADRATURE |EQEP_CONFIG_NO_SWAP));//(上下沿都收集|正交计数1模式|)
EQEP_setEmulationMode(EQEP1_BASE, EQEP_EMULATIONMODE_RUNFREE);
// Configure the position counter to reset on an index event
EQEP_setPositionCounterConfig(EQEP1_BASE, EQEP_POSITION_RESET_IDX,3999);//IDX索引后重置计数
// Enable the unit timer, setting the frequency to 100 Hz
EQEP_enableUnitTimer(EQEP1_BASE, (DEVICE_SYSCLK_FREQ / 100));//Unit Timer 溢出频率100HZ
// Configure the position counter to be latched on a unit time out
EQEP_setLatchMode(EQEP1_BASE, EQEP_LATCH_UNIT_TIME_OUT);
// Enable the eQEP1 module
EQEP_disableModule(EQEP1_BASE);
// Configure and enable the edge-capture unit. The capture clock divider is
// SYSCLKOUT/128. The unit-position event divider is QCLK/8.
EQEP_setCaptureConfig(EQEP1_BASE, EQEP_CAPTURE_CLK_DIV_64,EQEP_UNIT_POS_EVNT_DIV_32);
EQEP_enableCapture(EQEP1_BASE);
//GPIO配置
EALLOW;
GPIO_setPinConfig(DEVICE_GPIO_CFG_EQEP1A);
GPIO_setPadConfig(DEVICE_GPIO_PIN_EQEP1A, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(DEVICE_GPIO_CFG_EQEP1B);
GPIO_setPadConfig(DEVICE_GPIO_PIN_EQEP1B, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(DEVICE_GPIO_CFG_EQEP1I);
GPIO_setPadConfig(DEVICE_GPIO_PIN_EQEP1I, GPIO_PIN_TYPE_STD);
EDIS;
EQEP_setPosition(EQEP1_BASE, 0);
EQEP_enableModule(EQEP1_BASE);
DELAY_US(10000L);
}
/*
void QEP_int(void)
{
EQep1Regs.QUPRD =200000;
EQep1Regs.QDECCTL.bit.QSRC =00;
EQep1Regs.QEPCTL.bit.FREE_SOFT =2;
EQep1Regs.QEPCTL.bit.PCRM =00;
EQep1Regs.QEPCTL.bit.UTE =1;
EQep1Regs.QEPCTL.bit.QCLM =1;
EQep1Regs.QEPCTL.bit.QPEN =1;
EQep1Regs.QCAPCTL.bit.UPPS =5;
EQep1Regs.QCAPCTL.bit.CCPS =7;
EQep1Regs.QCAPCTL.bit.CEN =1;
EQep1Regs.QPOSMAX =4000;
EQep1Regs.QEPCTL.bit.SWI =1;
EALLOW;
GPIO_setPinConfig(DEVICE_GPIO_CFG_EQEP1A);
GPIO_setPadConfig(DEVICE_GPIO_PIN_EQEP1A, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(DEVICE_GPIO_CFG_EQEP1B);
GPIO_setPadConfig(DEVICE_GPIO_PIN_EQEP1B, GPIO_PIN_TYPE_STD);
GPIO_setPinConfig(DEVICE_GPIO_CFG_EQEP1I);
GPIO_setPadConfig(DEVICE_GPIO_PIN_EQEP1I, GPIO_PIN_TYPE_STD);
EDIS;
}
*/
/*-----------------------<QEP相关函数>-------------------------------------------------------------------------*/
在EQEP的引脚配置中,选取了:
- #2引脚(GPIO28)作为EQEP_A
- #29引脚(GPIO13)作为EQEP_Z
- #31引脚(GPIO11)作为EQEP_B
其中引脚配置要打开device.h,找到EQEP相关的定义修改成如下
//
// eQEP
//
#define DEVICE_GPIO_PIN_EQEP1A 28U // GPIO number for EQEP 1A IO2
#define DEVICE_GPIO_PIN_EQEP1B 11U // GPIO number for EQEP 1B IO31
#define DEVICE_GPIO_PIN_EQEP1I 13U // GPIO number for EQEP 1I IO29
#define DEVICE_GPIO_CFG_EQEP1A GPIO_28_EQEP1A // "pinConfig" for EQEP 1A
#define DEVICE_GPIO_CFG_EQEP1B GPIO_11_EQEP1B // "pinConfig" for EQEP 1B
#define DEVICE_GPIO_CFG_EQEP1I GPIO_13_EQEP1I // "pinConfig" for EQEP 1I
1.3-编码器的数值读取测试(取电机逆时针旋转为正方向增计数)
如此配置main函数进行编码器测试即可:
/**
* main.c
*/
#include "F28x_Project.h"
#include "IQmathLib.h"
#include "FOC.h"
#include "PWM.h"
#include "QEP.h"
/*全局变量区*/
uint16_t now_position;
int main(void)
{
InitSysCtrl();
DINT;
InitPieCtrl();
IER=0x0000;
IFR=0x0000;
InitPieVectTable();
DELAY_US(1000L);
QEP_int();
//EPWM1_int();
EINT; //使能全局中断
ERTM;
while (1)
{
now_position = EQEP_getPosition(EQEP1_BASE);
DELAY_US(20000L);
}
}
然后点击CCS左上角功能栏中的小甲壳虫(debug)按钮进入调试状态,用手逆时针转动电机,观看参数观察窗口中的now_position 数值变化。
2.1-userSPI.h配置
SPI的头文件配置中呢,主要是申明了三个函数,其一是SPI的初始化函数,其二是发送两个16位的数据发送函数,其三是具体的发送数据函数。
/*
* userSPI.h
*
* Created on: 2023年4月29日
* Author: 24460
*/
#ifndef USER_INC_USERSPI_H_
#define USER_INC_USERSPI_H_
void SPIA_int (void);
uint16_t SPIA_sendtwo(uint16_t txdata1,uint16_t txdata2);
void SPISendData(uint8_t *data, unsigned int len);
#endif /* USER_INC_USERSPI_H_ */
2.2-userSPI.c配置
2.21 初始化函数
void SPIA_int (void)
{
//GPIO配置
// SPISOMI.
//
GPIO_SetupPinMux(17, GPIO_MUX_CPU1, 1);
GPIO_SetupPinOptions(17, GPIO_PULLUP, GPIO_ASYNC);
//
// SPISIMO clock pin.
//
GPIO_SetupPinMux(16, GPIO_MUX_CPU1, 1);
GPIO_SetupPinOptions(16, GPIO_PULLUP, GPIO_ASYNC);
//
// SPICLK.
//
GPIO_SetupPinMux(9, GPIO_MUX_CPU1, 7);
GPIO_SetupPinOptions(9, GPIO_PULLUP, GPIO_ASYNC);
//
// SPICS.
//
GPIO_SetupPinMux(33, GPIO_MUX_CPU1, 0);
GPIO_SetupPinOptions(33, GPIO_OUTPUT, GPIO_ASYNC);
GPIO_WritePin(33, 1);
//SPI配置
// Set reset low before configuration changes
// Clock polarity (0 == rising, 1 == falling)
// 16-bit character
// Enable loop-back
//
SpiaRegs.SPICCR.bit.SPISWRESET = 0;
SpiaRegs.SPICCR.bit.CLKPOLARITY = 0;
SpiaRegs.SPICCR.bit.SPICHAR = (8 - 1);
SpiaRegs.SPICCR.bit.SPILBK = 0;
//
// Enable master (0 == slave, 1 == master)
// Enable transmission (Talk)
// Clock phase (0 == normal, 1 == delayed)
// SPI interrupts are disabled
//
SpiaRegs.SPICTL.bit.MASTER_SLAVE = 1;
SpiaRegs.SPICTL.bit.TALK = 1;
SpiaRegs.SPICTL.bit.CLK_PHASE = 0;
SpiaRegs.SPICTL.bit.SPIINTENA = 0;
//
// Set the baud rate using a 2 MHz SPICLK
// BRR = (LSPCLK / SPICLK) - 1
//
SpiaRegs.SPIBRR.bit.SPI_BIT_RATE = ((25000000 / 1000000) - 1);
//
// Set FREE bit
// Halting on a breakpoint will not halt the SPI
//
SpiaRegs.SPIPRI.bit.FREE = 1;
//
// Release the SPI from reset
//
SpiaRegs.SPICCR.bit.SPISWRESET = 1;
}
在SPI的引脚配置中,选取了:
- #62引脚(GPIO9)作为SPI_CLK
- #34引脚(GPIO17)作为SPI_SOMI
- #33引脚(GPIO16)作为SPI_SIMO
- #32引脚(GPIO33)作为SPI_CS
2.22 发送两个数据函数
uint16_t SPIA_sendtwo(uint16_t txdata1,uint16_t txdata2)
{
uint8_t data[6];
data[0] = 1;
data[5] = 255;
data[1] = txdata1/256;
data[2] = txdata1%256;
data[3] = txdata2/256;
data[4] = txdata2%256;
SPISendData(data, 6);
}
由于所要发送的数据是16位的,但是STM32方面只能接收8位的数据,所以要先将两个16位数据转换为4个8位数据进行存储,并且在数据发送中还要加上头尾标识数用以确保数据的准确发送于接收。
2.23 发送函数
void SPISendData(uint8_t *data, unsigned int len)
{
int i;
uint16_t rxdata;
GPIO_WritePin(33, 0);
for (i = 0; i < len; i++)
{
// 写入数据到SPI缓冲区
SpiaRegs.SPITXBUF = data[i]<<8;
// 等待数据发送完成
while (SpiaRegs.SPISTS.bit.INT_FLAG != 1);
rxdata = SpiaRegs.SPIRXBUF;
}
GPIO_WritePin(33, 1);
}
2.3-SPI通讯测试
从机STM32配置部分请参考这篇文章:
DSP280049C初学(3)-DSP280049C的ECAP配置,STM32F103C8T6作为信号发生端
/**
* main.c
*/
#include "F28x_Project.h"
#include "IQmathLib.h"
#include "FOC.h"
#include "PWM.h"
#include "QEP.h"
#include "userSPI.h"
/*全局变量区*/
uint16_t now_position;
int main(void)
{
InitSysCtrl();
DINT;
InitPieCtrl();
IER=0x0000;
IFR=0x0000;
InitPieVectTable();
DELAY_US(1000L);
SPIA_int ();
QEP_int();
//EPWM1_int();
EINT; //使能全局中断
ERTM;
while (1)
{
SPIA_sendtwo(1234,4321);
DELAY_US(1000L);
}
}
基于DSP280049C的电机驱动系列回顾:
(一):CCS文件夹的建立与IQmath导入
(二):FOC文件的建立与开环代码编写
(三):EPWM配置
(四):EQEP配置与SPI主机配置