找回密码
 立即注册
楼主: HiMrLe

USB型 1T 8051 单片机原理及应用-8H8K64U-学习打卡

[复制链接]
  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-03-31 08:20:20
已绑定手机

3

主题

43

回帖

141

积分

注册会员

积分
141
发表于 4 天前 | 显示全部楼层

打卡第十集-汇编语言程序设计的一般步骤和基本框架

汇编语言程序设计的一般步骤与基本框架

一、汇编语言程序设计的一般步骤

1. 需求分析

明确程序要实现的功能、输入输出条件、性能指标(如速度、精度)、硬件资源限制(ROM/RAM大小、I/O引脚数量等)。

2. 算法设计与数据结构选择

  • 确定解决问题的算法(如查找、排序、PID控制等)。
  • 规划数据存储方式:使用寄存器、内部RAM、外部RAM还是位寻址区。
  • 设计关键变量、标志位、缓冲区的组织方式。

3. 资源分配

  • 寄存器分配:将常用变量分配至工作寄存器 R0~R7,减少内存访问。
  • 内存分配:为全局变量、堆栈、缓冲区指定具体地址(或使用 DATA 伪指令定义)。
  • 位地址分配:为需要位操作的标志位分配位寻址区(20H~2FH)或可位寻址的 SFR。

4. 编写程序代码

采用模块化思路,按功能划分模块(主程序、初始化、子程序、中断服务)。
遵循自顶向下设计,先搭建框架,再逐步填充细节。

5. 编写伪指令与源程序

使用汇编器支持的伪指令(如 ORGEQUDBEND 等)定义段、常量、变量。

6. 汇编与链接

使用开发工具(如 Keil uVision)将汇编源文件转换为机器码(HEX 文件)。

7. 调试与测试

  • 使用仿真器或在线调试(如 STC-ISP 的仿真功能)单步执行。
  • 观察寄存器、内存、I/O 状态是否符合预期。
  • 边界条件测试、异常情况测试。

8. 优化与固化

  • 优化代码长度或执行速度(如用 DJNZ 替代 DEC+JNZ)。
  • 生成最终 HEX 文件并烧录至单片机。

二、汇编语言程序的基本框架

一个完整的汇编程序通常包含以下部分(以 8051/STC8H 为例):

1. 程序头部

包含注释说明、文件名、作者、功能描述等。

2. 包含头文件与符号定义

  • 使用 $INCLUDE#include 引入单片机寄存器定义文件(如 STC8H.INC)。
  • EQU 定义常量、地址、位符号,增强可读性。

3. 中断向量表

从地址 0000H 开始,为每个中断预留入口地址。通常使用 LJMP 跳转到实际中断服务程序。

4. 主程序

  • 初始化:设置堆栈指针、I/O 口模式、定时器、中断等。
  • 主循环:执行主要功能,通常是一个无限循环,内部可包含子程序调用、状态机处理等。

5. 子程序

实现特定功能的代码块,使用 LCALL/ACALL 调用,以 RET 返回。注意现场保护(如 PUSH/POP)。

6. 中断服务程序(ISR)

处理中断事件,遵循“快进快出”原则。需使用 RETI 返回,并注意保护/恢复现场。

7. 常量与数据表

使用 DBDW 定义查表数据、字符串等,通常放在程序末尾或专门的 CODE 段。

8. 结束伪指令

END 结尾,告诉汇编器源文件结束。


三、典型程序框架模板(STC8H8K64U)

assembly

;*******************************************************************************
; 文件名:    template.asm
; 功能:      STC8H8K64U 汇编程序模板
; 作者:
; 日期:
;*******************************************************************************

; 包含头文件(定义所有 SFR)
$INCLUDE (STC8H.INC)

; 符号定义
STACK_PTR   EQU     80H     ; 堆栈起始地址(避开中断向量区)
DELAY_COUNT EQU     0FFFFH  ; 延时计数常量

; 中断向量表(程序起始)
ORG     0000H
LJMP    MAIN                ; 复位入口

