51汇编仿真proteus8.15学习篇四(附源码)

文章目录


一、前言

`汇编语言是二进制指令的文本形式,与指令是一一对应的关系。比如,加法指令00000011写成汇编语言就是 ADD。只要还原成二进制,汇编语言就可以被 CPU 直接执行,所以它是最底层的低级语言。

最近对汇编的仿真产生兴趣,虽然尚未系统学习,但搜集了一些资料尝试实践。学习汇编有助于更深入理解硬件工作原理,顺带记录一下学习过程,也欢迎交流指正。


二、仿真

1.016-定时计数器T0作定时应用技术(二)

/*

016-定时计数器T0作定时应用技术(二)

一个典型的定时器中断控制多任务程序

4个LED会轮流闪烁,每个LED闪烁约0.4秒,闪烁5次,然后切换到下一个LED,形成轮流闪烁的效果。

*/

T0中断服务程序框图

主程序框图

1.1 电路仿真

1.2 仿真程序

c 复制代码
/*
016-定时计数器T0作定时应用技术(二)
一个典型的定时器中断控制多任务程序
4个LED会轮流闪烁,每个LED闪烁约0.4秒,闪烁5次,然后切换到下一个LED,形成轮流闪烁的效果。
*/

; ===== 定义变量 =====
TCOUNT2S EQU 30H   ; 2秒计时计数器
TCNT02S EQU 31H    ; 0.2秒计时计数器
ID EQU 32H         ; 状态ID(0-3,对应4个LED)
FLASH_COUNT EQU 33H  ; 闪烁次数计数器

ORG 00H            ; 程序从地址00H开始
LJMP START         ; 跳转到主程序

ORG 0BH            ; 定时器0中断向量地址
LJMP INT_T0        ; 跳转到定时器0中断服务程序

; ===== 主程序 =====
START: 
    MOV TCOUNT2S, #00H  ; 初始化2秒计数器为0
    MOV TCNT02S, #00H   ; 初始化0.2秒计数器为0
    MOV ID, #00H        ; 初始化状态ID为0
    MOV FLASH_COUNT, #00H ; 初始化闪烁次数计数器为0
    
    ; ===== 初始化所有LED为熄灭状态 =====
    SETB P1.0          ; 熄灭LED1(共阳极接法,1=熄灭)
    SETB P1.1          ; 熄灭LED2
    SETB P1.2          ; 熄灭LED3
    SETB P1.3          ; 熄灭LED4
    
    ; ===== 定时器0初始化 =====
    MOV TMOD, #01H      ; 设置定时器0为模式1(16位定时器)
    
    ; 计算并设置定时器初值(50ms定时,晶振12MHz)
    ; 65536 - 50000 = 15536 = 3CB0H
    MOV TH0, #(65536-50000) / 256   ; 高8位:3CH
    MOV TL0, #(65536-50000) MOD 256 ; 低8位:0B0H
    
    SETB TR0            ; 启动定时器0
    SETB ET0            ; 允许定时器0中断
    SETB EA             ; 开启总中断允许
    
    SJMP $              ; 原地循环,等待中断

; ===== 定时器0中断服务程序 =====
INT_T0: 
    ; 重装定时器初值(50ms)
    MOV TH0, #(65536-50000) / 256
    MOV TL0, #(65536-50000) MOD 256
    
    ; ===== 2秒计时 =====
    INC TCOUNT2S        ; 2秒计数器加1
    MOV A, TCOUNT2S
    CJNE A, #40, NEXT   ; 比较是否达到40次(40×50ms=2000ms=2秒)
    
    ; 达到2秒,重置2秒计数器
    MOV TCOUNT2S, #00H
    
    ; ===== 状态切换 =====
    INC ID              ; 状态ID加1(切换到下一个LED)
    MOV A, ID
    CJNE A, #04H, RESET_FLASH_COUNT  ; 检查ID是否达到4
    MOV ID, #00H        ; ID达到4,重置为0(实现0-3循环)

; ===== 重置闪烁计数器 =====
RESET_FLASH_COUNT:
    MOV FLASH_COUNT, #00H  ; 新状态开始,闪烁次数清零
    
    ; 熄灭所有LED
    SETB P1.0
    SETB P1.1
    SETB P1.2
    SETB P1.3
    
    SJMP NEXT           ; 跳转到下一步

; ===== 0.2秒计时 =====
NEXT: 
    INC TCNT02S         ; 0.2秒计数器加1
    MOV A, TCNT02S
    CJNE A, #4, DONE    ; 比较是否达到4次(4×50ms=200ms=0.2秒)
    
    ; 达到0.2秒,重置0.2秒计数器
    MOV TCNT02S, #00H
    
    ; ===== 检查闪烁次数 =====
    MOV A, FLASH_COUNT
    CJNE A, #10, DO_FLASH  ; 检查是否达到10次(5次闪烁,每次闪烁包含亮和灭)
    
    ; ===== 闪烁5次完成,熄灭当前LED =====
    ; 根据当前ID熄灭对应的LED
    MOV A, ID
    CJNE A, #00H, CHECK1
    
    ; ID=0:熄灭LED1
    SETB P1.0
    SJMP DONE

CHECK1: 
    CJNE A, #01H, CHECK2
    
    ; ID=1:熄灭LED2
    SETB P1.1
    SJMP DONE

CHECK2: 
    CJNE A, #02H, CHECK3
    
    ; ID=2:熄灭LED3
    SETB P1.2
    SJMP DONE

CHECK3: 
    ; ID=3:熄灭LED4
    SETB P1.3
    SJMP DONE

; ===== 执行闪烁 =====
DO_FLASH:
    ; 闪烁次数加1
    INC FLASH_COUNT
    
    ; 根据当前ID闪烁对应的LED
    MOV A, ID
    CJNE A, #00H, FLASH1
    
    ; ID=0:LED1闪烁
    CPL P1.0            ; 取反P1.0引脚
    SJMP DONE

FLASH1: 
    CJNE A, #01H, FLASH2
    
    ; ID=1:LED2闪烁
    CPL P1.1            ; 取反P1.1引脚
    SJMP DONE

FLASH2: 
    CJNE A, #02H, FLASH3
    
    ; ID=2:LED3闪烁
    CPL P1.2            ; 取反P1.2引脚
    SJMP DONE

FLASH3: 
    ; ID=3:LED4闪烁
    CPL P1.3            ; 取反P1.3引脚

DONE: 
    RETI                ; 中断返回

END                   ; 程序结束

2.017-99秒马表设计

/*

017-99秒马表设计

开始时,显示"00",第1次按下按键后就开始计时。

第2次按按键后,计时停止。

第3次按按键后,计时归零

*/

2.1 电路仿真

2.2 仿真程序

c 复制代码
/*
017-99秒马表设计
开始时,显示"00",第1次按下按键后就开始计时。
第2次按按键后,计时停止。
第3次按按键后,计时归零
*/

; 符号定义
TCNTA EQU 30H     ; 定时器中断计数器A(用于0.01秒计数)
TCNTB EQU 31H     ; 定时器中断计数器B(用于秒计数)
SEC EQU 32H       ; 秒计数变量(0-99)
KEYCNT EQU 33H    ; 按键计数器
SP1 BIT P3.5      ; 按键连接到P3.5

; 程序入口
ORG 00H           ; 复位向量
LJMP START        ; 跳转到主程序

; 中断向量
ORG 0BH           ; 定时器0中断向量
LJMP INT_T0       ; 跳转到定时器0中断服务程序

; 主程序
START: 
    MOV KEYCNT, #00H     ; 初始化按键计数器为0
    MOV SEC, #00H        ; 初始化秒计数为0
    
    ; 显示初始值00
    MOV A, SEC           ; 将秒数送入累加器A
    MOV B, #10           ; 除数10
    DIV AB               ; 将秒数分解为十位(A)和个位(B)
    MOV DPTR, #TABLE     ; 加载段码表地址
    MOVC A, @A+DPTR      ; 获取十位的7段码
    MOV P0, A            ; 输出到P0(十位数码管)
    MOV A, B             ; 取个位
    MOV DPTR, #TABLE     ; 重新加载段码表地址
    MOVC A, @A+DPTR      ; 获取个位的7段码
    MOV P2, A            ; 输出到P2(个位数码管)
    
    ; 定时器初始化
    MOV TMOD, #02H       ; 设置定时器0为模式2(8位自动重装)
    SETB ET0             ; 允许定时器0中断
    SETB EA              ; 允许总中断
    
; 主循环
WT: 
    JB SP1, WT           ; 等待按键按下(SP1为0表示按下)
    
    ; 按键消抖
    LCALL DELY10MS       ; 延时10ms
    JB SP1, WT           ; 再次检测,如果按键松开则为抖动
    
    ; 有效按键
    INC KEYCNT           ; 按键计数器加1
    MOV A, KEYCNT        ; 获取按键计数值
    
    ; 根据按键次数执行不同功能
    CJNE A, #01H, KN1    ; 第一次按键:启动计时
    SETB TR0             ; 启动定时器0
    MOV TH0, #06H        ; 设置定时器初值
    MOV TL0, #06H
    MOV TCNTA, #00H      ; 清空中断计数变量
    MOV TCNTB, #00H
    LJMP DKN
    
KN1: 
    CJNE A, #02H, KN2    ; 第二次按键:停止计时
    CLR TR0              ; 停止定时器0
    LJMP DKN
    
KN2: 
    CJNE A, #03H, DKN    ; 第三次按键:复位
    MOV SEC, #00H        ; 秒计数清零
    
    ; 显示复位后的00
    MOV A, SEC
    MOV B, #10
    DIV AB
    MOV DPTR, #TABLE
    MOVC A, @A+DPTR
    MOV P0, A
    MOV A, B
    MOV DPTR, #TABLE
    MOVC A, @A+DPTR
    MOV P2, A
    
    MOV KEYCNT, #00H     ; 按键计数器清零
    
; 等待按键释放
DKN: 
    JNB SP1, $           ; 等待按键释放
    LJMP WT              ; 返回主循环

; 10ms延时子程序
DELY10MS:
    MOV R6, #20          ; 外循环20次
D1: 
    MOV R7, #248         ; 内循环248次
    DJNZ R7, $           ; 内循环延时
    DJNZ R6, D1          ; 外循环控制
    RET

; 定时器0中断服务程序
INT_T0:
    INC TCNTA            ; 中断计数器A加1
    MOV A, TCNTA
    CJNE A, #100, NEXT   ; 判断是否达到100次中断(1秒?实际是4秒)
    MOV TCNTA, #00H      ; 清空中断计数器A
    INC TCNTB            ; 中断计数器B加1
    MOV A, TCNTB
    CJNE A, #30, NEXT     ; 判断是否达到30次
    MOV TCNTB, #00H      ; 清空中断计数器B
    INC SEC              ; 秒数加1
    
    ; 判断秒数是否达到100
    MOV A, SEC
    CJNE A, #100, DONE
    MOV SEC, #00H        ; 达到100秒则清零
    
; 更新显示
DONE: 
    MOV A, SEC
    MOV B, #10
    DIV AB
    MOV DPTR, #TABLE
    MOVC A, @A+DPTR
    MOV P0, A
    MOV A, B
    MOV DPTR, #TABLE
    MOVC A, @A+DPTR
    MOV P2, A
    
NEXT: 
    RETI                  ; 中断返回

; 7段数码管段码表(共阴极)
; 0-9的7段码
TABLE: 
    DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH
; 对应数字:0, 1, 2, 3, 4, 5, 6, 7, 8, 9

END

3.018-数字钟﹝★﹞

/*

018-数字钟

(1. 开机时,显示12:00:00的时间开始计时;

(2. P0.0/AD0控制"秒"的调整,每按一次加1秒;

(3. P0.1/AD1控制"分"的调整,每按一次加1分;

(4. P0.2/AD2控制"时"的调整,每按一次加1个小时;

*/

3.1 电路仿真

3.2 仿真程序

c 复制代码
/*
018-数字钟
(1. 开机时,显示12:00:00的时间开始计时; 
(2. P0.0/AD0控制"秒"的调整,每按一次加1秒; 
(3. P0.1/AD1控制"分"的调整,每按一次加1分; 
(4. P0.2/AD2控制"时"的调整,每按一次加1个小时;
*/

; 寄存器定义
SECOND  EQU 30H     ; 秒
MINUTE  EQU 31H     ; 分
HOUR    EQU 32H     ; 时
COUNT   EQU 33H     ; 定时中断计数
TEMP    EQU 34H     ; 临时寄存器
DISP_BUF EQU 40H    ; 显示缓冲区(8字节)

; 位定义
KEY_SEC BIT P0.0    ; 调秒
KEY_MIN BIT P0.1    ; 调分
KEY_HOUR BIT P0.2   ; 调时

ORG 0000H
LJMP MAIN
ORG 000BH          ; 定时器0中断入口
LJMP TIMER0_ISR

ORG 0100H
MAIN:
    MOV SP, #60H   ; 堆栈初始化
    MOV SECOND, #00H
    MOV MINUTE, #00H
    MOV HOUR, #0CH  ; 12点
    MOV COUNT, #00H
    LCALL UPDATE_DISP_BUF ; 初始化显示缓冲区
    
    ; 定时器0设置(方式1,50ms)
    MOV TMOD, #01H
    MOV TH0, #3CH   ; 12MHz下,定时50ms
    MOV TL0, #0B0H
    SETB ET0
    SETB EA
    SETB TR0

MAIN_LOOP:
    LCALL KEY_SCAN  ; 按键扫描
    LCALL DISPLAY   ; 数码管显示
    SJMP MAIN_LOOP

; 定时器0中断服务程序
TIMER0_ISR:
    PUSH ACC
    PUSH PSW
    CLR TR0
    MOV TH0, #3CH
    MOV TL0, #0B0H
    SETB TR0
    INC COUNT
    MOV A, COUNT
    CJNE A, #20, TIMER_EXIT ; 50ms*20=1秒
    MOV COUNT, #00H
    INC SECOND
    MOV A, SECOND
    CJNE A, #60, UPDATE_TIME
    MOV SECOND, #00H
    INC MINUTE
    MOV A, MINUTE
    CJNE A, #60, UPDATE_TIME
    MOV MINUTE, #00H
    INC HOUR
    MOV A, HOUR
    CJNE A, #24, UPDATE_TIME
    MOV HOUR, #00H
    
UPDATE_TIME:
    LCALL UPDATE_DISP_BUF
    
TIMER_EXIT:
    POP PSW
    POP ACC
    RETI

; 按键扫描程序
KEY_SCAN:
    ; 检查秒按键
    JNB KEY_SEC, KEY_SEC_PRESS
    SJMP CHECK_MIN_KEY
    
KEY_SEC_PRESS:
    LCALL DELAY_20MS
    JNB KEY_SEC, KEY_SEC_HANDLE
    SJMP CHECK_MIN_KEY
    
KEY_SEC_HANDLE:
    INC SECOND
    MOV A, SECOND
    CJNE A, #60, KEY_SEC_UPDATE
    MOV SECOND, #00H
KEY_SEC_UPDATE:
    LCALL UPDATE_DISP_BUF
    JNB KEY_SEC, $  ; 等待按键释放
    LCALL DELAY_20MS
    RET

CHECK_MIN_KEY:
    ; 检查分按键
    JNB KEY_MIN, KEY_MIN_PRESS
    SJMP CHECK_HOUR_KEY
    
KEY_MIN_PRESS:
    LCALL DELAY_20MS
    JNB KEY_MIN, KEY_MIN_HANDLE
    SJMP CHECK_HOUR_KEY
    
KEY_MIN_HANDLE:
    INC MINUTE
    MOV A, MINUTE
    CJNE A, #60, KEY_MIN_UPDATE
    MOV MINUTE, #00H
KEY_MIN_UPDATE:
    LCALL UPDATE_DISP_BUF
    JNB KEY_MIN, $  ; 等待按键释放
    LCALL DELAY_20MS
    RET

CHECK_HOUR_KEY:
    ; 检查时按键
    JNB KEY_HOUR, KEY_HOUR_PRESS
    RET
    
KEY_HOUR_PRESS:
    LCALL DELAY_20MS
    JNB KEY_HOUR, KEY_HOUR_HANDLE
    RET
    
KEY_HOUR_HANDLE:
    INC HOUR
    MOV A, HOUR
    CJNE A, #24, KEY_HOUR_UPDATE
    MOV HOUR, #00H
KEY_HOUR_UPDATE:
    LCALL UPDATE_DISP_BUF
    JNB KEY_HOUR, $  ; 等待按键释放
    LCALL DELAY_20MS
    RET

; 更新时间到显示缓冲区
UPDATE_DISP_BUF:
    ; 时
    MOV A, HOUR
    MOV B, #10
    DIV AB
    MOV DISP_BUF, A    ; 时十位
    MOV DISP_BUF+1, B  ; 时个位
    ; 横线
    MOV DISP_BUF+2, #10
    
    ; 分
    MOV A, MINUTE
    MOV B, #10
    DIV AB
    MOV DISP_BUF+3, A  ; 分十位
    MOV DISP_BUF+4, B  ; 分个位
    ; 横线
    MOV DISP_BUF+5, #10
    
    ; 秒
    MOV A, SECOND
    MOV B, #10
    DIV AB
    MOV DISP_BUF+6, A  ; 秒十位
    MOV DISP_BUF+7, B  ; 秒个位
    RET

; 数码管显示
DISPLAY:
    MOV R0, #DISP_BUF
    MOV R2, #0FEH      ; 位选初始值(P3.0=0,选中第一位)
    MOV R3, #8
    
DISPLAY_LOOP:
    MOV A, @R0
    LCALL SEG_TABLE    ; 查表获取段码
    MOV P1, A          ; 输出段码
    MOV P3, R2         ; 输出位选
    LCALL DELAY_2MS    ; 延时2ms
    MOV P3, #0FFH      ; 关闭显示,消隐
    
    INC R0             ; 指向下一个显示数据
    MOV A, R2
    RL A               ; 左移一位,选中下一位
    MOV R2, A
    DJNZ R3, DISPLAY_LOOP
    RET

; 共阴数码管段码表(0~9,横线)
; 顺序:P1.0~P1.7 -> a,b,c,d,e,f,g,dp
; 0: 3FH, 1: 06H, 2: 5BH, 3: 4FH, 4: 66H
; 5: 6DH, 6: 7DH, 7: 07H, 8: 7FH, 9: 6FH, -: 40H
SEG_TABLE:
    INC A
    MOVC A, @A+PC
    RET
    DB 3FH, 06H, 5BH, 4FH, 66H, 6DH, 7DH, 07H, 7FH, 6FH, 40H

; 延时子程序
DELAY_2MS:
    MOV R6, #4
DL1: MOV R7, #250
    DJNZ R7, $
    DJNZ R6, DL1
    RET

DELAY_20MS:
    PUSH 00H
    MOV R0, #100
DL2: LCALL DELAY_2MS
    DJNZ R0, DL2
    POP 00H
    RET

DELAY_1MS:
    MOV R6, #2
DL3: MOV R7, #250
    DJNZ R7, $
    DJNZ R6, DL3
    RET

END

4.019-点阵式LED"0-9"数字显示技术

/*

019-点阵式LED"0-9"数字显示技术

利用8X8点阵显示数字0到9的数字。

*/

4.1 电路仿真

显示数字0

; 数字0

DB 00H,00H,3EH,41H,41H,41H,3EH,00H

显示数字1

显示数字2

显示数字3

显示数字4

显示数字5

显示数字6

显示数字7

显示数字8

显示数字9

4.2 仿真程序

c 复制代码
/*
019-点阵式LED"0-9"数字显示技术
利用8X8点阵显示数字0到9的数字。 
*/

TIM  EQU 30H   ; 中断计数器,用于计时
CNTA EQU 31H   ; 位扫描指针(控制哪个数码管亮)
CNTB EQU 32H   ; 显示数字索引(0-9)

ORG 00H        ; 程序从地址00H开始
LJMP START     ; 跳转到主程序
ORG 0BH        ; 定时器0中断入口
LJMP T0X       ; 跳转到中断服务程序
ORG 30H        ; 主程序起始地址
START:
    MOV TIM,  #00H     ; 初始化中断计数器
    MOV CNTA, #00H     ; 初始化位扫描指针
    MOV CNTB, #00H     ; 初始化数字索引
    
    MOV TMOD, #01H     ; 设置定时器0为模式1(16位定时)
    
    ; 计算并设置定时初值(4000次计数,假设12MHz晶振,约4ms中断一次)
    MOV TH0, #(65536-4000)/256   ; 高8位
    MOV TL0, #(65536-4000) MOD 256 ; 低8位
    
    SETB TR0    ; 启动定时器0
    SETB ET0    ; 允许定时器0中断
    SETB EA     ; 开启总中断
    
    SJMP $      ; 原地循环,等待中断

T0X:
    ; 重装定时初值
    MOV TH0, #(65536-4000)/256
    MOV TL0, #(65536-4000) MOD 256
    
    ; --- 位选控制 ---
    MOV DPTR, #TAB      ; 指向位选码表
    MOV A, CNTA         ; 取当前位选索引
    MOVC A, @A+DPTR     ; 查表获取位选码
    MOV P3, A           ; 输出到P3口(控制哪个数码管亮)
    
    ; --- 段选控制 ---
    MOV DPTR, #DIGIT    ; 指向段码表
    MOV A, CNTB         ; 取当前显示数字索引
    MOV B, #8           ; 每个数字占8个字节(8位数码管)
    MUL AB              ; 计算数字在表中的偏移地址
    ADD A, CNTA         ; 加上当前位选偏移
    MOVC A, @A+DPTR     ; 查表获取段码
    MOV P1, A           ; 输出到P1口(控制显示内容)
    
    ; 更新位选指针
    INC CNTA
    MOV A, CNTA
    CJNE A, #8, NEXT    ; 如果未到8,继续
    MOV CNTA, #00H      ; 到8则归零(8位数码管循环)
    
NEXT:
    ; 更新中断计数
    INC TIM
    MOV A, TIM
    CJNE A, #250, NEX   ; 计数250次(4ms×250=1秒)
    MOV TIM, #00H       ; 计时到1秒,重置计数器
    
    ; 更新显示数字
    INC CNTB
    MOV A, CNTB
    CJNE A, #10, NEX    ; 如果未到10,继续
    MOV CNTB, #00H      ; 到10则归零(0-9循环)
    
NEX:
    RETI                ; 中断返回

; 位选码表(共阴数码管,低电平选中)
; 依次选中第1~8位数码管
TAB: DB 0FEH,0FDH,0FBH,0F7H,0EFH,0DFH,0BFH,07FH
    ; 对应二进制:11111110, 11111101, 11111011, 11110111, 
    ;            11101111, 11011111, 10111111, 01111111

; 段码表(共阴数码管,低电平点亮段)
; 每个数字8个字节,对应8位数码管的段码
DIGIT: 
    ; 数字0
    DB 00H,00H,3EH,41H,41H,41H,3EH,00H
    ; 数字1
    DB 00H,00H,00H,00H,21H,7FH,01H,00H
    ; 数字2
    DB 00H,00H,27H,45H,45H,45H,39H,00H
    ; 数字3
    DB 00H,00H,22H,49H,49H,49H,36H,00H
    ; 数字4
    DB 00H,00H,0CH,14H,24H,7FH,04H,00H
    ; 数字5
    DB 00H,00H,72H,51H,51H,51H,4EH,00H
    ; 数字6
    DB 00H,00H,3EH,49H,49H,49H,26H,00H
    ; 数字7
    DB 00H,00H,40H,40H,40H,4FH,70H,00H
    ; 数字8
    DB 00H,00H,36H,49H,49H,49H,36H,00H
    ; 数字9
    DB 00H,00H,32H,49H,49H,49H,3EH,00H
		
END; 结束	

三、总结

今天通过几个简单的51汇编仿真,我们亲眼看到了代码如何驱动硬件。算是为"更深层次了解单片机工作原理"这个目标迈出了一小步。感谢观看,后续继续分享!

感谢你的观看!

相关推荐
项目題供诗2 小时前
51单片机入门(三)
单片机·嵌入式硬件·51单片机
解局易否结局2 小时前
学习 Flutter for OpenHarmony 的前置 Dart 语言:高级特性实战笔记(下)
笔记·学习·flutter
峥嵘life2 小时前
Android16 EDLA【GTS】GtsUnofficialApisUsageTestCases存在fail项
android·linux·运维·学习
电子工程师成长日记-C512 小时前
51单片机16路抢答器
单片机·嵌入式硬件·51单片机
我的xiaodoujiao2 小时前
使用 Python 语言 从 0 到 1 搭建完整 Web UI自动化测试学习系列 44--Pytest框架钩子函数
python·学习·测试工具·pytest
studyForMokey2 小时前
【Android 源码】RecylerView的深入理解
android·学习
电饭叔2 小时前
一个虚假证明的错误(一)
学习
爱吃大芒果2 小时前
Flutter for OpenHarmony核心组件学习: MaterialApp、Scaffold 两大基础组件以及有无状态组件
开发语言·学习·flutter
xiaobuding_QAQ2 小时前
51汇编仿真proteus8.15学习篇三(附源码)
汇编·单片机·学习·proteus