|
本人新手,用的AVR mega16 想写一个简单的函数。让电机能够在速度为0的时候抱死,即用手拧不动。就用了比例一项。
我用的是输入捕获来计算脉冲的数目,同时在输入捕获的中断里面判断AB相的方向,如果正向就脉冲数加1 ,反之减1。现在有点不理解的就是,是否我可以用定时器每隔5个微秒读一下脉冲数和输入捕获里面的定时值。但是这样的话,定时值感觉就没有太大的意义了。不知道应该怎么处理呢?我程序里面写的是脉冲值一个变量,另外一个变量是无论脉冲正反,他都记一次数。记了10次,他就算一下脉冲值(有方向那个)和输入捕获的时间值。但是这样,如果速度为0的话,很有可能那个脉冲值达不到10.想问下有什么好办法吗?
下面是程序://定时器2 PWM输出端口在OC2引脚 ,PC2为码盘B相输入
//电机减速后事150转 码盘线数是400
#include<iom16v.h>
#include<macros.h>
#define uint unsigned int
#define uchar unsigned char
/**********************************************
电机速度和转向宏定义
***********************************************/
//定义PC0口为电机正反控制端1
#define CRT1_POWERON PORTC|=BIT(0)
#define CRT1_POWEROFF PORTC&=~BIT(0)
//定义PC1口为电机正反控制端2
#define CRT2_POWERON PORTC|=BIT(1)
#define CRT2_POWEROFF PORTC&=~BIT(1)
//限制最高转速 若要求限定最高转速,改变这个值即可
#define speed_MAX 255
//限制最高转速 若要求限定最高转速,改变这个值即可
#define speed_MIN 0
/**********************************************
码盘宏定义
码盘M/T法测速:
测速时间内码盘输出的脉冲数m1,又检测同一时间间隔内高频时钟脉冲数m2。
设高频时钟脉冲频率为f0 则测速时间 T=M2/f0;
习惯上转速常以每分钟转数来表示,则电机的转速可表示为:
n=60M1 *f0/(z*M2) r/min
式中,z为电机每转一圈所产生的脉冲数(z=倍频系数×码盘光栅数)
***********************************************/
#define CRYSTAL 80000000 //晶振
#define N 7000 //定义码盘线数
#define BEI 1 //倍频数
#define M1 100 //定义每次需测量的码盘输出的脉冲个数
#define f0 CRYSTAL/256//定义时钟
#define feedback 60*time*f0/(N*clknum) //定义码盘反馈的转速
#define setPWM OCR2 //PWM
//#define direction PC2 //定义码盘B相,码盘A相接ICP1 如果B相为1,则为正,为0 ,则为负
/**********************************************
PID参数宏定义
***********************************************/
#define P 100
#define I 10
#define D 20
float setspeed; //设定转速
uchar direction; //定义方向,1为正,0为反
uint olddata =0;//输入捕获ICP1的旧读数
uint newdata=0;//输入捕获ICP1的读数
uint clknum=0;
int adjPWM; //PID调整后的PWM
int tt; //码盘上升沿次数
float time; //码盘上升沿次数 ,分了方向的
float adjspeed;
//1ms延时,准确性较高
void DelayMs(unsigned int i)
{
while(i--)
{
unsigned int j;
for(j=1;j<=613;j++) ;
}
}
/*-----------------------------------------------------------------
函数名称: void time2_int(void)
函数功能: 定时器2初始化函数
参 数: 无
返 回 值: 无
-----------------------------------------------------------------*/
void time2_int(void)
{
TCNT2=0X01;
OCR2=100;
TCCR2=(1<<WGM20)|(1<<WGM21)|(1<<COM21)|0x06;//快速PWM,256分频,升序清0,降序置1
TIMSK=0XC0; //定时器2溢出中断使能,比较匹配中断使能
}
void PORT_INIT()
{
DDRA|=0XFF;
PORTA|=0;
DDRB|=0XFF;
PORTB|=0;
DDRC|=0XFF&(~(1<<2));
// PORTC|=BIT(0)|BIT(1);
DDRD|=0XFF;
// PORTD|=BIT(7);
}
/*正方向*/
void zheng()
{
CRT1_POWERON;
CRT2_POWEROFF;
}
/*反方向*/
void fan()
{
CRT1_POWEROFF;
CRT2_POWERON;
}
/*停止*/
void stop()
{
CRT1_POWEROFF;
CRT2_POWEROFF;
}
/*正转*/
void forward (float setspeed)
{
if(speed!=0)
{
setPWM=(setspeed*255)/150;//setspeed是想要的转速,这里把它转化成PWM的数字(0~255)
}
zheng();
}
/*反转*/
void reverse (uchar setspeed)
{
if(speed!=0)
{
setPWM=(setspeed*255)/150; //setspeed是想要的转速,这里把它转化成PWM的数字(0~255)
}
fan();
}
/*PID反馈调速*/
void speedadjust()
{
adjspeed=P*(setspeed-feedback);
if(feedback>setspeed)
{
setspeed=adjPWM;
zheng();
// PORTC ^= (1 << PC0);
//PORTC ^= (1 << PC1);
}
else
{
setspeed=adjPWM;
fan();
//PORTC ^= (1 << PC0);
//PORTC ^= (1 << PC1);
}
forward(setspeed);
}
/*
输入捕获初始化
*/
void Timer1_Init(void)
{
TCCR1A = 0x00;
// Input Capture on Falling Edge
TCCR1B = (1<<ICNC1)|(0<<ICES1)|(0<<CS12)|(1<<CS11)|(1<<CS10); //噪声抑制 ,低电平进行捕捉 , 64预分频
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK = (1<<TICIE1); //定时器1 输入捕捉使能
}
//定时器1 输入捕获中断
#pragma interrupt_handler timer1_capt_isr:6
void timer1_capt_isr(void)
{
if( PINC & (1 << 3) ) //读取PC2位,即B相
{time++;}
else
{
time--;
}
tt++;
if(tt==M1)// 100次读一下
{
tt=0;
time=0;
newdata=ICR1;
clknum=newdata-olddata;
olddata=newdata;
}
}
/*读取内部时钟的计数值
void readclk()
{
tt=0;
time=0;
newdata=ICR1;
clknum=newdata-olddata;
olddata=newdata;
}*/
void main()
{
Timer1_Init();
_SEI(); //全局中断使能
PORT_INIT();
time2_int();
while(1)
{
forward(0);
speedadjust();
DelayMs(50);
}
} |
阿莫论坛20周年了!感谢大家的支持与爱护!!
曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……
|