完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
|
|
相关推荐
1个回答
|
|
接着上篇,先解释一下为什么会出现“共振”现象
假如A1的占空比为25%,B2的占空比为10%,C2的占空比也为10%,我一开始想象的A1和B1之间的信号强度应该是: 25% x 10% = 2.5% 但是实际远不是这么回事,假如B2的高电平时间范围正好都落在了A1的高电平时间范围中,那么A1到B2的信号的实际占空比就是B2信号的占空比10%。但是如果 B2的高电平时间范围没有完全都落在了A1的高电平时间范围中或者完全没有落在A1的高电平时间范围中的话,A1到B2的有效信号宽度是A1和B2的信号中高电平重叠部分的宽度。比如C2的信号,高电平信号完全落在了A1信号高电平的外部,也就是A1到C2之间根本没有重叠的部分,不会有电流产生,即使A1和C2的占空都比大于0。 为了解决这个问题,我的做法是将所有PWM通道初始化之后先不要使能定时器,而是在初始化完所有定时器之后再统一进行定时器的使能,这样几个定时器的使能时间差在几个us的级别,甚至更小(CPU为48MHz主频,执行这几条指令耗时很低,而且将全局中断关闭,防止有中断打断该过程),而PWM信号的频率一般是20KHz,周期为50us,这样可以让PWM信号的初相尽可能一样,这样就能让PWM信号的重叠区域最大,示例程序如下: 。。。。。。 TIM1_PWM_Init(255 - 1,10); //48MHz / 10 / 255 = 18.8KHz TIM3_PWM_Init(255 - 1,10); TIM14_PWM_Init(255 - 1,10); 。。。。。。 __disable_irq(); //关闭全局中断 int tmp1,tmp2,tmp3; tmp1 = TIM1-》CR1 | TIM_CR1_CEN; tmp2 = TIM3-》CR1 | TIM_CR1_CEN; tmp3 = TIM14-》CR1 | TIM_CR1_CEN; TIM1-》CR1 = tmp1; TIM3-》CR1 = tmp2; TIM14-》CR1 = tmp3; __enable_irq(); //打开全局中断 。。。。。。 测试一下A1、B1、C1的波形相位问题: 可以看出来A1和B1的相位差0.25u(因为我的逻辑分析仪的采样率是4MHz,最小分辨率0.25us,所以实际的大小可能是小于0.25us的),已经很小了,但是B1和C1没有相位差,因为B1和C1都是TIM3输出的PWM,肯定没有误差。可以猜测B1和C2差不多也误差0.25us以下,属于可接受范围了,可以使用PWM信号来控制电流大小。实在是缺示波器。 下面为了使得PWM信号派上用场,这里对三相波形的细分。三相驱动信号原图为: 我们将电流的瞬变改成渐变,如下图的紫色、蓝色、绿色三根: 为了提高驱动电流,将t0到t5这6个阶段拆分成t0_1、t0_2、t1_1、t1_2、t2_1、t2_2、t3_1、t3_2、t4_1、t4_2、t5_1、t5_2这12个阶段,每一个单独的阶段中只有一相信号处于渐变状态,其余两相处于满状态(占空比100%),这样就提高了总的电流和扭矩。下图为扩展后的波形图(PS零水平,手绘): 12个阶段的A、B、C相的状态表也在上图中写出来了,根据这个状态表写每个阶段的程序即可: void t0_1(void){// printf(“A:0-》1 B:-1 C:1rn”); *A1 = 0; *A2 = 0; *B1 = 0; *B2 = MAX_PWM; *C1 = MAX_PWM; *C2 = 0; int i; for(i=0;i《=MAX_PWM;i++) { *A1 = i; delay_us(INTERVAL); }}void t0_2(void){// printf(“A:1 B:-1 C:1-》0rn”); *A1 = MAX_PWM; *A2 = 0; *B1 = 0; *B2 = MAX_PWM; *C1 = MAX_PWM; *C2 = 0; int i; for(i=0;i《=MAX_PWM;i++) { *C1 = MAX_PWM - i; delay_us(INTERVAL); }}void t1_1(void){// printf(“A:1 B:-1 C:0-》-1rn”); *A1 = MAX_PWM; *A2 = 0; *B1 = 0; *B2 = MAX_PWM; *C1 = 0; *C2 = 0; int i; for(i=0;i《=MAX_PWM;i++) { *C2 = i; delay_us(INTERVAL); }}void t1_2(void){// printf(“A:1 B:-1-》0 C:-1rn”); *A1 = MAX_PWM; *A2 = 0; *B1 = 0; *B2 = MAX_PWM; *C1 = 0; *C2 = MAX_PWM; int i; for(i=0;i《=MAX_PWM;i++) { *B2 = MAX_PWM - i; delay_us(INTERVAL); }}void t2_1(void){// printf(“A:1 B:0-》1 C:-1rn”); *A1 = MAX_PWM; *A2 = 0; *B1 = 0; *B2 = 0; *C1 = 0; *C2 = MAX_PWM; int i; for(i=0;i《=MAX_PWM;i++) { *B1 = i; delay_us(INTERVAL); }}void t2_2(void){// printf(“A:1-》0 B:1 C:-1rn”); *A1 = MAX_PWM; *A2 = 0; *B1 = MAX_PWM; *B2 = 0; *C1 = 0; *C2 = MAX_PWM; int i; for(i=0;i《=MAX_PWM;i++) { *A1 = MAX_PWM - i; delay_us(INTERVAL); }}void t3_1(void){// printf(“A:0-》-1 B:1 C:-1rn”); *A1 = 0; *A2 = 0; *B1 = MAX_PWM; *B2 = 0; *C1 = 0; *C2 = MAX_PWM; int i; for(i=0;i《=MAX_PWM;i++) { *A2 = i; delay_us(INTERVAL); }}void t3_2(void){// printf(“A:-1 B:1 C:-1-》0rn”); *A1 = 0; *A2 = MAX_PWM; *B1 = MAX_PWM; *B2 = 0; *C1 = 0; *C2 = MAX_PWM; int i; for(i=0;i《=MAX_PWM;i++) { *C2 = MAX_PWM - i; delay_us(INTERVAL); }}void t4_1(void){// printf(“A:-1 B:1 C:0-》1rn”); *A1 = 0; *A2 = MAX_PWM; *B1 = MAX_PWM; *B2 = 0; *C1 = 0; *C2 = 0; int i; for(i=0;i《=MAX_PWM;i++) { *C1 = i; delay_us(INTERVAL); }}void t4_2(void){// printf(“A:-1 B:1-》0 C:1rn”); *A1 = 0; *A2 = MAX_PWM; *B1 = MAX_PWM; *B2 = 0; *C1 = MAX_PWM; *C2 = 0; int i; for(i=0;i《=MAX_PWM;i++) { *B1 = MAX_PWM - i; delay_us(INTERVAL); }}void t5_1(void){// printf(“A:-1 B:0-》-1 C:1rn”); *A1 = 0; *A2 = MAX_PWM; *B1 = 0; *B2 = 0; *C1 = MAX_PWM; *C2 = 0; int i; for(i=0;i《=MAX_PWM;i++) { *B2 = i; delay_us(INTERVAL); }}void t5_2(void){// printf(“A:-1-》0 B:-1 C:1rn”); *A1 = 0; *A2 = MAX_PWM; *B1 = 0; *B2 = MAX_PWM; *C1 = MAX_PWM; *C2 = 0; int i; for(i=0;i《=MAX_PWM;i++) { *A2 = MAX_PWM - i; delay_us(INTERVAL); }} 主程序按顺序调用这12个函数: //设置所有桥臂为无输出。注意IO_X1和IO_X2信号不可以同时为高, //否则会导致桥臂短路,容易烧坏MOS管,同时在程序中最好先将为0的 //信号先设置为0,然后再设置不为0的信号,这样可以避免短路。 *A1 = 0; *A2 = 0; *B1 = 0; *B2 = 0; *C1 = 0; *C2 = 0; #define INTERVAL 10 //PWM上升下降间隔时间 #define MAX_PWM 255 //处于t5状态,并维持一段时间,保证可靠处于t5状态 printf(“Readyrn”); { //t5:CB printf(“t5:CBrn”); *A1 = 0; *A2 = 0; *C1 = MAX_PWM; *C2 = 0; *B1 = 0; *B2 = MAX_PWM; } delay_ms(200); while(1) { t0_1();// printf(“0_1rn”); delay_ms(2000); t0_2();// printf(“0_2rn”); delay_ms(2000); t1_1();// printf(“1_1rn”); delay_ms(2000); t1_2();// printf(“1_2rn”); delay_ms(2000); t2_1();// printf(“2_1rn”); delay_ms(2000); t2_2();// printf(“2_2rn”); delay_ms(2000); t3_1();// printf(“3_1rn”); delay_ms(2000); t3_2();// printf(“3_2rn”); delay_ms(2000); t4_1();// printf(“4_1rn”); delay_ms(2000); t4_2();// printf(“4_2rn”); delay_ms(2000); t5_1();// printf(“5_1rn”); delay_ms(2000); t5_2();// printf(“5_2rn”); delay_ms(2000); } 这里的INTERVAL是上升延时,和上篇文章中的不是一个含义。调整INTERVAL的大小可以改变转速,程序运行的不错,电机比之前运行丝滑很多,和某巧克力一样。 程序可以停在12个阶段中的任意一个阶段中的任意一个状态,所以可以实现和步进电机一样的步进控制,调大INTERVAL到1000以以上就能看出电机慢慢的转动的现象了,但是不如步进电机,老是会有“突变”的现象,可能就是无刷电机结构问题导致的,因为无刷电机一开始就没这么用的。。。。。。 再来改一下程序,如下: void go_stage(int stage){ if(stage == 0) { *A1 = 0; *A2 = 0; *B1 = 0; *B2 = MAX_PWM; *C1 = MAX_PWM; *C2 = 0; } else if(stage == 1) { *A1 = MAX_PWM; *A2 = 0; *B1 = 0; *B2 = MAX_PWM; *C1 = MAX_PWM; *C2 = 0; } else if(stage == 2) { *A1 = MAX_PWM; *A2 = 0; *B1 = 0; *B2 = MAX_PWM; *C1 = 0; *C2 = 0; } else if(stage == 3) { *A1 = MAX_PWM; *A2 = 0; *B1 = 0; *B2 = MAX_PWM; *C1 = 0; *C2 = MAX_PWM; } else if(stage == 4) { *A1 = MAX_PWM; *A2 = 0; *B1 = 0; *B2 = 0; *C1 = 0; *C2 = MAX_PWM; } else if(stage == 5) { *A1 = MAX_PWM; *A2 = 0; *B1 = MAX_PWM; *B2 = 0; *C1 = 0; *C2 = MAX_PWM; } else if(stage == 6) { *A1 = 0; *A2 = 0; *B1 = MAX_PWM; *B2 = 0; *C1 = 0; *C2 = MAX_PWM; } else if(stage == 7) { *A1 = 0; *A2 = MAX_PWM; *B1 = MAX_PWM; *B2 = 0; *C1 = 0; *C2 = MAX_PWM; } else if(stage == 8) { *A1 = 0; *A2 = MAX_PWM; *B1 = MAX_PWM; *B2 = 0; *C1 = 0; *C2 = 0; } else if(stage == 9) { *A1 = 0; *A2 = MAX_PWM; *B1 = MAX_PWM; *B2 = 0; *C1 = MAX_PWM; *C2 = 0; } else if(stage == 10) { *A1 = 0; *A2 = MAX_PWM; *B1 = 0; *B2 = 0; *C1 = MAX_PWM; *C2 = 0; } else if(stage == 11) { *A1 = 0; *A2 = MAX_PWM; *B1 = 0; *B2 = MAX_PWM; *C1 = MAX_PWM; *C2 = 0; }}void main(void){ 。。。。。。 //设置所有桥臂为无输出。注意IO_X1和IO_X2信号不可以同时为高, //否则会导致桥臂短路,容易烧坏MOS管,同时在程序中最好先将为0的 //信号先设置为0,然后再设置不为0的信号,这样可以避免短路。 *A1 = 0; *A2 = 0; *B1 = 0; *B2 = 0; *C1 = 0; *C2 = 0; #define INTERVAL 10 //PWM上升下降间隔时间 #define MAX_PWM 255 printf(“Readyrn”); stage = 0; go_stage(stage); delay_ms(200); direction = 0; //控制转动方向 stage = 0; //当前阶段 offset = 0; //阶段中偏移 while(1) { if(direction == 0) //顺时针 { offset++; if(offset == MAX_PWM + 1) //换相 { offset= 0; stage++; if(stage == 12) stage = 0; go_stage(stage); } } else { if(offset == 0) //换相 { offset= 255; if(stage == 0) stage = 11; else stage--; go_stage(stage); } else offset--; } switch(stage) { case 0 :*A1 = offset; break; case 1 :*C1 = MAX_PWM - offset; break; case 2 :*C2 = offset; break; case 3 :*B2 = MAX_PWM - offset; break; case 4 :*B1 = offset; break; case 5 :*A1 = MAX_PWM - offset; break; case 6 :*A2 = offset; break; case 7 :*C2 = MAX_PWM - offset; break; case 8 :*C1 = offset; break; case 9 :*B1 = MAX_PWM - offset; break; case 10 :*B2 = offset; break; case 11 :*A2 = MAX_PWM - offset; break; } delay_us(INTERVAL); }} 通过调整direction和INTERVAL的值可以修改转动方向和转动速度,改变MAX_PWM可以调整电流大小。抓取一下波形看看6个通道的PWM信号的12个阶段,其中白色的部分是PWM信号: 以第一个阶段也就是程序里面的 t0_1 阶段为例,6个通道首先处于 t5:CB 的初始化状态,然后A1通道从0%到100%渐变,A2通道为0%,B1、B2、C1、C2分别为0%、100%、100%、0%,和我们设计的波形是一样的。 程序里面可以把PWM的细分数降低,我改成(10 - 1)(这里 -1 是为了当PWM取值10时占空比为100%,与具体单片机内部定时器的PWM实现机制相关),然后将分频数增加到500,因为没必要细分那么多级,MAX_PWM的取值范围为 0 到 10 ,这样INTERVAL的值也可以放大到 ms 级别,可以放在一个定时时间为INTERVAL的定时器中断中来处理电机的驱动,如果INTERVAL很小的话,会导致一直在定时器中断中出不来,示例程序: TIM1_PWM_Init(10 - 1,500); //48M / 500 / 10 = 9.6KHz TIM3_PWM_Init(10 - 1,500); TIM14_PWM_Init(10 - 1,500); #define INTERVAL 1000 //PWM上升下降间隔时间 #define MAX_PWM 10 然后我将电机驱动电压改成12V的电源,调整MAX_PWM的值分别测量电流大小,我测试使用电机在满PWM的时候能达到3A的电流,在50%的占空比的时候电流为0.4A左右。不通电机和供电电压需要匹配不同的INTERVAL和MAX_PWM的值才能转的好。 |
|
|
|
只有小组成员才能发言,加入小组>>
646浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-22 11:46 , Processed in 0.675967 second(s), Total 76, Slave 60 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号