这个是电机调速控制系统的程序,单片机是AVR的mega16,采用液晶显示,电路图在前面已经发过了。
#include <mega16.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include "first.c"
#include "pid.c"
#include "delay.c"
#include "key_4.c"
#include "1602a.c"
// Declare your global variables here
bit s1; //停止/开始
bit s2; //正转反转
// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Place your code here
TCNT0=0x83;
if(++tc>250)
{
tc="0";
#asm("cli");
read="1";
}
if (++key_stime_counter >=3)//定时10MS
{
key_stime_counter = 0;
key_stime_ok = 1;
}
}
// External Interrupt 0 service routine
interrupt [EXT_INT0] void ext_int0_isr(void)
{
//read=1;
counter++;
}//end interrupt
/**************************读取计数值显示************************/
void read_counter()
{
unsigned int sett;
unsigned int count;//计数值
count="counter";
count=(count*60);
count="count">>3;
LcdPos(0,1); //确定光标位置
LcdWd('p'); //个位
LcdWd('r'); //
LcdWd('e');
LcdWd('=');
LcdPos(11,1); //确定光标位置
LcdWd('s'); //
LcdPos(10,1); //确定光标位置
LcdWd('/'); //
LcdPos(9,1); //确定光标位置
LcdWd('n'); //
LcdPos(8,1); //确定光标位置
LcdWd(count%10+0x30); //个位
count/=10; //十位
LcdPos(7,1); //确定光标位置
LcdWd(count%10+0x30);
count/=10; //百位
LcdPos(6,1); //确定光标位置
LcdWd(count%10+0x30);
count/=10; //千位
LcdPos(5,1); //确定光标位置
LcdWd(count%10+0x30);
count/=10; //万位
LcdPos(4,1); //确定光标位置
LcdWd(count%10+0x30);
sett="set";
LcdPos(0,0);
LcdWd('s');
LcdWd('e');
LcdWd('t');
LcdWd('=');
LcdPos(11,0); //确定光标位置
LcdWd('s');
LcdPos(10,0); //确定光标位置
LcdWd('/');
LcdPos(9,0); //确定光标位置
LcdWd('n');
LcdPos(8,0); //确定光标位置
LcdWd(sett%10+0x30);
sett/=10;
LcdPos(7,0); //确定光标位置
LcdWd(sett %10+0x30);
sett/=10;
LcdPos(6,0); //确定光标位置
LcdWd(sett%10+0x30);
sett/=10;
LcdPos(5,0); //确定光标位置
LcdWd(sett%10+0x30);
sett/=10;
LcdPos(4,0); //确定光标位置
LcdWd(sett%10+0x30);
counter="0";
#asm("sei");
}//end read_counter
/***************************主函数***********************************/
void main(void)
{
double rOut; // PID Response (Output)
double rIn; // PID Feedback (Input)
PIDInit ( &sPID ); // Initialize Structure
ocr="700";
set="1500";
sPID.Proportion =1.5; // Set PID Coefficients
// sPID.Integral = 0.683;
// sPID.Derivative = 0.683;
sPID.SetPoint =set; // Set PID Setpoint
sPID.SetPoint=sPID.SetPoint/60.0;
#asm("cli");
PORTA=0x00; //液晶
DDRA=0XFF;
PORTB=0x00;
DDRB=0x0F;//0000 1111
PORTC=0x00;
DDRC=0x00;
PORTD=0x30;//0000 0000 PD2外部中断入口
DDRD=0x30;//0011 0000
// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 125.000 kHz
// Mode: CTC top="OCR0"
// OC0 output: Disconnected
TCCR0=0x04; //定时4MS*500
TCNT0=0x83;
OCR0=0x82;
// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 1000.000 kHz
// Mode: Ph. correct PWM top="00FFh"
// OC1A output: Non-Inv.
// OC1B output: Discon.
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: Off
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0xc3;//选通OC1A
TCCR1B=0x01;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x03;
OCR1AL=0xff;
OCR1BH=0x03;
OCR1BL=0xff;//对应着PD4口的PWM波,
// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: Timer 2 Stopped
// Mode: Normal top="FFh"
// OC2 output: Disconnected
ASSR=0x00;
TCCR2=0x00;
TCNT2=0x00;
OCR2=0x00;
// External Interrupt(s) initialization
// INT0: On
// INT0 Mode: Rising Edge
// INT1: Off
// INT2: Off
GICR|=0x40;
MCUCR=0x03;
MCUCSR=0x00;
GIFR=0x40; //通过写1来清0
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=0x01;
// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
SFIOR=0x00;
RstLcd();
key_init(); //键盘初始化
#asm("sei") // 开放全局中断
while (1)
{
// Place your code here
//***********************键盘处理*******************************//
if (key_stime_ok) // 10ms到,键处理
{
key_stime_ok = 0;
switch (read_key()) // 调用按键接口程序
{
/****************复位******************/
case 1:
{
/************键值处理**************/
s1=!s1;
if (s1)
{
RR
LcdPos(14,1); //确定光标位置
LcdWd('R'); //
LcdPos(12,0); //确定光标位置
LcdWd('R');
LcdWd('U');
LcdWd('N');
LcdWd(' ');
}
else
{
ocr="0";
ST
LcdPos(12,0); //确定光标位置
LcdWd('S');
LcdWd('t');
LcdWd('o');
LcdWd('p');
}
} break;
case 2:
{
s2=!s2;
if (s2)
{
ocr="0";
RR//电机正转
ocr="700";
LcdPos(14,1); //确定光标位置
LcdWd('R'); //
LcdPos(12,0); //确定光标位置
LcdWd('R');
LcdWd('U');
LcdWd('N');
LcdWd(' ');
}
else
{
ocr="0";
LL
ocr="700";
LcdPos(14,1); //确定光标位置
LcdWd('L'); //
LcdPos(12,0); //确定光标位置
LcdWd('R');
LcdWd('u');
LcdWd('n');
LcdWd(' ');
}
}break;
case 3:
{
set-=100; //按一次加100
if (set<1500)
set="4000";
}
break;
case 4:
{
// read_counter();
// rIn = sensor (); // Read Input
// rOut = PIDCalc ( &sPID,rIn ); // Perform PID Interaction
// actuator ( rOut ); // Effect Needed Changes
set+=100; //按一次加100
if (set>4000)
set="1500";
}
break;
}
}//end keyproc
// read_counter();
if (read==1)
{
read="0";
if (counter<2) ST //当有外力时,停止
sPID.SetPoint=((unsigned int )sPID.SetPoint<<3)/60.0;
sPID.SetPoint =set;
sPID.SetPoint=sPID.SetPoint/60.0;
rIn = sensor (); // Read Input
rOut = PIDCalc ( &sPID,rIn ); // Perform PID Interaction
actuator ( rOut ); // Effect Needed Changes
read_counter();
}//end read
}//end while
}//end main
/*====================================================================================================
PID计算部分
=====================================================================================================*/
double PIDCalc( PID *pp, double NextPoint )//NextPOint为下次测量的值
{
double Error;
//dError,
Error = pp->SetPoint - NextPoint; // 偏差
// Error = NextPoint-pp->SetPoint ;
//if (Error>3000) ST;
// pp->SumError += Error; // 积分
// dError = pp->LastError - pp->PrevError; // 当前微分
pp->PrevError = pp->LastError;
pp->LastError = Error;
return (pp->Proportion *(Error*2.45 -3.0*pp->LastError+1.55 *pp->PrevError) // 比例项
// 积分项
// 微分项
);
}
/*====================================================================================================
Initialize PID Structure
=====================================================================================================*/
void PIDInit (PID *pp) //定义一下结构类型变量PP
{
memset ( pp,0,sizeof(PID)); //清空一个结构类型的变量或数组
}
/*====================================================================================================
Main Program
=====================================================================================================*/
double sensor (void) // 接收采集的数据
{
// if (counter<30) ST //当有外力时,停止
return (counter>>3);
}
void actuator(double rDelta) // 对接收回来的数进行处理送显示
{
ocr="ocr"+rDelta;
if (TCCR1A==0xc3)
{
OCR1A=ocr;}// 对应着PD5口输出的PWM波,当为0时最大
if (TCCR1A==0x33)
{OCR1B=ocr;}
if (ocr>1024) ocr="700";
// if (ocr<300) { ST};//停止
}
/***************定时器0中断进行键盘扫描时间****************/
/***********************************************
interrupt [TIM0_COMP] void timer0_comp_isr(void)
{
// Place your code here
if (++key_stime_counter >=5)//定时10MS
{
key_stime_counter = 0;
key_stime_ok = 1;
}
} */
/********************定时器0寄存初始化*********************/
/**********************************************/
void key_init(void)
{
//TCCR0|=0x0b;//采用比较模式,256分频 8M/256=31.25K
//TCNT0|=0x00;
//OCR0=0x3D;// (61+1)/31.25 =2ms
// Timer(s)/Counter(s) Interrupt(s) initialization
// TIMSK|=0x01;
// #asm("sei") // 开放全局中断
}
/***********************************/
/********函数功能说明***************/
/********键盘功能处理***************/
void key_pro(void)
{
if (key_stime_ok) // 10ms到,键处理
{
key_stime_ok = 0;
switch (read_key()) // 调用按键接口程序
{ case 1:
{ /************键值处理**************/
PORTA="0X11";
} break;
case 2:
PORTA="0XFE";
break;
case 3:
PORTA="0XF1";
break;
case 4:
PORTA="0x55";
break;
}
}
}
/*************键盘扫描*****************/
/****************************************/
char read_key(void)
{
char key_press, key_return = 0;
key_press = key_input; // 读按键I/O电平,当有键按下时为0,没按下时为1
switch (key_state)
{
case key_state_0: // 按键初始态
if (key_press!=0x3c) key_state = key_state_1;// 键被按下,状态转换到键确认态
break;
case key_state_1: // 按键确认态
if (key_press!=0X3C) //有键按下
{
//key_return = 1; // 按键仍按下,按键确认输出为"1"
switch (key_press=key_input)
{
case 0x1c:
key_return=1; break;
case 0x2c:
key_return=2;break;
case 0x34:
key_return=3;break;
case 0x38:
key_return=4;break;
}
key_state = key_state_2; // 状态转换到键释放态
}
else
key_state = key_state_0; // 按键已抬起,转换到按键初始态
break;
case key_state_2: //键已经释放,确认了有键按下
if (key_press==0x3c)
key_state = key_state_0; //按键已释放,转换到按键初始态
break;
}
return key_return; //当返回为0时,表示没有键按下,
}
用户166298 2009-5-3 21:37
用户166298 2009-2-7 22:43
用户66556 2006-11-23 13:01
非常不错的资料
12864_944456583 2006-11-15 09:04
用户57318 2006-10-29 16:34
博主,你好哦,由于我的电脑出现了问题,不能下载上面的两个PDF,您能不能把它们发送到我的邮箱来呢? 谢谢哦!
----weiajiuge@163.com
用户1347946 2006-10-27 22:30
用户61435 2006-10-27 15:27
我想请教一个问题:
在一根照明电缆上,要分时实现两种交流电压:~220V和~50V,供~220V时,不能供~50V.不供~220V时,才供~50V.交流~50V的电流<1A.交流~220V是由低压开关实现的.
lzy@cie-nj.com
用户10264 2006-10-15 11:05
我正需要这资料了。谢谢了
用户475531 2006-10-13 11:37