Pages: [1] 2   Go Down
Print
Author Topic: รบกวนขอวิธีการต่อจอ LCD 20x4 กับ PIC16F877 ด้วยครับ  (Read 40137 times)
0 Members and 1 Guest are viewing this topic.
pakapong16
Jr. Member
**
Offline Offline

Posts: 33


« on: September 18, 2009, 07:38:45 PM »

พอดีจะทำโครงงาน

จึงลบกวนขอวิธีการต่อจอ LCD 20x4 กับ PIC16F877 และ code การประกาศฟังก์ชันเชื่อมต่อกับจอด้วยครับ

ขอบคุณล่วงหน้าครับ
Logged
s_engine
Sr. Member
****
Offline Offline

Posts: 187


« Reply #1 on: September 20, 2009, 05:42:01 PM »

ต่อเหมือนกัน LCD 16x2 หละครับ
ตัวอย่าง แบบ 4 บิต ใช้แค่ขา D4-D7 และ RS RW E

#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_D5
#define LCD_DB6   PIN_D6
#define LCD_DB7   PIN_D7
#define LCD_RS    PIN_E0
#define LCD_RW    PIN_E1
#define LCD_E     PIN_E2

หรือ

#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_B1
#define LCD_DB6   PIN_C5
#define LCD_DB7   PIN_B5

#define LCD_RS    PIN_E2
#define LCD_RW    PIN_B2
#define LCD_E     PIN_D6
Logged
pakapong16
Jr. Member
**
Offline Offline

Posts: 33


« Reply #2 on: September 21, 2009, 04:06:53 AM »

เวลาจะให้มันไปแสดงบรรทัดที่สามและสี่อ่ะคับ

ทำงัย ผมทำไม่เป็น
Logged
s_engine
Sr. Member
****
Offline Offline

Posts: 187


« Reply #3 on: September 21, 2009, 08:43:20 AM »

อยากได้โค้ด ว่างั้น

ผมมีโค้ดจาก www.ccsinfo.com
credit ท่าน  PCM programmer

ก้อปมาทั้งดู้น เลย

Code:
#include <16F877.H> 
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)

#include <Flex_LCD420.c>   

//===================================
void main()
{
int8 i;
int8 b1, b2, b3, b4;

// The lcd_init() function should always be called once,
// near the start of your program.
lcd_init();

// Clear the LCD.
printf(lcd_putc, "\f");
delay_ms(500);


while(1)
  {
   // Test the clear screen and newline commands.
   // Also test that we can write to all 4 lines.
   printf(lcd_putc, "\fThis is the 1st line");
   printf(lcd_putc, "\nNext is the 2nd line");
   printf(lcd_putc, "\nThis is the 3rd line");
   printf(lcd_putc, "\nFinally the 4th line");
   delay_ms(3000);

   // Test some additional characters.
   printf(lcd_putc, "\fABCDEFGHIJKLMNOPQRST");
   printf(lcd_putc, "\nabcdefghijklmnopqrst");
   printf(lcd_putc, "\n12345678901234567890");
   printf(lcd_putc, "\n!@#$^&*(){}[]:;<>?/=");
   delay_ms(3000);

   // Clear the LCD.
   printf(lcd_putc, "\f");
   delay_ms(500);

   // Test that lcd_gotoxy() works.  Go to each of
   // the four corners and put a number in each one,
   // in a clockwise direction, starting with the upper
   // left corner.
   lcd_gotoxy(4, 2);       
   printf(lcd_putc, "Put a number in");   
   lcd_gotoxy(4, 3);       
   printf(lcd_putc, "each corner.");   
   lcd_gotoxy(1, 1);       
   printf(lcd_putc, "1");   
   lcd_gotoxy(20, 1);       
   printf(lcd_putc, "2");   
   lcd_gotoxy(20, 4);       
   printf(lcd_putc, "3");   
   lcd_gotoxy(1, 4);       
   printf(lcd_putc, "4");   
   delay_ms(3000);

// Read the character that was written in each corner
// of the LCD and display it.   This tests the lcd_getc()
// function.   
// The following test can only be done if we can read
// from the LCD.  If the RW pin is not used, then the
// LCD is in write-only mode, and we can't do this test.
// The #ifdef statement will prevent the code from
// being compiled, in that case.

#ifdef USE_RW_PIN   
   // Test if lcd_getc() can read
   // a byte from each corner.
   b1 = lcd_getc(1,1);   
   b2 = lcd_getc(20,1);   
   b3 = lcd_getc(20,4);   
   b4 = lcd_getc(1,4);   
   lcd_gotoxy(1, 1);       
   printf(lcd_putc, "\fRead these bytes\n");
   printf(lcd_putc, "from the 4 corners:\n\n");
   printf(lcd_putc, "     %c %c %c %c", b1, b2, b3, b4);       
   delay_ms(3000);
#endif

   // Type some characters and backspace over them.
   printf(lcd_putc, "\fType characters and\n");
   printf(lcd_putc,   "backspace over them.");
   delay_ms(2000);

   // Go to end of 2nd line.
   lcd_gotoxy(20, 2);       

   // Backspace over 2nd line.
   for(i = 0; i < 20; i++)
      {
       printf(lcd_putc," \b\b");
       delay_ms(150);
      }

   // Go to end of first line.               
   lcd_gotoxy(20, 1);       

   // Backspace over first line.
   for(i = 0; i < 20; i++)
      {
       printf(lcd_putc," \b\b");
       delay_ms(150);
      }         

  }   

}

Code:
// Flex_LCD420.c 

// These pins are for my Microchip PicDem2-Plus board,
// which I used to test this driver.
// An external 20x4 LCD is connected to these pins.
// Change these pins to match your own board's connections.

#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_D5
#define LCD_DB6   PIN_D6
#define LCD_DB7   PIN_D7

#define LCD_RS    PIN_E0
#define LCD_RW    PIN_E1
#define LCD_E     PIN_E2

/*
// To prove that the driver can be used with random
// pins, I also tested it with these pins:
#define LCD_DB4   PIN_D4
#define LCD_DB5   PIN_B1
#define LCD_DB6   PIN_C5
#define LCD_DB7   PIN_B5

#define LCD_RS    PIN_E2
#define LCD_RW    PIN_B2
#define LCD_E     PIN_D6
*/

// If you want only a 6-pin interface to your LCD, then
// connect the R/W pin on the LCD to ground, and comment
// out the following line.  Doing so will save one PIC
// pin, but at the cost of losing the ability to read from
// the LCD.  It also makes the write time a little longer
// because a static delay must be used, instead of polling
// the LCD's busy bit.  Normally a 6-pin interface is only
// used if you are running out of PIC pins, and you need
// to use as few as possible for the LCD.
#define USE_RW_PIN   1     


// These are the line addresses for most 4x20 LCDs.
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x40
#define LCD_LINE_3_ADDRESS 0x14
#define LCD_LINE_4_ADDRESS 0x54

// These are the line addresses for LCD's which use
// the Hitachi HD66712U controller chip.
/*
#define LCD_LINE_1_ADDRESS 0x00
#define LCD_LINE_2_ADDRESS 0x20
#define LCD_LINE_3_ADDRESS 0x40
#define LCD_LINE_4_ADDRESS 0x60
*/


//========================================

#define lcd_type 2   // 0=5x7, 1=5x10, 2=2 lines(or more)

int8 lcd_line;

int8 const LCD_INIT_STRING[4] =
{
 0x20 | (lcd_type << 2),  // Set mode: 4-bit, 2+ lines, 5x8 dots
 0xc,                     // Display on
 1,                       // Clear display
 6                        // Increment cursor
 };
                             

//-------------------------------------
void lcd_send_nibble(int8 nibble)
{
// Note:  !! converts an integer expression
// to a boolean (1 or 0).
 output_bit(LCD_DB4, !!(nibble & 1));
 output_bit(LCD_DB5, !!(nibble & 2)); 
 output_bit(LCD_DB6, !!(nibble & 4));   
 output_bit(LCD_DB7, !!(nibble & 8));   

 delay_cycles(1);
 output_high(LCD_E);
 delay_us(2);
 output_low(LCD_E);
}

//-----------------------------------
// This sub-routine is only called by lcd_read_byte().
// It's not a stand-alone routine.  For example, the
// R/W signal is set high by lcd_read_byte() before
// this routine is called.     

#ifdef USE_RW_PIN
int8 lcd_read_nibble(void)
{
int8 retval;
// Create bit variables so that we can easily set
// individual bits in the retval variable.
#bit retval_0 = retval.0
#bit retval_1 = retval.1
#bit retval_2 = retval.2
#bit retval_3 = retval.3

retval = 0;
   
output_high(LCD_E);
delay_us(1);

retval_0 = input(LCD_DB4);
retval_1 = input(LCD_DB5);
retval_2 = input(LCD_DB6);
retval_3 = input(LCD_DB7);
 
output_low(LCD_E);
delay_us(1);
   
return(retval);   
}   
#endif

//---------------------------------------
// Read a byte from the LCD and return it.

#ifdef USE_RW_PIN
int8 lcd_read_byte(void)
{
int8 low;
int8 high;

output_high(LCD_RW);
delay_cycles(1);

high = lcd_read_nibble();

low = lcd_read_nibble();

return( (high<<4) | low);
}
#endif

//----------------------------------------
// Send a byte to the LCD.
void lcd_send_byte(int8 address, int8 n)
{
output_low(LCD_RS);

#ifdef USE_RW_PIN
while(bit_test(lcd_read_byte(),7)) ;
#else
delay_us(60); 
#endif

if(address)
   output_high(LCD_RS);
else
   output_low(LCD_RS);
     
 delay_cycles(1);

#ifdef USE_RW_PIN
output_low(LCD_RW);
delay_cycles(1);
#endif

output_low(LCD_E);

lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
//----------------------------

void lcd_init(void)
{
int8 i;

lcd_line = 1;

output_low(LCD_RS);

#ifdef USE_RW_PIN
output_low(LCD_RW);
#endif

output_low(LCD_E);

// Some LCDs require 15 ms minimum delay after
// power-up.  Others require 30 ms.  I'm going
// to set it to 35 ms, so it should work with
// all of them.
delay_ms(35);         

for(i=0 ;i < 3; i++)
   {
    lcd_send_nibble(0x03);
    delay_ms(5);
   }

lcd_send_nibble(0x02);

for(i=0; i < sizeof(LCD_INIT_STRING); i++)
   {
    lcd_send_byte(0, LCD_INIT_STRING[i]);
   
    // If the R/W signal is not used, then
    // the busy bit can't be polled.  One of
    // the init commands takes longer than
    // the hard-coded delay of 50 us, so in
    // that case, lets just do a 5 ms delay
    // after all four of them.
    #ifndef USE_RW_PIN
    delay_ms(5);
    #endif
   }

}

//----------------------------

void lcd_gotoxy(int8 x, int8 y)
{
int8 address;


switch(y)
  {
   case 1:
     address = LCD_LINE_1_ADDRESS;
     break;

   case 2:
     address = LCD_LINE_2_ADDRESS;
     break;

   case 3:
     address = LCD_LINE_3_ADDRESS;
     break;

   case 4:
     address = LCD_LINE_4_ADDRESS;
     break;

   default:
     address = LCD_LINE_1_ADDRESS;
     break;
     
  }

address += x-1;
lcd_send_byte(0, 0x80 | address);
}

//-----------------------------
void lcd_putc(char c)
{
 switch(c)
   {
    case '\f':
      lcd_send_byte(0,1);
      lcd_line = 1;
      delay_ms(2);
      break;
   
    case '\n':
       lcd_gotoxy(1, ++lcd_line);
       break;
   
    case '\b':
       lcd_send_byte(0,0x10);
       break;
   
    default:
       lcd_send_byte(1,c);
       break;
   }
}

//------------------------------
#ifdef USE_RW_PIN
char lcd_getc(int8 x, int8 y)
{
char value;

lcd_gotoxy(x,y);

// Wait until busy flag is low.
while(bit_test(lcd_read_byte(),7)); 

output_high(LCD_RS);
value = lcd_read_byte();
output_low(LCD_RS);

return(value);
}
#endif
Logged
gundam
Global Moderator
Hero Member
*****
Offline Offline

Posts: 292



« Reply #4 on: September 21, 2009, 09:07:34 AM »

ในเวปนี้ก็มีรายละเอียดเกี่ยวกับ LCD นะครับ
การระบุบรรทัดลองดูที่ เซ็ทต่ำแหน่งใน DD-RAM (Set DD-RAM Address)
http://www.thaimicrotron.com/Referrence/LCD/LCD-Module2.htm
Logged
pakapong16
Jr. Member
**
Offline Offline

Posts: 33


« Reply #5 on: September 21, 2009, 05:58:51 PM »

ต่อทดสอบแล้วไม่แสดงอะไรเลย

ช่วยแนะนำด้วยครับ

ผมมีความรู้เรื่อง PIC ไม่มาก

รึว่าผมต่อวงจรผิด ขอคำแนะนำรูปการต่อวงจรจอด้วยครับ
Logged
s_engine
Sr. Member
****
Offline Offline

Posts: 187


« Reply #6 on: September 22, 2009, 03:34:45 PM »



ผม ซิมได้อยุ่นะ
Logged
pakapong16
Jr. Member
**
Offline Offline

Posts: 33


« Reply #7 on: September 22, 2009, 05:02:26 PM »

ผมก้อต่อตามพี่แล้วครับ

ให้ out put ที่ port c

เพราะปกติผมต่อแบบนี้อ่ะครับ
http://upload.siamza.com/showpic.php?id=283577

มันก้อไม่ออก
Logged
s_engine
Sr. Member
****
Offline Offline

Posts: 187


« Reply #8 on: September 24, 2009, 07:48:57 PM »

ต่อฮาร์ดแวร์ จริงใช่ไหมครับ หรือ ซิมเอา
RD0  ต่อกับ  RS
RD1  ต่อกับ  RW
RD2  ต่อกับ  E
RD3  ไม่ใช้
RD4  ต่อกับ  D4
RD5  ต่อกับ  D5
RD6  ต่อกับ  D6
RD7  ต่อกับ  D7

ลองดูอีกทีนะ

ถ้าต่อ ฮาร์ดแวร์จริง ลองจ่ายไฟเลี้ยง ดูยัง แล้วปรับ VR ให้ มี สีตรงส่วนที่จะแสดงผล เข้ม ขึ้นมา
20x4 ผมไม่มีของจริง แต่16x2 เวลาจ่ายไฟเลี้ยง ปรับ VR บรรทัดแรกมันจะ ค่อยๆทึบ โดยบรรทัดที่2 ยังเหมือนเดิม 20x4 ก็ น่าจะเหมือนกัน
Logged
pakapong16
Jr. Member
**
Offline Offline

Posts: 33


« Reply #9 on: September 25, 2009, 02:49:48 PM »

ต่อใช้งานจริงครับ


ต่อครบทุกอันแล้วครับ

มันขึ้นเส้นทึบบรรทัดที่ 1และ3  ไม่มีข้อมูลแสดงเลยครับ
Logged
s_engine
Sr. Member
****
Offline Offline

Posts: 187


« Reply #10 on: September 26, 2009, 09:40:23 PM »

แล้วการทำงานอย่างอื่นทำได้อยุ่ไหม เช่น เขียนโค้ดเพิ่มไปว่า กดสวิตช์ แล้วled ติด กดสวิตช์อีกตัว led ดับ โดยเพิ่มไปในโค้ดที่สั่งโชว์ LCD เพื่อดูว่า pic ยังทำงานอยุ่ไหม พวกคริสตั้นใช้ความถี่เท่าไหร่ R reset ต่อถูกต้องแล้วนะ
Logged
pakapong16
Jr. Member
**
Offline Offline

Posts: 33


« Reply #11 on: October 01, 2009, 02:37:36 AM »

ผมใช้โค๊ดนี้ออก  แต่ออกสองบรรทัด

#use delay (clock = 20000000)

struct lcd_pin_map {
         BOOLEAN rs;               // on to an I/O port to gain    PIN_D0
         BOOLEAN enable;           // access to the LCD pins.      PIN_D1
         BOOLEAN rw;               // The bits are allocated from  PIN_D2
         BOOLEAN unused;           // low order up.  ENABLE will   PIN_D3
         int     data : 4;         //                              PIN_D4-7
  } lcd;



  #byte lcd   = 8       //portd

  #define set_tris_lcd(x)   set_tris_d(x)

  #define lcd_type 2            // 0=5x7 1 line, 1=5x10 1 line, 2=5x7 2 line
  #define lcd_line_two 0x40     // LCD RAM address for the second line

  byte const LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0x0c, 1, 6};
  // Initial LCD

 struct lcd_pin_map const LCD_WRITE = {0, 0};
 struct lcd_pin_map const LCD_READ = {0, 15};   // 15 =  1111
 // Setting the I/O port direction register.

 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;
 delay_us(500);
 lcd.rs = address;
 delay_cycles(1);

 lcd_send_nibble(n >> 4);
 lcd_send_nibble(n & 0x0f);
 }

 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_init() {
 byte i;
 set_tris_lcd(LCD_WRITE);
 set_tris_d(0B00000000);
 lcd.rs = 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);
 }

 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;
       case '\p'   : lcd_gotoxy(9,2);        break;
       default     : lcd_send_byte(1,c);     break;
    }
 }
Logged
s_engine
Sr. Member
****
Offline Offline

Posts: 187


« Reply #12 on: October 01, 2009, 11:49:41 PM »

ลองใช้
   // Test some additional characters.
   printf(lcd_putc, "\fABCDEFGHIJKLMNOPQRST");
   printf(lcd_putc, "\nabcdefghijklmnopqrst");
   printf(lcd_putc, "\n12345678901234567890");
   printf(lcd_putc, "\n!@#$^&*(){}[]:;<>?/=");
   delay_ms(3000);
 ส่งดู มันจะโชว์ 4 บรรทัด
ที่คุณเขียนมา มันเป็นไดร์เวอร์ ของ 16*2 จาก
#define lcd_line_two 0x40     // LCD RAM address for the second line
เลยแสดงได้แค่ 2 บรรทัด
การแสดง 4 บรรทัด ต้องกำหนดแอดเดรส ให้กับแต่ละบรรทัดด้วย
ลอง include lcd420 ของ ccs มาใช้ดู ต่อขาตามเขา


Logged
s_engine
Sr. Member
****
Offline Offline

Posts: 187


« Reply #13 on: October 05, 2009, 09:14:41 AM »

เอาไปลองดูนะครับ
http://load1.uploadfile.biz/get.php?file=113i53i52i36date05102009am090012

ไฟล์ที่อัพ มีทั้ง .c และ .hex ที่ใช้เบิร์นได้เลย และมี proteus v7.4 pack3 verเก่ากว่าจะเปิดไม่ได้
ไว้สำหรับ simulate
ต่อขาตามนี้นะ
แต่ถ้าอยากเปลี่ยนต่ำแหน่งขาที่ต่อ ก็ให้ไปแก้ใน Flex_LCD420.c  ได้เลย

#define LCD_DB4   PIN_C4
#define LCD_DB5   PIN_C5
#define LCD_DB6   PIN_C6
#define LCD_DB7   PIN_C7

#define LCD_RS    PIN_C0
#define LCD_RW    PIN_C1
#define LCD_E     PIN_C2
Logged
pakapong16
Jr. Member
**
Offline Offline

Posts: 33


« Reply #14 on: October 05, 2009, 11:20:18 AM »

ขอบคุณมากครับ

จะลองเบิร์นดูครับ

Logged
Pages: [1] 2   Go Up
Print
 
Jump to: