51单片机工程实践--第3章 74HC595+ULN200

发布者:初入茅庐最新更新时间:2015-10-29 来源: eefocus关键字:51单片机  74HC595  ULN200 手机看文章 扫描二维码
随时随地手机看文章
首先上图,有图才有真相。实验中的图片。

1、刚上电,继电器不动作,很稳定。这是工程上需要的结果。
[转载]51单片机工程实践(连载)—第3章 <wbr>74HC595+ULN200

2、按下KEY1,继电器1吸合,其它继电器断开。

[转载]51单片机工程实践(连载)—第3章 <wbr>74HC595+ULN200

 

3、按下KEY2,继电器2吸合,其它继电器断开。
[转载]51单片机工程实践(连载)—第3章 <wbr>74HC595+ULN200
 


#include
#include


sbit KEY_IN1  = P2 ^ 4;         // 输入按键 接10K上拉电阻
sbit KEY_IN2  = P2 ^ 5;
sbit KEY_OUT1 = P2 ^ 3;         // 输出按键
sbit KEY_OUT2 = P2 ^ 2;

sbit BUZZER_OUT   = P1 ^ 7;         // 蜂鸣器
sbit LED          = P0 ^ 7;        // LED


sbit HC595_SCK_OUT = P1 ^ 0;   // 74HC595数据输入时钟线
sbit HC595_RCK_OUT = P1 ^ 1;   // 74HC595输出存储器锁存时钟线
sbit HC595_OE_OUT  = P1 ^ 2;   // 74HC595输出使能端 接10K上拉电阻
sbit HC595_SI_OUT  = P1 ^ 3;   // 74HC595数据线


typedef unsigned char uint8;
typedef unsigned int uint16;

typedef unsigned char u8;
typedef unsigned int u16;

#define CNT_DELAY_CNT1  25       // 按键去抖动延时阀值
#define CNT_DELAY_CNT2        // 按键列输出信号稳定的小延时

#define CNT_BUZZER_TIME 40



void interrupt_init(void);
void key_scan(void);
void key_service(void);
void relay_status_clear(void);
void relay_status_set_1(void);
void relay_status_set_2(void);
void relay_status_set_3(void);
void relay_status_set_4(void);
void relay_drive(void);
void delay(void);

 


u8 key_step    = 1;         // 按键扫描步骤变量,在switch()括号里面
u8 key_lock1   = 0;         // 按键自锁标志
u8 key_sec     = 0;         // 按键被触发的变量
u16 delay_cnt1 = 0;         // 延时计数器的变量
u16 delay_cnt2 = 0;         // 延时计数器的变量
u16 buzzer_time_cnt = 0;    // 蜂鸣器声音长短的计数延时
u16 relay_status = 0;  // 继电器状态寄存器

int main(void)
{
 interrupt_init();
 
 
 HC595_OE_OUT = 1;  // 置1,595输出口为高阻态,ULN2003输入口内部有下拉电阻,所以把595输出口拉低了
 relay_status_clear(); // 把relay_status清零
 relay_drive();   // 继电器驱动程序,relay_status映射继电器的状态
 HC595_OE_OUT = 0;  // 输出使能端拉低,595输出口有效
 
 BUZZER_OUT = 1;   // 上电关闭蜂鸣器
 
 while(1)
 {
  key_service();  // 按键服务函数
 }
 
 
 return 0;
}[page]

void timer0_interrupt(void) interrupt 1
{
    ET0 = 0;
    EA  = 0;                // 经测试 这里不关闭定时器中断也没有问题 鸿哥这里关闭定时器中断不知道是PIC单片机的特点还是其它原因
   
    key_scan();             // 按键扫描函数
   
    if(buzzer_time_cnt)     // 控制蜂鸣器声音的长短
    
        BUZZER_OUT = 0;     // 开启蜂鸣器
        --buzzer_time_cnt;  // 蜂鸣器声音长短的计数延时
    }
    else
    {
        BUZZER_OUT = 1;         // 关闭蜂鸣器
    }
   
    TH0  = 0xfe;
  TL0  = 0x33;

    ET0 = 1;
    EA  = 1;                // 前面关闭定时器中断,这里当然需要开启 
}

void interrupt_init(void)
{
 TMOD = TMOD | 0x01;
 TMOD = TMOD & 0xFD;
   
    TH0  = 0xfe;   
  TL0  = 0x33;        // 定时0.5ms
 TR0  = 1;

 ET0  = 1;           // 开启外部中断
 EA   = 1;           // 开启总中断  
}

void key_scan(void)
{
 
  switch(key_step)
  {
   case 1:    // 按键扫描 1、2 号按键
    KEY_OUT1 = 0; // 按键列扫描 第一列输出低电平
    KEY_OUT2 = 1; // 第二列输出高电平
    delay_cnt2 = 0; // 延时计数器清零
    key_step++;  // 切换到下一个步骤运行

   break;

  case 2:
   delay_cnt2++;
   if(delay_cnt2>CNT_DELAY_CNT2) // 小延时,但不是去抖动延时 保证列输出信号稳定
   {
    delay_cnt2 = 0;
    key_step++;     // 切换到下一个步骤运行
   }

   break;
   
  case 3:
   if((1==KEY_IN1)&&(1==KEY_IN2)) // 如果没有按键按下,则2个IO输入都是高电平
   {
    key_step++;     // 如果没有按键按下,下一个中断扫描另外2个按键
    key_lock1 = 0;    // 按键自锁标志清零
    delay_cnt1 = 0;    // 按键去抖动延时计数器清零,此处设计很巧妙
   }
   else if((0==KEY_IN1)&&(1==KEY_IN2)&&(0==key_lock1))
   {
    
    ++delay_cnt1;  // 延时计数器

    if(delay_cnt1>CNT_DELAY_CNT1) // 延时计数器超过阀值
    {
     delay_cnt1 = 0; 
     key_lock1 = 1;  // 自锁按键置位,避免一直触发,只有松开按键,才会被清零
     key_sec = 1;  // 触发 1 号按键
    }
   }
           
   else if((1==KEY_IN1)&&(0==KEY_IN2)&&(0==key_lock1))
   {
    ++delay_cnt1;
    if(delay_cnt1>CNT_DELAY_CNT1)
    {
     delay_cnt1 = 0;
     key_lock1 = 1;  // 自锁按键置位,避免一直触发,只有松开按键,才会被清零
     key_sec = 2;  // 触发 2 号按键
    }
   }

   break;

  case 4:    // 扫描 3、4 号按键
   KEY_OUT1 = 1; // 第一列输出高电平
   KEY_OUT2 = 0; // 按键列扫描,第二列输出低电平
   delay_cnt2 = 0; // 延时计数器清零
   key_step++;  // 切换到下一步运行

   break;

  case 5:
   delay_cnt2++;
   if(delay_cnt2>CNT_DELAY_CNT2) // 小延时,但不是去抖动延时 保证列输出信号稳定
   {
    delay_cnt2 = 0;
    key_step++;  // 切换到下一步运行
   }

   break;

  case 6:
   if((1==KEY_IN1)&&(1==KEY_IN2))
   {
    key_step++;
    key_lock1 = 0;
    delay_cnt1 = 0;
   }
   else if((0==KEY_IN1)&&(1==KEY_IN2)&&(0==key_lock1))
   {
    ++delay_cnt1;
    if(delay_cnt1>CNT_DELAY_CNT1)
    {
     delay_cnt1 = 0;
     key_lock1 = 1;
     key_sec = 3;  //  触发 3 号按键
    }
   }
   else if((1==KEY_IN1)&&(0==KEY_IN2)&&(0==key_lock1))
   {
    ++delay_cnt1;
    if(delay_cnt1>CNT_DELAY_CNT1)
    {
     delay_cnt1 = 0;
     key_lock1 = 1;
     key_sec = 4;  // 触发 4 号按键
    }
   }

   break;
  }

  if(key_step>6)  // 判断,第一组与第二组按键反复轮流扫描
  {
  key_step = 1;
  }
}