; 外部中断0
ORG     0003H
LJMP    INT0_ISR

; 定时器0中断
ORG     000BH
LJMP    T0_ISR

; 外部中断1
ORG     0013H
LJMP    INT1_ISR

; 定时器1中断
ORG     001BH
LJMP    T1_ISR

; 串口中断
ORG     0023H
LJMP    UART_ISR

; 其他中断入口根据需要添加...

;*******************************************************************************
; 主程序
;*******************************************************************************
ORG     0100H               ; 主程序起始地址(避开向量区)

MAIN:
    ; 1. 初始化堆栈
    MOV     SP, #STACK_PTR

    ; 2. I/O 口模式配置(STC8H 特有)
    MOV     P0M0, #00H      ; P0 为准双向口
    MOV     P0M1, #00H
    MOV     P1M0, #0FFH     ; P1 为推挽输出
    MOV     P1M1, #00H
    ; ... 其他端口配置

    ; 3. 定时器初始化(示例)
    MOV     TMOD, #01H      ; 定时器0工作于模式1(16位)
    MOV     TH0,  #0FCH     ; 预设初值(1ms  @ 24MHz)
    MOV     TL0,  #018H
    SETB    TR0             ; 启动定时器0

    ; 4. 中断使能
    SETB    ET0             ; 允许定时器0中断
    SETB    EA              ; 开总中断

    ; 5. 其他初始化
    ; ...

    ; 主循环
MAIN_LOOP:
    ; 主程序任务
    ; ...
    SJMP    MAIN_LOOP       ; 无限循环

;*******************************************************************************
; 子程序
;*******************************************************************************
; 示例:延时子程序(使用 DJNZ 实现)
DELAY_MS:
    ; 入口:R7 = 延时毫秒数(假设晶振频率已知)
    ; 出口:无
    ; 破坏:R6, R7
    MOV     R6, #250
DELAY_LOOP:
    DJNZ    R6, DELAY_LOOP
    DJNZ    R7, DELAY_MS
    RET

;*******************************************************************************
; 中断服务程序
;*******************************************************************************
INT0_ISR:
    PUSH    ACC             ; 保护现场
    PUSH    PSW
    ; 中断处理代码
    ; ...
    POP     PSW             ; 恢复现场
    POP     ACC
    RETI

T0_ISR:
    PUSH    ACC
    PUSH    PSW
    ; 定时器0中断处理
    ; 重装初值
    MOV     TH0, #0FCH
    MOV     TL0, #018H
    ; 用户代码
    ; ...
    POP     PSW
    POP     ACC
    RETI

UART_ISR:
    ; 串口中断处理
    RETI

;*******************************************************************************
; 常量与数据表
;*******************************************************************************
    ; 例如:LED 显示段码表
SEG_TABLE:
    DB      0C0H, 0F9H, 0A4H, 0B0H, 099H  ; 0-4
    DB      092H, 082H, 0F8H, 080H, 090H  ; 5-9

;*******************************************************************************
    END

四、编程建议与注意事项

  1. 堆栈指针设置:将 SP 设置在 80H 以上,避免与中断向量区和位寻址区冲突。
  2. 中断服务程序:尽量简短,耗时操作放在主循环中处理。
  3. 寄存器使用:明确各寄存器的用途,避免冲突。子程序中若使用 R0~R7,需考虑是否需要保护(例如通过 PUSH/POP)。
  4. 位操作:优先使用位操作指令提高效率,但注意位寻址区的地址范围。
  5. 代码可读性:使用有意义的标号、注释,适当使用 EQU 定义常量。
  6. 模块化:将功能划分为独立的子程序,便于测试和维护。
  7. 调试预留:可在关键位置设置软件断点(如 SJMP $),或通过 I/O 口输出调试信号。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-03-31 08:20:20
已绑定手机

3

主题

43

回帖

141

积分

注册会员

积分
141
发表于 4 天前 | 显示全部楼层

打卡第十一集-单片机C语言程序设计导入一

C51对ANSI C的扩展

image.png

C51(Keil C51编译器)支持的数据类型可以分为标准C数据类型针对8051单片机的扩展数据类型两大类。

下表汇总了C51支持的所有数据类型及其关键属性:

数据类型 位数 (Bits) 字节数 (Bytes) 取值范围 说明
基本数据类型
bit 1 0 或 1 位类型,用于位寻址
signed char 8 1 -128~ +127 有符号字符型
unsigned char 8 1 0~ 255 无符号字符型,常用于存储8位数据
signed int 16 2 -32768~ +32767 有符号整型
unsigned int 16 2 0~ 65535 无符号整型
signed long 32 4 -2147483648~ +2147483647 有符号长整型
unsigned long 32 4 0~ 4294967295 无符号长整型
float 32 4 ±1.175494E-38~ ±3.402823E+38 单精度浮点型,符合IEEE-754标准
enum 8 / 16 1 或 2 -128~127 或 -32768~32767 枚举型
* (指针) 8~24 1~3 取决于存储类型 指针变量,用于存放地址
扩展数据类型
sfr 8 1 0~ 255 用于定义8位特殊功能寄存器
sfr16 16 2 0~ 65535 用于定义16位特殊功能寄存器
sbit 1 0 或 1 用于定义特殊功能寄存器中的可寻址位

💡 数据类型详解

1. 标准C数据类型

这些类型与标准C语言类似,但在8051这种8位单片机架构下有特定的大小和实现:

  • char类型:占据1个字节,是C51中最基础的数据类型。常用 unsigned char来存储0-255的数值或ASCII字符,节省内存且处理效率高。
  • int类型:占据2个字节,用于需要更大范围的整数运算。当 charint混合运算时,char会自动转换为 int类型。
  • long类型:占据4个字节,用于处理大范围的整数。
  • float类型:占据4个字节,用于带小数点的浮点数运算。由于处理浮点数会占用较多代码空间和CPU时间,在资源受限的单片机中应谨慎使用。
  • enum类型:枚举类型,根据数值范围自动选择占用1或2个字节。

2. 针对8051的扩展数据类型

这部分是C51为了直接高效地操作8051单片机硬件而特有的数据类型:

  • bit:位类型,用于定义一个位变量。它类似于布尔类型,只能取0或1。bit变量会被存放在8051内部RAM的位寻址区(20H~2FH),非常节省资源。

  • sfr (Special Function Register):特殊功能寄存器类型。8051单片机的许多功能控制(如I/O端口、定时器)都是通过读写SFR实现的。使用 sfr可以为特定的SFR地址命名,方便操作。例如:
    c

    sfr P1 = 0x90;  // 定义P1端口,地址为0x90
    P1 = 0xFF;      // 将P1口所有引脚设为高电平
    
  • sfr16:16位特殊功能寄存器类型。用于一次性操作16位的SFR,例如定时器T0的16位计数初值(由TH0和TL0两个8位寄存器组成)。

  • sbit (Special Bit):特殊功能寄存器中的位类型。用于直接访问SFR或可位寻址RAM中的某一位,常用于引脚状态的读取和控制。例如:
    c

    sbit LED = P1^0;   // 定义LED为P1.0引脚
    LED = 0;           // 将P1.0引脚拉低,点亮LED
    

🔄 数据类型转换

在C51中,不同类型的数据进行运算时,编译器会遵循一定的规则进行自动类型转换,优先级大致为:bitcharintlongfloatsignedunsigned。你也可以使用强制类型转换符 () 来人为地将某个表达式转换为所需的类型。

C51通过这些丰富且针对性的数据类型,既保留了C语言的高级特性,又让开发者能精确地控制8051单片机的每一个硬件资源。


在C51(Keil C51编译器)中,指针的使用比标准C更加复杂,这是因为8051单片机具有多种物理存储空间(内部RAM、外部RAM、代码ROM等),每种存储空间的地址宽度和访问方式不同。C51通过引入存储类型限定符指针类型来精确控制指针的指向和存储位置,以达到高效利用资源的目的。


