📄 traffic.c
字号:
#include <reg52.h> //头文件
#include <rtx51tny.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
code char sysmenu[] = //系统命令菜单
"\n"
"+*** TRAFFIC LIGHT CONTROLLER using AT89S52 and RTX-51 Tiny ***+\n"
"+ 命令 ----+ 格式 -------+ 功能 -------------------------------+\n"
"| Display | D | 显示时间 |\n"
"| Time | T hh:mm:ss | 设置时钟时间 |\n"
"| start_time | S hh:mm:ss | 设置起始时间 |\n"
"| end_time | E hh:mm:ss | 设置结束时间 |\n"
"+----------+-------------+-------------------------------------+\n";
idata char inline[16]; //存储输入命令行
#define uchar unsigned char //宏定义
extern getline (char idata *, char); //外部函数声明:,用于行输入
extern init_serial (); //外部函数:声明,用于初始化串行口
#define INIT 0 //任务0: 初始化系统
#define COMMAND 1 //任务1: 命令处理
#define CLK 2 //任务2: 时钟控制
#define BLINKING 3 //任务3: 黄色灯闪烁
#define LIGHTS 4 //任务4: 交通灯工作
#define buttonREAD 5 //任务5: 读取行人按钮
#define GET_ESC 6 //任务6: 退出
#define ESC 0x1B //定义ESC 键代码
struct time { //定义时间结构
uchar hour; //小时
uchar min; //分
uchar sec; //秒
};
struct time clk_time = { 0, 0, 0 }; //存储时钟的时间值
struct time start_time = { 6, 30, 0 }; //开始时间
struct time end_time = { 20, 30, 0 }; //结束时间
struct time ztime; //输入时间暂存
bit escape; //ESC 键输入标志
bit display_time = 0; //标志:信号命令状态显示时间
sbit green = P2^0; //绿灯
sbit yellow = P2^1; //黄灯
sbit red = P2^2; //红灯
sbit stop = P2^3; //行人停止灯
sbit walk = P2^4; //行人通过灯
sbit button = P2^5; //行人按钮
init () _task_ INIT //任务0,程序起始处
{
init_serial (); //初始化单片机串行口
os_create_task (CLK); //启动任务2
os_create_task (COMMAND); //启动任务1
os_create_task (LIGHTS); //启动任务4
os_create_task (buttonREAD); //启动任务5
os_delete_task (INIT); //停止任务0
}
void clock () _task_ CLK //任务2
{
while (1)
{
if (++clk_time.sec == 60) //计算秒值
{
clk_time.sec = 0;
if (++clk_time.min == 60) //计算分钟值
{
clk_time.min = 0;
if (++clk_time.hour == 24) //计算小时值
{
clk_time.hour = 0;
}
}
}
if (display_time) //显示时间
{
os_send_signal (COMMAND); //向任务1发送信号
}
os_wait (K_IVL, 100, 0); //等待1秒
}
}
bit readtime (char idata *buffer) //读取时间函数
{
uchar args;
ztime.sec = 0; //初始化
args = sscanf (buffer, "%bd:%bd:%bd", //扫描输入,并保存至变量
&ztime.hour,
&ztime.min,
&ztime.sec);
if (ztime.hour > 23 || ztime.min > 59 || //检查输入时间值是否有效
ztime.sec > 59 || args < 2 || args == EOF)
{
printf ("\nINVALID TIME FORMAT!\n"); //输出错误信息
return (0);
}
return (1);
}
command () _task_ COMMAND //任务1
{
uchar i;
printf (sysmenu); //系统命令菜单
while (1)
{
printf ("\nCommand: "); //显示命令提示符
getline (&inline, sizeof (inline)); //获得命令行输入
for (i = 0; inline[i] != 0; i++) //将命令字符串转换为大写
{
inline[i] = toupper(inline[i]);
}
for (i = 0; inline[i] == ' '; i++); //跳过字符串中的空格符
switch (inline[i]) //命令处理
{
case 'D': //显示时间命令
printf ("start_time=: %02bd:%02bd:%02bd "
"end_time=: %02bd:%02bd:%02bd\n",
start_time.hour, start_time.min, start_time.sec,
end_time.hour, end_time.min, end_time.sec);
printf ("Input ESC to abort\r");
os_create_task (GET_ESC); //在显示任务中检查ESC 键
display_time = 1; //显示时间标志置1
escape = 0; //清除 ESC 标志
os_clear_signal (COMMAND);
while (!escape) //如果没有输入ESC
{
printf ("Time: %02bd:%02bd:%02bd\r",
clk_time.hour, clk_time.min, clk_time.sec);
os_wait (K_SIG, 0, 0); //等待
}
os_delete_task (GET_ESC); //删除任务
display_time = 0; //显示时间标志置0
printf ("\n\n"); //输出换行符
break;
case 'T': //设置时间命令
if (readtime (&inline[i+1])) //获取输入时间
{
clk_time.hour = ztime.hour;
clk_time.min = ztime.min;
clk_time.sec = ztime.sec;
}
break;
case 'S': //设置开始时间命令
if (readtime (&inline[i+1])) //获取输入时间
{
start_time.hour = ztime.hour;
start_time.min = ztime.min;
start_time.sec = ztime.sec;
}
break;
case 'E': //设置结束时间命令
if (readtime (&inline[i+1])) //获取输入时间
{
end_time.hour = ztime.hour;
end_time.min = ztime.min;
end_time.sec = ztime.sec;
}
break;
default: //无效指令
printf("Error!");
printf (sysmenu); //显示系统命令菜单
break;
}
}
}
bit signalon () //检查系统时钟是否处在开始时间和结束时间之间
{
if (memcmp (&start_time, &end_time, sizeof (struct time)) < 0)
{
if (memcmp (&start_time, &clk_time, sizeof (struct time)) < 0 &&
memcmp (&clk_time, &end_time, sizeof (struct time)) < 0)
return (1); //红绿灯处于活跃状态
}
else
{
if (memcmp (&end_time, &clk_time, sizeof (start_time)) > 0 &&
memcmp (&clk_time, &start_time, sizeof (start_time)) > 0)
return (1);
}
return (0); //信号结束,开始闪烁黄灯
}
void blinking () _task_ BLINKING //任务3
{
red = 0; //熄灭红灯
yellow = 0; //熄灭黄灯
green = 0; //熄灭绿灯
stop = 0; //熄灭行人红灯
walk = 0; //熄灭行人绿灯
while (1) //闪烁循环
{
yellow = 1; //点亮黄灯
os_wait (K_TMO, 30, 0); //等待超时
yellow = 0; //熄灭黄灯
os_wait (K_TMO, 30, 0); //等待超时
if (signalon ()) //如果闪烁时间段结束
{
os_create_task (LIGHTS); //启动任务4
os_delete_task (BLINKING); //停止任务3
}
}
}
void lights () _task_ LIGHTS //任务4
{
red = 1; //点亮红灯
yellow = 0; //熄灭黄灯
green = 0; //熄灭绿灯
stop = 1; //点亮行人红灯
walk = 0; //熄灭行人绿灯
while (1) //主循环
{
os_wait (K_TMO, 30, 0); //等待超时
if (!signalon ()) //如果系统时间处在活跃时间之外
{
os_create_task (BLINKING); //启动任务3
os_delete_task (LIGHTS); //停止任务4
}
yellow = 1;
os_wait (K_TMO, 30, 0); //等待超时
red = 0;
yellow = 0; //为主干道点亮绿灯
green = 1;
os_clear_signal (LIGHTS);
os_wait (K_TMO, 30, 0); //等待超时
os_wait (K_TMO + K_SIG, 300, 0); //等待超时和信号
yellow = 1;
green = 0;
os_wait (K_TMO, 30, 0); //等待超时
red = 1; //为主干道点亮红灯
yellow = 0;
os_wait (K_TMO, 30, 0); //等待超时
stop = 0; //为行人点亮绿灯,放行
walk = 1;
os_wait (K_TMO, 100, 0); //等待超时
stop = 1; //为行人点亮红灯
walk = 0;
}
}
void buttonread () _task_ buttonREAD //任务5
{
while (1)
{
if (button) //若行人按钮按下
{
os_send_signal (LIGHTS); //向任务4发送信号
}
os_wait (K_TMO, 3, 0); //等待超时
}
}
void get_escape () _task_ GET_ESC //任务6
{
while (1)
{
if (_getkey () == ESC) //如果ESC 键输入,置escape标志
escape = 1;
if (escape) //如果有escape标志,向任务1发送信号
{
os_send_signal (COMMAND);
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -