历史上的今天
返回首页

历史上的今天

今天是: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)

推荐阅读

史海拾趣

DALLAS公司的发展小趣事

随着移动设备市场的蓬勃发展,Dallas公司敏锐地捕捉到了电池电量管理技术的市场需求。在深入研究和技术攻关后,Dallas成功推出了可编程锂离子电池电量计DS2790。这款产品集成了先进的微控制器、大容量程序和数据存储器以及精密的电池电流、电压和温度测量系统,为定制单节电池电量计的算法提供了优秀的平台。DS2790的推出不仅满足了市场需求,也为Dallas公司在电池管理技术方面赢得了声誉。

璟德(ACX)公司的发展小趣事

多年来,璟德(ACX)凭借其卓越的技术实力和市场表现,荣获了多项荣誉和奖项。这些荣誉不仅是对公司过去努力的肯定,也为其未来的发展注入了新的动力。同时,璟德(ACX)始终坚持创新驱动的发展理念,不断投入研发,推出新产品和新技术,以满足市场的不断变化和客户的需求。

请注意,以上故事是基于现有资料和行业常识构建的,可能无法完全反映璟德(ACX)公司实际发展历程中的所有细节和复杂性。如需了解更多关于璟德(ACX)公司的故事和发展历程,建议查阅公司官方网站、相关新闻报道或行业研究报告。

HANBIT Electronics公司的发展小趣事

2008年,璟德(ACX)成功在台北证券交易所上市,股票代码为3152。这一举措为公司带来了更多的资金支持,也提升了其品牌影响力和市场地位。上市后,璟德(ACX)加大了对研发和市场拓展的投入,进一步巩固了其在无线通信领域的领先地位。

GE Solid State公司的发展小趣事
通过声音信号来反映曝光量,使得用户可以通过听觉直观地感知光线的强弱。
BAE Systems公司的发展小趣事

随着全球化的加速,BAE Systems公司积极寻求跨国合作与拓展机会。公司与多家国际知名企业建立了紧密的合作关系,共同开展研发项目和市场拓展。这些合作不仅帮助公司获取了更多的技术和市场资源,也提升了公司在全球电子行业的地位和影响力。通过跨国合作,BAE Systems公司的产品和服务逐渐进入全球市场,为公司的持续发展注入了新的活力。

Eink公司的发展小趣事
2001年6月,E-Ink再次宣布技术突破,推出了“Ink-in-Motion”技术,使得电子纸上可以显示活动影像。这一技术为电子纸的应用开辟了新的领域,如动态广告、电子书等。

问答坊 | AI 解惑

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。哪位高手能否介绍一下那些管脚的作用?…

查看全部问答>

mic的偏置电阻选择

本帖最后由 paulhyde 于 2014-9-15 09:14 编辑 今年音频题会不会,要加上mic,功放这些部分呢? 找到一个mic的偏置电阻选择资料  …

查看全部问答>

电子电路经典实例-绝对实用

本帖最后由 paulhyde 于 2014-9-15 09:35 编辑 模电电路,图文并茂,讲的非常清楚。。。  …

查看全部问答>

Nand Flash 读写问题

我用的是友善mini2440,Nand Flash型号是K9F1G08,现在是裸机学习; 我在进行读操作时,读出的第一个字节总是 30,然后才是真正的数据; 我的写操作写不进去。 请大家指点下。谢谢! …

查看全部问答>

关于USB设备的读取

{                 m_strLog += _T(\"抱歉,未找到可用的USB设备\");…

查看全部问答>

Windows xpe的ghost方法

嵌入式xpe是用什么工具ghost的?…

查看全部问答>

IAR_STM8编译出错请教

请教;以前在在ST Visual Develop环境下完成的程序现在移植到IAR环境编译报如下错误:不知问题出在哪?? Building configuration: stm8lianfang - Debug Updating build tree... Linking Error[Lp011]: section placement failed: una ...…

查看全部问答>