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

📄 m8pwm._c

📁 电动车控制器
💻 _C
字号:
/****************************************************************************** 
程序名称:电机驱动程序 
运行平台:ATMaga8 12m晶振 
程序说明:通过输入来调节pw波 
pc3 作为ad输入 

PD5=运行状态指示灯
pb0=左转灯,pb1=右转灯,pb=0时灯亮, 左右灯同时亮起为刹车状态 
 2007-12-24
******************************************************************************/ 
#include <iom8v.h> 
#include <macros.h> 

#pragma  interrupt_handler Timer1_vof:9  //计算速度信息
#pragma  interrupt_handler Adc_isr:15   // 采集握把信号
#pragma  interrupt_handler int0_isr:2    //用于计算每秒钟后轮转过的半圈数
#pragma  interrupt_handler int1_isr:3    //用于相应刹车 
#pragma  interrupt_handler uart0_rx_isr:12//串口接收程序

#define  uchar      unsigned char
#define  uint       unsigned int
#define  BRAKE_LED_ON      PORTC |=0x03
#define  BRAKE_LED_OFF     PORTC &=0xfc
#define  LEFT_LED_ON       PORTC |=0x01
#define  LEFT_LED_OFF      PORTC &=0xfe
#define  RIGHT_LED_ON      PORTC |=0x02
#define  RIGHT_LED_OFF     PORTC &=0xfd
#define  EEP_RANG          170
//Variable
unsigned char AdResult=0x10; //保存AD结果
unsigned char SpeedVal=0;    //速度
unsigned char RolCount=0;   //每秒钟后轮转过的半圈数
unsigned int  RolNum=0;     //记录总的圈数据,满1000米后将里程写入eeprom
unsigned int  KiloMeter=0;//里程数据
unsigned int  OldKiloMeter=0; //前一里程数据
unsigned char TenMeter=0;   //十米里程计数
unsigned char UartBuf[10],UartBufCount=0;
unsigned char LrLedReg=0;   //用于保存刹车灯的状态,以便在刹车释放后回复
unsigned char BrakeFlag=0;  //0=刹车松开,0x55=刹车



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

 /***************************************************************************/ 
 void Port_init(void); 
 void uart0_init(void);
 void uart0_tx(unsigned char tdata);
 void tx_pack(uchar mode);
 void Timer0_init(void); 
 void Timer1_init(void); 
 void Timer2_init(void);
 void SpeedControl(void);
 void Timer1a_c(void); 
 void Hardware_init(void); 
 void EepromWrite(uchar Address, uchar Data);
 uchar EepromRead(uchar Address);
 void Delay_ms(unsigned int delay_time); 
 void adc_init(void);   
/*************************************************************************** 
                                                    端口初始化 
****************************************************************************/ 
void Port_init(void) 
{ 
 
 PORTB=0b11110111; 
 DDRB =0b00001000;   //PB3用来输出pw波 
 PORTC=0b11111111;   //上拉使能
 DDRC =0b00100011;   //pc0,1=LR_led,Pc5=led in 
 //PORTD=0xff; 
 //DDRD =0xe0;   // d6d7=lr_led
 
}
/*************************************************************************** 
             串口0初始化 
****************************************************************************/  
// desired baud rate: 9600
// actual: baud rate:9615 (0.2%)
// char size: 8 bit
// parity: Disabled
void uart0_init(void)
{
 UCSRB = 0x00; //disable while setting baud rate
 UCSRA = 0x00;
 UCSRC = BIT(URSEL) | 0x06;
 UBRRL = 0x4D; //set baud rate lo
 UBRRH = 0x00; //set baud rate hi
 UCSRB = 0x98;
}

/*************************************************************************** 
                                                    定时器1初始化 
****************************************************************************/ 
//定时器1主要用来做速度扫描
void Timer1_init(void)                      
{ 
 //定时器1部分 ,1024分频,定时1s 
   TCCR1B = 0x00; //stop
   TCNT1H = 0xD2; //setup
   TCNT1L = 0x3A;
   OCR1AH = 0x3D;
   OCR1AL = 0x09;
   OCR1BH = 0x3D;
   OCR1BL = 0x09;
   //OCR1CH = $OCR1CH$;
   //OCR1CL = $OCR1CL$;
   ICR1H  = 0x3D;
   ICR1L  = 0x09;
   TCCR1A = 0x00;
   TCCR1B = 0x05; //start Timer
} 
/*************************************************************************** 
           Timer2初始化 ,PWM
****************************************************************************/ 
// desired value: 20KHz 
// actual value: 20.000KHz (0.0%) 
//定时器0用来产生PW波 
void Timer2_init(void)
{
 TCCR2 = 0x00; //stop
 ASSR  = 0x00; //set async mode
 TCNT2 = 0x0; //setup
 OCR2  = 0x1;//设置OCR2
 TCCR2 = 0x69; //8M/8=1MHz,0x79
}
/*************************************************************************** 
                                                    A/D初始化 
****************************************************************************/ 
void adc_init(void) 
{ 
 ADCSRA =0x0; //关闭AD 
 ADMUX = (1<<REFS0)|(1<<ADLAR)|(1<<MUX1)|(1<<MUX0); //选择外部参考电源 ADC3 左对齐 
 ACSR = (1<<ACD); //关闭模拟比较器 
 ADCSRA = (1<<ADEN)|(1<<ADIF)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS0);//中断允许 32分频 
 } 
