-2

ここに画像の説明を入力してください 質問 1- 以下のようなシステムでは、ユーザーは 4 桁のパスワードを入力する必要があります。プログラムを初めて実行すると、「パスワードを入力してください」と表示されます。ユーザーが 4 桁のパスワードを入力した後に正方形キーを押すと、パスワードが 1234 の場合、b0 に接続されている LED が点滅し、LCD 画面にパスワードを知っていることが表示されます。パスワードを 3 回間違えると、画面に「BLOKE」と表示されるはずです。そして、4 桁の「4321」ブロッキング パスワードを入力する必要があります。彼がブロッキング パスワードを正しく入力すると、b0 に接続された LED が点滅し、LCD にパスワードを知っていることが表示されます。

4

1 に答える 1

0

このスレッドはモデレーターによって数時間または数日で削除されると思います。

それまでは、楽しみながら、PIC16F877A、LCD モジュール、および 3x4 キーパッドが動作する Proteus シミュレーション モデルを取得する必要があるインフラストラクチャを実装するアプリケーションを投稿します。

パスワード検証を実装するコードは、元の投稿者が実装するために残されています。

このコードを Proteus シミュレーション ツールでテストしていないことに注意してください。MPLABX シミュレーターでは動作するようですが、あまり意味がありません。

/*
 * File:    main.c
 * Author:  dan1138
 * Target:  PIC16F877A
 * Compiler: XC8 v2.32
 * IDE: MPLABX v5.50
 * 
 * Created on January 27, 2022, 10:29 PM
 * 
 *                          PIC16F877A
 *                  +----------:_:----------+
 *        VPP ->  1 : MCLR/VPP      PGD/RB7 : 40 <> LCD_D7/PGD
 *            <>  2 : RA0/AN0       PGC/RB6 : 39 <> LCD_D6/PGC
 *            <>  3 : RA1               RB5 : 38 <> LCD_D5
 *            <>  4 : RA2               RB4 : 37 <> LCD_D4
 *            <>  5 : RA3               RB3 : 36 <> LCD_EN
 *            <>  6 : RA4               RB2 : 35 <> LCD_RW
 *            <>  7 : RA5               RB1 : 34 <> LCD_RS
 *            <>  8 : RE0          INT0/RB0 : 33 <> LED
 *            <>  9 : RE1               VDD : 32 <- PWR
 *            <> 10 : RE2               VSS : 31 <- GND
 *        PWR -> 11 : VDD               RD7 : 30 <> 
 *        GND -> 12 : VSS               RD6 : 29 <> 
 * 20MHz XTAL <> 13 : OSC1              RD5 : 28 <> 
 * 20MHz XTAL <> 14 : OSC2              RD4 : 27 <> 
 *      KP_C3 <> 15 : RC0/SOSCO   RX/DT/RC7 : 26 <> KP_RD
 *      KP_C2 <> 16 : RC1/SOSCI   TX/CK/RC6 : 25 <> KP_RC
 *      KP_C1 <> 17 : RC2/CCP1          RC5 : 24 <> KP_RB
 *            <> 18 : RC3               RC4 : 23 <> KP_RA
 *            <> 19 : RD0               RD3 : 22 <> 
 *            <> 20 : RD1               RD2 : 21 <> 
 *                  +-----------------------:
 *                           DIP-40
 * Description:
 * 
 */
// CONFIG
#pragma config FOSC = HS        // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = OFF      // Brown-out Reset Enable bit (BOR disabled)
#pragma config LVP = OFF        // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

/*
 * Tell compiler what we intend to set the system oscillator frequency as.
 */
#define _XTAL_FREQ (20000000UL)

#include <xc.h>
#include <stdio.h>

/* Define the LCD port pins */
#define LCD_DATA_BITS_MASK  0x3C
#define LCD_PORT_OUT        PORTC
#define LCD_PORT_DIR        TRISC

#define LCD_RS_PIN          PORTBbits.RB1
#define LCD_RW_PIN          PORTBbits.RB2
#define LCD_EN_PIN          PORTBbits.RB3
#define LCD_D4_PIN          PORTBbits.RB4
#define LCD_D5_PIN          PORTBbits.RB5
#define LCD_D6_PIN          PORTBbits.RB6
#define LCD_D7_PIN          PORTBbits.RB7

#define LCD_RS_DIR          TRISBbits.TRISB1
#define LCD_RW_DIR          TRISBbits.TRISB2
#define LCD_EN_DIR          TRISBbits.TRISB3
#define LCD_D4_DIR          TRISBbits.TRISB4
#define LCD_D5_DIR          TRISBbits.TRISB5
#define LCD_D6_DIR          TRISBbits.TRISB6
#define LCD_D7_DIR          TRISBbits.TRISB7

/* Clear display command */
#define CLEAR_DISPLAY       0b00000001

/* Return home command */
#define RETURN_HOME         0b00000010

/* Display ON/OFF Control defines */
#define DON                 0b00001111   /* Display on      */
#define DOFF                0b00001011   /* Display off     */
#define CURSOR_ON           0b00001111   /* Cursor on       */
#define CURSOR_OFF          0b00001101   /* Cursor off      */
#define BLINK_ON            0b00001111   /* Cursor Blink    */
#define BLINK_OFF           0b00001110   /* Cursor No Blink */

/* Cursor or Display Shift defines */
#define SHIFT_CUR_LEFT      0b00010011   /* Cursor shifts to the left   */
#define SHIFT_CUR_RIGHT     0b00010111   /* Cursor shifts to the right  */
#define SHIFT_DISP_LEFT     0b00011011   /* Display shifts to the left  */
#define SHIFT_DISP_RIGHT    0b00011111   /* Display shifts to the right */

/* Function Set defines */
#define FOUR_BIT            0b00101111   /* 4-bit Interface               */
#define EIGHT_BIT           0b00111111   /* 8-bit Interface               */
#define LINE_5X7            0b00110011   /* 5x7 characters, single line   */
#define LINE_5X10           0b00110111   /* 5x10 characters               */
#define LINES_5X7           0b00111011   /* 5x7 characters, multiple line */

/* Start address of each line */
#define LINE_ONE            0x00
#define LINE_TWO            0x40

static void LCD_E_Pulse(void)
{
    LCD_EN_PIN = 1;
    __delay_us(4);
    LCD_EN_PIN = 0;
    __delay_us(4);
}

static void LCD_DelayPOR(void)
{
    __delay_ms(15);
}

static void LCD_Delay(void)
{
    __delay_ms(5);
}

static void LCD_PutByte(unsigned char LCD_Data)
{
    LCD_PORT_DIR &= ~LCD_DATA_BITS_MASK; /* make LCD data bits outputs */
    
    /* send first(high) nibble */
    LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK;
    if(LCD_Data & 0x10) LCD_D4_PIN = 1;
    if(LCD_Data & 0x20) LCD_D5_PIN = 1;
    if(LCD_Data & 0x40) LCD_D6_PIN = 1;
    if(LCD_Data & 0x80) LCD_D7_PIN = 1;
    LCD_E_Pulse();
    
    /* send second(low) nibble */
    LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK;
    if(LCD_Data & 0x01) LCD_D4_PIN = 1;
    if(LCD_Data & 0x02) LCD_D5_PIN = 1;
    if(LCD_Data & 0x04) LCD_D6_PIN = 1;
    if(LCD_Data & 0x08) LCD_D7_PIN = 1;
    LCD_E_Pulse();

    LCD_PORT_DIR |= LCD_DATA_BITS_MASK; /* make LCD data bits inputs */
}

void LCD_SetPosition(unsigned char data)
{
    LCD_RS_PIN = 0;
    LCD_PutByte((unsigned char)(data | 0x80));
    __delay_us(40);
}

