?? 單片機.c
字號:
//////////相關內容可查閱計算機硬件技術基礎、課件、自動控制理論與單片機等書籍/////////////////
///////////////////////////////////程序基礎//////////////////////////////////////////////////
#pragma small
#include<reg51.h> ////包括51系列單片機的基本定義
#include<math.h>
#include<absacc.h>////擴展板必備
typedef unsigned char uchar;
typedef unsigned int uint;
///////////////////電路設定////////////////////////
#define BASE1 0x8100////擴展片選信號CS1(觸動開關擴展)
#define BASE2 0x8200////擴展片選信號CS2(雙頭檢測板)
#define BASE3 0x8300////擴展片選信號CS3 (單頭檢測板)
#define BASE5 0x8500////發光二極管陣列
#define BASE6 0x8600////p0輸入
#define BASE7 0x8700////p0輸出
#define BASE8 0x8800////PWM
#define BASE9 0x8900////碼盤計數
sbit P10=P1^0; ////碰撞開關接口
sbit P16=P1^6;
sbit P14=P1^4; ////電橋使能信號
sbit dir1=P1^2;////左輪方向標志,實質上為正負反饋標志。
sbit dir2=P1^3;////右輪方向標志,實質上為正負反饋標志。
//////////////////////基本參數//////////////////////////////
#define PI 3.1415926
#define D 0.12 ////輪子直徑
#define DISTANCE 0.37 ////L輪子間距
#define PANE 100 ////碼盤線數
#define PRESPEED 9000 ////原始最高速度(單位:轉/分)
#define RESPEED 300 ////減速最高速度(單位:轉/分)
#define RATE 30 ////減速比(原始最高速度/減速最高速度)
#define PWMBASE 250 ////(8254計數速率*PWM周期的一半(10M*25微秒),可任意)
#define INTOUT 200 ////(決定中斷周期(1/20K*200=10毫秒))
#define CONST 3 ////( 減速最高速度與碼盤線數之比(300(轉/分)/100=3),可任意)
#define RIGHT 1
#define LEFT 0
#define LINE 15915 ////走1米兩個輪子的碼盤線數(計算公式:2*(1/(PI*D))*RATE*PANE)
#define TURN 51 ////轉1度兩個輪子的碼盤線數(計算公式:((DISTANCE/D)*RATE*PANE)/180)
/////////////////////////控制用變量//////////////////////////////
struct discount
{
int uk1; ////上次輸出值
int videal;////理想速度(單位:轉/分)
int ek; ////本次誤差
int ek1; ////上次誤差
int ek2; ////前次誤差
};
data uint ukx,uky; ////實際輸出計數值
data struct discount sm2,sm1;////左右輪結構體變量
//////////////////////////中間運算變量//////////////////////////////
data uchar countl,counth; ////計數值高低位
data uint temp; ////每次中斷時碼盤線數(最大值為150:((PRESPEED/60)*中斷周期)/1000)*PANE)
data long temp1=0,temp2=0; ////左右輪總的碼盤線數
data long due; ////經PID調節后的偏差
data int uk; ////本次輸出值(-PWMBASE〈uk〈PWMBASE)
data int kp1,ki1,kd1; ////PID參數
data int kp2,ki2,kd2;
data uchar prestate=0x28,state;////巡線狀態
data char dv; ////速度調節量
int flag=0; ////巡線開關
//////////////////////結構體初始化//////////////////////////
void initstruct(struct discount *p)
{
p->ek2=0;
p->ek1=0;
p->ek=0;
p->uk1=0;
}
///////////////////////8254初始化///////////////////////////
void init8254() ////注意:8254為減法計數器
{
XBYTE[BASE8+3]=0x36; ////計數器0,工作方式3,計數初值500,主要功能分頻(輸出20KHZ的方波)
XBYTE[BASE8]=(PWMBASE*2)%256;
XBYTE[BASE8]=(PWMBASE*2)/256;
XBYTE[BASE8+3]=0x72; ////計數器1,工作方式1,計數初值250,主要功能輸出PWM波
XBYTE[BASE8+1]=PWMBASE%256;
XBYTE[BASE8+1]=PWMBASE/256;
XBYTE[BASE8+3]=0xb2; ////計數器2,工作方式1,計數初值250,主要功能輸出PWM波
XBYTE[BASE8+2]=PWMBASE%256;
XBYTE[BASE8+2]=PWMBASE/256;
XBYTE[BASE9+3]=0x30; ////計數器0,工作方式0,計數初值65534,計碼盤線數
XBYTE[BASE9]=0xfd;
XBYTE[BASE9]=0xff;
XBYTE[BASE9+3]=0x70; ////計數器1,工作方式0,計數初值65534,計碼盤線數
XBYTE[BASE9+1]=0xfd;
XBYTE[BASE9+1]=0xff;
XBYTE[BASE9+3]=0xb6; ////計數器2,工作方式3,計數初值200,主要功能分頻(10毫秒中斷一次)
XBYTE[BASE9+2]=INTOUT%256;
XBYTE[BASE9+2]=INTOUT/256;
}
///////////////////////延時////////////////////////
void delay(uchar i) ////以0.1秒為基本單位
{
uchar j,m;
long l;
for(j=0;j<i;j++)
{
for(l=0;l<100;l++)
{
for(m=0;m<250;m++)
{
;
}
}
}
}
///////////////////////中斷反饋控制/////////////////////
void int0(void) interrupt 0 using 1
{
EA=0;
////巡線
if(flag)
{
state=XBYTE[BASE2];
sm2.videal=sm1.videal;
if ((state&0x28)==0x28)
{
dv=0;
XBYTE[BASE5]=state;
}
else
{
switch(state&0xf0) ////左偏,要右轉
{case 0x20:dv=4;XBYTE[BASE5]=state;break;
case 0x30:dv=6;XBYTE[BASE5]=state;break;
case 0x10:dv=7;XBYTE[BASE5]=state;break;
case 0x90:dv=8;XBYTE[BASE5]=state;break;
case 0x80:dv=10;XBYTE[BASE5]=state;break;
case 0xc0:dv=12;XBYTE[BASE5]=state;break;
case 0x40:dv=14;XBYTE[BASE5]=state;break;
default:break;
}
switch(state&0x0f) ////右偏,要左轉
{case 0x08:dv=-4;XBYTE[BASE5]=state;break;
case 0x0c:dv=-6;XBYTE[BASE5]=state;break;
case 0x04:dv=-7;XBYTE[BASE5]=state;break;
case 0x06:dv=-8;XBYTE[BASE5]=state;break;
case 0x02:dv=-10;XBYTE[BASE5]=state;break;
case 0x03:dv=-12;XBYTE[BASE5]=state;break;
case 0x01:dv=-14;XBYTE[BASE5]=state;break;
default:break;
}
if(!state)
{
if((prestate&0xf0)==0x40)
{
dv=17;
}
else if((prestate&0x0f)==0x01)
{
dv=-17;
}
}
}
prestate=state;
sm2.videal=sm2.videal+dv;
}
////讀取電機1的速度
temp=0;
XBYTE[BASE9+3]=0xd2;
countl=XBYTE[BASE9];
counth=XBYTE[BASE9];
temp=65534-countl-counth*256;
if(temp>200) ////若超過最大值,則強制賦為0
{
temp=0;
}
temp1+=temp;
XBYTE[BASE9]=0xfd;
XBYTE[BASE9]=0xff;
////電機1PID控制
sm1.ek2=sm1.ek1;
sm1.ek1=sm1.ek;
if(!dir1) ////目的使其成為負反饋
sm1.ek=sm1.videal-temp*CONST;
else
sm1.ek=sm1.videal+temp*CONST;
due=((kp1+ki1+kd1)*sm1.ek-(kp1+kd1+kd1)*sm1.ek1+kd1*sm1.ek2)/8;////調節比例系數,使PID有合適的范圍
uk=due+sm1.uk1;
if(uk-PWMBASE>1)
uk=PWMBASE-1;
else
if(uk+PWMBASE<-1)
uk=PWMBASE-1;
sm1.uk1=uk;
ukx=uk+PWMBASE;
////讀取電機2的速度
temp=0;
XBYTE[BASE9+3]=0xd4;
countl=XBYTE[BASE9+1];
counth=XBYTE[BASE9+1];
temp=65534-countl-counth*256;
if(temp>200)
{
temp=0;
}
temp2+=temp;
XBYTE[BASE9+1]=0xfd;
XBYTE[BASE9+1]=0xff;
////電機2PID控制
sm2.ek2=sm2.ek1;
sm2.ek1=sm2.ek;
if(dir2)
sm2.ek=sm2.videal-temp*CONST;
else
sm2.ek=sm2.videal+temp*CONST;
due=((kp2+ki2+kd2)*sm2.ek-(kp2+kd2+kd2)*sm2.ek1+kd2*sm2.ek2)/8;
uk=due+sm2.uk1;
if(uk-PWMBASE>1)
uk=PWMBASE-1;
else
if(uk+PWMBASE<-1)
uk=PWMBASE-1;
sm2.uk1=uk;
uky=uk+PWMBASE-50;
XBYTE[BASE8+1]=ukx%256;
XBYTE[BASE8+1]=ukx/256;
XBYTE[BASE8+2]=uky%256;
XBYTE[BASE8+2]=uky/256;
EA=1;
}
///////////////////////子函數///////////////////////////
////直線程序////
void line(int linespeed,float distance)////以米為單位
{
long linesum=0;
temp1=temp2=0;
linesum=(long)LINE*distance;
sm1.videal=sm2.videal=20;
if((sm1.videal<=linespeed)&&(sm2.videal<=linespeed))
{
sm1.videal+=2;
sm2.videal+=2;
delay(2);
sm2.videal=sm1.videal;
}
sm1.videal=sm2.videal=linespeed;
while((temp1+temp2)<=linesum)
{}
sm1.videal=sm2.videal=0;
temp1=temp2=0;
}
////轉彎程序////
void turn(int direction,int turnspeed,int angle)
{
long turnsum=0;
temp1=temp2=0;
turnsum=TURN*angle;
if(direction)
{
sm2.videal=turnspeed;
sm1.videal=0-turnspeed;
}
else
{
sm1.videal=turnspeed;
sm2.videal=0-turnspeed;
}
while((temp1+temp2)<=turnsum)
{}
sm1.videal=sm2.videal=0;
temp1=temp2=0;
}
////扣球程序////
void rise(void)
{
while(P16)
{}
P14=1;
sm1.videal=sm2.videal=0;
XBYTE[BASE7]=0x80;
delay(6);
XBYTE[BASE7]=0x00;
delay(100);
XBYTE[BASE7]=0x80;
}
////出球程序////
void shoot(void)
{
while(P10)
{}
XBYTE[BASE7]=0x00;
XBYTE[BASE7]=0x04;
}
///////////////////////主函數///////////////////////////
main()
{
EA=0;
TCON=0x01; ////單片機控制字
SCON=0x50;
PCON=0x00;
TMOD=0x20;
init8254();
initstruct(&sm2);
initstruct(&sm1);
////PID參數調節
kp1=80;
ki1=10;
kd1=5;
kp2=80;
ki2=10;
kd2=5;
P14=1; ////關電橋
delay(2);
P14=0; ////開電橋
sm1.videal=0;
sm2.videal=0;
EA=1; ////開系統中斷
EX0=1; ////開外部0中斷
XBYTE[BASE7]=0x00;
XBYTE[BASE5]=0xff;
flag=0;
XBYTE[BASE5]=0x11;
line(30,1.15);
XBYTE[BASE5]=0x22;
turn(RIGHT,20,90);
XBYTE[BASE7]=0x10;
delay(5);
XBYTE[BASE7]=0x00;
flag=1;
sm1.videal=sm2.videal=30;
XBYTE[BASE5]=0x44;
rise();
flag=0;
XBYTE[BASE5]=0x88;
shoot();
while(1)
{}
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -