从单片机基础到程序框架(全集 2019pdf版).pdf - 第584页
sbit KEY_I NPUT1=P2^ 2; //【启动】按键 K 1 的输入口。 sbit Senso rRight_sr =P2^1; //右感应器的 输入口 sbit Senso rUp_sr=P2 ^0; //上感应器的 输入口 volatile u nsigned c har vGu8Sens orRight=0 ; //右感应器经 过滤波后的当 前电平状态。 volatile u nsigned c har vGu8Sen…

移动 2 秒,移动 2 秒后开始原路返回,“机械手”向上移动,碰到“上感应器”后,滑块开始往左边移动,
移动 3 秒后默认已经回到原位最左边,此时“计数器”累加 1,完成一次过程,如果再按下启动按键,继续
重复这个过程。
这个设备用了 2 个气缸。1 个“水平气缸”驱动滑块水平方向的左右移动,当控制“水平气缸”的输出
信号为 0 时往左边跑,当控制“水平气缸”的输出信号为 1 时往右边跑。另 1 个“垂直气缸”驱动“机械手”
的上下移动,当控制“垂直气缸”的输出信号为 0 时往上边跑,当控制“垂直气缸”的输出信号为 1 时往下
边跑。
这个设备用了 2 个开关感应器。分别是“右感应器”和“上感应器”。当感应器没有被碰到的时候信号
为 1,当感应器被碰到的时候信号为 0。
这个设备用了 1 个独立按键。控制运动的启动。
2 个气缸是输出信号,用 P1.4 和 P1.5 所控制的两个 LED 模拟。2 个开关感应器是输入信号,用 K2 和 K3
这两个独立按键模拟。1 个独立按键用 K1 按键。如上图。
#include "REG52.H"
#define KEY_VOICE_TIME 50
#define KEY_FILTER_TIME 25
#define SENSOR_TIME 20 //开关感应器的“滤波”时间
void T0_time();
void SystemInitial(void) ;
void Delay(unsigned long u32DelayTime) ;
void PeripheralInitial(void) ;
void BeepOpen(void);
void BeepClose(void);
void GoLeft(void) ; //“水平气缸”往左跑
void GoRight(void); //“水平气缸”往右跑
void GoUp(void); //“垂直气缸”往上跑
void GoDown(void); //“垂直气缸”往下跑
void VoiceScan(void);
void SensorScan(void); //开关感应器的消抖,在定时中断里调用处理
void KeyScan(void);
void KeyTask(void);
void RunTask(void); //运动控制的任务函数
sbit P1_4=P1^4; //水平气缸的输出
sbit P1_5=P1^5; //垂直气缸的输出
sbit P3_4=P3^4; //蜂鸣器的输出口

sbit KEY_INPUT1=P2^2; //【启动】按键 K1 的输入口。
sbit SensorRight_sr=P2^1; //右感应器的输入口
sbit SensorUp_sr=P2^0; //上感应器的输入口
volatile unsigned char vGu8SensorRight=0; //右感应器经过滤波后的当前电平状态。
volatile unsigned char vGu8SensorUp=0; //上感应器经过滤波后的当前电平状态。
volatile unsigned char vGu8BeepTimerFlag=0;
volatile unsigned int vGu16BeepTimerCnt=0;
volatile unsigned char vGu8KeySec=0;
unsigned char Gu8RunStart=0; //启动的总开关
unsigned char Gu8RunStatus=0; //运动的状态,0 为停止,1 为运行
unsigned int Gu16RunCnt=0; //计数器
unsigned int Gu16ReturnLeftTime=3000; //水平往左跑的延时变量,默认为 3 秒
unsigned int Gu16GoDownTime=2000; //垂直往下跑的延时变量,默认为 2 秒
volatile unsigned char vGu8RunTimerFlag=0; //用于控制运动过程中的延时的定时器
volatile unsigned int vGu16RunTimerCnt=0;
void main()
{
SystemInitial();
Delay(10000);
PeripheralInitial();
while(1)
{
KeyTask(); //按键的任务函数
RunTask(); //运动控制的任务函数
}
}
/* 注释一:
* 两个“计时器”相互“清零”相互“抗衡”,从而实现了开关感应器的“消抖”处理,
* 专业术语也叫“软件滤波”。这种滤波方式,不管是从“高转成低”,还是“低转成高”,
* 如果在某个瞬间出现干扰抖动,某个计数器都会及时被“清零”,从而起到非常高效的消抖滤波作用。
*/
void SensorScan(void) //此函数放在定时中断里每 1ms 扫描一次,用来识别和滤波开关感应器
{
static unsigned int Su16SensorRight_H_Cnt=0; //判断高电平的计时器

static unsigned int Su16SensorRight_L_Cnt=0; //判断低电平的计时器
static unsigned int Su16SensorUp_H_Cnt=0; //判断高电平的计时器
static unsigned int Su16SensorUp_L_Cnt=0; //判断低电平的计时器
//右感应器的滤波
if(0==SensorRight_sr)
{
Su16SensorRight_H_Cnt=0; //在判断低电平的时候,高电平的计时器被清零,巧妙极了!
Su16SensorRight_L_Cnt++;
if(Su16SensorRight_L_Cnt>=SENSOR_TIME)
{
Su16SensorRight_L_Cnt=0;
vGu8SensorRight=0; //此全局变量反馈经过滤波后“右感应器”当前电平的状态
}
}
else
{
Su16SensorRight_L_Cnt=0; //在判断高电平的时候,低电平的计时器被清零,巧妙极了!
Su16SensorRight_H_Cnt++;
if(Su16SensorRight_H_Cnt>=SENSOR_TIME)
{
Su16SensorRight_H_Cnt=0;
vGu8SensorRight=1; //此全局变量反馈经过滤波后“右感应器”当前电平的状态
}
}
//上感应器的滤波
if(0==SensorUp_sr)
{
Su16SensorUp_H_Cnt=0;
Su16SensorUp_L_Cnt++;
if(Su16SensorUp_L_Cnt>=SENSOR_TIME)
{
Su16SensorUp_L_Cnt=0;
vGu8SensorUp=0; //此全局变量反馈经过滤波后“上感应器”当前电平的状态
}
}
else
{
Su16SensorUp_L_Cnt=0;
Su16SensorUp_H_Cnt++;