微波EDA网,见证研发工程师的成长!
首页 > 硬件设计 > 嵌入式设计 > 51单片机工程实践--第3章 74HC595+ULN200

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

时间:11-25 来源:互联网 点击:
首先上图,有图才有真相。实验中的图片。

1、刚上电,继电器不动作,很稳定。这是工程上需要的结果。

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

3、按下KEY2,继电器2吸合,其它继电器断开。

#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 5 // 按键列输出信号稳定的小延时

#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;
}

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++;// 切换到下一步运行
}

Copyright © 2017-2020 微波EDA网 版权所有

网站地图

Top