2021-10-09

將程式寫入到 AT89S52

最近在解體一些古老電子產品時發一塊 AT89S52晶片,是一款常見的 微控制器晶片
AT89S52 是可以載入 Assembly, C 程式的微控制器晶片,既然又有「新」玩具,當然要玩一番

AT89S52晶片 外觀

見下文
見下文
AT89S52晶片 正面
寫著 AT89S52 24PU 1032A ,當中的 24PU 是標示晶片的規格
24 表示晶片最高支援 24MHz 時脈速度
P 是晶片封裝代號
  • P 表示 雙列直插封裝 (Dual In-line Package (DIP))
  • A 表示 薄方型扁平式封裝技術 (Thin Quad Flat Package (TQFP))
  • J 表示 塑料電極晶片載體 (Plastic Leaded Chip Carrier (PLCC))
U 是晶片運作級別
  • C 表示 商業級 (Commercial)
  • I 表示 有鉛工業級 (Industry)
  • U 表示 無鉛工業級 (Unleaded Industry)
(AT89S52 表面有些微破損,但仍能夠運作)

見下文
AT89S52晶片 背面

AT89S52晶片 引腳

引腳 編號 編號 引腳
T2 / P1.0 1 40 VCC (5V)
T2 EX / P1.1 2 39 P0.0 / A0
P1.2 3 38 P0.1 / A1
P1.3 4 37 P0.2 / A2
P1.4 5 36 P0.3 / A3
MOSI / P1.5 6 35 P0.4 / A4
MISO / P1.6 7 34 P0.5 / A5
SCK / P1.7 8 33 P0.6 / A6
RST 9 32 P0.7 / A7
Rx / P3.0 10 31 EV / VPP
Tx / P3.1 11 30 ALE / PROG
INT0 / P3.2 12 29 PSEN
INT1 / P3.3 13 28 P2.7 / A15
T0 / P3.4 14 27 P2.6 / A14
T1 / P3.5 15 26 P2.5 / A13
WR / P3.6 16 25 P2.4 / A12
RD / P3.7 17 24 P2.3 / A11
C0 18 23 P2.2 / A10
C1 19 22 P2.1 / A9
GND 20 21 P2.0 / A8

編號 引腳 方向 用途
1 P1.0 / T2 輸入/輸出 Port 1 第0位元;第2計時器
2 P1.1 / T2 EX 輸入/輸出 Port 1 第1位元;第2計時器
3 P1.2 輸入/輸出 Port 1 第2位元
4 P1.3 輸入/輸出 Port 1 第3位元
5 P1.4 輸入/輸出 Port 1 第4位元
6 P1.5 / MOSI 輸入/輸出 Port 1 第5位元;ISP 編程時用的 MOSI
7 P1.6 / MISO 輸入/輸出 Port 1 第6位元;ISP 編程時用的 MISO
8 P1.7 / SCK 輸入/輸出 Port 1 第7位元;ISP 編程時用的 SCK
9 RST 輸入 高電壓時,重設所有 Port;低電壓時,啟動所有 Port
10 P3.0 / Rx 輸入/輸出 Port 3 第0位元;序列輸入
11 P3.1 / Tx 輸入/輸出 Port 3 第1位元;序列輸出
12 P3.2 / INT0 輸入/輸出 Port 3 第2位元;第0中斷器
13 P3.3 / INT1 輸入/輸出 Port 3 第3位元;第1中斷器
14 P3.4 / T0 輸入/輸出 Port 3 第4位元;第0計時器
15 P3.5 / T1 輸入/輸出 Port 3 第5位元;第1計時器
16 P3.6 / WR 輸入/輸出 Port 3 第6位元;將資料寫入記憶體
17 P3.7 / RD 輸入/輸出 Port 3 第7位元;從記憶體讀取資料
18 C0 連接到 石英晶體振盪器
19 C1 連接到 石英晶體振盪器
20 GND 接地
21 P2.0 / A8 輸入/輸出 Port 2 第0位元 / 第8類比
22 P2.1 / A9 輸入/輸出 Port 2 第1位元 / 第9類比
23 P2.2 / A10 輸入/輸出 Port 2 第2位元 / 第10類比
24 P2.3 / A11 輸入/輸出 Port 2 第3位元 / 第11類比
25 P2.4 / A12 輸入/輸出 Port 2 第4位元 / 第12類比
26 P2.5 / A13 輸入/輸出 Port 2 第5位元 / 第13類比
27 P2.6 / A14 輸入/輸出 Port 2 第6位元 / 第14類比
28 P2.7 / A15 輸入/輸出 Port 2 第7位元 / 第15類比
29 PSEN 輸入 高電壓為啓用程式儲存,讀取外部儲存空間
30 ALE 輸入 高電壓為啓用地址鎖存,將地址總線儲存到 A0 至 A7 中
31 EA / VPP 輸入 高電壓時,使用 5V 編程;低電壓時,使用 12V 編程
32 P0.7 / A7 輸入/輸出 Port 0 第7位元 / 第7類比
33 P0.6 / A6 輸入/輸出 Port 0 第6位元 / 第6類比
34 P0.5 / A5 輸入/輸出 Port 0 第5位元 / 第5類比
35 P0.4 / A4 輸入/輸出 Port 0 第4位元 / 第4類比
36 P0.3 / A3 輸入/輸出 Port 0 第3位元 / 第3類比
37 P0.2 / A2 輸入/輸出 Port 0 第2位元 / 第2類比
38 P0.1 / A1 輸入/輸出 Port 0 第1位元 / 第1類比
39 P0.0 / A0 輸入/輸出 Port 0 第0位元 / 第0類比
40 VCC 接收 4V 至 6V 電源輸入

使用 Arduino UNO

AT89S52 的 S 表示能通過 系統中編程 (In-System Programming (ISP))
因此可以使用 Arduino UNO 當作 ISP 將程式寫入至 AT89S52
可以參考 https://hkgoldenmra.blogspot.com/2020/02/bootloader-atmega328p.html 製作 Arduino ISP 的方法

線路原型

見下文
Arduino UNO AT89S52 接駁電子零件
5V VCC (40)
5V EA (31)
GND GND (20)
C0 (18) C1 (19) 11.0592 MHz 石英晶體振盪器
GND C0 (18) 30pF 陶瓷電容器
GND C1 (19) 30pF 陶瓷電容器
SS (10) RST (9)
SCK (13) SCK (8)
MOSI (12) MISO (7)
MISO (11) MOSI (6)

接駁線路

見下文
見下文
使用跳線接駁將 Arduino 的 5V 連接到 AT89S52 的 VCC (第40引腳) 及 EA (第31引腳)

見下文
將 Arduino 的 GND 連接到 AT89S52 的 GND (第20引腳)
11.0592 MHz 石英晶體振盪器 連接 AT89S52 的 C0 (第18引腳) 及 C1 (第19引腳)
以 2粒 30uF陶瓷電容器 分別將 AT89S52 的 C0 及 C1 連接到 GND

見下文
見下文
將 Arduino 的 SS (第10引腳) 連接到 AT89S52 的 RST (第9引腳)
將 Arduino 的 SCK (第13引腳) 連接到 AT89S52 的 SCK (第8引腳)
將 Arduino 的 MOSI (第12引腳) 連接到 AT89S52 的 MISO (第7引腳)
將 Arduino 的 MISO (第10引腳) 連接到 AT89S52 的 MOSI (第6引腳)

見下文
實際線路

編寫程式

要將執行程式上載到 AT89S52 ,還需要 SDCC編譯器AVR設定檔
SDCC編譯器
AT89S52 的 C程式 與一般的 C程式 大致相同,只是編譯器不是使用一般的 C編譯器,而是使用 SDCC編譯器
SDCC 全名是 Small Device C Compiler ,是一種專門編譯 微控制器程式 的 C編譯器
在 Terminal 輸入
sudo apt install sdcc
按此安裝SDCC編譯器
#include <8052.h>

unsigned int i;

void main() {
	while (1) {
		// Port 1 bit 0
		P1_0 = 0;
		// delay
		for (i = 0; i < 50000; i++);
		P1_0 = 1;
		for (i = 0; i < 50000; i++);
	}
}
由於 AT89S52 屬於 8052 系列的晶片,因此需要載入 8052.h
不同系列的晶片需要載入不同系列的標頭檔案,編寫程式前需要了解有沒有相符合的標頭檔案
編寫後,以 SDCC編譯 程式,輸入
sdcc "test.c"

見下文
編譯後,會出現大量檔案,當中最重要的是 ihx檔案,是一種適用於 Intel CPU 的 十六進制檔案
如果晶片屬於 Intel 系列的 CPU ,可以將 ihx 寫入即可
但如果不支援 ihx ,便需要使用 packihx 將 ihx檔案 轉換成 hex檔案,輸入
packihx "test.ihx" >"test.hex"
(packihx 屬於 sdcc套件)

見下文
見下文
兩種檔案結構非常相似
AVR設定檔
將 十六進制檔案 寫入到 AT89S52 還需要 AVR工具,其實就是 Arduino 寫入資料到 Atmega328P 等晶片的 avrdude 指令
在 Terminal 輸入
sudo apt install avrdude
按此安裝 avrdude 除了 avrdude ,還要將 AT89S52(或對應的晶片)資料 儲存為設定檔案 (檔案類型並不重要)
# avr-at89s52.conf

part
	id = "at89s52";
	desc = "AT89S52";
	stk500_devcode = 0xE1;
	signature = 0x1e 0x52 0x06;
	chip_erase_delay = 500000;
	reset = dedicated;
	pgm_enable = "1 0 1 0 1 1 0 0 0 1 0 1 0 0 1 1", "x x x x x x x x x x x x x x x x";
	chip_erase = "1 0 1 0 1 1 0 0 1 0 0 x x x x x", "x x x x x x x x x x x x x x x x";
	memory "flash"
		size = 8192;
		read = "0 0 1 0 0 0 0 0 x x x a12 a11 a10 a9 a8", "a7 a6 a5 a4 a3 a2 a1 a0 o o o o o o o o";
		write = "0 1 0 0 0 0 0 0 x x x a12 a11 a10 a9 a8", "a7 a6 a5 a4 a3 a2 a1 a0 i i i i i i i i";
	;
	memory "signature"
		size = 3;
		read = "0 0 1 0 1 0 0 0 0 0 0 0 0 0 a1 a0", "0 0 0 0 0 0 0 0 o o o o o o o o";
	;
;

programmer
	id = "stk500v1";
	desc = "Atmel STK500 Version 1.x firmware";
	type = "stk500";
	connection_type = serial;
	baudrate = 19200;
;

寫入HEX檔案

見下文
檢查 ISP裝置 的位置,最簡單的方法是使用 Arduino IDE 來檢查
(能夠製作 Arduino ISP 即是有安裝 Arduino IDE)

見下文
但如果沒有 Arduino IDE ,可以輸入
ls -l /dev/serial/by-id
顯示所有序列裝置的對應位置
(原裝的 Arduino UNO 使用 /dev/ttyACM0)

見下文
確認所有資料後,可以輸入
avrdude -C "avr-at89s52.conf" -c stk500v1 -P /dev/ttyACM0 -p at89s52 -U flash:w:"test.ihx"
  • -C 為 AVR設定檔 的位置,例如在下的 avr-at89s52.conf
  • -c 為 燒錄器類型,大部分 Arduino 的 Bootloader 都是使用 stk500v1 (需要對應 AVR設定檔 的 programmer id)
  • -P 為 ISP裝置的位置,通常是 /dev/tty* 的位置
  • -p 為 寫入目標的類型 (需要對應 AVR設定檔 的 part id)
  • -U 為 上載參數,如果不需要執行其他操作,修改檔案名即可

見下文
測試效果

使用 FTDI 及 ATmega328P

由於 Arduino UNO 佔據空間,如果要方便寫入程式到 AT89S52 ,可以使用 ATmega328P 配合 FTDI模組
使用 FTDI模組 透過 ATmega328P 將程式寫入到 AT89S52

線路原型
見下文
FTDI ATmega328P AT89S52 接駁電子零件
5V VCC (7) VCC (40)
GND GND (8) GND (20)
C0 (9) C1 (10) 16 MHz 石英晶體振盪器
GND C0 (9) 22pF 陶瓷電容器
GND C1 (10) 22pF 陶瓷電容器
DTR RST (1) 100pF 陶瓷電容器
C0 (18) C1 (19) 11.0592 MHz 石英晶體振盪器
GND C0 (18) 30pF 陶瓷電容器
GND C1 (19) 30pF 陶瓷電容器
TXD RX (2)
RXD TX (3)
SS (10) RST (9)
SCK (13) SCK (8)
MOSI (12) MISO (7)
MISO (11) MOSI (6)

接駁線路
見下文
實際接駁線路

見下文
在下將先前的測試程式稍作修改
#include <8052.h>

unsigned int i;

void main() {
	while (1) {
		// Port 1 bit 0 to bit 7
		// 0x01 = B00000001
		// equal to 
		// P1_0 = 1
		// P1_1 = 0
		// P1_2 = 0
		// P1_3 = 0
		// P1_4 = 0
		// P1_5 = 0
		// P1_6 = 0
		// P1_7 = 0
		P1 = 0x01;
		// delay
		for (i = 0; i < 50000; i++);
		// 0x02 = B00000010
		// equal to 
		// P1_0 = 0
		// P1_1 = 1
		// P1_2 = 0
		// P1_3 = 0
		// P1_4 = 0
		// P1_5 = 0
		// P1_6 = 0
		// P1_7 = 0
		P1 = 0x02;
		for (i = 0; i < 50000; i++);
	}
}

總結

見下文
原裝 Arduino UNO 使用 /dev/ttyACM* 位置
而 FTDI模組 或 一些Arduino兼容模組 是使用 /dev/ttyUSB*

/dev/ttyUSB* 明顯就是 USB 相關的裝置,針對較單一功能的通訊協定
FTDI模組 上的 FT232 及 一些Arduino UNO兼容板 上的 CH340G ,主要提供 RS232 或 UART 等協定

而 /dev/ttyACM* 則是 通訊裝置類別 (Communication Device Class (CDC)) 中的 抽象控制模型 (Abstract Control Model (ACM))
針對較複雜功能的通訊協定,例如 Arduino UNO 上的 ATmega16U2 就是具備 USB 協定
亦因此 Arduino UNO 的 ATmega16U2 上有一組可以修改內容的 ICSP2 引腳

在應用上上其實並沒有太大分別,但成本差異則頗大
Arduino UNO 使用 ATmega16U2 大約 20美金
FT232R+ATmega328P 大約 10美金
Arduino UNO兼容板 使用 CH340G 大約 6美金

因此閣下可以考慮選擇使用哪種裝置將資料寫入到 AT89S52

參考資料

1 則留言 :