動態分配對於AVR來說並不是一個好主意,不是因爲它是一個8位MCU,而是因爲潛在的棧堆衝突。上面的問題是你有一個全局的char *,並且是全局的,它被初始化爲NULL
[這是C標準的一部分,你無法控制這個,它由最終可執行文件的__do_clear_bss
部分完成]。當你在這個NULL
指針上做strcpy()
這一刻,你就開始寫地址0了。現在,如果這是一臺x86機器,並且你正在應用程序級別工作,那麼軟件會因爲分段錯誤而崩潰。 AVR中沒有存儲器保護,因此strcpy()
將開始將字符串複製到RAM中的地址0。如果使用絕對地址,這就直接進入寄存器文件,這意味着任何在這些寄存器上被緩存的變量現在都被丟棄了。考慮一下這個測試案例:
#include <string.h>
int main(void) {
char p[] = "hello";
strcpy(0, p);
while(1);
}
其編譯成:如果與AVR-gcc版本4.8.2,並調用與avr-gcc -O3 -mmcu=atmega168 -o avr.elf avr.c
從手動設置的AVR指令編譯器完成
-- snip --
00000096 <main>:
-- snip --
a0: cd b7 in r28, 0x3d ; 61
a2: de b7 in r29, 0x3e ; 62
a4: 86 e0 ldi r24, 0x06 ; 6
a6: e0 e0 ldi r30, 0x00 ; 0
a8: f1 e0 ldi r31, 0x01 ; 1
aa: de 01 movw r26, r28
ac: 11 96 adiw r26, 0x01 ; 1
ae: 01 90 ld r0, Z+
b0: 0d 92 st X+, r0
b2: 8a 95 dec r24
b4: e1 f7 brne .-8 ; 0xae <main+0x18>
b6: be 01 movw r22, r28
b8: 6f 5f subi r22, 0xFF ; 255
ba: 7f 4f sbci r23, 0xFF ; 255
bc: 80 e0 ldi r24, 0x00 ; 0
be: 90 e0 ldi r25, 0x00 ; 0
c0: 0e 94 63 00 call 0xc6 ; 0xc6 <strcpy>
-- snip --
000000c6 <strcpy>:
c6: fb 01 movw r30, r22
c8: dc 01 movw r26, r24
ca: 01 90 ld r0, Z+
cc: 0d 92 st X+, r0
ce: 00 20 and r0, r0
d0: e1 f7 brne .-8 ; 0xca <strcpy+0x4>
d2: 08 95 ret
, st指令說: 「存儲一個字節間接有或沒有從寄存器到數據空間的位移對於具有SRAM的部分,數據空間由寄存器文件,I/O存儲器和內部SRAM(以及外部SRAM,如果適用)組成, 。對於沒有SRAM的部件,數據空間僅由註冊文件組成。「
其證實了上述情況。很明顯,編譯器並不知道你拋棄了這些寄存器,並且很樂意將它們用於其他事情,甚至進一步摧毀它們。在strcpy()之後從它們中讀取也會產生問題。您可以通過創建一個緩衝區來解決問題,如果您希望它是全局的,則可以使用char message[8];
。由於它是一個全局變量,因此所有元素都會自動初始化爲0.至於您的數據爲什麼會被刪除,我將不得不查看更多的代碼來確定原因。儘管如此,很可能是由於內存損壞。
乾杯。
現在,刪除最後一行一切似乎都恢復正常。無線電干擾的串口線?我不確定。很明顯'message = serialOut'也會導致垃圾泄露。那麼,如何在代碼中稍後使用'serialOut'到'message'來複制? – Madivad
我真的沒有得到的是爲什麼使用memcpy,memmove,strcpy後'serial.println'導致錯誤數據被髮送出去,這是我的問題的癥結 – Madivad