C51 与 STM32 编程对比:从数据类型、关键字到程序结构
最近准备面试一家公司,公司主要用8位机去做的,所以现在我来先了解一下51,我学习单片机是直接从STM32开始学的,最真实的感受就是太吃力了。
一、硬件基础差异
|
维度 |
C51(8051 系列) |
STM32(ARM Cortex-M) |
对编程的影响 |
|---|---|---|---|
| 位宽/架构 |
8 位,经典哈佛结构(程序/数据存储器分离) |
32 位,改进哈佛 + 总线矩阵 |
C51 运算慢、内存小,必须手动管理存储区;STM32 接近“电脑式”编程 |
| 主频/性能 |
通常 12~24MHz,指令多周期 |
几十~几百 MHz,单周期指令 |
C51 适合简单控制,STM32 可跑复杂算法/RTOS |
| 内存 |
RAM 几十~几百字节,Flash 几 KB |
RAM/Flash 几十 KB~几 MB |
C51 变量必须指定存储类型,否则溢出 |
| 外设 |
基础(GPIO、定时器、串口) |
丰富(ADC/DAC、DMA、USB、CAN 等) |
C51 直接操作寄存器;STM32 有 HAL 抽象层 |
二、开发环境与编译器差异
- C51
:只能用 Keil C51(uVision 老版本),严格的“方言 C”。不支持标准 C 的很多特性,必须用扩展关键字。
- STM32
:Keil MDK / STM32CubeIDE / IAR / GCC 都行,使用标准 C/C++,配合 STM32CubeMX + HAL/LL 库,代码更规范、可移植性强。
C51 存储类型修饰符:
-
data:片内直接寻址 RAM(最快,128 字节)
-
idata:片内间接寻址 RAM(全 256 字节)
-
xdata:片外数据存储器(最常用外部扩展)
-
code:程序存储器(ROM/Flash,只读,常用于常量表)
-
bdata:可位寻址区(20H~2FH)
unsigned char data flag; // 片内快速变量unsigned int xdata buffer[100]; // 外部 RAM 数组unsigned char code table[] = {1,2,3}; // 放在 Flash
四、特殊关键字对比
C51 有 19 个扩展关键字,STM32 几乎全用标准 C。
|
关键字 |
C51 作用 |
STM32 对应方式 |
示例(C51) |
|---|---|---|---|
| sfr |
定义特殊功能寄存器(SFR) |
直接用寄存器结构体或 HAL |
sfr P1 = 0x90; |
| sbit |
定义 SFR 的某一位(最常用!) |
HAL_GPIO 或 BSRR 寄存器 |
sbit LED = P1^7; |
| bit |
定义普通 1 位变量 |
bool / uint8_t |
bit flag; |
| interrupt |
定义中断服务函数 |
NVIC + 函数名固定 |
void isr() interrupt 1 |
| using |
指定寄存器组(0~3) |
无 |
using 1 |
| reentrant |
可重入函数(支持递归/中断调用) |
标准 C 支持 |
void func() reentrant |
| at |
指定变量绝对地址 |
attribute
((at())) 或 linker |
unsigned char xdata var _at_ 0x8000; |
| small/large/compact |
内存模型(影响指针大小和代码效率) |
无 |
small(默认) |
// C51 点灯(超级简洁)sbit LED = P1^7;LED = 0; // 亮灯(低电平有效)// STM32 点灯(HAL 风格)HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET);
STM32 HAL → C51 完整重写
1. 点灯实验
#include <reg52.h>sbit LED = P1^0; // STM32: LED_Pin = GPIO_PIN_0void main(void){LED = 1; // STM32: HAL_GPIO_WritePin(..., GPIO_PIN_SET);while(1){LED = 0; // 亮灯(低电平有效) // 简单延时(实际项目用定时器代替)unsigned int i = 50000;while(i--);LED = 1; // 灭灯i = 50000;while(i--);}}
2. 按键实验(检测按键)
#include <reg52.h>sbit LED = P1^0;sbit KEY = P3^7; // STM32: KEY_Pin = GPIO_PIN_7 (低电平按下)void Delay_ms(unsigned int ms) // 简单软件延时(面试可改成定时器){unsigned int i, j;for(i = ms; i > 0; i--)for(j = 120; j > 0; j--);}void main(void){LED = 1; // 初始灭灯while(1){if(KEY == 0) // STM32: if(HAL_GPIO_ReadPin(...) == GPIO_PIN_RESET){Delay_ms(20); // 消抖(STM32常用HAL_Delay)if(KEY == 0) // 再次确认{LED = ~LED; // 翻转LED(STM32: HAL_GPIO_TogglePin)while(KEY == 0); // 松手检测(防止连击)}}}}
3. 定时器实验
#include <reg52.h>sbit LED = P1^0; // STM32: LED_Pinunsigned char count = 0;// 软件计数(实现500ms)// ================== STM32 HAL_TIM 等价中断服务函数 ==================void timer0_isr() interrupt 1 // interrupt 1 = 定时器0{TH0 = 0x3C; // 重新装50ms初值(STM32: __HAL_TIM_SET_COUNTER)TL0 = 0xB0;count++;if(count >= 10) // 10次 × 50ms = 500ms{count = 0;LED = ~LED; // 翻转LED(STM32: HAL_GPIO_TogglePin)}}void main(void){// ================== STM32 MX_TIMx_Init 等价初始化 ==================TMOD = 0x01; // 定时器0,方式1TH0 = 0x3C; // 50ms初值TL0 = 0xB0;TR0 = 1; // 启动定时器(HAL_TIM_Base_Start)ET0 = 1; // 允许定时器0中断EA = 1; // 开总中断(__enable_irq())LED = 1; // 初始灭灯while(1){// 主循环可以空着,也可以放其他非阻塞任务(STM32 while(1)风格)}}
感觉要寄了,
更多推荐


所有评论(0)