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

📄 diantcontrol.c

📁 AVR的mega16电梯控制模型序LCD显示
💻 C
字号:
/***********************************************
****     电梯控制模型                        ***

****    目标MCU: Atmeag 16                   ***
	
****    作者:   XueTwins                    ***

****  	时间	 2007.05.05                  ***
***********************************************/
#include <iom16v.h>
#include <macros.h>
#include <stdio.h>

unsigned char str[20]="";
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////

/*******************************************************************************
                           延时函数
                         系统时钟:8M
*******************************************************************************/
void delay_1us(void)                 //1us延时函数
{
    asm("nop");
    asm("nop");
    asm("nop");
    asm("nop");
}

void delay_nus(unsigned int n)       //N us延时函数
{
   unsigned int i=0;
   for (i=0;i<n;i++)
   delay_1us();
}
  
void delay_1ms(void)                 //1ms延时函数
{
   unsigned int i;
   for (i=0;i<1142;i++);
}
  
void delay(unsigned int n)       //N ms延时函数
{
   unsigned int i=0;
   for (i=0;i<n;i++)
   delay_1ms();
}

/***********************************************
         定义MCU与LCD的接口
接线:EN------PD3、RS-----PD2、DATA-----PB4,5,6,7
***********************************************/
#define LCD_EN_PORT PORTB//PB3使能LCD
#define LCD_RS_PORT PORTB//PB2
#define LCD_DATA_PORT PORTB

#define LCD_EN 0x08//PB3 out
#define LCD_RS 0x04//PB2 out
#define LCD_DATA 0xF0//PB4,5,6,7
/***********************************************
         函数原型声明
***********************************************/
void LCD_init(void);//LCD初始化
void LCD_en_write(void);//LCD写
void LCD_set_xy(unsigned char x,unsigned char y);//写X,Y地址
void LCD_write_string(unsigned char x,unsigned char y,unsigned char *string);
void LCD_write_char(unsigned command,unsigned data);
/**************************************************
          上面声明各函数的实现
*************************************************/
void LCD_init(void)
{
   LCD_write_char(0x28,0); 
   LCD_en_write();
   delay(15);//延时15ms
   LCD_write_char(0x28,0);//四位数据接口,二行显示,5*7点阵字符
   LCD_write_char(0x0C,0);//显示开
   LCD_write_char(0x01,0);//清屏
   delay(2);
   LCD_write_char(0x06,0);//显示光标移动设置  
}
void LCD_en_write(void)//液晶使能
{
   LCD_EN_PORT|=LCD_EN;
   delay(1);
   LCD_EN_PORT&=~LCD_EN;
}
/**************************************************
// 写数据
*************************************************/

void LCD_write_char(unsigned command,unsigned data) 
{
 unsigned command_temp,data_temp;
 command_temp=command;
 data_temp=data;
 delay(16);
 if(command==0)
 {
  LCD_RS_PORT|=LCD_RS;               //RS=1
  LCD_DATA_PORT&=0X0f;
  LCD_DATA_PORT|=data_temp&0xf0;     //写高四位
  LCD_en_write();
  data_temp=data_temp<<4;  
  LCD_DATA_PORT&=0X0f;
  LCD_DATA_PORT|=data_temp&0xf0;     //写低四位
  LCD_en_write();
 }
 else
 {
  LCD_RS_PORT&=~LCD_RS;              //RS=0
  LCD_DATA_PORT&=0X0f;
  LCD_DATA_PORT|=command_temp&0xf0;  //写高四位
  LCD_en_write();
  command_temp=command_temp<<4;
  LCD_DATA_PORT&=0x0f;
  LCD_DATA_PORT|=command_temp&0xf0;  //写低四位
  LCD_en_write();
  }
}

void LCD_set_xy(unsigned char x,unsigned char y)//写地址
{//设置LCD显示的起始位置,显示字符串的位置,X:0-15,Y:0-1
 // LCD第一行显示寄存器地址:0X80-0X8F
 // LCD第一行显示寄存器地址:0XC0-0XCF
   unsigned char address;
	if(y==0)
	    address=0x80 + x;
    else              //即y==1
	    address=0xC0 + x;
	LCD_write_char(address,0);
}
void LCD_write_string(unsigned char x,unsigned char y,unsigned char *string)
{//英文字符串显示函数
   LCD_set_xy(x,y);//写地址
   while (*string)  // 写显示字符
    {
      LCD_write_char(0,*string);
      string ++;
    }
} 

////////////////////电梯控制/////////////////////////////////////
/////////////////////////////////////////////////////////////////
//标志状态
#define stop 0x01    
#define up   0x02
#define down 0x03
#define stop5s 0x04

unsigned char key_number;//记录按下哪个键
unsigned char dir,cur_floor,next_floor,run_state;//记录电梯的方向,当前层数,下一层数,电梯状态
unsigned char upward,downward;//向上,向下

/**************************************************
            扫描键盘函数
*************************************************/
void keyboard(void)
{
     if(!(PINA&0x08))
	    key_number=0;	   //第一行按下
     else if(!(PINA&0x04))
	    key_number=4;     //第二行按下
     else if(!(PINA&0x02))
	    key_number=8;     //第三行按下
     else if(!(PINA&0x01))
	    key_number=12;    //第四行按下
     DDRA=0x0F;           //反转PORTA的I/O端口
     PORTA=0xF0;          //列PA7..4为高电平,行PA3..0为低电平
     delay(20);           //延时,消抖
 
     if(!(PINA&0x80))
	   key_number+=0;	//第一列按下				  
     else if(!(PINA&0x40))
	   key_number+=1;   //第二列按下
     else if(!(PINA&0x20))
	   key_number+=2;   //第三列按下
     else if(!(PINA&0x10))
	   key_number+=3;   //第四列按下
 
     DDRA=0xF0;			//再反转一次
     PORTA=0x0F;
}
/*******************************************************
              外部中断INT0
*******************************************************/
#pragma interrupt_handler int0_isr:2
void int0_isr(void)
{   
    LCD_write_string(0,0,"int0");//////////////////
	
    switch(dir)
	{
	    case up:
		    cur_floor++;
			if(cur_floor>=5)
			{
			    cur_floor=5;
				dir=down;
			}
			if(cur_floor==next_floor)
			{
			    run_state=stop5s;
			}
			sprintf(str,"Now F=%d",cur_floor);//显示当前到达的层数
			LCD_write_string(6,0,str);
			
			break;
		case down:
		    cur_floor--;
			if(cur_floor<=1)
			{
			    cur_floor=1;
				dir=up;
			}
			if(cur_floor==next_floor)
			{
			    run_state=stop5s;
			}
			sprintf(str,"Now F=%d",cur_floor);//显示当前到达的层数
			LCD_write_string(6,0,str);
			
			break;
	}
}

/*******************************************************
               定时器0(初始化)
*******************************************************/
void timer0_init(void)
{
    TCNT0=0xB2;//10ms产生一次中断
	TCCR0=0x05;//1024分频
	TIMSK|=(1<<TOIE0);//允许timer0溢出中断
	
	ACSR = 0x80;	 //关闭模拟比较器
}
/*******************************************************
               定时器0(溢出中断)..........可简化程序.............
标记规则:  5 4 3 2 1 
upward:      1 1 1 1
downward:  1 1 1 1
例如:想要去1楼,temp_floor==1,则downward的最后一位(temp_floor-1)置1
*******************************************************/
#pragma interrupt_handler timer0_isr:10
void timer0_isr(void)
{
	unsigned char temp_floor;
	TCNT0=0xB2;//重载初值
	
	keyboard();
	
	//DDRA=0xF0; //PA7..4为输出,PA3..0为输入
   // PORTA=0x0F;//行PA3..0为高电平,列PA7..4为低电平
	LCD_write_string(5,1,"time0");
	sprintf(str,"%d",key_number);
	LCD_write_string(7,0,str);
	/*
	switch(key_number)
	{
	    case 0:            //按键0
		    temp_floor=1;  //想要去1楼
		    if(cur_floor>temp_floor)downward|=(1<<(temp_floor-1));///用于标记
			if(cur_floor<temp_floor)upward|=(1<<(temp_floor-1));
			break;
		case 1:
		    temp_floor=2;   //想要去2楼
			if(cur_floor>temp_floor)downward|=(1<<(temp_floor-1));
			if(cur_floor<temp_floor)upward|=(1<<(temp_floor-1));
			break;
		case 2:
		    temp_floor=3;   //想要去3楼
			if(cur_floor>temp_floor)downward|=(1<<(temp_floor-1));
			if(cur_floor<temp_floor)upward|=(1<<(temp_floor-1));
			break;
		case 3:
		    temp_floor=4;   //想要去4楼
			if(cur_floor>temp_floor)downward|=(1<<(temp_floor-1));
			if(cur_floor<temp_floor)upward|=(1<<(temp_floor-1));
			break;
		case 4:
		    temp_floor=5;  //想要去5楼
			if(cur_floor>temp_floor)downward|=(1<<(temp_floor-1));
			if(cur_floor<temp_floor)upward|=(1<<(temp_floor-1));
			break;
		case 5:
		    upward|=(1<<0);break;   //1楼向上按键
		case 6:
		    upward|=(1<<1);break;   //2楼向上按键
		case 7:
		    downward|=(1<<1);break; //2楼向下按键
		case 8:
		    upward|=(1<<2);break;   //3楼向上按键
		case 9:
		    downward|=(1<<2);break; //3楼向下按键
		case 10:
		    upward|=(1<<3);break;   //4楼向上按键
		case 11:
		    downward|=(1<<3);break; //4楼向下按键
		case 12:
		    downward|=(1<<4);break; //5楼向下按键
			
		case 13:
		case 14:
		case 15:
		case 16:break;
		
	}*/
}