一、指针的基本声明语法

C51指针的声明格式为:

text

[存储类型] 数据类型 [存储器类型 *] 指针变量名;
  • 存储类型:指针变量本身存放在哪个存储区(dataxdatapdata等)。
  • 数据类型:指针所指向的数据的类型。
  • 存储器类型:指针指向的对象位于哪个存储区(如 xdatacode等)。

二、指针的两大分类

1. 通用指针(Generic Pointer)

通用指针可以指向任何存储空间的对象,声明时不指定目标存储类型。编译器会为通用指针分配3个字节(第一字节表示存储类型,后两字节为16位地址)。

c

char *ptr;           // 通用指针,占3字节,可指向任何存储区的char
int *iptr;           // 通用指针,占3字节

优点:灵活,可以指向不同存储区的变量。
缺点:占用内存多,访问速度慢(因为每次需要解析存储类型)。

2. 基于存储器的指针(Memory-Specific Pointer)

基于存储器的指针在声明时指定了目标存储区,因此指针本身只存放地址(1或2字节),不包含存储类型信息。

目标存储区 地址宽度 指针大小 声明示例
data, idata, bdata 8位 1字节 char data *p;
pdata 8位 1字节 int pdata *p;
xdata 16位 2字节 long xdata *p;
code 16位 2字节 void code *p;

优点:占用内存小,访问效率高。
缺点:只能指向指定存储区的对象。


三、存储类型对指针本身位置的影响

指针变量本身也可以存放在不同存储区,通过声明时在变量名前添加存储类型来实现。

c

char *data p1;      // p1存放在data区,指向char型数据(通用指针,占3字节)
char xdata *p2;     // p2存放在xdata区,指向char型数据(通用指针,占3字节)
char *xdata p3;     // p3存放在xdata区,指向char型数据(通用指针,占3字节)——注意与上行的区别
char xdata *xdata p4; // p4存放在xdata区,指向xdata区的char(基于存储器的指针,占2字节)

关键点* 左边的存储类型表示指针指向的目标的存储区;变量名左边的存储类型表示指针变量自身的存储区。


四、常用存储区说明

存储类型 物理空间 地址宽度 访问速度 说明
data 内部RAM低128字节 8位 最快 直接寻址,可位寻址
idata 内部RAM全部256字节 8位 间接寻址
bdata 内部RAM位寻址区(20H~2FH) 8位 可位寻址
pdata 外部RAM一页(256字节) 8位 较慢 分页访问,使用MOVX @Ri
xdata 外部RAM全部64KB 16位 使用MOVX @DPTR
code 程序存储器(ROM) 16位 只读 存放常量

五、指针的初始化与使用

c

#include <reg51.h>

// 定义不同存储区的变量
unsigned char data   var1 = 0x12;     // data区变量
unsigned char xdata  var2 = 0x34;     // xdata区变量
unsigned char code   var3[] = {0x56, 0x78}; // code区常量数组

void main(void) {
    // 通用指针,可指向任意存储区
    unsigned char *ptr_g;
    ptr_g = &var1;          // 指向data区
    ptr_g = &var2;          // 指向xdata区
    ptr_g = var3;           // 指向code区

    // 基于存储器的指针,只能指向指定存储区
    unsigned char data *ptr_d;   // 指向data区的指针
    ptr_d = &var1;               // 合法
    // ptr_d = &var2;            // 错误!不能指向xdata区

    unsigned char xdata *ptr_x;  // 指向xdata区的指针
    ptr_x = &var2;               // 合法

    unsigned char code *ptr_c;   // 指向code区的指针
    ptr_c = var3;                // 合法
}

六、指针运算与数组

C51支持标准C的指针运算(++--、加减整数等),但要注意:

  • 通用指针运算时,编译器根据指针当前的存储类型决定步长,但效率较低。
  • 基于存储器的指针运算效率高,因为步长固定。

