找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 554|回复: 0
打印 上一主题 下一主题
收起左侧

23LC1024 SRAM测试程序 - ASM完整版

[复制链接]
跳转到指定楼层
楼主

; =============================================
; 23LC1024 SRAM测试程序 - ASM完整版
; =功能:完整的SRAM读写测试,包含UART输出和LED指示
; =============================================

.include "m16def.inc"          ; 包含ATmega16定义文件

; 系统常量定义
.equ F_CPU = 1000000           ; CPU频率 1MHz
.equ SRAM_CS   = PB4           ; SRAM片选引脚(PB4)
.equ MOSI_PIN  = PB5           ; SPI主出从入引脚(PB5)
.equ MISO_PIN  = PB6           ; SPI主入从出引脚(PB6)  
.equ SCK_PIN   = PB7           ; SPI时钟引脚(PB7)
.equ CMD_READ  = 0x03          ; SRAM读命令
.equ CMD_WRITE = 0x02          ; SRAM写命令
.equ CMD_RDSR  = 0x05          ; 读状态寄存器命令
.equ CMD_WRSR  = 0x01          ; 写状态寄存器命令
.equ MODE_SEQ  = 0x40          ; 顺序模式配置值
.equ UBRR_VAL  = 12            ; 波特率9600 @ 1MHz

; 数据段定义(SRAM变量)
.dseg
write_data:   .byte 1          ; 写入数据存储
read_data:    .byte 1          ; 读取数据存储  
addr_high:    .byte 1          ; 24位地址高字节
addr_mid:     .byte 1          ; 24位地址中字节
addr_low:     .byte 1          ; 24位地址低字节
temp:         .byte 1          ; 临时变量
test_index:   .byte 1          ; 测试用例计数器
test_offset:  .byte 1          ; 测试表偏移量

; 代码段定义
.cseg
.org 0x0000                    ; 程序起始地址
    rjmp main                  ; 复位向量跳转到主程序

; 测试数据表 - 7个测试用例(地址+数据)
; 格式:地址高字节, 地址中字节, 地址低字节, 测试数据
test_table:
    .db 0x10, 0x00, 0x00, 0x11  ; 测试1: 地址 0x100000, 数据 0x11
    .db 0x20, 0x00, 0x00, 0x22  ; 测试2: 地址 0x200000, 数据 0x22  
    .db 0x00, 0x01, 0x00, 0x33  ; 测试3: 地址 0x000100, 数据 0x33
    .db 0x00, 0x00, 0x10, 0x44  ; 测试4: 地址 0x000010, 数据 0x44
    .db 0x30, 0x20, 0x10, 0x55  ; 测试5: 地址 0x302010, 数据 0x55
    .db 0x50, 0x20, 0x10, 0x65  ; 测试5: 地址 0x302010, 数据 0x65
    .db 0x80, 0x20, 0x10, 0x81  ; 测试5: 地址 0x302010, 数据 0x81


