Я хочу сделать калькулятор на STM32 с моей клавиатурой 4x4 и SSD (7-сегментный дисплей). Я буду использовать A в качестве сложения на клавиатуре и, скажем, я посчитаю это: 9 + 8 = 17. Я использую прерывания для получения чисел с клавиатуры, поэтому прерывания, которые я использовал для этих чисел, следующие:
//INTERRUPT FOR NUMBER 9
void EXTI0_1_IRQHandler(void){ // Interrupt from PB0
GPIOB->ODR ^= (1U << 9); //PB9
if ((GPIOB->IDR >> 0) & 1){
//9
setSSD(9);
}
GPIOB->ODR ^= (1U << 9); //PB9
}
//INTERRUPT FOR NUMBER 8
void EXTI2_3_IRQHandler(void){// Interrupt from PB2
GPIOB->ODR ^= (1U << 9); //PB9
if ((GPIOB->IDR >> 2) & 1){
//8
setSSD(8);
}
}
//INTERRUPT FOR A
void EXTI4_15_IRQHandler(void){
if ((GPIOA->IDR >> 9) & 1){
//A
addition (x,y);
}
GPIOB->ODR ^= (1U << 4); //PB4
}
Вот моя проблема: на обычном языке C я бы попросил пользователя дать число с помощью scanf и поместить число в переменную x, а затем взять другое число, поместить его в y. И определите A как x + y, чтобы вычисление было выполнено.
Но здесь нет такой функции, как scanf, так как я могу упорядочить прерывания? Например, первое прерывание (нажатие первого числа) должно быть x, а второе прерывание (нажатие второго числа) должно быть y.
Извините, мой разум перепутался, я был бы очень рад, если бы вы могли придумать какое-либо решение.
7 сег. отображать. Отредактировано.
Сколько цифр?
Одно прерывание на клавишу кажется довольно экстравагантным (и маловероятным). Это действительно то, как работает оборудование?
Пользовательский интерфейс, как вы его описываете, имеет состояние, то есть он может находиться в состоянии, когда вы вводите «X», или в состоянии, когда вы вводите «Y». Вы можете добавить «ветви» состояния в обработчики прерываний, т.е. if (state == StateX) ... else if (state == StateY) ...
. Но обработчики прерываний часто лучше оставить короткими и простыми.
Один из способов сделать это может быть следующим: пусть прерывания по цифре и десятичной точке работают в каком-то Q
регистре, а затем, когда нажаты нецифровые клавиши, вы используете текущее состояние, чтобы решить, в какой регистр Q
следует скопировать (и вы также обновите состояние тогда).
Вам нужно будет нарисовать себе диаграмму состояний, чтобы определить, какие состояния вам интересны, что вызывает переходы между ними и что происходит, когда каждое состояние входит и выходит (эти действия могут быть пустыми, конечно).
Вам нужно пересмотреть свой дизайн, а не смешивать ввод-вывод с приложением. Сначала заставьте ваш ввод-вывод работать с устранением дребезга коммутатора и т. д. (который может использовать или не использовать прерывания); затем напишите приложение-калькулятор. Вы уже обдумали, как это сделать с помощью stdio, и точно так же, как scanf()
не обновляет дисплей или не выполняет вычисления, не должен этого делать и ваш драйвер клавиатуры.
Подходящий драйвер клавиатуры будет обнаруживать нажатия клавиш, выполнять устранение дребезга, а затем помещать нажатие клавиши в кольцевой буфер или очередь. После этого ваше приложение-калькулятор может быть реализовано в обычном потоке обработки, а не в обработчиках прерываний.
Затем вам нужно разбить приложение калькулятора на подпрограммы для каждого возможного нажатия клавиши. Например, ниже я предположил простой калькулятор с четырьмя функциями.
В частности, ответ на ваш вопрос заключается в использовании простого «автомата состояний», где состояние увеличивается при нажатии клавиши оператора, и использовать это «состояние», чтобы определить, какой оператор обновляется. Вам нужно только два «регистра», потому что вместо A = x + y настоящий калькулятор выполняет x = x + y, так что ответ можно использовать в качестве операнда в дальнейших операндах.
// Variables to store the operands and operator
int operand[2] = 0 ;
int operand_idx = 0 ;
typedef enum
{
ADD,SUB,MUL,DIV
} eOperator ;
eOperator operator ;
// Call for each digit key pressed
void addDigit( int d )
{
operand[operand_idx] *= 10 ;
operand[operand_idx] += d ;
display( operand[operand_idx] ) ;
}
// Call when an operator key is pressed
void setOperator( eOperator op )
{
if ( operator == 0 )
{
operator = op ;
operand_idx = 1 ;
}
else
{
calculate() ;
}
}
// Call when " = " / answer key pressed
void calculate()
{
switch( operator )
{
case ADD : operand[0] = operand[0] + operand[1] ; break ;
case SUB : operand[0] = operand[0] - operand[1] ; break ;
case MUL : operand[0] = operand[0] * operand[1] ; break ;
case DIV : operand[0] = operand[0] / operand[1] ; break ;
}
display( operand[0] ) ;
operand[1] = 0 ;
}
// Call to clear calculation
void clear()
{
operand[0] = 0 ;
operand[1] = 0 ;
operand_idx = 0 ;
}
Затем, если вы реализуете подходящий драйвер клавиатуры с функцией getKey()
, тогда сам калькулятор будет выглядеть так:
for(;;)
{
char key = getKey() ;
if ( isdigit( key ) )
{
addDigit( key - '0' ) ;
}
else
{
switch( key )
{
case 'A' : setOperator( ADD ) ; break ;
case 'B' : setOperator( SUB ) ; break ;
case 'C' : setOperator( MUL ) ; break ;
case 'D' : setOperator( DIV ) ; break ;
case 'E' : calculate() ; break ;
case 'F' : clear() ; break ;
}
}
}
SSD? Это может быть многое. Устранить неоднозначность. Хотя обработка нажатий клавиш в прерываниях возможна, у вас, вероятно, будут проблемы с отказом переключения. Вам лучше разделить процесс на обработку нажатия клавиш, числовой ввод и калькулятор, а не пытаться делать все это в прерываниях - это нецелесообразно.