79.gif (605.63 KB, 下載次數: 0)
下載附件
2025-10-7 11:24 上傳
; =============================================
; 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 ; 返回
; =============================================
; 程序結束
; =============================================
|