・通信技術の基本中の基本であるモールス符号を練習するための機械。
・ボタンを短く押すと「トン」、長く押すと「ツー」の音が発生して、LEDが点滅する。
・モールス符号は「トン」「ツー」の音の組み合わせで、アルファベットと数字を表す。液晶画面には、押したモールス符号に対応する文字が表示される。
・通信では、「電鍵」とよばれる高級なスイッチを使うが、あまりにも高価なものであるため、ゲーム用の押しボタンスイッチで代用した。
・ケースには100円均一ショップにあったコレクションボックスを利用した。
トランジスタ 2SC1815GR
カーボン抵抗器 10kΩ x 2個、1kΩ x 2個
セラミックコンデンサ 0.022uF (223) x 2個、0.22uF (224)
オーディオパワーアンプIC HOLTEK HT82V739
ICソケット 8PIN
積層セラミックコンデンサ 1uF x 2個、47uF
可変抵抗器(ボリウム) 10kΩ Bカーブ
スピーカー Φ50mm, 8Ω, 8W
PICマイコン PIC12F1822
ICソケット 8PIN
カーボン抵抗器 10kΩ x 2個
積層セラミックコンデンサ 1uF x 2個、0.1uF
押ボタンスイッチ(電鍵代用)
I2C接続小型8文字x2行液晶ディスプレイ AQM0802A-RN-GBW
バッテリースナップ
電池ボックス 単3×3本用(ニッケル水素電池使用)
トグルスイッチ 基板・パネル両用
ユニバーサル基板 片面ガラス・ユニバーサル基板(ブレッドボード配線パターンタイプ)[AZ0526]
ピンヘッダ、ボックスヘッダ
スペーサー、ネジ類
ケース類
I2C接続液晶の制御関数は、【きむ茶工房ガレージハウス】(http://www.geocities.jp/zattouka/GarageHouse/index.htm)のコードを"skI2Clib.h", "skI2Clib.c", "skI2CLCDlib.h", "skI2CLCDlib.c"を利用させていただいた。
(XC8コンパイラ用)
/*
* File: cw-asc-i2c-lcd8x2-12f1822.c
* Author: kaimu
*
* Created on 2015/06/28, 9:08
*/
/*
* Push switch : PIN 4 (RA3)
* Tone generator On/Off : PIN 3 (RA4) : 0-ON, 1-off
* SCL : PIN 6 (RA1)
* SDA : PIN 5 (RA2)
*
*/
#include <xc.h>
#include <stdlib.h>
#include "skI2Clib.h"
#include "skI2CLCDlib.h"
/*
* I/O port name
*/
#define isSwitchOff() (RA3)
#define isSwitchOn() (!RA3)
#define toneOn() (RA4 = 0)
#define toneOff() (RA4 = 1)
// Configuration 1
#pragma config FOSC = INTOSC // Internal Clock
#pragma config WDTE = OFF // NO Watchdog timer
#pragma config PWRTE = ON // Program start at Power on after 64ms
#pragma config MCLRE = OFF // No Ext Reset, Enable RA3 input pin
#pragma config CP = OFF // No Code protect
#pragma config CPD = OFF // No Data Protect
#pragma config BOREN = ON // Brown out enable
#pragma config CLKOUTEN = OFF // CLKOUT as RA4
#pragma config IESO = OFF // No Internal External clock
#pragma config FCMEN = OFF // No FCM
// Configuration 2
#pragma config WRT = OFF // No Write Protect
#pragma config PLLEN = OFF // No PLL
#pragma config STVREN = ON // Reset on Stack over / under flow
#pragma config BORV = HI // Watch Voltage drop (2.5V = HI)
#pragma config LVP = OFF // No Low Voltage Programming
/*
* Interrupt
*/
volatile int TimerCounter; //
void interrupt InterFunction( void )
{
if (TMR0IF == 1) { // Timer 0 interrupt
TMR0 = 0 ; // initialize TIMER0
TimerCounter++ ; // update Timer Counter
TMR0IF = 0 ; // reser TIMER0 interrupt flag
}
// I2C Interrupt
InterI2C() ;
}
void msgReady(void)
{
LCD_SetCursor(0,0) ; // set locatin ( 1st column, 1st row. )
LCD_Puts(">") ;
}
void msgOn(void)
{
LCD_SetCursor(0,0) ; // set locatin ( 1st column, 1st row. )
LCD_Puts("ON.") ;
}
void msgOff(void)
{
LCD_SetCursor(0,0) ; // set locatin ( 1st column, 1st row. )
LCD_Puts("OFF") ;
}
void msgClear(int row)
/**
* clear LCD at row
* @param row : row cleard (0 or 1)
*/
{
LCD_SetCursor(0, row) ; // set locatin ( 1st column, row row. )
LCD_Puts(" "); // clear line
}
void msgNum(int i)
/*
* Output number on LCD
*
* @param i : number
*/
{
char buf[9] = {0};
itoa(buf, i, 10);
LCD_SetCursor(0,1) ; // set locatin ( 1st column, 2nd row. )
LCD_Puts(buf);
}
void putDotBar(unsigned short mcode)
{
int col;
int i;
unsigned short m;
char dotbar[9];
msgClear(1); // message clear ( 2nd row )
for (col = 0, i = 0; i < 8 ; i++, mcode >>= 2 ) {
m = mcode & 0b11;
switch(m) {
case 0b01 :
dotbar[7 - i] = '.';
break;
case 0b11 :
dotbar[7 - i] = '-';
break;
default :
dotbar[7 - i] = ' ';
}
}
dotbar[8] = '\0';
LCD_SetCursor(0, 1);
LCD_Puts(dotbar);
}
void putAlNum(unsigned short mcode)
/**
* put Alphabet & Number on LCD
* @param mcode : morse code '.' 0b01, '-' 0b11
*/
{
static int c = 0; // column of LCD
if (c > 7) { LCD_Clear(); c = 0;}
LCD_SetCursor(c, 0);
switch (mcode) {
case 0b000000000111 :
LCD_Putc('A');
break;
case 0b0000000011010101 :
LCD_Putc('B');
break;
case 0b0000000011011101 :
LCD_Putc('C');
break;
case 0b0000000000110101 :
LCD_Putc('D');
break;
case 0b0000000000000001 :
LCD_Putc('E');
break;
case 0b0000000001011101 :
LCD_Putc('F');
break;
case 0b0000000000111101 :
LCD_Putc('G');
break;
case 0b0000000001010101 :
LCD_Putc('H');
break;
case 0b0000000000000101 :
LCD_Putc('I');
break;
case 0b0000000001111111 :
LCD_Putc('J');
break;
case 0b0000000000110111 :
LCD_Putc('K');
break;
case 0b0000000001110101 :
LCD_Putc('L');
break;
case 0b0000000000001111 :
LCD_Putc('M');
break;
case 0b0000000000001101 :
LCD_Putc('N');
break;
case 0b0000000000111111 :
LCD_Putc('O');
break;
case 0b0000000001111101 :
LCD_Putc('P');
break;
case 0b0000000011110111 :
LCD_Putc('Q');
break;
case 0b0000000000011101 :
LCD_Putc('R');
break;
case 0b0000000000010101 :
LCD_Putc('S');
break;
case 0b0000000000000011 :
LCD_Putc('T');
break;
case 0b0000000000010111 :
LCD_Putc('U');
break;
case 0b0000000001010111 :
LCD_Putc('V');
break;
case 0b0000000000011111 :
LCD_Putc('W');
break;
case 0b0000000011010111 :
LCD_Putc('X');
break;
case 0b0000000011011111 :
LCD_Putc('Y');
break;
case 0b0000000011110101 :
LCD_Putc('Z');
break;
case 0b0000001111111111 :
LCD_Putc('0');
break;
case 0b0000000111111111:
LCD_Putc('1');
break;
case 0b0000000101111111 :
LCD_Putc('2');
break;
case 0b0000000101011111 :
LCD_Putc('3');
break;
case 0b0000000101010111 :
LCD_Putc('4');
break;
case 0b0000000101010101 :
LCD_Putc('5');
break;
case 0b0000001101010101 :
LCD_Putc('6');
break;
case 0b0000001111010101 :
LCD_Putc('7');
break;
case 0b0000001111110101 :
LCD_Putc('8');
break;
case 0b0000001111111101 :
LCD_Putc('9');
break;
default :
LCD_Putc('?');
}
c++; // next column of LCD
}
void initIO(void)
{
OSCCON = 0b01110010 ; // Internal clock 8MHz
OPTION_REG = 0b00000000 ; // Weak Pull up Resistor ON
ANSELA = 0b00000000 ; // NO Analog PORT
TRISA = 0b00001110 ; // Input : RA1, RA2, RA3 Output: others
WPUA = 0b00000110 ; // Weak pullup : RA1, RA2
PORTA = 0b00000000 ; // Initialize PORTA
}
void initTimer0(void)
{
OPTION_REG = 0b00000110 ; // TIMER0 enable, internal clock 、prescaler 1:128
TMR0 = 0 ; // initialize TIMER0 Counter
TMR0IF = 0 ; // reset TIMER0 flag
TimerCounter = 0 ; // reset Timer Counter
TMR0IE = 1 ; // Enable Timer1 Interrupt
GIE = 1 ; // Enable Interrupt
}
void outReadySignal(void)
{
toneOn(); TimerCounter = 0; while (TimerCounter < 50);
toneOff(); TimerCounter = 0; while (TimerCounter < 10);
toneOn(); TimerCounter = 0; while (TimerCounter < 10);
toneOff(); TimerCounter = 0; while (TimerCounter < 50);
}
/*
* main function
*/
void main()
{
unsigned short mcode; // Morse code 01 = . , 11 = -
int flag; // flag = 1 ... code reading
int i; // index of morse code bit
// Initialize I/O ports
initIO();
// Initialize TIMER0
initTimer0();
// Initialize I2C ( 100kHz )
InitI2C_Master(0) ;
toneOff();
// Initialize LCD module
// Arguments : ICON OFF, Contrast(0-63), VDD=3,3V, LCD 8 characters
LCD_Init(LCD_NOT_ICON,16,LCD_VDD3V,8) ;
msgReady(); // output "RDY"
outReadySignal(); // Start up signal
while(1) {
if (isSwitchOn()) { // when switch is ON
for (flag = 1, mcode = 0, i = 0;
flag == 1 && i < 8; i++) {
TimerCounter = 0;
toneOn();
while (isSwitchOn());
if ( TimerCounter < 3) {
i --; // Too short signal is ignored as chattering noise
} else if ( TimerCounter < 10 ) {
mcode <<= 2;
mcode |= (0b01); // .
} else {
mcode <<= 2;
mcode |= (0b11); // -
}
toneOff();
TimerCounter = 0;
while (isSwitchOff()) {
if (TimerCounter > 42 ) {
flag = -1; // A Word end
break;
} else if (TimerCounter > 18) {
flag = 0; // A character end
break;
}
}
}
putAlNum(mcode);
putDotBar(mcode);
}
}
}