?? diantcontrol.c
字號:
/***********************************************
**** 電梯控制模型 ***
**** 目標(biāo)MCU: Atmeag 16 ***
**** 作者: XueTwins ***
**** 時間 2007.05.05 ***
***********************************************/
#include <iom16v.h>
#include <macros.h>
#include <stdio.h>
unsigned char str[20]="";
/////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////
/*******************************************************************************
延時函數(shù)
系統(tǒng)時鐘:8M
*******************************************************************************/
void delay_1us(void) //1us延時函數(shù)
{
asm("nop");
asm("nop");
asm("nop");
asm("nop");
}
void delay_nus(unsigned int n) //N us延時函數(shù)
{
unsigned int i=0;
for (i=0;i<n;i++)
delay_1us();
}
void delay_1ms(void) //1ms延時函數(shù)
{
unsigned int i;
for (i=0;i<1142;i++);
}
void delay(unsigned int n) //N ms延時函數(shù)
{
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
/***********************************************
函數(shù)原型聲明
***********************************************/
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);
/**************************************************
上面聲明各函數(shù)的實現(xiàn)
*************************************************/
void LCD_init(void)
{
LCD_write_char(0x28,0);
LCD_en_write();
delay(15);//延時15ms
LCD_write_char(0x28,0);//四位數(shù)據(jù)接口,二行顯示,5*7點陣字符
LCD_write_char(0x0C,0);//顯示開
LCD_write_char(0x01,0);//清屏
delay(2);
LCD_write_char(0x06,0);//顯示光標(biāo)移動設(shè)置
}
void LCD_en_write(void)//液晶使能
{
LCD_EN_PORT|=LCD_EN;
delay(1);
LCD_EN_PORT&=~LCD_EN;
}
/**************************************************
// 寫數(shù)據(jù)
*************************************************/
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)//寫地址
{//設(shè)置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)
{//英文字符串顯示函數(shù)
LCD_set_xy(x,y);//寫地址
while (*string) // 寫顯示字符
{
LCD_write_char(0,*string);
string ++;
}
}
////////////////////電梯控制/////////////////////////////////////
/////////////////////////////////////////////////////////////////
//標(biāo)志狀態(tài)
#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;//記錄電梯的方向,當(dāng)前層數(shù),下一層數(shù),電梯狀態(tài)
unsigned char upward,downward;//向上,向下
/**************************************************
掃描鍵盤函數(shù)
*************************************************/
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; //反轉(zhuǎn)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; //再反轉(zhuǎn)一次
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);//顯示當(dāng)前到達的層數(shù)
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);//顯示當(dāng)前到達的層數(shù)
LCD_write_string(6,0,str);
break;
}
}
/*******************************************************
定時器0(初始化)
*******************************************************/
void timer0_init(void)
{
TCNT0=0xB2;//10ms產(chǎn)生一次中斷
TCCR0=0x05;//1024分頻
TIMSK|=(1<<TOIE0);//允許timer0溢出中斷
ACSR = 0x80; //關(guān)閉模擬比較器
}
/*******************************************************
定時器0(溢出中斷)..........可簡化程序.............
標(biāo)記規(guī)則: 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));///用于標(biāo)記
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);
//向上計數(shù)置1,向下計數(shù)置0 (10位PWM相位可調(diào))WGM13--10 為0011
TCCR1B|=(1<<CS10);//1分頻
}
/*******************************************************
上升
*******************************************************/
void forward(void)//正轉(zhuǎn)上升
{
OCR1A=0x00FF;//255
PORTD|=BIT(6);
PORTD&=~BIT(7);
}
/*******************************************************
下降
*******************************************************/
void backward(void)//反轉(zhuǎn)下降
{
OCR1A=0x00FF;//255;
PORTD|=BIT(7);
PORTD&=~BIT(6);
}
/*******************************************************
停止運行
*******************************************************/
void stopmove(void)
{
PORTD&=~BIT(6);
PORTD&=~BIT(7);
}
/*******************************************************
電機運行狀態(tài)(上.下.停)
*******************************************************/
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是移位位數(shù)
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;//移位位數(shù),多少人有按按鍵,有請求的層
if( (dir==up) && (cur_floor<5) )
{
if( (upward & 0x1F)!=0 )//有向上鍵按下了
{
for(i=0;i<5;i++) //i為移位位數(shù)(移四位就到第五層)
{
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);
}
}
}
}
}
/*******************************************************************************
主函數(shù)
*******************************************************************************/
void main(void)
{
CLI();//關(guān)中斷
DDRB|=LCD_EN | LCD_RS | LCD_DATA;//EN方向,RS方向,數(shù)據(jù)口方向為輸出
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();//實際調(diào)用 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();//*/
}
}
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -