完成我的项目(使用 PIC18 和键盘 4x4、LCD 和 4 个 LED 的计算器)后,我在乘法运算中遇到了奇怪的问题
当乘以奇数 (> 1) * 偶数 (> 0) 时,结果并不完全正确,例如 3 * 4 = 11.99999
=====================
在这里,我将尝试描述这种情况:
用户按下键盘的一个按钮,然后程序从键盘获取字符并将其存储到 char[](一次一个字符),所以最后我们有两个 char[] Operand[13] 和 Operand[13]。输入 Operand1 和 Operand2 后,程序使用 atof() 函数将其转换为浮点数,然后应用一些操作('+'、'-'、'*' 或 '/')并将结果存储在 int Result 中。最后,程序使用 FloatToStr() 函数将此 int 转换为 char[] 并显示在 LCD 上。
======================
这是我的代码:(对不起,它有点长,但我希望你帮我解决这个问题)
unsigned char Key[4][4] = {{'1','2','3','4'}, // Keypad 4x4 Matrix
{'5','6','7','8'},
{'9','0','.','E'},
{'+','-','*','/'}};
unsigned char Operand_String[2][13], Operation_String, Result_String[15]; // Where we store the operand, operation & Result as chars
unsigned char Row, Column; // Row & Column determine the location of Key in the Keypad matrix that the user pressed
unsigned char State; // 1: Operand1 - 2: Operand2 - 3: Operation - 4: Result
unsigned int EntryCount; // Counter for counts entries on LCD
unsigned int Operand1_length, Operand2_length; // Lengths of Operand1 & Operand2
bit Direction; // 1: right - 0: left
bit Operand1_Sign, Operand2_Sign; // 1: negative - 0: positive
signed float Operand1, Operand2, Result; // Fields where we store Operand1, Operand2 and Result
typedef unsigned int boolean; // ** DEFINING **
#define false 0 // ** BOOLEAN **
#define true (!false) // ** TYPE **
boolean ButtonIsPressed = false; // Flag that indicates whether a button is pressed or no button is pressed
boolean FloatingPointIncluded = false; // Flag that indicates if there is a floating point in the LCD or not
boolean Operand1_signed = false; // Flag that indicates if Operand1 has a sign or not
boolean Operand2_signed = false; // Flag that indicates if Operand2 has a sign or not
// ***** Lcd pinout settings *****
sbit LCD_RS at RD4_bit;
sbit LCD_EN at RD5_bit;
sbit LCD_D7 at RD3_bit;
sbit LCD_D6 at RD2_bit;
sbit LCD_D5 at RD1_bit;
sbit LCD_D4 at RD0_bit;
// ***** Pin Direction *****
sbit LCD_RS_Direction at TRISD4_bit;
sbit LCD_EN_Direction at TRISD5_bit;
sbit LCD_D7_Direction at TRISD3_bit;
sbit LCD_D6_Direction at TRISD2_bit;
sbit LCD_D5_Direction at TRISD1_bit;
sbit LCD_D4_Direction at TRISD0_bit;
// ***** End LCD module connections *****
// ***** Method that determines no. of Row and Column of keypad matrix where the user presses the button of that location on the keypad *****
void scan_key()
{
unsigned char portValue[4][4] = {{0b11101110, 0b11101101, 0b11101011, 0b11100111},
{0b11011110, 0b11011101, 0b11011011, 0b11010111},
{0b10111110, 0b10111101, 0b10111011, 0b10110111},
{0b01111110, 0b01111101, 0b01111011, 0b01110111}};
unsigned char temp[4] = {0B11111110, 0B11111101, 0B11111011, 0B11110111};
unsigned int loop_col = 1;
unsigned int loop_row = 1;
for (loop_col = 1; loop_col < 5; loop_col++)
{
PORTB = temp[loop_col - 1];
for (loop_row = 1; loop_row < 5; loop_row++)
{
if ( PORTB == portValue[loop_row - 1][loop_col - 1])
{
Row = loop_row;
Column = loop_col;
return;
}
}
PORTB = 0B11110000;
}
}
// ***** Interrupt Service Routine (ISR) *****
void interrupt() org 0x08
{
if (INTCON.TMR0IF) // Timer0 Interrupt
{
scan_key();
//Delay_ms(40);
INTCON.RBIE = 1;
INTCON.TMR0IF = 0;
}
else if (INTCON.RBIF) // PORTB Interrupt
{
INTCON.TMR0IF = 1;
INTCON.TMR0IE = 1;
INTCON.RBIE = 0;
INTCON.RBIF = 0;
ButtonIsPressed = true;
}
}
// ***** Method that calculates the result of the arithmatic Operation *****
float CalculateResult()
{
Operand1 = atof(Operand_String[0]);
Operand2 = atof(Operand_String[1]);
if(Operand1_sign == 1) Operand1 = - Operand1;
if(Operand2_sign == 1) Operand2 = - Operand2;
switch(Operation_String)
{
case '+': Result = Operand1 + Operand2; break;
case '-': Result = Operand1 - Operand2; break;
case '*': Result = Operand1 * Operand2; break;
case '/': Result = Operand1 / Operand2; break;
}
return Result;
}
// ***** Method that makes LEDs blink *****
void LEDsBlink(int iteration)
{
char PORTA_Temp;
int i;
PORTA_Temp = PORTA;
if(iteration < 0)
{
PORTA = ~PORTA;
Delay_ms(200);
}
else
{
for(i = 0; i < iteration; i++)
{
PORTA = 0x0F;
Delay_ms(50);
PORTA = 0x00;
Delay_ms(50);
}
PORTA = PORTA_Temp;
}
}
// ***** Method that resets the variables *****
void Reset_Values()
{
EntryCount = 0;
State = 1;
Row = 0;
Column = 0;
Direction = 0;
Operand1_Sign = 0;
Operand2_Sign = 0;
Operand1 = 0;
Operand2 = 0;
Result = 0;
memset(Operand_String, 0, 2 * 13);
memset(Result_String, 0, 15);
ButtonIsPressed = false;
Operand1_signed = false;
Operand2_signed = false;
PORTA = 0x0F; // Turn on the 4 LEDs
}
void main()
{
// ***** Initializations of PIC18F4550 *****
TRISA = 0; // Configure the 4 LEDs as output
PORTA = 0x0F; // Turn on the 4 LEDs
TRISB = 0xF0; // Configure RB0 ~ RB3 as outputs & RB4 ~ RB7 as inputs
PORTB = 0xF0; // Assign 0xF0
OSCCON = 0x63; // 4 MHz - Internal oscillator
INTCON2.B7 = 0; // PORTB pull-ups are enabled by individual port latch values
INTCON.RBIF = 0; // Reset the interrupt flag
INTCON.RBIE = 1; // RB Change interrupt ON
INTCON.GIE = 1; // Global interrupts ON
ADCON1 = 0b00001111; // Digital inputs
// ***** Initializations of LCD *****
Lcd_Init(); // Initialize LCD
Lcd_Cmd(_LCD_CLEAR); // Clear LCD
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off
Lcd_Out(1, 2, "Fouad Al-Malki"); // ** WELCOME **
Lcd_Out(2, 4, "CALCULATOR"); // ** MESSAGE **
Delay_ms(2000); // delay for 2 seconds
Lcd_Cmd(_LCD_CLEAR); // Clear DCD
Lcd_Out(1, 4, "Operand1: "); // Write "Operand1: " at first row
Lcd_Cmd(_LCD_SECOND_ROW); // Make current position at second row
Lcd_Cmd(_LCD_BLINK_CURSOR_ON); // Cursor on
// ***** Reset all values *****
Reset_Values();
while(1)
{
// ***** Control of LCD *****
if(ButtonIsPressed)
{
if(State == 1)
{
if(Key[row-1][column-1] != 'E')
{
if((EntryCount <= 13 && Key[row-1][column-1] != '+' && Key[row-1][column-1] != '-' && Key[row-1][column-1] != '/' && Key[row-1][column-1] != '*'))
{
if((Key[row-1][column-1] == '.' && !FloatingPointIncluded && EntryCount > 0) || Key[row-1][column-1] != '.')
{
Lcd_Chr_Cp(Key[row-1][column-1]);
Operand_String[0][EntryCount] = Key[row-1][column-1];
EntryCount++;
if(Key[row-1][column-1] == '.') FloatingPointIncluded = true;
}
else LEDsBlink(3);
}
else if(!Operand1_signed && EntryCount == 0 && (Key[row-1][column-1] == '+' || Key[row-1][column-1] == '-'))
{
if(Key[row-1][column-1] == '+') Operand1_Sign = 0;
else if(Key[row-1][column-1] == '-') Operand1_Sign = 1;
Lcd_Chr_Cp(Key[row-1][column-1]);
Operand1_signed = true;
}
else LEDsBlink(3);
}
else if(Key[row-1][column-1] == 'E' && EntryCount != 0)
{
State = 2;
FloatingPointIncluded = false;
Operand1_length = EntryCount;
EntryCount = 0;
Row = 0;
Column = 0;
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Out(1, 4, "Operand2: ");
Lcd_Cmd(_LCD_SECOND_ROW);
Lcd_Cmd(_LCD_BLINK_CURSOR_ON); // Cursor on
if(PORTA.B0 == 1)
{
PORTA = 0x08;
}
}
else LEDsBlink(3);
}
else if(State == 2)
{
if(Key[row-1][column-1] != 'E')
{
if((EntryCount <= 13 && Key[row-1][column-1] != '+' && Key[row-1][column-1] != '-' && Key[row-1][column-1] != '/' && Key[row-1][column-1] != '*'))
{
if((Key[row-1][column-1] == '.' && !FloatingPointIncluded && EntryCount > 0) || Key[row-1][column-1] != '.')
{
Lcd_Chr_Cp(Key[row-1][column-1]);
Operand_String[1][EntryCount] = Key[row-1][column-1];
EntryCount++;
if(Key[row-1][column-1] == '.') FloatingPointIncluded = true;
}
else LEDsBlink(3);
}
else if(!Operand2_signed && EntryCount == 0 && (Key[row-1][column-1] == '+' || Key[row-1][column-1] == '-'))
{
if(Key[row-1][column-1] == '+') Operand2_Sign = 0;
else if(Key[row-1][column-1] == '-') Operand2_Sign = 1;
Lcd_Chr_Cp(Key[row-1][column-1]);
Operand2_signed = true;
}
else LEDsBlink(3);
}
else if(Key[row-1][column-1] == 'E' && EntryCount != 0)
{
State = 3;
FloatingPointIncluded = false;
Operand2_length = EntryCount;
EntryCount = 0;
Row = 0;
Column = 0;
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Out(1, 4, "Operation: ");
Lcd_Cmd(_LCD_SECOND_ROW);
Lcd_Cmd(_LCD_BLINK_CURSOR_ON); // Cursor on
if(PORTA.B0 == 1)
{
PORTA = PORTA << 1;
Direction = 0;
}
}
else LEDsBlink(3);
}
else if(State == 3)
{
if(Key[row-1][column-1] != 'E')
{
if(EntryCount == 0 && (Key[row-1][column-1] == '+' || Key[row-1][column-1] == '-' || Key[row-1][column-1] == '/' || Key[row-1][column-1] == '*'))
{
Lcd_Chr_Cp(Key[row-1][column-1]);
Operation_String = Key[row-1][column-1];
EntryCount++;
}
else LEDsBlink(3);
}
else if(Key[row-1][column-1] == 'E' && EntryCount != 0)
{
State = 4;
FloatingPointIncluded = false;
EntryCount = 0;
Row = 0;
Column = 0;
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Out(1, 3, "The Result: ");
Lcd_Cmd(_LCD_SECOND_ROW);
Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off
Result = CalculateResult();
//printOut(Result, "/*rn");
FloatToStr(Result, Result_String);
Lcd_Out(2,1,Result_String);
PORTA = 0x0F;
}
else LEDsBlink(3);
}
else if(State == 4)
{
if(Key[row-1][column-1] == 'E')
{
Reset_Values();
Lcd_Cmd(_LCD_CLEAR); // Clear display
Lcd_Out(1, 4, "Operand1: ");
Lcd_Cmd(_LCD_SECOND_ROW);
Lcd_Cmd(_LCD_BLINK_CURSOR_ON); // Cursor on
PORTA == 0x0F;
}
}
ButtonIsPressed = false;
}
// ***** Control of LEDs *****
else
{
if(State == 1)
{
if(PORTA == 0x0F) PORTA = 0x01;
Delay_ms(300);
if(PORTA < 0x08) PORTA = PORTA << 1;
if(PORTA == 0x08)
{
Delay_ms(300);
PORTA = 0x01;
}
}
if(State == 2)
{
Delay_ms(300);
PORTA = PORTA >> 1;
if(STATUS.C == 1)
{
PORTA = 0x08;
STATUS.C = 0;
}
}
if(State == 3)
{
Delay_ms(300);
if (Direction == 0) {
PORTA = PORTA >> 1;
if (PORTA.B0 == 1) Direction = 1;
}
else
{
PORTA = PORTA << 1;
if (PORTA.B3 == 1) Direction = 0;
}
}
if(State == 4)
{
LEDsBlink(-1);
}
}
}
}