一、裸机
裸机是一个在计算机硬件与软件开发领域高频出现的概念,核心定义是 “未安装操作系统(OS),仅包含硬件本身(或仅运行最底层硬件驱动 / 控制程序)的设备”。
在电脑中,裸机会映射代码到cpu(中央处理元件)上,cpu会处理裸机的代码;mpu(微处理元件)与mcu(微控制元件)是cpu上的硬件辅助模块,与cpu相辅相成。
在 AT89C52(经典 8052 架构单片机)上的裸机程序,其核心特点是不依赖操作系统,直接通过操作硬件寄存器(如 I/O 口、定时器、中断控制器等)实现功能,程序逻辑以 “初始化 + 主循环 + 中断服务” 的形式运行。
二、AT89C52
AT89C52 是 Atmel 公司(现被 Microchip 收购)推出的8 位增强型单片机,属于经典的 MCS-51 系列(8051 架构),因成本低、编程简单、兼容性强,广泛用于入门级嵌入式开发和小型电子系统(如智能玩具、小家电控制、传感器数据采集等)。
原理图
实物图
AT89C52的引脚是从左上延伸向下,从从下延伸向上;网络端口从右上向下,跳到左上向下。
AT89C52特点
1. 存储系统:程序与数据分离
- 程序存储器(Flash):8KB 容量可存储用户程序(如控制逻辑、中断服务函数等),支持在系统编程(ISP)或通过编程器烧录,无需紫外线擦除(优于早期 EPROM 芯片)。
- 数据存储器(RAM):256 字节内部 RAM 中,低 128 字节(00H~7FH)为通用 RAM(可直接访问),高 128 字节(80H~FFH)与特殊功能寄存器(SFR)地址重叠,需通过间接寻址访问(用于复杂变量存储)。
2. 外设资源:满足基础控制需求
I/O 端口(P0~P3):
- P0 口:8 位漏极开路输出,作为通用 I/O 时需外接上拉电阻;访问外部存储器时复用为低 8 位地址 / 数据总线。
- P1~P3 口:内部带上拉电阻的准双向口,无需外接上拉;P3 口引脚可复用为外设功能(如 P3.0/RxD、P3.1/TxD 为串行口,P3.2/INT0、P3.3/INT1 为外部中断输入等)。
定时器 / 计数器 T2:相比 AT89C51 新增的 16 位定时器,支持三种工作模式(自动重装载、捕获、波特率发生器),适合需要精确定时或高频计数的场景(如脉冲测量、高频信号采样)。
中断系统:6 个中断源可独立使能 / 禁止,通过 IP 寄存器配置高 / 低优先级,确保紧急事件(如外部触发信号)优先响应(例如:按键中断优先于 LED 闪烁定时器中断)。
3. 兼容性与开发门槛
- 指令兼容:完全兼容 MCS-51 指令集,基于 AT89C51 开发的程序可直接移植到 AT89C52(仅需注意 RAM 容量差异)。
- 开发简单:支持 C 语言或汇编语言编程,常用编译器(如 Keil C51)可直接生成 hex 文件,通过编程器烧录到芯片;入门成本低,适合嵌入式新手学习。
三、AT89C52下的裸机程序
1.跑马灯
#include<reg52.h>
#include"led.h"
#include"delay.h"void led_all_on(void)
{P2 = 0;
}void led_all_off(void)
{P2 = 0xFF;
}void led_on(unsigned char n)
{P2 = ~n;
}void paomadeng()
{led_all_off();while(1)//跑马灯{int i = 0;for(i; i < 8; ++i){//P2 = ~(1 << i);led_on((1 << i));delay(9000); }for(i = 6; i> 0; --i){//P2 = ~(1 << i);led_on((1 << i));delay(9000);}}
}
在这个程序中使用到了P2寄存器(寄存器:能够操作硬件的,具有固定地址的内存空间),将电平转为低实现二极管的导通;
使用两次for循环在0~9之间跳变,实现跑马灯;使用delay(),为了更好观察;在循环中,使用位运算对led实现显示,先全部置1,在使用位运算对1动态左移的结构取反。
网络编号P20—P27对应D1—D7。
2.数码管
#include<reg52.h>
#include "delay.h"
#include "digiter.h"void bit_select(int n){P1 &= ~(0x0F << 0);P1 |= (1 << n); }void segment_select(int i){unsigned char t[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};P0 = t[i];delay(300);//保证二极管导通P0 = 0;delay(1000); //消影}void show_number(int n){ int t = 0;if(n > 9999){return ;}else if(n == 0){bit_select(0);segment_select(0);}while(n){bit_select(t++);segment_select(n % 10);n /= 10;}}
上述代码中实现数码的动态选择发亮,其中P1寄存器,选择要亮的数码管,P0寄存器选择要来亮的具体结,如图:
将要亮的数字对应的部分置0或者1,保持高位在前、低位在后的规则,dp是最高位,转换为十六进制;
在主函数中,可调用show—number函数,传参任意数,若为固定数则显示,也可以定义变量为0,在循环中传参变量自增,设定延迟时间,实现数字的自增(计数器)。