0

完成我的项目(使用 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);
               }
          }
     }

}
4

3 回答 3

4

您正在使用浮点类型,在某些数学运算下,并不总是保证以完全准确的方式表示。

可能值得进行某种检查以查看其中一个或两个操作数是否为整数,然后尽可能使用int类型。

于 2011-05-04T18:47:02.747 回答
3

原因是它在内部存储为二进制浮点,而不是十进制浮点,这意味着一些容易用十进制表示的数字不可能用二进制表示完全准确,因此四舍五入到最接近的可能值。

于 2011-05-04T18:48:25.777 回答
1

通常,像这样的两个小整数浮点数的直接乘法会产生x.0结果。但是,对于更复杂的浮点数学,您确实必须采取任何结果都是估计的态度,并且会有一定的少量错误。通常它取决于输入中的错误量,但至少您应该将仅在最后一个可表示数字中关闭的任何结果视为“正确”。一般来说,期望从浮点数学中得到准确的答案是错误的

另请注意,在这种情况下,它似乎试图告诉您答案是 11.9(9 重复)。从数学上讲,这与 12 相同。所以我不会真的认为这个答案是“错误的”。

于 2011-05-04T18:58:47.867 回答