STC89C52RC/LE52RC

news2025/5/25 14:18:56

STC89C52RC

  • 芯片手册
  • 原理图
    • 扩展版原理图
  • 功能示例
    • LED灯
      • ==LED灯的常亮效果==
      • ==LED灯的闪烁==
      • ==LED灯的跑马灯效果:从左到右,从右到左==
    • 数码管
      • 静态数码管
      • 数码管计数
        • App.c
        • App.h
        • Com.c
        • Com.h
        • Dir.c
        • Dir.h
        • Int.c
        • Int.h
        • Mid.c
        • Mid.h
  • 模板
        • mian.c
        • App.c
        • App.h
        • Com.c
        • Com.h
        • Dir.c
        • Dir.h
        • Int.c
        • Int.h
        • Mid.c
        • Mid.h

芯片手册

STC89C52

原理图

扩展版原理图

扩展版原理图

功能示例

LED灯

LED灯的常亮效果

# include <STC89C5xRC.H>
void main(){
		//将LED连接的P00端口设置为0
		P00 =0;
		while(1);
}

LED灯的闪烁

/*----------------------------------------------------------
 * 文件名:LED_FlowLight.c
 * 功能:STC89C52RC单片机控制的LED流水灯程序(单向左移循环)
 * 硬件连接:P0口接8个共阳LED,P4.6控制蜂鸣器
 * 作者:[您的名字]
 * 日期:[创建日期]
 *---------------------------------------------------------*/

#include <STC89C5xRC.H> // 包含STC89C52RC系列单片机寄存器定义头文件
#include <INTRINS.H>    // 包含内部函数库(提供_nop_()空指令)

/* 类型重定义(增强可读性)*/
typedef unsigned char u8;  // 定义无符号8位数据类型(范围0~255)
typedef unsigned int u16;  // 定义无符号16位数据类型(范围0~65535)

/* 函数声明 */
void Delayms(u16 count);   // 毫秒级延时函数声明

/*----------------------------------------------------------
 * 主函数
 *---------------------------------------------------------*/
void main()
{
    // 变量初始化
    u8 temp = 0x01;  // 初始化LED位置(二进制00000001,对应最右侧LED)
                     // 注:实际是P0.0对应第一个LED,P0.7对应第八个LED
    
    P46 = 0;         // 关闭蜂鸣器(硬件设计缺陷,P4.6低电平关闭蜂鸣器)
                     // 如果不设置,上电时可能产生噪音
    
    while (1)        // 主循环(单片机程序必须包含无限循环)
    {
        /* LED显示控制 */
        P0 = ~temp;  // 输出到P0口控制LED:
                     // - 取反操作是因为采用共阳接法(端口输出0时LED亮)
                     // - 例如temp=0x01(00000001),取反后=0xFE(11111110),
                     //   即P0.0输出0,对应LED点亮
        
        /* 更新LED位置 */
        temp <<= 1;  // 左移一位,实现LED流水效果
                     // 例如:0x01→0x02→0x04→...→0x80
        
        /* 循环检测 */
        if (temp == 0) // 当左移超出8位时(0x80<<1会变成0x00)
        {
            temp = 0x01; // 重新从最右侧开始
        }
        
        /* 延时控制流水速度 */
        Delayms(100); // 延时100ms(控制LED移动速度)
    }
}

/*----------------------------------------------------------
 * 函数名称:Delayms
 * 功能:实现毫秒级延时
 * 参数:count - 需要延时的毫秒数
 * 说明:针对12MHz晶振校准,其他频率需调整参数
 *---------------------------------------------------------*/
