Master 코드설명
/*
* I2C 모듈 마스터
* version 0.0.1
* by hojin
*/
#include <Wire.h>
#include <EEPROM.h>
#include <LiquidCrystal_I2C.h> // 라이브러리 설치
#include <SoftwareSerial.h>
#define DEBUG 1
#define BEEP_PIN 11 // 능동부저
#define BEEP 11 // 수동부저
#define BUTTON1 8
#define BUTTON2 9
#define BUTTON3 10
#define BT_RXD 7 // 블루투스모듈 TX연결
#define BT_TXD 6 // 블루투스모듈 RX연결
// 0 : ready
// 1 : setup
int status = 0;
int timedelay = 0;
int address = 0;
int time_blank_delay[19] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
// i2c 기기 번호 0x27
LiquidCrystal_I2C lcd(0x27,16,2);
// 블루투스 소프트시리얼
SoftwareSerial bluetooth(BT_RXD, BT_TXD);
/**
* 내부 LED 깜빡임 (초기값 1초)
*/
void builtin_led_blank(int time=1000) {
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(time); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(time); // wait for a second
}
void beep(int time)
{
// 초기화2 : 비프 소리
digitalWrite(BEEP_PIN, HIGH);
delay(time);
digitalWrite(BEEP_PIN, LOW);
delay(time);
}
void lcd_init() {
lcd.init();
lcd.backlight();
lcd.setCursor(0,0);
}
String ProductName;
int addr_title_enable = 128;
int product_name_addr = 256;
void product_name_read() {
char c;
if(EEPROM.read(addr_title_enable) == 1) {
for(int a=product_name_addr, i=0; a<16; a++,i++) {
c = EEPROM.read(a);
if( c > 20 && c <= 126 ) {
ProductName += c;
} else {
ProductName += '_';
}
}
} else {
ProductName = "I2C-Master";
}
}
void start_beep() {
tone(BEEP,1046); // 도
delay(200);
noTone(BEEP);
tone(BEEP,1046); // 도
delay(200);
noTone(BEEP);
}
void ready_beep() {
/*
tone(BEEP,523); // 도
delay(500);
tone(BEEP,587); // 레
delay(500);
*/
tone(BEEP,660); // 미
delay(100);
/*
tone(BEEP,698); // 파
delay(500);
*/
tone(BEEP,784); // 솔
delay(300);
/*
tone(BEEP,880); // 라
delay(500);
*/
tone(BEEP,988); // 시
delay(500);
/*
tone(BEEP,1046); // 도
delay(500);
*/
noTone(BEEP);
}
Setup 파트
void setup() {
// 초기화0. EEPROM
// - Arduino Uno: 1 kB EEPROM storage.
// 초기화1 : 내부 LED, Beep
pinMode(LED_BUILTIN, OUTPUT);
time_blank_delay[12] = 500;
// 초기화2. 전원 입력시 삑 (1번)
/*
pinMode(BEEP_PIN, OUTPUT);
beep(50); // 삐빅
*/
pinMode(BEEP,OUTPUT); // 수동부저 출력 11핀
start_beep();
// 초기화4. 시리얼 초기화
Serial.begin(2000000);
beep(100); // 삐빅
product_name_read();
Serial.print(ProductName);
// 초기화3. LCD 초기화
lcd_init();
lcd.setCursor(0,0);
lcd.print(ProductName);
// 초기화7. 버튼
pinMode(BUTTON1, INPUT);
pinMode(BUTTON2, INPUT);
pinMode(BUTTON3, INPUT);
/*
if(digitalRead(BUTTON1) == 0) {
beep(200); // 삐빅
status = 1; // setup 상태
lcd.setCursor(0,1);
lcd.print("Setup mode");
//lcd.blink();
Serial.println(" = Setup Mode!");
} else {
lcd.setCursor(0,1);
lcd.print("ready!");
Serial.println(" = Ready!");
}
*/
lcd.setCursor(0,1);
lcd.print("ready!");
Serial.println(" = Ready!");
// 초기화5. I2C
Wire.begin(); // i2c 통신
// 초기화6. 블루투스
bluetooth.begin(9600);
ready_beep();
}
// 모듈로 값을 전달합니다.
void commandModule(int module, int value)
{
Wire.beginTransmission(module);
Wire.write(value);
Wire.endTransmission();
}
/*
버튼 검출 로직
*/
int button1_press = 0;
int button1_time_count = 0;
int button1_press_check() {
int count;
if(digitalRead(BUTTON1) == 0) {
if(button1_press == 0) {
button1_press = timedelay;
}
button1_time_count++;
}
if(digitalRead(BUTTON1) == 1) {
if(button1_press > 0) {
button1_press = 0;
Serial.print("button1 press = ");
Serial.println( button1_time_count );
count = button1_time_count;
button1_time_count=0;
return count;
}
}
return 0;
}
int button2_press = 0;
int button2_time_count = 0;
int button2_press_check() {
int count;
if(digitalRead(BUTTON2) == 0) {
if(button2_press == 0) {
button2_press = timedelay;
}
button2_time_count++;
}
if(digitalRead(BUTTON2) == 1) {
if(button2_press > 0) {
button2_press = 0;
Serial.print("button2 press = ");
Serial.println( button2_time_count );
count = button2_time_count;
button2_time_count=0;
return count;
}
}
return 0;
}
int button3_press = 0;
int button3_time_count = 0;
int button3_press_check() {
int count;
if(digitalRead(BUTTON3) == 0) {
if(button3_press == 0) {
button3_press = timedelay;
}
button3_time_count++;
}
if(digitalRead(BUTTON3) == 1) {
if(button3_press > 0) {
button3_press = 0;
Serial.print("button3 press = ");
Serial.println( button3_time_count );
count = button3_time_count;
button3_time_count=0;
return count;
}
}
return 0;
}
loop 파트
loop 동작을 반복하면서 Master와 Slave간에 통신을 처리합니다.
String input;
String bluetooth_input; // 블루투스로 받는 문자열
int time_led_toggle = 0;
int time_beep_toggle = 0;
int mode_count = 0;
void loop() {
// 설정모드
if(status == 1) {
}
// 블루투스 통신
if(bluetooth.available()){
bluetooth_input = bluetooth.readStringUntil('\n'); //엔터까지 입력받기
Serial.print("+< ");
Serial.println(bluetooth_input);
command_parser(bluetooth_input);
}
// 시리얼 통신
if(Serial.available()>0){
String serial_input = Serial.readStringUntil('\n'); //엔터까지 입력받기
Serial.println("> " + serial_input);
command_parser(serial_input);
}
// builtin_led_blank(500); // 0.5초 깜빡임
time_led_blank(time_blank_delay[12], LED_BUILTIN);
//time_beep_blank(500, 12);
// 타임딜레이 5초간격 초기화
if(timedelay > 5000) {
timedelay = 0; //
}
timedelay++; delay(1);
} /* --- loop end ---*/
주기적으로 led를 깜빡임
void time_led_blank(int time, int pin) {
if(timedelay % time == 0) {
if(time_led_toggle == 0) {
time_led_toggle = 1;
} else {
time_led_toggle = 0;
}
digitalWrite(pin, time_led_toggle);
}
}
주기적으로 beep음을 출력합니다.
void time_beep_blank(int time, int pin) {
if(timedelay % time == 0) {
if(time_beep_toggle == 0) {
time_beep_toggle = 1;
} else {
time_beep_toggle = 0;
}
digitalWrite(pin, time_beep_toggle);
}
}
통신
마스터는 컴퓨터 및 슬레이브와 다양한 통신을 처리합니다. 또한, 블루투스로 명령을 입력받아 슬레이브에 명령을 전달하는 역할 을 수행합니다.
I2C 통신 처리
I2C를 통하여 슬레이브와 통신을 처리합니다. 이를 위해서는 데이터를 전송하는 함수와 수신하는 함수가 필요합니다.
/*
I2C 통신
*/
// 지정한 id로 데이터를 요청합니다.
void wire_request(int id, int len) {
Wire.requestFrom(id, len); // request 6 bytes from slave device #8
while (Wire.available()) { // slave may send less than requested
char c = Wire.read(); // receive a byte as character
Serial.print(c); // print the character
}
}
명령어 파서
문자열로 전송되는 명령을 분석하고, 일치하는 동작의 함수를 호출합니다.
/*
명령어 분석 처리
*/
void command_parser(String input) {
// 첫번째 글자가 ?인 경우, 도움말 함수를 호출합니다.
if(input.charAt(0) == '?') {
help();
return;
}
//문자의 첫번째 위치부터 다음 토큰까지 읽어낸다
int space_idx = input.indexOf("=");
//첫번째 인자의 경우, 공백을 만나지못하면 인자 딱 하나만 입력한 경우이므로 처음부터 끝까지 읽고,
//공백을 만나면 그 공백 전까지 짤라서 읽어내면 됨. (인자가 2개 이상인 경우)
String cmd = space_idx == -1 ? input.substring(0, input.length()) : input.substring(0, space_idx);
if(space_idx == -1) {
cmd = input.substring(0, input.length());
command(cmd, ""); // 명령어 분석
} else {
command(cmd, input.substring(space_idx+1, input.length()) );
}
}
첫번째 글자가 ?인 경우, 도움말 함수를 호출합니다.
시리얼 모니터로 master가 연결이 되어 있는 경우 사용법에 대해서 안내 메시지를 출력합니다.
void help() {
Serial.println("----- ----- ----- ----- -----");
Serial.println("+명령: 블루투스AT 명령전송");
Serial.println("i번호: i2c select");
Serial.println("lcd=문자열: LCD출력");
Serial.println("beep=시간: 부저출력");
Serial.println("----- ----- ----- ----- -----");
}
명령어에 대한 함수 호출 동작 처리
입력된 명령어와 일치하는 함수를 호출합니다.
int command(String cmd, String str) {
int module_idx = 0;
Serial.println("command = " + cmd);
// command prefix check
// 커멘드에 번호가 있는지?
//문자의 첫번째 위치부터 다음 토큰까지 읽어낸다
int space_idx = cmd.indexOf(":");
if(space_idx!= -1) {
// 모듈 번호 구분
module_idx = cmd.substring(0, space_idx).toInt();
Serial.print("Module = ");
Serial.print(module_idx);
// 지정한 I2C 모듈 선택
Wire.beginTransmission(module_idx);
// 명령어를 전송합니다.
Serial.print(", Command = ");
for(int n=(space_idx+1); n<cmd.length(); n++) {
Wire.write(cmd.charAt(n));
Serial.print(cmd.charAt(n));
}
// 2차 매개변수가 있는 경우 데이터 추가 전송
if(str.length()>0) {
// 구분기호 전송
Wire.write('=');
Serial.print("=");
// 파라미터 값을 추가 전송합니다.
//Serial.print("Wrie value = ");
for(int n=0; n<str.length(); n++) {
Wire.write(str.charAt(n));
Serial.print(str.charAt(n));
}
Serial.println("...");
}
Wire.endTransmission();
return 0; //함수 중단
}
// 블루투스 코멘드
// +시작하는 명령 :
if(cmd.charAt(0) == '+') {
// +를 제외한 명령
// 블루투스 명령 전송
for(int n=1; n<cmd.length(); n++) {
bluetooth.write(cmd.charAt(n));
}
}
// local 커멘드
if (cmd == "i2c-scan") {
parser_i2c_scan(str);
}
if (cmd == "lcd") {
parser_lcd(str);
}
if (cmd == "beep") {
parser_beep(str);
}
if (cmd == "led") {
parser_led(str);
}
if (cmd == "title") {
int a = product_name_addr;
for(int i=0; i<str.length(); a++,i++) {
EEPROM.write(a, str.charAt(i));
//Serial.print(" ");
//Serial.print(EEPROM.read(a));
}
if(str.length() < 16) {
for(int i=str.length(); i<16; a++,i++) {
EEPROM.write(a, 20); // 공백
}
}
//Serial.println("");
for(int i=str.length(); i<16;i++) {
str += ' ';
}
lcd.setCursor(0,0);
lcd.print(str);
}
}
동작함수
LCD 출력
Master에 연결된 I2C LCD 모듈에 데이터를 출력합니다.
// LCD 출력
// 첫번째 줄과 두번째 줄은 `/`로 구분함
void parser_lcd(String str) {
lcd.clear();
// 첫번째줄 읽기
int space_idx = str.indexOf("/"); //문자의 첫번째 위치부터 다음 공백까지 읽어낸다
//첫번째 인자의 경우, 공백을 만나지못하면 인자 딱 하나만 입력한 경우이므로 처음부터 끝까지 읽고,
//공백을 만나면 그 공백 전까지 짤라서 읽어내면 됨. (인자가 2개 이상인 경우)
String arg0;
if(space_idx == -1) {
arg0 = str.substring(0, str.length()); // '/' 를 검출하지 못한경우
} else {
arg0 = str.substring(0, space_idx);
}
// 첫번째줄 출력
lcd.setCursor(0,0);
lcd.print(arg0);
// Serial.println(arg0);
// 다음 공백 위치 찾는 코드
// Serial.println(space_idx);
// '/'로 시작해서, 첫번째줄을 생략하는 경우
String arg1 = "";
if(space_idx == -1) {
arg1="";
} else {
arg1 = str.substring(space_idx + 1, str.length());
}
// 2번째줄 출력
lcd.setCursor(0,1);
Serial.println(arg1);
lcd.print(arg1);
}
I2c 스케닝
// I2c 스케닝
void parser_i2c_scan(String str) {
byte Err, adr;
int N_Device;
Serial.println("Scanning...");
N_Device = 0;
for(adr=1;adr<127; adr++){
Wire.beginTransmission(adr);
Err = Wire.endTransmission();
// 전송성공
if(Err == 0) {
Serial.print("0x");
Serial.print(adr, HEX);
Serial.print(" => ");
Serial.println("I2C device found at address");
N_Device++;
}
if(N_Device == 0) {
Serial.println("No I2C Device found");
} else {
Serial.println("Done");
}
}
}
비프소리 출력
// 비프소리 출력
void parser_beep(String str) {
int time = str.toInt();
beep(time);
}
내부 LED 깜빡임 속도 변경
// 내부 LED 깜빡임 속도 변경
void parser_led(String str) {
time_blank_delay[12] = str.toInt();
}
서브목차