搜索
bottom↓
回复: 8

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

[复制链接]

出0入0汤圆

发表于 2005-12-31 10:06:56 | 显示全部楼层 |阅读模式
m16的4路pwm不够用哈

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

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

阿莫论坛20周年了!感谢大家的支持与爱护!!

一只鸟敢站在脆弱的枝条上歇脚,它依仗的不是枝条不会断,而是自己有翅膀,会飞。

出0入0汤圆

 楼主| 发表于 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的大小,

出0入0汤圆

发表于 2005-12-31 18:06:21 | 显示全部楼层
为什么不用硬件的?

出0入0汤圆

 楼主| 发表于 2006-1-1 08:33:32 | 显示全部楼层
zhouyh :

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

我需要6路的pwm以上的

进行6个电机分别调速

调一个灯的亮度

出0入0汤圆

发表于 2006-1-2 00:46:54 | 显示全部楼层
arm可以

出0入0汤圆

 楼主| 发表于 2006-1-2 19:27:56 | 显示全部楼层
arm?说得容易哈

如果在要多几路pwm

arm还那么牛吗?

出0入296汤圆

发表于 2006-1-2 20:05:14 | 显示全部楼层
晕,动态改变是很容易的事情啊



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







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

程序名称:电机驱动程序

运行平台:ATMaga8 4m晶振

程序版本:2.0

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

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

                 pwm 波通过pc5输出

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

                 



键盘说明

        [rest]   [+]  [-]

                [none] [none] [none ]

                 

作者:傻孩子



最后修改:傻孩子

修改时间:2004年12月29日



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



#include <iom8v.h>

#include <macros.h>



#pragma  interrupt_handler Timer1_ovf:9

#pragma  interrupt_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[Where];  

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

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编辑过

出0入296汤圆

发表于 2006-1-2 20:09:13 | 显示全部楼层
当时刚刚学AVR,所以直接用TCNT0做的计数器,所以频率相当高。

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

if (TCNT0>Mark_Line)

      {

      //驱动电机

        PORTC |= 0b00100000;

      }

     else

      {

      //停止驱动

        PORTC &= 0b11011111;

      }



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

出0入0汤圆

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

本版积分规则

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

GMT+8, 2024-5-14 14:23

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

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