PIC Vietnam

PIC Vietnam (http://www.picvietnam.com/forum/index.php)
-   Các ngôn ngữ lập trình khác (CCS C, HT PIC,...) (http://www.picvietnam.com/forum/forumdisplay.php?f=12)
-   -   CCS C for PIC16F877A (http://www.picvietnam.com/forum/showthread.php?t=357)

falleaf 12-05-2006 09:04 PM

Bạn nhớ sử dụng thẻ [CODE] để viết các đoạn mã lệnh trong đó nhé, vì các bài viết mã lệnh nhiều khi cần thụt ra thụt vào nhìn cho nó dễ coi, nếu bạn không đặt cái thẻ này vào thì sẽ rất khó nhìn vì nó thẳng tuột.

Ngoài ra, nếu được, mong bạn khi viết chú thích thêm bằng tiếng Việt.

Chúc vui.

nhh 03-06-2006 07:10 PM

Tìm hiểu về LCD
 
LCD được tìm hiểu ở đây là HD44780 của hãng Hitachi, gồm 2 dòng, mỗi dòng 16 kí tự.


HD44780 có 14 chân, chức năng của các chân:

1.Các chân VCC, VSSVEE: Chân VCC_Cấp dương nguồn 5V, chân VCC_Nối đất, chân VEE được dùng để điều khiển độ tương phản của màn hình LCD.

2.Chân chọn thanh ghi RS (Register Select):
Có hai thanh ghi rất quan trọng bên trong LCD, chân RS được dùng để chọn các thanh ghi này như sau: Nếu RS = 0 thì thanh ghi mà lệnh được chọn để cho phép người dùng gửi một lệnh chẳng hạn như xoá màn hình, đưa con trỏ về đầu dòng,… Nếu RS = 1 thì thanh ghi dữ liệu được chọn cho phép người dùng gửi dữ liệu cần hiển thị trên LCD.

3.Chân đọc/ghi R/W:
Đầu vào đọc/ghi cho phép người dùng ghi thông tin lên LCD khi R/W = 0 hoặc đọc thông tin từ nó khi R/W = 1.

4.Chân cho phép E (Enable):
Chân cho phép E được sử dụng bởi LCD để chốt thông tin hiện hữu trên chân dữ liệu của nó. Khi dữ liệu được cấp đến chân dữ liệu thì một xung mức cao xuống thấp phải được áp đến chân này để LCD chốt dữ liệu trên các chân dữ liêu. Xung này phải rộng tối thiểu là 450ns.

5.Các chân D0 - D7:
Đây là 8 chân dữ liệu 8 bít, được dùng để gửi thông tin lên LCD hoặc đọc nội dung của các thanh ghi trong LCD.
Để hiển thị các chữ cái và các con số, chúng ta gửi các mã ASCII của các chữ cái từ A đến Z, a đến f và các con số từ 0 - 9,... đến các chân này khi bật RS = 1.
Cũng có các mã lệnh mà có thể được gửi đến LCD để xoá màn hình hoặc đưa con trỏ về đầu dòng hoặc nhấp nháy con trỏ.Dưới đây là bảng liệt kê các mã lệnh:
(Phải qua lần post khác vì số ảnh vượt quá 4.....:cool: )

nhh 03-06-2006 07:13 PM

Tìm hiểu về LCD (ct)
 
Chúng ta cũng sử dụng RS = 0 để kiểm tra bít cờ bận để xem LCD có sẵn sàng nhận thông tin chưa. Cờ bận là D7 và có thể được đọc khi R/W = 1 và RS = 0 như sau:

Nếu R/W = 1, RS = 0 khi D7 = 1 (cờ bận 1) thì LCD bận bởi các công việc bên trong và sẽ không nhận bất kỳ thông tin mới nào. Khi D7 = 0 thì LCD sẵn sàng nhận thông tin mới. Lưu ý chúng ta nên kiểm tra cờ bận trước khi ghi bất kỳ dữ liệu nào lên LCD.

Có thể di chuyển con trỏ đến vị trí bất kì trên màn hình LCD bằng cách nạp vào các giá trị tương ứng như bảng sau và gởi yêu cầu đến LCD:

Tham khảo thêm về LCD tại đây: http://www.iaehv.nl/users/pouweha/lcd.htm

nhh 03-06-2006 07:17 PM

Lập trình cho LCD
 
Có hai cách lập trình cho LCD: dùng 8bit interface (đơn giản) hoặc 4bit interface (phức tạp hơn)

1.8bit interface
Code:

/*Để LCD thực thi các lệnh điều khiển:*/

RS = 0;                //chọn thanh ghi lệnh
R/W = 0;        //ghi dữ liệu, R/W = 1;//đọc dữ liệu
E= 1;                //đưa chân E lên mức cao
E= 0;                  //tạo sườn xuống để chốt dữ liệu

/*Để LCD thực thi các lệnh hiển thị:*/

RS = 1;                //chọn thanh ghi dữ liệu
R/W = 0;        //ghi dữ liệu
E = 1;                //đưa chân E lên mức cao
E = 0;          //tạo sườn xuống để chốt dữ liệu

Sử dụng 8 chân D0 - D7 để truyền thông tin, dữ liệu đến LCD.
- Để điều khiển LCD (Chọn chế độ LCD, bật/tắt hiển thị, bật/tắt/nhấp nháy/di chuyển con trỏ,...): Nhập giá trị tương ứng vào D0-D7 rồi gởi lệnh yêu cầu LCD thực thi lệnh điều khiển, tiếp theo cho LCD thời gian trễ để thực thi (hoặc hỏi cờ bận xem LCD sẵn sàng thực hiện lệnh tiếp theo chưa?)
- Để hiển thị dữ liệu lên LCD:Nhập dữ liệu cần hiển thị vào D0-D7 rồi gởi lệnh yêu cầu LCD thực thi lệnh hiển thị dữ liệu, tiếp theo cho LCD thời gian trễ để thực thi (hoặc hỏi cờ bận xem LCD sẵn sàng thực hiện lệnh tiếp theo chưa?)

Đây là mạch nguyên lý kết nối LCD dùng 8 chân interface với PIC16F877A qua PORTB:
http://www.freewebtown.com/nhhao/PIC/LCD_8pindata.gif

2.4bit interface

Sử dụng 4 chân D4 - D7 (hoặc D0-D3 <- ít dùng) để truyền thông tin, dữ liệu đến LCD.
- Để điều khiển LCD (Chọn chế độ LCD, bật/tắt hiển thị, bật/tắt/nhấp nháy/di chuyển con trỏ,...): Nhập giá trị tương ứng vào D0-D7,lấy giá trị 4bit cao D4-D7 rồi gởi lệnh yêu cầu LCD thực thi lệnh điều khiển, tiếp theo cho LCD thời gian trễ để thực thi (hoặc hỏi cờ bận xem LCD sẵn sàng thực hiện lệnh tiếp theo chưa?).Tiếp tục, gởi 4bit thấp D0-D3 rồi gởi lệnh yêu cầu LCD thực thi lệnh điều khiển, tiếp theo cho LCD thời gian trễ để thực thi (hoặc hỏi cờ bận xem LCD sẵn sàng thực hiện lệnh tiếp theo chưa?)
- Để hiển thị dữ liệu lên LCD:Cũng làm tương tự trên nhưng thay yêu cầu LCD điều khiển bằng yêu cầu LCD hiển thị.

Đây là mạch nguyên lý kết nối LCD dùng 4 chân interface với PIC16F877A qua PORTB:
http://www.freewebtown.com/nhhao/PIC/LCD_4pindata.gif

Nếu trong ứng dụng sử dụng ngắt ngoài thì có thể chuyển sang nối với PORTD hoặc tùy thích.

nhh 03-06-2006 07:20 PM

Hiển thị LCD 8bit interface
 
2 Attachment(s)
Chương trình hiển thị dòng chữ "BE YEU" trên hàng 1, bắt đầu tại cột 6, không hỏi cờ bận D7.
Do trong thân hàm comnwrt() và datawrt() đã tạo trễ 1ms cuối thân hàm nên sau khi gọi không cần tạo trễ cho LCD thực thi lệnh.
Code:

/*-----------------------------------------------------------------------------
* Author          : nhh
* Date            : 05/04/06
* Hardware        : PIC16F877A
* Compiler          : CCS C 3.249
* Description  : Hien thi LCD
*=============================================================================*/
#include <16F877A.h>
#include <DEFS_16F877A.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#define RS  RD0
#define RW  RD1
#define E  RD2
#define LCD PORTB

/*Ham yeu cau goi lenh dieu khien LCD*/
void comnwrt(void)
{
 RS = 0;
 RW = 0;
 E  = 1;
 E  = 0;
 delay_ms(1);
}
/*Ham yeu cau goi du lieu hien thi len LCD*/
void datawrt(void)
{
 RS = 1;
 RW = 0;
 E  = 1;
 E  = 0;
 delay_ms(1);
}
/*Ham main*/
void main(void)
{
 set_tris_B(0);
 set_tris_D(0);
 delay_ms(100);  //  Tao tre 100ms cho LCD khoi dong

 LCD = 0x38;      //  Hai hang, ma tran dot 5*7, 8 bit interface
 comnwrt();
 LCD = 0x0C;      //  Bat hien thi, tat con tro
 comnwrt();

 LCD = 0x85;      //  Vi tri hang 1,cot 6
 comnwrt();

 LCD = 'B';      //  Xuat dong chu "BE YEU" ra LCD
 datawrt();
 LCD = 'E';
 datawrt();
 LCD = ' ';
 datawrt();
 LCD = 'Y';
 datawrt();
 LCD = 'E';
 datawrt();
 LCD = 'U';
 datawrt();
 LCD = '!';
 datawrt();
}


nhh 03-06-2006 07:22 PM

2 Attachment(s)
Thêm một ví dụ khác, chương trình hiển thị dòng "HELLO PICVIETNAM!".
Code:

/*-----------------------------------------------------------------------------
* Author          : nhh
* Date            : 05/04/06
* Hardware        : PIC16F877A
* Compiler          : CCS C 3.249
* Description  : Hien thi LCD
*=============================================================================*/
#include <16F877A.h>
#include <DEFS_16F877A.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#define RS  RD0
#define RW  RD1
#define E  RD2
#define LCD PORTB

const unsigned char key[]="HELLOPICVIETNAM!";
int i = 0;

/*Ham yeu cau goi lenh dieu khien LCD*/
void comnwrt(void)
{
 RS = 0;
 RW = 0;
 E  = 1;
 E  = 0;
 delay_ms(1);
}
/*Ham yeu cau goi du lieu hien thi len LCD*/
void datawrt(void)
{
 RS = 1;
 RW = 0;
 E  = 1;
 E  = 0;
 delay_ms(1);
}
/*Ham main*/
void main(void)
{
 set_tris_B(0);
 set_tris_D(0);
 delay_ms(100);  //  Tao tre 100ms cho LCD khoi dong

 LCD = 0x38;      //  Hai hang, ma tran dot 5*7, 8 bit interface
 comnwrt();
 LCD = 0x0C;      //  Bat hien thi, tat con tro
 comnwrt();
 LCD = 0x86;      //  Vi tri hang 1,cot 7
 comnwrt();
 while(true)
  {
      LCD = key[i];
      datawrt();
      delay_ms(100);
      i++;
      if(i==5)              //  Hien thi xong HELLO
        {
            LCD = 0xC3;      //  Vi tri hang 2,cot 4
            comnwrt();
            delay_ms(100);
        }
      if(i==16)              //  Hien thi xong PICVIETNAM!
        {
            delay_ms(1100);
            LCD = 0x01;      //  Xoa man hinh hien thi
            comnwrt();
            delay_ms(500);
            LCD = 0x86;      //  Vi tri hang 1,cot 7
            comnwrt();
            i = 0;
        }
  }
}


nhh 03-06-2006 07:24 PM

Hiển thị LCD 4bit interface
 
2 Attachment(s)
Cái này trong thư viện của CCS C đã có file lcd.c trong thư mục Drivers rất là hay rồi, nên không cần viết lại làm gì.File này rất hay,nhưng chỉ dùng cho LCD 2 line.Các bác tự nghiên cíu nhé!

Chương trình hiển thị chữ "HI!" bắt đầu tại hàng 1, cột 7.Dùng LCD 4bit interface và thư viện lcd.c của CCS C

Code:

/*-----------------------------------------------------------------------------
* Author          : nhh
* Date            : 05/14/06
* Hardware        : PIC16F877A
* Compiler          : CCS C 3.249
* Description  : Hien thi LCD
*=============================================================================*/
#include <16F877A.h>
#include <DEFS_16F877A.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#define use_portb_lcd TRUE
#include <lcd.c>

void main(void)
{

    delay_ms(100);          // tao tre 100ms cho LCD khoi dong
    lcd_init();
    lcd_gotoxy(7,1);        // vi tri (x,y)=(7,1)= hang 1, cot 7
    lcd_putc('H');
    lcd_putc('I');
    lcd_putc('!');
}


falleaf 04-06-2006 02:48 AM

Quá tuyệt vời, chân thành cảm ơn nhh về loạt bài viết này.

Trân trọng

nhh 06-06-2006 11:03 AM

LCD_8bit interface, có kiểm tra cờ bận.
 
1 Attachment(s)
Bài cuối về LCD. Hoạt động theo 8bit interface, có hỏi cờ bận đảm bảo LCD luôn thực thi đúng lệnh yêu cầu ! Chú ý việc hỏi cờ bận là hết sức cần thiết!

Một điều nữa là Protues mô phỏng cho LCD hơi cà thoạt, nên dùng Picsimulator.Tốt nhất kiếm 1 chú LCD làm cho xom!:rolleyes:

Chương trình hiển thị dòng chữ "WONDERFUL PICVIETNAM!",tham khảo source code của CCS C.
Code:

/*-----------------------------------------------------------------------------
* Author          : nhh
* Date            : 05/04/06
* Hardware        : PIC16F877A
* Compiler          : CCS C 3.249
* Description  : Hien thi LCD
*=============================================================================*/
#include <16F877A.h>
#include <DEFS_16F877A.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#define E  RD2
#define RS RD0
#define RW RD1
#byte lcd_data = 0x06  // Dia chi PORTB

/* Khai bao nguyen mau cac ham su dung */
byte lcd_read_byte();
void lcd_send_byte( byte address, byte n );
void lcd_init();
void lcd_gotoxy( byte x, byte y);
void lcd_putc( char c);
void lcd_refresh();

/* Doc mot byte tu LCD */
byte lcd_read_byte()
{
  byte read_byte;
  set_tris_B(0xFF);      // PORTB = input
  RW = 1;
  delay_cycles(1);
  E  = 1;
  delay_cycles(1);
  read_byte = lcd_data;
  E  = 0;
  set_tris_B(0x00);      // PORTB = output
  return(read_byte);
}

/* Goi 1byte den LCD */
void lcd_send_byte( byte address, byte n )
{
  RS = 0;
  while ( bit_test(lcd_read_byte(),7) ) ;
  RS = address;
  delay_cycles(1);
  RW = 0;
  delay_cycles(1);
  E  = 0;
  lcd_data = n;
  delay_cycles(1);
  E = 1;
  delay_us(2);
  E = 0;
}

/* Khoi tao ban dau cho LCD */
void lcd_init()
{
    byte const lcd_init_string[4] = {0x38, 0x0C, 1 , 6};
    byte i;
    set_tris_B(0x00);
    RS = 0;
    RW = 0;
    E  = 0;
    delay_ms(15);
    for(i=1;i<=3;++i)
      {
        lcd_data = 3;
        delay_cycles(1);
        E = 1;
        delay_us(2);
        E = 0;
        delay_ms(5);
      }
    lcd_data = 2;
    delay_cycles(1);
    E = 1;
    delay_us(2);
    E = 0;
    delay_ms(5);
    for(i=0;i<=3;++i)
      {
        lcd_send_byte(0,lcd_init_string[i]);
      }
}

/* Nhay den vi tri (x,y) tren LCD,nhay nham y se bao loi */
void lcd_gotoxy( byte x, byte y)
{
  byte address;
  switch(y)
      {
        case 1:  address=0;
                  address+=x-1;
                  lcd_send_byte(0,0x80|address);
                  break;
        case 2:  address=0x40;
                  address+=x-1;
                  lcd_send_byte(0,0x80|address);
                  break;
        default :lcd_init();
                  lcd_putc("ERROR Y POSITION");
                  while(true); // Dung tai day!
      }
}

/* Hien thi ki tu hoac chuoi ra LCD */
void lcd_putc( char c)
{
  lcd_send_byte(1,c);
}

/* Hien thi ki tu hoac chuoi ra LCD */
void lcd_refresh()
{
  lcd_send_byte(0,1);
  lcd_send_byte(0,6);
}

/* Ham main */
void main (void)
{
  set_tris_B(0);    //PORTB = output
  set_tris_D(0);    //PORTD = output

  lcd_init();

  lcd_gotoxy(5,1);
  lcd_putc("WONDERFUL");

  lcd_gotoxy(4,2);
  lcd_putc("PICVIETNAM!");
}

http://www.freewebtown.com/nhhao/PIC/WDF_PVN.gif

Nên gom các hàm trên thành 1 file lcd_8bit.c chẳng hạn, đến khi sử dụng chỉ việc include nó vào cho khỏe... :D

tact 16-06-2006 06:04 PM

Các bác viết bài nhiệt tình quá. Em không biết các bác lấy thời giân đâu mà viết nữa. Khâm phục! Khâm phục!
Em đọc rất nhiều bài của các bác viết. Nhưng em chưa thấy bài nào nói về vấn đề XTAL. giả sử em có 1 con thạch anh 12M, em muốn config cho nó chạy ở 48MHz, theo các bác, cần phải làm thế nào?

namqn 16-06-2006 07:47 PM

Trích:

Nguyên văn bởi tact
Các bác viết bài nhiệt tình quá. Em không biết các bác lấy thời giân đâu mà viết nữa. Khâm phục! Khâm phục!
Em đọc rất nhiều bài của các bác viết. Nhưng em chưa thấy bài nào nói về vấn đề XTAL. giả sử em có 1 con thạch anh 12M, em muốn config cho nó chạy ở 48MHz, theo các bác, cần phải làm thế nào?

Câu hỏi của bạn không hoàn toàn rõ ràng.

Bạn hẳn là không thể bắt thạch anh 12 MHz chạy ở 48 MHz, do đó tôi hiểu theo một cách khác.

Nếu bạn muốn config. một con PIC chạy ở 48 MHz với thạch anh 12 MHz, cần thỏa mãn 2 điều kiện: con PIC phải có khả năng chạy ở 48 MHz (tôi không ủng hộ overclocking), và phải có một mạch nhân tần số (bên trong PIC hay bên ngoài, thường là các bộ PLL).

Bạn kiểm tra lại các điều kiện, nếu phần cứng của bạn thỏa điều kiện đã nêu, bạn có thể hỏi tiếp về cách config., nêu rõ chip cần được config.

Thân,

TTL 18-06-2006 06:01 PM

Bài viết này em sử dụng Lcd 2 hàng để hiển thị giá trị anlog đưa vào ở kênh A và dưa ra các cổng nối tiếp, thời gian để thay dổi giá trị ADC là 1s. (trong ccs chỉ hổ trợ Lcd 2 hàng nhưng basic lại rất hổ trợ rất nhiều LCD, mình muốn viết điều khiển LCD bằng Basic, nhưng lại muốn nhúng nó vào trong ccs phải làm sao mong các bác chỉ giúp)

/* bai tap su dung chuyen doi ADC the hien len LCD va goi qua cong RS232 sau 1s
(su dung ngat int_ad) */

#include "16f877a.h"
#use delay(clock=4000000)
#fuses nowdt,protect
#use rs232(baud=9600,parity=n,xmit=pin_c6,rcv=pin_c7)

#include "lcd.c"

long int a;
int x,y,z,t;

#int_ad
isr()
{
x=(a/100)+48; //lay ma Ascii cua gia tri ad
y=((a/10)-(a/100))+48;
z=(a%10)+48;
lcd_putc("\f");//xoa man hinh lcd
printf("Gia tri Digital: %ld \n",a);
lcd_putc("Digital:");
lcd_putc(x );
lcd_putc(y );
lcd_putc(z );
delay_ms(1000);
lcd_putc("\f") ;
}

main()
{
lcd_init();
enable_interrupts(int_ad);
enable_interrupts(global);
setup_port_a(all_analog);
setup_adc(adc_clock_internal);
set_adc_channel(0);
printf("Mach ADC \n");
lcd_putc("khoi tao lcd");
while(1)
{
a=read_adc();
}
}

nhh 20-06-2006 08:01 PM

Trong thư viện của CCS C không chỉ hỗ trợ LCD 2 hàng thôi đâu bạn, trong thư mục Drivers có 16*2, 20*2 và cả LCD graphic nữa.Bạn tìm kĩ trong đó!

Sangcao 21-06-2006 01:53 PM

Trang nay hay the ma it nguoi viet bai nhi?

Bác Nhh viết bài nhiều nhiều dể anh em học tập tí!

MoH 08-07-2006 05:30 PM

CCSC hỗ trợ LCD graphic cũng rất tốt, rất dễ ứng dụng, nhưng các bạn chú ý chân của LCD graphic hơi ngược nguồn so với LCD thường,
chân 1. VDD
2. VSS
Hic, chính vì sơ ý không để ý cái này mà em mất toi con LCD 128x64


Múi giờ GMT. Hiện tại là 09:32 AM.

Tên diễn đàn: vBulletin Version 3.8.11
Được sáng lập bởi Đoàn Hiệp.
Copyright © PIC Vietnam