| 
| 
查看: 6868|回复: 14
 | 
【教学】PIC 连接4x4 Keypad , 显示在 16x2 LCD
 [复制链接] |  
 |  | 
 
| 本帖最后由 pic 于 9-3-2012 11:25 AM 编辑 
 过去有一些帖子, 示范了怎样用CCS C, 使用 PIC MCU 的ADC, 连接去LCD, USART 等等。。
 矩阵键盘 (Keypad ) 倒是还没有说过。。 这里引用CCS C 的 示范程序, EX_LCDKB.C , LCD.C,  KBD.C, 做部分修改后, 在proteus 运行示范。
 
 供网友们参考。 有问题可以发问, 但是请不要离题。
 
 电路图如下, LCD 是接去 16F887 的Port D, Keypad 是接去 Port B,相对的按键, 会显示在LCD 上, 按 [On/C] 键会清除 LCD。
 矩阵键盘 的Row (行), 需要电位拉高 pull high,可以用4.7k~10K 的电阻。
 
 
   
 CCS C 源码:下载
 
 主程序
 
 复制代码
// Demo: Keypad 4x4, display on LCD 16x2
// Modified from CCS C Ex_LCDKB.C
// Filename: Cari_LCDKB.C
// Date: 6 Mar 2012
// by: pic@cArI 
#include <16F887.h>
#fuses INTRC_IO,NOWDT,NOPROTECT,NOLVP
#use delay(clock=8000000)
#include <mylcd.c>
#include <mykbd.c>
void main() {
   char k;
   lcd_init();
   lcd_putc("\fReady...\n");
   while (TRUE) 
   {
      k=kbd_getc();
      if(k!=0)
        if(k=='N')
          lcd_putc('\f');
        else
          lcd_putc(k);
   }
}
 | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 
 楼主|
发表于 6-3-2012 09:00 PM
|
显示全部楼层 
myKBD.C
| 本帖最后由 pic 于 6-3-2012 09:15 PM 编辑 
 Keypad 的bouncing , 可以设定, 在#define KBD_DEBOUNCE_FACTOR
 我修改了 CCS C 原本的 Keypad Scan Driver , KBD.C  (4x3)变成 myKBD.C (4x4)
 复制代码
// Filename: myKBD.C
#define use_portb_kbd TRUE  // 使用 PortB
#if defined(__PCH__)
#if defined use_portb_kbd
   #byte kbd = 0xF81                   // This puts the entire structure
#else
   #byte kbd = 0xF83                   // This puts the entire structure
#endif
#else
#if defined use_portb_kbd
   #byte kbd = 6                  // on to port B (at address 6)
#else
   #byte kbd = 8                 // on to port D (at address 8)
#endif
#endif
#if defined use_portb_kbd
   #define set_tris_kbd(x) set_tris_b(x)
#else
   #define set_tris_kbd(x) set_tris_d(x)
#endif
#define COL0 (1 << 4)   // Col0 接去PortB.4
#define COL1 (1 << 5)   // Col1 接去PortB.5
#define COL2 (1 << 6)   // Col2 接去PortB.6
#define COL3 (1 << 7)   // Col3 接去PortB.7
#define ROW0 (1 << 0)   // ROW0 接去PortB.0
#define ROW1 (1 << 1)   // ROW1 接去PortB.1
#define ROW2 (1 << 2)   // ROW2 接去PortB.2
#define ROW3 (1 << 3)   // ROW3 接去PortB.3
#define ALL_ROWS (ROW0|ROW1|ROW2|ROW3)
#define ALL_PINS (ALL_ROWS|COL0|COL1|COL2|COL3)
// Keypad layout:
char const KEYS[4][4] = {{'7','8','9','/'},
                         {'4','5','6','x'},
                         {'1','2','3','-'},
                         {'N','0','=','+'}};
#define KBD_DEBOUNCE_FACTOR 33    // Set this number to apx n/333 where
                                  // n is the number of times you expect
                                  // to call kbd_getc each second
void kbd_init() 
{
   port_b_pullups (true);
}
char kbd_getc( ) {
   static BYTE kbd_call_count;
   static int kbd_down;
   static char last_key;
   static BYTE col;
   BYTE kchar;
   BYTE row;
   kchar='\0';
   if(++kbd_call_count>KBD_DEBOUNCE_FACTOR) 
   {
       switch (col) 
       {
         case 0   : set_tris_kbd(ALL_PINS&~COL0);
                    kbd=~COL0&ALL_PINS;
                    break;
         case 1   : set_tris_kbd(ALL_PINS&~COL1);
                    kbd=~COL1&ALL_PINS;
                    break;
         case 2   : set_tris_kbd(ALL_PINS&~COL2);
                    kbd=~COL2&ALL_PINS;
                    break;
         case 3   : set_tris_kbd(ALL_PINS&~COL3);
                    kbd=~COL3&ALL_PINS;
                    break;
       }
       if(kbd_down) 
       {
         if((kbd & (ALL_ROWS))==(ALL_ROWS)) {
           kbd_down=FALSE;
           kchar=last_key;
           last_key='\0';
         }
       } else {
          if((kbd & (ALL_ROWS))!=(ALL_ROWS)) 
          {
             if((kbd & ROW0)==0)
               row=0;
             else if((kbd & ROW1)==0)
               row=1;
             else if((kbd & ROW2)==0)
               row=2;
             else if((kbd & ROW3)==0)
               row=3;
             last_key =KEYS[row][col];
             kbd_down = TRUE;
          } 
          else
          {
             ++col;
             if(col==4)
               col=0;
          }
       }
      kbd_call_count=0;
   }
  set_tris_kbd(ALL_PINS);
  return(kchar);
}
 | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 
 楼主|
发表于 6-3-2012 09:04 PM
|
显示全部楼层 
myLCD.C
| 修改了 CCS C 原本的 LCD Driver, LCD.C 变成 myLCD.C , 改变了 RS, RW , Enable的接线。 复制代码
////                             myLCD.C                               ////
////                 Driver for common LCD modules                     ////
////  lcd_init()   Must be called before any other function.           ////
////  lcd_putc(c)  Will display c on the next position of the LCD.     ////
////                     The following have special meaning:           ////
////                      \f  Clear display                            ////
////                      \n  Go to start of second line               ////
////                      \b  Move back one position                   ////
////                                                                   ////
////  lcd_gotoxy(x,y) Set write position on LCD (upper left is 1,1)    ////
////  lcd_getc(x,y)   Returns character at position x,y on LCD         ////
//     D0  rs
//     D1  rw
//     D2  enable
//     D4  D4
//     D5  D5
//     D6  D6
//     D7  D7
struct lcd_pin_map {                 // This structure is overlayed
           BOOLEAN rs;               // on to an I/O port to gain
           BOOLEAN rw;               // access to the LCD pins.
           BOOLEAN enable;           // The bits are allocated from
           BOOLEAN unused;           // low order up.  ENABLE will
           int     data : 4;         // be pin B0.
        } lcd;
#if defined(__PCH__)
#if defined use_portb_lcd
   #byte lcd = 0xF81                   // This puts the entire structure
#else
   #byte lcd = 0xF83                   // This puts the entire structure
#endif
#else
#if defined use_portb_lcd
   #byte lcd = 6                  // on to port B (at address 6)
#else
   #byte lcd = 8                 // on to port D (at address 8)
#endif
#endif
#if defined use_portb_lcd
   #define set_tris_lcd(x) set_tris_b(x)
#else
   #define set_tris_lcd(x) set_tris_d(x)
#endif
#define lcd_type 2           // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40    // LCD RAM address for the second line
BYTE const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
                             // These bytes need to be sent to the LCD
                             // to start it up.
                             // The following are used for setting
                             // the I/O port direction register.