void Delayms(u16 count)
{
    /* 变量定义(使用data关键字将变量存储在内部RAM,提高访问速度)*/
    u8 data i, j;  
    
    while (count--)  // 外层循环(控制总延时毫秒数)
    {
        _nop_();    // 空指令(消耗1个机器周期,12MHz下=1us)
                    // 用于微调延时精度
        
        /* 双重循环实现精确延时 */
        i = 2;
        j = 199;
        do
        {
            while (--j); // 内层循环1(约199×3个机器周期)
        } while (--i);   // 内层循环2(外层循环2次)
        
        /* 
         * 延时计算(12MHz时钟):
         * - 1机器周期=1us
         * - 内层循环:199×3 = 597us
         * - 外层循环:2×597 = 1194us ≈ 1ms
         * - 总延时:count × 1ms
         */
    }
}

LED灯的跑马灯效果:从左到右,从右到左

#include <STC89C5xRC.H>  // 包含STC89C52RC系列单片机头文件
#include <INTRINS.H>     // 包含 intrinsics 函数(如_nop_)

typedef unsigned char u8;   // 定义无符号8位数据类型(0~255)
typedef unsigned int u16;   // 定义无符号16位数据类型(0~65535)

// 函数声明
void Delayms(u16 count);    // 毫秒级延时函数声明

void main()
{
    // 变量初始化
    u8 temp = 0x01;     // 初始灯位(00000001,最右侧LED亮)
    bit is_left = 1;    // 方向标志(1=左移,0=右移)

    while (1)           // 主循环
    {
        P0 = ~temp;     // 输出到P0口(取反因为LED共阳接法)
        
        // 根据移动方向更新灯位
        if (is_left) {
            temp <<= 1; // 左移一位(LED向左移动)
        } else {
            temp >>= 1; // 右移一位(LED向右移动)
        }

        // 检测边界条件并改变方向
        if (temp == 0x80) { // 当移动到最左端(10000000)
            is_left = 0;     // 改为右移方向
        }
        if (temp == 0x01) {  // 当移动到最右端(00000001)
            is_left = 1;      // 改为左移方向
        }

        Delayms(100);    // 延时100ms控制移动速度
    }
}

/**
 * @brief 毫秒级延时函数
 * @param count 延时毫秒数
 * @note 针对12MHz晶振校准,其他频率需要调整参数
 */
void Delayms(u16 count)
{
    u8 data i, j;       // 使用data关键字将变量存储在内部RAM
    while (count--)     // 外层循环(毫秒级)
    {
        _nop_();       // 空指令(4个时钟周期)
        i = 2;
        j = 199;
        do              // 内层循环(微秒级)
        {
            while (--j); // 约100us
        } while (--i);   // 组合成约1ms延时
    }
}

数码管

静态数码管

#include <STC89C5xRC.H>  // 包含STC89C52RC系列单片机头文件
#include <INTRINS.H>     // 包含 intrinsics 函数(如_nop_)

typedef unsigned char u8;   // 定义无符号8位数据类型
typedef unsigned int u16;   // 定义无符号16位数据类型
typedef unsigned long u32;  // 定义无符号32位数据类型

// 函数声明
void DigitalTube_setBuffer(u32 number);  // 设置数码管显示缓冲区
void DigitalTube_Single(u8 pos, u8 number); // 控制单个数码管显示
void DigitalTube_Refresh();              // 刷新整个数码管显示
static void Delayms(u16 count);         // 毫秒级延时函数(static限制作用域)

// 数码管段选码(共阴数码管0-9,对应a~dp段)
// 编码格式:gfedcba(P0.0~P0.6),最高位P0.7为小数点
const u8 number_codes[10] = {
    0x3F, // 0 - 00111111
    0x06, // 1 - 00000110
    0x5B, // 2 - 01011011
    0x4F, // 3 - 01001111
    0x66, // 4 - 01100110
    0x6D, // 5 - 01101101
    0x7D, // 6 - 01111101
    0x07, // 7 - 00000111
    0x7F, // 8 - 01111111
    0x6F  // 9 - 01101111
};

u8 digital_buffer[8]; // 数码管显示缓冲区(存储8位数码管的段选值)

