9. 直流无刷驱动板温度电压采集¶
野火使用MOS管搭建的直流无刷驱动板做到了信号完全隔离,其他驱动板基本都只是使用光耦隔离了控制信号, 并没有对ADC采样电路进行隔离,野火不仅使用光耦对控制信号进行了隔离, 还使用AMC1200SDUBR隔离运放对ADC采样电路进行了隔离。
9.1. 电源电压采样电路¶
如下图所示是电源电压采样电路,在电源电压上并联R53和R54的串联电阻,R54两端的电压作为隔离运放的输入, 再经过隔离运放后差分输出,使用普通运放将差分输出转换成单端输出,连接到RA6T2的ADC采样通道。
从上图中我们可以知道是一个负反馈电路,那么根据虚短和虚断可以知道Up=Un, p点和n点没有电流到运放的2脚和3脚,可以得:
将(1)式和(2)式整理可得:
因为Up=Un,所以有:
其中R55=R56=R51=R52=10KΩ, 将R55、R56、R51和R52阻值带入上式化简可得:
9.2. 温度采样电路¶
使用时需要外接NTC热敏采样电阻,将NTC电阻贴在电机表面,采集电机温度。 热敏电阻器是利用金属氧化物半导体具有较大温度系数的特性,对温度敏感的电阻器。 其电阻值的温度依赖性为:
Rt=R25 exp[B(1/T-1/T25)]
Rt:温度T时阻值
R25:温度T25时阻值
T25:标准温度298.15 K(25℃)
B:热敏电阻常数
B的计算公式如下:
B=ln(Rt/R25)/(1/T-1/T25)
由上式可解得:
T=B*R25/(B+T25*ln(Rt/R25)) (1)
上式结果单位为开尔文(K)。
如下图所示是电机温度采样电路,
由上图可知其中运放是一个电压跟随器,其中运放的5脚和7脚电压相等。
所以,Rt=(3.3-Temperature_ADC)/(Temperature_ADC/4700.0)。 将Rt带入上面的(1)式计算温度。配套的NTC温度传感器B为3950。
9.3. 硬件连接¶
本章实验需要连接开发板和驱动板,这里给出接线表。
9.3.1. MOS管搭建驱动板¶
电机主控板与无刷电机驱动板连接见下表所示。
电机 |
无刷电机驱动板 |
---|---|
粗黄 |
U |
粗绿 |
V |
粗蓝 |
W |
细红 |
+(编码器电源) |
细黑 |
-(编码器电源) |
细黄 |
HIU |
细绿 |
HIV |
细蓝 |
HIW |
无刷电机驱动板与主控板连接见下表所示。
无刷电机驱动板 |
主控板 |
---|---|
5V_IN |
5V |
GND |
GND |
U+ |
PE10 |
U- |
PE13 |
V+ |
PE11 |
V- |
PE14 |
W+ |
PE12 |
W- |
PE15 |
HU |
PB06 |
HV |
PB07 |
HW |
PA10 |
SD |
PB15 |
TEMP |
PA03 |
VBUS |
PA01 |
推荐使用配套的牛角排线直接连接驱动板和主控板。连接开发板的那端,请连接在“无刷电机驱动接口2”上。
在NTC接口上插入NTC采样电阻,并将另一头贴于电机表面。
9.4. 在RA6T2中实现温度和电源电压采集¶
从前面两节中我们知道了温度和电源电压计算方法,下面我们看代码如何实现部分的处理。
9.4.1. 软件设计¶
配套代码在下面目录中可以找到:
\base_code\basis_part\6T2\直流无刷电机-温度-电源电压读取
9.4.1.1. 编程要点¶
初始化ADC并进行数据的获取
编写函数对采集得到的数据进行处理
编写获取最终温度值、电压值的函数
测试代码
9.4.1.2. 新建工程¶
我们直接在上一章节的的 “400_Motor_BLDC_Hall_SixStep_SpeedControl” 例程的基础上修改程序。
- 对于 e2 studio 开发环境:
拷贝一份我们之前的 e2s 工程 “400_Motor_BLDC_Hall_SixStep_SpeedControl”, 然后将工程文件夹重命名为 “402_Motor_BLDC_Temp_Voltage_Collect”,最后再将它导入到我们的 e2 studio 工作空间中。
- 对于 Keil 开发环境:
拷贝一份我们之前的 Keil 工程 “400_Motor_BLDC_Hall_SixStep_SpeedControl”, 然后将工程文件夹重命名为 “402_Motor_BLDC_Temp_Voltage_Collect”,并进入该文件夹里面双击 Keil 工程文件,打开该工程。
工程新建好之后,在工程根目录的 “src” 文件夹下面新建 “adc” 文件夹, 再进入 “adc” 文件夹里面新建源文件和头文件:“motor_v_c_acquisition.c” 和 “motor_v_c_acquisition.h”。 工程文件结构如下。
402_Motor_BLDC_Temp_Voltage_Collect
├─ ......
└─ src
├─ debug_uart
│ ├─ bsp_debug_uart.c
│ └─ bsp_debug_uart.h
├─ adc
│ ├─ bsp_adc_vr.c
│ └─ bsp_adc_vr.h
├─ led
│ ├─ bsp_led.c
│ └─ bsp_led.h
├─ motor_control
│ ├─ bsp_motor_control.c //新建文件
│ └─ bsp_motor_control.h //新建文件
├─ motor_GPT
│ ├─ bsp_motor_gpt.c //新建文件
│ └─ bsp_motor_gpt.h //新建文件
└─ hal_entry.c
9.4.1.3. FSP配置¶
下面以野火启明6T2开发板为例来讲解相关的 FSP 配置。
根据原理图所示,需要打开 AN001 以及 AN003 引脚用作电压和电流的采集引脚。 ADC相关知识请参考《瑞萨RA系列FSP库开发实战指南》,这里不过多赘述。 这里来讲解使用FSP库进行电压电流采集时如何更便捷的使用偏置值计算,如下图:
在图中,除了设置ADC模块的名称以及回调函数,还有两个特殊的表,分别代表 “用户偏移功能” 以及 “用户增益功能”, 用户偏移调整功能可在 A/D 转换数据中添加或减去一个常量值。Virtual channels 从用户指定的值表中选择一个偏移量。 用户增益调整功能将 A/D 转换数据乘以任意系数值。与偏移一样,虚拟通道可以从用户指定的表中选择一个增益值。
提示
当转换数据的数据长度选择14位/12位/10位时,偏移值的低位将根据数据格式的选择进行切割。
所以,使用常用的12位精度接收数据时,应该注意此处的偏移量为16位,要将偏移量切换成二进制,再统一切换成16位数值。 例如本实验中,电压的偏移值为1.24V,计算得到的偏移量为: 1.24V / 3.3V(参考电压) × 65535 ≈ 24625 ,由于是多的偏置值,要减去, 所以FSP偏移表第一项填写 -24625 。
随后在虚拟通道中从设定的表中选择一个偏移量,如下图所示:
这样就省去了我们在软件中的计算量,另外还需要新建一个定时器模块,用来定时打印电压电流值。 有关定时器部分也可以看之前的“瑞萨RA系列定时器详解”章节,这里不再赘述。
9.4.1.4. ADC初始化函数¶
此函数主要的功能是初始化ADC模块
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /**
* @brief 初始化ADC模块
*
* 该函数用于初始化ADC模块,包括打开ADC、配置扫描组和启动扫描组。
* @note 在调用此函数之前,请确保ADC配置结构体已正确设置。
*/
void adc_Init(void)
{
fsp_err_t err = FSP_SUCCESS;
//ADC初始化
err = R_ADC_B_Open(&g_adc_motor_ctrl, &g_adc_motor_cfg);
assert(FSP_SUCCESS == err);
err = R_ADC_B_ScanCfg(&g_adc_motor_ctrl, &g_adc_motor_scan_cfg);
assert(FSP_SUCCESS == err);
err = R_ADC_B_ScanGroupStart(&g_adc_motor_ctrl, ADC_GROUP_MASK_ALL);
assert(FSP_SUCCESS == err);
}
|
9.4.1.5. 电压温度值读取函数¶
此函数的功能是去读取温度,电压的ADC值,并通过对于的公式去换算出温度、电压数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | /**
* @brief 读取ADC电压值
*
* 该函数从ADC通道1读取电压值,并将其转换为实际电压值。
*
* @param[in] 无
* @return 返回读取到的电压值
* @note 此函数在调用前需确保ADC扫描已完成。
*/
double Read_ADC_Voltage_Value(void)
{
uint16_t adc1_data;
double c0;
while (!scan_complete_flag) //等待扫描完成
{
;
}
R_ADC_B_Read(&g_adc_motor_ctrl,ADC_CHANNEL_1, &adc1_data);
c0 = GET_ADC_VDC_VAL(adc1_data);
c0 = GET_VBUS_VAL(c0);
return c0;
}
/**
* @brief 读取ADC温度电压
*
* 该函数从ADC通道3读取温度电压
*
* @param[in] 无
* @return 返回读取到的温度电压
* @note 此函数在调用前需确保ADC扫描已完成。
*/
double Read_ADC_Temp_Value(void)
{
uint16_t adc2_data;
double c1;
while (!scan_complete_flag) //等待扫描完成
{
;
}
R_ADC_B_Read(&g_adc_motor_ctrl,ADC_CHANNEL_3, &adc2_data);
c1 = GET_ADC_VDC_VAL(adc2_data);//计算电流
return c1;
}
/**
* @brief 获取温度传感器端的电阻值
* @param 无
* @retval 转换得到的电阻值
*/
double get_ntc_r_val(void)
{
double r = 0;
double vdc = Read_ADC_Temp_Value();
r = ((VREF - vdc) / (vdc / (float)4700.0));
return r;
}
/**
* @brief 获取温度传感器的温度
* @param 无
* @retval 转换得到的温度,单位:(℃)
*/
double get_ntc_t_val(void)
{
double t = 0; // 测量温度
double Rt = 0; // 测量电阻
double Ka = 273.15; // 0℃ 时对应的温度(开尔文)
double R25 = 10000.0; // 25℃ 电阻值
double T25 = Ka + 25; // 25℃ 时对应的温度(开尔文)
double B = 3950.0; /* B-常数:B = ln(R25 / Rt) / (1 / T – 1 / T25),
其中 T = 25 + 273.15 */
Rt = get_ntc_r_val(); // 获取当前电阻值
t = B * T25 / (B + log(Rt / R25) * T25) - Ka ; // 使用公式计算
return t;
}
|
9.4.1.6. 定时打印函数¶
此函数1s输出一次电压、温度值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // GPT中断回调函数
void gpt0_timing_callback(timer_callback_args_t *p_args)
{
// 定时器溢出事件
if (TIMER_EVENT_CYCLE_END == p_args->event)
{
Time += 5;
// 每秒计算一次平均值并打印
if (Time == 100)
{
printf("电压 = %.2fV, 温度=%0.1f°\r\n", Read_ADC_Voltage_Value(),get_ntc_t_val());
// 重置时间
Time = 0;
}
}
}
|
9.4.1.7. hal_entry入口函数¶
此函数可以通过接收串口命令去控制电机,在电机运行时观察数据的变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | void hal_entry(void)
{
/* TODO: add your own code here */
/* LED初始化 */
LED_Init();
/* 串口初始化 */
Debug_UART9_Init();
adc_Init();
/* 电机初始化 */
bldcm_init();
printf("这是一个无刷电机基础控制示例\r\n");
printf("打开串口助手发送以下指令,可控制电机运行状态:\r\n");
printf("s----------------电机开始旋转\r\n");
printf("p----------------电机停止旋转\r\n");
printf("u----------------电机加速旋转[PWM+10%%]\r\n");
printf("d----------------电机减速旋转[PWM-10%%]\r\n");
printf("r----------------电机反向旋转\r\n");
R_BSP_SoftwareDelay(1, BSP_DELAY_UNITS_SECONDS); //延时1秒
while(1)
{
if(uart_recv_motor_enable == true)
{
uart_recv_motor_enable = false;
/* 使能电机 */
ChannelPulse = 10;
set_bldcm_speed(ChannelPulse);
set_bldcm_enable();
GPT_Timing_Init(); //启动定时器
}
if(uart_recv_motor_disenable == true)
{
uart_recv_motor_disenable = false;
/* 停止电机 */
ChannelPulse = 0;
set_bldcm_disable();
}
if(uart_recv_motor_speed_up == true)
{
uart_recv_motor_speed_up = false;
static int is_run_flag;
if(ChannelPulse==0)//占空比从零增加后 重新使能一次
{
is_run_flag=1;
}
/* 增大占空比 */
ChannelPulse +=10;
if(ChannelPulse >= 90)
ChannelPulse = 100;
set_bldcm_speed(ChannelPulse);
if(is_run_flag==1)
{
set_bldcm_enable();
is_run_flag=0;
}
}
if(uart_recv_motor_speed_down == true)
{
uart_recv_motor_speed_down = false;
/* 减小占空比 */
if(ChannelPulse <= 10)
ChannelPulse = 0;
else
ChannelPulse -= 10;
set_bldcm_speed(ChannelPulse);
}
if(uart_recv_motor_reverse == true)
{
uart_recv_motor_reverse = false;
Motor_Control_Reverse();
}
}
#if BSP_TZ_SECURE_BUILD
/* Enter non-secure code */
R_BSP_NonSecureEnter();
#endif
}
|
9.4.2. 下载验证¶
编译并下载程序后,复位开发板使程序重新运行,打开串口调试助手,连接好电机以及电机驱动板,启动电机,就可以看到开发板采集的电压值和电流值。