示例:遍历xdata数组

c

unsigned int xdata array[10] = {0};
unsigned int xdata *p;
for (p = array; p < array + 10; p++) {
    *p = 0xFFFF;
}

七、特殊注意事项

1. 不能指向SFR

特殊功能寄存器(SFR)虽然地址在0x80~0xFF,但SFR不是RAM,不能用普通指针指向。操作SFR应使用 sfrsbit关键字。

2. 空指针

C51中通用指针的NULL是三个字节全零,基于存储器的指针NULL是地址部分为零。但不同存储区的零地址可能有效(如data区的0地址),因此使用指针前最好检查是否合法。

3. 类型强制转换

可以将一种指针类型强制转换为另一种,但需注意存储区的兼容性。例如,将 xdata指针转换为 data指针可能导致错误,因为地址宽度可能不匹配。

4. 代码常量的访问

指向 code区的指针只能读取,不能写入。


八、指针选择建议

  • 追求速度、内存紧张:使用基于存储器的指针,并合理分配存储区。
  • 需要灵活性:使用通用指针,但要注意其3字节的开销和较慢的访问速度。
  • 指向大数组或外部RAM:使用 xdata *指针。
  • 指向常量字符串或查表:使用 code *指针。

九、总结

C51的指针系统是对标准C的扩展,旨在适应8051的分区内存架构。理解存储类型和指针分类,有助于写出高效、紧凑的嵌入式代码。合理使用基于存储器的指针可以显著减少RAM占用并提升执行速度。

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-03-31 08:20:20
已绑定手机

3

主题

43

回帖

141

积分

注册会员

积分
141
发表于 前天 00:21 | 显示全部楼层

打卡第十二集-单片机C语言程序设计导入二

单片机的C语言程序设计实例

image.png

image.png

Keil 的调试功能是嵌入式开发中定位问题、验证逻辑的核心工具。

🛠️ 第一步:配置调试器

在开始调试前,需要先告诉 Keil 用哪种方式连接你的硬件。点击魔术棒图标,在 Debug 标签页进行配置:

  • 选择调试器:在 Use 一栏的下拉菜单中,选择你使用的工具,如 ST-Link DebuggerJ-LINKCMSIS-DAP Debugger
  • 关键设置
    • Load Application at Startup:勾选后,每次进入调试模式会自动加载程序。
    • Run to main():勾选后,程序会直接运行到 main() 函数开头并停下,非常方便。
    • Initialization File:如果你的程序需要特殊的初始化(例如外部 RAM 初始化、加载多个代码段),可以在此指定一个 .ini 脚本文件。

🚀 第二步:掌握调试界面与核心操作

配置好后,点击工具栏上的红绿“d”图标或按 Ctrl+F5 进入调试模式。你会看到多出一个工具栏,掌握这几个按钮就能开始调试了:

图标 名称 功能说明
RST 复位 模拟芯片硬件复位,程序指针回到起点。
Run 运行 全速执行程序,直到遇到断点或手动停止。
Stop 停止 暂停正在运行的程序,定位到当前执行位置。
Step In 单步进入 执行当前行代码。如果是函数调用,会进入函数内部。
Step Over 单步跳过 执行当前行代码。如果是函数调用,会一次性执行完该函数,不进入内部。
Step Out 执行跳出 执行完当前函数的剩余部分,并返回到调用处。
Run to Cursor 运行到光标处 程序全速执行,直到停在光标所在行。

🎯 第三步:核心调试技巧

光会跑和停还不够,关键是能看到程序内部发生了什么。

1. 设置断点 (Breakpoints)
这是最常用的手段。只需在代码行号左侧的灰色区域单击,就会出现一个红色圆点。程序运行到此处时会自动停下,方便你检查状态。最多可以设置多少个断点取决于芯片,例如 MSPM0 系列只支持 4 个硬件断点

2. 查看变量 (Watch Window)
这是观察程序数据的窗口。在调试模式下,点击 View -> Watch Windows -> Watch 1。在窗口中输入你想观察的变量名,它的值会随着程序单步执行而实时更新。你也可以在代码区直接把鼠标悬停在变量上,查看其当前值。

3. 查看内存 (Memory Window)
想直接查看特定内存地址的数据?点击 View -> Memory Windows -> Memory 1,在 Address 栏输入地址(如 0x20000000),就能看到该区域的数据变化。

4. 查看外设寄存器 (System Viewer)
检查外设配置是否正确,看寄存器最直接。点击菜单栏的 Peripherals -> System Viewer,选择你想看的外设(如 USART1)。一个详细的寄存器窗口会打开,所有位的状态一目了然,是排查初始化问题的神器。

🔧 第四步:高级调试场景

1. 调试 HardFault 异常
这是 Cortex-M 开发者最常遇到的“噩梦”。当程序跑飞并卡死在 HardFault_Handler 里时,可以这样定位:

  • 查看 Fault Reports:点击 Peripherals -> Core Peripherals -> Fault Reports。看是哪个错误标志位被置位了(如 IMPRECISERR),它能给你一个初步的方向。
  • 查看调用堆栈 (Call Stack):在 Call Stack + Locals 窗口中,右键点击 HardFault_Handler,选择 Show Caller Code。Keil 会尝试带你跳转到真正触发 HardFault 的前一行代码附近。

2. 高级初始化文件 (.ini)
对于代码在外部 Flash (XIP) 运行的场景,直接调试可能会失败。这时可以编写一个 .ini 脚本,在调试器加载你的应用代码前,先执行一段初始化脚本(如配置外部总线)。脚本示例如下:

bash

// 先加载并运行一段初始化程序 (如 FSBL)
LOAD .\FSBL.axf INCREMENTAL
// 手动设置 PC 指针到初始化程序的入口地址
PC = 0x34180404
// 运行这段初始化程序
G
// 初始化完成后,再加载你自己的应用代码进行调试
LOAD .\Objects\Appli.axf CLEAR INCREMENTAL

3. 使用调试代码 (Debug Code)
除了硬件调试器,在代码里加入调试手段也很有效。例如,用 LED 闪烁指示程序运行到某个关键点,或者通过串口用 printf 输出变量值和运行状态。

⚠️ 常见问题提醒

  • 调试器连接不上:检查项目里选择的芯片型号是否正确,以及调试器(如 ST-Link)的驱动是否安装好。
  • 断点设置无效或数量受限:这是硬件限制,特别是对于低成本芯片。试着删除一些暂时不用的断点。
  • 程序复位后乱跑Reset 按钮只复位内核,不会复位外设。如果需要完整的复位效果,最好按一下板子上的硬件复位键。
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-03-31 08:20:20
已绑定手机

3

主题

43

回帖

141

积分

注册会员

积分
141
发表于 前天 00:59 | 显示全部楼层

打卡第十三集-中断原理及工作机制一

中断的概念
所谓中断是指计算机在执行其他程序的过程中,当出现了某些异常事件或某种请求时,CPU暂时中止正在执行的程序,而转去执行对异常事件或某种请求的服务程序。当服务完毕后, CPU再回到被暂时中止的程序继续执行。

其他中断相关概念
请示CPU中断的请求源称为中断源。 中断源向CPU发出中断申请,CPU暂停当前工作转去处理中断源事件称为中断响应。 对整个事件的处理过程称为中断服务。 事件处理完毕CPU返回到被中断的地方称为中断返回。

中断的优先级
计算机的中断系统一般允许多个中断源,当几个中断源同时向CPU请求中断,要求为其服务的时候,就存在CPU优先响应哪一个中断源请求的问题。通常根据中断源的轻重缓急排队,优先处理最紧急事件的中断请求源,即规定每一个中断源有一个优先级别。CPU总是先响应优先级别最高的中断请求。 当CPU正在处理一个中断源请求的时候(执行相应的中断服务程序),发生了另外一个优先级比它更高的中断源请求, CPU暂停原来中断源的服务程序,转而去处理优先级更高的中断请求源,处理完以后,再回到原低优先级中断的服务程序,这样的过程称为中断嵌套。

中断的优势
计算机采用中断技术,大大提高了工作效率和处理问题的灵活性,主要表现在3个方面:
①解决了快速CPU和慢速外设之间的矛盾,可使CPU和外设并行工作。
②可及时处理控制系统中许多随机参数和信息。
③具备了处理故障的能力,提高了机器自身的可靠性。
中断类似于程序设计中的调用子程序,但它们又有区别,主要区别如表6-1所示。
一般保护断点是硬件完成的,保护现场须在中断处理程序中用相应的指令完成。

开中断和关中断
中断的开放(称开中断或中断允许)和中断的关闭(称关中断或中断禁止)可以通过指令设置相关特功能寄存器的内容来实现,这是CPU能否接受中断请求的关键。只有在开中断的情况下,才有可能接受中断源的请求。

6、保护现场和恢复现场
在主程序调用子程序或中断处理过程时,分别要保存返回地址(断点地址)和保护现场,以便在返回时能够回到调用前的程序段,继续运行原来的程序。进入子程序或中断处理程序后保护相关寄存器中的值的操作,叫做保护现场;子程序返回或中断处理返回前,恢复相关寄存器中的值的操作,叫做恢复现场。保护现场的方法是将现场条件(寄存器的值)先推入(使用PUSH命令)堆栈保存,然后再使用这些寄存器,返回主程序前,弹出(使用POP指令)寄存器的值。这些功能都要通过堆栈操作来实现。其中通用寄存器的保存和恢复需要由堆栈操作指令来完成;返回地址的保存与恢复的堆栈操作都是在相应的子程序的调用和返回指令的操作中自动完成的,无需再用专门的堆栈操作指令。

7、堆栈
堆栈区是将内部存储器的一部分区域划作专门用于堆栈的区域。堆栈操作有其特定的规则,叫做后进先出(Last In First Out, LIFO)规则,即最后存入的数据将被最先取出。堆栈区当前的栈项地址用堆栈指针寄存器(SP)中的值表示,即SP 始终指向栈顶。

中断的撤除
在响应中断请求后,返回主程序之前,该中断请求标志应该撤除,否则,单片机执行完中断服务程序会误判为又发生了中断请求而错误地再次进入中断服务程序。单片机中有些中断请求标志会自动撤除,有些不能自动撤除,必须用户使用相应的指令撤除。

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-03-31 08:20:20
已绑定手机

3

主题

43

回帖

141

积分

注册会员

积分
141
发表于 前天 09:57 | 显示全部楼层

打卡第十四集-中断原理及工作机制二

单片机对中断优先级的处理原则是:
1) 不同级的中断源同时申请中断时,先高后低;
2) 处理低级中断又收到高级中断请求时,停低转高;
3)处理高级中断却收到低级中断请求时,高不睬低;
4)同一级的中断源同时申请中断时,事先规定。


在程序的运行过程中,并不是任何时刻都可以响应中断请求。当出现下列情况时,CPU不会响
应中断请求

1) 中断允许总控制位EA=0或发出中断请求的中断所对应的中断允许控制位为0。
2) CPU正在执行一个同级或高一级的中断服务程序。
3)当前执行的机器周期不是指令周期的最后一个机器周期。
4) 正在执行的指令是中断返回指令RETI或者是访问专用寄存器IE或IP的指令时,CPU
至少要再执行一条指令才能响应中断请求。


中断服务
中断服务程序从入口地址开始执行,直到执行返回指令RETI为止。RETI指令表示中断服务程序的结束,CPU执行该指令,一方面清除中断响应时所置位的优先级有效触发器,一方面由栈顶弹出断点地址送程序计数器PC,从而返回主程序。中断服务程序由四个部分组成,即保护现场、中断服务、恢复现场以及中断返回。由于在主程序中一般都会用到累加器A和程序状态字寄存器PSW,所以在现场保护时一般都需要保护A和PSW,其他寄存器根据使用情况决定是否需要保护。
在编写中断服务程序时应注意以下两点:
1) 单片机响应中断后,不会自动关闭中断系统。如果用户程序不希望出现中断嵌套,则必须在中断服务程序的开始处关闭中断,从而禁止更高优先级的中断请求中断当前的服务程序。
2)为了保证保护现场和恢复现场能够连续进行,在保护现场和恢复现场之前应先关中断,当现场保护或现场恢复结束后,再根据实际需要决定是否需要开中断。


中断请求的撤除
当某个中断源的请求被CPU响应后,应将相应的中断请求标志清除,否则CPU会再一次响应该中断源的请求,这将使CPU进入死循环。对于不同的中断源,清除中断请求的方法不同。
(1) 有些中断请求由硬件自动清除,在处理这些中断时,用户无需关心清除中断请求标志的问题。
(2) 有些中断请求不能自动清除,在处理这些中断时,用户需要通过指令清除。

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-03-31 08:20:20
已绑定手机

3

主题

43

回帖

141

积分

注册会员

积分
141
发表于 前天 23:29 | 显示全部楼层

打卡第十五集-定时器原理及STC拓展

单片机定时器的核心原理是一个数字计数器,它以固定的时钟频率累加计数,当计数值达到预设的阈值时,产生一个溢出信号,可以触发中断或让输出引脚电平翻转。

具体工作流程:

  1. 计数时钟:定时器的计数脉冲来自单片机内部的系统时钟(经分频后)或外部输入引脚。时钟频率决定了计数速度。
  2. 计数过程:计数器寄存器(如THx/TLx)在每个时钟脉冲到来时自动加1(或减1)。如果设置为自动重装模式,计数到最大值(如16位定时器的65535)后,会溢出归零,并重新从初始值开始计数。
  3. 溢出中断:每次溢出时,硬件会自动置位中断标志位,若中断使能,CPU会暂停当前任务去执行中断服务程序。通过记录溢出的次数,就能精确测量时间间隔。
  4. 应用示例:设单片机时钟为12MHz,定时器预分频为12,则计数脉冲频率为1MHz(周期1µs)。若需定时1ms,可设置初始计数值为1000,计数器每1µs加1,1000个脉冲后溢出,触发中断。

定时/计数器的作用
STC8H8K64U单片机内部集成了五个16位的定时/计数器(TO、T1、T2、
T3和T4),作用如下:
(1) 方便地用于定时控制;
(2)用作分频器和用于事件记录;
(3)可编程时钟输出功能,用于给外部器件提供时钟;
(4)可用作串口的波特率发生器。


image.png

image.png

回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:18
  • 最近打卡:2026-03-31 08:20:20
已绑定手机

3

主题

43

回帖

141

积分

注册会员

积分
141
发表于 昨天 19:04 | 显示全部楼层

打卡第十九集-NTC温度采集

NTC(Negative Temperature Coefficient)是指随温度上升电阻呈指数关系减小、具有负温度系数的热敏电阻现象和材料。该材料是利用锰、铜、硅、钴、铁、镍、锌等两种或两种以上的金属氧化物进行充分混合、成型、烧结等工艺而成的半导体陶瓷,可制成具有负温度系数(NTC)的热敏电阻。其电阻率和材料常数随材料成分比例、烧结气氛、烧结温度和结构状态不同而变化。现在还出现了以碳化硅、硒化锡、氮化钽等为代表的非氧化物系NTC热敏电阻材料。


NTC利用过渡金属氧化物中电子热激活跳跃导电,实现温度越高、电阻越小的特性


Rt = RT0*EXP(Bn*(1/T-1/T0))

式中RT、RT0分别为温度T、T0时的电阻值,Bn为材料常数.陶瓷晶粒本身由于温度变化而使电阻率发生变化,这是由半导体特性决定的。


image.png

回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-3-31 18:30 , Processed in 0.113640 second(s), 72 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表