[FPGA] 세탁기 프로젝트

2021. 11. 30. 11:21코딩/FPGA

 

AVR-FPGA 를 이용하여 세탁기 모형 제작

 

FPGA 블록도

 

상태천이도

MAIN.c

#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#include "button.h"
#include "buzzer.h"
#include "lcd_4bit.h"
#include "mode.h"

int main(void)
{
	pwmInit();
	char buff[30];
	LCD_Init();
	
	
	int count = 0;
	
	modeState = mainmenu;
	
	
	while (1)
	{		
		select_mode();
	}
}

LCD_4bit.c

#include "lcd_4bit.h"

uint8_t lcdData = 0;



void slaveSelect(uint8_t state)
{
	if (state == LOW)
	{
		LCD_SS_PORT &= !(1<<LCD_SS);
	}
	else
	{
		LCD_SS_PORT |= (1<<LCD_SS);
	}
}

void shiftClock()
{
	LCD_SHIFT_CLK_PORT |= (1<<LCD_SHIFT_CLK);
	LCD_SHIFT_CLK_PORT &= ~(1<<LCD_SHIFT_CLK);
}

void LCD_Data(uint8_t data)
{	
	//LCD_DATA_PORT = data // 8bit data 전소
	//8bit serial 전송,msb부터 전송
	//0b11001010
	//i_ss핀을 low로 만든다.
	slaveSelect(LOW);
	for (int i=0; i<8; i++)
	{
		if (data & (0x80>>i)) LCD_MOSI_PORT |= (1<<LCD_MOSI);
		else LCD_MOSI_PORT &= ~(1<<LCD_MOSI);
		
		shiftClock();
	}
	//i_ss핀을 high로 만든다
	slaveSelect(HIGH);
}

void LCD_Data4bit(uint8_t data)
{
	lcdData = (lcdData & 0x0f) | (data & 0xf0); // 상위 4bit 출력
	LCD_EnablePin();
	lcdData = (lcdData & 0x0f) | ((data & 0x0f) << 4); // 하위 4bit 출력
	LCD_EnablePin();
}

void LCD_Data4bitInit(uint8_t data)
{
	lcdData = (lcdData & 0x0f) | (data & 0xf0); // 상위 4bit 출력
	LCD_EnablePin();
}


void LCD_WriteMode()
{
	lcdData &= ~(1<<LCD_RW);
}


void LCD_EnablePin()
{
	lcdData &= ~(1<<LCD_E);
	LCD_Data(lcdData);
	lcdData |= (1<<LCD_E);
	LCD_Data(lcdData);
	lcdData &= ~(1<<LCD_E);
	LCD_Data(lcdData);
	_delay_us(1600);
}

void LCD_WriteCommand(uint8_t commadData)
{
	lcdData &= ~(1<<LCD_RS);
	LCD_WriteMode();
	LCD_Data4bit(commadData);
}

void LCD_WriteCommandInit(uint8_t commadData)
{
	lcdData &= ~(1<<LCD_RS);
	LCD_WriteMode();
	LCD_Data4bitInit(commadData);
}

void LCD_WriteData(uint8_t charData)
{
	lcdData |= (1<<LCD_RS);
	LCD_WriteMode();
	LCD_Data4bit(charData);
}

void LCD_GotoXY(uint8_t row, uint8_t col)
{
	col %= 16;
	row %= 2;
	
	uint8_t address = (0x40 * row) + col;
	uint8_t command = 0x80 + address;
	LCD_WriteCommand(command);
}

void LCD_WriteString(char *string)
{
	for (uint8_t i=0; string[i]; i++)
	{
		LCD_WriteData(string[i]);
	}
}

void LCD_WriteStringXY(uint8_t row, uint8_t col, char *string)
{
	LCD_GotoXY(row, col);
	LCD_WriteString(string);
}

void LCD_Init()
{
	LCD_DATA_DDR = 0xff;
	LCD_RS_DDR |= (1<<LCD_RS);
	LCD_RW_DDR |= (1<<LCD_RW);
	LCD_E_DDR |= (1<<LCD_E);
	LCD_SHIFT_CLK_DDR |= (1<<LCD_SHIFT_CLK);
	LCD_MOSI_DDR |= (1<<LCD_MOSI);
	LCD_SS_DDR |= (1<<LCD_SS);
	
	_delay_ms(20);
	LCD_WriteCommand(0x03);
	_delay_ms(5);
	LCD_WriteCommand(0x03);
	_delay_ms(1);
	LCD_WriteCommand(0x03);
	LCD_WriteCommand(0x02);
	LCD_WriteCommand(COMMAND_4_BIT_MODE);
	LCD_WriteCommand(COMMAND_DISPLAY_OFF);
	LCD_WriteCommand(COMMAND_DISPLAY_CLEAR);
	LCD_WriteCommand(COMMAND_ENTRY_MODE);
	LCD_WriteCommand(COMMAND_DISPLAY_ON);
}

MODE.c

#include "mode.h"
#include "button.h"
#include "lcd_4bit.h"

void select_mode()
{
		switch (modeState)
		{
			case mainmenu:
			
			sprintf(buff, "--select  mode--");
			LCD_WriteStringXY(0, 0, buff);
			sprintf(buff, "1.wash 2.dry");
			LCD_WriteStringXY(1, 0, buff);
			_delay_ms(100);
			if(getButton1State())
			{
				modeState = washmode;
			}
			if(getButton2State())
			{
				modeState = drymode;
			}
			break;
			
			case washmode:
			
			sprintf(buff, "  --wash mode--  ");
			LCD_WriteStringXY(0, 0, buff);
			sprintf(buff, "count: %d    ", timecount);
			LCD_WriteStringXY(1, 0, buff);
			if(getButton1State())
			{
				timecount = timecount +5;
			}
			if(getButton2State())
			{
				modeState = start;
			}
			
			_delay_ms(100);
			break;
			
			case drymode:
			
			sprintf(buff, "  --dry  mode--  ");
			LCD_WriteStringXY(0, 0, buff);
			break;
			
			case start:
			if (timecount >= 1)
			{
				sprintf(buff, "count: %3d", timecount--);
				LCD_WriteStringXY(1, 0, buff);
				_delay_ms(100);
			}
			else if (timecount == 0)
			{
				sprintf(buff, "count: %3d", timecount);
				LCD_WriteStringXY(1, 0, buff);
				_delay_ms(100);
				
				modeState = mainmenu;
			}
				break;
			
		}
}

BUTTON.c

#include "button.h"
#include "buzzer.h"

void buttonInit()
{
	BUTTON1_DDR &= ~(1<<BUTTON1);
	BUTTON2_DDR &= ~(1<<BUTTON2);
	BUTTON3_DDR &= ~(1<<BUTTON3);
}


uint8_t getButton1State()
{
	static uint8_t prevButton1State = RELEASED; //기존 값 유지 변수유지
	uint8_t curButtonState = BUTTON1_PIN &(1<<BUTTON1);

	if((curButtonState == PUSHED)&&(prevButton1State == RELEASED)) //처음 누른 상태
	{
		_delay_ms(20);
		prevButton1State = PUSHED;
		return FALSE;
		
	}
	else if((prevButton1State == PUSHED)&&(curButtonState != PUSHED)) //버튼을 땠을때
	{
		_delay_ms(20);
		prevButton1State = RELEASED;
		return TRUE;
	}
	return FALSE;
}

uint8_t getButton2State()
{
	static uint8_t prevButton2State = RELEASED; //기존 값 유지 변수유지
	uint8_t curButtonState = BUTTON2_PIN &(1<<BUTTON2);

	if((curButtonState == PUSHED)&&(prevButton2State == RELEASED)) //처음 누른 상태
	{
		_delay_ms(30); //debouncing 때문에 딜레이를 준다. 노이즈때문에, 두 번 바뀌는 경우가 있다.
		prevButton2State = PUSHED;
		return FALSE;
		
	}
	else if((prevButton2State == PUSHED)&&(curButtonState != PUSHED)) //버튼을 땠을때
	{
		_delay_ms(30);
		prevButton2State = RELEASED;
		return TRUE;
	}
	return FALSE;
}

uint8_t getButton3State()
{
	static uint8_t prevButton3State = RELEASED; //기존 값 유지 변수유지
	uint8_t curButtonState = BUTTON3_PIN &(1<<BUTTON3);

	if((curButtonState == PUSHED)&&(prevButton3State == RELEASED)) //처음 누른 상태
	{
		_delay_ms(30); //debouncing 때문에 딜레이를 준다. 노이즈때문에, 두 번 바뀌는 경우가 있다.
		prevButton3State = PUSHED;
		return FALSE;
		
	}
	else if((prevButton3State == PUSHED)&&(curButtonState != PUSHED)) //버튼을 땠을때
	{
		_delay_ms(30);
		prevButton3State = RELEASED;
		return TRUE;
	}
	return FALSE;
}

uint8_t getButton4State()
{
	static uint8_t prevButton4State = RELEASED; //기존 값 유지 변수유지
	uint8_t curButtonState = BUTTON4_PIN &(1<<BUTTON4);

	if((curButtonState == PUSHED)&&(prevButton4State == RELEASED)) //처음 누른 상태
	{
		_delay_ms(30); //debouncing 때문에 딜레이를 준다. 노이즈때문에, 두 번 바뀌는 경우가 있다.
		prevButton4State = PUSHED;
		return FALSE;
		
	}
	else if((prevButton4State == PUSHED)&&(curButtonState != PUSHED)) //버튼을 땠을때
	{
		_delay_ms(30);
		prevButton4State = RELEASED;
		return TRUE;
	}
	return FALSE;
}

 

세탁기 프로젝트를 진행하면서 LCD Shift register, PWM, interrupt 에 관하여 한번더 공부를 할 수가 있었습니다.

저번 유사한 프로젝트에서 부족했던 부분을 이번 프로젝트 에서는 보강을 할수 있었기 때문에 그부분은 만족스러웠습니다.

 

다만 너무 기본적인 기능들만 제공 하였기 때문에 다음에 기회가 있다면 한층 더 보강하여 제작을 하고 싶습니다.

 

세탁, 탈수에 각기 다른 PWM을 적용시켰는데 현재 상태가 LCD에 표기가 되니 각기 다른 PWM을 적용 시키는게 아니라 각 기능에 강,,약 기능을 추가하는것이 좋았을거라는 생각이 들어서 아쉬웠습니다.

 

 

'코딩 > FPGA' 카테고리의 다른 글

[FPGA]FPGA 보드에 CPU 코어 만들기 MicroBlaze 사용  (0) 2021.11.17
[FPGA] FPGA+ AVR Buzzer + Motor  (0) 2021.11.12
[FPGA] FPGA + AVR StopWatch  (0) 2021.11.12
FPGA IP PACKAGE 하는 방법  (0) 2021.11.12
[FPGA] Stopwatch + Clock + LED bar  (0) 2021.11.10