历史上的今天
今天是:2024年11月10日(星期日)
2021年11月10日 | 51单片机实现用LED灯和按键来模拟工业自动化设备的运动控制
2021-11-10 来源:eefocus
一、使用proteus绘制简单的电路图,用于后续仿真
二、编写程序
/********************************************************************************************************************
---- @Project: LED-74HC595
---- @File: main.c
---- @Edit: ZHQ
---- @Version: V1.0
---- @CreationTime: 20200602
---- @ModifiedTime: 20200603
---- @Description: 用矩阵键盘中的S1键作为启动独立按键,用S5按键模拟左边
---- 的开关感应器,用S9按键模拟右边的开关感应器,用S13按键模拟下边的开关感应器。
---- 记得把输出线P0.4一直输出低电平,模拟独立按键的触发地GND。
---- 开机默认机械手在左上方的原点位置。按下启动按键后,机械手从左边开始往右边移动,当机械手移动
---- 到最右边时,机械手马上开始往下移动,最后机械手移动到最右下角的位置时,延时1秒,然后原路返
---- 回,一直返回到左上角的原点位置。注意:启动按键必须等机械手处于左上角原点位置时,启动按键的
---- 触发才有效。
---- 单片机:AT89C52
********************************************************************************************************************/
#include "reg52.h"
/*——————宏定义——————*/
#define FOSC 11059200L
#define T1MS (65536-FOSC/12/1000) /*1ms timer calculation method in 12Tmode*/
#define const_voice_short 40 /*蜂鸣器短叫的持续时间*/
#define const_key_time1 20 /*按键去抖动延时的时间*/
#define const_sensor 20 /*开关感应器去抖动延时的时间*/
#define const_1s 500 /*开关感应器去抖动延时的时间*/
/*——————变量函数定义及声明——————*/
/*定义74HC595*/
sbit Hc595_Sh = P2^3;
sbit Hc595_St = P2^4;
sbit Hc595_Ds = P2^5;
/*定义蜂鸣器*/
sbit Beep = P2^7;
/*定义按键*/
sbit Key_S1 = P0^0; /*定义按键S1,对应S1*/
sbit Key_Left = P0^1; /*定义开关感应器Left,对应S5*/
sbit Key_Right = P0^2; /*定义开关感应器Right,对应S9*/
sbit Key_Down = P0^3; /*定义开关感应器Down,对应S13*/
sbit Key_Gnd = P0^4; /*定义按键模拟地*/
unsigned char ucLED1 = 0; /*代表16个灯的亮灭状态,0代表灭,1代表亮*/
unsigned char ucLED2 = 0;
unsigned char ucLED3 = 0;
unsigned char ucLED4 = 0;
unsigned char ucLED5 = 0;
unsigned char ucLED6 = 0;
unsigned char ucLED7 = 0;
unsigned char ucLED8 = 0;
unsigned char ucLED9 = 0;
unsigned char ucLED10 = 0;
unsigned char ucLED11 = 0;
unsigned char ucLED12 = 0;
unsigned char ucLED13 = 0;
unsigned char ucLED14 = 0;
unsigned char ucLED15 = 0;
unsigned char ucLED16 = 0;
unsigned char ucLed_update = 1; /*刷新变量。每次更改LED灯的状态都要更新一次。*/
unsigned char ucLedStatus16_09 = 0; /*代表底层74HC595输出状态的中间变量*/
unsigned char ucLedStatus08_01 = 0; /*代表底层74HC595输出状态的中间变量*/
unsigned int uiRunTimeCnt = 0; /*运动中的时间延时计数器变量*/
unsigned char ucRunStep = 0; /*运动控制的步骤变量*/
unsigned char ucKeySec = 0; /*被触发的按键编号*/
unsigned int uiKeyTimeCnt1 = 0;
unsigned char ucKeyLock1 = 0;
unsigned int uiLeftCnt1 = 0; /*左边感应器软件抗干扰所需的计数器变量*/
unsigned int uiLeftCnt2 = 0;
unsigned char ucLeft = 0; /*左边感应器经过软件抗干扰处理后的状态标志*/
unsigned int uiRightCnt1 = 0; /*右边感应器软件抗干扰所需的计数器变量*/
unsigned int uiRightCnt2 = 0;
unsigned char ucRight = 0; /*右边感应器经过软件抗干扰处理后的状态标志*/
unsigned int uiDownCnt1 = 0; /*下边感应器软件抗干扰所需的计数器变量*/
unsigned int uiDownCnt2 = 0;
unsigned char ucDown = 0; /*下边感应器经过软件抗干扰处理后的状态标志*/
unsigned int uiVoiceCnt = 0; /*蜂鸣器鸣叫的持续时间计数器*/
/**
* @brief 定时器0初始化函数
* @param 无
* @retval 初始化T0
**/
void Init_T0(void)
{
TMOD = 0x01; /*set timer0 as mode1 (16-bit)*/
TL0 = T1MS; /*initial timer0 low byte*/
TH0 = T1MS >> 8; /*initial timer0 high byte*/
}
/**
* @brief 外围初始化函数
* @param 无
* @retval 初始化外围
**/
void Init_Peripheral(void)
{
ET0 = 1;/*允许定时中断*/
TR0 = 1;/*启动定时中断*/
EA = 1;/*开总中断*/
}
/**
* @brief 初始化函数
* @param 无
* @retval 初始化单片机
**/
void Init(void)
{
Key_Gnd = 0;
Beep = 1;
Init_T0();
}
/**
* @brief 延时函数
* @param 无
* @retval 无
**/
void Delay_Long(unsigned int uiDelayLong)
{
unsigned int i;
unsigned int j;
for(i=0;i for(j=0;j<500;j++) /*内嵌循环的空指令数量*/ { ; /*一个分号相当于执行一条空语句*/ } } } /** * @brief 延时函数 * @param 无 * @retval 无 **/ void Delay_Short(unsigned int uiDelayShort) { unsigned int i; for(i=0;i ; /*一个分号相当于执行一条空语句*/ } } /** * @brief 开关感应器软件抗干扰处理函数 * @param 无 * @retval 放在定时中断里 * 开关感应器的抗干扰处理,本质上类似按键的去抖动处理。唯一的区别是: * 按键去抖动关注的是IO口的一种状态,而开关感应器关注的是IO口的两种状态。 * 当开关感应器从原来的1状态切换到0状态之前,要进行软件滤波处理过程,一旦成功地 * 切换到0状态了,再想从0状态切换到1状态的时候,又要经过软件滤波处理过程,符合 * 条件后才能切换到1的状态。通俗的话来说,按键的去抖动从1变成0难,从0变成1容易。 * 开关感应器从1变成0难,从0变成1也难。这里所说的"难"是指要经过去抖处理。 **/ void Sensor_Scan(void) { if(Key_Left == 1) /*左边感应器是高电平,说明有可能没有被接触*/ { uiLeftCnt1 = 0; /*在软件滤波中,非常关键的语句!!!类似按键去抖动程序的及时清零*/ uiLeftCnt2 ++; if(uiLeftCnt2 > const_sensor) { uiLeftCnt2 = 0; ucLeft = 1; /*说明感应器确实没有被接触*/ } } else { uiLeftCnt2 = 0; uiLeftCnt1 ++; if(uiLeftCnt1 > const_sensor) { uiLeftCnt1 = 0; ucLeft = 0; /*说明感应器确实被接触到了*/ } } if(Key_Right == 1) /*右边感应器是高电平,说明有可能没有被接触*/ { uiRightCnt1 = 0; /*在软件滤波中,非常关键的语句!!!类似按键去抖动程序的及时清零*/ uiRightCnt2 ++; if(uiRightCnt2 > const_sensor) { uiRightCnt2 = 0; ucRight = 1; /*说明感应器确实没有被接触*/ } } else { uiRightCnt2 = 0; uiRightCnt1 ++; if(uiRightCnt1 > const_sensor) { uiRightCnt1 = 0; ucRight = 0; /*说明感应器确实被接触到了*/ } } if(Key_Down == 1) /*下边感应器是高电平,说明有可能没有被接触*/ { uiDownCnt1 = 0; /*在软件滤波中,非常关键的语句!!!类似按键去抖动程序的及时清零*/ uiDownCnt2 ++; if(uiDownCnt2 > const_sensor) { uiDownCnt2 = 0; ucDown = 1; /*说明感应器确实没有被接触*/ } } else { uiDownCnt2 = 0; uiDownCnt1 ++; if(uiDownCnt1 > const_sensor) { uiDownCnt1 = 0; ucDown = 0; /*说明感应器确实被接触到了*/ } } } /** * @brief 扫描按键 * @param 无 * @retval 放在定时中断里 **/ void Key_Scan(void) { if(Key_S1 == 1) /*IO是高电平,说明按键没有被按下,这时要及时清零一些标志位*/ { ucKeyLock1 = 0; uiKeyTimeCnt1 = 0; } else if(ucKeyLock1 == 0) /*有按键按下,且是第一次被按下*/ { uiKeyTimeCnt1 ++; /*累加定时中断次数*/ if(uiKeyTimeCnt1 > const_key_time1) { uiKeyTimeCnt1 = 0; ucKeyLock1 = 1; /*自锁按键置位,避免一直触发*/ ucKeySec = 1; } } } /** * @brief 按键服务的应用程序 * @param 无 * @retval 无 **/ void Key_Service(void) { switch(ucKeySec) /*按键服务状态切换*/ { case 1: /*启动按键,对应S1*/ if(ucLeft == 0) /*处于左上角原点位置*/ { ucRunStep = 1; /*启动*/ uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/ } ucKeySec = 0; /*响应按键服务处理程序后,按键编号清零,避免一致触发*/ break; } } /** * @brief 595驱动函数 * @param 无 * @retval * 两个联级74HC595的工作过程: * 每个74HC595内部都有一个8位的寄存器,两个联级起来就有两个寄存器。ST引脚就相当于一个刷新 * 信号引脚,当ST引脚产生一个上升沿信号时,就会把寄存器的数值输出到74HC595的输出引脚并且锁存起来, * DS是数据引脚,SH是把新数据送入寄存器的时钟信号。也就是说,SH引脚负责把数据送入到寄存器里,ST引脚 * 负责把寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来。 **/ void HC595_Drive(unsigned char ucLedStatusTemp16_09, unsigned char ucLedStatusTemp08_01) { unsigned char i; unsigned char ucTempData; Hc595_Sh = 0; Hc595_St = 0; ucTempData = ucLedStatusTemp16_09; /*先送高8位*/ for(i = 0; i < 8; i ++) { if(ucTempData >= 0x80) { Hc595_Ds = 1; } else { Hc595_Ds = 0; } Hc595_Sh = 0; /*SH引脚的上升沿把数据送入寄存器*/ Delay_Short(15); Hc595_Sh = 1; Delay_Short(15); ucTempData = ucTempData <<1; } ucTempData = ucLedStatusTemp08_01; /*再先送低8位*/ for(i = 0; i < 8; i ++) { if(ucTempData >= 0x80) { Hc595_Ds = 1; } else { Hc595_Ds = 0; } Hc595_Sh = 0; /*SH引脚的上升沿把数据送入寄存器*/ Delay_Short(15); Hc595_Sh = 1; Delay_Short(15); ucTempData = ucTempData <<1; } Hc595_St = 0; /*ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来*/ Delay_Short(15); Hc595_St = 1; Delay_Short(15); Hc595_Sh = 0; /*拉低,抗干扰就增强*/ Hc595_St = 0; Hc595_Ds = 0; } /** * @brief LED更新函数 * @param 无 * @retval * 把74HC595驱动程序翻译成类似单片机IO口直接驱动方式的过程。 * 每次更新LED输出,记得都要把ucLed_update置1表示更新。 **/ void LED_Update() { if(ucLed_update == 1) { ucLed_update = 0; /*及时清零,让它产生只更新一次的效果,避免一直更新。*/ if(ucLED1 == 1) { ucLedStatus08_01 = ucLedStatus08_01 | 0x01; } else { ucLedStatus08_01 = ucLedStatus08_01 & 0xfe; } if(ucLED2 == 1) { ucLedStatus08_01 = ucLedStatus08_01 | 0x02; } else { ucLedStatus08_01 = ucLedStatus08_01 & 0xfd; } if(ucLED3 == 1) { ucLedStatus08_01 = ucLedStatus08_01 | 0x04; } else { ucLedStatus08_01 = ucLedStatus08_01 & 0xfb; } if(ucLED4 == 1) { ucLedStatus08_01 = ucLedStatus08_01 | 0x08; } else { ucLedStatus08_01 = ucLedStatus08_01 & 0xf7; } if(ucLED5 == 1) { ucLedStatus08_01 = ucLedStatus08_01 | 0x10; } else { ucLedStatus08_01 = ucLedStatus08_01 & 0xef; } if(ucLED6 == 1) { ucLedStatus08_01 = ucLedStatus08_01 | 0x20; } else { ucLedStatus08_01 = ucLedStatus08_01 & 0xdf; } if(ucLED7 == 1) { ucLedStatus08_01 = ucLedStatus08_01 | 0x40; } else { ucLedStatus08_01 = ucLedStatus08_01 & 0xbf; } if(ucLED8 == 1) { ucLedStatus08_01 = ucLedStatus08_01 | 0x80; } else { ucLedStatus08_01 = ucLedStatus08_01 & 0x7f; } if(ucLED9 == 1) { ucLedStatus16_09 = ucLedStatus16_09 | 0x01; } else { ucLedStatus16_09 = ucLedStatus16_09 & 0xfe; } if(ucLED10 == 1) { ucLedStatus16_09 = ucLedStatus16_09 | 0x02; } else { ucLedStatus16_09 = ucLedStatus16_09 & 0xfd; } if(ucLED11 == 1) { ucLedStatus16_09 = ucLedStatus16_09 | 0x04; } else { ucLedStatus16_09 = ucLedStatus16_09 & 0xfb; } if(ucLED12 == 1) { ucLedStatus16_09 = ucLedStatus16_09 | 0x08; } else { ucLedStatus16_09 = ucLedStatus16_09 & 0xf7; } if(ucLED13 == 1) { ucLedStatus16_09 = ucLedStatus16_09 | 0x10; } else { ucLedStatus16_09 = ucLedStatus16_09 & 0xef; } if(ucLED14 == 1) { ucLedStatus16_09 = ucLedStatus16_09 | 0x20; } else { ucLedStatus16_09 = ucLedStatus16_09 & 0xdf; } if(ucLED15 == 1) { ucLedStatus16_09 = ucLedStatus16_09 | 0x40; } else { ucLedStatus16_09 = ucLedStatus16_09 & 0xbf; } if(ucLED16 == 1) { ucLedStatus16_09 = ucLedStatus16_09 | 0x80; } else { ucLedStatus16_09 = ucLedStatus16_09 & 0x7f; } HC595_Drive(ucLedStatus16_09, ucLedStatus08_01); } } /** * @brief 机械手变化函数 * @param 无 * @retval 无 **/ void Left2Right(void) { ucLED1 = 1; /*1代表左右气缸从左边移动到右边*/ ucLed_update = 1; } void Right2Left(void) { ucLED1 = 0; /*0代表左右气缸从右边移动到左边*/ ucLed_update = 1; } void Up2Down(void) { ucLED2 = 1; /*1代表左右气缸从上边移动到下边*/ ucLed_update = 1; } void Down2Up(void)
史海拾趣
|
Chrome渲染引擎同Safari 正开发Linux和MAC版 北京时间9月2日消息:据国外媒体报道,Google周一通过漫画宣布,将推出网络浏览器 Chrome。目前,有关Chrome的技术内容也逐渐出现在了网上。 据悉,Chrome浏览器使用了开源的网页渲染引擎WebKit,这个引擎也被使用在了苹果公司的Safari浏览器中, ...… 查看全部问答> |
|
本人有个带驱动器的步进电机,型号为BL55S-M01是三星打印机上的,上面带一个10针的插座分别为:1.24V 2. 24V 3.GND 4.GND 5.BK 6.5V(NC) 7.ST/SP 8.RD 9.CLK 10.CW /CCW。哪位高手能否介绍一下那些管脚的作用?… 查看全部问答> |
|
我用的是友善mini2440,Nand Flash型号是K9F1G08,现在是裸机学习; 我在进行读操作时,读出的第一个字节总是 30,然后才是真正的数据; 我的写操作写不进去。 请大家指点下。谢谢! … 查看全部问答> |
|
请教;以前在在ST Visual Develop环境下完成的程序现在移植到IAR环境编译报如下错误:不知问题出在哪?? Building configuration: stm8lianfang - Debug Updating build tree... Linking Error[Lp011]: section placement failed: una ...… 查看全部问答> |






