#include "reg52.h"
#include <intrins.h>
typedef unsigned int uint;
typedef unsigned char uchar;
#define LIFT_FLOORS 4 // 定义电梯的层数
// sbit led = P2^0;
sbit LSA = P2^2;
sbit LSB = P2^3;
sbit LSC = P2^4;
sbit k3 = P3^2;
// sbit k2 = P3^2;
sbit lift0_led = P2^6;
sbit lift1_led = P2^7;
#define GPIO_DIG P0
#define GPIO_KEY P1
uchar digit_code[17] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07,
0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71};
// 分别是对应-1、0、1的move值的
uchar arrow_code[3] = {0x44, 0x0, 0x42};
uchar open_code = 0x73; // 开门的符号标志
// Only count from 1 when display digits!
struct {
/* OUTSIDE up&down requests in all floors */
char up[LIFT_FLOORS], down[LIFT_FLOORS];
/* request of floors INSIDE lifts */
char lift_to[2][LIFT_FLOORS];
/* lift STATES */
/* current position */
char lift_at[2];
/* 1 for upstairs, -1 for downstairs, 0 for not moving */
char lift_move[2];
char lift_bmove[2]; // bopen: before openning
/* is the lift open? */
char lift_open[2];
char flag; /* whether key scanning keeps going */
} status;
// 非常重要的一个计时器,必须是足够长的uint类型
uint timerint_counter = 0;
/* Delay for some time, helper function. */
void delay(uint i) {
while (i--);
}
/* If condition holds, the block will run and
it will wait until the condition turns false.
Otherwise, the block will be skipped. */
#define RUN_AND_WAIT(_condition, _block) do {\
if (_condition) {\
_block;\
while (_condition);\
}\
} while(0)
// 每1ms到期一次的计数值
#define __RESET_TIMER_COUNT__ {\
TH0=0Xfc; \
TL0=0X18;\
}
#define __RESET_TIMER__ {\
timerint_counter = 0;\
status.flag = 1;\
__RESET_TIMER_COUNT__ \
TR0 = 1;\
}
// 现在的通知并不会关掉计时器,这样计时器的数量就会一直上升,每一轮都是同样的触发时间
#define __NOTIFY__ {\
status.flag = 0;\
}
void global_init() {
char i;
/* Turn on interrupt feature */
IT0 = 1;
EA = 1;
EX0 = 1;
/* Set up timer feature */
TMOD |= 0x1;
// 开启定时器中断
ET0=1; /* enable timer 0 */
// 初始化计时器
__RESET_TIMER_COUNT__
/* init global status */
/* Probably needs to update every now and then. */
for (i = 0; i < LIFT_FLOORS; ++i) {
status.up[i] = 0;
status.down[i] = 0;
status.lift_to[0][i] = 0;
status.lift_to[1][i] = 0;
}
for (i = 0; i < 2; ++i) {
status.lift_at[i] = 0;
status.lift_move[i] = 0;
status.lift_bmove[i] = 0;
status.lift_open[i] = 0;
}
status.flag = 1;
// 开启定时器
TR0=1; /* turn timer0 on */
// 只需要用一个定时器就能够完成定期刷新
}
void display() {
// 显示第一个电梯的方向
LSA = 1; LSB = 0; LSC = 1;
P0 = arrow_code[status.lift_move[0] + 1];
// 显示开门信息
if (!status.lift_move[0] && status.lift_open[0]) {
P0 = open_code;
}
delay(1);
P0 = 0;
// 显示第一个电梯的楼层
LSA = 0; // LSB = 0; // LSC = 1;
P0 = digit_code[status.lift_at[0] + 1];
delay(1); // 消隐
P0 = 0;
// 显示第二个电梯的楼层
LSA = 0; LSB = 0; LSC = 0;
P0 = digit_code[status.lift_at[1] + 1];
delay(1); // 消隐
P0 = 0;
// 显示第二个电梯的方向
LSA = 1;
P0 = arrow_code[status.lift_move[1] + 1];
if (!status.lift_move[1] && status.lift_open[1]) {
P0 = open_code;
}
delay(1); // 消隐
P0 = 0;
/* P2 controls LED */
/* because LSA/LSB/LSC turn it on, we have to undo it */
P2 = ~0;
/* show status of open lifts */
lift0_led = ~status.lift_open[0];
lift1_led = ~status.lift_open[1];
}
// void exint_handler() interrupt 0 {
// /* It seems that only K3 can arise interrupt 0, but how come? */
// delay(1000);
// }
void timerint_handler() interrupt 1 {
__RESET_TIMER_COUNT__
display();
/** 不会关掉定时器,定时器继续运行
但是因为1ms才运行一次,所以在后面的时间内不会溢出,最后由__RESET_TIMER__宏重置
*/
if (++timerint_counter == 700) {
__NOTIFY__
}
}
#define inside_request(lift, floor) do {\
status.lift_to[lift][floor] = 1;\
} while (0)
/* scan user inputs and store them as requests */
void input_scan() {
/* scan key press */
int KeyValue = -1; // remember to init KeyValue to prevent previous impact
int a = 0;
GPIO_KEY = 0x0f;
if(GPIO_KEY != 0x0f) {
// handle jitter
// delay_with_display(64);
delay(800);
if(GPIO_KEY != 0x0f) {
// 获取按键的输入
GPIO_KEY = 0X0F;
switch(GPIO_KEY) {
case(0X07): KeyValue = 0; break;
case(0X0b): KeyValue = 1; break;
case(0X0d): KeyValue = 2; break;
case(0X0e): KeyValue = 3; break;
}
GPIO_KEY = 0XF0;
switch(GPIO_KEY) {
case(0X70): KeyValue = KeyValue; break;
case(0Xb0): KeyValue = KeyValue + 4; break;
case(0Xd0): KeyValue = KeyValue + 8; break;
case(0Xe0): KeyValue = KeyValue + 12; break;
}
// 处理按键的输入
switch (KeyValue) {
case 0: /*调试按键用*/
status.lift_at[0] = (status.lift_at[0] + 1) % LIFT_FLOORS;
break; // 顶楼不能向上
case 1: status.down[3] = 1; break;
case 2: inside_request(0, 3); break;
case 3: inside_request(1, 3); break;
case 4: status.up[2] = 1; break;
case 5: status.down[2] = 1; break;
case 6: inside_request(0, 2); break;
case 7: inside_request(1, 2); break;
case 8: status.up[1] = 1; break;
case 9: status.down[1] = 1; break;
case 10: inside_request(0, 1); break;
case 11: inside_request(1, 1); break;
case 12: status.up[0] = 1; break;
case 13: break; // 一楼不能够向下
case 14: inside_request(0, 0); break;
case 15: inside_request(1, 0); break;
}
// 等待按键的释放
while((a < 300) && (GPIO_KEY != 0xf0)) {
// delay_with_display(32);
delay(100);
a++;
}
}
}
}
// 会让程序冻结,用来做测试
#define __FREEZE__ {\
EA = 0;\
while (1);\
}
#define open_lift(i) do {\
status.lift_open[i] = 1;\
status.lift_bmove[i] = status.lift_move[i];\
status.lift_move[i] = 0;\
} while (0)
// 关门的时候恢复之前的速度?
#define shut_lift(i) do {\
status.lift_open[i] = 0;\
status.lift_move[i] = status.lift_bmove[i];\
} while (0)
void update() {
char i, j, pos;
char has_inside_reqs;
char has_outside_reqs;
char step;
// for each lift
for (i = 0; i < 2; ++i) {
// update position
status.lift_at[i] += status.lift_move[i];
pos = status.lift_at[i];
step = status.lift_move[i];
// 计算这一个电梯是否有内部的请求
for (j = 0, has_inside_reqs = 0; j < LIFT_FLOORS; ++j) {
has_inside_reqs = has_inside_reqs || status.lift_to[i][j];
}
/** 计算是否有外部的请求。
因为前一个电梯可能已经转化了一个外部请求,所以每部电梯应该单独计算外面是否还有请求
*/
for (j = 0, has_outside_reqs = 0; j < LIFT_FLOORS; ++j) {
has_outside_reqs = has_outside_reqs || status.down[j] || status.up[j];
}
/* 检查是否应该开门
* 1. 本层内部有请求,到达该楼层
* 2. 内部有请求且顺路
* 3. 内部没有请求,但是外部当层有请求
*/
// 检查是否需要开门,若需要开门,后面的运算不再进行
if (status.lift_to[i][pos]
|| (has_inside_reqs && (step < 0 && status.down[pos] || step > 0 && status.up[pos]))
|| (!has_inside_reqs && (status.down[pos] || status.up[pos]))
) {
status.lift_to[i][po