Skip to content
TUWLAB.com
AVR

[온도조절 인두기] 5. 소프트웨어 제작

Posted 2014. 01. 21 Updated 2017. 06. 02 Views 12722 Replies 0
Atachment
첨부

오랜 시간 중단되었던 온도조절 인두기 프로젝트를 다시 꺼낸건 3학년 2학기가 끝나고 겨울방학이 시작한 12월 말이었습니다.

다시 시작할때는 이제 코딩만 하면 된다는 생각에 큰 부담은 없었습니다.
- 단지, 방학이 시작함과 동시에 몰아닥친 귀차니즘이 가장 큰 적이 되었죠..


하드웨어를 제어하는 펌웨어를 만들 때는, 주변 장치를 제어하는 드라이버 역할을 하는 장치 제어 모듈들을 따로 만들어서 검증한 다음, main에서 이들을 통합하는 순서로 진행하면 디버깅 없이 깔끔하게 작성할 수 있습니다.

소프트웨어 제작과정에서 예상대로 딱히 큰 어려움은 없었습니다..
- 귀차니즘때문에 하루면 코딩할거 며칠씩 붙잡고 있었던 현상만 제외하면 말이죠.


AVR에 C++ 객체지향 프로그래밍을 적용한 첫 프로젝트였던 만큼, 모듈화와 재사용성을 고려하여 프로그램을 작성하였습니다. 각 모듈별로 추후 다방면으로 응용이 가능한 요소들을 추가하기도 했습니다.



▲ 제어 소프트웨어 구조


- Button : 온도조절 버튼 2개를 제어하는 모듈. 단순 클릭만 감지하는 것이 아니라, 계속 누르고 있을 경우 지속적으로 이벤트를 발생시키는 Key Repeat 감지 기능도 지원합니다.

- Buzzer : 부저를 켜고 끄는 모듈. 뒤에서 설명할 Note Player에서 내부적으로 이 모듈을 활용합니다.

- Config : EEPROM을 제어하여 환경설정을 저장하거나 읽어오는 모듈. 마지막 설정 온도를 기억하고, 부저로부터 발생하는 소리를 켜고 끄는 기능을 지원합니다.

- Display : 4자리 숫자판(FND)을 제어하는 모듈. C언어의 printf와 같은 인터페이스를 제공하고, 숫자 뿐만 아니라 알파벳의 일부와 특수문자도 표시할 수 있습니다.

- Heater : 히터에 공급되는 24V를 외부 제어로 단속하고, 히터의 현재 온도를 지속적으로 계산하여 지정된 Event Listener로 반환합니다.

- Light : 기판 하단에 부착된 두 개의 상태표시등(청, 적)을 제어합니다.

- NotePlayer : 악보를 입력받아서 Buzzer 모듈을 통해 재생하는 모듈. 지금 생각해도 사실 이 모듈이 구지 온도조절 인두기에 구현될 필요는 없습니다. 단지 재미와 추후 재사용성을 위해 구현해 보았습니다. Timer를 활용여 구현하였기 때문에 Main routine을 Blocking하지 않고 마치 음악 재생 쓰레드가 새로 생성된 것과 유사하게 동작합니다.


다음은 모든 모듈들을 통합하여 인두기를 구동하는 Main Routine의 원본 소스코드입니다.

#define F_CPU 8000000UL
#define __DELAY_BACKWARD_COMPATIBLE__

#include <avr/io.h>
#include <avr/interrupt.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <util/delay.h>

#include "include/Display.cpp"
#include "include/Light.cpp"
#include "include/Buzzer.cpp"
#include "include/NotePlayer.cpp"
#include "include/Button.cpp"
#include "include/Config.cpp"
#include "include/Heater.cpp"

#define TEMPERATURE_IDLE 455

static unsigned char melodyTemperatureIncrease[][3] = 
{
	{4, NP_SYB_C, NP_DUR_32},
	{4, NP_SYB_E, NP_DUR_32}
};

static unsigned char melodyTemperatureDecrease[][3] =
{
	{4, NP_SYB_E, NP_DUR_32},
	{4, NP_SYB_C, NP_DUR_32}
};

static unsigned char melodyHeaterOff[][3] =
{
	{5, NP_SYB_C, NP_DUR_32},
	{4, NP_SYB_G, NP_DUR_32},
	{4, NP_SYB_E, NP_DUR_32},
	{4, NP_SYB_C, NP_DUR_32}
};

static unsigned char melodyBoot[][3] = 
{
	{4, NP_SYB_E, NP_DUR_16},
	{4, NP_SYB_Eb, NP_DUR_16},
	{4, NP_SYB_E, NP_DUR_16},
	{4, NP_SYB_Eb, NP_DUR_16},
	{4, NP_SYB_E, NP_DUR_16},
	{4, NP_SYB_B, NP_DUR_16},
	{4, NP_SYB_D, NP_DUR_16},
	{4, NP_SYB_C, NP_DUR_16},
	{4, NP_SYB_A, NP_DUR_8}
};

bool gFlagSoundEnable;
unsigned int gTemperature;

void * operator new(size_t size)	{ return malloc(size); }
void * operator new[](size_t size)	{ return malloc(size); }
void operator delete(void * ptr)	{ free(ptr); }
void operator delete[](void * ptr)	{ free(ptr); }
	
void ControlHeater();
void DisplayTemperature();
void StartIncreaseTemperature();
void IncreaseTemperature();
void StartDecreaseTemperature();
void DecreaseTemperature();
void SaveTemperature();
/************************** Caution ************************
Set compiler optimization option to 'Optimize Most(-O3)'.
Otherwise, EEPROM write procedure will not operate properly.
************************************************************/

#include "AdjustableSolderingIron.hpp"

void ControlHeater()
{
	unsigned int currentTemperature = hHeater->GetTemperature();

	if (gTemperature == TEMPERATURE_IDLE)
	{
		hHeater->Off();
		
		hLight->Off(LIGHT_RED);
		
		if (currentTemperature > 64)
			hLight->On(LIGHT_BLUE);
		else
			hLight->Off(LIGHT_BLUE);
	}
	else
	{
		hLight->Off(LIGHT_BLUE);
		
		if (currentTemperature <= gTemperature - 5)
		{
			hHeater->On();
			hLight->On(LIGHT_RED);
		}
		else if (currentTemperature >= gTemperature + 10)
		{
			hHeater->Off();
			hLight->Off(LIGHT_RED);
		}
	}
}

void DisplayTemperature()
{
	if (gTemperature == TEMPERATURE_IDLE)
		hDisplay->Printf(" 0FF");
	else
		hDisplay->Printf("%3u.c", gTemperature);
}

void StartIncreaseTemperature()
{
	IncreaseTemperature();

	if (gFlagSoundEnable)
	{
		if (gTemperature != TEMPERATURE_IDLE)
			hNotePlayer->SetNote(melodyTemperatureIncrease, 2, 0.5);
		else
			hNotePlayer->SetNote(melodyHeaterOff, 4, 0.5);
		
		hNotePlayer->Play();
	}
}

void IncreaseTemperature()
{
	if (gTemperature == TEMPERATURE_IDLE)
		gTemperature = 200;
	else if (gTemperature + 25 <= 450)
		gTemperature += 25;
	else
		gTemperature = TEMPERATURE_IDLE;

	DisplayTemperature();
}

void StartDecreaseTemperature()
{
	DecreaseTemperature();

	if (gFlagSoundEnable)
	{
		if (gTemperature != TEMPERATURE_IDLE)
			hNotePlayer->SetNote(melodyTemperatureDecrease, 2, 0.5);
		else
			hNotePlayer->SetNote(melodyHeaterOff, 4, 0.5);
		
		hNotePlayer->Play();
	}
}

void DecreaseTemperature()
{
	if (gTemperature == TEMPERATURE_IDLE)
		gTemperature = 450;
	else if (gTemperature - 25 >= 200)
		gTemperature -= 25;
	else
		gTemperature = TEMPERATURE_IDLE;

	DisplayTemperature();
}

void SaveTemperature()
{
	hConfig->SetLastTemperature(gTemperature);
}

int main(void)
{
	// Wait for power to be stable
	_delay_ms(10);
	
	// Change sound flag if button is pushed when booting
	if (hButton->GetButtonState(BUTTON_0) == BUTTON_STATE_DOWN)
	{
		gFlagSoundEnable = true;
		hConfig->SetSoundFlag(true);
	}
	else if (hButton->GetButtonState(BUTTON_1) == BUTTON_STATE_DOWN)
	{
		gFlagSoundEnable = false;
		hConfig->SetSoundFlag(false);
	}
	else
	{
		gFlagSoundEnable = hConfig->GetSoundFlag();
	}
	
	// Load last temperature
	gTemperature = hConfig->GetLastTemperature();
	
	// Validate temperature correctness (200 ~ 450 Celsius, Step = 25, 455 = IDLE)
	if (gTemperature != TEMPERATURE_IDLE && (gTemperature < 200 || gTemperature > 450 || (gTemperature % 25 != 0)))
	{
		gTemperature = 350;
		hConfig->SetLastTemperature(gTemperature);
	}
	
	// Booting Completed
	sei();

	if (gFlagSoundEnable)
	{
		hNotePlayer->SetNote(melodyBoot, 9, 0.3);
		hNotePlayer->Play();
	}

	DisplayTemperature();
	
	hHeater->SetEventListener(HEATER_EVENT_TEMPERATURE_CHANGED, ControlHeater);

	hButton->SetEventListener(BUTTON_0, BUTTON_EVENT_KEYDOWN, StartIncreaseTemperature);
	hButton->SetEventListener(BUTTON_0, BUTTON_EVENT_KEYPRESS, IncreaseTemperature);
	hButton->SetEventListener(BUTTON_0, BUTTON_EVENT_KEYUP, SaveTemperature);
	
	hButton->SetEventListener(BUTTON_1, BUTTON_EVENT_KEYDOWN, StartDecreaseTemperature);
	hButton->SetEventListener(BUTTON_1, BUTTON_EVENT_KEYPRESS, DecreaseTemperature);
	hButton->SetEventListener(BUTTON_1, BUTTON_EVENT_KEYUP, SaveTemperature);

	while (1);
}


