51单片机最快能生成多高频率的方波?

前言

在嵌入式系统开发中,51 单片机作为一种非常非常非常经典,贯穿上下几十年的微控制器,被广泛应用于各种电子项目中。其中,生成特定频率的方波信号是一项常见的需求。

那么,51 单片机究竟能以多快的速度生成方波呢?这不仅涉及到硬件的性能极限,也与软件编程的技巧密切相关。

在实际应用中,我们可能需要根据不同的场景来生成不同频率的方波,例如用于驱动电机、产生时钟信号或者进行通信等。而了解 51 单片机生成方波的最高频率,是一个有趣又有实用性的探索目标

所以,最快能实现多快?

测试平台

开发工具是keil 5

51单片机是STC89C52RC(16Mhz晶振)

最新手的方式

其实硬件上最简单就是换晶振,如果你换到一个

这个代码就是最简单的,在c语言中实现一个方波输出,只要快速切换电平就可以实现,

cpp 复制代码
#include <reg52.h>
#include <stdio.h>

sbit LCD_RS = P1^3;
void delay(unsigned int i)
{
    while (i--);
}

void main()
{
    // 设置 P1.3 为输出模式
 

    while (1)
    {
        // 点亮 LED(P1.3 输出低电平)
        LCD_RS = 0;
        delay(1);
        // 熄灭 LED(P1.3 输出高电平)
        LCD_RS = 1;
        delay(1);
    }
}

在烧录上面,我们

此时生成的频率为1.425Khz,好像还行,但是不够快

那么我们修改一下烧写,改成双倍速,结果就是没有什么差别,看来烧写并不影响

所以,还是要改程序,我们先试试增加头文件#include "intrins.h"然后把while改成_nop_();

cpp 复制代码
#include <reg52.h>
#include <stdio.h>
#include "intrins.h"

sbit LCD_RS = P1^3;
void delay(unsigned int i)
{
    _nop_();
}

void main()
{
    // 设置 P1.0 为输出模式
 

    while (1)
    {
        // 点亮 LED(P1.0 输出低电平)
        LCD_RS = 0;
        delay(1);
        // 熄灭 LED(P1.0 输出高电平)
        LCD_RS = 1;
        delay(1);
    }
}

这下的波形还是方波,同时,变成了111.111kHz ,非常的快速了,四舍五入有0.2Mhz

但是,有没有可能更快一点?

中等水平的方式

使用定时器,可以有更快的中断方式来实现,理论来说会比使用nop函数更快

这里设置的是 8 位自动重装模式,Timer0 的计数从 TL0TH0,当 Timer0 计数器达到最大值(0xFF)并溢出时,TL0 会被重装载为 TH0 的值。Timer0 的计数范围是 8 位,即从 0 到 255,总共有 256 个计数值。

cpp 复制代码
#include <reg52.h>  // 包含 STC89C52RC 的头文件

void Timer0_Init(void) {
    TMOD &= 0xF0;  // 清除 Timer0 的模式设置位
    TMOD |= 0x02;  // 设置 Timer0 为 8 位自动重装模式

    TH0 = 0xFF;    // 设置 Timer0 的重装载初值(高字节)
    TL0 = 0xF0;    // 设置 Timer0 的初值(低字节)

    ET0 = 1;       // 使能 Timer0 中断
    TR0 = 1;       // 启动 Timer0
    EA = 1;        // 使能全局中断
}

void Timer0_ISR(void) interrupt 1 {
    // Timer0 中断服务程序
    P1 ^= 0x08;    // 反转 P1.3 引脚的电平(0x08 是二进制 00001000)
}

void main(void) {
    P1 = 0x00;  // 初始化 P1 端口

    Timer0_Init();  // 初始化 Timer0

    while (1) {
        // 主循环可以为空,所有的工作都由 Timer0 中断处理
    }
}

可以看到,**最终我们实现了133.333Khz,这个速度非常可以了,**TH0的数值可以直接控制频率

鲜有使用的方式

除了中断之外还有一种比较少用的方法,就是直接使用汇编语言来操控单片机,这种方法可读性比较差但是确实又可以实现

这里我们直接用三部分实现

cpp 复制代码
ORG 0000H          ; 程序起始地址

; 主程序
MAIN_LOOP:
    ; 初始化 P1 端口
    MOV P1, #0FFH  ; 将所有 P1 端口设置为高电平
    CLR P1.3       ; 将 P1.3 设置为低电平

TOGGLE_LOOP:
    CPL P1.3       ; 反转 P1.3 引脚的电平
    ; 延时循环
    MOV R0, #1   ; 设置延时计数器初值
DELAY:
    NOP            ; 空操作指令,用于延时
    DJNZ R0, DELAY ; 延时循环
    SJMP TOGGLE_LOOP ; 无限循环,反复翻转 P1.3 引脚

END

SJMP是短跳转,在-127到+128字之间进行跳转

DJNZ,相当于 if(i--<=0) 这样的条件句式

在这种代码下,翻转频率直接达到了190.476khz,可以说是真的非常非常的快速了。

当然我们还可进一步的提升,我们直接去掉NOP符号,这下直接来到了222.222khz,真的是特别快速的一个频率

还能再快吗?可以,只要继续缩短就能实现

cpp 复制代码
ORG 0000H          ; 程序起始地址

; 主程序
MAIN_LOOP:
    ; 初始化 P1 端口
    MOV P1, #0FFH  ; 将所有 P1 端口设置为高电平
    CLR P1.3       ; 将 P1.3 设置为低电平

TOGGLE_LOOP:
    CPL P1.3       ; 反转 P1.3 引脚的电平
    ; 延时循环
    SJMP TOGGLE_LOOP ; 无限循环,反复翻转 P1.3 引脚

END

直接来到了444.444Khz

总结

实现方法 方波频率
快速切换电平,使用while (i--); 1.425Khz
快速切换电平,增加头文件#include "intrins.h"并把while改成_nop_(); 111.111kHz
使用定时器,8 位自动重装模式 133.333Khz
使用汇编语言,含NOP指令 190.476khz
使用汇编语言,去掉NOP指令 222.222khz
相关推荐
良许Linux36 分钟前
32岁入行STM32迟吗?
stm32·单片机·嵌入式硬件
m0_466607701 小时前
【STM32CubeMX】ST官网MCU固件库下载及安装
stm32·单片机·嵌入式硬件
Wallace Zhang5 小时前
STM32F103_Bootloader程序开发11 - 实现 App 安全跳转至 Bootloader
stm32·嵌入式硬件·安全
GodKK老神灭5 小时前
STM32 CCR寄存器
stm32·单片机·嵌入式硬件
杰克逊的日记9 天前
MCU编程
单片机·嵌入式硬件
Python小老六9 天前
单片机测ntc热敏电阻的几种方法(软件)
数据库·单片机·嵌入式硬件
HX科技10 天前
STM32给FPGA的外挂FLASH进行升级
stm32·嵌入式硬件·fpga开发·flash·fpga升级
Suagrhaha10 天前
驱动入门的进一步深入
linux·嵌入式硬件·驱动
国科安芯10 天前
基于ASP4644多通道降压技术在电力监测系统中集成应用与发展前景
嵌入式硬件·硬件架构·硬件工程
Li Zi10 天前
STM32 ADC(DMA)双缓冲采集+串口USART(DMA)直接传输12位原始数据到上位机显示并保存WAV格式音频文件 收藏住绝对实用!!!
经验分享·stm32·单片机·嵌入式硬件