运行环境
RX62T 低电压电机控制评估系统
下面以瑞萨 RX62T 低电压电机控制评估系统 (RSSK)为例,介绍控制相关内容。RSSK 是以 24V 电机为对象,进行 120°/180° 通电,实施霍尔传感器 / 旋转编码器 / 无传感器控制的实验系统。程序中的变量在实际运行过程中的变 化可以通过 PC 显示,也可以通过低电压电机控制系 统的变量波形显示工具 ICS(In-Circuit Scope)显 示,有助于缩短开发时间(照片 1)。
系统运行参数
(1)电 机 ·电机转速:最低 600r/min,最高 2000r/min ·母线电压:24V ·电流:最大相电流为 1.8A (2)逆变器 ·载波频率:20kHz ·电流 / 电压控制:PI 控制(监测 U 相、V 相、 W 相电流,母线电压) ·编码器脉冲:输出轴每旋转 1 圈产生 300 个脉冲 (3)软 件 微处理器 RX62T 的资源分配参见表 1,软件结 构如图 2 所示。
控制方法
控制周期
由于是矢量控制,根据 PWM 载波周期(20kHz) 的编码器输出信号,计算转子位置和转速,并调整 PWM 输出。速度控制(PI 运算)以 1ms 为周期, 读取编码器脉冲计数的累计值。运算处理的负荷很大,能否在规定时间内完成 运算处理十分重要。运算处理的时间概念如图 3 所 示。下面,我们来看看具体内容。
每个载波周期的运算处理项目
载波周期内的矢量控制运算,大致可以归纳为 以下几点。·获取 U、W 相电流(V 相电流通过计算得出), 逆变器母线电压 ·坐标变换(U,V,W → α, β → d, q) ·电流 PI 控制 ·非干涉控制 ·调制,坐标变换(d, q → α β → U,V,W) ·设定 PWM 输出占空比(U,V,W) 也就是说,将矢量控制插入载波周期中断。当然,所有的计算都不能超过周期,这是必须遵守的绝对条件。对于没有 FPU(浮点运算单元) 的微处理器,要在进行坐标变换时,设定固定的小 数点。另外, 微处理器的时钟频率要达到 50MHz 左右,才有足够的处理能力。使用 20MHz 左右的微 处理器进行控制时,要下调载波频率;或者放弃在 每个载波周期进行控制,每 3 个周期进行一次矢量 控制。
运算的输入参数
(1)编码器输入 编码器检测速度、位置,输入 MTU3 的 MTCLKA、MTCLKB 进行计数(图 4)。
编码器每转 动 1 圈输出 300 个脉冲,其脉冲沿计数不会超过:300×4 倍= 1200当计数达到 1200 时,计数器归零。这就是编码 器的设定方式。但是,根据编码器输入得到的是相对位置 (图5),应在电机启动时进行位置调整。其方法将 在后面的内容中介绍。
(2)母线电压 母线电压变化时,电机驱动的正弦波的峰峰值 与有效值也会变化。因此,这需要反映到 PWM 输 出占空比控制。实际上,这就决定了正弦波输出有 效值的大小(图 6)。
(3)相电流 相电流的检测时间,是载波周期内 PWM 输出 切换后电流达到稳定时。PWM 载波周期为 20kHz(50μs)。这比 A-D 转 换时间 1μs 要大,而且,使用了编码器的控制,是 根据相电流来估算转子位置的。因此,A-D 转换开 始触发,即使在载波周期中断内启动软件也是完全 可以的(图6)。
为了提高相电流的检测精度,可以放大信号, 使 A - D 转 换 器 工 作 于 极 致 状 态 ( 图 7 )。
当 然 , 分流电阻损耗会增加。以 RSSK 为例,电阻值为 0.05Ω(50mΩ)。测量范围是 -10~+10A,信号经 5 倍放大后, 有效值为 1/2Vcc 时,电压为 -2.5~+2.5V。
程序实例1矢量控制——初始化部分
void R_MTR_InitHardware(void)
{
/*==========================*/
/* 初始化时钟 */
/*==========================*/
XXXXXXXXXXXXXXXT.ICK = 0x00; // ICLK : EXTAL×8 (96MHz) / EXTAL=12MHz
XXXXXXXXXXXXXXXT.PCK = 0x01; // PCLK : EXTAL×4 (48MHz) / EXTAL=12MHz
/*===========================*/
/* 初始化外设功能 */
/*===========================*/
MSTP_CMT0 = 0; // 模块停止状态被取消
MSTP_MTU = 0;
MSTP_S12AD0 = 0;
MSTP_S12AD1 = 0;
/*========================*/
/* 初始化 CMT0 */
/*========================*/
XXXXXXXXXXXXXXXXXR0 = 0; // 停止 CMT0
XXXXXXXXXXXXXXXXS = 0; // 时钟 : PCLK/8 */
XXXXXXXCOR = 5999; // 设定间隔时间
XXXXXXXXXXXXXXXXIE = 1; // 比较匹配中段(CMI0) 使能
ICU.IPR[0x04].BIT.IPR = 13;
XXXXXX[28].XXXXXX = 0;
XXXXXXR[0x03].XXXXXXN4 = 1;
/*===================================*/
/* 初始化 MTU3_3,MTU3_4 */
/*===================================*/
XXXXXXXXXXXXTE = 0x00; // 停止 MTU3
XXXXXXXXXXXXXXXSC = 0; // MTU3_3 时钟 : ICLK
XXXXXXXXXXXXXXXEG = 0;
XXXXXXXXXXXXXXXSC = 0; // MTU3_4 时钟 : ICLK
XXXXXXXXXXXXXXXEG = 0;
XXXXXXXXXXXXXXXXC = 0;
XXXXXXXNT = MTR_DEADTIME_SET; // 设定社区时间
XXXXXXXNT = 0;
XXXXXXXRB = MTR_HALF_CARRIER_SET; // 设定占空比
XXXXXXXRA = MTR_HALF_CARRIER_SET;
XXXXXXXRB = MTR_HALF_CARRIER_SET;
XXXXXXXRD = MTR_HALF_CARRIER_SET; // 设定占空比
XXXXXXXRC = MTR_HALF_CARRIER_SET;
XXXXXXXRD = MTR_HALF_CARRIER_SET;
XXXXXXDRA = MTR_DEADTIME_SET;
XXXXXXDRA = (uint16)(MTR_CARRIER_SET - MTR_DEADTIME_SET);
XXXXXXBRA = (uint16)(MTR_CARRIER_SET - MTR_DEADTIME_SET);
XXXXXXXRA = MTR_CARRIER_SET; // 设定载波周期
XXXXXXXRC = MTR_CARRIER_SET;
XXXXXXXXXXXXXXXXXYE = 0;
XXXXXXXXXXXXXT.OLSP = 1; // 正相:初始输出"L", 有效电平"H"
XXXXXXXXXXXXXT.OLSN = 1; // 反相:初始输出"H", 有效电平"H"
XXXXXXXXXXXXXXXXX = 14; // 互补PWM 模式
XXXXXXXXXXXXXXXXXA = 1; // TGRA 和TGRC 一起用于缓冲器换作
XXXXXXXXXXXXXXXXXB = 1; // TGRB 和TGRD 一起用于缓冲器换作
XXXXXXXXXXXXXTE = 0x00;
XXXXXXXXXXXXTE = 0xC0; // PWM 输出禁止
XXXXXXXXXXXXXXXFV = 0; // 下溢中断(TGIA) 使能
XXXXXXXXXXXXXXXXIEV = 1;
ICU.IPR[0x5A].BIT.IPR = 14;
XXXXXX[138].XXXXXX = 0;
XXXXXXR[0x11].XXXXXXN2 = 1;
XXXXXXXXXXXXXT.TITM = 0; // 设定中断跳过功能
XXXXXXXXXXXXXXT.T4VCOR = 1;
XXXXXXXXXXXXXXT.T4VEN = 1;
XXXXXXXXXXXXTE = 0xC0; // 启动 MTU3_3 和MTU3_4
/*********** for encoder ***********/
XXXXXXXXXXXXT.B2 = 1; // B 相输入模式
XXXXXXXXXXXXT.B2 = 0;
XXXXXXXXXXXXT.B3 = 1; // A 相输入模式
XXXXXXXXXXXXT.B3 = 0;
XXXXXXXXXXXXXXXXX = 4;
XXXXXXXXXXXXXXXLR = 1;
XXXXXXXRA = (uint16)(MTR_LOAD_ENCD_CNT - MTR_ENCD_CPR_MECH) + 1;
XXXXXXXXXXXXT.CST1 = 1;
/*=======================================*/
/* 初始化 POE3 */
/*=======================================*/
XXXXXXXXXXXXXXXXT.POE0E = 1; // POE3 过电流设定
XXXXXXXXXXXXT.POE0M = 0x00;
XXXXXXXXXXXXT.PIE1 = 1;
XXXXXXR[0x15].XXXXXXN2 = 1;
ICU.IPR[0x67].BIT.IPR = 15;
XXXXXXXXXXXXT.OCE1 = 1;
XXXXXXXXXXXXT.OIE1 = 1;
XXXXXXXXXXXXXXXXXU3BDZE = 1;
XXXXXXXXXXXXXXXXXU4ACZE = 1;
XXXXXXXXXXXXXXXXXU4BDZE = 1;
/*=============================*/
/* 初始化 I/O 端品 */
/*=============================*/
/*************** inverter ***************/
XXXXXXXXXXXXT.B1 = 1; // Up 输出模式
XXXXXXXXXXXXT.B2 = 1; // Vp 输出模式
XXXXXXXXXXXXT.B3 = 1; // Wp 输出模式
XXXXXXXXXXXXT.B4 = 1; // Un 输出模式
XXXXXXXXXXXXT.B5 = 1; // Vn 输出模式
XXXXXXXXXXXXT.B6 = 1; // Wn 输出模式
XXXXXXXXXXXT.B1 = 0; // Up = "L"
XXXXXXXXXXXT.B2 = 0; // Vp = "L"
XXXXXXXXXXXT.B3 = 0; // Wp = "L"
XXXXXXXXXXXT.B4 = 0; // Un = "L"
XXXXXXXXXXXT.B5 = 0; // Vn = "L"
XXXXXXXXXXXT.B6 = 0; // Wn = "L"
/*************** A/D 转换器 ***************/
XXXXXXXXXXXXT.B0 = 1; ADC
XXXXXXXXXXXXT.B1 = 1;
XXXXXXXXXXXXT.B2 = 1;
XXXXXXXXXXXXT.B6 = 1;
/*==================================*/
/* 初始化 A/D 转换器 */
/*==================================*/
/*************** Unit0 (Iu,Iw,Vdc) ***************/
XXXXXXXXXXXXXXXXXXXGE = 0; // 使用具有采样保持功能的单周期扫描模式
XXXXXXXXXXXXXXXXXXXS = 3;
XXXXXXXXXXXXXXXXXXXIE = 0;
XXXXXXXXXXXXXXXXXXXCS = 1;
XXXXXXXXXXXXXXXXXXX = 2;
XXXXXXXXXXXXXXXXXXXBYP = 0;
XXXXXXXXXXXXXXXXXXXRFMT = 0;
/*************** Unit1 (VR1) ***************/
XXXXXXXXXXXXXXXXXXXGE = 0; // 使用单一模式
XXXXXXXXXXXXXXXXXXXS = 3;
XXXXXXXXXXXXXXXXXXXIE = 0;
XXXXXXXXXXXXXXXXXXXCS = 0;
XXXXXXXXXXXXXXXXXXX = 2;
XXXXXXXXXXXXXXXXXXXRFMT = 0;
/*========================*/
/* 初始化 WDT */
/*========================*/
WDT.WRITE.WINA = 0x5A00; // 使用看门狗定时器模式
WDT.WRITE.WINB = 0xA500;
WDT.WRITE.WINB = 0x5A5F;
WDT.WRITE.WINA = 0xA5FF;
}
程序2 每个载波周期的矢量控制
static void mtr_mtu4_interrupt(void)
{
fl oat32 f4_temp0;
fl oat32 f4_temp1;
fl oat32 f4_temp2;
/*=============================================*/
/* A/D : 电流和电压检测 */
/*=============================================*/
clrpsw_i();
mtr_get_iuiwvdc(&g_f4_iu_ad, &g_f4_iw_ad, &g_f4_vdc_ad);
setpsw_i();
g_f4_iu_ad = g_f4_iu_ad - MTR_ADC_SCALING;
g_f4_iw_ad = g_f4_iw_ad - MTR_ADC_SCALING;
g_f4_iu_ad = g_f4_iu_ad * MTR_CURRENT_SCALING; // U 相电流
g_f4_iw_ad = g_f4_iw_ad * MTR_CURRENT_SCALING; // W 相电流
/*** 电流偏差调整 ***/
if (g_u2_cnt_adjust == 100)
{
g_f4_iu_ad = -g_f4_iu_ad + g_f4_offset_iu;
g_f4_iw_ad = -g_f4_iw_ad + g_f4_offset_iw;
g_f4_iu_ad = g_f4_pre_iu_ad + MTR_CURRENT_LPF_K * (g_f4_iu_ad - g_f4_pre_iu_ad);
g_f4_pre_iu_ad = g_f4_iu_ad;
g_f4_iw_ad = g_f4_pre_iw_ad + MTR_CURRENT_LPF_K * (g_f4_iw_ad - g_f4_pre_iw_ad);
g_f4_pre_iw_ad = g_f4_iw_ad;
}
else
{
/*** 调整偏差 ***/
g_f4_offset_iu += MTR_CURRENT_LPF_K * (g_f4_iu_ad - g_f4_offset_iu);
g_f4_iu_ad = -g_f4_iu_ad + g_f4_offset_iu;
g_f4_offset_iw += MTR_CURRENT_LPF_K * (g_f4_iw_ad - g_f4_offset_iw);
g_f4_iw_ad = -g_f4_iw_ad + g_f4_offset_iw;
g_u2_cnt_adjust++;
if (g_u2_cnt_adjust >= 100)
{
g_u2_cnt_adjust = 100;
}
}
g_f4_iv_ad = - (g_f4_iu_ad + g_f4_iw_ad); // V 相电流
g_f4_vdc_ad = g_f4_vdc_ad * MTR_VDC_SCALING; // Vdc
/*============================*/
/* 检查误差 */
/*============================*/
mtr_error_check();
/*====================================*/
/* 速度和角度计量 */
/*====================================*/
mtr_angle_speed();
/*=============================================================*/
/* 坐标变换(UVW -> αβ ->dq) */
/*=============================================================*/
f4_temp0 = cosf(g_f4_angle_rad) * g_f4_iu_ad;
f4_temp1 = cosf(g_f4_angle_rad - (MTR_TWOPI / 3)) * g_f4_iv_ad;
f4_temp2 = cosf(g_f4_angle_rad + (MTR_TWOPI / 3)) * g_f4_iw_ad;
g_f4_id_lpf = MTR_SQRT_2_3 * (f4_temp0 + f4_temp1 + f4_temp2);
f4_temp0 = sinf(g_f4_angle_rad) * g_f4_iu_ad;
f4_temp1 = sinf(g_f4_angle_rad - (MTR_TWOPI / 3)) * g_f4_iv_ad;
f4_temp2 = sinf(g_f4_angle_rad + (MTR_TWOPI / 3)) * g_f4_iw_ad;
g_f4_iq_lpf = MTR_SQRT_2_3 * (f4_temp0 + f4_temp1 + f4_temp2);
g_f4_iq_lpf = -g_f4_iq_lpf;
/*============================*/
/* 电流 PI 控制 */
/*============================*/
/* d-axis */
vd.f4_diff = g_f4_id_ref - g_f4_id_lpf;
vd.f4_kp = g_f4_kp_id;
vd.f4_ki = g_f4_ki_id;
vd.f4_limit = g_f4_lim_vd;
vd.f4_ilimit = g_f4_ilim_vd;
g_f4_vd_ref = mtr_pi_ctrl( &vd );
/* q-axis */
vq.f4_diff = g_f4_iq_ref - g_f4_iq_lpf;
vq.f4_kp = g_f4_kp_iq;
vq.f4_ki = g_f4_ki_iq;
vq.f4_limit = g_f4_lim_vq;
vq.f4_ilimit = g_f4_ilim_vq;
g_f4_vq_ref = mtr_pi_ctrl( &vq );
/*============================*/
/* 解耦控制 */
/*============================*/
f4_temp0 = MTR_LQ * g_f4_iq_lpf; // Lq*iq
f4_temp0 = g_f4_ref_speed_rad * f4_temp0; // w*Lq*iq
g_f4_vd_ref = g_f4_vd_ref - f4_temp0; // -w*Lq*iq
f4_temp0 = MTR_LD * g_f4_id_lpf; // Ld*id
f4_temp0 = f4_temp0 + MTR_M; // Ld*id+Ke
f4_temp0 = g_f4_ref_speed_rad * f4_temp0; // w*(Ld*id+Ke)
g_f4_vq_ref = g_f4_vq_ref + f4_temp0; // +w*(Ld*id+Ke)
/* 坐标变换(dq -> UVW) */
/*================================================*/
f4_temp0 = cosf(g_f4_angle_rad) * g_f4_vd_ref;
f4_temp1 = sinf(g_f4_angle_rad) * g_f4_vq_ref;
g_f4_refu = MTR_SQRT_2_3 * (f4_temp0 - f4_temp1);
f4_temp0 = cosf(g_f4_angle_rad - (MTR_TWOPI / 3)) * g_f4_vd_ref;
f4_temp1 = sinf(g_f4_angle_rad - (MTR_TWOPI / 3)) * g_f4_vq_ref;
g_f4_refv = MTR_SQRT_2_3 * (f4_temp0 - f4_temp1);
f4_temp0 = cosf(g_f4_angle_rad + (MTR_TWOPI / 3)) * g_f4_vd_ref;
f4_temp1 = sinf(g_f4_angle_rad + (MTR_TWOPI / 3)) * g_f4_vq_ref;
g_f4_refw = MTR_SQRT_2_3 * (f4_temp0 - f4_temp1);
if (g_f4_refu < -g_f4_inv_limit)
{
g_f4_refu = -g_f4_inv_limit;
}
else if (g_f4_refu > g_f4_inv_limit)
{
g_f4_refu = g_f4_inv_limit;
}
else
{ }
if (g_f4_refv < -g_f4_inv_limit)
{
g_f4_refv = -g_f4_inv_limit;
}
else if (g_f4_refv > g_f4_inv_limit)
{
g_f4_refv = g_f4_inv_limit;
}
else
{ }
if (g_f4_refw < -g_f4_inv_limit)
{
g_f4_refw = -g_f4_inv_limit;
}
else if (g_f4_refw > g_f4_inv_limit)
{
g_f4_refw = g_f4_inv_limit;
}
else
{ }
/*==============================*/
/* PWM 参考值设定 */
/*==============================*/
mtr_inv_set_uvw(g_f4_refu, g_f4_refv, g_f4_refw, g_f4_vdc_ad);
mtr_clear_mtu4_fl ag();
}
void mtr_get_iuiwvdc(volatile fl oat32 *f4_iu_ad,
volatile fl oat32 *f4_iw_ad, volatile fl oat32 *f4_vdc_ad)
{
XXXXXXXXXXXXXXXXXXXST = 1; // 开始转换
while (XXXXXXXXXXXXXXXXXXXST == 1);
*f4_iu_ad = (fl oat32)XXXXXXXXXDR0A;
*f4_iw_ad = (fl oat32)XXXXXXXXXDR1;
*f4_vdc_ad = (fl oat32)XXXXXXXXXDR2;
}
void mtr_inv_set_uvw(fl oat32 f4_u, fl oat32 f4_v, fl oat32 f4_w, fl oat32 f4_vdc)
{
fl oat32 f4_temp0, f4_temp1;
f4_temp0 = (fl oat32)(MTR_HALF_CARRIER_SET);
f4_temp1 = (f4_vdc / 2);
f4_u = -f4_u;
XXXXXXXRD = (uint16)(((f4_temp0 * f4_u) / f4_temp1) + f4_temp0);
// set U 相占空比设定
f4_v = -f4_v;
XXXXXXXRC = (uint16)(((f4_temp0 * f4_v) / f4_temp1) + f4_temp0);
// set V 相占空比设定
f4_w = -f4_w;
XXXXXXXRD = (uint16)(((f4_temp0 * f4_w) / f4_temp1) + f4_temp0);
// set W 相占空比设定
}
void mtr_angle_speed(void)
{
fl oat32 f4_temp_d_encd_tcnt;
fl oat32 f4_temp_speed_rad;
fl oat32 f4_temp;
g_f4_encd_tcnt = mtr_get_encd_tcnt();
if (g_f4_encd_tcnt == 0)
{
g_f4_encd_tcnt = MTR_LOAD_ENCD_CNT; // 编码器 : 0 -> 0x10000 */
}
if (MTR_ENCD_FOC_MODE == g_u2_run_mode)
{
f4_temp_d_encd_tcnt = g_f4_pre_encd_tcnt - g_f4_encd_tcnt;
if (f4_temp_d_encd_tcnt < 0)
{
f4_temp_d_encd_tcnt += MTR_ENCD_CPR_MECH;
}
g_f4_d_angle_rad = ((MTR_TWOPI * f4_temp_d_encd_tcnt) / MTR_ENCD_CPR_ELE);
/* 速度 */
f4_temp_speed_rad = (g_f4_d_angle_rad / MTR_CHECK_ENCD_PERIOD);
g_f4_speed_rad += MTR_SPEED_LPF_K * (f4_temp_speed_rad - g_f4_speed_rad);
/* LPF */
/* 角度 */
f4_temp = MTR_LOAD_ENCD_CNT - g_f4_encd_tcnt;
g_f4_angle_rad = ((MTR_TWOPI * f4_temp) / MTR_ENCD_CPR_ELE); /* angle: 0 to 7*2pi [rad] */
}
else
{
/* 速度 */
g_f4_speed_rad = 0;
if (0 == g_u1_fl ag_id_open)
{
/* 角度 */
g_f4_angle_rad = 0;
}
else if (1 == g_u1_fl ag_id_open)
{
/* 角度 */
g_f4_angle_rad = MTR_HALFPI;
}
}
g_f4_pre_encd_tcnt = g_f4_encd_tcnt;
}
1
END
1