void main()
{
    // 初始化IO口
    // P0 = 0x00;  // 段选初始化为全灭(注释掉,实际在刷新函数中处理)
    // P1 = 0xC7;  // 位选初始化为全灭(P1.3-P1.5控制位选,11000111)
    P46 = 0;    // 可能的总使能信号(低电平有效)
    P36 = 0;    // 数码管使能信号(低电平有效)
    P34 = 1;    // 关闭流水灯(高电平关闭)
    
    DigitalTube_setBuffer(99998888); // 设置初始显示值为250
    
    while (1)
    {
        DigitalTube_Refresh(); // 持续刷新数码管显示
    }
}

/**
 * @brief 设置数码管显示缓冲区内容
 * @param number 要显示的数字(最大支持8位数)
 * @note 数字将右对齐显示,不显示前导零
 */
void DigitalTube_setBuffer(u32 number)
{
    u8 i;
    
    // 1. 清空缓冲区(全部显示空白)
    for (i = 0; i < 8; i++) {
        digital_buffer[i] = 0; // 0表示不显示任何段
    }
    
    // 2. 从最右侧开始填充数字(右对齐)
    for (i = 7; i >= 0; i--) {
        digital_buffer[i] = number_codes[number % 10]; // 获取当前位的段码
        number /= 10;  // 移除已处理的最低位
        
        if (number == 0) break; // 数字已处理完毕则退出
    }
}

/**
 * @brief 控制单个数码管显示
 * @param pos 数码管位置(0-7对应位选)
 * @param number 要显示的段码值
 * @note 使用P1.3-P1.5控制3-8译码器选择位选
 */
void DigitalTube_Single(u8 pos, u8 number)
{
    // 1. 位选控制(通过P1.3-P1.5)
    pos <<= 3;       // 左移3位,将0-7映射到P1.3-P1.5
    P1 &= 0xC7;      // 11000111 - 清除位选位(P1.3-P1.5)
    P1 |= pos;       // 设置新的位选
    
    // 2. 段选输出
    P0 = number;     // 输出段码值到P0口
}

/**
 * @brief 刷新整个数码管显示(动态扫描)
 * @note 采用循环扫描方式,每位显示1ms
 */
void DigitalTube_Refresh()
{
    u8 i = 0;
    while (i <= 7)  // 扫描0-7共8位数码管
    {
        DigitalTube_Single(i, digital_buffer[i]); // 显示当前位
        Delayms(1);  // 保持显示1ms
        i++;
    }
}

/**
 * @brief 毫秒级延时函数
 * @param count 延时毫秒数
 * @note 使用static限制只在本文件使用,防止命名冲突
 */
static void Delayms(u16 count)
{
    u8 data i, j;
    while (count--)
    {
        _nop_();  // 空指令,用于精确延时
        i = 2;
        j = 199;
        do
        {
            while (--j);  // 内层循环延时
        } while (--i);    // 外层循环延时
    }
}

数码管计数

mian.c

#include ".\Com\Com_Util.h"
#include ".\Int\Int_DigitalTube.h"

// 主函数
void main()
{
    u8 num = 100;
    u8 count = 0;
    u8 i=0;
    P46 = 0; // 关闭蜂鸣器

    // 初始化数码管
    Int_DigitalTube_Init();
    //设置要显示的数字
    Int_DigitalTube_setBuffer(num);
    //死循环
    while (1)
    {
        Int_DigitalTube_setBuffer(num);
        while (count <= 100)
        {
            Int_DigitalTube_Refresh();
            count++;
        }
        if (num > 0)
        {
            num--;
            count=0;
        }else if (num == 0)
        {
            while (1)
            {
                Int_DigitalTube_setBuffer(0);
            }
        }
    }
}

App.c
App.h
Com.c
#include "Com_Util.h"

// 延时函数,指定延时多少毫秒
void Delayms(u16 count)
{
    u8 data i, j;
    while (count)
    {
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j)
                ;
        } while (--i);
        count--;
    }
}
Com.h
#ifndef __COM_UTIL_H__
#define __COM_UTIL_H__

#include <STC89C5xRC.H>
#include <INTRINS.H>

// 类型别名
typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long u32;

