51单片机学习2
9.独立按键
1. 按键一端接到GND,另外一端接到GPIO引脚
2. 如果按键被按下,GND会和引脚短路到一起,此时引脚呈现低电平,代表按键被按下
3.代码:
//按键初始化
void key_init()
{
//P1|=(0x0F<<4);
P1|=(0xF0<<0);
P3|=(1<<5);
}
//按键检测
int key_press(void)
{
//低电平表示按键被按下
int ret=0;
if((P1&(1<<4))==0)
{
ret=1;
}
else if((P1&(1<<5))==0)
{
ret=2;
}
else if((P1&(1<<6))==0)
{
ret=3;
}
else if((P1&(1<<7))==0)
{
ret=4;
}
else if((P3&(1<<5))==0)
{
ret=5;
}
return ret;
}
10.中断
1.中断:CPU在处理某个任务时,被外界更为紧急的事件打断,要求CPU优先去处理 这个更为紧急的事件;处理完紧急事件后,再回到之前被打断的地方继续向下执行
2.中断源:打断CPU执行当前的任务源头/事件
3.中断源分类:外部中断0、外部中断1、定时器0、定时器1、串口
4.外部中断:引脚电平变化所引发的中断
- INT0(外部中断0):P3_2引脚;
- INT1(外部中断1):P3_3引脚
5.中断优先级:CPU总是先处理优先级高的中断,处理完优先级高的中断之后再处理优先级低的中断(数字越小优先级越高)
6.中断嵌套:CPU处理一个中断时再去嵌套另一个中断任务(最多两层嵌套)
7.中断处理流程(中断源->CPU过程):
- 中断源发出中断请求;
- 检查CPU是否允许中断(总开关,能够响应外部中断)及该中断源是否被屏蔽(子开关,能够产生中断)
- 比较中断优先级
- 保护现场
- 执行中断服务函数(回调函数)
- 恢复现场
8.中断向量表:本质是一个数组,数组中存的是中断服务函数的入口地址
9.中断向量:中断向量表中的标号,通过标号可以访问到对应中断服务函数
10.外部中断0的配置流程
1)将外部中断0引脚拉高
2)设置外部中断0引脚中断触发方式:下降沿触发
TCON寄存器中bit0置1 TCON |=(1<<0);
3)将外部中断0中断打开(bit0)
允许CPU响应中断(bit7)
lE寄存器中的bit7和bit0置1
IE|=(1<<0);
IE|=(1<<7);
11.代码:
//外部中断0 服务函数
void int0_handler(void)interrupt 0
{
g_i++;
}
//外部中断0初始化
void int0_init(void)
{
//1.将外部中断1电平拉高
P3|=(1<<2);
//2.配置外部中断0引脚中断触发方式 下降沿触发(置1)
TCON|=(1<<0);
//3.允许外部中断0产生中断
IE|=(1<<0);
//4.允许CPU响应所有中断
IE|=(1<<7);
}
11.定时器模块
1.定时器:实现精准的定时,外设对时序要求比较高
2定时器分类:
Timer0(自增型定时器)
Timer1
3.定时器工作模式:
- 1)16位计数器:0-65535 ;TL0存放低位数据,TH0存放高位数据,都参与计数
- 2)8位自动重装计数器:0-255(UART);TH0不参与计数,存放初始值(重装值);TL0参与计数,当溢出时将TH0存放的初始值自动重装入(拷贝)TL0
3.定时器的工作原理:
unsigned short cnt = 0; // 16位计数器(0 ~ 65535)
1)赋初值:cnt = 64535
2) 打开计数器,开始计数
3) 按照固定的频率++
4.)计数器从初值加到65535 + 1 -> 溢出 -> CPU 定时器中断请求
从初值 + 溢出 -> 所经历的时间:1. 初值大小 2. 频率
4.定时器的配置流程:
1)配置定时器0工作模式:16位定时器
TMOD寄存器bit0置1
2)设置定时器0初值
TL0 =
TH0 =
3)打开定时器0,开始计数
TCON寄存器bit4置1
4)打开定时器0中断(IE寄存器bit1置1)
打开CPU总中断(IE寄存器bit7置1)
5.实例:实现1ms的精准定时 (计算其初值)
1)晶振频率:12MHZ 11.0592MHZ(本51单片机采用的12MHZ)
2)51单片机实际工作频率(12分频)、固定频率:12MHZ / 12 = 1MHZ
时间:1 / 1MHZ = 1us 1 / 0.9MHZ = 1.1us
3)1ms定时:1ms = 1000us
计数次数:1000us / 1us = 1000
4)定时器初值:65535 - 1000 = 64535
6.代码:
unsigned int g_t=0;
//定时器0中断服务函数
void timer0_handler(void) interrupt 1
{
//实例:实现1ms的精准定时
// 必须重置初始值
// 不重置初始值的话,中断触发后,计数器当前值溢出后会变为0 ,所以下一次计时的起点变了
TL0=64535;
TH0=(64535>>8);
g_t++;
if(g_t>=1000) //中断触发1000次,也就是1s之后翻转LED状态
{
led_nor();
g_t=0;
}
}
//定时器0初始化
void timer0_init(void)
{
//1.配置定时器0工作模式
TMOD&=~(0x0F<<0);
TMOD|=(1<<0);
//2.设置定时器初始值 高位截断
//1ms
// TL0=64535;
// TH0=(64535>>8);
//3. 打开定时器0开始计数
TCON|=(1<<4);
//4.打开定时器0的中断
IE|=(1<<1);
//5.打开CPU的中断
IE|=(1<<7);
}
5.PWM:脉冲宽度调制,能够让引脚产生一个方波,能够让引脚周期性产生电平变化
PWM周期:一个方波所经历的周期(上升沿/下降沿到下一个上升沿/下降沿所经历的时间)
PWM占空比:在一个周期内高电平所占的比例(LCD屏亮度的调节、led灯亮度调节、蜂鸣器)
12.蜂鸣器模块![]()
1.分类:
- 有源蜂鸣器:内部存在震荡源,通电后可以发出持续固定频率的声音
- 无源蜂鸣器:不存在震荡源,需要给定对应引脚一个高低电平产生震荡(输出指定频率音调)(本单片机用的无源蜂鸣器)
2.实例:200HZ 占空比:50%
求初值的过程:
频率:200HZ400HZ 600HZ 800HZ 1000HZ
时间:1 / 200HZ = 0.005s
定时时间:0.005s / 2 = 0.0025s
晶振频率:12MHZ * 10^6 = 12000000HZ
分频:12000000 / 12 = 1000000HZ
时间:1 / 1000000HZ = 0.000001s
计数次数:0.0025s / 0.000001s = 2500
初值:65535 - 2500 = 63035
代码:
//定时器0中断服务函数
void timer0_handler(void) interrupt 1
{
//蜂鸣器200hz
TH0=63035>>8;
TL0=63035;
P2^=(1<<1);//P2.1是蜂鸣器的引脚高电平蜂鸣器鸣叫
}
//定时器0初始化
void timer0_init(void)
{
//1.配置定时器0工作模式
TMOD&=~(0x0F<<0);
TMOD|=(1<<0);
//2.设置定时器初始值 高位截断
//蜂鸣器
TH0=g_t>>8;
TL0=g_t;
//3. 打开定时器0开始计数
TCON|=(1<<4);
//4.打开定时器0的中断
IE|=(1<<1);
//5.打开CPU的中断
IE|=(1<<7);
}
