⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ir- motor-lcd1602.c

📁 红外遥控步进电机动作并且lcd液晶显示数据状态
💻 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 + -