# 発表レポート 第1班
k17001 青木 結汰
k17004 天野 樹
k17006 天野 巧巳
## 1.制作動機
ポケベルがサービス終了するので自分でポケベルを真似て改良してみようと考え、制作に至った。
## 2.作品概要
キーボードから入力してメッセージを送り合う装置である。
シリアルモニタからメッセージをマイコンに送り、bluetooth通信でマイコン間にメッセージを送信する。
受信したメッセージはモニタで確認できる。
画面上は現在のモードを、画面下はメッセージを出力する。
モニタ出力のイメージを図1に示す。

図1. 出力イメージ図
起動するとコマンドモードになり、キーボードからのコマンド入力に応じて、モードを受信、送信、編集、削除、確認に切り替えることができる。各モードの内容を表1に示す。また、メッセージの受信や未送信メッセージの存在などで、アイコンが点滅するようになっている。その状態を表2、表3に示す。
表1.コマンド一覧
|コマンド入力|モード|内容|
|:--:|:--:|:--:|
|O|受信|受信したメッセージを表示|
|S|送信|編集したメッセージを送信|
|W|編集|送信するメッセージを編集|
|R|削除|編集中のメッセージを削除|
|P|確認|編集したメッセージを表示|
|C|コマンド|コマンド入力の受付|
それぞれのモードの詳細な動作を以下に示す。
#### 受信モード(オープンモード)
「O」を入力すると遷移する。
上段にCommand Modeと表示する。
下段に受信したメッセージを表示する。
「C」を入力するとコマンドモードに戻る。
#### 送信モード(センドモード)
「S」を入力すると遷移し、メッセージを送信する。
上段にsend Modeと表示する。
送るメッセージがない場合下段にNot found messageと表示する。
送信できたら「complete」と表示し鉛筆マークを消灯する。
「C」を入力するとコマンドモードに戻る
#### 編集モード(ライトモード)
「W」を入力すると遷移する。
送信するメッセージを新規作成、編集する。
編集モードのときは鉛筆マークが点滅している。
64文字まで入力できるが、表示できるのは16文字まである。
編集後、enterでコマンドモードに戻る。
#### 削除モード(リセットモード)
「R」を入力すると遷移する。
送信するメッセージを削除する。
上段にreset Modeと表示する。
「C」を入力するとコマンドモードに戻る。
#### 確認モード(プレビューモード)
「P」を入力すると遷移する。
送信するメッセージを下段に表示する。
上段にPreview Modeと表示する。
「C」を入力するとコマンドモードに戻る。
#### コマンドモード
基本的に、それぞれのモードで「C」を入力すると遷移する初期状態である。
モード遷移のためのコマンドを受け付けている
#### 画面表示
表2.メールマークによる状態表示
|表示状態|内容|
|:--:|:--:|
|消灯時|受信メッセージはありません|
|点灯時|受信メッセージは全て既読です|
|点滅時|未読のメッセージがあります|
表3.鉛筆マークによる状態表示
|表示状態|内容|
|:--:|:--:|
|消灯時|編集中のメッセージはありません|
|点灯時|メッセージを編集中です|
|点滅時|未送信のメッセージがあります|
## 3.使用部品
入力 Bluetoothモジュール RN42-I/RM
無線通信をする際に使う通信モジュールである。
通信距離は~30mである[1]。
ピン配置を図2に示す。

図2.Bluetoothモジュールのピン配置
出力 OLCDディスプレイ SEL10016G
有機ELを使用したディスプレイであり、文字が光って表示されるため、視認性が高いという特徴がある。
動作電圧は3.3~5.0Vであり、色は緑のみである[2]。
ピン配置を図3に示す。

図3.OLCDディスプレイのピン配置
## 4.工夫点
キーボードでかんたんに操作できる。
メッセージの送受信の状態がアイコンで一目でわかるようにした。
ポケベルで使っていたような数字の語呂合わせなどの隠しコマンドでディスプレイに特殊メッセージが送れる。
数字、英語、半角カタカナが送れる。
## 5.回路図・部品リスト
使用した回路を図4に示す。
### 回路図

図4.ポケベル装置一機あたりの回路
#### 回路説明
5Vの電源電圧がBluetoothモジュールのVccに供給され、ArduinoのD7、D8ピンを介してデータの送受信を行い、GNDへ流れる。有機ELモジュールにも5Vの電源電圧がVccに供給され、ArduinoのD2〜D6ピン,D10〜D12ピンを介して4ビットモードで動作し、VssからGNDへ流れる。
#### 部品リスト
マイクロチップ Bluetoothモジュール RN42-I/RM 2台
ストロベリー・リナックス グラフィック有機 EL モジュール (SEL10016G) 2台
Arduino nano 2台
## 6.プログラム
使用したプログラムを図5に示す。
### 使用プログラム
```
1. #include <SoftwareSerial.h>
2. #include <LiquidCrystal.h>
3. #include <KanaLiquidCrystal.h>
4. KanaLiquidCrystal lcd(12, 11, 10, 5, 4, 3, 2);
5.
6. int mailcount=0;
7. int pencilcount=0;
8. int bluetoothRx = 7; // RX-I of bluetooth
9. int bluetoothTx = 8; // TX-O of bluetooth
10. SoftwareSerial mySerial(bluetoothRx, bluetoothTx);
11. int count=0;
12. char input[64];
13. boolean flag=false;
14. boolean get=false;
15. boolean m = true;
16. String mode="command";
17. String message="";
18. void setup()
19. {
20. Serial.begin(9600);
21. mySerial.begin(115200); // The Bluetooth Mate defaults to 115200bps
22. mySerial.print("$$$"); // Enter command mode
23. delay(100); // Short delay, wait for the Mate to send back CMD
24. mySerial.println("U,9600,N"); // Temporarily Change the baudrate to 9600, no parity
25. // 115200 can be too fast at times for NewSoftSerial to relay the data reliably
26. mySerial.begin(9600); // Start bluetooth serial at 9600
27. lcd.begin(16,2);
28. lcd.noDisplay();
29. for(int i=2;i<6;i++){
30. analogWrite(i,0);
31. }
32. lcd.clear();
33. lcd.display();
34. }
35. void loop()
36. {
37. if(mode.equals("write")){
38. Serial.println("Write");
39. lcd.clear();
40. while(flag==false){
41. pencilicon();
42. while(Serial.available()){
43. char c = Serial.read();
44. if(count>0 && c=='\n') flag=true;
45. if(c=='\n') break;
46. Serial.println(c);
47. input[count]=c;
48. count++;
49. if(count==64){
50. Serial.print("Over number of characters");
51. lcd.clear();
52. lcd.setCursor(3, 1);
53. lcd.print("Over number of characters");
54. break;
55. }
56. }
57. }
58. m=true;
59. lcd.clear();
60. mode="command";
61. }
62. if(mode.equals("send")){
63. Serial.println("send");
64. lcd.clear();
65. lcd.setCursor(3,0);
66. lcd.print("send Mode");
67. if (flag){
68. for(int i=0;i<count;i++){
69. mySerial.print(input[i]);
70. Serial.print(input[i]);
71. }
72. lcd.setCursor(3,1);
73 lcd.print("complete");
74. Serial.println();
75. }
76. else{
77. lcd.setCursor(3, 1);
78. lcd.print("Not found message");
79. Serial.println("Not found message");
80. }
81. while(Serial.available()){
82. if(!Serial.available())break;
83. char d=Serial.read();
84. }
85. while(!Serial.available());
86. char c = Serial.read();
87. if(c=='C'){
88. lcd.clear();
89. count=0;
90. flag=false;
91. m=true;
92. mode="command";
93. }
94. }
95. if(mode.equals("open")){
96. lcd.kanaOn();
97. Serial.println("open");
98. lcd.clear();
99. lcd.setCursor(3,0);
100. lcd.print("open Mode");
101. if(get){
102. message=Check_String(message);
103. lcd.setCursor(3, 1);
104. lcd.print(message);
105. Serial.println(message);
106. }
107- else{
108. lcd.setCursor(3, 1);
109. lcd.print("Not found message");
110. Serial.println("Not found message");
111. }
112. while(Serial.available()){
113. if(!Serial.available())break;
114 . char d=Serial.read();
115. }
116. while(!Serial.available());
117. char c = Serial.read();
118. if(c=='C'){
119. lcd.clear();
120. get=false;
121. message="";
122. m=true;
123. mode="command";
124. }
125. }
126. if(mode.equals("reset")){
127. char d = Serial.read();
128. Serial.println("reset message");
129. lcd.clear();
130. lcd.setCursor(3, 1);
131. lcd.print("reset message");
132. while(Serial.available()){
133. if(!Serial.available())break;
134. char d=Serial.read();
135. }
136. while(!Serial.available());
137. char c = Serial.read();
138. if(c=='C'){
139. lcd.clear();
140. flag=false;
141. count=0;
142. message="";
143. m=true;
144. mode="command";
145. }
146. }
147. if(mode.equals("preview")){
148. String s;
149. lcd.clear();
150. lcd.setCursor(3,0);
151. lcd.print("Preview Mode");
152. lcd.setCursor(3,1);
153. for(int i=0;i<count;i++){
154. s+=(char)input[i];
155. }
156. lcd.print(s);
157. while(Serial.available()){
158. if(!Serial.available())break;
159. char d=Serial.read();
160. }
161. while(!Serial.available());
162. char c = Serial.read();
163. if(c=='C'){
164. m=true;
165. lcd.clear();
166. mode="command";
167. }
168. }
169. while(mode.equals("command")){
170. if(m){
171. lcd.setCursor(3, 0);
172. lcd.print("Command Mode");
173. Serial.println("Command Mode");
174. if(get){
175. Serial.println("Get");
176. }
177. m=false;
178. }
179. int a1;
180. if(mySerial.available())
181. {
182. a1 = mySerial.read();
183. message += (char)a1;
184. get=true;
185. }
186. if(get){
187. mailcount = blink_mailicon(mailcount);
188. }
189. if(flag){
190. pencilcount = blink_pencilicon(pencilcount);
191. }
192. if(Serial.available()){
193. switch(char c = Serial.read()){
194. case 'W':
195. mode="write";
196. break;
197. case 'O':
198. mode="open";
199. break;
200. case 'S':
201. mode ="send";
202. break;
203. case 'R':
204. mode = "reset";
205. break;
206. case 'P':
207. mode="preview";
208. break;
209. }
210. }
211. }
212. }
213. void mailicon(){
214. byte mail1[8]={
B11111,B11000,B10100,B10010,B10001,B10000,B10000,B11111 };
215. byte mail2[8]={
B11111,B00011,B00101,B01001,B10001,B00001,B00001,B11111 };
216. lcd.createChar(1, mail1);
217. lcd.createChar(2, mail2);
218. lcd.setCursor(0,0);
219. lcd.write(1);
220. lcd.setCursor(1,0);
221. lcd.write(2);
222. }
223. void blankicon(int mode){
224. byte blank[8]={
B00000,B00000,B00000,B00000,B00000,B00000,B00000,B00000 };
225. lcd.createChar(3, blank);
226. lcd.setCursor(0,mode);
227. lcd.write(3);
228. lcd.setCursor(1,mode);
229. lcd.write(3);
230. }
231. void pencilicon(){
232. byte pencil1[8]={
B00001,B00010,B00100,B01000,B00100,B00010,B00001,B00000 };
233. byte pencil2[8]={
B00000,B10000,B01000,B00100,B01010,B10010,B00110,B11110 };
234. lcd.createChar(4, pencil1);
235. lcd.createChar(5, pencil2);
236. lcd.setCursor(0,1);
237. lcd.write(4);
238. lcd.setCursor(1,1);
239. lcd.write(5);
240. }
241. int blink_mailicon(int count){
242. if(count>100){
243. count = 0;
244. }
245. if(count%100<50){
246. mailicon();
247. }
248. else{
249. blankicon(0);
250. }
251. return(++count);
252. }
253. int blink_pencilicon(int count){
254. if(count>100){
255. count = 0;
256. }
257. if(count%100<50){
258. pencilicon();
259. }
260. else{
261. blankicon(1);
262. }
263. return(++count);
264. }
265. String Check_String(String s){
266. if(s.equals("0833")) return "オヤスミ";
267. else if(s.equals("194")) return "イクヨ";
268. else if(s.equals("10105")) return "イマドコ";
269. else if(s.equals("1056194")) return "イマカライクヨ";
270. else if(s.equals("1052167")) return "ドコニイルノ";
271. else if(s.equals("21104")) return "ツイタヨ";
272. else if(s.equals("8181")) return "バイバイ";
273. else return s;
274. }
```
図5.使用したプログラム
#### プログラム概要
ディスプレイとBluetoothの初期設定を行なっている。またデバイスへのコマンドモード、ライトモード、オープンモード、センドモード、リセットモード、プレビューモードの実装をしている。
#### プログラム説明
1〜17行目:プログラムに必要な変数の宣言と定義
18~34行目:Arduino及びプログラムの初期設定
20~26行目ではシリアル通信の通信速度、Bluetoothの通信速度を設定している。
27~33行目ではディスプレイの初期設定として、ディスプレイの初期化と使用するピンに対してアナログ出力を設定している。
35~212行目:デバイスへの各モードの実装
各モードの切り替えはグローバル関数であるString modeの値を変えることで切り替えている。
37~61行目はライトモードのプログラムである。ディスプレイにライトモードであることを伝える鉛筆マークを点灯表示させる。そしてシリアルポートからのメッセージの入力待ちをする。シリアルポートからの入力があった場合は一文字ずつグローバル変数のchar input[64]に格納している。配列の関係で64文字が限界のため64文字を超えた場合はディスプレイに”Over number of characters”と表示させている。最後にコマンドモードに戻すためグローバル変数modeにコマンドモードを示すcommandを格納している。
62~94行目はセンドモードのプログラムである。ディスプレイに”send Mode”と表示し、グローバル変数のinput[64]から一文字ずつBluetoothに送信している。送信した場合はディスプレイに”complete”と表示させている。また、もしメッセージの入力がされていなかった場合にはディスプレイに”Not found message”と表示させる。その後シリアルポートからの入力待ちを行い、”C”が入力されたらコマンドモードへ切り替えている。
95~125行目はオープンモードのプログラムである。ディスプレイに”open Mode”と表示し、Bluetoothからメッセージの入力があった場合そのメッセージをディスプレイに表示させている。メッセージの入力がなかった場合はディスプレイに”Not found message”と表示させている。最後にシリアルポートからの入力待ちを行い”C”が入力されたらコマンドモードに切り替えている。
126~146行目はリセットモードのプログラムである。ディスプレイに”reset Mode”と表示し、入力したメッセージの消去を行なっている。最後にシリアルポートからの入力待ちを行い”C”と入力されたらコマンドモードに切り替えている。
147~168行目はプレビューモードのプログラムである。ディスプレイに”Preview Mode”と表示させ入力されているメッセージをディスプレイに表示させている。入力されている文字がない場合は”Preview Mode”とだけ表示される。
169~211行目まではコマンドモードのプログラムである。ディスプレイに”Command Mode”と出力し、その後シリアルポートとBluetoothからの入力待ちをする。Bluetoothからの入力があった場合は入力された値をグローバル変数であるString messageに格納する。そしてディスプレイにメッセージを受信したことを伝えるためにメールマークを点滅表示させる。シリアルポートからの入力があった場合は入力された文字を判定し各モードへの切り替えを行う。
213~222行目:関数mailicon
メールのアイコンを表示する関数である。アイコンのドットのパターンを登録して2文字分使って上の列に表示している。
223~230行目:関数blinkicon
点灯させたアイコンを消灯させる関数で、おもにアイコンを点滅させる為に使用している。引数modeによって点滅させるアイコンの列を指定することで、点滅するアイコンを選択している。
231~240行目:関数pencilicon
鉛筆のアイコンを表示する関数である。mailiconと同様に2文字分使って下の列に表示している。
241~252行目:関数blink_mailicon
253~264行目:関数blink_pencilicon
blinkicon関数を使いそれぞれのアイコンを点滅させる関数である。
265~274行目:関数Check_String
特定の文字が入力された場合に半角カナ変換を行う関数である。
## 7.役割分担
役割は表4のように分担した。
表4. 役割分担表
|役割|名前|
|:--:|:--:|
|通信|青木|
|ディスプレイ表示|樹|
|プロジェクトマネージャー|巧巳|
### <参考文献>
[1]秋月電子通商 Bluetoothモジュール RN42-I/RM データシート http://akizukidenshi.com/download/ds/microchip/rn42v2_32r.pdf (2013年4月11日)
[2]strawberry linux グラフィック有機ELモジュール 説明書
https://strawberry-linux.com/pub/oled-green.pdf (2012年4月)