// PIC16F876A Configuration Bit Settings // 'C' source line config statements // CONFIG #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #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) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. #include #define _XTAL_FREQ 20000000 // 20MHz #define TIMER_COUNT 60 #define BUFFERSIZE 16 unsigned char outB[] = {0b00000001, 0b00000010, 0b00000100, 0b00001000, 0b00010000, 0b00100000}; //unsigned char outB[] = {0b11111110, 0b11111101, 0b11111011, 0b11110111, 0b11101111, 0b11011111}; unsigned char keyStat[6][5]; volatile int row; volatile char keyBuffer[BUFFERSIZE]; volatile int head, knum; char keycode; #define LCDCLK PORTCbits.RC7 #define LCDDAT PORTCbits.RC6 #define LCDWAIT 100 char keyMap[6][5] = { { 0, 0, '/', '*', 'A'}, { 0, '0', '2', '3', '1'}, {'.', 'R', '5', '6', '4'}, { 0, '7', '9', '-', '8'}, { 0, '%', 0, '=', 'M'}, { 0, 0, 0, 'C', 0} }; void sendChar(char chr) { for(int n = 0; n < 8; n++) { LCDDAT = (chr >> n) & 1; __delay_us(LCDWAIT); LCDCLK = 0; __delay_us(LCDWAIT); LCDCLK = 1; } } // アナログ入力 char analogRead(char ch) { ADCON0 &= 0b11000111; ADCON0 |= (ch << 3); ADCON0bits.ADON = 1; // ADコンバータON __delay_us(20); // 充電待ち //ADコンバート GO = 1; // AD変換開始 while(GO); // AD変換終了待ち return ADRESL; } // キーをバッファに入力 void enqueue(char ch) { if(knum < BUFFERSIZE) { keyBuffer[(head + knum) % BUFFERSIZE] = ch; ++knum; } } // キーをバッファから取り出す char dequeue() { char ch = 0xff; if(knum > 0) { ch = keyBuffer[head]; head = (head + 1) % BUFFERSIZE; --knum; } return ch; } char h2c(char hex) { if(hex > 9) return 'A' + hex - 10; else return '0' + hex; } void keyCheck(int an, int r) { char val; val = analogRead((char)an); if(val > 0x20) { if(keyStat[r][an] == 0) // キーが押された { enqueue(0x80); // カーソル位置先頭 enqueue(keyMap[r][an]); enqueue(' '); enqueue(h2c((val & 0xF0) >> 4)); enqueue(h2c(val & 0xF)); keyStat[r][an] = 1; } } else { if(keyStat[r][an] == 1) // キーが離された { enqueue(0x80); // カーソル位置先頭 for(int i=0; i<4; i++) enqueue(' '); keyStat[r][an] = 0; } } } // キースキャン割り込みエントリ void __interrupt() isr(void) { if (INTCONbits.TMR0IF) // TMR0 { switch(row) { case 0: PORTB = outB[0]; for(int i=2; i<5; i++) { keyCheck(i, 0); } break; case 1: case 3: PORTB = outB[row]; for(int i=1; i<5; i++) { keyCheck(i, row); } break; case 2: PORTB = outB[2]; for(int i=0; i<5; i++) { keyCheck(i, 2); } break; case 4: PORTB = outB[4]; keyCheck(1, 4); keyCheck(3, 4); keyCheck(4, 4); break; case 5: PORTB = outB[5]; keyCheck(3, 5); break; } if(++row > 5) row = 0; INTCONbits.TMR0IF = 0; // 割り込みフラグクリア TMR0 = TIMER_COUNT; // タイマ再設定 } } void main(void) { CVRCONbits.CVREN = 0; // コンパレータ電力カット CVRCONbits.CVROE = 0; // コンパレータ VrefをRA2から切り離し SSPCONbits.SSPEN = 0; // SPI/I2C無効 SCK SDO SDI SSはI/Oにする RCSTAbits.SPEN = 0; // シリアルポート無効 RC6/RC7はデジタルI/Oにする ADCON0 = 0b10000000; //TAD 1/20μs * 32 = 1.6μs ADCON1 = 0b10000010; // VREF使わない AN0〜RA4はアナログI/Oにする CMCON = 0b00000111; // コンパレータOFF CCP1CON = 0b00000000; // CCP1(Capture/Compare/PWM)無効 CCP2CON = 0b00000000; // CCP2無効 // I/O設定 0.OUTPUT 1.INPUT TRISA = 0b00101111; // AD入力 TRISB = 0b00000000; TRISC = 0b00000000; // 出力 0.LOW 1.HI PORTA = 0b00000000; PORTB = 0b00000000; PORTC = 0b00000000; // タイマー0設定 インターバル時間10msにする // クロック周期 20MHz×4 = 0.05μs×4 = 0.2μs // タイマーカウント数 = インターバル時間÷クロック周期 = 10000÷0.2 = 50000 // プリスケーラ256にする 50000÷256 = 195.3125 ≒ 195カウント(TIMER_COUNT = 255-195) OPTION_REGbits.T0CS = 0; // TMR0クロックソースは内部クロック OPTION_REGbits.PSA = 0; // プリスケーラをTMR0へ割り当て OPTION_REGbits.PS = 0b111; // プリスケーラ256 row = 0; head = 0; knum = 0; LCDCLK = 1; __delay_ms(300); // LCD準備待ち // キー状態初期化 for(int i=0; i<6; i++) for(int j=0; j<5; j++) keyStat[i][j] = 0; // タイマー割り込み開始 TMR0 = TIMER_COUNT; INTCONbits.TMR0IE = 1; // TMR0割り込みを許可 INTCONbits.GIE = 1; // すべての割り込み許可 while(1) { keycode = dequeue(); if(keycode != 0xff) { sendChar(keycode); } } return; }