📄 diantcontrol.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 + -