⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 speed check avr.c

📁 用于测量电机转速并带速度反馈,配增量编码器,用AVR单片机ATMEGA48
💻 C
字号:
//ICC-AVR application builder : 2006-2-24 14:20:32
// Target : M48
// Crystal: 8.0000Mhz
//本程序采用M/T法进行测速,高速时采用M法,低速时采用T法。M1、M2分别为编码器脉冲计数和时钟脉冲计数

#include <iom48v.h>
#include <macros.h>
//#include <slavr.h>

#define TLC5615_CS(x) if(x==1)PORTB|=BIT(PB1);else PORTB&=~BIT(PB1)
#define MAX7219_CS(x) if(x==1)PORTB|=BIT(PB2);else PORTB&=~BIT(PB2)
#define SIGB    3//B输入接Pd3    
#define LED_NUM 5//显示LED的个数为5
#define MAX_5615  811//输出为10V时5615的值
#define MIN_5615  9  //输出为-10V时5615的值
#define ZERO_5615 410//输出为0V时5615的值
#define M_T_Point 16//M/T法的速度分界点,上一次计算得出的速度小于此值,则采取T法计算当前速度,否则采用M法计算
unsigned char led_buff[LED_NUM]={18,0,0,0,0};//led_buffer[0] is direction,other is rev  
const unsigned char Driver_table[8]={0x0c,0x01,0x0b,0x04,0x0a,0x0a,0x09,0x00};
const unsigned char seg_table[]={0x7e,0x30,0x6d,0x79,0x33,0x5b,0x5f,0x70,0x7f,0x7b,
	  		   		0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80,0x00};
unsigned int  Cnt_M1=1,Cnt_M1_Cur=1;//the number of pulse
unsigned int  Spd_buff[]={0,0,0,0};//速度显示缓冲器,用来存储转速
unsigned int  Cnt_M2=1,Cnt_M2_Cur=1;//number of counter within Cnt_M1
unsigned int  N_Last=24;//last rev
unsigned int  N_Current=0;//current rev
unsigned char Flag_M1=0x00;//the flag of start counting
unsigned char V_Flag=0;//速度计算方法选择标志
unsigned int  Speed_Num=0;//编码脉冲计数值,本例中为INTO的脉冲个数
unsigned char Calc_Flag=0;//速度计算标志,需进行计算时为0xff
unsigned char Run_Dir=0;//运行方向,正转时为0
unsigned char T1_OVF_Cnt=0;//T1溢出次数计数
unsigned char DISP_Cnt=0;//显示刷新时间控制
unsigned int  DA_OUT=0;//DA输出

void DA_transmit(unsigned int data);
void Refresh(void);

void port_init(void)
{
 PORTB = 0x06;
 DDRB  = 0xFF;//B口为输出
 PORTC = 0x00; //m103 output only
 DDRC  = 0x00;
 PORTD = 0x00;
 DDRD  = 0x00;//D口为输入
}
//TIMER1 initialize - prescale:8
// WGM: 0) Normal, TOP=0xFFFF
// desired value: 1Hz
// actual value: Out of range
void timer1_init(void)//用来计算M2值
{
 TCCR1B = 0x00; //stop
 TCNT1H = 0x00 /*INVALID SETTING*/; //setup
 TCNT1L = 0x00 /*INVALID SETTING*/;
 OCR1AH = 0x00 /*INVALID SETTING*/;
 OCR1AL = 0x00 /*INVALID SETTING*/;
 OCR1BH = 0x00 /*INVALID SETTING*/;
 OCR1BL = 0x00 /*INVALID SETTING*/;
 ICR1H  = 0x00 /*INVALID SETTING*/;
 ICR1L  = 0x00 /*INVALID SETTING*/;
 TCCR1A = 0x00;
}
//TIMER0 initialize - prescale:1024
// WGM: Normal
// desired value: 20mSec
// actual value: 19.968mSec (0.2%)
void timer0_init(void)
{
 TCCR0B = 0x00; //stop
 TCNT0 = 0x64; //set count
 TCCR0A = 0x00; 
 TCCR0B = 0x05; //start timer
}

#pragma interrupt_handler timer0_ovf_isr:17
void timer0_ovf_isr(void)
{
	SEI();//开中断,允许中断嵌套
	DISP_Cnt++;
	TCNT0 = 0x64; //set count //TIMER0 has overflowed
	DA_OUT=N_Current/5;//????????
	if(Run_Dir==0)
	{
		DA_OUT+=ZERO_5615;
	}
	else
	{
		DA_OUT=ZERO_5615-DA_OUT;
	}
	DA_transmit(DA_OUT);
	if(DISP_Cnt>=10)//每200MS刷新一次显示
	{
		Refresh();
		DISP_Cnt=0;
	}
}

#pragma interrupt_handler timer1_ovf_isr:14
void timer1_ovf_isr(void)
{
	//TIMER1 has overflowed
	T1_OVF_Cnt++;
	N_Last=M_T_Point;
	N_Current=M_T_Point; //将这两个值给0是否可以消除不回零的情况呢?????????
	V_Flag=0;//采用T法计算速度
	Calc_Flag=0xFF;//计算速度
	EIMSK&=~BIT(INT1);//INT1中断禁止

}

void SPI_transmit(unsigned char data,unsigned char addr)
{
 unsigned char temp;
 MAX7219_CS(0);
 SPDR=addr;
 while(!(SPSR&(1<<SPIF)));
 SPDR=data;
 while(!(SPSR&(1<<SPIF)));
 MAX7219_CS(1);
}

//Refresh LED Displayer
void Refresh(void)
{
 unsigned char i,temp;
 if(Run_Dir==0)
	led_buff[0]=18;
 else
	led_buff[0]=10;
 for(i=0;i<LED_NUM;i++)
 {
  temp=led_buff[i];
  temp=seg_table[temp];
  SPI_transmit(temp,i+1);
 }
}

void init_7219(void)
{
 unsigned char cmd_code,led_addr;
 int i,j;
 for(i=0;i<4;i++)
 {
  j=i*2;
  cmd_code=Driver_table[j+1];
  led_addr=Driver_table[j];
  SPI_transmit(cmd_code,led_addr);
 }
 Refresh();  
}


//SPI initialize
// clock rate: 125000hz
void spi_init(void)
{
 SPCR = 0x52; //setup SPI
 SPSR = 0x01; //setup SPI
}

void Rev_transfer(unsigned int rev)//将速度值存储到显示缓冲区
{
	unsigned char i;
	for(i=1;i<5;i++)
	{
		led_buff[5-i]=rev%10;//依次取个位、十位、百位、千位
		rev/=10;
	}
}

void Calc_Speed(void)//M/T法公式为N=(60f/p)*(M1/M2)=(60*1M/600)*(M1/M2)=100000*(M1/M2)
{
	unsigned long temp=0;
	if(V_Flag==0xFF)//M法
	{
		temp=100000*Cnt_M1;
		N_Current=temp/Cnt_M2;
	}
	else
	{
		N_Current=25000/Cnt_M2;//T法,此时M1=1/4
	}
}

#pragma interrupt_handler int0_isr:2
void int0_isr(void)
{
	T1_OVF_Cnt=0;//timer1溢出中断次数清零
	Run_Dir=PIND&(1<<SIGB);//INT0上升沿中断时,若SIGB=0时为正向
	if(V_Flag==0)//speed low,采用T法测速
	{
		EIFR|=BIT(INTF1);//清INT1中断标志,防止错误中断
		EIMSK|=BIT(INT1);//enable INT1
		TCCR1B = 0x00; //stop
		TCNT1H = 0x00; 
		TCNT1L = 0x00;//clear timer1
		TCCR1B = 0x02; //start Timer,并且为8分频
	}
	else
	{
		if(Flag_M1==0)//开始用M法测速
		{
			Flag_M1=0xFF;
			TCCR1B = 0x00; //stop
			TCNT1H = 0x00; 
			TCNT1L = 0x00;//clear timer1
			TCCR1B = 0x02; //start Timer
			Cnt_M1_Cur=N_Last>>3;//M1的值为上次速度的1/8
			Speed_Num=0;
		}
		else
		{
			Speed_Num++;
			if(Speed_Num>=Cnt_M1_Cur)
			{
				TCCR1B = 0x00; //stop
				Calc_Flag=0xFF;
				Cnt_M2_Cur=TCNT1L;
				Cnt_M2_Cur+=(unsigned int)(TCNT1H<<8);//读取M2的值
				Flag_M1=0;
			}			
		}
	}
}

#pragma interrupt_handler int1_isr:3
void int1_isr(void)
{
	Calc_Flag=0xFF;//计算速度
	TCCR1B = 0x00; //stop timer1
	Cnt_M2_Cur=TCNT1L;
	Cnt_M2_Cur+=(unsigned int)(TCNT1H<<8);//读取M2值
	EIMSK&=~BIT(INT1);//disable INT1
	TCCR1B = 0x02;//enable timer1
}

//call this routine to initialize all peripherals
void init_devices(void)
{
 //stop errant interrupts until set up
 CLI(); //disable all interrupts
 port_init();
 spi_init();
 timer0_init();
 timer1_init();

 MCUCR = 0x00;
 EICRA = 0x07; //extended ext ints,INT0为上升沿中断,INT1为任意沿中断
 EIMSK = 0x01;//open INT0 interrupt
 
 TIMSK0 = 0x01; //timer 0 溢出中断使能
 TIMSK1 = 0x01; //timer 1 溢出中断使能
 TIMSK2 = 0x00; //timer 2 interrupt sources
 
 PCMSK0 = 0x00; //pin change mask 0 
 PCMSK1 = 0x00; //pin change mask 1 
 PCMSK2 = 0x00; //pin change mask 2
 PCICR = 0x00; //pin change enable 
 PRR = 0x00; //power controller
 init_7219();
 SEI(); //re-enable interrupts
 //all peripherals are now initialized
}

void DA_transmit(unsigned int data)//将DA数据发送到5615
{
 unsigned char temp1,temp2;
 data<<=2;//5615为12位数据输出,最低2位为无效位,所以输出数据左移两位
 temp1=data>>8;//DA高8位
 temp2=data;//DA低8位
 TLC5615_CS(0);
 SPDR=temp1;
 while(!(SPSR&(1<<SPIF)));
 SPDR=temp2;
 while(!(SPSR&(1<<SPIF)));
 TLC5615_CS(1);
}

void main(void)
{
	unsigned char i;
	unsigned int temp=0;
	init_devices();
	if(N_Last<M_T_Point)
		V_Flag=0;
	else
		V_Flag=0xff;
	
	while(1)
	{
		if(Calc_Flag==0xFF)
		{
			if(T1_OVF_Cnt<1)//T1无溢出
			{
				Cnt_M1=Cnt_M1_Cur;
				Cnt_M2=Cnt_M2_Cur;
				Calc_Speed();
			}
			else//Timer1 溢出
			{
				N_Current=0;
				T1_OVF_Cnt=0;
			}
			temp=0;
			for(i=1;i<4;i++)
			{
				Spd_buff[4-i]=Spd_buff[3-i];
				temp+=Spd_buff[3-i];
			}
			Spd_buff[0]=N_Current;
			temp+=N_Current;
			N_Current=temp>>2;//滑动滤波,采用4组数据
			N_Last=N_Current;
			if(N_Last<M_T_Point)
				V_Flag=0;
			else
				V_Flag=0xff;
			Calc_Flag=0;
			Rev_transfer(N_Current);			
		}
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -