BASIC4MCU | 질문게시판 | 3x4 키패드를 이용한 LCD 계산기 코딩 질문입니다.
페이지 정보
작성자 LCDnoob 작성일2022-11-16 13:26 조회1,445회 댓글1건첨부파일
본문
#define F_CPU 16000000UL
#include
#include
#include
#include
#define LCD_DB_PORT PORTA // LCD_DATABUS
#define LCD_DB_DDR DDRA
#define LCD_CMD_PORT PORTC // LCD_COMMAND
#define LCD_CMD_DDR DDRC
#define YES 12 // 숫자는 의미 없음. 분별을 위한 임의의 값
#define NO 34
#define PASS 56
#define ERROR 78
unsigned char char_address = 0x80; // CLCD 1열 첫번째 문자위치 어드레스
unsigned char keypad_press = NO; // 키패드의 버튼이 눌렸는지의 여부
unsigned char operand1_complete = NO; // 피연산자1의 입력이 완료되었는지의 여부
unsigned char operand2_complete = NO; // 피연산자2의 입력이 완료되었는지의 여부
unsigned char operator_complete = NO; // 연산자의 입력이 완료되었는지의 여부
unsigned char overflow_flag = NO; // 값이 자료형의 사이즈를 벗어났는지의 여부
char val_buffer; // 데이터 값 버퍼
char key_buffer; // 키 값 버퍼
void LCD_cmd(unsigned char cmd) // LCD에 command를 입력함수
{
LCD_CMD_PORT = 0x00; // Instruction register 선택, Write Disable
LCD_DB_PORT = cmd; // LCD data bus에 command 출력
LCD_CMD_PORT = 0x01; // Write Enable
_delay_us(1); // LCD 명령처리 지연시간
LCD_CMD_PORT = 0x00; // Write Disable
_delay_us(100); // LCD 명령처리 지연시간
}
void LCD_init(void) // LCD 초기화 함수(Initialize)
{
LCD_cmd(0x38); // Function set (data length-8bit, 2행, 5x8dote)
LCD_cmd(0x0F); // Display on/off control(화면출력 ON, 커서표시 & 커서깜빡임 OFF)
LCD_cmd(0x06); // Entry mode set(커서 오른쪽 이동, 화면이동 OFF)
LCD_cmd(0x01); // Clear display
_delay_ms(2);
}
void LCD_data(unsigned char data) // LCD Data 전송 함수
{
LCD_CMD_PORT = 0x02; // Data register 선택, Write Disable
LCD_DB_PORT = data; // LCD data bus에 Data 출력
LCD_CMD_PORT = 0x03; // Write Enable
_delay_us(1);
LCD_CMD_PORT = 0x02; // Write Disable
_delay_us(100);
}
void LCD_print(unsigned char cmd, char *str) // LCD 문자열 출력 함수
{
LCD_cmd(cmd); // 출력위치 지정
while(*str != 0) // 문자열의 끝이 올때까지
{ LCD_data(*str);
str++;
}
}
void LCD_char_print(unsigned char cmd, char *str) // LCD 문자 출력 함수
{
LCD_cmd(cmd); // 출력위치 지정
LCD_data(*str);
}
void buzzer(void) // 부저 울림 함수
{
PORTF = 0x01;
_delay_ms(50); // 50ms 동안만
PORTF = 0x00;
}
char Keypad_input(void) // 키패드 입력받는 함수
{
unsigned char input=' '; // 키 패드의 입력값, 초기값은 공백문자
PORTD = 0xFF; // pin 0,1,2,3 은 키패드의 Row(출력)
DDRD = 0x0F; // pin 4,5,6 은 키패드의 Column(입력)
PORTD = 0b11111110; // 1번 Row 선택
_delay_us(1); // 명령처리 딜레이 타임
if ((PIND & 0x10) == 0) input = '1';
else if ((PIND & 0x20) == 0) input = '2';
else if ((PIND & 0x40) == 0) input = '3';
PORTD = 0b11111101; // 2번 Row 선택
_delay_us(1);
if ((PIND & 0x10) == 0) input = '4';
else if ((PIND & 0x20) == 0) input = '5';
else if ((PIND & 0x40) == 0) input = '6';
PORTD = 0b11111011; // 3번 Row 선택
_delay_us(1);
if ((PIND & 0x10) == 0) input = '7';
else if ((PIND & 0x20) == 0) input = '8';
else if ((PIND & 0x40) == 0) input = '9';
PORTD = 0b11110111; // 4번 Row 선택
_delay_us(1);
if ((PIND & 0x10) == 0) input = '*';
else if ((PIND & 0x20) == 0) input = '0';
else if ((PIND & 0x40) == 0) input = '#';
key_buffer = input;
return input; // 입력이 없으면 공백문자 리턴
}
unsigned char keypad_db_input(void) // 키패드 입력 debouncing 함수
{
unsigned char input; // 키패드 입력값 변수
input = Keypad_input();
if(input == ' ') // 키가 아무것도 눌리지 않았을 때(혹은 눌렀다 뗐을 때)
{
if(keypad_press == NO) return input; // 키가 이전에 눌린 적이 없다면
else // 키가 이전에 눌린 적이 있다면
{
_delay_ms(20);
keypad_press = NO;
return input;
}
}
else // 키가 눌렸을 때
{
if(keypad_press == YES) return ' '; // 키가 이전에 눌린 적이 있다면
else // 키가 눌린 적이 없다면
{
if (key_buffer != ' ' ) buzzer(); // 키가 눌리면 부저 1회 울림
keypad_press = YES;
return input;
}
}
}
void Title_display(void) // 초기 타이틀 화면 출력 함수
{
LCD_print(0x80," DIGITAL "); // 1열 문자열 출력
LCD_print(0xC0," CALCULATOR "); // 2열 문자열 출력
}
int Ch_to_int(char *val) // 입력된 문자열을 정수로 변환하는 함수
{
long total = atol(val); // 문자열 배열을 long 형 정수로
if (32768 > total && total >= 0) return total; // 입력값이 0 ~ 2^15 범위 안이면
else // 범위를 초과하면
{
overflow_flag = YES;
return 0;
}
}
int Operand1_entering() // 피연산자 1 입력함수
{
char val;
char operand[5] = {0}; // 입력값이 저장 될 문자열 배열
int operand1 = 0;
unsigned int i=0;
unsigned char entering_start = NO; // 입력이 시작되었는지의 여부(처음엔 숫자 이외엔 못 누르게 하기 위해)
while(operand1_complete != YES) // 첫번째 피연산자 입력이 완료될 때까지 무한루프
{
val = keypad_db_input();
if (val == ' ') continue; // 입력이 없으면 Continue
else if(val != '*' && val != '#') // 숫자를 누르면
{
entering_start = YES;
operand[i++] = val; // 배열에 입력된 숫자 저장
LCD_char_print(char_address++, &val); // CLCD 해당 문자주소에 문자 출력
if(i == 5) // 5자리까지 숫자가 입력되면
{
while(Keypad_input() != '*'); // 연산자 선택버튼(*)을 누를 때까지 대기
operand1_complete = YES;
}
}
else if (val == '*' && entering_start == YES) // 연산자 선택버튼(*)을 누르면 피연산자1 입력완료
{
operand1_complete = YES;
}
}
operand1 = Ch_to_int(operand);
return operand1;
}
int Operator_entering() // 연산자 입력 함수
{
char val;
unsigned int i=0;
char operator[4] = {'+','-','*','/'};
char operator_num = 0;
LCD_char_print(char_address, &operator[i++]); // CLCD 1열의 해당 문자주소에 해당 연산자 출력
while(operator_complete != YES) // 연산자 입력이 완료될 때까지 무한루프
{
val = keypad_db_input();
if (val == ' ' || val == '#') continue; // 공백문자나 '#'버튼 누름은 무시
else if(val == '*') // 연산자 선택버튼(*)이 눌러지면
{
if (i == 4 ) i = 0;
LCD_char_print(char_address, &operator[i]); // CLCD의 해당 문자주소에 해당 연산자 출력
operator_num = i++;
}
else if(val != '*' && val != '#') // 숫자를 눌렀을 때
{
val_buffer = val;
char_address++;
operator_complete = YES; // 연산자 선택 완료
}
}
return operator_num;
}
int Operand2_entering() // 피연산자 2 입력함수
{
char val;
char operand[5] = {0}; // 입력값이 저장 될 문자열 배열
int operand2 = 0;
unsigned int i=1;
operand[0] = val_buffer; // 이전에 눌렸던 숫자값을 저장
LCD_char_print(char_address++, &val_buffer); // CLCD 해당 문자주소에 문자 출력
while(operand2_complete != YES) // 두번째 피연산자 입력이 완료될 때까지 무한루프
{
val = keypad_db_input();
if (val == ' ' || val == '*') continue;
else if(val != '*' && val != '#') // 숫자를 누르면
{
operand[i++] = val; // 배열에 입력된 숫자 저장
LCD_char_print(char_address++, &val); // CLCD 해당 문자주소에 문자 출력
if(i == 5) // 5자리까지 숫자가 입력되면
{
while(Keypad_input() != '#'); // 결과출력버튼(#)을 누를 때까지 대기
operand2_complete = YES;
}
}
else if (val == '#') // 결과출력버튼(#)을 누르면 피연산자2 입력완료
{
operand2_complete = YES;
}
}
operand2 = Ch_to_int(operand);
return operand2;
}
char Result_check(long val) // 결과값이 자료형 사이즈를 오버하였는지 검사하는 함수
{
if (2147483648 > val && val > -2147483648) // 자료가 -2^31 ~ 2^31 범위(32비트) 안이라면
{
return PASS;
}
else return ERROR;
}
void Calculating(long opr1,long opr2,int opt) // 결과값 계산 함수
{
long i_result = 0;
float f_result = 0;
char check_result = 0 ;
char str[16];
switch(opt)
{
case 0: // 덧셈 연산
i_result = opr1 + opr2;
break;
case 1: // 뺄셈 연산
i_result = opr1 - opr2;
break;
case 2: // 곱셈 연삼
i_result = opr1 * opr2;
check_result = Result_check(i_result); // 곱셈은 자료형 이상의 값이 나올 수 있으므로 검사
if (check_result == ERROR) opt = ERROR; // 자료형 이상의 값이 나올경우 에러메세지 출력
break;
case 3: // 나눗셈 연산
f_result = (float)opr1 / opr2;
break;
}
switch(opt)
{
case 0: // 덧, 뺄, 곱셈 연산의 경우 정수 출력
case 1:
case 2:
sprintf(str,"%15ld",i_result);
LCD_print(0xC0,str);
break;
case 3: // 나눗셈 연산의 경우 실수 출력
sprintf(str,"%15.2f",(double)f_result); // sprintf는 float형을 지원하지 않으므로 double로 형변환
LCD_print(0xC0,str);
break;
case ERROR: // 결과값이 자료형을 초과할 경우 에러메세지 출력
sprintf(str," VALUE ERROR ");
LCD_print(0xC0,str);
}
}
void Initialize() // 변수 초기화 함수
{
char_address = 0x80;
operand1_complete = NO;
operand2_complete = NO;
operator_complete = NO;
overflow_flag = NO;
LCD_cmd(0x01); // Clear display
}
int main(void) // 메인함수
{
DDRD = 0x0F; // pin 0,1,2,3 은 키패드의 Row(출력)
PORTD = 0xFF; // pin 4,5,6 은 키패드의 Column(입력)
DDRF = 0xFF;
PORTF = 0x00;
LCD_DB_DDR = 0xFF; // LCD data bus, LCD command port 출력모드
LCD_CMD_DDR = 0xFF;
LCD_DB_PORT = 0x00;
LCD_CMD_PORT = 0x00;
int operand1,operand2,operator; // 피연산자와 연산자 선언
char str[16];
LCD_init();
_delay_us(50); // 명령처리 대기시간
Title_display();
_delay_ms(2000);
LCD_cmd(0x01); // Clear display
while(1)
{
operand1 = Operand1_entering();
operator = Operator_entering();
operand2 = Operand2_entering();
if(overflow_flag == YES) // 피연산자 중 자료형을 초과한 것이 있다면
{
sprintf(str," VALUE OVERFLOW "); // 에러메세지 출력
LCD_print(0xC0,str);
}
else Calculating(operand1,operand2,operator);
while(keypad_db_input() != '#'); // 연산이 끝나면 대기하다가 '#'를 누르면 초기화 후 연산시작
Initialize();
}
}
4x3키패드로 LCD에 사칙연산을 하는 회로이며
소스코드에서 에러가 왜 뜨는지 알 수가 없습니다 ㅠ
혹시 알려주실 수 있으신가요?
빨간 글씨가 에러 부분입니다. 소스코드 파일도 같이 첨부합니다.
댓글 1
조회수 1,445master님의 댓글
master 작성일
#include <avr/io.h>
int main(){}
이런 간단한 코드로 컴파일 해보세요
그래도 컴파일 오류가 발생하면 컴파일 설치를 다시 하든지 설정을 체크 해보셔야 합니다.