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)

ncv 06-05-2006 10:28 AM

Ví dụ nhỏ về ngắt ngoài
 
Bình thường thì LED6 sáng, LED7 tối. Khi nhấn phím, LED6 tối, LED7 sáng
trong vòng 0,5 giây, rồi trở về trạng thái ban đầu (LED6 sáng, LED7 tối)

#include <16F877A.h>
#fuses NOWDT, XT
#use delay(clock=4000000)

void high_b6_low_b7() {
output_high(PIN_B6);
output_low(PIN_B7);
}

void low_b6_high_b7() {
output_low(PIN_B6);
output_high(PIN_B7);
}

///////////////////////////////////////////////////////////
#INT_EXT
void RB0_handler() {
low_b6_high_b7();
delay_ms(500);
high_b6_low_b7();
}

///////////////////////////////////////////////////////////
/**
* Keep B6 on and B7 off. Pressing the button causes interrupt:
* B6 off and B7 on, delay half second, then B6 on and B7 off
*
* Wiring (TM Board)
* (1) PIC's B0 to Matrix Key R0
* Matrix Key C0 to GND
* (2) PIC's B6-B7 to LED6-LED7
*
* Ref: Interrupt Mechanism
* http://www.mikroelektronika.co.yu/en...sicbook/06.htm
*/
void main() {
enable_interrupts(GLOBAL); // enable all interrupts
enable_interrupts(INT_EXT); // enable external interrupt from pin RB0/INT

high_b6_low_b7();
while (true) {
// do nothing
}
}

ncv 06-05-2006 01:56 PM

Ngắt ngoài và đèn 7 đoạn
 
Một phương án khác:

#include <16F877A.h>
#fuses NOWDT, XT
#fuses NOLVP // important
#use delay(clock=4000000)

// 0 1 2 3 4 5 6 7 8 9
byte const DIGITS[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f };
int8 i = 0;

///////////////////////////////////////////////////////////
/* private */void off_on_led_transistor() {
output_low(PIN_D1);
delay_ms(1);
output_high(PIN_D1);
}

///////////////////////////////////////////////////////////
/* private */void display(int8 digit) {
output_c(DIGITS[digit] ^ 0xff);
off_on_led_transistor();
}

///////////////////////////////////////////////////////////
#INT_EXT
void ngat_RB0() {
i = (i < 9) ? i+1 : 1;
delay_ms(200); // switch debounce period
}

///////////////////////////////////////////////////////////
/**
* Count number of key presses and display it on a 7-segment LED.
* If the number is 9, the next count will be 1
*
* Wiring (TM Board)
* (1) PIC's B0 to R0
* Matrix Key C0 to GND
* (2) PIC's C0-C6 to 7-segment LED's A-G
* PIC's D1 to 7-segment LED's C2
*/
void main() {
enable_interrupts(GLOBAL);
enable_interrupts(INT_EXT);

while (true)
display(i);
}

Trích:

Nguyên văn bởi nhh
Chào cả nhà !

Sao không thấy bác nào post bài vào luồng này vậy kà !Trầm quá...!Trầm quá...!Hay cái CCS C này không hấp dẫn mọi người chăng!
Không ai viết gì, tớ vẫn post cho nó đỡ trầm....!

Đã ví dụ về ngắt Timer, sau đây là 2 ví dụ về ngắt ngoài trên chân RB0 và trên các chân RB4 đến RB7:

Chương trình sau dùng ngắt ngoài trên RB0 đếm số lần cái button được nhấn xuống, hiển thị lên led 7 đoạn (common cathode).Nếu số lần nhấn vượt quá 9, chương trình sẽ quay về hiển thị lên led từ số 1.
Code:

//*****************************************************************************
// Author  : nhh
// Date    : 03/04/06
// Hardware: PIC16F877A
...
// Chuong trinh chinh
main()
{
set_tris_b(0b00000001);
set_tris_d(0);
enable_interrupts(global);
enable_interrupts(int_ext);
ext_int_edge(H_to_L);
portd=0b00111111;
while(true)
  {
  // chi doi ngat nen vong lap nay ko co gi ca !
  }
}



NTVinh 08-05-2006 05:36 PM