void key_service(void)
{
 switch(key_sec)
 {
  case 1:  // 1 号按键
   relay_status_clear(); // 把relay_status清零
   relay_status_set_1(); // 把relay_status对应的第一个继电器启动
   relay_drive();   // 把relay_status的状态通过595驱动出来
   buzzer_time_cnt = CNT_BUZZER_TIME;
   key_sec = 0;   // 处理完相应按键程序后,把按键选择变量清零,避免一直触发
   
   break;

  case 2:  // 2 号按键
   relay_status_clear(); // 把relay_status清零
   relay_status_set_2(); // 把relay_status对应的第一个继电器启动
   relay_drive();   // 把relay_status的状态通过595驱动出来
   buzzer_time_cnt = CNT_BUZZER_TIME;
   key_sec = 0;

   break;

  case 3:  // 3 号按键
   relay_status_clear(); // 把relay_status清零
   relay_status_set_3(); // 把relay_status对应的第一个继电器启动
   relay_drive();   // 把relay_status的状态通过595驱动出来
   buzzer_time_cnt = CNT_BUZZER_TIME;
   key_sec = 0;

   break;

  case 4:  // 4 号按键
   relay_status_clear(); // 把relay_status清零
   relay_status_set_4(); // 把relay_status对应的第一个继电器启动
   relay_drive();   // 把relay_status的状态通过595驱动出来
   buzzer_time_cnt = CNT_BUZZER_TIME; 
   key_sec = 0;
   
   break;
 }
}

void relay_status_clear(void)
{
 relay_status = 0;
}

void relay_status_set_1(void)
{
 relay_status |= 0x0001;
}

void relay_status_set_2(void)
{
 relay_status |= 0x0002;
}

void relay_status_set_3(void)
{
 relay_status |= 0x0004;
}

void relay_status_set_4(void)
{
 relay_status |= 0x0008;
}

void relay_drive(void)
{
 u8 tempdata = 0;
// u16 relay_status_temp = 0;
 
 HC595_SCK_OUT = 0;  
 HC595_RCK_OUT = 0;
 
// relay_status_temp = relay_status;
 
 for(tempdata=0; tempdata<16; tempdata++)
 {
  if(relay_status & 0x8000)
  {
   HC595_SI_OUT = 1;
  }
  else
  {
   HC595_SI_OUT = 0;
  }
  
  HC595_SCK_OUT = 0;
  _nop_();
  _nop_();
  HC595_SCK_OUT = 1;
  _nop_();
  _nop_();
  relay_status <<= 1;
 }
 
 HC595_RCK_OUT = 0;
 _nop_();
 _nop_();
 HC595_RCK_OUT = 1;
 _nop_();
 _nop_();
 
 HC595_SCK_OUT = 0;  // 拉低,增强抗干扰
 HC595_RCK_OUT = 0;
 HC595_SI_OUT  = 0; 
}