void LCD_WriteCmd(unsigned char data)
{
    LCD_RS_PIN = 0;
    LCD_PutByte(data);
    __delay_ms(4);
}

void LCD_WriteData(unsigned char data)
{
    LCD_RS_PIN = 1;
    LCD_PutByte(data);
    LCD_RS_PIN = 0;
    __delay_us(40);
}

void LCD_Init(void) 
{
    unsigned char LCD_Data;
    
    LCD_PORT_DIR &= ~LCD_DATA_BITS_MASK;    /* make LCD data bits outputs */
    LCD_EN_DIR = 0;                         /* make LCD Enable strobe an output */
    LCD_RW_DIR = 0;                         /* make LCD Read/Write an output */
    LCD_RS_DIR = 0;                         /* make LCD Register select an output */
    LCD_EN_PIN = 0;                         /* set LCD Enable strobe to not active */
    LCD_RW_PIN = 0;                         /* set LCD write mode  */
    LCD_RS_PIN = 0;                         /* set LCD Register select to command group */
    LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK;    /* set LCD data bits to zero */
    LCD_DelayPOR();                         /* wait for LCD power on to complete */

    /* Force LCD to 8-bit mode */
    LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK;    /* set LCD data bits to zero */
    LCD_D4_PIN = 1;
    LCD_D5_PIN = 1;
    LCD_E_Pulse();
    LCD_Delay();
    LCD_E_Pulse();
    LCD_Delay();
    LCD_E_Pulse();
    LCD_Delay();
    
    /* Set LCD to 4-bit mode */
    LCD_PORT_OUT &= ~LCD_DATA_BITS_MASK;    /* set LCD data bits to zero */
    LCD_D5_PIN = 1;
    LCD_E_Pulse();
    LCD_Delay();

    /* Initialize LCD mode */
    LCD_WriteCmd(FOUR_BIT & LINES_5X7);

    /* Turn on display, Setup cursor and blinking */
    LCD_WriteCmd(DOFF & CURSOR_OFF & BLINK_OFF);
    LCD_WriteCmd(DON & CURSOR_OFF & BLINK_OFF);
    LCD_WriteCmd(CLEAR_DISPLAY);
    LCD_WriteCmd(SHIFT_CUR_LEFT);

    /* Set first position on line one, left most character */
    LCD_SetPosition(LINE_ONE);
}
/*
 * Hook for printf
 */
void putch(char txData)
{
    LCD_WriteData(txData);
}
/*
 * Keypad 3x4
 */
#define KP_DEBOUNCE_COUNT (16)

#define KP_RA_IN      PORTCbits.RC4
#define KP_RB_IN      PORTCbits.RC5
#define KP_RC_IN      PORTCbits.RC6
#define KP_RD_IN      PORTCbits.RC7
#define KP_C1_OUT     PORTCbits.RC2
#define KP_C2_OUT     PORTCbits.RC1
#define KP_C3_OUT     PORTCbits.RC0

#define KP_RA_IN_DIR  TRISCbits.TRISC4
#define KP_RB_IN_DIR  TRISCbits.TRISC5
#define KP_RC_IN_DIR  TRISCbits.TRISC6
#define KP_RD_IN_DIR  TRISCbits.TRISC7
#define KP_C1_OUT_DIR TRISCbits.TRISC2
#define KP_C2_OUT_DIR TRISCbits.TRISC1
#define KP_C3_OUT_DIR TRISCbits.TRISC0

enum eKeyEvent
{
    eNoEvent = 0,
    eKeyChanged
};

typedef enum eKeyEvent eKeyEvent_t;

struct sKeypadEvent
{
    unsigned int ButtonMatrix;
    unsigned int ChangedMask;    
};

typedef struct sKeypadEvent KeypadEvent_t;

static unsigned int  KP_Sample;
static unsigned int  KP_Last;
static unsigned int  KP_Changed;
static unsigned int  KP_Stable;
static unsigned char KP_DebounceCounter;
/*
 * Initialize the GPIO pins used for the 3x4 keypad
 */