; 消息字符串定义(中英双语注释)
msg_title:    .db "23LC1024 ASM 完整测试",13,10,0                    ; 程序标题
msg_init:     .db "SRAM 已初始化",13,10,0                           ; SRAM初始化完成
msg_test:     .db "正在运行完整测试...",13,10,0                      ; 测试开始提示
msg_ok:       .db " [通过]",13,10,0                                 ; 测试通过
msg_fail:     .db " [失败]",13,10,0                                 ; 测试失败
msg_addr:     .db "Addr 0x",0                                       ; 地址显示前缀
msg_write:    .db " W=0x",0                                         ; 写入数据显示前缀
msg_read:     .db " R=0x",0                                         ; 读取数据显示前缀
msg_crlf:     .db 13,10,0,0                                         ; 回车换行
msg_done:     .db "=== 所有测试已完成! ===",13,10,0                 ; 测试完成提示
; =============================================
; 主程序
; =系统初始化和测试流程控制
; =============================================
main:
    ; 初始化堆栈指针
    ldi r16, high(RAMEND)      ; 加载RAM结束地址高字节
    out SPH, r16               ; 设置堆栈指针高字节
    ldi r16, low(RAMEND)       ; 加载RAM结束地址低字节
    out SPL, r16               ; 设置堆栈指针低字节

    rcall uart_init            ; 初始化UART串口

    ; 显示程序标题
    ldi ZL, low(2*msg_title)   ; 加载标题字符串地址低字节
    ldi ZH, high(2*msg_title)  ; 加载标题字符串地址高字节
    rcall uart_puts            ; 发送标题字符串
    rcall uart_crlf            ; 发送回车换行

    ; 初始化SRAM
    rcall sram_init            ; 初始化SPI和SRAM

    ; 显示初始化完成信息
    ldi ZL, low(2*msg_init)    ; 加载初始化消息地址低字节
    ldi ZH, high(2*msg_init)   ; 加载初始化消息地址高字节
    rcall uart_puts            ; 发送初始化消息

    ; 显示测试开始信息
    ldi ZL, low(2*msg_test)    ; 加载测试消息地址低字节
    ldi ZH, high(2*msg_test)   ; 加载测试消息地址高字节
    rcall uart_puts            ; 发送测试消息
    rcall uart_crlf            ; 发送回车换行

    ; 设置测试用例数量
    ldi r16, 7                 ; 设置总共运行5个测试用例
    sts test_index, r16        ; 保存测试计数器

    ldi r17, 0                 ; 初始化测试表偏移量为0
    sts test_offset, r17       ; 保存偏移量

; 测试循环主程序
run_tests:
    ; 设置Z指针指向测试参数表的起始地址
    ldi ZL, low(2*test_table)  ; 加载测试表地址低字节
    ldi ZH, high(2*test_table) ; 加载测试表地址高字节

    ; 加上当前测试的偏移量以定位到具体测试用例
    lds r17, test_offset       ; 加载当前偏移量
    add ZL, r17                ; 加到Z指针低字节
    ldi r18, 0                 ; 清零用于带进位加法
    adc ZH, r18                ; 加到Z指针高字节(带进位)

    ; 从程序存储器加载测试参数
    lpm r16, Z+                ; 加载地址高字节并递增指针
    sts addr_high, r16         ; 保存地址高字节
    lpm r16, Z+                ; 加载地址中字节并递增指针
    sts addr_mid, r16          ; 保存地址中字节
    lpm r16, Z+                ; 加载地址低字节并递增指针
    sts addr_low, r16          ; 保存地址低字节
    lpm r16, Z+                ; 加载测试数据并递增指针
    sts write_data, r16        ; 保存要写入的数据

    ; 执行SRAM读写测试
    rcall sram_write_byte      ; 向SRAM写入测试数据
    rcall sram_read_byte       ; 从SRAM读取数据
    rcall display_test_result  ; 显示测试结果

    ; 更新偏移量指向下一个测试用例(每个测试4个字节参数)
    lds r17, test_offset       ; 加载当前偏移量
    subi r17, -4               ; 偏移量加4(指向下一个测试)
    sts test_offset, r17       ; 保存更新后的偏移量

    ; 检查是否完成所有测试
    lds r16, test_index        ; 加载剩余测试计数
    dec r16                    ; 计数器减1
    sts test_index, r16        ; 保存更新后的计数
    brne run_tests             ; 如果未完成,继续下一个测试

    ; 所有测试完成,显示结束信息
    ldi ZL, low(2*msg_done)    ; 加载完成消息地址低字节
    ldi ZH, high(2*msg_done)   ; 加载完成消息地址高字节
    rcall uart_puts            ; 发送完成消息

    ; 成功指示 - 闪烁LED (如果PC0连接了LED)
    sbi DDRC, 0                ; 设置PC0为输出(连接LED)
success:
    sbi PORTC, 0               ; 点亮LED(PC0输出高电平)
    ldi r16, 100               ; 设置延时100ms
    rcall delay_ms             ; 调用延时子程序
    cbi PORTC, 0               ; 熄灭LED(PC0输出低电平)
    ldi r16, 100               ; 设置延时100ms
    rcall delay_ms             ; 调用延时子程序
    rjmp success               ; 无限循环闪烁LED