void delay(void)
{
 u8 t = 0;
 
 for(t=0; t<0x0F; t++)
 {;}

关键字:51单片机  74HC595  ULN200 引用地址:51单片机工程实践--第3章 74HC595+ULN200

上一篇:两片74HC595级联动态驱动8位数码管 51单片机
下一篇:51单片机驱动能力

推荐阅读最新更新时间:2024-03-16 14:37

MCS-51单片机之液晶显示
用MCS-51单片机来驱动液晶显示本已不属于单片机本身的知识了,我所用到的液晶是1602液晶屏,主要是要自已去查看相关芯片的文档,所以自然对英语阅读能力是一个不小的挑战.在看文档的时候,我们也只需要注意几个相对重要的问题,而不用面对大篇的文档而不知何去何从,第一重要当然是液晶的时序图了,只有掌握了时序图后我们才能写出合理正确的程序,除此之外,还有相关引角的作用也是必不可少的. 在编写相关程序时,首先是将相关位进行设置,将RW接地即可,还有就是要合理设置RS位和EN位了,它们分别是读写选择位,命令数据先择位,使能位了,在操作时序的时候,我们主要也是来操作EN位来以时序进行控制的所以,她是极其重要的.接下来,我们就可以向芯片写
[单片机]
51单片机+PWM控制渐变七彩灯C51程序
一、硬件介绍: (采用5050LED 2W) RGB三色LED控制引脚分别为单片机P1.2 、 P1.1 、 P1.0。LED正极接主电源(24V)正极,负极接驱动3颗三极管的集电极,单片机控制脚分别接3颗NPN三极管,三极管发射极接地,而单片机的供电是来自三端稳压器7805,祥细原理如下: 二、实物图片: 三、软件部分: 1、/*原理: 先亮红灯(保持一会儿)----红绿过度(绿加1、红减1循环240次)------ 绿灯亮起(保持一会儿)----绿兰过度(兰加1、绿减1循环240次) -----兰灯亮起(保持)-----兰白过度(绿加1、红加1循环240次、兰不变) ---白红过度,技术支持网站: http
[单片机]
<font color='red'>51单片机</font>+PWM控制渐变七彩灯C51程序
单片机定时器/计数器的方式控制字
从上一节我们已经得知,单片机中的定时/计数器都能有多种用途,那么我怎样才能让它们工作于我所需要的用途呢?这就要通过定时/计数器的方式控制字来设置。 在单片机中有两个特殊功能寄存器与定时/计数有关,这就是TMOD和TCON。顺便说一下,TMOD和TCON是名称,我们在写程序时就能直接用这个名称来指定它们,当然也能直接用它们的地址89H和88H来指定它们(其实用名称也就是直接用地址,汇编软件帮你翻译一下而已)。 TMOD结构 从图1中我们能看出,TMOD被分成两部份,每部份4位。分别用于控制T1和T0,至于这里面是什么意思,我们下面介绍。 TCON结构 从图2中我们能看出,TCON也被分成两部份,高4位用于定时/计数器,
[单片机]
单片机定时器/计数器的方式控制字
基于AT89C51单片机控制LED摇摇棒的研究
0 引言 随着现代科技的发展,高科技产品以其简洁化、便携等,给人们带来了很大的方便。而“摇摇棒”以其更加简捷与新颖的信息传递方式给人们带来耳目一新的感受,也必将会给人们带来一种新的方便的文化传递方式,常用在晚会及大型的娱乐节目场合。 本文通过研究和设计一个利用事先编好程序来控制16个LED发光二极管,并配合左右手的摇晃来显示字符和简易图形的电子装置(简称为“摇摇棒”),来传递有趣的信息。此装置利用AT89C51单片机对发光二极管阵列进行控制。用滚珠开关检测当前摇动状态,单片机控制16个发光二极管进行不同频率的亮灭刷新,则只要摇动就可以可显示输出文字及图案等信息,从而达到在该视觉平面上传达信息的作用。 1 硬件系统的组成
[单片机]
基于AT89C<font color='red'>51单片机</font>控制LED摇摇棒的研究
c51单片机定时中断的精确定时编程方法大全
引 言   MCS-51单片机的中断响应延迟时间,取决于其它中断服务程序是否在进行,或取决于正在执行的是什么样的指 令。单中断系统中的中断响应时间为3~8个机器周期 。无论是哪一种原因引起的误差,在精确定时的应用场合, 必须考虑它们的影响,以确保精确的定时控制。根据定时中断的不同应用情况,应选择不同的精确定时编程方法。   文中以定时器T1工作在定时方式1为例,晶振频率为12MHz 。 1 方法1   在定时器溢出中断得到响应时,停止定时器计数,读出计数值(反映了中断响应的延迟时间),根据此计数值算 出到下一次中断时,需多长时间,由此来重装载和启动定时器。例如定时周期为1ms,则通常定时器重装载值为- 1000(0FC18H)。下
[单片机]
51单片机基础实验例程
代码来源见代码注释。 实验1:点亮第一个LED /************************************************************************************** * 点亮第一个LED实验 * 实现现象:下载程序后D1指示灯点亮 注意事项:无 ***************************************************************************************/ #include reg52.h //此文件中定义了单片机的一些特殊功能寄存器 sbit led=P2^0
[单片机]
<font color='red'>51单片机</font>基础实验例程
基于C8051单片机和FPGA实现导纳测量仪的系统设计
虚拟仪器的广泛应用,使得用户可以根据需求,设计自己的仪器系统。无源网络导纳测量仪即是虚拟仪器设计思想的一种具体运用,旨在实现对端口网络的导纳进行自动测量。测量仪是以C8051单片机为控制和处理核心,采用可编程逻辑器件EPF10K10,根据DDS原理产生信号源,将信号源连接到待测的网络上,对网络两端的电压和电流进行差分放大,使其输出电压尽可能达到ADC的最大输入电压,然后进行A/D采样,采样时,频率随信号频率而改变,一个周期内固定采32个点,用单片机的P1、P2直接接收数据,边采样边接收。对采样所得的电流、电压数据进行快速傅立叶变换(FFT),并分别求出其模值和相位,则导纳的模值为电流模值与电压模值之比,相位为电流与电压的相位之差。
[单片机]
基于C80<font color='red'>51单片机</font>和FPGA实现导纳测量仪的系统设计
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved