211 lines
5.7 KiB
C
211 lines
5.7 KiB
C
#include "main.h"
|
|
#include "i2c.h"
|
|
#include "usart.h"
|
|
#include "gpio.h"
|
|
#include "kb.h"
|
|
#include "sdk_uart.h"
|
|
#include "pca9538.h"
|
|
#include "oled.h"
|
|
#include "fonts.h"
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
|
|
void SystemClock_Config(void);
|
|
|
|
typedef enum { OP_NONE, OP_ADD, OP_SUB, OP_MUL } Operation;
|
|
typedef enum { STATE_INPUT_A, STATE_INPUT_B, STATE_RESULT } CalcState;
|
|
|
|
static int32_t num_a = 0;
|
|
static int32_t num_b = 0;
|
|
static int32_t result = 0;
|
|
static int32_t repeat_val = 0;
|
|
static Operation current_op = OP_NONE;
|
|
static Operation repeat_op = OP_NONE;
|
|
static CalcState state = STATE_INPUT_A;
|
|
static uint8_t has_input = 0;
|
|
static char buf[32];
|
|
|
|
static const char* op_str(Operation op) {
|
|
switch(op) {
|
|
case OP_ADD: return "+";
|
|
case OP_SUB: return "-";
|
|
case OP_MUL: return "*";
|
|
default: return "";
|
|
}
|
|
}
|
|
|
|
static int32_t calc(int32_t a, int32_t b, Operation op) {
|
|
switch(op) {
|
|
case OP_ADD: return a + b;
|
|
case OP_SUB: return a - b;
|
|
case OP_MUL: return a * b;
|
|
default: return a;
|
|
}
|
|
}
|
|
|
|
static void update_display(void) {
|
|
oled_Fill(Black);
|
|
|
|
oled_SetCursor(80, 0);
|
|
oled_WriteString("1 2 3", Font_7x10, White);
|
|
oled_SetCursor(80, 12);
|
|
oled_WriteString("4 5 6", Font_7x10, White);
|
|
oled_SetCursor(80, 24);
|
|
oled_WriteString("7 8 9", Font_7x10, White);
|
|
oled_SetCursor(80, 36);
|
|
oled_WriteString("* 0 #", Font_7x10, White);
|
|
|
|
oled_SetCursor(0, 0);
|
|
|
|
if (state == STATE_INPUT_A) {
|
|
sprintf(buf, "%ld", (long)num_a);
|
|
oled_WriteString(buf, Font_16x26, White);
|
|
oled_SetCursor(0, 28);
|
|
oled_WriteString("*:op #:clr", Font_7x10, White);
|
|
}
|
|
else if (state == STATE_INPUT_B) {
|
|
sprintf(buf, "%ld %s", (long)num_a, op_str(current_op));
|
|
oled_WriteString(buf, Font_11x18, White);
|
|
oled_SetCursor(0, 20);
|
|
sprintf(buf, "%ld", (long)num_b);
|
|
oled_WriteString(buf, Font_16x26, White);
|
|
oled_SetCursor(0, 48);
|
|
oled_WriteString("*:chg #:=", Font_7x10, White);
|
|
}
|
|
else {
|
|
sprintf(buf, "=%ld", (long)result);
|
|
oled_WriteString(buf, Font_16x26, White);
|
|
oled_SetCursor(0, 28);
|
|
oled_WriteString("*:use #:rpt", Font_7x10, White);
|
|
}
|
|
|
|
oled_UpdateScreen();
|
|
}
|
|
|
|
static int8_t get_key(void) {
|
|
uint8_t k;
|
|
k = Check_Row(ROW1);
|
|
if (k == 0x04) return 1;
|
|
if (k == 0x02) return 2;
|
|
if (k == 0x01) return 3;
|
|
k = Check_Row(ROW2);
|
|
if (k == 0x04) return 4;
|
|
if (k == 0x02) return 5;
|
|
if (k == 0x01) return 6;
|
|
k = Check_Row(ROW3);
|
|
if (k == 0x04) return 7;
|
|
if (k == 0x02) return 8;
|
|
if (k == 0x01) return 9;
|
|
k = Check_Row(ROW4);
|
|
if (k == 0x04) return -1;
|
|
if (k == 0x02) return 0;
|
|
if (k == 0x01) return -2;
|
|
return -100;
|
|
}
|
|
|
|
static void reset_all(void) {
|
|
num_a = num_b = result = 0;
|
|
current_op = OP_NONE;
|
|
state = STATE_INPUT_A;
|
|
has_input = 0;
|
|
}
|
|
|
|
static void on_star(void) {
|
|
if (state == STATE_INPUT_A && has_input) {
|
|
current_op = OP_ADD;
|
|
state = STATE_INPUT_B;
|
|
}
|
|
else if (state == STATE_INPUT_B) {
|
|
if (current_op == OP_ADD) current_op = OP_SUB;
|
|
else if (current_op == OP_SUB) current_op = OP_MUL;
|
|
else current_op = OP_ADD;
|
|
}
|
|
else if (state == STATE_RESULT) {
|
|
num_a = result;
|
|
num_b = 0;
|
|
current_op = OP_ADD;
|
|
state = STATE_INPUT_B;
|
|
}
|
|
}
|
|
|
|
static void on_hash(void) {
|
|
if (state == STATE_INPUT_A) {
|
|
reset_all();
|
|
}
|
|
else if (state == STATE_INPUT_B) {
|
|
repeat_val = num_b;
|
|
repeat_op = current_op;
|
|
result = calc(num_a, num_b, current_op);
|
|
state = STATE_RESULT;
|
|
}
|
|
else if (state == STATE_RESULT) {
|
|
result = calc(result, repeat_val, repeat_op);
|
|
}
|
|
}
|
|
|
|
static void on_digit(int8_t d) {
|
|
if (state == STATE_INPUT_A) {
|
|
if (num_a < 100000000) {
|
|
num_a = num_a * 10 + d;
|
|
has_input = 1;
|
|
}
|
|
}
|
|
else if (state == STATE_INPUT_B) {
|
|
if (num_b < 100000000)
|
|
num_b = num_b * 10 + d;
|
|
}
|
|
else {
|
|
reset_all();
|
|
num_a = d;
|
|
has_input = 1;
|
|
}
|
|
}
|
|
|
|
int main(void) {
|
|
HAL_Init();
|
|
SystemClock_Config();
|
|
MX_GPIO_Init();
|
|
MX_I2C1_Init();
|
|
MX_USART6_UART_Init();
|
|
oled_Init();
|
|
|
|
int8_t last = -100;
|
|
update_display();
|
|
|
|
while (1) {
|
|
int8_t key = get_key();
|
|
if (key != last && key != -100) {
|
|
if (key >= 0) on_digit(key);
|
|
else if (key == -1) on_star();
|
|
else if (key == -2) on_hash();
|
|
update_display();
|
|
}
|
|
last = key;
|
|
HAL_Delay(100);
|
|
}
|
|
}
|
|
|
|
void SystemClock_Config(void) {
|
|
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
|
|
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
|
|
__HAL_RCC_PWR_CLK_ENABLE();
|
|
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
|
|
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
|
|
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
|
|
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
|
|
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
|
|
RCC_OscInitStruct.PLL.PLLM = 25;
|
|
RCC_OscInitStruct.PLL.PLLN = 336;
|
|
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
|
|
RCC_OscInitStruct.PLL.PLLQ = 4;
|
|
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) Error_Handler();
|
|
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
|
|
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
|
|
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
|
|
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
|
|
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
|
|
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK) Error_Handler();
|
|
}
|
|
|
|
void Error_Handler(void) { while(1) {} }
|