/*******************************************************
               PWM初始化(比较匹配A)
*******************************************************/
void PWM_init(void)
{
    DDRD|=BIT(5);//PB1(OC1A) 
	PORTD|=BIT(5);//高电平
	
	TCNT1=0x0000;
	OCR1A=0x01FF;//输出比较寄存器,用来控制占空比(占空比50%)
		         
	TCCR1A|=(1<<COM1A1)|(1<<COM1A0)|(1<<WGM11)|(1<<WGM10);
	//向上计数置1,向下计数置0                   (10位PWM相位可调)WGM13--10 为0011           
	TCCR1B|=(1<<CS10);//1分频 
}

/*******************************************************
               上升
*******************************************************/
void forward(void)//正转上升
{
    OCR1A=0x00FF;//255
	PORTD|=BIT(6);
	PORTD&=~BIT(7);	
}
/*******************************************************
               下降
*******************************************************/
void backward(void)//反转下降
{
    OCR1A=0x00FF;//255;
	PORTD|=BIT(7);
	PORTD&=~BIT(6);
}
/*******************************************************
              停止运行
*******************************************************/
void stopmove(void)
{
    PORTD&=~BIT(6);
	PORTD&=~BIT(7);
}

/*******************************************************
              电机运行状态(上.下.停)
*******************************************************/
void state(void)
{
    if(dir==up)
	{
	    LCD_write_string(0,0,"UP");
		forward();      //向上
		
		if(dir==stop5s)
		{
		    LCD_write_string(0,0,"STOP5s");
			stopmove(); //停止5s
			delay(5000);
			
			LCD_write_string(0,0,"UP");
			dir=up;
			forward();
		}
	}
	if(dir==down)      //向下
	{
	    LCD_write_string(0,0,"DOWN");
		backward();
		
		if(dir==stop5s)
		{
		    LCD_write_string(0,0,"STOP5s");
			stopmove();
			delay(5000);
			
			LCD_write_string(0,0,"DOWN");
			dir=down;
			backward();
		}
	}
	if(dir==stop)      //停止
	{
	    LCD_write_string(0,0,"STOP");
		stopmove();
	}
}
/*******************************************************
             确定是哪一层有人按下
dir是upward downward的形参,movebit是移位位数
movebit是要移位的某一位
(dir&(1<<movebit))可判断出5位中哪一位为1,如果与(&)后是1证明这一层被按下,
则右移(>>)几位,使temp的值为1,是为了方便计算
*******************************************************/
unsigned char check_floor(unsigned char dir,unsigned char movebit)
{
    unsigned char temp=0;
	temp=( (dir&(1<<movebit)) >>movebit );
	return temp;
}
/*******************************************************
             电梯运行到请求层 (可多层请求)
*******************************************************/
unsigned char n;

void call(void)
{
    unsigned char i,call_floor;//移位位数,多少人有按按键,有请求的层
	
	if( (dir==up) && (cur_floor<5) )
	{
	    if( (upward & 0x1F)!=0 )//有向上键按下了
		{
		    for(i=0;i<5;i++)    //i为移位位数(移四位就到第五层)
			{
			    call_floor = check_floor(upward , i);//确定请求层
				if(call_floor==1)//为1证明该层有人按下按键
				{
				    n++;//有n人按
					next_floor = cur_floor+i;//next_floor为要运行到的层
					sprintf(str,"F=%d,N=%d",next_floor,n);/////////不知对不对
					LCD_write_string(6,1,str);
				}
			}
		}
	}
	
	if( (dir==down) && (cur_floor>1) )
	{
	    if( (downward & 0x1F)!=0 )//向下键有人按下
		{
		    for(i=4;i>0;i--)
			{
			    call_floor = check_floor(downward , i);
				if(call_floor==1)
				{
				    n++;
					next_floor = cur_floor+i;
					sprintf(str,"F=%d,N=%d",next_floor,n);/////////不知对不对
					LCD_write_string(6,1,str);
				}
			}
		}
	}
}
/*******************************************************************************
                      主函数
*******************************************************************************/
void main(void)
{
	CLI();//关中断
	
	DDRB|=LCD_EN | LCD_RS | LCD_DATA;//EN方向,RS方向,数据口方向为输出
    LCD_EN_PORT &= ~LCD_EN;      //EN=0
	LCD_init();
   
	DDRA=0xF0; //PA7..4为输出,PA3..0为输入
    PORTA=0x0F;//行PA3..0为高电平,列PA7..4为低电平
	
	DDRD=0B11111011;// INT0为输入
	PORTD|=BIT(2);
	
	
	MCUCR= 0x03;//上降沿申请中断(白色为低电平,黑色为高电平)
    GICR = 0x40;//  INT0
	
	PWM_init();
	timer0_init();
    
    
    SEI();//开中断
	/*
	dir=stop;
	state();//实际调用 stopmove();停止
	while(!(upward & 0x1F));//等待有向上键按下 跳出
	dir=up;
	*/
	while(1)
	{
		
		
		
		dir=up;
		state();
		
		delay(5000);
		
		dir=down;
		state();
		delay(5000);
		
		/*call();
		
		switch(dir)
		{
		    case up:  LCD_write_string(0,1,"UP");
			case down:LCD_write_string(0,1,"DOWN");
		}
		
		state();//*/
	}
    
  
}





⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -