[AVR] 계산기
2021. 11. 9. 22:22ㆍ코딩/AVR
main.c
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#include <string.h>
#include <stdio.h>
#include <avr/interrupt.h> // interrupt 관련 lib가 들어 있다.
#include "uart0.h"
#include "queue.h"
#include "I2C_LCD.h"
#include "I2C.h"
char buff[40];
extern void UART0_transmit(char data);
// printf를 동작 시키위한 mapping작업
FILE OUTPUT = FDEV_SETUP_STREAM(UART0_transmit, NULL, _FDEV_SETUP_WRITE);
volatile uint32_t keypad_timer=0;
ISR(TIMER0_COMP_vect)
{
volatile uint8_t keydata=0;
keypad_timer++;
if (keypad_timer >= 60) // 60ms reached
{
keypad_timer=0;
if ((keydata=keypad_scan()))
{
insert_queue(keydata);
}
}
}
void timer0_init()
{
TCCR0 |= (1 << CS02) | (0 << CS01) | (0 << CS00); // 64분주
TCCR0 |= (1 << WGM01) | (0 << WGM00); // CTC mode
TIMSK |= ( 1<< OCIE0); // 비교 일치
OCR0 = 250; // 1ms 간격으로 INT 발생
}
int index=0;
char buff[40];
int main(void)
{
uint8_t key_value;
timer0_init();
stdout = &OUTPUT;
UART0_init();
keypad_int();
I2C_LCD_init(); //lcd 모듈 초기화
I2C_LCD_clear();
sei(); // grobal int enb
printf("main start !!!!\n");
while (1)
{
I2C_LCD_write_string_XY(0,0,buff);
if (queue_empty() != TRUE) //queue_empty 가 TRUE면 LCD 클리어
{
I2C_LCD_clear();
key_value=read_queue();
buff[index]=key_value; //buff[index]에 값을 저장
index++; // 1번index ++로 다음 2번 index에 저장하는식
if (key_value == '=') // 만약 =를 넣을시
{
buff[index]='\0'; //문자열을 마무리하고 //문자열은 항상 null,\0로 끝나야한다. 없을시 끝이 어딘지 몰라서 계속 프린트를 실행한다.
calculator(buff); //calculator식을 불러와서 계산
}
if (key_value == ' ')
{
clear_buff(); // ' '일시 buff를 비운다.
}
printf("key_value:%c\n", key_value);
}
}
}
// 111+123=
void calculator(char *buff) //배열의 주소는 자기자신 그니까 이 밑에 숫자 1~9,연산자를 따로 할당하지않고 위 배열에 할당된 값을 그대로 이용
{
char num1buff[10]; // buff 포인터로 불러왔기 때문에 &buff인데 &가 안보이는 상태이다
char num2buff[10]; // 각각 숫자1,2번을 출력하는 buff10칸
int i,j;
int num1, num2, result;
char calculator_mode=' ';
for (i=0; buff[i] >= '0' && buff[i] <= '9'; i++ ) //ex)123 + 456 일때 buff[0]에 1을넣고 i++로인해 buff[1]넘어가서 2를넣고
num1buff[i]=buff[i]; //buff[2]에 3을넣고 연산자는 아스키코드로 1~9 사이의 조건에 안맞기 때문에 for문을 빠져나온다
num1buff[i]='\0'; // 문자열에 null를 표기 안해주면 끝을 모르기때문에 위 예시같은경우 buff[3]칸에 \0가 들어간 것이다.
calculator_mode=buff[i];
i++; // 연산자를 끝낸후 num2에 값(456) 을 넣어주기위한 과정
for (j=0; buff[i] >= '0' && buff[i] <= '9'; i++,j++ ) //위와 메커니즘은 같으나 num2buff[j]에 j대신 i를 넣을시 기존 num1buff[i] 와 충돌이날수있다.
num2buff[j]=buff[i];
num2buff[j]='\0'; // 123\0
num1=atoi(num1buff); //atoi = ascii to interger 문자열을 정수형으로 받겠다는의미
num2=atoi(num2buff);
switch(calculator_mode) {
case '+':
result = num1 + num2;
break;
case '-':
result = num1 - num2;
break;
case '*':
result = num1 * num2;
break;
case '/':
result = num1 / num2;
break;
default:
break;
}
sprintf(buff, "%d%c%d=%d", num1,calculator_mode,num2,result);
printf("%s\n", buff);
}
void clear_buff()
{
for (int i=0; i < 40; i++)
buff[i]='\0';
index=0;
}
keypad.c
#include "keypad.h"
#define KEYPAD_DDR DDRA
#define KEYPAD_PIN PINA
#define KEYPAD_PORT PORTA
void keypad_init()
{
KEYPAD_DDR = 0x0f; // row(PA4 ~ 7) : input col(PA0 ~ 3) : output
KEYPAD_PORT = 0xff;
}
uint8_t keypad_scan()
{
uint8_t data = 0; // key 값 저장 변수
for (int row = 0; row < 4; row++)
{
for (int col = 0; col < 4; col++)
{
data = get_button(row,col);
if (data) //if (data >= 1)
return data;
}
}
}
uint8_t get_button(int row, int col)
{
uint8_t keypad_char[4][4] = {
{'-', '*', '/', '+'},
{'9', '6', '3', '='},
{'8', '5', '2', '0'},
{'7', '4', '1', ' '},
};
static uint8_t prev_state[4][4]=
{
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
{1, 1, 1, 1},
};
uint8_t current_state = 1;
KEYPAD_PORT = 0xff;
KEYPAD_PORT &= ~(1 << col); // 해당 col에 전류를 흘린다.
for(int delay = 0; delay < 20; delay++) // 키패드 체크 delay를 위한 코드
;
current_state = (KEYPAD_PIN & (1 << (row + 4))) >> (row + 4);
// 예) row 0 : PA4에 연결 row:0 +4
// 76543210
// 11101111 : KEYPAD_PIN & ( 1<< (row+4))
// 00001110 : >> (row+4)
if ((current_state == 0) && (prev_state[col][row] == 1))
{ //처음 버튼이 눌렸을 때(현재 버튼이 눌리고 이전에 버튼이 안눌렸다)
prev_state[col][row] = current_state;
return 0;
}
else if ((current_state == 1) && (prev_state[col][row] == 0))
{ // 이전에 버튼이 눌러졌고 현재는 버튼을 뗀 상태이면
prev_state[col][row] = current_state; // key status table을 release 상태로 바꾼다.
printf("key: %c\n", keypad_char[col][row]);
return(keypad_char[col][row]);
}
return 0;
}
계산기 동작 동영상
'코딩 > AVR' 카테고리의 다른 글
[AVR]출입 통제 시스템 (3) | 2021.11.09 |
---|---|
[AVR]전자레인지 동작 동영상 (0) | 2021.11.09 |
[AVR] 모터 속도제어 (선풍기) (0) | 2021.11.09 |
[AVR] UltraSonic 활용 (0) | 2021.11.09 |
[AVR] DP Blink/Stopwatch,Clock 구분 LED표시 시간 표시 기능 (0) | 2021.11.09 |