?? ir- motor-lcd1602.c
字號:
/*****************************************************************/
/* 紅外遙控步進電機 */ *
/*****************************************************************/
#include <reg51.h> //51芯片管腳定義頭文件
#include <intrins.h> //內部包含延時函數 _nop_();
#define uchar unsigned char
#define uint unsigned int
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
uchar code FFW[8]= {0xf1,0xf3,0xf2,0xf6,0xf4,0xfc,0xf8,0xf9};
uchar code REV[8]= {0xf9,0xf8,0xfc,0xf4,0xf6,0xf2,0xf3,0xf1};
uchar IRCOM[6]=(0x00,0x00,0x00,0x00,0x00,0x00);
sbit BEEP = P3^7; //蜂鳴器
sbit IRIN=P3^2; //紅外接收端口
sbit LCD_RS = P2^0;
sbit LCD_RW = P2^1;
sbit LCD_EN = P2^2;
bit on_off=0; //運行與停止標志
bit direction=1; //方向標志
bit rate_dr=1; //速率標志
bit snum_dr=1; //圈數標志
bit flag; //紅外接收有效標志
bit pause1=0; //暫停標志
//uchar code cdis1[ ] = {" STEPPING MOTOR "};
//uchar code cdis2[ ] = {"CONTROL PROCESS"};
uchar code cdis1[ ] = {" IR CONTROL "};
uchar code cdis2[ ] = {" STEPPING MOTOR "};
uchar code cdis3[ ] = {"IR:--H STOP "};
uchar code cdis4[ ] = {"NUM: RATE: "};
uchar code cdis5[ ] = {" RUN "};
uchar code cdis6[ ] = {" STOP"};
uchar code cdis7[ ] = {"PAUSE"};
uchar m,v=0,q=0;
uchar number=0,number1=0;
uchar snum=10,snum1=10; //預設定圈數
uchar rate=8; //預設定速率
uchar data_temp,data_temp1,data_temp2;
uchar TEMP;
void IR_IN();
/********************************************************/
/*
/* 延時t毫秒
/* 11.0592MHz時鐘,延時約1ms
/*
/********************************************************/
void delay(uint t)
{
uchar k;
while(t--)
{
for(k=0; k<125; k++)
{ }
}
}
/********************************************************/
void delayB(uchar x) //x*0.14MS
{
uchar i;
while(x--)
{
for (i=0; i<13; i++)
{ }
}
}
/********************************************************/
void beep()
{
uchar j;
for (j=0;j<100;j++)
{
delayB(5);
BEEP=!BEEP; //BEEP取反
}
BEEP=1; //關閉蜂鳴器
}
/********************************************************/
/*
/*檢查LCD忙狀態
/*lcd_busy為1時,忙,等待。為0時,閑,可寫指令與數據。
/*
/********************************************************/
bit lcd_busy()
{
bit result;
LCD_RS = 0;
LCD_RW = 1;
LCD_EN = 1;
delayNOP();
result = (bit)(P0&0x80);
LCD_EN = 0;
return(result);
}
/********************************************************/
/*
/*寫指令數據到LCD
/*RS=L,RW=L,E=高脈沖,D0-D7=指令碼。
/*
/********************************************************/
void lcd_wcmd(uchar cmd)
{
while(lcd_busy());
LCD_RS = 0;
LCD_RW = 0;
LCD_EN = 0;
_nop_();
_nop_();
P0 = cmd;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/********************************************************/
/*
/*寫顯示數據到LCD
/*RS=H,RW=L,E=高脈沖,D0-D7=數據。
/*
/********************************************************/
void lcd_wdat(uchar dat)
{
while(lcd_busy());
LCD_RS = 1;
LCD_RW = 0;
LCD_EN = 0;
P0 = dat;
delayNOP();
LCD_EN = 1;
delayNOP();
LCD_EN = 0;
}
/********************************************************/
/*
/* LCD初始化設定
/*
/********************************************************/
void lcd_init()
{
delay(30);
lcd_wcmd(0x38); //16*2顯示,5*7點陣,8位數據
delay(5);
lcd_wcmd(0x38);
delay(5);
lcd_wcmd(0x38);
delay(5);
lcd_wcmd(0x0c); //顯示開,關光標
delay(5);
lcd_wcmd(0x06); //移動光標
delay(5);
lcd_wcmd(0x01); //清除LCD的顯示內容
delay(5);
}
/********************************************************/
/*
/* 設定顯示位置
/*
/********************************************************/
void lcd_pos(uchar pos)
{
lcd_wcmd(pos | 0x80); //數據指針=80+地址變量
}
/********************************************************/
/*
/* LCD1602初始顯示子程序
/*
/********************************************************/
void LCD_init_DIS()
{
delay(10); //延時
lcd_init(); //初始化LCD
lcd_pos(0); //設置顯示位置為第一行的第1個字符
for(m=0;m<16;m++)
lcd_wdat(cdis1[m]);
lcd_pos(0x40); //設置顯示位置為第二行第1個字符
for(m=0;m<16;m++)
lcd_wdat(cdis2[m]);
delay(3000); //延時
lcd_pos(0); //設置顯示位置為第一行的第1個字符
for(m=0;m<16;m++)
lcd_wdat(cdis3[m]);
lcd_pos(0x40); //設置顯示位置為第二行第1個字符
for(m=0;m<16;m++)
lcd_wdat(cdis4[m]);
for(m=0;m<2;m++)
{
lcd_pos(0x0d+m); //顯示方向符號
lcd_wdat(0x3e);
}
}
/********************************************************/
/*
/*數據轉換子程序
/*
/********************************************************/
void data_conv()
{
data_temp1=data_temp/10; //高位
if(data_temp1==0)
{data_temp1=0x20;} //高位為0不顯示
else
{data_temp1=data_temp1+0x30;}
data_temp2=data_temp%10; //低位
data_temp2=data_temp2+0x30;
}
void code_conv()
{
IRCOM[5]=IRCOM[2];
IRCOM[6]=IRCOM[5]&0x0f; //低位
if(IRCOM[6]>0x09)
IRCOM[6]=IRCOM[6]+0x37;
else
IRCOM[6]=IRCOM[6]+0x30;
IRCOM[5]=(IRCOM[5]&0xf0)>>4; //高位
if(IRCOM[5]>0x09)
IRCOM[5]=IRCOM[5]+0x37;
else
IRCOM[5]=IRCOM[5]+0x30;
}
/********************************************************/
/*
/*數據顯示子程序
/*
/********************************************************/
void data_dis()
{
code_conv();
lcd_pos(0x03);
lcd_wdat(IRCOM[5]);
// lcd_pos(0x08);
lcd_wdat(IRCOM[6]);
data_temp = snum; //顯示圈數
data_conv();
lcd_pos(0x44);
lcd_wdat(data_temp1);
// lcd_pos(0x45);
lcd_wdat(data_temp2);
data_temp = rate; //顯示速率
data_conv();
lcd_pos(0x4d);
lcd_wdat(data_temp1);
// lcd_pos(0x4e);
lcd_wdat(data_temp2);
}
/********************************************************
/*
/* 顯示運行方向符號
/*
/********************************************************/
void motor_DR()
{
if(direction==1) //正轉方向標志
{
for(m=0;m<2;m++)
{
lcd_pos(0x0d+m); //顯示方向符號
lcd_wdat(0x3e);
}
}
else
{
for(m=0;m<2;m++) //反轉方向標志
{
lcd_pos(0x0d+m); //顯示方向符號
lcd_wdat(0x3c);
}
}
}
/********************************************************
/*
/* 顯示運行狀態
/*
/********************************************************/
void motor_RUN()
{
if(on_off==1)
{ TR0=1;
lcd_pos(7); //設置顯示位置為第一行的第1個字符
for(m=0;m<5;m++)
lcd_wdat(cdis5[m]); //RUN
motor_DR(); //
}
else
{ TR0=0; P1 =0xf0;
lcd_pos(7); //設置顯示位置為第一行的第1個字符
for(m=0;m<5;m++)
lcd_wdat(cdis6[m]); //STOP
motor_DR(); //
snum=snum1; //
number1=0; //清圈數計數器
}
}
/********************************************************
*
* 主程序
*
*********************************************************/
main()
{
LCD_init_DIS();
// IE=0x81; //允許總中斷中斷,使能 INT0 外部中斷
// TCON=0x01; //觸發方式為脈沖負邊沿觸發
TMOD = 0x01; //T0定時方式1
TL0 = 0x33;
TH0 = 0xf5;
ET0 = 1;
EA = 1;
P1 = 0xf0;
while(1)
{
IR_IN();
TEMP=IRCOM[2];
if(flag)
{
/********************************************************
運行控制
********************************************************/
if(TEMP==0x10) //啟動、停止
{
on_off=~on_off;
motor_RUN();
}
/********************************************************
設定圈數
********************************************************/
if(TEMP==0x09) //增加圈數
{
if(snum!=0x14)
{
snum++;
snum1=snum;
}
}
if(TEMP==0x1f) //減少圈數
{
if(snum!=0x00)
{
snum--;
snum1=snum;
}
}
/********************************************************
方向轉換
********************************************************/
if(TEMP==0x11) //正轉
{
direction=1;
motor_DR();
}
if(TEMP==0x19) //反轉
{
direction=0;
motor_DR();
}
/********************************************************
速率調整
********************************************************/
if(TEMP==0x12) //增加速率,減速
{
if(rate!=0x10)
rate++;
}
if(TEMP==0x1d) //減少速率,加速
{
if(rate!=0x01)
rate--;
}
if(TEMP==0x03)
{
if(on_off&(!pause1))
{
pause1=1;
TR0=0; //暫停
lcd_pos(7); //設置顯示位置
for(m=0;m<5;m++)
lcd_wdat(cdis7[m]); //PAUSE
}
else if(pause1)
{
motor_RUN();
pause1=0;
TR0=1;
}
}
flag=0;
} // end of if(flag)
/********************************************************/
if(number1==snum1) //與設定圈數是否相等
{
number1=0;
on_off=0;
TR0=0;
snum=snum1;
P1 =0xf0;
motor_RUN();
}
data_dis();
} // while(1) end
} //main end
/********************************************************/
/*
/* 定時器 0 中斷
/*
/********************************************************/
void motor_onoff() interrupt 1
{
TL0 = 0x33;
TH0 = 0xf5;
q++;
if(q < rate)
{ return; }
else
{ q=0;
number++; //脈沖計數
if(number==96) //96個脈沖電機轉一圈
{ snum--;
number=0;
number1++; } //電機轉動圈數
if(direction==1) //方向標志
{ if(v<8)
{P1 = FFW[v];v++;} //取數據,正轉
if(v==8)
{ v=0; }
}
else
{ if(v<8)
{P1 = REV[v];v++;} //取數據,反轉
if(v==8)
{ v=0; }
}
}
}
/**********************************************************
中斷服務函數
**********************************************************/
void IR_IN() //interrupt 0 using 0
{
unsigned char j,k,N=0;
// EX0 = 0;
delayB(15);
if (IRIN==1) //確認IR信號是否出現
{
// EX0 =1;
return;
}
while (!IRIN) //等IR變為高電平,跳過9ms的前導低電平信號。
delayB(1);
for (j=0;j<4;j++) //收集四組數據
{
for (k=0;k<8;k++) //每組數據有8位
{
while (IRIN) //等 IR 變為低電平,跳過4.5ms的前導高電平信號。
delayB(1);
while (!IRIN) //等 IR 變為高電平
delayB(1);
while (IRIN) //計算IR高電平時長
{
delayB(1);
N++;
if (N>=20)
{
// EX0=1;
return; //0.14ms計數過長自動離開。
}
} //高電平計數完畢
IRCOM[j]=IRCOM[j] >> 1; //數據最高位補"0"
if (N>=8)
IRCOM[j]=IRCOM[j] | 0x80; //數據最高位補"1"
N=0;
}//end for k
} //end for j
if(IRCOM[2]!=~IRCOM[3]) //檢驗接收數據是否正確
{ //EX0=1;
return; }
if(IRCOM[0]!=0x00) //效驗用戶碼
{
// EX0=1;
return;
}
beep(); //接收有效,蜂鳴器響一聲
flag=1 ; //置接收有效標志
// EX0 = 1; //重開中斷
}
/*********************************************************/
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -