You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

请求协助将实现十进制转二进制功能的C程序转换为Atmega32a平台的AVR汇编程序

把十进制转二进制的C程序转成ATmega32A的AVR汇编

当然可以帮你搞定这个转换!先看看你的C程序逻辑:它通过不断取余和整除2来提取每一位二进制数,然后把这些位按顺序组合成一个十进制形式的“二进制数”(比如输入十进制5,程序最终输出的是十进制数101,本质是把二进制位当作十进制数字串来展示)。下面是适配ATmega32A的AVR汇编实现,我会一步步拆解关键部分。

原C程序:

int main() { 
    int num, bin = 0, rem = 0, place = 1; 
    printf("Enter a decimal number\n"); 
    scanf("%d", &num); 
    printf("\nBinary equivalent of %d is ", num); 
    while(num) { 
        rem = num % 2; 
        num = num / 2; 
        bin = bin + (rem * place); 
        place = place * 10; 
    } 
    printf("%d\n", bin); 
    return 0; 
}

适配ATmega32A的AVR汇编实现

ATmega32A没有C标准库的printf和scanf,所以我们得先实现基础的USART串口收发函数来替代它们,再实现十进制转二进制的核心逻辑。以下是完整可运行的汇编代码:

; ATmega32A 汇编程序:十进制转二进制(输出为十进制形式的二进制数,如5→101)
; 假设使用16MHz晶振,串口波特率9600

.include "m32def.inc"

; --------------------------
; USART串口初始化函数
; --------------------------
USART_INIT:
    ldi r16, 0x00
    out UBRRH, r16
    ldi r16, 103        ; 16MHz晶振下,9600波特率对应的UBRR值
    out UBRRL, r16
    ldi r16, (1<<RXEN)|(1<<TXEN)
    out UCSRB, r16      ; 启用串口接收和发送
    ldi r16, (1<<UCSZ1)|(1<<UCSZ0)
    out UCSRC, r16      ; 设置8位数据位、1停止位、无校验
    ret

; --------------------------
; 发送单个字符(字符在r16中)
; --------------------------
USART_TX:
    sbis UCSRA, UDRE    ; 等待发送寄存器为空
    rjmp USART_TX
    out UDR, r16        ; 发送字符
    ret

; --------------------------
; 发送字符串(字符串以0结尾,地址在Z寄存器)
; --------------------------
USART_TX_STR:
    lpm r16, Z+         ; 从程序存储器加载字符
    cpi r16, 0          ; 判断是否到达字符串末尾
    breq USART_TX_STR_END
    rcall USART_TX
    rjmp USART_TX_STR
USART_TX_STR_END:
    ret

; --------------------------
; 接收单个字符(结果存在r16中)
; --------------------------
USART_RX:
    sbis UCSRA, RXC     ; 等待接收完成
    rjmp USART_RX
    in r16, UDR         ; 读取接收到的字符
    ret

; --------------------------
; 接收十进制数(结果存在r24:r23,16位整数)
; --------------------------
USART_RX_DEC:
    clr r23             ; 高位清零
    clr r24             ; 低位清零
USART_RX_DEC_LOOP:
    rcall USART_RX
    cpi r16, 0x0D       ; 检测回车符,结束输入
    breq USART_RX_DEC_END
    subi r16, 0x30      ; ASCII码转数字('0'-'9'→0-9)
    mul r24, r17        ; 当前数值乘以10(r17预先存10)
    mov r24, r0
    add r24, r16        ; 加上新输入的数字
    adc r23, r1         ; 处理乘法和加法的进位
    rjmp USART_RX_DEC_LOOP
USART_RX_DEC_END:
    ret

; --------------------------
; 发送十进制数(输入在r24:r23,16位整数)
; --------------------------
USART_TX_DEC:
    ldi r18, 0          ; 记录栈中数字的个数
    ldi r17, 10         ; 除数10
USART_TX_DEC_PUSH:
    clr r0
    clr r1
    div r24, r17        ; r24 = r24/10,r0=余数
    push r0
    inc r18
    cpi r24, 0
    brne USART_TX_DEC_PUSH
USART_TX_DEC_POP:
    pop r16
    subi r16, -0x30     ; 数字转ASCII码(0-9→'0'-'9')
    rcall USART_TX
    dec r18
    brne USART_TX_DEC_POP
    ret

; --------------------------
; 主程序入口
; --------------------------
.org 0x0000
rjmp MAIN

MAIN:
    ldi r17, 10         ; 预先加载常量10,复用减少指令
    rcall USART_INIT    ; 初始化串口

    ; 发送输入提示信息
    ldi ZH, high(PROMPT<<1)
    ldi ZL, low(PROMPT<<1)
    rcall USART_TX_STR

    ; 接收用户输入的十进制数,存在r24:r23
    rcall USART_RX_DEC
    movw r20, r23       ; 备份原输入值,因为后面要修改num

    ; 发送结果提示前缀
    ldi ZH, high(RESULT_PROMPT<<1)
    ldi ZL, low(RESULT_PROMPT<<1)
    rcall USART_TX_STR
    movw r24, r23       ; 把原输入值放到r24:r23用于发送
    rcall USART_TX_DEC
    ldi ZH, high(IS_STR<<1)
    ldi ZL, low(IS_STR<<1)
    rcall USART_TX_STR

    ; 初始化变量:bin=0(r19:r18),place=1(r16)
    clr r19
    clr r18             ; bin初始化为0
    ldi r16, 1          ; place初始化为1

    ; 核心循环:while(num != 0)
LOOP:
    cpi r21, 0          ; 判断num(r21:r20)是否为0
    brne LOOP_CONTINUE
    cpi r20, 0
    breq LOOP_END
LOOP_CONTINUE:
    ; rem = num % 2:取num的最低位(等价于取余2)
    mov r22, r20
    andi r22, 0x01      ; rem结果存在r22中

    ; num = num / 2:逻辑右移一位,等价于除以2
    lsr r21
    ror r20

    ; bin = bin + (rem * place)
    mov r23, r18        ; 把当前bin值放到r24:r23
    mov r24, r19
    mul r22, r16        ; 计算rem*place,结果在r1:r0
    add r23, r0
    adc r24, r1         ; 加上进位
    mov r18, r23        ; 更新bin值
    mov r19, r24

    ; place = place * 10
    mov r23, r16        ; place放到r24:r23(高位为0)
    clr r24
    mul r23, r17        ; 计算place*10,结果在r1:r0
    mov r16, r0         ; 更新place的低位
    mov r15, r1         ; 保存place的高位,防止溢出

    rjmp LOOP
LOOP_END:
    ; 输出最终的bin值
    mov r23, r18
    mov r24, r19
    rcall USART_TX_DEC

    ; 发送换行符
    ldi r16, 0x0A
    rcall USART_TX
    ldi r16, 0x0D
    rcall USART_TX

    rjmp MAIN           ; 循环等待下一次输入,可改为停止

; --------------------------
; 程序存储器中的字符串定义
; --------------------------
PROMPT: .db "Enter a decimal number:", 0x0A, 0x0D, 0
RESULT_PROMPT: .db "\nBinary equivalent of ", 0
IS_STR: .db " is ", 0

关键细节说明

  • 串口实现:ATmega32A没有现成的标准IO函数,所以我们手动实现了USART收发,支持字符串和十进制数的输入输出,波特率适配16MHz晶振下的9600。
  • 核心逻辑优化:
    • 原C中的num % 2用位与操作替代,比除法指令快很多,AVR中andi r22, 0x01直接取最低位,结果就是余数。
    • num / 2用右移指令lsr(高位右移)和ror(低位带进位右移)实现,完全等价于整数除以2,效率更高。
    • 乘法操作使用AVR的mul指令,因为我们处理的数值范围不大,16位寄存器足够存储中间结果。
  • 寄存器分配:
    • num:r21(高位)、r20(低位)
    • bin:r19(高位)、r18(低位)
    • place:r16(低位)、r15(高位,防止溢出)
    • rem:r22
    • 常量10:r17(预先加载,避免重复初始化)

内容的提问来源于stack exchange,提问作者Nar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 18:12:32