프로젝트 설정에서 컴파일러 옵션 중 최적화(Optimization)를 -O3 로 설정해야 정상적으로 빌드됩니다. 최적화 하지 않으면 프로그램이 8KByte를  초과하고, 최적화 옵션을 낮게 설정하면 EEPROM Write가 정상적으로 이루어지지 않습니다.
(컴파일 옵션과 EEPROM Write의 연관성과 문제점은 추후 다른 포스트에서 다루도록 하겠습니다.)



▲ ADC Result - 히터 온도 변환 테이블 데이터 측정


사진을 보면 알 수 있지만, 작업하는 장소가 바뀐것을 알 수 있습니다. 그만큼 그 사이 엄청난 시간간극이... 이곳은 익산 제 방 테이블이 아닌 학교 기숙사입니다.


그렇게 소프트웨어 작성도 모두 끝나고, 칩에 굽는데도 성공했습니다. 그러나, 이것이 끝이 아니었습니다...
근본적인 문제가 해결되지 않은 하드웨어상의 문제점이 다시 고개를 든 것입니다... Hㅏ..


- 다음 글에 계속 -


서비스 선택
이용중인 SNS 버튼을 클릭하여 로그인 해주세요.
SNS 계정을 통해 로그인하면 회원가입 없이 댓글을 남길 수 있습니다.
댓글
?
Powered by SocialXE

List of Articles
번호 분류 제목 글쓴이 최근 수정일 조회 수
129 일반 AutoCAD 자주 사용하는 명령어 요약 정리 TUW 2014.04.24 22794
128 Linux SSHFS를 활용한 원격 디렉토리 마운트 TUW 2014.04.24 9567
127 Apache [Apache] .htaccess를 활용한 이미지 외부링크 방지하기 2 file TUW 2017.06.02 17877
126 AVR [온도조절 인두기] 6. 마지막 디버깅 - LM2575 오버슈트(Overshoot) 현상 file TUW 2017.09.22 14218
» AVR [온도조절 인두기] 5. 소프트웨어 제작 file TUW 2017.06.02 12722
124 AVR [온도조절 인두기] 4. 문제점 발견 - ADC 입력에 저항분압 회로를 사용할 경우 문제점 file TUW 2017.06.02 15097
123 AVR [온도조절 인두기] 3. 하드웨어 디버깅 file TUW 2017.06.02 13050
122 AVR [온도조절 인두기] 2. 하드웨어 제작 file TUW 2017.06.02 12653
121 AVR [온도조절 인두기] 1. 모든 사건(?)의 발단 file TUW 2017.06.02 14001
120 Apache Apache에사 Proxy Server를 통해 Port - Sub Domain 연결하기 TUW 2015.10.02 11370
119 Linux Ubuntu에서 Global Menu Bar 해제하기 TUW 2014.04.24 11769
118 일반 MediaWiki 기본 문법 TUW 2014.04.23 14865
117 Linux Ubuntu에서 분산 컴파일러 (ICECC) 설치 및 사용하기 file TUW 2017.06.02 15879
116 Linux [Ubuntu] Bashrc Shell Prompt 커스터마이징 (.bashrc PS1) TUW 2014.04.24 21441
115 Linux Ubuntu에 GITLAB 설치하기 A to Z, Apache 연동 file TUW 2017.06.02 22231
114 Linux Windows 및 Linux 클라이언트에서 SSH 자동 로그인 설정하기 file TUW 2018.07.22 34522
목록
Board Pagination Prev 1 2 3 4 5 6 7 8 ... 13 Next
/ 13

Powered by Xpress Engine / Designed by Sketchbook

sketchbook5, 스케치북5

sketchbook5, 스케치북5