/// a single digit Calculator
#include <stdint.h>
/* ---------- REGISTER DEFINITIONS ---------- */
#define DDRA (*(volatile uint8_t*)0x21)
#define PORTA (*(volatile uint8_t*)0x22)
#define DDRB (*(volatile uint8_t*)0x24)
#define PORTB (*(volatile uint8_t*)0x25)
#define DDRF (*(volatile uint8_t*)0x30)
#define PORTF (*(volatile uint8_t*)0x31)
#define DDRK (*(volatile uint8_t*)0x107)
#define PORTK (*(volatile uint8_t*)0x106)
/* ---------- DISPLAY DIGITS ---------- */
uint8_t seg[10] = {
0x3F,0x06,0x5B,0x4F,0x66,
0x6D,0x7D,0x07,0x7F,0x6F
};
/* ---------- DIGIT ENABLE (ACTIVE LOW) ---------- */
#define DIG1_ON() (PORTB = ~(1<<3))
#define DIG2_ON() (PORTB = ~(1<<2))
#define DIG3_ON() (PORTB = ~(1<<1))
#define DIG4_ON() (PORTB = ~(1<<0))
#define DIG_OFF() (PORTB = 0xff)
/* ---------- KEYPAD MAP ---------- */
char keymap[4][4] = {
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
/* ---------- GLOBALS ---------- */
uint8_t i;
uint8_t digits[4] = {0,0,0,0};
uint8_t first_digit = 0;
uint8_t second_digit = 0;
char op = 0;
/* ---------- STATES ---------- */
#define WAIT_FIRST_DIGIT 0
#define WAIT_OPERATOR 1
#define WAIT_SECOND_DIGIT 2
#define WAIT_EQUAL 3
uint8_t state = WAIT_FIRST_DIGIT;
/* ---------- DELAYS ---------- */
void delay_refresh(void)
{
for (volatile uint16_t i=0;i<800;i++);
}
void debounce_delay(void)
{
for (volatile uint16_t i=0;i<2000;i++);
}
/* ---------- DISPLAY ---------- */
void display_4digit(uint8_t d1,uint8_t d2,uint8_t d3,uint8_t d4)
{
PORTA = seg[d1]; DIG1_ON(); delay_refresh(); DIG_OFF();
PORTA = seg[d2]; DIG2_ON(); delay_refresh(); DIG_OFF();
PORTA = seg[d3]; DIG3_ON(); delay_refresh(); DIG_OFF();
PORTA = seg[d4]; DIG4_ON(); delay_refresh(); DIG_OFF();
}
/* ---------- KEYPAD COLUMN ---------- */
int get_column(uint8_t col)
{
if (col & (1<<0)) return 0;
if (col & (1<<1)) return 1;
if (col & (1<<2)) return 2;
if (col & (1<<3)) return 3;
return -1;
}
/* ---------- SETUP ---------- */
void setup(void)
{
DDRF = 0x0F; // rows
DDRK = 0x00; // columns
DDRA = 0xFF; // segments
DDRB = 0x0F; // digit select
PORTB = 0xFF; // digits off
}
/* ---------- MAIN LOOP ---------- */
void loop(void)
{
/* Always refresh display */
display_4digit(
digits[0],
digits[1],
digits[2],
digits[3]
);
for (i=0;i<4;i++)
{
PORTF = (1<<i);
debounce_delay();
uint8_t col_val = PORTK;
if (col_val)
{
debounce_delay();
col_val = PORTK;
if (col_val)
{
int col = get_column(col_val);
char key = keymap[i][col];
/* ---------- KEY DECODING ---------- */
if (key >= '0' && key <= '9')
{
uint8_t num = key - '0';
if (state == WAIT_FIRST_DIGIT)
{
first_digit = num;
digits[3] = num;
state = WAIT_OPERATOR;
}
else if (state == WAIT_SECOND_DIGIT)
{
second_digit = num;
digits[3] = num;
state = WAIT_EQUAL;
}
}
else if (key == 'A' && state == WAIT_OPERATOR)
{
op = '+';
state = WAIT_SECOND_DIGIT;
}
else if (key == 'B' && state == WAIT_OPERATOR)
{
op = '-';
state = WAIT_SECOND_DIGIT;
}
else if (key == 'C' && state == WAIT_OPERATOR)
{
op = '*';
state = WAIT_SECOND_DIGIT;
}
else if (key == 'D' && state == WAIT_OPERATOR)
{
op = '/';
state = WAIT_SECOND_DIGIT;
}
else if (key == '#' && state == WAIT_EQUAL)
{
uint8_t result = 0;
if (op == '+')
result = first_digit + second_digit;
else if(op == '-'){
result = result = first_digit - second_digit;
}
else if(op == '*'){
result = result = first_digit * second_digit;
}
else if(op == '/'){
result = result = first_digit / second_digit;
}
else {
result = 0;
}
digits[0] = 0;
digits[1] = 0;
digits[2] = result / 10;
digits[3] = result % 10;
/* AUTO RESET */
state = WAIT_FIRST_DIGIT;
first_digit = 0;
second_digit = 0;
op = 0;
}
/* wait till release */
while (PORTK);
debounce_delay();
}
}
}
}