mega16 控制步进电机调整调压器 从而控制电流
刚学 AVR不久 利用它改进了先前开发的一个控制系统,电路图线路板实物图随后给出先贴点东西 以感谢网站的培育之恩!
/***********************************************
**** AVR 自动分解程序 ***
**** ***
**** 策划、整理与测试: 许汉武 ***
**** 代码编写:xuhanwuAVR ***
**** 编译器:WINAVR20050214 ***
**** TEL:13860186*** ***
**** xuhw@lisheng-xm.com 2006.4.28 ***
***********************************************/
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/signal.h>
#include <avr/interrupt.h>
#include <stdio.h>
//#include <avr/pgmspace.h>
#define uchar unsigned char
#define uintunsigned int
//#define MAX2 PA2 //调压器2到达最大时该引脚被拉低
#define MAX1 !(PINA&_BV(PA2)) //一旦按下开始按键,该位1
//#define MIN2 PA3 //调压器1到达最小时该引脚被拉低
#define MIN1 !(PINA&_BV(PA3)) //一旦按下开始按键,该位1
//#define MAX1 PA4
#define MAX2 !(PINA&_BV(PA4)) //一旦按下开始按键,该位1
//#define MIN1 PA5
#define MIN2 !(PINA&_BV(PA5)) //一旦按下开始按键,该位1
#define LG PA6
#define LR PA7
#define LG_ON()PORTA&=~_BV(PA6)//设置绿色的指示灯亮
#define LR_ON()PORTA&=~_BV(PA7)//设置红色的指示灯亮
#define LG_OFF() PORTA|=_BV(PA6) //设置绿色的指示灯灭
#define LR_OFF() PORTA|=_BV(PA7) //设置红色的指示灯灭
#define DIR2PC0 //步进电机2方向控制
#define PLS2PC1 //步进电机2脉冲输出
#define DIR1PC2 //步进电机1方向控制
#define PLS1PC3 //步进电机1脉冲输出
#define SET_DIR2()PORTC|=_BV(DIR2)
#define CLR_DIR2()PORTC&=~_BV(DIR2)
#define SET_PLS2()PORTC|=_BV(PLS2)
#define CLR_PLS2()PORTC&=~_BV(PLS2)
#define SET_DIR1()PORTC|=_BV(DIR1)
#define CLR_DIR1()PORTC&=~_BV(DIR1)
#define SET_PLS1()PORTC|=_BV(PLS1)
#define CLR_PLS1()PORTC&=~_BV(PLS1)
#define T_MAX PC4 //温度上限控制
#define T_MIN PC5 //温度下限控制
#define START !(PINC&_BV(PC6)) //一旦按下开始按键,该位1
#define AUTO!(PINC&_BV(PC7)) //一旦按下开始按键,该位1
#define PIN_RXD PD0 //通讯口
#define PIN_TXD PD1 //通讯口
#define STOPPD2 //停止按键口,接至外部中断0
#define DE PD4 //DE输出为1时处于发送状?
#define SET_DE() PORTD|=_BV(DE)
#define CLR_DE() PORTD&=~_BV(DE)
#define TEST_N 5 //数模转换中值取样次数
#define INBUF_LEN 39 //用于存放所接收的分界参数
uchar inbuf;
uchar *str;
//uchar count_read;
//uint ADC0_Result; // ADC0转换结果
//uint ADC1_Result; // ADC1转换结果
volatile uchar g_bCount=0;
volatile uchar STOP_FLAG;
volatile uchar system_time;
//static
//分解参数
uchar cur_1; //分解电流1
uchar cur_2;
uchar cur_3;
uchar cur_4;
uchar cur_5;
uchar cur_6;
uchar cur_7;
uchar cur_8;
uchar cur_9;
uchar cur_10;
uchar cur_11;
uchar cur_12;
uchar cur_13;
uchar cur_14;
uchar cur_15;
uchar cur_time1; //分解时间1
uchar cur_time2;
uchar cur_time3;
uchar cur_time4;
uchar cur_time5;
uchar cur_time6;
uchar cur_time7;
uchar cur_time8;
uchar cur_time9;
uchar cur_time10;
uchar cur_time11;
uchar cur_time12;
uchar cur_time13;
uchar cur_time14;
uchar cur_time15;
uchar dcur_1; //激活电流1
uchar dcur_2;
uchar dcur_3;
uchar dcur_4;
uchar dcur_time1;
uchar dcur_time2;
uchar dcur_time3;
uchar dcur_time4;
void Delay_1ms(uint count_delay);
uchar Wating_Start(void); //等待启动键按下启动返回1,否则返回0
void init_USART(void); //初始化串口
uchar usart_putchar(uchar c); //发送一个字符
uchar usart_getchar(void); //接收一个字符
uint read_adc(uchar adc_input); //ADC转换,返回中值 0对应T1调压器
uchar get_decompose_data(void); //获取分解参数,1表示接收成功,0表接收失败
void moto_go(uchar moto,uchar dire,uchar delay_time); //启动步进电机delay_time速度
//moto 电机
//dire 方向 1 正 0反
void Auto(uint I_input,uint time,uchar delay_time);//I_input输入电流 time 分解时间
void InitialMotor(uchar delay_time);
void Activation(uchar I_input,uchar time);
void Activation_goback(uchar I_input,uchar time);
int main(void)
{
uchar i;
PORTA=0XFC; //PA0 与PA1为电流传感器输入接口,取消上拉电阻
PORTC=0XFF;
PORTD=0XFC; //PD0 PD1为串口输出,也取消上拉电阻
DDRA=_BV(LG)|_BV(LR); //LG 和 LR 为指示灯控制脚 故此设置为输出
DDRC=_BV(DIR2)|_BV(PLS2)|_BV(DIR1)|_BV(PLS1);
DDRD=_BV(DE);
init_USART();
//****************************计时功能设置*******************************//
ADCSRA=_BV(ADEN)|_BV(ADPS2)|_BV(ADPS1); //使能ADC转换器,64分频
TCNT0=0; //计时功能 256次
TCCR0=_BV(CS02)|_BV(CS00); //时钟1024分频
//**************************停止外部中断*********************************//
MCUCR=_BV(ISC01); //INT0的下降沿产生异步中断请求
GIFR=_BV(INTF0); //先写1清零中断标志为
GICR=_BV(INT0); //使能中断功能
sei();
while(1)
{
STOP_FLAG=0;
system_time=0;
InitialMotor(8);
LG_OFF();
LR_OFF();
while(!STOP_FLAG)
{
system_time=0;
LG_ON();
while(!Wating_Start());
for(i=0;i<2;i++)
{
moto_go(1,1,3);
moto_go(2,1,3);
}
Auto(80,30,6);// 第一位表示分解电流,第二位表示分解时间,第三位表示速度越大速度越慢
Auto(90,30,6);
Auto(100,50,6);
Auto(110,80,6);
Auto(120,90,6);
Auto(130,30,6);
Auto(90,2,6);
while((!Wating_Start())&&(!STOP_FLAG))
{
Delay_1ms(1000);
LG_OFF();
Delay_1ms(1000);
LG_ON();
}
Activation(190,2);
Activation(160,1);
Activation(190,2);
Auto(110,20,6);
InitialMotor(8);
}
}
}
void Delay_1ms(uint count_delay)
{
uint i,j;
for(i=0;i<count_delay;i++)
for(j=0;j<9000;j++);
}
uchar Wating_Start(void)
{
if(START)
{
Delay_1ms(10); //延时消抖动
if(START)
{
loop_until_bit_is_set(PINC,PC6); //等待按键释放
return 1;
}
}
else return 0;
}
void init_USART(void)
{ //USART 9600 8, n,1
UCSRB=_BV(TXEN)|_BV(RXEN); //使能接收中断,使能接收,使能发送UBRRH=0;
UBRRL=71;
fdevopen(usart_putchar,usart_getchar,0);
}
uchar usart_getchar(void)
{
CLR_DE();
loop_until_bit_is_set(UCSRA,RXC);
return UDR;
}
uchar usart_putchar(uchar c)
{
SET_DE();
if(c=='/n')
usart_putchar('/r');
loop_until_bit_is_set(UCSRA,UDRE);
UDR=c;
return 0;
}
uchar get_decompose_data(void)
{
uchar checksum;
uchar i;
init_USART();
LG_OFF();
LR_OFF();
for(i=0;i<INBUF_LEN;i++)
{
inbuf=usart_getchar();
checksum=checksum^inbuf;//校验 所接收的最后一个是 前38个的校验和,
}
if(checksum!=0)
{
checksum=0;
LR_ON();
for(i=0;i<INBUF_LEN;i++)
{
inbuf=0;
}
return 1;
}
else
{
LG_ON();
//添加参识赋值
return 0;
}
}
uint read_adc(uchar adc_input)
{
uint adc_value_buf;
uint tmp;
long tmp32;
uchar adc_count,i,j;
if(adc_input)
ADMUX=0B01000001;
else
ADMUX=0B01000000;
for(adc_count=0;adc_count<TEST_N;adc_count++)
{
ADCSRA|=_BV(ADSC);
loop_until_bit_is_set(ADCSRA,ADIF);
ADCSRA|=_BV(ADIF);
adc_value_buf=ADC;
}
for(j=0;j<TEST_N-1;j++) //从小到大排列
for(i=0;i<TEST_N-j;i++)
{
if(adc_value_buf>adc_value_buf)
{
tmp=adc_value_buf;
adc_value_buf=adc_value_buf;
adc_value_buf=tmp; //已经经过测试,正确!
}
}
tmp=adc_value_buf[(TEST_N-1)/2]; //取中值
tmp32=(long)tmp*600; //转换为0~600的数值,表示600mA
tmp=(unsigned int)(tmp32/1024); //ADC位10位精度,所以除于1024
return tmp;
}
INTERRUPT(SIG_OVERFLOW0) //可以被其他中断所中断
{
if(++g_bCount>42) //一秒钟
{
g_bCount=0;
system_time++; //产生系统时钟,用来比较分解时间
}
}
SIGNAL(SIG_INTERRUPT0) //屏蔽到所有的中断
{
Delay_1ms(100);
if(!(PIND&_BV(STOP)))
{
LR_ON(); //红灯亮表示程序停止
STOP_FLAG=1; //置位停止位,程序将从头开始
TIMSK&=~_BV(TOIE0); //关闭计时功能
}
loop_until_bit_is_set(PIND,PD2); //等待按键释放
Delay_1ms(100);
}
void moto_go(uchar moto,uchar dire,uchar delay_time)
{
//************************电机1*****************************************//
if(moto==1) //如果是第一个电机,执行以下程序
{
if(dire==1) //表示正转
{
CLR_DIR1(); //选择正转方向
SET_PLS1(); //脉冲为低(经过一个非门),输出一个脉冲
_delay_us(5000); //延时
Delay_1ms(delay_time); //该delay_time决定电机速度,大反而慢
CLR_PLS1(); //脉冲为高(经过一个非门)
_delay_us(5000); //控制脉冲宽度
Delay_1ms(delay_time);
}
else //表示反转
{
SET_DIR1(); //选择反方向
SET_PLS1(); //同上
_delay_us(5000);
Delay_1ms(delay_time);
CLR_PLS1();
_delay_us(5000);
Delay_1ms(delay_time);
}
}
//************************电机2*****************************************//
else if(moto==2) //如果选择第二个电机,则执行以下程序
{
if(dire==1) //同上
{
CLR_DIR2();
SET_PLS2();
_delay_us(5000);
Delay_1ms(delay_time);
CLR_PLS2();
_delay_us(5000);
Delay_1ms(delay_time);
}
else
{
SET_DIR2();
SET_PLS2();
_delay_us(5000);
Delay_1ms(delay_time);
CLR_PLS2();
_delay_us(5000);
Delay_1ms(delay_time);
}
}
}
void Auto(uint I_input,uint time,uchar delay_time)
{
uchar adc_arrived_times=0;
uchar timeout=0;
uint adc0=0;
uint adc1=0;
while((timeout==0)&&(!(time==0))&&(!STOP_FLAG))//如果停止则跳出循环
{
//如果分解时间达到;系统的分解时间为0;或者停止中断产生,跳出循环
//************************电机1*****************************************//
adc0=read_adc(0); //获取T1的分解电流
if((adc0<=(I_input-1))&&(!MAX1)) //将数值转换完成后再进行对比
moto_go(1,1,delay_time);
else if(adc0>=(I_input+1)) //不用下限限制
moto_go(1,0,delay_time);
//************************电机2*****************************************//
adc1=read_adc(1); //获取T2的分解电流
if((adc1<=(I_input-1))&&(!MAX2)) //将数值转换完成后再进行对比
moto_go(2,1,delay_time);
else if(adc1>=(I_input+1))
moto_go(2,0,delay_time);
//************************计时程序***************************************//
if((adc0==I_input)&&(adc1==I_input)) //一旦路都达到设定电流
adc_arrived_times++; //adc计数位加1
if(adc_arrived_times==5) //连续5次达到,才开始计时
TIMSK=_BV(TOIE0); //计时中断使能,计时开始
if(system_time>=time) //如果达到设定时间
{
TIMSK&=~_BV(TOIE0); //关闭计时中断,停止计时
timeout=1; //标志超时,结束该自动分解程序
adc_arrived_times=0; //清除adc计数位
system_time=0; //系统计时位清零
}
//************************掉电测试***************************************//
while(((adc0==0)|(adc1==0))&&(!STOP_FLAG))
{
TIMSK&=~_BV(TOIE0); //掉电时暂停系统时间
adc0=read_adc(0);
adc1=read_adc(1);
if(adc0==0) //如果是第一通道掉电,快速闪烁红灯
{
LR_ON();
Delay_1ms(1000);
LR_OFF();
Delay_1ms(1000);
}
else if(adc1==0) //如果第二通道掉电,慢速闪烁红灯
{
LR_ON();
Delay_1ms(5000);
LR_OFF();
Delay_1ms(5000);
}
if(!AUTO) //一旦转换到手动,则
{
LR_ON(); //红色指示灯常亮
LG_ON(); //绿色指示灯常亮
InitialMotor(8); //电机归位(归位后红灯继续闪)
} //()中的数表示电机的速度
else if(START)//在掉电状态中,按下启动键,则。。。
{
moto_go(1,1,3); //强制电机走动2步
moto_go(1,1,3); //可以避开启动时的,电流为0
moto_go(2,1,3);
moto_go(2,1,3);
LR_OFF();
break; //跳出掉电循环程序,继续分解
}
}
}
}
void InitialMotor(uchar delay_time)//电机归位子程序
{
while((!MIN1)||(!MIN2))
{
//**************************电机1*************************************//
if(!MIN1)
{
SET_DIR1();
SET_PLS1();
_delay_us(200);
Delay_1ms(delay_time);
CLR_PLS1();
_delay_us(200);
Delay_1ms(delay_time);
}
//**************************电机2*************************************//
else if(!MIN2)
{
SET_DIR2();
SET_PLS2();
_delay_us(200);
Delay_1ms(delay_time);
CLR_PLS2();
_delay_us(200);
Delay_1ms(delay_time);
}
}
}
void Activation(uchar I_input,uchar time)
{
uchar adc_arrived_times=0;
uchar timeout=0;
uint adc0=0;
uint adc1=0;
while((timeout==0)&&(!(time==0))&&(!STOP_FLAG))
{
//*****************************电机1*************************************//
adc0=read_adc(0);
if((adc0<=(I_input-1))&&(!MAX1)) //将数值转换完成后再进行对比
moto_go(1,1,1); //激活时无需电机回调,防抖动
//*****************************电机2*************************************//
adc1=read_adc(1);
if((adc1<=(I_input-1))&&(!MAX2)) //将数值转换完成后再进行对比
moto_go(2,1,1); //激活时无需电机回调,防抖动
//******************************计时*************************************//
if((adc0>=I_input)&&(adc1>=I_input)) //只要测试电流大于设定值
adc_arrived_times++; //就可以计时
if(adc_arrived_times==2)
TIMSK=_BV(TOIE0); //计时中断使能
if(system_time>=time)
{
TIMSK&=~_BV(TOIE0);
timeout=1;
adc_arrived_times=0;
system_time=0;
}
//************************掉电测试*************************************//
while(((adc0==0)|(adc1==0))&&(!STOP_FLAG))
{
TIMSK&=~_BV(TOIE0);
adc0=read_adc(0);
adc1=read_adc(1);
if(adc0==0)
{
LR_ON();
Delay_1ms(1000);
LR_OFF();
Delay_1ms(1000);
}
if(adc1==0)
{
LR_ON();
Delay_1ms(3000);
LR_OFF();
Delay_1ms(3000);
}
if(!AUTO)
{
LR_ON();
LG_ON();
InitialMotor(8);
}
else if(START)
{
moto_go(1,1,3);
moto_go(1,1,3);
moto_go(2,1,3);
moto_go(2,1,3);
LR_OFF();
break;
}
}
}
}
void Activation_goback(uchar I_input,uchar time)
{
uchar adc_arrived_times=0;
uchar timeout=0;
uint adc0=0;
uint adc1=0;
while((timeout==0)&&(!(time==0))&&(!STOP_FLAG))
{
//************************电机1*************************************//
adc0=read_adc(0);
if(adc0>=(I_input+1))//&&MIN1)
moto_go(1,0,1);
//************************电机2*************************************//
adc1=read_adc(1);
if(adc1>=(I_input+1))//&&MIN1)
moto_go(2,0,1);
//************************计时*************************************//
if((adc0==I_input)&&(adc1==I_input))//用于判断分解时间是否完成
adc_arrived_times++;
if(adc_arrived_times==2)
TIMSK=_BV(TOIE0); //计时中断使能
if(system_time>=time)
{
TIMSK&=~_BV(TOIE0);
timeout=1;
adc_arrived_times=0;
system_time=0;
}
//************************掉电测试*************************************//
while(((adc0==0)|(adc1==0))&&(!STOP_FLAG))
{
TIMSK&=~_BV(TOIE0);
adc0=read_adc(0);
adc1=read_adc(1);
if(adc0==0)
{
LR_ON();
Delay_1ms(1000);
LR_OFF();
Delay_1ms(1000);
}
if(adc1==0)
{
LR_ON();
Delay_1ms(3000);
LR_OFF();
Delay_1ms(3000);
}
if(!AUTO)
{
LG_ON();
InitialMotor(8);
}
else if(START)
{
moto_go(1,1,3);
moto_go(1,1,3);
moto_go(2,1,3);
moto_go(2,1,3);
LR_OFF();
break;
}
}
}
} 呵呵,谢谢分享! 太感谢了 大哥请问怎么测试电流呢? 期待楼主的电路,非常好的资料 希望楼主提供更多资料。
页:
[1]