Chương trình ví dụ sau mô tả cách dùng PWM do CCS cung cấp.
PWM là gì? sử dụng nó vào mục đích gì?
1) PWM là gì? PWM là một bộ điều chế độ rộng xung. Có hai thông số (tạm gọi đơn giản như vậy, và có lẽ cũng chỉ quan tâm đến hai thông số này với PWM) quan trọng của PWM là chu kỳ xung T và thời gian t1 của mức logic 0,
trong ví dụ này thì t1 tương ứng với value. Để "điều chế độ rộng xung" thì chúng ta sẽ giữ nguyên T và thay đổi t1, theo yêu cầu của bài toán cụ thể.
Value trong ví dụ sau lấy được từ đầu vào anlaog, chu kỳ (hay tần số) của xung được chọn lựa từ PC thông qua cổng truyền thông nối tiếp RS232.
2) PWM dùng vào mục đích gì? Có nhiều ứng dụng cho nó, ví dụ truyền thông, điều khiển các van bán dẫn trong các biến tần, làm bộ nguồn chuyển mạch,...ôi nhiều lắm!
Bắt đầu viết nhé:

#if defined(__PCM__)
#include <16F877.h>

#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, BRGH1OK)

#elif defined(__PCH__)
#include <18F452.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, BRGH1OK)
#endif


void main() {
char selection=1;
int8 value;



printf("\r\nFrequency:\r\n");
printf(" 1) 7.8 khz\r\n");
printf(" 2) 19.5 khz\r\n");
printf(" 3) 0.48 khz\r\n");
do {
selection=getc();
}while((selection<'1')||(selection>'3'));


setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM

// The cycle time will be (1/clock)*4*t2div*(period+1)
// In this program clock=4000000 and period=127 (below)
// For the three possible selections the cycle time is:
// (1/4000000)*4*1*128 = 12.8 us or 7.8 khz
// (1/4000000)*4*4*128 = 51.2 us or 19.5 khz
// (1/4000000)*4*16*128= 204.8 us or 0.48 khz
switch(selection) {
case '1' : setup_timer_2(T2_DIV_BY_1, 127, 1);
break;
case '2' : setup_timer_2(T2_DIV_BY_4, 127, 1);
break;
case '3' : setup_timer_2(T2_DIV_BY_16, 127, 1);
break;
}



setup_port_a(ALL_ANALOG);
setup_adc(adc_clock_internal);
set_adc_channel( 0 );
printf("%c\r\n",selection);

while( TRUE ) {
value=read_adc();
//value++;
printf("%2X\r",value);
set_pwm1_duty(value); //value may be an 8 or 16 bit constant or variable
// This sets the time the pulse is
// high each cycle. We use the A/D
// input to make a easy demo.
// the high time will be:
// if value is LONG INT:
// value*(1/clock)*t2div
// if value is INT:
// value*4*(1/clock)*t2div
// for example a value of 30 and t2div
// of 1 the high time is 30us
// WARNING: A value too high or low will
// prevent the output from
// changing.
}

}
Nguyen The Vinh.

ncv 09-05-2006 09:18 PM

Chương trình hiển thị phím số ra đèn 7 đoạn (không dùng interrupt)
 
Code:

Chương trình hiển thị phím số trên ma trận phím 4x3 ra đèn 7 đoạn (không dùng interrupt)

#include <16F877A.h>
#fuses NOWDT, XT
#fuses NOLVP // important
#use delay(clock=4000000)

#include <kbd.c> // in PICC\Drivers

// 0 1 2 3 4 5 6 7 8 9
byte const DIGITS[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f };

///////////////////////////////////////////////////////////
/* private */void off_on_led_transistor() {
output_low(PIN_D1);
delay_ms(1);
output_high(PIN_D1);
}

///////////////////////////////////////////////////////////
void display(int8 digit) {
output_c(DIGITS[digit] ^ 0xff);
off_on_led_transistor();
}

///////////////////////////////////////////////////////////
int8 char_to_digit(char c) {
return c & 0b00001111; // first 4 bits only
}

///////////////////////////////////////////////////////////
int1 digit_key_pressed(char key) {
byte pattern;
pattern = 0b00110000;
return (key & pattern) == pattern;
}

///////////////////////////////////////////////////////////
/**
* Echo digit-key presses (0 to 9) of a 4x3 keypad to the 7-segment LED
*
* Configuration:
* Use PORTB for keypad by uncommenting the following line in PICC\Drivers\KBDD.c
* #define use_portb_kbd TRUE
*
* Wiring: (TM Board)
* (1) PIC's B1-B7 to Matrix Keypad's R3-R0&C2-C0 (notice the reverse order)
* (2) PIC's C0-C6 to 7-segment LED's A-G
* PIC's D1 to 7-segment LED's C2
*/
void main() {
int8 i, digit;
char key;

kbd_init();
while (true) {
key = kbd_getc();
if (digit_key_pressed(key)) {
digit = char_to_digit(key);
for (i = 0; i < 200; i++) // repeat the display for human eyes
display(digit);
}
}
}


ncv 12-05-2006 05:24 PM

Chương trình hiển thị phím số ra đèn 7 đoạn (DÙNG INTERRUPT)
 
Chương trình hiển thị phím số trên bàn phím 4x3 ra đèn 7 đoạn (DÙNG INTERRUPT).

#include <16F877A.h>
#fuses NOWDT, XT
#fuses NOLVP // important
#use delay(clock=4000000)

#include <kbd.c> // in PICC\Drivers

// 0 1 2 3 4 5 6 7 8 9
byte const DIGITS[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f };

///////////////////////////////////////////////////////////
/* private */void off_on_led_transistor() {
output_low(PIN_D1);
delay_ms(1);
output_high(PIN_D1);
}

///////////////////////////////////////////////////////////
void display(int8 digit) {
output_c(DIGITS[digit] ^ 0xff);
off_on_led_transistor();
}

///////////////////////////////////////////////////////////
int8 char_to_digit(char c) {
return c & 0b00001111; // first 4 bits only
}

///////////////////////////////////////////////////////////
int1 digit_key_pressed(char key) {
byte pattern;
pattern = 0b00110000;
return (key & pattern) == pattern;
}

///////////////////////////////////////////////////////////
#INT_RB
void RB_handler() {
int8 i, digit;
char key;

key = kbd_getc();
if (digit_key_pressed(key)) {
digit = char_to_digit(key);
for (i = 0; i < 200; i++) // repeat the display for human eyes
display(digit);
}
}
///////////////////////////////////////////////////////////
/**
* Echo digit-key presses (0 to 9) of a 4x3 keypad to the 7-segment LED
*
* Configuration:
* Use PORTB for keypad by uncommenting the following line in PICC\Drivers\KBDD.c
* #define use_portb_kbd TRUE
*
* Wiring: (TM Board)
* (1) PIC's B1-B7 to Matrix Keypad's R3-R0&C2-C0 (notice the reverse order)
* (2) PIC's C0-C6 to 7-segment LED's A-G
* PIC's D1 to 7-segment LED's C2
*/
void main() {
enable_interrupts(GLOBAL);
enable_interrupts(INT_RB);
kbd_init();
while (true) {
// do nothing
}
}

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

bien_van_khat 09-07-2006 11:59 PM

hì, tui hài lòng với CCS C chỉ trừ duy nhất 1 cái báo lỗi:
Attempt to create a pointer to a constant ->x(

bien_van_khat 10-07-2006 12:04 AM

Trích:

Nguyên văn bởi MoH
CCSC hỗ trợ LCD graphic cũng rất tốt,

Bác có thể nói rõ đó là file nào ko?

Trích:

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
LCD graphic nhiều loại lắm, mỗi loại lại có 1 kiểu chân, nếu ko có đúng datasheet của nó thì đừng bao giờ đoán mò. Tui mém tiu 1 con 128x64, vì ko có datasheet nên nhìn đại con nào giống giống rồi mắc thử, hix.

MoH 20-07-2006 01:05 PM

HÌ, xin lỗi mình đã hơi vội vàng, đúng là có nhiều kiểu chân của LCD Graphic khác nhau.
Còn file exp của CCSC dùng cho LCD Graphic là EX_GLCD

briantk_1988 21-07-2006 08:05 AM

Các bác ơi, cháu không có CSC C, nếu bác nào có upload lên được không?

Cám ơn rất nhiều

dohoangnam 21-07-2006 10:48 AM

Tỗi sẽ thử CCS này xem sao. Thú thực tôi cũng có dùng qua nó, với Mikro C, với HTPIC, thì thấy khả năng tối ưu mã của nó không tốt lắm nên không thích thôi nhưng thấy mọi người khen nhiều quá tôi phải xem lại. Tôi thấy Mikro rất tốt, chuyên nghiệp nhanh nhẹn và có nhiều hỗi trợ, dễ sử dụng.

heliman 01-08-2006 09:56 AM

Tôi chạy thử bài LCDFirst của bác nhh rồi, bác kiếm con LCD HD4470 (16_X_2) màu vàng này ở đâu thế(Nó không có trong thư viện của Proteus). Tôi ghép song song với LCD LM016L (trong TV Proteus) mà cái hiện, cái không.

Sao không gửi hình JPG được nhỉ. tôi sẽ gửi cho bác nhh dể bác gửi lên vậy.

heliman 01-08-2006 05:38 PM

Bác nhh ơi , bác ghi tiêu đề là "dùng 4 bít LCD dữ liệu", nhưng bác lại gửi nhầm file " lcd_pvn.rar" lên . File này đã được gửi trước đó, nhưng là file "dùng 8 bit dữ liệu" .
Bác gửi file rar đó (4 bit dl , sơ đồ + code) lên cho anh em cùng tham khảo.

Trích:

Nguyên văn bởi nhh
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('!');
}



linhnc308 01-08-2006 07:15 PM

Lập trình CCS cho PIC6F877A tôi đã pót khá nhiều bài lập trình bên đien tử VN rồi:
http://dientuvietnam.net/forums/showthread.php?t=1008

Bạn nào quan tâm thjif qua đó down về, có đủ cả code và mạch.

Chúc thành công!

hpecom 02-08-2006 10:54 AM

Trích:

Nguyên văn bởi briantk_1988
Các bác ơi, cháu không có CSC C, nếu bác nào có upload lên được không?

Cám ơn rất nhiều

Bé Briantk_1988 vào đây nhé
http://www.picvietnam.com/forum/showthread.php?t=21
Àh mà bé học lớp chồi mấy?:D Chắc thần đồng đất Việt đây!
Chúc bé mau ăn chóng lớn.

briantk_1988 03-08-2006 08:18 AM

Cám ơn bác hpecom, cháu hoc lớp chồi THPT (sinh năm 1988 mà lị) :-), hết lớn rồi, ăn nhiều cũng không lớn nổi.

Các bác cho cháu hỏi cau này về CCS: trong hầu hết các ví dụ của CCS C, họ đều dùng printf (RS232) để xuất dữ liệu. Cháu không hiểu làm như thể để làm gì. Cháu cũng không biết vẽ mạch thế nào để xuất hiện các dòng chữ trong printf.

Cám ơn các bác...

hpecom 03-08-2006 10:07 AM

Hàm printf() xuất một chuỗi ra cổng nối tiếp.
Nếu kết nối PIC với máy tính bằng RS232 và cấu hình thích hợp cho cổng thì máy tính sẽ nhận được chuỗi mà bé đặt trong dấu ().
Vẽ mạch thì bé vẽ theo các mạch giao tiếp máy tính mà các chú đã vẽ trên diễn đàn: Chỉ cần 3 sợi dây Rx (receive), Tx (Transfer) và chân Gnd. Cần có con đệm Max232 nằm ở giữa. Nghĩa là PIC - Max232 - PC.
Nhưng tại sao bé không làm các bài tập đơn giản trước như điều khiển LED chớp tắt, hiển thị số trên LED 7 đoạn hay điều khiển nhiều đèn LED chớp theo nhiều kiểu, .. mà lại làm giao tiếp máy tính cho khó khăn vậy?
Dù sao hpecom cũng chúc bé thành công và đừng để ảnh hưởng đến việc học!
hpecom.

briantk_1988 03-08-2006 09:54 PM

Cám ơn sư huynh đã quan tâm :-)

Bé đã tập viết bằng ASM, điều khiển LED, Interupt... rồi. Hôm nay mới chuyến sang CCS C. Theo lời huynh nói thì mọi ví dụ trong CCS C phải được nối với PC mới có thể xem kết quả được.

Cám ơn rất nhiều.

hpecom 04-08-2006 10:24 AM

Công nhận bé này mau lớn thật! Mới hôm qua gọi bác hôm này đã gọi là huynh, không biết ngày mai là cái gì?:D. 1988 là đã tốt nghiệp THPT rồi.

Không phải mọi ví dụ mà chương trình nào có lệnh printf() thì cần máy tính nếu đệ muốn xem kết quả của lệnh.
Chúc đệ thành công.

briantk_1988 04-08-2006 11:40 PM

Cám ơn, cám ơn.

Chatchit một chút: hôm qua mới để tử mởi nhập môn, gọi là bác; hôm nay, thành đệ tử một túi rồi nên gọi là huynh.

b

boys3509_2006 06-08-2006 04:09 PM

Cho hỏi tí

Em mới vô thôi, huynh giải thích mấy dòng code sau cho em được ko ?
" set_timer0(6) " ; " ++count; " ; "if (count==2000) "

Nó nằm trong ct nháy led dùng interrup và timer0. biến count và a có tác dụng gì ? tại sao phải lùi a "a=a<<1" ?

hpecom 07-08-2006 09:31 AM

Chào boys!
* set_timer0(6); đây là phương thức gọi hàm. set_timer0() là một hàm, 6 là tham số. Còn hàm này làm gì thì bạn phải tự tìm hiểu lấy.
* ++count; là thực hiện tăng biến count lên 1 đơn vị. Nó giống lệnh count=count+1. Còn có một cú pháp nhữa là count++. Hai lệnh lệnh này có sự khác nhau về thứ tự thực hiện khi nằm trong một biểu thức so sánh.
* if(count==2000) là phép so sánh. Nếu giá trị của biến count bằng 2000 thì kết quả của phép so sánh là True ngược lại là False.
* a là .. mình chịu thua!?!?:D Còn dịch trái là để nhân đôi giá trị biết. Bạn hãy xem lại đại số bool có rất nhiều điều hay ở đó.
Bạn nên tìm một cuốn sách lập trình C của Quách Tuấn Ngọc để hiểu về những điều này.
Chúc bạn thành công.
hpecom.

boys3509_2006 13-08-2006 03:37 PM

CCS for pic6F877A
 
cảm ơn anh hpecom đã chỉ giáo :D

boys3509_2006 13-08-2006 03:48 PM

CCS C for PIC16F877A
 
Nhân tiện anh cho em hỏi thêm : giả sử em viết một ct nháy led (cho nó chạy như vòng lặp ), đầu tiên kt các khóa để biết ct sẽ nháy led kiểu nào. sau đó thì ct sẽ thực hiện lệnh nháy đèn led, nếu như sau khi ta bấm nút chọn kiểu nháy, ct sẽ tiếp tục thực hiện lệnh tiếp theo mà ta đổi ý bấm nút khác để đổi kiểu thì ct sẽ không nhận vì đang thực hiện các lệnh bật-tắt led. Bài tập này hình như có ở trang 2, 3 dùng interrup và timer0, Tại sao nhỉ ?

hpecom 14-08-2006 09:58 AM

Nếu bạn sử dụng vòng lặp thì nút bấm sẽ ko được nhận trong khi vòng lặp đang thực hiện. Cách giải quyết bài toán như sau:
_ Bạn hãy khai báo 1 biến toàn cục. Biến này lưu kiểu chớp. Hàm chớp sẽ dựa vào giá trị biến này mà đổi kiểu chớp.
_ Sử dụng timer0 làm thời gian chuẩn để trì hoãn chớp tắt (vì nếu dùng làm thời gian trì hoãn chớp tắt thì nó quá ngắn ta không thể thấy chớp được).
_ Khai báo một biến toàn cục làm hệ số cho thời gian trì hoãn. Trong ngắt Timer0 bạn sẽ đếm biến này đến một giá trị nào đó thì gọi hàm chớp tắt.
_ Bạn cũng cần khai báo một biến toàn cục để cho hàm chớp tắt biết mình phải làm gì. Hoặc nếu ko bạn có thể truyền tham số cho hàm.
_ Trong chương trình main, bạn dùng vòng lặp để bắt phím nhấn (hoặc dùng ngắt) và thực hiện thay đổi giá trị của biến kiểu chớp.
Trên đây là giải thuật, đó là phương pháp để giải quyết bài toán. Tất nhiên trong quá trình viết bạn có thể khai báo thêm các biến toàn cục hay cục bộ để thực hiện thuật toán. Tốt nhất là bạn nên viết trước và gặp khó khăn thì đưa cả code lên để mọi người giúp bạn giải quyết.
Đây là một bài toán khá hay, mong rằng bạn sẽ thành công.
hpecom.

boys3509_2006 19-08-2006 04:51 PM

CCS C for PIC16F877A
 
Em mượn tạm đoạn code của nhh anh mổ xẻ nó giùm em nhé

//************************************************** **
// Author : nhh
// Date : 02/04/06
// Hardware: PIC16F877A
//************************************************** **
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#byte portb=0x06
#define led pin_B0
int16 count;
int8 a;

//Chuong trinh ngat TMR0
#int_timer0
void interrupt_timer0()
{
set_timer0(6);
++count;
if(count==2000)
{
count=0;
a=a<<1; // dich trai a 1bit :confused:
}
if(a==256)
{
a=1;
count=0;
}
}

//Chuong trinh chinh
main()
{
set_tris_b(0);
enable_interrupts(global);
enable_interrupts(int_timer0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); :confused:
set_timer0(6);
count=0;
a=1;
while(true)
{
portb=a; :confused:
}
}

Anh giải thích mấy cỗ có :confused: giùm em. Tại sao phải setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); mà ko Div 3, 4,... hở anh ?


Múi giờ GMT. Hiện tại là 02:36 PM.

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