void Keypad_Init(void)
{
    KP_RB_IN_DIR  = 1;
    KP_RB_IN_DIR  = 1;
    KP_RC_IN_DIR  = 1;
    KP_RD_IN_DIR  = 1;
    KP_C1_OUT_DIR = 0;
    KP_C2_OUT_DIR = 0;
    KP_C3_OUT_DIR = 0;
    KP_Last = 0;
    KP_DebounceCounter = 0;
}
/*
 * Called from ISR handler to sample all keys
 * in the keypad matrix, debounce and update the
 * stable state.
 */
void Keypad_Scan(void)
{
    KP_Sample = 0;
    KP_C1_OUT = 1;
    KP_C2_OUT = 1;
    KP_C3_OUT = 1;
    KP_C2_OUT_DIR = 1;
    KP_C3_OUT_DIR = 1;
    KP_C1_OUT_DIR = 0;
    KP_C1_OUT = 0;
    if (!KP_RA_IN) KP_Sample |= 0x0001;
    if (!KP_RB_IN) KP_Sample |= 0x0002;
    if (!KP_RC_IN) KP_Sample |= 0x0004;
    if (!KP_RD_IN) KP_Sample |= 0x0008;
    KP_C1_OUT = 1;
    KP_C1_OUT_DIR = 1;
    KP_C3_OUT_DIR = 1;
    KP_C2_OUT_DIR = 0;
    KP_C2_OUT = 0;
    if (!KP_RA_IN) KP_Sample |= 0x0010;
    if (!KP_RB_IN) KP_Sample |= 0x0020;
    if (!KP_RC_IN) KP_Sample |= 0x0040;
    if (!KP_RD_IN) KP_Sample |= 0x0080;
    KP_C2_OUT = 1;
    KP_C2_OUT_DIR = 1;
    KP_C1_OUT_DIR = 1;
    KP_C3_OUT_DIR = 0;
    KP_C3_OUT = 0;
    if (!KP_RA_IN) KP_Sample |= 0x0100;
    if (!KP_RB_IN) KP_Sample |= 0x0200;
    if (!KP_RC_IN) KP_Sample |= 0x0400;
    if (!KP_RD_IN) KP_Sample |= 0x0800;
    KP_C2_OUT = 0;
    KP_C1_OUT = 0;
    KP_C1_OUT_DIR = 0;
    KP_C2_OUT_DIR = 0;
    KP_C3_OUT_DIR = 0;
    
    /* check if matrix changed since last scan */
    if ((KP_Sample ^ KP_Last) != 0)
    {
        KP_Last = KP_Sample;
        KP_DebounceCounter = 0;
        return;
    }

    /* check if we have sampled inputs for long enough to debounce */
    if (KP_DebounceCounter < KP_DEBOUNCE_COUNT)
    {
        KP_DebounceCounter++;
        return;
    }

    /* Update the stable output only after pevious stable state has been read */
    if (KP_Changed == 0)
    {
        KP_Changed = KP_Sample ^ KP_Stable;
        KP_Stable = KP_Sample;
    }
}
/*
 * Returns non-zero when a key event occurs.
 * A key event is when one key is pressed or released.
 */
eKeyEvent_t Keypad_GetEvent(void)
{
    eKeyEvent_t Event;
    

    INTCONbits.TMR0IE = 0;  /* disable tick to read keypad sample memory */
    if (KP_Changed == 0)
    {
        Event = eNoEvent;
    }
    else
    {
        Event = eKeyChanged;
    }
    INTCONbits.TMR0IE = 1;  /* enable tick */
    
    return Event;
}
/*
 * Returns ASCII character of keypad event.
 * If more than one key is pressed returns ZERO.
 */
