這個作品是2013年無線電單片機競賽的亞軍。感謝所有支持這個作品的你們!
在對稱加密學當中,恩尼格碼機絕對是承前啓後的存在。它將密碼學研究從以前的語言文字學中心完全轉移到了數學身上。在這裏牽涉的密碼並不是我們平時郵箱、銀行帳號那種狹義概念,那種頂多叫做口令。這裏說的密碼就是通過某種轉換規律方式,把一篇文章變得面目全非,非常人能閱讀,以達到保密效果。這篇文章適於電腦控、軍事控、歷史控、數學控閱讀,請做好燒腦準備。【原址:】
主要材料:
1個Arduino Mega 2560板 | 26個字母按鍵 |
26個1/4英寸單通道母接口 | 10個1/4英寸單通道公接口 |
36個機械按鈕 | 1個單刀三擲開關 |
4個16段橙色LED顯示 | 4個注塑2升汽水瓶罩子 |
1個膠合板盒子 | 一個鉸鏈 |
一個半榫接鎖 | 一個接線盤 |
38個470歐電阻 | 40個1千歐電阻 |
7個IRF9Z24N P型晶體管 | 1塊金屬片 |
所需工具:
以及噴漆 |
製作步驟:
第1步:
在對稱加密學當中,恩尼格碼機絕對是承前啓後的存在。它將密碼學研究從以前的語言文字學中心完全轉移到了數學身上。在這裏牽涉的密碼並不是我們平時郵箱、銀行帳號那種狹義概念,那種頂多叫做口令。這裏說的密碼就是通過某種轉換規律方式,把一篇文章變得面目全非,非常人能閱讀,以達到保密效果。這篇文章適於電腦控、軍事控、歷史控、數學控閱讀,請做好燒腦準備。
這是我們的初號機。以下教程將手把手教你如何完美山寨史上著名的德國恩尼格瑪密碼機(以下稱啞謎機,不清楚歷史的可以到維基、百度等地方腦補一下)。這個基於Arduino的開源程序能夠加解密任何啞謎機M4型(海軍型)的信息。
這個第一臺全功能開源完美啞謎機複製品是根據sketchsk3tch寫的《Kid’s Game to Arduino Enigma Machine》(從兒童玩具到Arduino恩尼格瑪機)所作。
採用多路複用LED電路,僅用38個針腳的115個發光二極管和4個針腳的36個按鍵所連接的整個電路,全靠在鍵盤迴路里準確放置的電阻以及P型號晶體管得以實現。要不然,4個16段顯示器,以及每個按鍵上的LED將大幅增加所需針腳總量,即使用了Arduino Mega板但如果沒用上述兩個方法也不能如此簡潔。 面對電路的超額需求,我們在設計了專用的PCB板。直接跳到第10步和以後的步驟可以找到更多信息。同時,我們以測試過的完整電子組裝套裝發佈。
第2步:
麪包板上的論證
第3步:
在開始製作電子啞謎機之前,我們先要確保能驅動16段LED顯示。如果能的話,我們就能做接下來的所有步驟,除了數學上的問題,一切都是浮雲。
第4步:
萬事具備
第5步:
佈置零件
第6步:
第7步:
第8步:
第9步:
6*8寸無線電麪包版是最合適放置所有元件的,既不多餘也不擁擠,而且和啞謎機盒子內部完美吻合。
最初我們將麪包等分三塊區域,但很快意識到如此一來,電子版啞謎機將比原版機械啞謎機長。於是我們將所有零件縮放到正好夠佔用的空間。
每個元件位置就緒,下一步就是焊接。
第10步:
第11步:
我焊,我焊,我焊焊焊……
第12步:
第13步:
第14步:
第15步:
第16步:
好吧,在單一作品身上,我從沒焊接如此多次。16段顯示的18個針腳,還有26個字母鍵乘以每個4個腳,外加26個鍵盤燈,一些其他LED,一個三擲開關,真乃“成吉思焊”。
當初我們的決定是使這些16段LED顯示看起來像老式電子管的感覺,增加了不少焊點,“巨焊”!
Arduino Mega板上針腳的分配: 17段:
第17步:
第18步:
第19步:
在原版M4型木盒內得到確定位置數據後,我們買了一塊膠合板,將它切塊,然後砌盒子。
我們從舊服務器機架上卸了一塊鋼板,厚度正合需要。將模具(上面早已畫好每個按鍵和燈位,並切好了洞洞)蓋在鋼板上,然後用記號筆畫出需要切出的洞洞。
接着,我們用噴漆把它塗黑,就像真的啞謎機那樣。
第20步:
組裝測試
第21步:
第22步:
第23步:
第24步:
第25步:
第26步:
首先把金屬板在麪包版上永久固定,確保所有按鍵正常工作,所有LED都能發光。
接着就是把這一大坨東東裝入木盒,確保沒有空隙位置。
第27步:
第28步:
在組裝硬件過程中,我們也寫了個小型Arduino程序框架,用以測試特定幾個需要關注的部分:
用來測試每個按鍵信號能準確讀取,還有測試10個功能按鍵的代碼。
Enigma_POST(上電自檢)確保在每種模式下所有鍵盤等都能準確亮起,在每種模式下每個LED信號都能傳送。我們對原本麪包板上的代碼做了修正,確保4個16段LED顯示的每個部件無懈可擊。
但,即使所有手上的程序片段都說明機器狀態完好,重現M4海軍型啞謎機加解密功能,數學方面居功至偉。
所有Arduino程序片段在我們剛剛建好的雲端都能找到。
以下是Enigma_POST程序片段(上電自檢):
/* Enigma Development Code to Test each of the 4 Nixies, the 5 LEDs,
then Turn On each Lamp in sequence.
Written by Marc Tessier & James Sanderson 9/8/13
*/
// Define the 16-Segments Pins
int segment[17] = {24,22,25,31,38,36,32,30,28,26,23,27,33,35,34,29,37};
int anode[4] = {39,41,43,45};
// Define the 9 lamps Pins
int lamp[9] = {10,9,8,7,6,5,4,3,2};
int lanode[3] = {11,12,13};
// LTP587P Segments: A,B,C,D,E,F,G,H,K,M,N,P,R,S,T,U,dp
boolean segmentvals[39][17] = { { 0,0,0,0,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = A
{ 0,0,0,0,0,0,1,1,1,0,1,0,1,0,1,1,1 }, // = B
{ 0,0,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = C
{ 0,0,0,0,0,0,1,1,1,0,1,1,1,0,1,1,1 }, // = D
{ 0,0,1,1,0,0,0,0,1,1,1,0,1,1,1,0,1 }, // = E
{ 0,0,1,1,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = F
{ 0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,1,1 }, // = G
{ 1,1,0,0,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = H
{ 0,0,1,1,0,0,1,1,1,0,1,1,1,0,1,1,1 }, // = I
{ 1,1,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1 }, // = J
{ 1,1,1,1,1,1,0,0,1,1,0,1,0,1,1,0,1 }, // = K
{ 1,1,1,1,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = L
{ 1,1,0,0,1,1,0,0,0,1,0,1,1,1,1,1,1 }, // = M
{ 1,1,0,0,1,1,0,0,0,1,1,1,0,1,1,1,1 }, // = N
{ 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = O
{ 0,0,0,1,1,1,0,0,1,1,1,0,1,1,1,0,1 }, // = P
{ 0,0,0,0,0,0,0,0,1,1,1,1,0,1,1,1,1 }, // = Q
{ 0,0,0,1,1,1,0,0,1,1,1,0,0,1,1,0,1 }, // = R
{ 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0,1 }, // = S
{ 0,0,1,1,1,1,1,1,1,0,1,1,1,0,1,1,1 }, // = T
{ 1,1,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1 }, // = U
{ 1,1,1,1,1,1,0,0,1,1,0,1,1,1,0,1,1 }, // = V
{ 1,1,0,0,1,1,0,0,1,1,1,1,0,1,0,1,1 }, // = W
{ 1,1,1,1,1,1,1,1,0,1,0,1,0,1,0,1,1 }, // = X
{ 1,1,1,1,1,1,1,1,0,1,0,1,1,0,1,1,1 }, // = Y
{ 0,0,1,1,0,0,1,1,1,1,0,1,1,1,0,1,1 }, // = Z
{ 0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,1,1 }, // = 0
{ 1,1,0,0,1,1,1,1,1,1,0,1,1,1,1,1,1 }, // = 1
{ 0,0,0,1,0,0,0,1,1,1,1,0,1,1,1,0,1 }, // = 2
{ 0,0,0,0,0,0,1,1,1,1,1,0,1,1,1,1,1 }, // = 3
{ 1,1,0,0,1,1,1,0,1,1,1,0,1,1,1,0,1 }, // = 4
{ 0,0,1,0,0,0,1,0,1,1,1,0,1,1,1,0,1 }, // = 5
{ 0,0,1,0,0,0,0,0,1,1,1,0,1,1,1,0,1 }, // = 6
{ 0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1 }, // = 7
{ 0,0,0,0,0,0,0,0,1,1,1,0,1,1,1,0,1 }, // = 8
{ 0,0,0,0,0,0,1,0,1,1,1,0,1,1,1,0,1 }, // = 9
{ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1 }, // = Space
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, // = Full Lit
{ 1,0,1,0,1,0,1,0,1,0,1,0,1,0,1,0,1 } // = SS
};
// LTP587P Segments: A,B,C,D,E,F,G,H,K,M,N,P,R,S,T,U,dp
boolean lampvals[9][9] = { { 0,1,1,1,1,1,1,1,1 }, // = Q or A or P
{ 1,0,1,1,1,1,1,1,1 }, // = W or S or Y
{ 1,1,0,1,1,1,1,1,1 }, // = E or D or X
{ 1,1,1,0,1,1,1,1,1 }, // = R or F or C
{ 1,1,1,1,0,1,1,1,1 }, // = T or G or V
{ 1,1,1,1,1,0,1,1,1 }, // = Z or H or B
{ 1,1,1,1,1,1,0,1,1 }, // = U or J or N
{ 1,1,1,1,1,1,1,0,1 }, // = I or K or M
{ 1,1,1,1,1,1,1,1,0 } // = O or L
};
int value_row1 = 0;
int value_row2 = 0;
int value_row3 = 0;
char key = 91;
int led1 = 40;
int led2 = 42;
int led3 = 44;
int led4 = 46;
int led5 = 48;
int wait = 100;
void setup() {
for (int index = 0 ; index <= 3; index++) {
pinMode (anode[index], OUTPUT);
digitalWrite (anode[index], 1);
}
for (int index = 0 ; index <= 16; index++) {
pinMode (segment[index], OUTPUT);
digitalWrite (segment[index], 1);
}
// initialize the digital pins as an output.
pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);
pinMode(led4, OUTPUT);
pinMode(led5, OUTPUT);
for (int index = 0 ; index <= 2; index++) {
pinMode (lanode[index], OUTPUT);
digitalWrite (lanode[index], 1);
}
for (int index = 0 ; index <= 8; index++) {
pinMode (lamp[index], OUTPUT);
digitalWrite (lamp[index], 1);
}
}
void loop() {
sixteenSegWrite(0, 38);
sixteenSegWrite(1, 38);
sixteenSegWrite(2, 38);
sixteenSegWrite(3, 38);
digitalWrite(led1, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led1, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second
digitalWrite(led2, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led2, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second
digitalWrite(led3, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led3, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second
digitalWrite(led4, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led4, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second
digitalWrite(led5, HIGH); // turn the LED on (HIGH is the voltage level)
delay(200); // wait for a second
digitalWrite(led5, LOW); // turn the LED off by making the voltage LOW
delay(wait); // wait for a second
for (int index = 0 ; index <= 2; index++) {
digitalWrite (lanode[index], 0);
for (int mychar = 0; mychar < 9; mychar++) {
for (int sindex = 0; sindex < 9; sindex++) {
digitalWrite(lamp[sindex], lampvals[mychar][sindex]);
delay (30);
}
}
digitalWrite (lanode[index], 1);
}
}
void sixteenSegWrite(int digit, int character) {
digitalWrite(anode[digit],0);
for (int index = 0; index < 17; index++) {
digitalWrite(segment[index], segmentvals[character][index]);
}
}
第29步:
第30步:
第31步:
第32步:
第33步:
第34步:
第35步:
第36步:
第37步:
首先,我們寫了個函數,給每個啞謎機工作模式用。
在模式0、默認模式,啞謎機僅僅是一臺普通打字機,以跑馬燈方式顯示它的型號。
模式1下,允許用戶從八個轉子中選取三個,兩個反射器中選擇一個進行使用。
模式2下,允許用戶排列轉子次序。
模式3用於自定義轉子初始字母排列。
選擇模式4,用戶最多可以使用接線板上10對交換字母排列。
模式5是運行模式,此時啞謎機能加解密任何從鍵盤錄入的信息。
如果有足夠利潤,我們將研發印刷電路板,裝載更容易組裝的全功能啞謎機複製品。
第38步:
電路圖
第39步:
徇衆要求,電路圖兩份在此。
第一個是仿電子管(4個16段顯示單元)如何佈線,用於顯示轉子在啞謎機上的輸出信號。同時,它們也用於每種調試模式,反饋用戶機器設定信息。
第二幅電路圖顯示26個字母按鍵及10個功能鍵、26個鍵盤燈和5個LED是如何佈線的。
所有LED電阻都是470歐,而開關電阻則都是1千歐。 印刷電路設計檔仍在修正中。 希望您享受我們第一份製作教程,感謝您抽出寶貴時間閱讀!
第40步:
PCB樣機版
第41步:
徇衆要求,我們設計及定製了一些印刷電路板。
它們終於面世了,如此清純可愛!我們忙於組裝,並測試其中一塊樣品,確保它在功能上與外觀一樣完美無暇。更重要的是,能和那臺原型測試機一樣的功能。 訂購回來的底板幾乎完美,只需一點引腳線去修補設計瑕疵。而這些瑕疵對功能沒有影響,修理它們是小菜一碟。 有了這些引腳,你能更容易製作自己的啞謎復刻機,比起教程裏的佈線方便多了。我們在此很高興宣佈,測試完成,新型板一樣給力!
第42步:
組裝完成的作品
第43步:
第44步:
第45步:
第46步:
第47步:
花了一晚上組裝完成
小貼士:
原址: