567|1

27

帖子

0

TA的资源

一粒金砂(中级)

楼主
 

【极海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

 

 

点赞 关注(1)
 
 

回复
举报

27

帖子

0

TA的资源

一粒金砂(中级)

沙发
 

已解决。

为什么会发生循环执行无法退出ADC中断的情况,是因为ADC中断处理函数 的执行时间 大于 ADC触发周期。因此产生了退不出中断的错觉。

 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/7 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表