在m16中,用软件法怎么编pwm?用这种pwm驱动直流电机来的
m16的4路pwm不够用哈在m16中,用软件法怎么编pwm?用这种可调的pwm驱动电机来的,
分辨率不作要求的从,占空比分5步达到就可以了, #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 :
有什么硬件介绍哈???/
我需要6路的pwm以上的
进行6个电机分别调速
调一个灯的亮度 arm可以 arm?说得容易哈
如果在要多几路pwm
arm还那么牛吗? 晕,动态改变是很容易的事情啊
一年前写的程序:这个程序用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编辑过 当时刚刚学AVR,所以直接用TCNT0做的计数器,所以频率相当高。
为了获得相对稳定的波形,我当时重复拷贝了关键代码
if (TCNT0>Mark_Line)
{
//驱动电机
PORTC |= 0b00100000;
}
else
{
//停止驱动
PORTC &= 0b11011111;
}
其实,比较规范的做法是,使用定时器中断产生一个精确的毫秒计数器,然后利用这个毫秒计数器来作为PWM输出的计数器,这样波形要漂亮的许多。 强
页:
[1]