搜索
bottom↓
回复: 50

帖一个偶写的小型直流电机控制例子

[复制链接]

出0入0汤圆

发表于 2005-9-11 20:08:00 | 显示全部楼层 |阅读模式
初学AVR,手头没有什么具体实践的课题,拆了几个小马达,玩玩中,也学到不少东西。希望可以给初学着一点帮助。

这个小型的直流电机控制系统很容易就可以实现,采用PWM调速方式,驱动电路,可以用分立元件搭,(网上这种电路很多),也可以采用集成IC器件,我采用的就是L293。电路很简单,就不画图了。

接线描述如下:

   PORTC7,PORTC6分别接L293 IN1,IN2,察看L293资料可知,ENA=H,IN1=H,IN2=L正转

                                                        ENA=H,IN1=L,IN2=H反转

                                             ENA=H,同IN2(IN4),同IN1(IN3)  快速停止

                                             ENA=L,                            停止

   OCR2接L293 ENA

   测速反馈信号接T0

代码描述如下:

   本系统可以同过串口接收上位机控制命令,可以实现开启,停机,调速,及时速度反馈。串口采用接收中断方式,命令协议如下:命令采用M**C模式,所有命令字符串以M开头,C结尾。中间两个字符定义:s表示调速,以第三个命令字符和0xff的比值作为PWM的占空比进行调速。

    d表示向上位机发送当前转速。

    t表示停机

    r表示开启

    o表示方向翻转

测速采用测速脉冲信号(霍尔速度传感器)作为T2的外部计数脉冲,T1 CTC模式,实现1s定时,比较匹配中断允许,中断服务程序读TCNT2的值,即为转速,读后重新初始化Timer2。

对初学者来说,测速可以使用cpu风扇来作试验,cpu风扇自带一个速度输出线,内部采用的是霍尔传感器,注意,霍尔传感器输出端是oc门开路,需要接上拉电阻。可以得到很标准的方波!另:注意将风扇接地和你的开发板接地连在一起。

原代码如下:

  程序采用的是ICC自动生成代码,再移植到codevision中,本人觉得ICC自动生成代码结构清晰,很适合初学者,也可能有不妥的地方!

// Target : M16

// Crystal: 4.0000Mhz



#include <mega16.h>

#include <delay.h>

#include <stdio.h>

unsigned char rx_data[5];//数据缓冲区

volatile unsigned char rx_counter=0;



volatile unsigned char crut_sped;//当前转速

//const unsigned char seg_table[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,

//0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

void port_init(void)

{

PORTA = 0x00;

DDRA  = 0x00;

PORTB = 0x00;

DDRB  = 0x00;

PORTC = 0b01000000; //m103 output only

DDRC  = 0xFF;

PORTD = 0xFF;

DDRD  = 0xFF;

}

//外部事件计数

void timer0_init(void)

{

TCCR0 = 0x00; //stop

TCNT0 = 0x00;

OCR0  = 0x00 ;   

TCCR0 = 0x07; //start

}  

//TIMER1 initialize - prescale:64

// WGM: 4) CTC, TOP=OCRnA

// desired value: 1Sec

// actual value:  1.000Sec (0.0%)

void timer1_init(void)

{

TCCR1B = 0x00; //stop

TCNT1H = 0x0B; //setup

TCNT1L = 0xDD;

OCR1AH = 0xF4;

OCR1AL = 0x23;

OCR1BH = 0xF4;

OCR1BL = 0x23;

ICR1H  = 0xF4;

ICR1L  = 0x23;

TCCR1A = 0b00000000;

TCCR1B = 0b00001011; //start Timer

}

//TIMER2 initialize - prescale:64

// WGM: PWM Phase correct

// desired value: 122Hz

// actual value: 122.549Hz (0.4%)

void timer2_init(void)

