51单片机---硬件学习(跑马灯、数码管、外部中断、按键、蜂鸣器)
裸机:编写的代码直接操作硬件。
一、基本概念
1、CPU,MPU,MCU,GPU,SOC的定义
1)CPU(中央处理器)
计算机的核心运算与控制单元,负责执行系统指令、处理数据,是通用计算的 “大脑”。
2)MPU(微处理器)
集成了 CPU 核心及少量外围电路的微处理器,需搭配外部存储、外设才能工作,常用于早期计算机或简单控制场景。
3)MCU(微控制器)
将 CPU 核心、存储器、I/O 接口等集成在单芯片上的 “微控制器”,可独立完成控制任务,广泛用于家电、物联网等嵌入式设备。
4)GPU(图像处理器)
专门处理图形渲染和并行计算的处理器,擅长海量数据的并行运算,也用于 AI 训练、科学计算等场景。
5)SOC(高性能集成芯片)
将 CPU、GPU、存储器、外设接口及专用功能模块(如 AI 加速单元)等高度集成在单芯片上的 “系统级芯片”,可实现完整电子系统功能。
2、外设寄存器
外设寄存器是嵌入在芯片外设(如GPIO、UART、定时器等)中的特殊存储单元,用于配置外设功能、读取状态或发送/接收数据。
每个寄存器对应特定功能(如配置引脚方向、设置波特率),通过读写寄存器的值可控制外设工作。
寄存器有固定的地址,CPU通过访问这些地址来操作外设(例如向GPIO的控制寄存器写入值,可设置引脚为输入/输出)。
3、LED实验中常用的寄存器(以8051或STM32为例)
LED实验的核心是控制GPIO引脚输出高低电平,常用寄存器包括:
方向寄存器(如8051的P1口寄存器、STM32的GPIOx_MODER):
配置引脚为输入或输出(例如设置为输出模式才能控制LED亮灭)。
数据寄存器(如8051的P1口数据寄存器、STM32的GPIOx_ODR):
向寄存器写入0或1,控制引脚输出低电平(LED导通)或高电平(LED截止)。
(部分芯片)上拉/下拉寄存器:若LED通过引脚高电平点亮,可能需要配置上拉电阻确保电平稳定。
4、GPIO
GPIO(General Purpose Input/Output,通用输入输出)
GPIO是芯片上的通用引脚,可通过软件配置为输入或输出,实现与外部设备的交互:
输出模式:可输出高低电平,用于控制LED、继电器、电机等。
输入模式:可读取外部信号(如按钮状态、传感器数据)。
灵活性高,是嵌入式开发中最基础、最常用的外设,几乎所有MCU/MPU都包含GPIO模块。
例如:LED实验中,GPIO被配置为输出模式,通过输出高低电平控制LED的亮灭。
5、中断与中断源
1)中断(Interrupt)
当中央处理机CPU正在处理某件事的时候外界发生了紧急事件请求,要求CPU暂停当前的工作,转而去处理这个紧急事件,处理完以后,再回到原来被中断的地方,继续原来的工作。
2)中断源(Interrupt Source)
指能主动向CPU发送“中断请求”,暂停当前任务、迫使其优先处理紧急事件的硬件或软件实体。
6、中断处理流程
1)中断源发送中断请求
2)内核检查是否响应中断,以及该中断是否被屏蔽
3)内核会检查中断的中断优先级
4)保护现场
5)执行中断服务函数
6)恢复现场
7、中断嵌套
中断嵌套是高优先级中断打断低优先级中断处理过程的机制,核心是“优先处理更紧急的事件”。51单片机有2个优先级(高优先级、低优先级),可通过IP寄存器设置(如PT0=1设T0为高优先级);
低优先级中断执行时,若有高优先级中断请求,CPU会暂停低优先级中断,先处理高优先级中断;同优先级中断不会嵌套(如两个低优先级中断,先响应的先处理,后请求的需等前一个处理完);高优先级中断执行时,其他中断(无论优先级)都无法打断它。
8、中断向量表
中断向量表是存储“中断源”与“对应中断服务程序入口地址”的表格,本质是CPU的“中断导航图”——当某个中断源触发时,CPU通过查表就能快速找到该中断该去哪里执行处理逻辑。
9、51单片机的定时器工作原理
可编程的 16 位加 1 计数器,先通过程序向定时器寄存器(THx 高 8 位、TLx 低 8 位)写入初始计数值,随后定时器在系统时钟(经 12 分频后)或外部引脚输入脉冲的驱动下开始累加计数,当计数值累加到最大值(如 16 位时为 0xFFFF)并产生溢出时,会自动触发定时器中断请求(若中断使能),同时可选择自动重装初始值(仅模式 2)或需程序重新赋值,以此实现定时(基于内部时钟)或计数(基于外部脉冲)功能。
10、PWM及其重要参数
1)PWM(脉冲宽度调制,Pulse Width Modulation)
是一种利用数字信号(高低低电平脉冲)模拟模拟信号的技术,核心原理是通过周期性地输出高低电平脉冲,通过改变高(或低电平)在一个周期内的占比。
2)PWM的核心参数
占空比、周期与频率、分辨率、幅值。
二、功能实现(应用示例)
1、LED灯:全亮(led_all_on)、全灭(led_all_off)、指定灯亮(led_on)
#include "led.h"
#include <reg52.h>void led_all_on(void)
{P2 = 0;
}void led_all_off(void)
{P2 = 0xFF;
}void led_on(unsigned char n)
{P2 = n;
}
2、数码管显示屏:位选(bit_select)、0~9显示(segment——select)、9999以内数字显示(show_number)
#include "delay.h"
#include "digiter.h"
#include <reg52.h>//位选
void bit_select(int n)
{P1 &= ~(0x0F << 0); P1 |= (1 << n);
}void segment_select(int n) //0~9
{ unsigned char t[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};P0 = t[n];delay(400);//保证二极管导通P0 = 0;//消去残影delay(100);
}void show_number(int n)
{int t = 0;if(t > 9999){return ;}else if(n == 0){bit_select(0);segment_select(0);}while(n){bit_select(t++);segment_select(n % 10);n /= 10;}
}
3、延迟函数:delay
#include "delay.h"
#include <reg52.h>void delay(unsigned int n) //0~65535
{while(n--);
}
4、来回显示跑马灯
#include <reg52.h>
#include "led.h"
#include "delay.h"int main(void)
{//跑马灯led_all_off();P2 = 0xFF;while(1){int i = 0;for(i = 0; i < 8; i++){led_on(1 << i);delay(9000);}for(i = 6; i >= 0; --i){led_on(1 << i);delay(9000);}}
}
5、数码管显示:重复显示0~9
#include <reg52.h>
#include "led.h"
#include "digiter.h"
#include "delay.h"int main(void)
{int i = 0;bit_select(2);while(1){ segment_select(i++);if(i > 9){i = 0;}delay(20000); }
}
6、按键:初始化按键(init_key)、按键选择(key_pressed)
#include <reg52.h>
#include "digiter.h"
#include "key.h"
#include "delay.h"void init_key(void)
{P1 |= (0x0F << 4);//0000 1111 P3 |= (0x0F << 4);
}int key_pressed(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;
}int main(void)
{init_key();P2 = 0xFF;while(1){int key;key = key_pressed();if(key != 0){P2 = 0;//亮灯}delay(0x9000);}return 0;
}
7、外部中断:外部中断0---加、外部中断0---减
#include <reg52.h>
#include "delay.h"
#include "digiter.h"void init_eint0(void)
{IE |= (1 << 7) | (1 << 0) | (1 << 2);TCON |= (1 << 2);TCON &= ~(1 << 0);//enit0 lowP3 |= (1 << 2) | (1 << 3);
}int num = 0;void enit0_handle(void) interrupt 0
{++num;if(num > 9999){num = 0;}
}void enit1_handle(void) interrupt 2
{--num;if(num < 0){num = 9999;}
}int main(void)
{init_eint0();P2 = 0xFF;while(1){show_number(num);}
}
8、定时器:实现类似电子琴的效果
#include <reg52.h>
#include "key.h"#define Hz200 63035
#define Hz400 64285
#define Hz600 64702
#define Hz800 64910
#define Hz1000 65035unsigned short n = Hz200;void init_timer0(void)
{TMOD &= ~(3 << 2);TMOD &= ~(3 << 0);TMOD |= (1 << 0);TH0 = n >> 8;TL0 = n;IE |= (1 << 7) | (1 << 1);
}void timer0_handler(void) interrupt 1
{P2 ^= (1 << 1);TH0 = n >> 8;TL0 = n;
}int main(void)
{init_timer0();init_key();while(1){int key;key = key_pressed();if(key == 1){n = Hz200;TCON |= (1 << 4);}else if(key == 2){n = Hz400;TCON |= (1 << 4);}else if(key == 3){n = Hz600;TCON |= (1 << 4);}else if(key == 4){n = Hz800;TCON |= (1 << 4);}else if(key == 5){n = Hz1000;TCON |= (1 << 4);}else if(key == 0){TCON &= ~(1 << 4);}}return 0;
}
【END】