aman 发表于 2005-12-31 10:06:56

在m16中,用软件法怎么编pwm?用这种pwm驱动直流电机来的

m16的4路pwm不够用哈

在m16中,用软件法怎么编pwm?用这种可调的pwm驱动电机来的,

分辨率不作要求的从,占空比分5步达到就可以了,

aman 发表于 2005-12-31 17:35:51

#include <avr/io.h>

#include <avr/delay.h>

main()

{

int i=0x010;

while(i<=500)

   {

    PORTA=0x01

    _delay_us(i);

    PORTA=0x00;

    _delay_us(500-i);

   

   }

}



上面的只能生成单一的pwm,

我想用按键(pc的vb界面按键)控制他占空比的大小,

很难办到啊,



很难跳出上面循环,很难改变i的大小,

zhouyh 发表于 2005-12-31 18:06:21

为什么不用硬件的?

aman 发表于 2006-1-1 08:33:32

zhouyh :

有什么硬件介绍哈???/

我需要6路的pwm以上的

进行6个电机分别调速

调一个灯的亮度

hotpower 发表于 2006-1-2 00:46:54

arm可以

aman 发表于 2006-1-2 19:27:56

arm?说得容易哈

如果在要多几路pwm

arm还那么牛吗?

Gorgon_Meducer 发表于 2006-1-2 20:05:14

晕,动态改变是很容易的事情啊



一年前写的程序:这个程序用AD或者键盘来控制暂空比。







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

程序名称:电机驱动程序

运行平台:ATMaga8 4m晶振

程序版本:2.0

程序说明:通过按键 A/D输入来调节pw波

         pc0-pc4 对应 r3-r1(pc3 作为ad输入)

               pwm 波通过pc5输出

               当a/d输入有效时,键盘自动屏蔽

               



键盘说明

         [+][-]

               

               

作者:傻孩子



最后修改:傻孩子

修改时间:2004年12月29日



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



#include <iom8v.h>

#include <macros.h>



#pragmainterrupt_handler Timer1_ovf:9

#pragmainterrupt_handler Adc_isr:15   //

const char DispCode[]={0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,

0xee,0x3e,0x9c,0x7a,0x9e,0x8e}; //数码管译码表

const char DispBit[] = {0b11101111,0b11011111,0b10111111,0b01111111};//数码管初始位值



unsigned char Mark_Line=0x80;



//定时器延时

unsigned int Timer_Count_End=0;

unsigned int Timer_Count=0;



//unsigned char PressKey_Per_n_Timer_Ovf=0;        //定义按键时间计数器

unsigned char Press_Keys=0;    //按键代码



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

void Port_init(void);

void Timer0_init(void);

void Timer1_init(void);

void Timer1_ovf(void);

void Hardware_init(void);

void Delay_ms(unsigned int delay_time);

void Key_Press_Scan(void);

void adc_init(void);

void Display_Message(unsigned char Where,unsigned char Number,unsigned char delays);



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



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

                                                  端口初始化

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

void Port_init(void)

{

//定义c为输入

DDRC =0b11111111;

PORTC=0b11111111;

DDRC =0b00100000;   //PC5用来输出pw波



//定义B口为输出,用于显示数据

DDRB=0xff;

PORTB=0xff;



//定义D口为输出,用于显示数据

DDRD=0xff;

PORTD=0x00;



}



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

                                                  定时器0初始化

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

//TIMER0 initialize - prescale:1

// desired value: 20KHz

// actual value: 20.000KHz (0.0%)

//定时器0用来产生PW波

void Timer0_init(void)

{

TCCR0 = 0x00; //stop

TCNT0 = 0x38; //set count

TCCR0 = 0x01; //start timer

}



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

                                                  定时器1初始化

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

//定时器1主要用来做精确延时

void Timer1_init(void)                     

{

//定时器1部分

   TCNT1H = 0xE0;

   TCNT1L = 0xC0;

       TCCR1B = 0x01;                     //1分频,定时1ms

}



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

                                                  A/D初始化

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

void adc_init(void)

{

ADCSRA =0X00; //关闭AD

ADMUX = 0b00100011; //选择外部参考电源 ADC3 左对齐

ACSR = (1<<ACD); //关闭模拟比较器

ADCSRA = 0b10011101;//中断允许 32分频

}

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

                                                  A/D中断处理

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

void Adc_isr(void)

{

Mark_Line=ADCH; //读取高位数据(左对齐)

ADMUX = 0b00100011; //选择外部参考电源 ADC3 左对齐

ADCSRA |=(1<<ADSC);//启动AD转换

}

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

                                                  定时器1中断处理程序

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

void Timer1_ovf(void)                                      //1ms中断程序,检测主程序标志

{

       TCNT1H = 0xE0;

       TCNT1L = 0xC0;                                    //复位1ms记数器

           if (Timer_Count>0)

                     {

                   Timer_Count++;

                  }

               

          

           if (Press_Keys==2)

                     {

                   Mark_Line++;

                   if (Mark_Line>0xff)

                     {

                       Mark_Line=0x00;

                       }

                  }

           if (Press_Keys==3)

              {

                   Mark_Line--;

                   if (Mark_Line<0x01)

                  {

                       Mark_Line=0xff;

                        }

                  }

           if (Press_Keys==1)

              {

                   Mark_Line=0x80;   //复位

                  }

       

        if (TCNT0>Mark_Line)

           {

           //驱动电机

             PORTC |= 0b00100000;

           }

          else

           {

           //停止驱动

             PORTC &= 0b11011111;

           }

}



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

                                                  系统初始化

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

void Hardware_init(void)

{

CLI();



Port_init();

Timer1_init();

Timer0_init();

adc_init();

TIMSK = 0x04;



SEI();

}



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

                                                  延时程序

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

/*void Delay_ms(unsigned int delay_time)

{

Timer_Count_End=delay_time;

Timer_Count=1;                         //启动计数器

re_delay:

if (Timer_Count<=Timer_Count_End)

        {

       if (TCNT0>Mark_Line)

           {

           //驱动电机

             PORTC |= 0b00100000;

           }

          else

           {

           //停止驱动

             PORTC &= 0b11011111;

           }

       goto re_delay;

       

        }

   else

    {

       Timer_Count_End=0;

       Timer_Count=0;

        }

}*/

void Delay_ms(unsigned int m)//1ms延时

{

int l,j;

for(l=0;l<m;l++)

   for(j=0;j<500;j++)

   {

   if (TCNT0>Mark_Line)

           {

           //驱动电机

             PORTC |= 0b00100000;

           }

          else

           {

           //停止驱动

             PORTC &= 0b11011111;

           }

   }

}



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

                                                  按键扫描程序

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

void Key_Press_Scan(void)//判断键值

{ //unsigned char temp=0;

    //扫描第一列

        Press_Keys=0;

        PORTC = 0b00000111;

    DDRC =0b00110000;

        //temp=PINC;          

    if ( (PINC&0b00000100) == 0)   

          {

           Delay_ms(10);

           if ((PINC&0b00000100) == 0)

                     {

                  Press_Keys=1;

                  }

          }

    else if ((PINC&0b00000010) ==0)

          {

           Delay_ms(10);

           if ((PINC&0b00000010) ==0)

                     {

                  Press_Keys=2;

              }

          }

    else if ((PINC&0b00000001) ==0)   

          {

           Delay_ms(10);

           if ((PINC&0b00000001) ==0)

                     {

                  Press_Keys=3;

                  }

          }



   /*

        //扫描第二列

        PORTC = 0b00010111;   

             

    DDRC =0b00111000;

        //temp=PINC;

    if ( (PINC&0b00000100) == 0)

           {

                   Delay_ms(10);

          if ((PINC&0b00000100) == 0)

                     {

                  Press_Keys=4;

                  }

           }

    else if ((PINC&0b00000010) ==0)

           {

                   Delay_ms(10);

          if ((PINC&0b00000010) ==0)

                     {

                  Press_Keys=5;

                  }

           }       

    else if ((PINC&0b00000001) ==0)

           {

                   Delay_ms(10);

          if ((PINC&0b00000001) ==0)

                     {

                  Press_Keys=6;

                  }

           }*/

}





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

                                                  显示函数

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

void Display_Message(unsigned char Where,unsigned char Number,unsigned char delays)

{

//在指定的位置显示指定的数字

PORTD = DispBit;

PORTB = DispCode; //调用数码管译码表

Delay_ms(delays);

}



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

                                                        主函数

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

void main(void)

{

Hardware_init();

ADCSRA |=(1<<ADSC);//启动AD转换

while(1)

   {

           if (TCNT0>Mark_Line)

           {

           //驱动电机

             PORTC |= 0b00100000;

           }

          else

           {

           //停止驱动

             PORTC &= 0b11011111;

           }

   Key_Press_Scan();

        Display_Message(0,((Mark_Line<<4)>>4),5);

        Display_Message(1,(Mark_Line>>4),5);

   }

}




-----此内容被Gorgon Meducer于2006-01-02,20:10:51编辑过

Gorgon_Meducer 发表于 2006-1-2 20:09:13

当时刚刚学AVR,所以直接用TCNT0做的计数器,所以频率相当高。

为了获得相对稳定的波形,我当时重复拷贝了关键代码

if (TCNT0>Mark_Line)

      {

      //驱动电机

      PORTC |= 0b00100000;

      }

   else

      {

      //停止驱动

      PORTC &= 0b11011111;

      }



其实,比较规范的做法是,使用定时器中断产生一个精确的毫秒计数器,然后利用这个毫秒计数器来作为PWM输出的计数器,这样波形要漂亮的许多。

aman 发表于 2006-1-3 08:31:58

页: [1]
查看完整版本: 在m16中,用软件法怎么编pwm?用这种pwm驱动直流电机来的