/**
 * @brief 延时函数,指定延时多少毫秒
 *
 * @param count 指定多少毫秒
 */
void Delayms(u16 count);

#endif
Dir.c
Dir.h
Int.c
#include "Int_DigitalTube.h"

// 定义数组,保存每个数字的段选信息
static u8 s_number_codes[10] = {
    0x3F, // 0
    0x06, // 1
    0x5B, // 2
    0x4F, // 3
    0x66, // 4
    0x6D, // 5
    0x7D, // 6
    0x07, // 7
    0x7F, // 8
    0x6F  // 9
};

// 定义数组,8个元素,对应数码管8个位置; 每个元素存储数字的段选信息
static u8 s_digital_buffer[8];

/**
 * @brief 数码管初始化
 */
void Int_DigitalTube_Init()
{
    // 打开数码管开关
    P36 = 0;
    // 关闭流水灯
    P34 = 0;
}

/**
 * @brief 将指定的整数设置到数码管显示缓存中(s_digital_buffer数组)
 *
 * @param number
 */
void Int_DigitalTube_setBuffer(u32 number)
{
    u8 i;

    // 1. 清空之前的显示内容
    for (i = 0; i < 8; i++)
    {
        s_digital_buffer[i] = 0x00;
    }

    // 2. 依次取出number中每位上的数,将其段选信息存储数组;最低位存入最后一个元素
    for (i = 7;; i--)
    {
        // 取出当前位上的数,将其段选信息存入数组指定位置
        s_digital_buffer[i] = s_number_codes[number % 10];
        // 处理number,去掉最低位
        number /= 10;
        // 如果number变为0,说明数字已经取完,停止循环
        if (number == 0 || i == 0)
        {
            break;
        }
    }
}

/**
 * @brief 数码管指定位置指定数字
 *
 * @param pos     位置,使用数字0~7分别表示从左边数第1到到第8个
 * @param code    数字的段选信息
 */
void Int_DigitalTube_Single(u8 pos, u8 number_code)
{
    // 1. 位选 -------------------------------
    // 1.1 pos 左移3位,  与P15、P14、P13 对齐
    pos <<= 3;
    // 1.2 将P1的P15、P14、P13三位置0,其他位保持不变, P1 & 0b11000111
    P1 &= 0xC7;
    // 1.3 将pos上的三位有效数, 赋值到 P15、P14、P13 位置上
    P1 |= pos;

    // 2. 段选 --------------------------------
    P0 = number_code;
}

/**
 * @brief 刷新数码管
 *
 */
void Int_DigitalTube_Refresh()
{
    // 循环0到7
    u8 i;
    for (i = 0; i <= 7; i++)
    {
        Int_DigitalTube_Single(i, s_digital_buffer[i]);
        Delayms(1);
    }
}

Int.h
#ifndef __INT_DIGITALTUBE_H__
#define __INT_DIGITALTUBE_H__

#include "..\Com\Com_Util.h"

/**
 * @brief 数码管初始化
 */
void Int_DigitalTube_Init();

/**
 * @brief 将指定的整数设置到数码管显示缓存中(digital_buffer数组)
 * 
 * @param number 
 */
void Int_DigitalTube_setBuffer(u32 number);

/**
 * @brief 数码管指定位置指定数字
 *
 * @param pos     位置,使用数字0~7分别表示从左边数第1到到第8个
 * @param code    数字的段选信息
 */
void Int_DigitalTube_Single(u8 pos, u8 number_code);

/**
 * @brief 刷新数码管
 *
 */
void Int_DigitalTube_Refresh();

#endif
Mid.c
Mid.h

模板

mian.c
App.c
App.h
Com.c
Com.h
Dir.c
Dir.h
Int.c
Int.h
Mid.c
Mid.h

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2385394.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

✨ PLSQL卡顿优化

✨ PLSQL卡顿优化 1.&#x1f4c2; 打开首选项2.&#x1f527; Oracle连接配置3.⛔ 关闭更新和新闻 1.&#x1f4c2; 打开首选项 2.&#x1f527; Oracle连接配置 3.⛔ 关闭更新和新闻

python+vlisp实现对多段线范围内土方体积的计算

#在工程中&#xff0c;经常用到计算土方回填、土方开挖的体积。就是在一个范围内&#xff0c;计算土被挖走&#xff0c;或者填多少&#xff0c;这个需要测量挖填前后这个范围内的高程点。为此&#xff0c;我开发一个app&#xff0c;可以直接在autocad上提取高程点&#xff0c;然…

APM32小系统键盘PCB原理图设计详解

APM32小系统键盘PCB原理图设计详解 一、APM32小系统简介 APM32微控制器是国内半导体厂商推出的一款高性能ARM Cortex-M3内核微控制器&#xff0c;与STM32高度兼容&#xff0c;非常适合DIY爱好者用于自制键盘、开发板等电子项目。本文将详细讲解如何基于APM32 CBT6芯片设计一款…

对象存储(Minio)使用

目录 1.安装 MinIO&#xff08;Windows&#xff09; 2.启动minio服务&#xff1a; 3.界面访问 4.进入界面 5.前后端代码配置 1)minio前端配置 2&#xff09;minio后端配置 1.安装 MinIO&#xff08;Windows&#xff09; 官方下载地址&#xff1a;[Download High-Perform…

yolov11使用记录(训练自己的数据集)

官方&#xff1a;Ultralytics YOLO11 -Ultralytics YOLO 文档 1、安装 Anaconda Anaconda安装与使用_anaconda安装好了怎么用python-CSDN博客 2、 创建虚拟环境 安装好 Anaconda 后&#xff0c;打开 Anaconda 控制台 创建环境 conda create -n yolov11 python3.10 创建完后&…

知识宇宙:技术文档该如何写?

名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、技术文档的价值与挑战1. 为什么技术文档如此重要2. 技术文档面临的挑战 二、撰…

技嘉主板怎么开启vt虚拟化功能_技嘉主板开启vt虚拟化教程(附intel和amd开启方法)

最近使用技嘉主板的小伙伴们问我&#xff0c;技嘉主板怎么开启vt虚拟。大多数可以在Bios中开启vt虚拟化技术&#xff0c;当CPU支持VT-x虚拟化技术&#xff0c;有些电脑会自动开启VT-x虚拟化技术功能。而大部分的电脑则需要在Bios Setup界面中&#xff0c;手动进行设置&#xff…

Java 并发编程高级技巧:CyclicBarrier、CountDownLatch 和 Semaphore 的高级应用

Java 并发编程高级技巧&#xff1a;CyclicBarrier、CountDownLatch 和 Semaphore 的高级应用 一、引言 在 Java 并发编程中&#xff0c;CyclicBarrier、CountDownLatch 和 Semaphore 是三个常用且强大的并发工具类。它们在多线程场景下能够帮助我们实现复杂的线程协调与资源控…

PT5F2307触摸A/D型8-Bit MCU

1. 产品概述 ● PT5F2307是一款51内核的触控A/D型8位MCU&#xff0c;内置16K*8bit FLASH、内部256*8bit SRAM、外部512*8bit SRAM、触控检测、12位高精度ADC、RTC、PWM等功能&#xff0c;抗干扰能力强&#xff0c;适用于滑条遥控器、智能门锁、消费类电子产品等电子应用领域。 …

线性代数中的向量与矩阵:AI大模型的数学基石

&#x1f9d1; 博主简介&#xff1a;CSDN博客专家、CSDN平台优质创作者&#xff0c;高级开发工程师&#xff0c;数学专业&#xff0c;10年以上C/C, C#, Java等多种编程语言开发经验&#xff0c;拥有高级工程师证书&#xff1b;擅长C/C、C#等开发语言&#xff0c;熟悉Java常用开…

打卡第27天:函数的定义与参数

知识点回顾&#xff1a; 1.函数的定义 2.变量作用域&#xff1a;局部变量和全局变量 3.函数的参数类型&#xff1a;位置参数、默认参数、不定参数 4.传递参数的手段&#xff1a;关键词参数 5.传递参数的顺序&#xff1a;同时出现三种参数类型时 作业&#xff1a; 题目1&a…

python训练营day34

知识点回归&#xff1a; CPU性能的查看&#xff1a;看架构代际、核心数、线程数GPU性能的查看&#xff1a;看显存、看级别、看架构代际GPU训练的方法&#xff1a;数据和模型移动到GPU device上类的call方法&#xff1a;为什么定义前向传播时可以直接写作self.fc1(x) 作业 复习今…

人工智能在医疗影像诊断上的最新成果:更精准地识别疾病

摘要&#xff1a;本论文深入探讨人工智能在医疗影像诊断领域的最新突破&#xff0c;聚焦于其在精准识别疾病方面的显著成果。通过分析深度学习、多模态影像融合、三维重建与可视化以及智能辅助诊断系统等关键技术的应用&#xff0c;阐述人工智能如何提高医疗影像诊断的准确性和…

塔能节能平板灯:点亮苏州某零售工厂节能之路

在苏州某零售工厂的运营成本中&#xff0c;照明能耗占据着一定比例。为降低成本、提升能源利用效率&#xff0c;该工厂与塔能科技携手&#xff0c;引入塔能节能平板灯&#xff0c;开启了精准节能之旅&#xff0c;并取得了令人瞩目的成效。 一、工厂照明能耗困境 苏州该零售工厂…

3DMAX插件UV工具UV Tools命令参数详解

常规: 打开UV工具设置对话框。 右键点击: 隐藏/显示主界面。 添加 为选定对象添加展开修改器。 将从下拉菜单中选择映射通道。 Ctrl+点击: 克隆任何当前的修饰符。 右键点击: 找到第一个未展开的修改器。 地图频道 设置展开映射通道。 Ctrl+Click:添加选定的映射通道的展开…

Docker 与微服务架构:从单体应用到容器化微服务的迁移实践

随着软件系统规模和复杂性的日益增长,传统的单体应用(Monolithic Application)在开发效率、部署灵活性和可伸缩性方面逐渐暴露出局限性。微服务架构(Microservice Architecture)作为一种将大型应用拆分为一系列小型、独立、松耦合服务的模式,正成为现代企业构建弹性、敏捷…

《岁月深处的童真》

在那片广袤而质朴的黄土地上&#xff0c;时光仿佛放慢了脚步&#xff0c;悠悠地流淌着。画面的中央&#xff0c;是一个扎着双髻的小女孩&#xff0c;她静静地伫立着&#xff0c;宛如一朵绽放在岁月缝隙中的小花。 小女孩身着一件略显陈旧的中式上衣&#xff0c;布料的纹理间似乎…

文件夹图像批处理教程

前言 因为经常对图像要做数据清洗&#xff0c;又很费时间去重新写一个&#xff0c;我一直在想能不能写一个通用的脚本或者制作一个可视化的界面对文件夹图像做批量的修改图像大小、重命名、划分数据训练和验证集等等。这里我先介绍一下我因为写过的一些脚本&#xff0c;然后我…

RL电路的响应

学完RC电路的响应&#xff0c;又过了一段时间了&#xff0c;想必很多人都忘了RC电路响应的一些内容。我们这次学习RL电路的响应&#xff0c;以此同时&#xff0c;其实也是带大家一起回忆一些之前所学的RC电路的响应的一些知识点。所以&#xff0c;这次的学习&#xff0c;其实也…

30-消息队列

一、消息队列概述 队列又称消息队列&#xff0c;是一种常用于任务间通信的数据结构&#xff0c;队列可以在任务与任务间、 中断和任务间传递信息&#xff0c;实现了任务接收来自其他任务或中断的不固定长度的消息&#xff0c;任务能够从队列里面读取消息&#xff0c;当队列中的…