struct lcd_pin_map const LCD_WRITE = {0,0,0,0,0}; // For write mode all pins are out
struct lcd_pin_map const LCD_READ = {0,0,0,0,15}; // For read mode data pins are in
BYTE lcd_read_byte() {
      BYTE low,high;
      set_tris_lcd(LCD_READ);
      lcd.rw = 1;
      delay_cycles(1);
      lcd.enable = 1;
      delay_cycles(1);
      high = lcd.data;
      lcd.enable = 0;
      delay_cycles(1);
      lcd.enable = 1;
      delay_us(1);
      low = lcd.data;
      lcd.enable = 0;
      set_tris_lcd(LCD_WRITE);
      return( (high<<4) | low);
}
void lcd_send_nibble( BYTE n ) {
      lcd.data = n;
      delay_cycles(1);
      lcd.enable = 1;
      delay_us(2);
      lcd.enable = 0;
}
void lcd_send_byte( BYTE address, BYTE n ) {
      lcd.rs = 0;
      while ( bit_test(lcd_read_byte(),7) ) ;
      lcd.rs = address;
      delay_cycles(1);
      lcd.rw = 0;
      delay_cycles(1);
      lcd.enable = 0;
      lcd_send_nibble(n >> 4);
      lcd_send_nibble(n & 0xf);
}
void lcd_init() {
    BYTE i;
    set_tris_lcd(LCD_WRITE);
    lcd.rs = 0;
    lcd.rw = 0;
    lcd.enable = 0;
    delay_ms(15);
    for(i=1;i<=3;++i) {
       lcd_send_nibble(3);
       delay_ms(5);
    }
    lcd_send_nibble(2);
    for(i=0;i<=3;++i)
       lcd_send_byte(0,LCD_INIT_STRING[i]);
}
void lcd_gotoxy( BYTE x, BYTE y) {
   BYTE address;
   if(y!=1)
     address=lcd_line_two;
   else
     address=0;
   address+=x-1;
   lcd_send_byte(0,0x80|address);
}
void lcd_putc( char c) {
   switch (c) {
     case '\f'   : lcd_send_byte(0,1);
                   delay_ms(2);
                                           break;
     case '\n'   : lcd_gotoxy(1,2);        break;
     case '\b'   : lcd_send_byte(0,0x10);  break;
     default     : lcd_send_byte(1,c);     break;
   }
}
char lcd_getc( BYTE x, BYTE y) {
   char value;
    lcd_gotoxy(x,y);
    while ( bit_test(lcd_read_byte(),7) ); // wait until busy flag is low
    lcd.rs=1;
    value = lcd_read_byte();
    lcd.rs=0;
    return(value);
}
 | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 7-3-2012 09:32 AM
|
显示全部楼层 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 7-3-2012 07:18 PM
|
显示全部楼层 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 9-3-2012 01:49 AM
|
显示全部楼层 
| 回复 3# pic 
 那个myKBD.c 我copy到完,可是有error哦***Error128"myKBD.c"Line6(5,9):A #DEVICE required before this line
 
 那个myLCD.c 我copy到完,也是有error哦***Error128"myKBD.c"Line21(1,8):A #DEVICE required before this line
 | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 
 楼主|
发表于 9-3-2012 11:19 AM
|
显示全部楼层 
| 回复  pic 
 那个myKBD.c 我copy到完,可是有error哦***Error128"myKBD.c"Line6(5,9):A #DEVICE required ...
 Harry88 发表于 9-3-2012 01:49 AM
 那些file 要放在同一个folder。
 直接给你源码吧
 下载CCS C源码
 | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 12-3-2012 12:23 AM
|
显示全部楼层 
| 好贴~谢谢楼主的分享  | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 12-3-2012 12:31 AM
|
显示全部楼层 
| 谢谢分享  | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 12-3-2012 03:51 PM
|
显示全部楼层 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 12-3-2012 06:12 PM
|
显示全部楼层 
| 谢谢分享。。 我不是很会PIC。。慢慢学着。。
 对了,我可以问看版主你会不会arduino?
 | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 
 楼主|
发表于 12-3-2012 06:39 PM
|
显示全部楼层 
| 谢谢分享。。我不是很会PIC。。慢慢学着。。
 对了,我可以问看版主你会不会arduino?
 希椏 发表于 12-3-2012 06:12 PM
 没有接触过, 但是未来会买了玩玩体验。。。
 
 Arduino 适合给不是很会电子的朋友, 比如读机械工程的, 业余爱好者,
 他们想要控制一些东西, 但是又不要很深入, 不是做商业用途的,
 就依赖模块, 要什么功能 , 就买特定的模块, 应用人家已经写好的程序,
 做出一些控制。
 
 好处是速成, 缺点是会依赖模块, 仰赖人家写的程序 library。
 ok, 离题了。
 | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 12-3-2012 10:43 PM
|
显示全部楼层 
| 没有接触过, 但是未来会买了玩玩体验。。。
 Arduino 适合给不是很会电子的朋友, 比如读机械工程的, ...
 pic 发表于 12-3-2012 06:39 PM
 
 好的,谢谢你!
 
 我也会试学PIC,因为现在假期当中。。
 
 希望能把握时机。。
 | 
 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 13-3-2012 08:40 PM
|
显示全部楼层 |  |  |  |
 
|  |  |  
|  |  | 
 |  | 
 
 发表于 13-3-2012 11:46 PM
|
显示全部楼层 
| 谢谢楼主分享~   | 
 |  |  |  |
 
|  |  |  
|  |  |  |  | 
            本周最热论坛帖子 |