📄 m8pwm._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 + -