嵌入式学习——51单片机——(按键、中断)day17

1. 按键程序

1.1 主函数

#include <reg51.h>
#include "digit.h"
#include "key.h"

void delay(int n)
{
	while (n--);
}

int main(void)
{
	int cnt = 0;

	init_digit();
	init_key();

	while (1)
	{	
	  	if (2 == key_pressed())
		{
			cnt++;
			delay(0x5fff);
		}
		show_number(cnt);
	}
	
	return 0;
}

1.2 头文件

#ifndef _KEY_H_
#define _KEY_H_

extern void init_key(void);
extern int key_pressed(void);

#endif 

1.3 源文件

#include <reg51.h>
#include "digit.h"
#include "key.h"

void init_key(void)
{
	P1 |= ((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
	P3 |= (1 << 5);
}

int key_pressed(void)
{
	int ret = 0;

	if (0 == (P1 & (1 << 4)))
	{
		ret = 1;
	}
	else if (0 == (P1 & (1 << 5)))
	{
		ret = 2;
	}
	else if (0 == (P1 & (1 << 6)))
	{
		ret = 3;
	}
	else if (0 == (P1 & (1 << 7)))
	{
		ret = 4;
	}
	else if (0 == (P3 & (1 << 5)))
	{
		ret = 5;
	}
	
	return ret;	
}

2. 中断系统

2.1 中断的定义

        当CPU正在处理某件事情的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完后,再回到原来中断的地方继续原来的工作,这样的过程称为中断。

2.2 中断源的定义

        可以引发中断是事件、条件或者硬件模块,即请示CPU中断的请求源称为中断源。

        常见的中断源

                1. 外部中断源

                2. 定时器、计数器中断源

                3. 串口中断源

                4. ADC中断源

                5. 比较器中断源

                6. 看门狗定时器中断源

2.3 中断执行流程

        1. 中断源发出中断请求

        2. CPU查询中断是否被运行、以及中断是否被屏蔽

        3. CPU考察中断优先级

        4. CPU保护现场

        5. 执行中断服务函数

        6. 恢复现场 

2.4 中断的分类——51单片机

        1. 外部中断0和外部中断1

        2. 定时器中断0和定时器中断1

        3. UART串口中断

3. 外部中断——EINT

3.1 外部中断初始化函数

void init_eint(void)
{
	P3 |= ((1 << 2) | (1 << 3)); 
	IE |= ((1 << 7) | (1 << 2) | (1 << 0));
	TCON &= ~((1 << 0) | (1 << 2));
}

3.2 外部中断0和外部中断1的中断服务函数

void eint0_handle(void)   interrupt 0
{
	num++;
	delay(0xff);	
}

void eint1_handle(void)   interrupt 2
{
	num--;
	delay(0xff);	
}

3.3 通过插拔杜邦线是否接地控制外部中断请求源来实现触发外部中断0和外部中断1

#include <reg51.h>
#include "digit.h"

unsigned int num = 0;

void delay(unsigned int n)
{
	while (n--);
}

void init_eint(void)
{
	P3 |= ((1 << 2) | (1 << 3)); 
	IE |= ((1 << 7) | (1 << 2) | (1 << 0));
	TCON &= ~((1 << 0) | (1 << 2));
}

void eint0_handle(void)   interrupt 0
{
	num++;
	delay(0xff);	
}

void eint1_handle(void)   interrupt 2
{
	num--;
	delay(0xff);	
}

int main(void)
{
	init_eint();

	while (1)
	{
		show_number(num);
	}

	return 0;
}

4.   51单片机的机器周期和指令周期(12分频)

4.1 机器周期——12MHZ

4.2 指令周期——1MHZ(每执行一条指令消耗的时间为1/1000000(s))

5. 定时器中断——定时器溢出可以触发中断,定时器核心部件是一个对脉冲进行计数的加法器

5.1 定时器0中断初始化

void 	timer0_init(void)
{
	TMOD |= ((1 << 0) | (1 << 3));	 //定时器0的工作模式选择
	TMOD &= ~(1 << 1);

	IE |= ((1 << 1) | (1 << 7));//打开CPU总中断和定时器0的溢出中断允许开关

	TH0 = (65535 - 1000) >> 8;
	TL0 = (65535 - 1000);

	TCON |= (1 << 4);
}

5.2 定时器0的中断服务函数

void timer_handle(void)	 interrupt 1
{
	cnt++;
	if (cnt >= 1000)
	{
		num++;
		cnt = 0;
	}
	TH0 = (65535 - 1000) >> 8;
	TL0 = (65535 - 1000);
}

  5.3 通过定时器0的中断来实现数码管按照每秒加1的形式进行计数

        1. 主函数

#include <reg51.h>
#include "digit.h"

unsigned int cnt = 0;
unsigned int num = 0;

void 	timer0_init(void)
{
	TMOD |= ((1 << 0) | (1 << 3));	 //定时器0的工作模式选择
	TMOD &= ~(1 << 1);

	IE |= ((1 << 1) | (1 << 7));//打开CPU总中断和定时器0的溢出中断允许开关

	TH0 = (65535 - 1000) >> 8;
	TL0 = (65535 - 1000);

	TCON |= (1 << 4);
}

void timer_handle(void)	 interrupt 1
{
	cnt++;
	if (cnt >= 1000)
	{
		num++;
		cnt = 0;
	}
	TH0 = (65535 - 1000) >> 8;
	TL0 = (65535 - 1000);
}


int main(void)
{
	timer0_init();

	while (1)
	{
		show_number(num);
	}
	
	return 0;
}

        2. 数码管显示函数

#include <reg51.h>
#include "digit.h"

void display(int digit, int n)
{
	unsigned char a[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
	P1 &= ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3));
	P1 |= (1 << digit);
	P0 = a[n];
}

void show_number(unsigned int n)
{

	int i = 0;
	int j = 0;

	if (0 == n)
	{
		display(0, 0);	
	}else
	{
		while (n != 0)
		{
			i = n % 10;
			n /= 10;
			display(j++, i);
		}
	}
}

6. PWM波

6.1 定义

        PWM(Pulse Width Modulation,脉宽调制)波是一种周期性的方波信号,其特点是脉冲的宽度可以根据需要进行调制。在PWM波中,每个周期由一个高电平脉冲和一个低电平脉冲组成,其间隔时间是一个固定的周期。但是,高电平脉冲的宽度可以根据需要进行调节,通过改变脉冲的宽度,可以改变信号的平均功率,从而实现对电路或设备的控制。

6.2 用途

        PWM波常用于模拟信号的数字控制,例如在调节电机速度、调光LED灯、音频放大器等应用中都有广泛的应用。通过改变PWM波的占空比(高电平脉冲时间与周期时间的比值),可以实现对输出信号的精确控制。因此,PWM波在数字系统中被广泛应用于需要精确控制的场景中。

7. 蜂鸣器——51单片机上为无源蜂鸣器

7.1 有源蜂鸣器

        需要外部电源供电:有源蜂鸣器不像无源蜂鸣器那样能够直接通过激励信号产生声音,而是需要外部电源提供工作电压。

7.2 无源蜂鸣器

        无需外部电源:无源蜂鸣器不需要外部电源供电,它可以直接通过在其引脚上施加电压(通常是直流电压)来产生声音

7.3 不同频率下使蜂鸣器震动发声——下面代码为400hz

#include <reg51.h>

unsigned int cnt = 0;

void 	timer0_init(void)
{
	TMOD |= ((1 << 0) | (1 << 3));	 //定时器0的工作模式选择
	TMOD &= ~(1 << 1);

	IE |= ((1 << 1) | (1 << 7));//打开CPU总中断和定时器0的溢出中断允许开关

	TH0 = (65535 - 125) >> 8;
	TL0 = (65535 - 125);

	TCON |= (1 << 4);
}

void timer_handle(void)	 interrupt 1
{
	cnt++;
	if (cnt >= 10)
	{
		P2 ^= (1 << 1);
		cnt = 0;
	}
	TH0 = (65535 - 125) >> 8;
	TL0 = (65535 - 125);
}


int main(void)
{
	timer0_init();

	while (1)
	{
	}
	
	return 0;
}

7.4 通过不同按键实现不同频率下使蜂鸣器震动发声

        1. 主函数

#include <reg51.h>
#include "key.h"

unsigned int cnt = 0;
unsigned int n = 0;
unsigned int a[3] = {125, 50, 31};	//400hz、1000hz、大约1600hz

void 	timer0_init(void)
{
	TMOD |= ((1 << 0) | (1 << 3));	 //定时器0的工作模式选择
	TMOD &= ~(1 << 1);

	IE |= ((1 << 1) | (1 << 7));//打开CPU总中断和定时器0的溢出中断允许开关

	TH0 = (65535 - a[n]) >> 8;
	TL0 = (65535 - a[n]);
}

void timer_handle(void)	 interrupt 1
{
	cnt++;
	if (cnt >= 10)
	{
		P2 ^= (1 << 1);//控制蜂鸣器以百分之五十占空比发声
		cnt = 0;
	}
	TH0 = (65535 - a[n]) >> 8;
	TL0 = (65535 - a[n]);
}


int main(void)
{
	int key = 0;
	timer0_init();
	init_key();

	while (1)
	{	key = key_pressed();
		if (0 == key)
		{
			TCON &= ~(1 << 4);
		}
		else	if (1 == key)
		{
			n = 0;
			TCON |= (1 << 4);
		}
		else if (2 == key)
		{
			n = 1;
			TCON |= (1 << 4);			
		}
		else if (3 == key)
		{
			n = 2;
			TCON |= (1 << 4);
		}	
	}
	
	return 0;
}

        2. 按键函数

#include <reg51.h>
#include "key.h"

void init_key(void)
{
	P1 |= ((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
	P3 |= (1 << 5);
}

int key_pressed(void)
{
	int ret = 0;

	if (0 == (P1 & (1 << 4)))
	{
		ret = 1;
	}
	else if (0 == (P1 & (1 << 5)))
	{
		ret = 2;
	}
	else if (0 == (P1 & (1 << 6)))
	{
		ret = 3;
	}
	else if (0 == (P1 & (1 << 7)))
	{
		ret = 4;
	}
	else if (0 == (P3 & (1 << 5)))
	{
		ret = 5;
	}
	
	return ret;	
}

8. 利用按键、定时器中断、数码管实现秒表的功能

8.1 主函数

#include <reg51.h>
#include "key.h"
#include "digit.h"

unsigned int cnt = 0;
unsigned int num = 0;

void 	timer0_init(void)
{
	TMOD |= ((1 << 0) | (1 << 3));	 //定时器0的工作模式选择
	TMOD &= ~(1 << 1);

	IE |= ((1 << 1) | (1 << 7));//打开CPU总中断和定时器0的溢出中断允许开关

	TH0 = (65535 - 1000) >> 8;
	TL0 = (65535 - 1000);
}

void timer_handle(void)	 interrupt 1
{
	cnt++;
	if (cnt >= 1000)
	{
		num++;
		cnt = 0;
	}
	TH0 = (65535 - 1000) >> 8;
	TL0 = (65535 - 1000);
}


int main(void)
{
	int key = 0;

	timer0_init();
	init_key();

	while (1)
	{	
		key = key_pressed();
		
		if (1 == key)
		{
			TCON |= (1 << 4);
		}
		else if (2 == key)
		{
			TCON &= ~(1 << 4);			
		}
		else if (3 == key)
		{
			num = 0;
			TCON &= ~(1 << 4);
		}

		show_number(num);	
	}
	
	return 0;
}

8.2 按键函数

#include <reg51.h>
#include "key.h"

void init_key(void)
{
	P1 |= ((1 << 4) | (1 << 5) | (1 << 6) | (1 << 7));
	P3 |= (1 << 5);
}

int key_pressed(void)
{
	int ret = 0;

	if (0 == (P1 & (1 << 4)))
	{
		ret = 1;
	}
	else if (0 == (P1 & (1 << 5)))
	{
		ret = 2;
	}
	else if (0 == (P1 & (1 << 6)))
	{
		ret = 3;
	}
	else if (0 == (P1 & (1 << 7)))
	{
		ret = 4;
	}
	else if (0 == (P3 & (1 << 5)))
	{
		ret = 5;
	}
	
	return ret;	
}

8.3 数码管函数

#include <reg51.h>
#include "digit.h"

void display(int digit, int n)
{
	unsigned char a[10] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};
	P1 &= ~((1 << 0) | (1 << 1) | (1 << 2) | (1 << 3));
	P1 |= (1 << digit);
	P0 = a[n];
}

void show_number(unsigned int n)
{

	int i = 0;
	int j = 0;

	if (0 == n)
	{
		display(0, 0);	
	}else
	{
		while (n != 0)
		{
			i = n % 10;
			n /= 10;
			display(j++, i);
		}
	}
}

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值