【极海APM32M3514电机通用评估板】外设篇(求助ADC)
[复制链接]
本帖最后由 不语arc 于 2024-12-17 17:02 编辑
0.前提
官方例程是使用滑模观测器的无感FOC控制,但我无法测得自己的电机的各项参数,调试滑模观测器参数始终无法让电机转动起来(求大佬指点)。所以后续我打算直接使用有感FOC完成对电机的控制。
极海lib中的算法相当于使用uint类型完成浮点计算,也就是标幺化。但使用官方api完成有感控制,需要做大量的移植工作,而且有难度。因此,计划先使用math库,完成有感foc控制。在本篇,我将先完成对各个外设的基本驱动。
1.usart
串口配置,参考:【极海APM32M3514电机通用评估板】 串口输出测试 - 国产芯片交流 - 电子工程世界-论坛
将swd复用为串口,在硬件上与ch340模块的TX管脚相连(用不到RX),这里我使用了波动开关。
swd连ch340时,在main.c中开头加一段延时,如此可以在这个时间中继续使用下载功能。不连ch340时,swd仍可以用于调试,需将初始化USART的代码注释掉。
上位机vofa+用于显示波形非常方便,这里使用JustFloat发送格式,只需要在包尾发送对应的tail[4]{0x00,0x00,0x80,0x7f}即可上传多个通道的数据。
发送函数:
//本协议是纯十六进制浮点传输
void vofa_JustFloat_output(float s1,float s2,float s3,float s4)
{
float data[4];
uint8_t tail[4] = {0x00, 0x00, 0x80, 0x7f};
// 发送数据
data[0] = s1;
data[1] = s2;
data[2] = s3;
data[3] = s4;
Usart_SendData(MINI_COM1,(uint8_t*)data,sizeof(float) * 4); //发送数据
// 发送帧尾
Usart_SendData(MINI_COM1,tail,4);
}
2.PWM
本身的pwm配置已经配置好了,宏定义如下。pwm时钟频率同样为72Mhz,计数采用中心对齐模式,pwm开关频率为16khz。
3. I2C编码器
见上一篇分享
4.ADC
五路ADC
其中W相电流 = Ibus - Iu - Iv
配置方式不变,注意右对齐也就是低12位存储读取的结果。
将读取结果转成实际值,注意这里的ADC_Ia_offset为电机未转动时,读取的a相偏置电流大小。
实际读取的值是运放 输出的结果,对其进行解算,得到实际值。
typedef struct
{
float Ia; // Phase A current
float Ib; // Phase B current
float Ic; // Phase C current
float Ibus;
float Vbus;
float VHandle; //0-3.3的范围
uint16_t ADC_Ia; // Phase A Voltage(I*R)
uint16_t ADC_Ib; // Phase B Voltage
uint16_t ADC_Ibus; // SUM Voltage
uint16_t ADC_Ia_offset; // 电流零点偏置
uint16_t ADC_Ib_offset; // 电流零点偏置
uint16_t ADC_Ibus_offset; // 电流零点偏置
uint16_t ADC_Vbus; // Phase bus Voltage
uint16_t ADC_Handle;
} CURRENT_Def;
#define ADC_V_K 0.0008 // 3.3/4096.0 // ADC 与电压转换系数
#define VREF 1.65 //参考电压偏置
#define AM_GAIN 4.86 //运放放大倍数
#define R_SENSE 0.02 //Ω 采样电阻
#define V_GAIN 21 //(100+100+10)/10
void GetADCvaule(){
current.ADC_Ia = (int16_t)ADC_GetValue(CURR_CHANNEL_U);
current.ADC_Ib = (int16_t)ADC_GetValue(CURR_CHANNEL_V);
current.ADC_Ibus = (int16_t)ADC_GetValue(IBUS_CHANNEL);
current.Ia = (ADC_V_K*(current.ADC_Ia-current.ADC_Ia_offset) - VREF) / (AM_GAIN * R_SENSE);
current.Ib = (ADC_V_K*(current.ADC_Ib-current.ADC_Ib_offset) - VREF) / (AM_GAIN * R_SENSE);
current.Ibus = (ADC_V_K*(current.ADC_Ibus-current.ADC_Ibus_offset) - VREF) / (AM_GAIN * R_SENSE);
current.Ic = current.Ibus - current.Ia - current.Ib;
current.ADC_Vbus = (int16_t)ADC_GetValue(VDC_CHANNEL);
current.Vbus = ADC_V_K*(current.ADC_Vbus) * V_GAIN;
current.ADC_Handle = (int16_t)ADC_GetValue(Handle_CHANNEL);
current.VHandle = ADC_V_K*(current.ADC_Handle); //0-3.3的范围
}
在这里提一个问题:为什么U、V两相的运放反相输入端为什么是实际的SUM?计算出的公式,是按照反相输入端接地计算得到的,虽然SUM值不算大。
另外,ADC的中断处理函数好像存在bug,为什么会发生循环执行无法退出ADC中断的情况。具体表现为ADC->STS 无法幅值,中断标志位无法清零。(关闭了看门狗)
两处写法很奇怪,但官方例程居然不怎么出现这个bug
|