; =============================================
; 显示测试结果
; =功能:显示SRAM测试的详细结果和验证状态
; =============================================
display_test_result:
    ; 显示地址信息
    ldi ZL, low(2*msg_addr)    ; 加载"地址:"字符串地址低字节
    ldi ZH, high(2*msg_addr)   ; 加载"地址:"字符串地址高字节
    rcall uart_puts            ; 发送地址标签字符串

    ; 显示24位地址(高字节→中字节→低字节)
    lds r16, addr_high         ; 加载地址高字节
    rcall uart_puthex          ; 以十六进制显示高字节
    lds r16, addr_mid          ; 加载地址中字节
    rcall uart_puthex          ; 以十六进制显示中字节
    lds r16, addr_low          ; 加载地址低字节
    rcall uart_puthex          ; 以十六进制显示低字节

    ; 显示写入的数据
    ldi ZL, low(2*msg_write)   ; 加载"写入:"字符串地址低字节
    ldi ZH, high(2*msg_write)  ; 加载"写入:"字符串地址高字节
    rcall uart_puts            ; 发送写入标签字符串

    lds r16, write_data        ; 加载之前写入的数据
    rcall uart_puthex          ; 以十六进制显示写入的数据

    ; 显示读取的数据
    ldi ZL, low(2*msg_read)    ; 加载"读取:"字符串地址低字节
    ldi ZH, high(2*msg_read)   ; 加载"读取:"字符串地址高字节
    rcall uart_puts            ; 发送读取标签字符串

    lds r16, read_data         ; 加载从SRAM读取的数据
    rcall uart_puthex          ; 以十六进制显示读取的数据

    ; 验证测试结果:比较写入和读取的数据
    lds r17, write_data        ; 重新加载写入的数据到r17
    lds r18, read_data         ; 加载读取的数据到r18
    cp r17, r18                ; 比较两个数据(r17 - r18)
    breq test_ok               ; 如果相等(Z=1),跳转到成功处理

    ; 测试失败处理
    ; 写入和读取的数据不匹配
    ldi ZL, low(2*msg_fail)    ; 加载"失败"字符串地址低字节
    ldi ZH, high(2*msg_fail)   ; 加载"失败"字符串地址高字节
    rcall uart_puts            ; 发送失败信息
    ret                        ; 返回主程序

; 测试成功处理
test_ok:
    ; 写入和读取的数据完全匹配
    ldi ZL, low(2*msg_ok)      ; 加载"成功"字符串地址低字节
    ldi ZH, high(2*msg_ok)     ; 加载"成功"字符串地址高字节
    rcall uart_puts            ; 发送成功信息
    ret                        ; 返回主程序
; =============================================
; UART子程序
; UART串口通信相关功能子程序
; =============================================

; UART初始化子程序
; 功能:设置UART波特率、数据帧格式和使能发送
uart_init:
    ldi r16, low(UBRR_VAL)      ; 加载波特率分频值的低字节
    out UBRRL, r16             ; 写入波特率低字节寄存器
    ldi r16, high(UBRR_VAL)     ; 加载波特率分频值的高字节
    out UBRRH, r16             ; 写入波特率高字节寄存器
    ldi r16, (1<<TXEN)         ; 设置TXEN位(发送使能)
    out UCSRB, r16             ; 写入UART控制状态寄存器B
    ldi r16, (1<<URSEL)|(1<<UCSZ1)|(1<<UCSZ0) ; 设置URSEL(选择UCSRC)、8位数据位
    out UCSRC, r16             ; 写入UART控制状态寄存器C
    ret                        ; 返回

; 发送单个字符子程序
; 输入:r16 - 要发送的字符
uart_putchar:
    sbis UCSRA, UDRE           ; 跳过下条指令如果UDR空(UDRE=1)
    rjmp uart_putchar          ; UDR未空,继续等待
    out UDR, r16               ; UDR已空,发送字符
    ret                        ; 返回

; 发送字符串子程序
; 输入:Z指针 - 指向程序存储器中的字符串(以null结尾)
uart_puts:
    lpm r16, Z+                ; 从程序存储器加载字符并递增Z指针
    tst r16                    ; 测试字符是否为0
    breq uart_puts_end         ; 如果是0,字符串结束
    rcall uart_putchar         ; 发送当前字符
    rjmp uart_puts             ; 继续发送下一个字符
uart_puts_end:
    ret                        ; 返回

; 发送回车换行子程序
; 功能:发送CR(回车)和LF(换行)序列
uart_crlf:
    ldi ZL, low(2*msg_crlf)    ; 加载回车换行字符串地址低字节
    ldi ZH, high(2*msg_crlf)   ; 加载回车换行字符串地址高字节
    rcall uart_puts            ; 发送回车换行字符串
    ret                        ; 返回

; 发送十六进制数字子程序
; 输入:r16 - 要发送的字节(以十六进制形式发送两个字符)
uart_puthex:
    push r16                   ; 保存原始值
    swap r16                   ; 交换高低4位
    andi r16, 0x0F            ; 屏蔽高4位,保留低4位
    rcall hex_to_ascii         ; 转换为ASCII字符
    rcall uart_putchar         ; 发送高4位对应的字符
    pop r16                    ; 恢复原始值
    andi r16, 0x0F            ; 屏蔽高4位,保留低4位
    rcall hex_to_ascii         ; 转换为ASCII字符
    rcall uart_putchar         ; 发送低4位对应的字符
    ret                        ; 返回

; 十六进制到ASCII转换子程序
; 输入:r16 - 十六进制数字(0-15)
; 输出:r16 - 对应的ASCII字符
hex_to_ascii:
    cpi r16, 10                ; 比较数字是否小于10
    brlo hex_digit             ; 如果小于10,跳转到数字处理
    subi r16, -('A'-10)        ; 大于等于10,转换为'A'-'F'
    ret                        ; 返回
hex_digit:
    subi r16, -'0'             ; 小于10,转换为'0'-'9'
    ret                        ; 返回
; =============================================
; SPI子程序
; =SPI总线通信和SRAM操作相关子程序
; =============================================

; SPI初始化子程序
; 功能:配置SPI引脚方向和SPI控制寄存器
spi_init:
    sbi DDRB, MOSI_PIN         ; 设置MOSI引脚为输出
    sbi DDRB, SCK_PIN          ; 设置SCK时钟引脚为输出
    sbi DDRB, SRAM_CS          ; 设置SRAM片选引脚为输出
    cbi DDRB, MISO_PIN         ; 设置MISO引脚为输入
    sbi PORTB, SRAM_CS         ; 拉高SRAM片选(不选中)
    ldi r16, (1<<SPE)|(1<<MSTR)|(1<<SPR0) ; 使能SPI、主机模式、时钟分频
    out SPCR, r16              ; 写入SPI控制寄存器
    ret                        ; 返回

; SPI数据传输子程序
; 功能:通过SPI发送和接收一个字节
; 输入:r16 - 要发送的数据
; 输出:r16 - 接收到的数据
spi_transfer:
    out SPDR, r16              ; 启动SPI传输,写入数据到SPI数据寄存器
spi_wait:
    in r16, SPSR               ; 读取SPI状态寄存器
    sbrs r16, SPIF             ; 跳过下条指令如果传输完成(SPIF=1)
    rjmp spi_wait              ; 传输未完成,继续等待
    in r16, SPDR               ; 传输完成,读取接收到的数据
    ret                        ; 返回

; SRAM初始化子程序
; 功能:初始化SPI接口并配置SRAM工作模式
sram_init:
    rcall spi_init             ; 初始化SPI接口
    cbi PORTB, SRAM_CS         ; 拉低SRAM片选(选中芯片)
    ldi r16, CMD_WRSR          ; 加载写状态寄存器命令
    rcall spi_transfer         ; 发送命令
    ldi r16, MODE_SEQ          ; 加载顺序模式配置值
    rcall spi_transfer         ; 发送模式配置
    sbi PORTB, SRAM_CS         ; 拉高SRAM片选(取消选中)
    ldi r16, 10                ; 设置延时10ms
    rcall delay_ms             ; 调用延时子程序
    ret                        ; 返回