unsigned char Keypad_GetKey(KeypadEvent_t * KeypadEvent)
{
    unsigned char Key;
    unsigned int ButtonMatrix;
    unsigned int ChangedMask;    

    Key = 0;
    INTCONbits.TMR0IE = 0;  /* disable tick to read keypad sample memory */
    ButtonMatrix = KP_Stable;
    ChangedMask  = KP_Changed;
    /* Tell ISR we have read the current state */
    KP_Changed = 0;
    INTCONbits.TMR0IE = 1;  /* enable tick */

    /* return current state of the keypad matrix */
    if (KeypadEvent)
    {
        KeypadEvent->ButtonMatrix = ButtonMatrix;
        KeypadEvent->ChangedMask  = ChangedMask;
    }
    /* decode key in ASCII */
    if (ChangedMask)
    {
        switch (ButtonMatrix)
        {
        case 0x0001U:
            Key = '1';
            break;
        case 0x0002U:
            Key = '4';
            break;
        case 0x0004U:
            Key = '7';
            break;
        case 0x0008U:
            Key = '*';
            break;
        case 0x0010U:
            Key = '2';
            break;
        case 0x0020U:
            Key = '5';
            break;
        case 0x0040U:
            Key = '8';
            break;
        case 0x0080U:
            Key = '0';
            break;
        case 0x0100U:
            Key = '3';
            break;
        case 0x0200U:
            Key = '6';
            break;
        case 0x0400U:
            Key = '9';
            break;
        case 0x0800U:
            Key = '#';
            break;
        default:
            Key = 0;
            break;
        }
    }
    return Key;
}
/*
 * Setup TIMER0 to assert an interrupt every 16384 instruction cycles
 */
void Tick_Init(void)
{
    INTCONbits.TMR0IE = 0;
    OPTION_REG = 0xD3;      /* TMR0 clock FOSC/4Y, TMR0 prescale 1:16      */
    TMR0 = 0;               /* TIMER0 will assert the overflow flag every 256*16 (4096)               */
    INTCONbits.TMR0IF = 0;  /* instruction cycles, with a 5MHz oscillator this is 0.8192 milliseconds. */
    INTCONbits.TMR0IE = 1;
}
/*
 * Main application
 */

volatile unsigned char SysTick;

void main(void) 
{
    unsigned int  KP_sample;
    unsigned char Key;
    KeypadEvent_t Keypad_Event;

    /* Disable all interrupt sources */
    INTCON = 0;
    PIE1 = 0;
    PIE2 = 0;
    /* Make all GPIO pins digital */
    ADCON1 = 0x0F;
    CMCON = 0x07;
    
    LCD_Init();
    Keypad_Init();
    Tick_Init();
    
    /* Enable interrupt system */
    INTCONbits.PEIE = 1;
    INTCONbits.GIE  = 1;

    __delay_ms(100);

    LCD_SetPosition(LINE_ONE);
    printf("Enter Password");
    
    /*
     * Application loop
     */
    for(;;)
    {
        /* check for and process key presses */
        if (Keypad_GetEvent() == eKeyChanged)
        {
            LCD_SetPosition(LINE_TWO);
            printf("Key Pressed:    ");
            Key = Keypad_GetKey(&Keypad_Event);
            if (Key != 0)
            {
                LCD_SetPosition(LINE_TWO+13);
                LCD_WriteData(Key);
                switch (Key)
                {
                    case '0':
                        break;
                    case '1':
                        break;
                    case '2':
                        break;
                    case '3':
                        break;
                    case '4':
                        break;
                    case '5':
                        break;
                    case '6':
                        break;
                    case '7':
                        break;
                    case '8':
                        break;
                    case '9':
                        break;
                    case '*':
                        break;
                    case '#':
                        break;
                    default:
                        break;
                }
            }
        }
    }
}
/*
 * Interrupt handlers
 */
void __interrupt() ISR_Handler(void)
{
    /* Handle system tick */
    if (INTCONbits.TMR0IE)
    {
        if(INTCONbits.TMR0IF)
        {
            INTCONbits.TMR0IF = 0;
            SysTick++;
            Keypad_Scan();
        }
    }
}
于 2022-01-28T08:05:30.157 に答える