/*************************************************************************** 
                                                    A/D中断处理 
****************************************************************************/ 
void Adc_isr(void) 
{ 
 AdResult=ADCH; //读取高位数据(左对齐)
 //OCR2 = 0xff - AdResult; //更新PWM参数  
 
} 
/*************************************************************************** 
          定时器1中断处理程序 
****************************************************************************/ 
void Timer1_vof(void)                                      
//1s中断程序,用于检测转速
{    
   TCNT1=0xD23A;
   SpeedVal=RolCount*1.13;  //3.1415*3.6*后轮半径(0.1m)=1.13                   
   RolCount=0;    
     
} 
/*************************************************************************** 
          外部中断0处理程序 
****************************************************************************/
void int0_isr(void)
{
 //external interupt on INT0
    RolCount++;//半圈数增加	
	if(RolNum> 3183)//半圈=3.1416*0.1米=0.31416米,1000/0,31416=3183
	{
	   RolNum=0;
	   ++KiloMeter;//个位,十位不为0,只需要改变个位十位	
	}
}
/*************************************************************************** 
          外部中断1处理程序 
****************************************************************************/
void int1_isr(void)
{
   //external interupt on INT1
   if(MCUCR&(0x01<<ISC10))
   {//上升沿触发中断,为释放状态  
      TCCR2=0x69; //8M/8=1MHz
	  MCUCR&=~(0x01<<ISC10);//clear ISC10 ,设为下降沿触发
	  BRAKE_LED_OFF;
	  BrakeFlag=0;
   }
   else
   {//下降沿触发中断,为刹车状态  
      TCCR2=0;//
	  MCUCR|=(0x01<<ISC10);//set ISC10,设为上升沿触发
	  BRAKE_LED_ON;
	  BrakeFlag=0x55;
   }   
}
/*************************************************************************** 
                     串口接收中断程序
****************************************************************************/ 
void uart0_rx_isr(void)
{
 //uart has received a character in UDR    
	
	UartBuf[UartBufCount++]= UDR;
	//PORTC ^=0x20;
	if(UartBuf[0]==0xaa)//包头
	{
	//UartBuf[3]=Rev,Rev,Rev,RevMode,Rev,Rev,LEFT_LED,RIGHT_LED
	
	     if(UartBufCount>4)
		 {
		    if( ((UartBuf[1]+UartBuf[2])==0xff)&&
				((UartBuf[3]+UartBuf[4])==0xff) ) 
			{				    		        
				LrLedReg=UartBuf[3]&0x03;//
				if(BrakeFlag!=0x55)
				{
				    PORTC&=0xfc;//
				    PORTC|=LrLedReg;	
				}	       
		        tx_pack(UartBuf[3]);
				PORTC ^=0x20;						
		    }
		    UartBufCount=0;			
	     }	    
	}
	else UartBufCount=0;   
	
}
/*************************************************************************** 
                     串口接收程序
****************************************************************************/ 
void uart0_tx(unsigned char tdata)
{
   while(!(UCSRA & (1<<UDRE) ));
   UDR = tdata;
}
void tx_pack(uchar mode)
{   //revmode=mode&0x10
    uchar tmptt;
	uart0_tx(0xaa);
	if(mode&0x10)
	{//revmode=1,返回里程;
	    tmptt=KiloMeter&0x00ff;
		uart0_tx(tmptt);
        uart0_tx(0xff-tmptt);
		tmptt=(KiloMeter>>8)&0x00ff;
	    uart0_tx(tmptt);//+24V
	    uart0_tx(0xff-tmptt);
	}
	else
	{//revmode=0,返回电压和速度
	    uart0_tx(SpeedVal);
        uart0_tx(0xff-SpeedVal);
	    uart0_tx(AdResult);//+24V
	    uart0_tx(0xff-AdResult);
	
	}	
}
void SpeedControl(void)
{
    uint tmp1,tmp2;
	tmp1=OCR2+SpeedVal+5;
	if(tmp1>0xff)tmp1=0xff;	 
	if( UartBuf[1]>tmp1 )
	{
	    OCR2 = (tmp1&0x00ff);//速度控制信息
	}	
	else OCR2 = UartBuf[1];
	//OCR2 = UartBuf[1];
}
/*EEPROM读*/
uchar EepromRead(uchar Address)  
{  	
	uchar eeprom_temp[3];
	uchar eeprom_data,k,eeprom_flag=0;
	for(k=0;k<3;k++)
	{
	    while(EECR & (1<<EEWE));  
		EEAR = Address+k*EEP_RANG;       //一次读出三个单元的内容然后判断,
		EECR |= (1<<EERE);  
	  	eeprom_temp[k]=EEDR;
	}
	/*判断读取的数据是否正确*/
	if( (eeprom_temp[0]==eeprom_temp[1]) & (eeprom_temp[1]==eeprom_temp[2]) )
		eeprom_data=EEDR;
	/*判断发生错误的单元,少数服从多数原则*/
	else if(eeprom_temp[0]==eeprom_temp[1])
		 {
		 /*第三单元出错*/
		     eeprom_data = eeprom_temp[0];
		     eeprom_flag=0xff;
		 }
	else if(eeprom_temp[1]==eeprom_temp[2])
		 {
		 /*第一单元出错*/
		     eeprom_data = eeprom_temp[1];
		     eeprom_flag=0xff;
		 }
	else if(eeprom_temp[0]==eeprom_temp[2])
		 {
		 /*第二单元出错*/
		     eeprom_data = eeprom_temp[0];
		     eeprom_flag=0xff;
		 }
	else
	     {//三个单元都不相等,则将数据填为0xff
		    eeprom_data = 0xff;
			eeprom_flag=0xff;
		 }
	if(eeprom_flag)EepromWrite(Address,eeprom_data);//发生错误,则将数据重新写入	
return eeprom_data; 	 
}  
///////////////////////////////////////////////////////////////////////////////
//*EEPROM写,一次写三单元,作为备份*/
void EepromWrite(uchar Address, uchar Data)  
{  
	char tmpeeprom,k;
	tmpeeprom=SREG;          		 // 保存当前设置,以便恢复
   	CLI();                    		 // 关闭中断
	if(Address >EEP_RANG)Address=EEP_RANG;
	for(k=0;k<3;k++)
	{
	   while(EECR & (1<<EEWE));  	 
   	   EEAR = (Address+k*EEP_RANG);  		// 写地址,相隔rang个单元
   	   EEDR = Data;  					// 写数据
   	   EECR |= (1<<EEMWE);  	    	// 置位EEMWE同时清零EEWE
  	   EECR |= (1<<EEWE);        		 // 在4个时钟周期内置位EEWE  	                  		
   	   EEAR = 0;    	 
    }
	SREG =tmpeeprom; 	 // 恢复当前设置
    SEI();				            // 打开中断
} 
/*************************************************************************** 
                                                    系统初始化 
****************************************************************************/ 
void Hardware_init(void) 
{ 
 CLI();   
 Port_init(); 
 uart0_init();
 Timer1_init(); 
 Timer2_init(); 
 adc_init(); 
 MCUCR = (0x01<<ISC01)|(0x01<<ISC11);//INT0、1下降沿触发
 GICR  = (0x01<<INT0)|(0x01<<INT1); //INT0、1使能
 TIMSK = (0x01<<OCIE1A);   
 SEI(); 
 BRAKE_LED_OFF;
 KiloMeter=EepromRead(1)+EepromRead(2)*0x100;
 OldKiloMeter=KiloMeter;
 if(KiloMeter==0xffff)KiloMeter=0;
} 

/*************************************************************************** 
                                                    延时程序 
****************************************************************************/ 

void Delay_ms(unsigned int m)  //1ms延时 
{ 
 int l,j; 
 for(l=0;l<m;l++) 
   for(j=0;j<500;j++) 
   { 
       ;
   } 
} 
/************************************************************************** 
                                                        主函数 
**************************************************************************/ 
void main(void) 
{ 
 int k=0,adc=0;
 uchar edata;
 Hardware_init(); 
 while(1) 
   {         
		if(KiloMeter!=OldKiloMeter)
		{ 
		    edata = KiloMeter&0x00ff;
			if(edata) //只改变十位个位
			{
			    EepromWrite(1,edata); //30ms
			}
			else
			{   //60ms
			    EepromWrite(1,edata);
				edata = (KiloMeter>>8)&0x00ff;
				EepromWrite(2,edata);
			}			
		}
		if(++adc>1)
		{
		    ADCSRA |=(1<<ADSC);  //启动AD转换 
			adc=0;
		}
		Delay_ms(100);
        SpeedControl();
				
   } 
} 

⌨️ 快捷键说明

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