; SRAM写字节子程序
; 功能:向SRAM指定地址写入一个字节数据
; 输入:addr_high, addr_mid, addr_low - 24位地址
;       write_data - 要写入的数据
sram_write_byte:
    cbi PORTB, SRAM_CS         ; 拉低SRAM片选(选中芯片)
    ldi r16, CMD_WRITE         ; 加载写命令
    rcall spi_transfer         ; 发送写命令
    lds r16, addr_high         ; 加载地址高字节
    rcall spi_transfer         ; 发送地址高字节
    lds r16, addr_mid          ; 加载地址中字节
    rcall spi_transfer         ; 发送地址中字节
    lds r16, addr_low          ; 加载地址低字节
    rcall spi_transfer         ; 发送地址低字节
    lds r16, write_data        ; 加载要写入的数据
    rcall spi_transfer         ; 发送数据字节
    sbi PORTB, SRAM_CS         ; 拉高SRAM片选(取消选中)
    ldi r16, 5                 ; 设置延时5ms
    rcall delay_ms             ; 调用延时子程序
    ret                        ; 返回

; SRAM读字节子程序
; 功能:从SRAM指定地址读取一个字节数据
; 输入:addr_high, addr_mid, addr_low - 24位地址
; 输出:read_data - 读取到的数据
sram_read_byte:
    cbi PORTB, SRAM_CS         ; 拉低SRAM片选(选中芯片)
    ldi r16, CMD_READ          ; 加载读命令
    rcall spi_transfer         ; 发送读命令
    lds r16, addr_high         ; 加载地址高字节
    rcall spi_transfer         ; 发送地址高字节
    lds r16, addr_mid          ; 加载地址中字节
    rcall spi_transfer         ; 发送地址中字节
    lds r16, addr_low          ; 加载地址低字节
    rcall spi_transfer         ; 发送地址低字节
    ldi r16, 0x00              ; 加载哑元数据用于接收
    rcall spi_transfer         ; 发送哑元数据并接收SRAM数据
    sts read_data, r16         ; 保存读取到的数据
    sbi PORTB, SRAM_CS         ; 拉高SRAM片选(取消选中)
    ret                        ; 返回
; =============================================
; 延时子程序
; =功能:提供精确的微秒和毫秒级延时
; =============================================

; 毫秒延时子程序
; 输入:r16 - 延时的毫秒数
; 使用寄存器:r16, r17, r18
delay_ms:
    push r17                   ; 保存r17寄存器
    push r18                   ; 保存r18寄存器
delay_ms_outer:
    ldi r17, 200               ; 设置外层循环计数器(200次)
delay_ms_inner:
    ldi r18, 250               ; 设置内层循环计数器(250次)
delay_ms_inner2:
    dec r18                    ; 内层循环递减
    brne delay_ms_inner2       ; 内层循环未结束则继续
    dec r17                    ; 外层循环递减
    brne delay_ms_inner        ; 外层循环未结束则继续
    dec r16                    ; 毫秒计数器递减
    brne delay_ms_outer        ; 未达到指定毫秒数则继续
    pop r18                    ; 恢复r18寄存器
    pop r17                    ; 恢复r17寄存器
    ret                        ; 返回

; 微秒延时子程序
; 输入:r16 - 延时的微秒数
; 注意:基于1MHz时钟,每个循环约4个时钟周期=4微秒
; 实际延时时间 = (r16 * 4) 微秒
delay_us:
    nop                        ; 空操作(1周期)
    nop                        ; 空操作(1周期)
    nop                        ; 空操作(1周期)
    dec r16                    ; 计数器递减(1周期)
    brne delay_us              ; 不为零则跳转(2周期为零跳转/1周期继续)
    ret                        ; 返回
; =============================================
; 程序结束
; =============================================

评分

参与人数 2黑币 +80 收起 理由
admin + 50 共享资料的奖励!
wpppmlah + 30 赞一个!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏1 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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