{

TCCR2 = 0x00; //stop

TCNT2 = 0x01; //set count

OCR2  = 0x3f;  //set compare

TCCR2 = 0b01100011; //start timer

}



interrupt [TIM1_COMPA] void timer1_compa_isr(void)

{

//compare occured TCNT3=OCR3A

crut_sped=TCNT0;

timer0_init();

}  

//UART0 initialize

// desired baud rate: 19200

// actual: baud rate:19231 (0.2%)

// char size: 8 bit

// parity: Disabled

void uart_init(void)

{

UCSRB = 0x00; //disable while setting baud rate

UCSRA = 0x00;

UCSRC = 0x06;

UBRRL = 0x0C; //set baud rate lo

UBRRH = 0x00; //set baud rate hi

UCSRB = 0x98;

}





interrupt[USART_RXC] void uart_rx_isr(void)

{

  /*if (rx_counter >= 4)

       {

               rx_counter = 0;

                if ((!(rx_data[0] == 'M'))||(!(rx_data[3] == 'C')))

                  {

                    rx_data[0]=0;

             rx_data[1]=0;

             rx_data[2]=0;

             rx_data[3]=0;

                  }  

       }   */

    rx_data[rx_counter] = UDR;

     

     if (rx_data[rx_counter]=='M')

       {

                 rx_data[0]=rx_data[rx_counter];

                 rx_counter=0;

       }

     rx_counter++;

  

      

}   



void init_devices(void)

{

//stop errant interrupts until set up

#asm("cli"); //disable all interrupts

port_init();

timer0_init();

timer1_init();

timer2_init();

uart_init();

MCUCR = 0x00;

GICR  = 0x00;

TIMSK = 0b00010000; //输出比较匹配A中断使能

#asm("sei");//re-enable interrupts

//all peripherals are now initialized

}

void timer2_reset(unsigned char i)

{

if((i>0x00)&&(i<0xff))

{

TCCR2 = 0x00; //stop

TCNT2 = 0x01; //set count

OCR2  = i;  //set compare

TCCR2 = 0b01100011; //start timer

}



}

void speed_direction(void)

{

  PORTC^=0x80;

  PORTC^=0x40;  

}



void main(void)

{

init_devices();

  while(1)

  {

    if (rx_counter==4)

       {

          rx_counter=0;

          if ((rx_data[0] == 'M')&&(rx_data[3] == 'C'))

          {

            if(rx_data[1]=='s')//设定速度

            {

             timer2_reset(rx_data[2]);

            }

             else if(rx_data[1]=='d')

               {

              putchar(crut_sped);

               }  

             else if(rx_data[1]=='t')

               {

              PORTC=0x00;

               }

             else if(rx_data[1]=='r')

             {

             PORTC=0x80;

             }

             else if(rx_data[1]=='o')

             {

             speed_direction();

             }

            }  

           else  

            

           {  

          printf("your command is wrong
");

             }

              rx_data[0]=0;

              rx_data[1]=0;

              rx_data[2]=0;

              rx_data[3]=0;

            }  

      

  }

}
-----此内容被crab于2005-09-14,08:57:08编辑过

出0入0汤圆

发表于 2005-9-11 20:28:50 | 显示全部楼层
好贴!谢谢!

出0入0汤圆

发表于 2005-9-12 23:28:39 | 显示全部楼层
最好有张图就更好不过了,不过还是讲谢谢

出0入0汤圆

 楼主| 发表于 2005-9-13 19:19:54 | 显示全部楼层
图太简单,如果有必要,可以抽空弄张。

另:使用串口调试助手进行调试的时候,最好使用16进制发送方式,那样Ms*C中的*即可使用确切16进制数值,可以比较精确确定占空比。注意:M用4DH代替,其他字符一样处理即可实现。还有,cpu风扇不能翻转!

出0入0汤圆

发表于 2006-1-23 08:22:20 | 显示全部楼层
你的电机是什么 ,一般非遥控玩具电动车上的直流电动机么?比如 130电机

出0入0汤圆

 楼主| 发表于 2006-3-12 19:08:35 | 显示全部楼层
小型的直流电机都可以啊,可以用cpu风扇啊,还有个速度输出线,注意它里面采用的是霍尔传感器,是OC门开路的,要接上拉

出0入4汤圆

发表于 2006-3-24 10:40:29 | 显示全部楼层

出0入0汤圆

发表于 2006-5-23 22:55:59 | 显示全部楼层
控制直流电机 有没有必要搞这么复杂啊?

出0入0汤圆

发表于 2006-5-24 11:22:21 | 显示全部楼层
给周期20ms的方波脉冲(脉冲部分在1ms到2ms内可调)控制调速器会比上诉方案简单一些的!

出0入0汤圆

发表于 2006-5-26 13:54:50 | 显示全部楼层
只有转速反馈吗?

用到pi调节了?

具体那一部分?

谢谢

出0入0汤圆

发表于 2006-8-18 13:53:47 | 显示全部楼层
谢谢!

出0入0汤圆

发表于 2006-9-4 11:47:08 | 显示全部楼层
好象没用道PID算法

出0入0汤圆

发表于 2006-10-1 16:48:16 | 显示全部楼层
http://www.openservo.com/



这儿肯定有你感兴趣的PID控制。!

出0入0汤圆

发表于 2006-10-3 17:21:24 | 显示全部楼层
http://www.openservo.com/ 上有数码舵机资料,俺看过,非常不错啊!

年初时俺在试着作数码舵机程序,可对于PID算法了解不多,当时还没上这个望去看,自己编了一个程序,但不用PID算法;在有输出位置差时全开输出端口,同时测电机转速,在输出臂快要到达舵机脉冲指定位置前一点使电机制动,制动开启时间与电机转速有关;程序编译通过后打了个面包板测试,基本上可以使用,就是制动开启时间和持续时间需要修改;后来朋友让俺看看这个网站,赫赫,原来使用PID算法要好一些;但前一段时间测试两种程序时发现,用PID的反应时间比俺自己做的要慢一点(测试舵机是用减速电机改装的为了测试方便采用了每分钟10转的)。。。。。

出0入0汤圆

发表于 2006-10-4 23:20:18 | 显示全部楼层
谢谢推荐的http://www.openservo.com/ 网站~~

我也在这这个实验~~

我觉得还是要用算法会好一些,为了加速响应可以在靠近目标位置的时候再用PID算法

频繁的制动会产生大量的热,而且在带上负载后很难有一个确定的制动时间,要么制动过头要么制动不足
-----此内容被violit于2006-10-04,23:25:39编辑过

出0入0汤圆

发表于 2006-10-4 23:39:43 | 显示全部楼层
呵呵,关注的人还挺多的阿。



那么咱们是不是该把那个资料整一份到这儿呢?



violit   来整理如何?

出0入0汤圆

发表于 2006-10-5 00:30:37 | 显示全部楼层
要说整理我还真不知道该怎么整理哦~~

刚才在啃英文~~

看到他的原理图中的驱动部分好像不提供能耗刹车功能,还有一个zxct1009来做电机电流检测,不知道这个片子好买不,可以用什么来替代?



另外觉得他的舵机好像是用IIC来做通信的,很适合做机器人,而且还多了反馈位置的功能,便于实现机器人的动作记忆,但是IIC通信距离不能太长,我觉得用485来不错的。

还有就是他的算法应该比较好,学习中~~~~~~
-----此内容被violit于2006-10-05,00:35:02编辑过

出0入0汤圆

发表于 2006-10-31 10:51:15 | 显示全部楼层
学习中!

准备用直流电机加速度传感作一个遥控小车 实现PID控制 有兴趣的朋友一起讨论~

出0入0汤圆

发表于 2006-10-31 13:22:11 | 显示全部楼层
好资料

出0入0汤圆

发表于 2006-11-7 14:41:14 | 显示全部楼层
http://www.openservo.com/

上去看看,是否有PID算法的例程?

出0入0汤圆

发表于 2007-4-1 16:28:59 | 显示全部楼层
呵呵  挺不错的,电路图要是能画上就更好的   呵呵  谢谢

出0入0汤圆

发表于 2007-4-1 16:29:40 | 显示全部楼层
呵呵  挺不错的,电路图要是能画上就更好的   呵呵  谢谢

出0入0汤圆

发表于 2007-5-28 11:35:45 | 显示全部楼层
强烈要求上电路图

出0入0汤圆

发表于 2007-5-28 21:42:05 | 显示全部楼层
贴个ARM上用的



/*****************************/

/*** WUDI'S 91SAM7S64 HEAD ***/

/*****************************/





#define IN1      (1<<7)

#define IN2      (1<<8)

#define IN3      (1<<9)

#define IN4      (1<<10)

#define EN1      (1<<11)

#define EN2      (1<<12)





void cfgout(unsigned int Flag)                  //config port as output

{

AT91F_PIO_CfgOutput(AT91C_BASE_PIOA,Flag);

AT91F_PIO_Enable(AT91C_BASE_PIOA,Flag);

}



void outh(unsigned int Flag)                  //set pin high

{

AT91F_PIO_SetOutput(AT91C_BASE_PIOA,Flag);

}



void outl(unsigned int Flag)                  //set pin low

{

AT91F_PIO_ClearOutput(AT91C_BASE_PIOA,Flag);

}





void go(signed char left,signed char right)

{

switch(left)

{

case -1:

outh(IN2|EN1);

outl(IN1);

break;

case 0:

outl(IN1|IN2|EN1);

break;

case 1:

outh(IN1|EN1);

outl(IN2);

break;

}



switch(right)

{

case -1:

outh(IN3|EN2);

outl(IN4);

break;

case 0:

outl(IN3|IN4|EN2);

break;

case 1:

outh(IN4|EN2);

outl(IN3);

break;

}

}









PS:使用前注意初始化

出0入0汤圆

发表于 2007-5-28 21:47:43 | 显示全部楼层
小型的电机驱动使用298/293芯片电路相当简单,只要按照DATASHEET上把IC和MCU与电源线连起来就可以了。



如果想学习原理,可以用三极管搭桥。



如果想要驱动大电流,可以参考我的帖子



http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=755194&bbs_page_no=2&bbs_id=1000



最大33A

出0入0汤圆

发表于 2007-8-14 09:52:55 | 显示全部楼层
如果这也叫好贴,那这个论坛的人都是傻鸟或者是垃圾初学者了,

出0入0汤圆

发表于 2008-4-7 15:35:51 | 显示全部楼层
个位大侠,有没有一个完整的用AVR控制直流电机的例子(有电路连接图最好).小弟想参考一下,谢谢.可以发到我的邮箱.pingping0229@126.com

出0入0汤圆

发表于 2008-4-13 14:07:01 | 显示全部楼层
有玩过步进电机
以前是用L298的芯片做

出0入0汤圆

发表于 2008-10-15 16:33:14 | 显示全部楼层
25楼的貌似很牛啊,初学者怎么的了

出0入0汤圆

发表于 2008-11-2 00:36:28 | 显示全部楼层
不过我真觉得贴程序没什么意思,LZ的付出令人敬佩,但是程序难读,而且每个人的程序风格和方法不同。看起来累。



说说方法和思路就很够了。大家就该明白了,程序自己思考。



方法和思路好不好都该鼓掌,呵呵

出0入0汤圆

发表于 2008-11-1 23:32:03 | 显示全部楼层
不错!学习一下!!

过段之间也控制一下直流电机

出0入0汤圆

发表于 2008-11-1 17:41:10 | 显示全部楼层
25楼没意思啊,你懂了,你也可以找点基础的帮帮我们初学的忙嘛!

出0入0汤圆

发表于 2008-10-15 23:49:03 | 显示全部楼层
L298

出0入0汤圆

发表于 2009-3-7 21:37:11 | 显示全部楼层
有哪位大家能帮忙编一个产生pwm的源程序,其空燃比用PID算法控制,小弟不胜感激

出85入4汤圆

发表于 2009-3-7 23:32:33 | 显示全部楼层
感谢楼主分享,小型直流电机驱动

出0入0汤圆

发表于 2009-3-11 07:51:41 | 显示全部楼层
感谢楼主分享

出0入0汤圆

发表于 2009-3-12 14:09:57 | 显示全部楼层
受教了 俺没25L牛

出0入0汤圆

发表于 2009-4-6 09:41:58 | 显示全部楼层
#include <reg52.h>
sbit KEY1 = P3^1;
sbit PWM = P1^5;
unsigned char CYCLE; //定义周期 该数字X基准定时时间 如果是10 则周期是10 x 0.1ms
unsigned char PWM_ON ;//定义高电平时间
void delay(unsigned int cnt)
{
while(--cnt);
}

main()
{
unsigned char PWM_Num;//定义档位
TMOD |=0x01;//定时器设置 1ms in 12M crystal
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;//定时1mS
IE= 0x82;  //打开中断
TR0=1;

CYCLE = 10;// 时间可以调整 这个是10步调整 周期10ms 8位PWM就是256步
while(1)
  {
if(!KEY1)
  {
   delay(10000);
   if(!KEY1)
     {
      PWM_Num++;
          if(PWM_Num==4)PWM_Num=0;
       switch(PWM_Num){
       case 0:P1=0xFE;PWM_ON=0;break;//高电平时长
       case 1:P1=0xFD;PWM_ON=4;break;
       case 2:P1=0xFB;PWM_ON=6;break;
       case 3:P1=0xF7;PWM_ON=8;break;
       default:break;
     }
   }

  }
}

}
/********************************/
/*      定时中断                */
/********************************/
void tim(void) interrupt 1 using 1
{
static unsigned char count; //
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;//定时1mS

if (count==PWM_ON)
    {
     PWM = 1; //灯灭
    }
  count++;
if(count == CYCLE)
    {
    count=0;
        if(PWM_ON!=0) //如果左右时间是0 保持原来状态
           PWM = 0;//灯亮

    }

}

出0入0汤圆

发表于 2009-5-4 20:28:08 | 显示全部楼层
拖25楼的出去枪毙~~~~~
初学者得罪你了?

出0入0汤圆

发表于 2009-5-18 15:54:43 | 显示全部楼层
爱好就是值得尊重     爱好就是动力  说不定通过努力 将来成为高手中的高手

出0入0汤圆

发表于 2009-8-25 08:59:46 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-1-5 22:13:11 | 显示全部楼层
我以前也用过293,不过我是用汇编编的

出0入0汤圆

发表于 2010-3-2 16:12:53 | 显示全部楼层
MARK!

出0入0汤圆

发表于 2010-8-30 16:56:29 | 显示全部楼层
顶上

出0入0汤圆

发表于 2010-8-30 23:06:14 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-6 15:20:16 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-21 04:48:46 | 显示全部楼层
mark

出0入0汤圆

发表于 2010-12-24 01:42:00 | 显示全部楼层
就冲楼主这精神也得收藏啊,谢谢分享!!慢慢品了

出0入0汤圆

发表于 2011-4-14 20:23:20 | 显示全部楼层
好贴

出0入0汤圆

发表于 2011-4-16 16:41:51 | 显示全部楼层
好贴

出0入0汤圆

发表于 2014-4-1 11:24:46 | 显示全部楼层
呵呵 正在弄小型直流电机
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-5 04:39

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表