历史上的今天
返回首页

历史上的今天

今天是:2024年11月10日(星期日)

正在发生

2021年11月10日 | 51单片机实现两片联级74HC595控制跑马灯

2021-11-10 来源:eefocus

一、使用proteus绘制简单的电路图,用于后续仿真

二、编写程序


/********************************************************************************************************************

---- @Project: LED-74HC595

---- @File: main.c

---- @Edit: ZHQ

---- @Version: V1.0

---- @CreationTime: 20200529

---- @ModifiedTime: 20200529

---- @Description: 第1个至第8个LED灯一直不亮。在第9个至第16个LED灯,依次逐个

---- 亮灯并且每次只能亮一个灯。每按一次独立按键S13键,原来运行的跑马灯会暂停,原

---- 来暂停的跑马灯会运行。用S1来改变方向,用S5和S9来改变速度。

---- 单片机:AT89C52

********************************************************************************************************************/

#include "reg52.h"

/*——————宏定义——————*/

#define FOSC 11059200L

#define T1MS (65536-FOSC/12/1000)   /*1ms timer calculation method in 12Tmode*/

 

 

#define const_voice_short 80 /*蜂鸣器短叫的持续时间*/

 

#define const_key_time1 40

#define const_key_time2 40

#define const_key_time3 40

#define const_key_time4 40

 

/*——————变量函数定义及声明——————*/

/*定义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_S2 = P0^1; /*定义按键S2,对应S5*/

sbit Key_S3 = P0^2; /*定义按键S3,对应S9*/

sbit Key_S4 = P0^3; /*定义按键S4,对应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 = 0;  /*刷新变量。每次更改LED灯的状态都要更新一次。*/

 

unsigned char ucLedStep_01_08 = 0; /*第1个至第8个LED跑马灯的步骤变量*/

unsigned int  uiTimeCnt_01_08 = 0; /*第1个至第8个LED跑马灯的统计定时中断次数的延时计数器*/

 

unsigned char ucLedStep_09_16 = 0; /*第9个至第16个LED跑马灯的步骤变量*/

unsigned int  uiTimeCnt_09_16 = 0; /*第9个至第16个LED跑马灯的统计定时中断次数的延时计数器*/

 

unsigned char ucLedStatus16_09 = 0;   /*代表底层74HC595输出状态的中间变量*/

unsigned char ucLedStatus08_01 = 0;   /*代表底层74HC595输出状态的中间变量*/

 

unsigned char ucKeySec = 0; /*被触发的按键编号*/

unsigned int uiKeyTimeCnt1 = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock2 = 0; /*按键触发后自锁的变量标志*/

unsigned int uiKeyTimeCnt2 = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock3 = 0; /*按键触发后自锁的变量标志*/

unsigned int uiKeyTimeCnt3 = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock1 = 0; /*按键触发后自锁的变量标志*/

unsigned int uiKeyTimeCnt4 = 0; /*按键去抖动延时计数器*/

unsigned char ucKeyLock4 = 0; /*按键触发后自锁的变量标志*/

unsigned int uiVoiceCnt = 0; /*蜂鸣器鸣叫的持续时间计数器*/

 

unsigned int uiSetTimeLevel_09_16 = 300; /*速度变量,此数值越大速度越慢,此数值越小速度越快。*/

unsigned char ucLedDirFlag = 0; /*方向变量,把按键与跑马灯关联起来的核心变量,0代表正方向,1代表反方向*/

unsigned char ucLedStartFlag = 1; /*启动和暂停的变量,0代表暂停,1代表启动*/

/**

* @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 放在定时中断里

**/

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;

}

}

if(Key_S2 == 1) /*IO是高电平,说明按键没有被按下,这时要及时清零一些标志位*/

{

ucKeyLock2 = 0;

uiKeyTimeCnt2 = 0;

}

else if(ucKeyLock2 == 0) /*有按键按下,且是第一次被按下*/

{

uiKeyTimeCnt2 ++; /*累加定时中断次数*/

if(uiKeyTimeCnt2 > const_key_time2)

{

uiKeyTimeCnt2 = 0;

ucKeyLock2 = 1; /*自锁按键置位,避免一直触发*/

ucKeySec = 2;

}

}

if(Key_S3 == 1) /*IO是高电平,说明按键没有被按下,这时要及时清零一些标志位*/

{

ucKeyLock3 = 0;

uiKeyTimeCnt3 = 0;

}

else if(ucKeyLock3 == 0) /*有按键按下,且是第一次被按下*/

{

uiKeyTimeCnt3 ++; /*累加定时中断次数*/

if(uiKeyTimeCnt3 > const_key_time3)

{

uiKeyTimeCnt3 = 0;

ucKeyLock3 = 1; /*自锁按键置位,避免一直触发*/

ucKeySec = 3;

}

}

if(Key_S4 == 1) /*IO是高电平,说明按键没有被按下,这时要及时清零一些标志位*/

{

ucKeyLock4 = 0;

uiKeyTimeCnt4 = 0;

}

else if(ucKeyLock4 == 0) /*有按键按下,且是第一次被按下*/

{

uiKeyTimeCnt4 ++; /*累加定时中断次数*/

if(uiKeyTimeCnt4 > const_key_time4)

{

uiKeyTimeCnt4 = 0;

ucKeyLock4 = 1; /*自锁按键置位,避免一直触发*/

ucKeySec = 4;

}

}

}

/**

* @brief  按键服务的应用程序

* @param  无

* @retval 无

**/

void Key_Service(void)

{

switch(ucKeySec) /*按键服务状态切换*/

{

case 1: /*改变跑马灯方向的按键,对应S1*/

if(ucLedDirFlag == 0) /*通过中间变量改变跑马灯的方向*/

{

ucLedDirFlag = 1;

}

else

{

ucLedDirFlag = 0;

}

uiVoiceCnt = const_voice_short; /*按键声音触发,滴一声就停。*/

ucKeySec = 0; /*响应按键服务处理程序后,按键编号清零,避免一致触发*/

break;

case 2:

if(uiSetTimeLevel_09_16 >= 50)

{

uiSetTimeLevel_09_16 = uiSetTimeLevel_09_16 - 10;

}

else /*最快限定在50*/

{

uiSetTimeLevel_09_16 = 50;

}

uiVoiceCnt = const_voice_short;

ucKeySec = 0;

break;

case 3:

if(uiSetTimeLevel_09_16 <= 550)

{

uiSetTimeLevel_09_16 = uiSetTimeLevel_09_16 + 10;

}

else /*最快限定在550*/

{

uiSetTimeLevel_09_16 = 550;

}

uiVoiceCnt = const_voice_short;

ucKeySec = 0;

break;

case 4:

if(ucLedStartFlag == 1) /*启动和暂停两种状态循环切换*/

{

ucLedStartFlag = 0;

}

else

{

ucLedStartFlag = 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  LED服务函数

//* @param  无

//* @retval 无

//**/

//void LED_Flicker_01_08(void)

推荐阅读

史海拾趣

川土(Chipanalog)公司的发展小趣事

2016年,上海川土微电子有限公司(简称“川土微电子”)正式成立,标志着Chipanalog川土微电子的诞生。作为一家专注于模拟芯片产品研发与销售的高科技公司,川土微电子从成立之初就明确了其核心使命——为中国电子信息制造企业提供高品质进口替代模拟芯片。在创始人及团队的共同努力下,公司迅速确定了发展方向,并开始着手研发首款模拟芯片产品。

智浦欣(Chipstar)公司的发展小趣事

随着技术的不断进步和市场需求的日益增长,智浦欣公司意识到,只有不断创新和突破,才能在激烈的市场竞争中立于不败之地。于是,公司加大了对研发团队的投入,引进了一批国内外顶尖的模拟器件和混合信号设计人才。经过数月的努力,团队成功研发出了一款具有高性价比的WLED驱动器产品,该产品以其卓越的性能和稳定的质量赢得了客户的广泛好评。随后,公司又相继推出了多款具有竞争力的新产品,进一步巩固了其在消费类电子市场的地位。

Hosiden Corporation公司的发展小趣事

随着全球市场的不断扩展,Hosiden积极实施全球化战略,以满足全球客户对高质量电子产品的需求。公司不仅在日本本土拥有强大的生产基地和销售网络,还通过设立海外分支机构、与国际知名企业建立战略合作关系等方式,不断拓宽其全球市场版图。例如,Hosiden在中国市场通过投资豪熙电电子(上海)有限公司等方式,加强了其在中国及亚太地区的业务布局。

EUCHNER公司的发展小趣事

EUCHNER公司一直将质量和服务视为其生命线。公司严格控制产品质量,所有核心部件均自行生产,以确保产品的可靠性和稳定性。同时,公司还注重客户服务体验,为客户提供具有竞争力的价格及优质服务。无论是为大型汽车制造企业还是小型研究机构提供解决方案,公司都坚持与客户紧密合作并倾听他们的需求。通过持续提升质量和服务水平,EUCHNER公司逐渐赢得了客户的信任和忠诚。

东晶(ECEC)公司的发展小趣事

近年来,随着电子信息技术的快速发展和智能化趋势的加剧,东晶电子也面临着新的机遇和挑战。为了适应市场变化和满足客户需求,公司开始实施战略转型和升级。公司加大了对新型电子元器件的研发力度,推动产品向微型化、功能化、高精度方向发展。同时,公司还积极开拓新领域和新市场,拓展业务范围和市场份额。这些举措为公司未来的发展奠定了坚实的基础。

请注意,这些故事是基于已知信息的概括性描述,并非具体的历史事件。在实际情况中,东晶电子的发展历程可能更加复杂和多样化。

Diamond SA公司的发展小趣事

在电子行业竞争日益激烈的背景下,Diamond SA公司开始寻求通过并购来实现规模扩张和资源整合。他们精心挑选了一些具有潜力的目标企业,通过谈判和交易成功完成了并购。这些并购不仅为Diamond SA公司带来了更多的技术资源和市场份额,还增强了公司的整体竞争力。

问答坊 | AI 解惑

请问大家用C开发AVR时使用的是哪个开发环境,哪个更好用.

请问大家用C开发AVR时使用的是哪个开发环境,哪个更好用. 刚刚从C51转到AVR我这里有三个开发环境,AVR Studio | ICCAVR | cvavr | 其中,AVR Studio是买仿真器自带的,现在准备用Mega64做个。产品不知哪个开发环境好用更适合开发呢? 请大家指点 ...…

查看全部问答>

arm

ARM入门笔记…

查看全部问答>

FPGA可综合性对初学着的一些建议

FPGA可综合性对初学着的一些建议一、HDL不是硬件设计语言 过去笔者曾碰到过不少VHDL或Verilog HDL的初学者问一些相似的问题,诸如如何实现除法、开根号,如何写循环语句等等。在这个论坛上,也时常能看到一些网友提出这一类的问题。 对于这些问 ...…

查看全部问答>

IC (es56031)时序问题

有哪位弄过ES56031混响吗? 我按照datasheet的时序,采用UCOM模式,依次发送D4,D3,D2,D1,SHEEP = 10110,但是就是得不到正确的延时啊,总是得到最小的那个延时12MS,我怀疑是一个初始值,也就是说我没有设置成功。…

查看全部问答>

多线程实质是什么?

多线程实质是什么? …

查看全部问答>

如何使用Windows CE开发Web server。最好又实例,谢谢了。

问题如题提供实例者奖1000分。请求帮忙。 可发邮件给我ld.wuxi@yahoo.com.cn…

查看全部问答>

首家外包网络服务平台问世

  “外包在线”网络技术有限公司CEO喻烜为大家讲述了她鲜为人知的创业经历,从初识“外包”到立志创业,从寻求投资到初有成就,借由这朵铿锵玫瑰坚韧不拔的毅力和非凡的智慧,国内首家外包服务网络平台终于问世,自此“外包”服务更加平民化,从 ...…

查看全部问答>

一道非常简单的问题!就当送分!

地址总线A15—A0(低),存储器地址空间为3000H-67FFH,按字节编址。其中3000H-4FFH为ROM区,选用EPROM芯片(4K*2b/片);5000H-67FFH为RAM区,选用DRAM芯片(2K*4位/片) 解释3000H是如何推出(A15A14为00),而 4FFFH又是如何推出(A15A14为01) ...…

查看全部问答>

嵌入式开发经典网站集锦

国内站点: 华恒公司的主页,里面有很多的相关资料,有待大家去发现 http://www.hhcn.com/chinese/embedlinux-res.html SkyEye嵌入式硬件仿真项目 www.skyeye.org http://gro.clinux.org/projects/skyeye/ 公社的SkyEye项目专栏 http://www.linuxfa ...…

查看全部问答>

士大夫

                                 士大夫…

查看全部问答>