PDA

View Full Version : CCS C for PIC16F877A


Pages : [1] 2

nhh
26-03-2006, 05:58 PM
Chào cả nhà!

Để lập trình cho PIC, mọi người có thể chọn cho mình những ngôn ngữ lập trình khác nhau như ASM, CCS C, HT-PIC, pascal, basic,...
Với nhh, đầu tiên tìm hiểu và viết chương trình cơ bản bằng ASM để hiểu rõ cấu trúc sau đó thì viết bằng CCS C cũng viết lại những cái cơ bản và đi dần lên, tốc độ lúc này nhanh hơn khi viết bằng ASM rất nhiều.

Khi viết bằng CCS C thông thường thì dịch ra file.hex có dài hơn so với khi viết bằng ASM. Hai ngôn ngữ CCS C và HT-PIC được ưa chuộng hơn cả, CCS C dễ học,gần gũi với ASM còn HT-PIC là dạng ANSI C.

Để lập trình và biên dịch CCS C, dùng chương trình PIC C Complier,sau khi soạn thảo các bạn ấn F9
để dịch,nếu thành công sẽ có thông báo như sau:

http://i82.photobucket.com/albums/j257/nhhao/ccsc.gif

Ngoài ra, để xem code ASM như thế nào,sau khi dịch bạn chọn mục C/ASM List như hình dưới đây:

http://i82.photobucket.com/albums/j257/nhhao/ccsc1.gif

Link download trình biên dịch CCS C ở đây: http://www.tailieuvietnam.net/download/PICSoft/CCSC_3.249.rar
Phiên bản mới hơn tải tại: www.kho.tailieuvietnam.net, vào Download Home > Điện tử tàn thư > Vi điều khiển - Vi xử lý - PLC

Chúng ta cùng nhau tìm hiểu lần lượt các phần sau:

1.I/O + Delay
2.Timer và ngắt Timer
3.Ngắt ngoài
4.ADC, PWM,... (tập trung mổ xẻ nhiều)
5......

Tạm thời cứ như vậy đã, sau này sẽ tính tiếp!
Nào,chúng ta bắt đầu thôi!

nhh
26-03-2006, 06:07 PM
Chương trình này làm nhấp nháy con led ở chân RB0 1s sáng, 1s tắt.
#include<16F877A.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=10000000)
main()
{
while(true)
{
output_high(PIN_B0);
delay_ms(1000);
output_low(PIN_B0);
delay_ms(1000);
}
}
Trên đây:
#include<16F877A.h>
Khai báo con PIC bạn sử dụng, file này chương trình viết sẵn nhằm khai báo các bit, thanh ghi quan trọng trong con pic này.Các bạn có thể vào thư mục cài đặt C:\Program Files\PICC\Devices\16F877A.h để xem nó khai báo được những gì trong đó!
#fuses NOWDT,PUT,HS,NOPROTECT
Thiết lập các config
#use delay(clock=10000000)
Khai báo tần số dao động cấp cho PIC
output_high(PIN_B0)
Xuất ra chân RB0 mức logic 1 (tức 5V), do khi thực hiện hàm này đã bao hàm luôn việc tác động lên thanh ghi TRISB (dùng chọn chân I/O) do vậy ta không cần viết lệnh chọn chân I/O nữa.
output_low(PIN_B0)
Ngược lại
delay_ms(1000)
Tạo trễ khoảng thời gian theo mili giây là 1000 (tức 1s)
Chú ý hàm này chỉ có tác dụng khi có khai báo tần số dao động cấp cho PIC

Và bây giờ thử làm cho tất cả 8 led nối với portB chớp tắt 1s xem nào!Phải chăng ta sẽ làm như sau (Viết trong vòng lặp while):
{
output_high(PIN_B0);
output_high(PIN_B1);
output_high(PIN_B2);
output_high(PIN_B3);
output_high(PIN_B4);
output_high(PIN_B5);
output_high(PIN_B6);
output_high(PIN_B7);
delay_ms(1000);
output_low(PIN_B0);
output_low(PIN_B1);
output_low(PIN_B2);
output_low(PIN_B3);
output_low(PIN_B4);
output_low(PIN_B5);
output_low(PIN_B6);
output_low(PIN_B7);
delay_ms(1000);
}
Viết như thế này thì quá dài và thiếu chính xác nữa, có cách nào khác hay hơn không ? Sao ta không xuất đẩy hẳn portB lên mức cao,tạo trễ 1s rồi ép cho nó xuống mức thấp,tạo trễ 1s cùng một lúc nhỉ !
Bài tiếp theo sẽ đưa ra câu trả lời....
http://www.freewebtown.com/nhhao/PIC/Delay%201s%20RB0.GIF

ntc
26-03-2006, 06:18 PM
Hihi.

Sợ ASM rồi hả!

nhh
26-03-2006, 06:30 PM
Ah ..ah!
Sợ thì không hẳn nhưng viết nó phức tạp quá....:D làm dễ phát chán ...
Nhưng không sao chính cứ post mấy cái tutorial nhanh nhanh lên, nhh vẫn dùng asm như thường à .....

Cái nào đơn giản ,dễ học thì mình vào thôi....

nhh
26-03-2006, 06:39 PM
Ăc..ặc..đang post thì bị cúp điện,bực cả mình...:mad:

Và đây là câu trả lời cho việc delay led ở portB 1s


#include<16F877A.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=10000000)
#use fast_io(b)
#byte portb=0x6
main()
{
set_tris_b(0);
while(true)
{
portb=255; //all led on
delay_ms(1000);
portb=0; //all led off
delay_ms(1000);
}
}


#byte portb=0x6
Khai báo địa chỉ portB, không như trong MPLAB đã định nghĩa luôn cái này cho ta, nếu không có dòng này chương trình sẽ báo lỗi chưa định nghĩa portB
set_tris_b(0)
Tất cả các chân của portB là output, muốn set tất cả các chân là input thì trong ngoặc là 255,....
Trong HELP hướng dẫn lệnh này như sau:

"These functions allow the I/O port direction (TRI-State) registers to be set. This must be used with FAST_IO and when I/O ports are accessed as memory such as when a #BYTE directive is used to access an I/O port. Using the default standard I/O the built in functions set the I/O direction automatically."

Rõ ràng khi set byte làm I/O nếu ta thêm khai báo:
#use fast_io(b)
Dùng khai báo này thì CCS sẽ chỉ thực hiện đúng một lệnh cho việc I/O các chân trên port tương ứng, nếu ko nó phải mất khoảng 3 hay 4 lệnh gì đó.

Phần I/O + Delay tạm thời xong như vậy, bác nào có phản hồi thì tiếp tục thảo luận.Xong phần này có thể viết về xuất led 7 đoạn, quét phím, LCD,....Bác nào viết thì cứ post lên cho bà con thảo luận nhé !
Hẹn gặp lại vài hôm nữa ở bài Timer/Counter !
Chào!

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

nhh
27-03-2006, 08:10 PM
Nguyên văn bởi ngoalongdochanh
Cho toi hoi tai sao khi khai bao:
#device PIC16F877 *=16 ADC=10

thi CCSC bao loi: "Can not change device type this far into the code"
Cach khac phuc
Đây là 1 ví dụ nhỏ về ADC,chân RA0 lấy tín hiệu Analog từ biến trở và xuất giá trị số biến đổi tương ứng qua tám led nối ở portB
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#device 16F877*=16 ADC=8
#use delay(clock=10000000)
Int8 adc;
main()
{
setup_adc(adc_clock_internal);
setup_adc_ports(AN0);
set_adc_channel(0);
delay_ms(10);
while(true)
{
adc=read_adc();
output_B(adc);
}
}

ngoalongdochanh
29-03-2006, 10:29 AM
Cám ơn nhh đã trả lời cho mình, do lần trước mình khai báo chưa đúng cách giữa 16f877A và *=16 đúng ra phải viết liền như bạn minh lại viết cách ra như thế này "16f877A *=16". Nhân tiện cho mình hỏi luôn ý nghĩa của việc khai báo "#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT"

nhh
31-03-2006, 12:15 PM
Cám ơn nhh đã trả lời cho mình, do lần trước mình khai báo chưa đúng cách giữa 16f877A và *=16 đúng ra phải viết liền như bạn minh lại viết cách ra như thế này "16f877A *=16". Nhân tiện cho mình hỏi luôn ý nghĩa của việc khai báo "#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT"

He he...
Tui cứ tưởng ko ma nào vào luồng này chứ !
Khai báo:
"#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT

-HS :sử dụng thạch anh tần số cao
-NOWDT:tắt WDT
-NOPROTECT:tắt PROTECT
-NOLVP:không dùng LVP
-NOBROWNOUT:ko BROWNOUT

Còn cụ thể ý nghĩa thế nào,bạn vào help của CCS C gõ :"#fuses"

Chào!

ntc
01-04-2006, 12:33 PM
Cái luồng bên này nhh vẽ hình cẩu thả quá!

Cái chân MCLR*, bạn phải nối thên cái công tắc ấn vào. nhh nối như vậy thì không reset được con PIC đâu

Hai cái chân Vss phải được nối mass.

Chân nào không xài, nhh nên đánh dấu bỏ đi (trong thanh công cụ của ORCAD có cái dấu này đó).


Nếu mình chịu khó cẩn thận hơn một chút thì sẽ hạn chế được rất nhiều sự bỡ ngỡ cho người mới học. Bạn coi mấy cái hình mình vẽ trong mấy cái Tutorial thì thấy, từng chi tiết đều được chú ý cả, không thể tùy tiện được.

:D

nhh
01-04-2006, 01:42 PM
Thank you!
Đúng là mình ko chú ý chỗ này!Mình sẽ sửa và up lên lại!

batos
02-04-2006, 08:54 AM
cho mình hỏi viết chương trình như thế nào để có thể nạp qua bootloader cho 877A dùng Tinybootloader . Bạn có thể viết 1 ví dụ nháy led như trên đc ko

falleaf
02-04-2006, 10:30 AM
Viết chương trình như bình thường, không có gì thay đổi, nhưng vị trí đầu tiên của chương trình phải lưu ý. Bạn xem hướng dẫn tinybootloader.

Chúc vui.

nhh
02-04-2006, 11:27 AM
Hi....!

Trong Pic16f877a có 3 timer :
+ Timer0 : 8 bit
+ Timer1 : 16 bit
+ Timer2 : 8 bit
Timer dùng cho nhiều ứng dụng : định thời, capture, pwm, ...

1.Timer0

Thanh ghi tác động:
http://www.freewebtown.com/nhhao/PIC/TMR0-thanh ghi tac dong.GIF
Các lệnh:
setup_TIMER_0(mode);
setup_COUNTERS (rtcc_state, ps_state); // hay setup_WDT()
set_TIMER0(value); // hay set_RTCC(value) :xác định giá trị ban đầu (8bit) cho Timer0
get_TIMER0(); // hay get_RTCC() :trả về số nguyên (8bit) của Timer0
Trong đó mode là một hoặc hai constant (nếu dùng hai thì chèn dấu "|"ở giữa) được định nghĩa trong file 16F877A.h gồm :

RTCC_INTERNAL : chọn xung clock nội
RTCC_EXT_L_TO_H : chọn bit cạnh lên trên chân RA4
RTCC_EXT_H_TO_L : chọn bit cạnh xuống trên chân RA4

RTCC_DIV_2 :chia prescaler 1:2
RTCC_DIV_4 1:4
RTCC_DIV_8 1:8
RTCC_DIV_16 1:16
RTCC_DIV_32 1:32
RTCC_DIV_64 1:64
RTCC_DIV_128 1:128
RTCC_DIV_256 1:256

rtcc_state là một trong những constant sau:

RTCC_INTERNAL
RTCC_EXT_L_TO_H
RTCC_EXT_H_TO_L

ps_state là một trong những constant sau:

RTCC_DIV_2
RTCC_DIV_4
RTCC_DIV_8
RTCC_DIV_16
RTCC_DIV_32
RTCC_DIV_64
RTCC_DIV_128
RTCC_DIV_256
WDT_18MS
WDT_36MS
WDT_72MS
WDT_144MS
WDT_288MS
WDT_576MS
WDT_1152MS
WDT_2304MS

Mình cũng chưa hiểu ý nghĩa của hàm WDT_..., ko biết có phải khai báo như trên thì sau khoảng thời gian ms bao nhiêu đó đặt sau WDT_ thì sẽ reset lại Pic ?????:confused:

2.Timer1

Thanh ghi tác động:
http://www.freewebtown.com/nhhao/PIC/TMR1-thanh ghi tac dong.GIF
Các lệnh:
setup_TIMER_1(mode);
set_TIMER1(value); // xác định giá trị ban đầu (16bit) cho Timer1
get_TIMER1(); // trả về số nguyên (16bit) của Timer1
mode gồm (có thể kết hợp bằng dấu "|"):

T1_DISABLED : tắt Timer1
T1_INTERNAL : xung clock nội (Fosc/4)
T1_EXTERNAL : xung clock ngoài trên chân RC0
T1_EXTERNAL_SYNC : xung clock ngoài đồng bộ
T1_CLK_OUT
T1_DIV_BY_1
T1_DIV_BY_2
T1_DIV_BY_4
T1_DIV_BY_8

3.Timer2

Thanh ghi tác động:
http://www.freewebtown.com/nhhao/PIC/TMR2-thanh ghi tac dong.GIF
Các lệnh:
setup_TIMER_2(mode, period, postscale);
set_TIMER2(value); // xác định giá trị ban đầu (8bit) cho Timer2
get_TIMER2(); // trả về số nguyên 8bit
Với mode gồm (co the ket hop bang dau "|"):

T2_DISABLED
T2_DIV_BY_1
T2_DIV_BY_4
T2_DIV_BY_16

period là số nguyên từ 0-255, xác định giá trị xung reset
postscale là số nguyên 1-16, xác định reset bao nhiêu lần trước khi ngắt.

nhh
02-04-2006, 11:40 AM
INTERRUPT

Các lệnh dùng cho ngắt:
enable_interrupts(level); //cho phép ngắt kiểu level
disable_interrupts(level); //cấm ngắt kiểu level
ext_int_edge(edge); // chọn cách lấy xung loại edge
level bao gồm:

GLOBAL : ngắt toàn cục
INT_RTCC : tràn TMR0
INT_RB : có thay đổi trạng thái một trong các chân RB4 đến RB7
INT_EXT : ngắt ngoài
INT_AD : chuyển đổi AD đã hoàn tất
INT_TBE : bộ đệm chuyển RS232 trống
INT_RDA : data nhận từ RS232 sẵn sàng
INT_TIMER1 : tràn TMR1
INT_TIMER2 : tràn TMR2
INT_CCP1 : có capture hay compare trên CCP1
INT_CCP2 : có capture hay compare trên CCP2
INT_SSP : có hoạt động SPI hay I2C
INT_PSP : có data vào cổng parallel slave
INT_BUSCOL : xung đột bus
INT_EEPROM : ghi vào eeprom hoàn tất
INT_TIMER0 : tràn TMR0
INT_COMP : kiểm tra bằng nhau comparator

edge bao gồm:

L_TO_H : cạnh lên
H_TO_L : cạnh xuống

Sau khai báo trên để vào đoạn chương trình ngắt, khai báo:

#INT_.........

Ví dụ vào thực thi ngắt ngoài, ta có đoạn code:
#INT_EXT
void ngat_ngoai()
{
//Chương trình ngắt tại đây
}

nhh
02-04-2006, 11:45 AM
Đây là chương trình dùng ngắt Timer0 định thì 1s.
Đầu tiên led ở chân RB0 sáng, sau 1s sẽ dịch sang trái, nghĩa là led 1 trên chân RB1 sáng , lần lượt như vậy cho các led trên portB và lặp lại mãi mãi.
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#byte PORTB = 0x06

int16 count;
int8 a;
//Chuong trinh ngat TMR0
#int_timer0
void interrupt_timer0()
{
set_timer0(6);
++count;
if(count == 2000) // 2000*500us = 500000us = 1s
{
count=0;
rotate_left(&a,1);
}
}
//Chuong trinh chinh
void main(void)
{
set_tris_b(0);
enable_interrupts(int_timer0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);
enable_interrupts(global);
set_timer0(6);// T_dinhthi = 2*(256 - 6)*1us = 500us
a = 0x01;

while(true)
{
PORTB = a;
}
}

ntc
02-04-2006, 03:33 PM
Mình cũng chưa hiểu ý nghĩa của hàm WDT_..., ko biết có phải khai báo như trên thì sau khoảng thời gian ms bao nhiêu đó đặt sau WDT_ thì sẽ reset lại Pic ?????


WDT là "chó giữ nhà" (Watchdog Timer). Bộ phận này có nhiệm vụ reset lại PIC sau một khoảng thời gian định trước. WDT sẽ reset vi điều khiển khi bộ đếm của WDT bị tràn. Mục đích của nó là tránh trường hợp vi điều khiển bị "treo" khi phải hoạt động liên tục trong một khoảng thời gian lâu dài.

Thời gian định trước này phụ thuộc vào tần số loại thạch anh sử dụng và bộ chia tần số trước (prescaler) của WDT.

Ta thấy WDT chỉ liên quan đến Timer 0, còn các Timer khác không có liên quan. Đó là tại vì WDT có bộ chia tần số (prescaler) dùng chung với Timer 0.

Lưu ý là muốn sử dụng WDT cần chú ý đến phần khai báo các "fuse" ở đầu chương trình.


rtcc_state là một trong những constant sau:

RTCC_INTERNAL
RTCC_EXT_L_TO_H
RTCC_EXT_H_TO_L


Mỗi Timer đều có 2 tác dụng:

Tác dụng định thời: Timer sẽ dựa vào các xung tạo ra bởi bộ dao động (thạch anh, dao động RC, ...) cung cấp cho vi điều khiển để đếm. Và dựa vào tần số bộ dao động, giá trị các bộ chia tần số và giá trị của Timer, ta có thể xác định được thời gian thực. Như vậy trong trường hợp muốn Timer hoạt động ở chế độ định thời, ta phải khai báo rtcc_state là "RTCC_INTERNAL" (xử dụng tần số dao động nội).

Tác dụng đếm: Timer sẽ dựa vào các xung lấy từ môi trường bên ngoài để đếm. Tùy theo Timer mà ta sử dụng chân lấy xung tương ứng (Timer 0 là chân RA4, Timer1 là chân RC0). Các xung này có tác dụng phản ánh các hiện tượng trong thực tế, và việc đếm các xung cũng đồng nghĩa với việc đếm các hiện tượng đó. Và để linh động hơn trong quá trình xử lí, Timer còn cho phép chọn cạnh tác động lên bộ đếm (chế độ này chỉ có ở Timer 0). Như vậy muốn Timer hoạt động ở chế độ đếm, ta phải khai báo rtcc_state là một trong 2 trường hợp còn lại (sử dụng dao động ngoài).


ps_state là một trong những constant sau:

RTCC_DIV_2
RTCC_DIV_4
RTCC_DIV_8
RTCC_DIV_16
RTCC_DIV_32
RTCC_DIV_64
RTCC_DIV_128
RTCC_DIV_256
WDT_18MS
WDT_36MS
WDT_72MS
WDT_144MS
WDT_288MS
WDT_576MS
WDT_1152MS
WDT_2304MS


Ở đây có đến 2 hàm dùng để ấn định tỉ số chia của prescaler, một hàm là "RTCC_DIV_...", một hàm là "WDT_ ...". Đó là bởi vì Timer 0 và WDT dùng chung bộ chia tần số. Khi bộ chia được Timer 0 sử dụng thì WDT không đựoc hỗ trợ với bộ chia này nữa. Như vậy sự khác biệt về thao tác giữa 2 hàm này có thể là như sau:

Hàm "RTCC_DIV_..." : cho phép Timer 0 sử dụng bộ chia tần số, không cho phép WDT sử dụng và ấn định tỉ số chia của nó.

Hàm "WDT_ ..." : cho phép WDT 0 sử dụng bộ chia tần số, không cho phép Timer 0 sử dụng và ấn định tỉ số chia của nó.

T2_DISABLED
T2_DIV_BY_1
T2_DIV_BY_4
T2_DIV_BY_16

period là số nguyên từ 0-255, xác định giá trị xung reset
postscale là số nguyên 1-16, xác định reset bao nhiêu lần trước khi ngắt.
hôm nay 09:30 AM


Ta có thể nhận thấy là Timer 2 có đến 2 bộ chia tần số trước và sau, một bộ prescaler được đính kèm vào các chế độ hoạt động của Timer 2 (T2_DIV_BY_1, T2_DIV_BY_4, T2_DIV_BY_16), một bộ là postscaler cis tỉ số chia từ 1:16. Như vậy nó cho phép việc lựa chọn tỉ số chia linh động hơn.

Timer 2 không hoạt động ở chế độ đếm. Chức năng của nó chủ yếu là tác động lên tốc độ baud cho MSSP thì phải. Không nhớ rõ lắm.

postscale là số nguyên 1-16, xác định reset bao nhiêu lần trước khi ngắt.

Cái này để mình coi lại đã, tại sao nó lại xác định reset bao nhiêu lần trước khi ngắt ??. Phải coi lại cái sơ đồ khối của Timer 2 mới biết được.

nhh
05-04-2006, 11:05 AM
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.
//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#use fast_io(d)
#byte portb=0x06
#byte portd=0x08
const unsigned char digital[]={0b00000110, 0b01011011, 0b01001111, 0b01100110,\
0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111};
// ma hoa digital duoi dang mang
// Chuong trinh ngat
#int_ext
void ngat_RB0()
{
int i;
if(i<9)
{
portd=digital[i];
++i;
}
if(i==9)
{
i=0;
}
}
// 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 !
}
}
http://www.freewebtown.com/nhhao/PIC/dem1_9dungngatngoai.gif

nhh
05-04-2006, 11:08 AM
Còn đây là ứng dụng ngắt ngoài trên RB4 đến RB7 để thay đổi kiểu cũng như tốc độ chớp nháy mấy con led chỉ để....ngắm cho vui mắt !

Ấn sw1, led1 nhấp nháy với delay 250ms
Ấn sw2, led1,2 nhấp nháy với delay 200ms
Ấn sw3, led1,2,3 nhấp nháy với delay 150ms
Ấn sw4, led1,2,3,4 nhấp nháy với delay 100ms
//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#byte portb=0x06
#byte intcon=0x000B
#bit RB4=portb.4
#bit RB5=portb.5
#bit RB6=portb.6
#bit RB7=portb.7
#bit RBIF=intcon.0 //dinh nghia co ngat RB
#bit RBIE=intcon.3 //dinh nghia bit cho phep ngat RB
int led=0,speed;
// Chuong trinh ngat
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
//Kiem tra sw1
{
if(RB4==0)
{
led=0b00000001; //led1 sang
speed=250;
}
}
//Kiem tra sw2
{
if(RB5==0)
{
led=0b00000011; //led1,2 sang
speed=200;
}
}
//Kiem tra sw3
{
if(RB6==0)
{
led=0b00000111; //led1,2,3 sang
speed=150;
}
}
//Kiem tra sw4
{
if(RB7==0)
{
led=0b00001111; //led1,2,3,4 sang
speed=100;
}
}
RBIF=0; //Xoa co ngat RB
}
}
// Chuong trinh chinh
main()
{
set_tris_b(0b11110000);
portb=0b00001111;
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
while(true)
{
portb=led;
delay_ms(speed);
portb=0;
delay_ms(speed);
}
}

Không như trong MPLAB, đã định nghĩa sẵng các thanh ghi và bit tương ứng, còn CCS C chỉ định nghĩa chân PIC, những thanh ghi, những bit mà CCS C cho là cần thiết, ta xem trong file PIC16F887A.h, thanh ghi, bit nào chưa định nghĩa mà muốn sử dụng thì phải định nghĩa nó.
Ta có thể viết riêng 1 file.h loại này sao cho mình dễ nhớ nhất, đến khi muốn sử dụng chỉ cần khai báo #include<file.h> vào là xài thôi!

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

nhh
13-04-2006, 01:27 PM
Mạch quét 16 phím, hiện kết quả lên led 7 đoạn.
//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#use fast_io(c)
#byte portb = 0x06
#byte portc = 0x07
#bit RB0 = 0x06.0
#bit RB1 = 0x06.1
#bit RB2 = 0x06.2
#bit RB3 = 0x06.3
#bit RB4 = 0x06.4
#bit RB5 = 0x06.5
#bit RB6 = 0x06.6
#bit RB7 = 0x06.7
#bit RBIF=intcon.0 //dinh nghia co ngat RB
#bit RBIE=intcon.3 //dinh nghia bit cho phep ngat RB
int a;
const unsigned char dig[]={0b00111111,0b00000110, 0b01011011,0b01001111,\
0b01100110,0b01101101,0b01111101,0b00000111,0b0111 1111,0b01101111,0b01110111,\
0b01111100,0b00111001,0b01011110,0b11111001,0b1111 0001};
// ma hoa digital duoi dang mang
// Chuong trinh ngat
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
{
if(RB4&&RB0)
a=dig[0];
}
{
if(RB4&&RB1)
a=dig[4];
}
{
if(RB4&&RB2)
a=dig[8];
}
{
if(RB4&&RB3)
a=dig[12];
}
//.......
{
if(RB5&&RB0)
a=dig[1];
}
{
if(RB5&&RB1)
a=dig[5];
}
{
if(RB5&&RB2)
a=dig[9];
}
{
if(RB5&&RB3)
a=dig[13];
}
//........
{
if(RB6&&RB0)
a=dig[2];
}
{
if(RB6&&RB1)
a=dig[6];
}
{
if(RB6&&RB2)
a=dig[10];
}
{
if(RB6&&RB3)
a=dig[14];
}
//........
{
if(RB7&&RB0)
a=dig[3];
}
{
if(RB7&&RB1)
a=dig[7];
}
{
if(RB7&&RB2)
a=dig[11];
}
{
if(RB7&&RB3)
a=dig[15];
}
RBIF=0; //Xoa co ngat RB
}
}
// Chuong trinh chinh
main()
{
set_tris_b(0b11110000);
set_tris_c(0);
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
portb=0;
portc=0;
while(true)
{
portb=1;
portb=2;
portb=4;
portb=8;
portc=a;
}
}


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

falleaf
13-04-2006, 05:06 PM
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=4000000)

Bạn chú ý, clock = 4MHz là chế đọ dao động XT chứ không phải HS.

Chúc vui

ncv
20-04-2006, 02:01 PM
Một phương án khác:

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

void main() {
byte leds = 0xff;
set_tris_b(0x00); // configure pins of PORTB as output
while (true) {
output_b(leds);
leds = ~leds; // toggle leds
delay_ms(1000);
}
}

Ăc..ặc..đang post thì bị cúp điện,bực cả mình...:mad:

Và đây là câu trả lời cho việc delay led ở portB 1s


#include<16F877A.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=10000000)
#use fast_io(b)
#byte portb=0x6
main()
{
set_tris_b(0);
while(true)
{
portb=255; //all led on
delay_ms(1000);
portb=0; //all led off
delay_ms(1000);
}
}

ncv
20-04-2006, 03:34 PM
Một cách viết khác để tham khảo:

#include <16F877A.h>
#fuses HS, NOWDT, NOPROTECT, NOLVP
#device 16F877*=16, ADC=8
#use delay(clock=4000000)

void main() {
setup_adc(adc_clock_internal);
setup_adc_ports(ALL_ANALOG);
set_adc_channel(0); // TM Board: VR3=0, VR2=1, VR1=2
delay_ms(10);
while (true)
output_b(read_adc());
}

[QUOTE=nhh]Đây là 1 ví dụ nhỏ về ADC,chân RA0 lấy tín hiệu Analog từ biến trở và xuất giá trị số biến đổi tương ứng qua tám led nối ở portB
#include <16F877.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#device 16F877*=16 ADC=8
#use delay(clock=10000000)
Int8 adc;
main()
{
setup_adc(adc_clock_internal);
setup_adc_ports(AN0);
set_adc_channel(0);
delay_ms(10);
while(true)
{
adc=read_adc();
output_B(adc);
}
}

idiot
20-04-2006, 03:47 PM
xin lỗi các huynh cho tiểu đẹ hỏi 1 câu ngu dốt...các huynh có tài liệu asem về pic không?cho em 1 bản
rất cám ơn
idiot0910@yahoo.com

ncv
20-04-2006, 05:10 PM
Một cách viết khác để tham khảo với hy vọng viết C sao cho dễ hiểu :-)

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

#define INITIAL_VALUE 6

byte count;
byte led;

void change_led(void);

#int_timer0
void interrupt_timer0() {
set_timer0(INITIAL_VALUE);
count++;
if (count == 2000) {
count = 0;
change_led();
}
}

void main() {
set_tris_b(0);
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER0);
setup_timer_0(RTCC_INTERNAL | RTCC_DIV_2); // set mod
set_timer0(INITIAL_VALUE); // set initial value

count = 0;
led = 1;
while (true)
output_b(led);
}

void change_led() {
led = led << 1;
if (led == 0)
led = 1;
}

Đây là chương trình dùng ngắt Timer0 định thì 1s.
Đầu tiên led ở chân RB0 sáng, sau 1s sẽ dịch sang trái, nghĩa là led 1 trên chân RB1 sáng , lần lượt như vậy cho các led trên portB và lặp lại mãi mãi.
//************************************************** **
// 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
}
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);
set_timer0(6);
count=0;
a=1;
while(true)
{
portb=a;
}
}

namqn
20-04-2006, 07:54 PM
xin lỗi các huynh cho tiểu đẹ hỏi 1 câu ngu dốt...các huynh có tài liệu asem về pic không?cho em 1 bản
rất cám ơn
idiot0910@yahoo.com
Nhìn cái nick thì hiểu rồi, :) . Nói đùa chút thôi!
Nếu bạn cần tài liệu về hợp ngữ cho PIC16 thì download tài liệu này:

http://ww1.microchip.com/downloads/en/DeviceDoc/33014J.pdf

Thân,

linhnc308
26-04-2006, 03:12 AM
Sử dụng CCS cho việc lập trình PIC là rất hay và tiện lợi.Truoc day ban noisepic có đề cập cách lập trình cho ccs khá hay. Ta sẽ khai báo thêm một file định nghĩa các thanh ghi của pic kiểu như :
#byte PORTA =0x05
#byte PORTB =0x06
#byte PORTC =0x07
#byte PORTD =0x08
#byte PORTE =0x09
...
#byte EEDATA =0x10C
#byte EEADR =0x10D
#byte EEDATH =0x10E
#byte EEADRH =0x10F
#byte ADCON0 =0x1F
#byte ADCON1 =0x9F
#byte ADRESH =0x9F
#byte ADSESL =0x9F

sau đó ta có thể sử dụng lệnh gán PortB = 0x00 để xuất sẽ tiện hơn nhiều. Mình lập trình cho CCS đều dùng kiểu này. Khi đó ta sẽ vừa tận dụng được các hàm có sẵn của CCS vừa thao tác trực tiếp các thanh ghi như bên ASM.
Mình có viết một cái TUT về CCS này và đã gửi cho a F. Hy vọng sẽ sớm pót lên cho mọi người tham khảo.
Chúc thành công với CCS

linhnc308
26-04-2006, 03:23 AM
1. Tổng quan về CCS
1.1. Vì sao ta sử dung CCS ?
Sự ra đời của một loại vi điều khiển đi kèm với việc phát triển phần mềm ứng dụng cho việc lập trình cho con vi điều khiển đó. Vi điều khiển chỉ hiểu và làm việc với hai con số 0 và 1. Ban đầu để việc lập trình cho VĐK là làm việc với dãy các con số 0 và 1. Sau này khi kiến trúc của Vi điều khiển ngày càng phức tạp, số luợng thanh ghi lệnh nhiều lên, việc lập trình với dãy các số 0 và 1 không còn phù hợp nữa, đòi hỏi ra đời một ngôn ngữ mới thay thế. Và ngôn ngữ lập trình Assembly. Ở đây ta không nói nhiều đến Assmebly. Sau này khi ngôn ngữ C ra đời, nhu cầu dùng ngôn ngữ C đề thay cho ASM trong việc mô tả các lệnh lập trình cho Vi điều khiển một cách ngắn gọn và dễ hiểu hơn đã dẫn đến sự ra đời của nhiều chương trình soạn thảo và biên dịch C cho Vi điều khiển : Keil C, HT-PIC, MikroC, CCS…
Tôi chọn CCS cho bài giới thiệu này vì CCS là một công cụ lập trình C mạnh cho Vi điều khiển PIC. Những ưu và nhược điểm của CCS sẽ được đề cập đến trong các phần dưới đây.

1.2. Giới thiệu về CCS ?
CCS là trình biên dịch lập trình ngôn ngữ C cho Vi điều khiển PIC của hãng Microchip. Chương trình là sự tích hợp của 3 trình biên dich riêng biết cho 3 dòng PIC khác nhau đó là:
- PCB cho dòng PIC 12-bit opcodes
- PCM cho dòng PIC 14-bit opcodes
- PCH cho dòng PIC 16 và 18-bit
Tất cả 3 trình biên dich này đuợc tích hợp lại vào trong một chương trình bao gồm cả trình soạn thảo và biên dịch là CCS, phiên bản mới nhất là PCWH Compiler Ver 3.227

Giống như nhiều trình biên dich C khác cho PIC, CCS giúp cho người sử dụng nắm bắt nhanh được vi điều khiển PIC và sử dụng PIC trong các dự án. Các chương trình diều khiển sẽ được thực hiện nhanh chóng và đạt hiệu quả cao thông qua việc sử dụng ngôn ngữ lạp trình cấp cao – Ngôn ngữ C

Tài liệu hướng dẫn sử dụng có rất nhiều, nhưng chi tiết nhất chính là bản Help đi kèm theo phần mềm (tài liệu Tiếng Anh). Trong bản trợ giúp nhà sản xuất đã mô tả rất nhiều về hằng, biến, chỉ thị tiền xủa lý, cấu trúc các câu lệnh trong chương trình, các hàm tạo sẵn cho người sử dụng… Ngoài ra về Tiếng Việt cũng có bản dịch của tác giả Trần Xuân Trường, SV K2001 DH BK HCM. Tài liệu này dịch trên cơ sở bản Help của CCS, tuy rằng chưa đầy đủ nhưng đây là một tài liệu hay, nếu bạn tìm hiểu về PIC và CCS thì nên tìm tài liệu này về đọc. Địa chỉ Download tài liệu: www.picvietnam.com -> Mục nói về CCS.

linhnc308
26-04-2006, 03:26 AM
3. Một số ví dụ cho lập trình CCS
Với mục tiêu giúp người đọc nhanh chóng lắm bắt được cách lập trình C cho PIC thông qua chương trình dịch CCS. Dưới đây tôi giới thiệu một vài bài lập trình đơn giản cho PIC, các bài mẫu này dựa theo tài liệu tutorial của Nigel như quét LED, LED 7 thanh, LCD, bàn phím…, cách dùng các giao tiếp của PIC để giao tiếp với thiết bị ngoại vi như Real Time IC, ADC, EEPROM…
· Yêu cầu về phần cứng tối thiểu cần có để thực hành:
- PIC16F877A ( hoặc 16F876A hay 16F88) = 50K (Tốt nhất là PIC16F877A)
- 1 Board cắm linh kiện (tối thiểu ) = 40K
- Thạch anh 20MHz, tụ 22pF, 10uF, trở 10K, 4K7, 330Ω, nút bấm = 10K
- 10 LED đơn xanh hay đỏ, 4 LED 7 thanh (loại 4 LED liền một đế ) = 15K
- MAX232 để giao tiếp máy tính () = 10K
Tổng cộng là: 125K
· Phần cứng mở rộng
- LCD 1602A loại 2 dòng 16 ký tự (Nếu có LCD 2002 càng tốt) = 65K (Minh Hà có bán)
- Real Time IC DS1307 hay DS1337 = 25K (có thể xin sample của Maxim-IC)
- EEPROM AT24Cxx
- ADC/DAC IC loại 12-bit trở nên (ADC 10-bit thì PIC cũng có)
- Sensor nhiêt LM335 hay LM35 = 13K
- Động cơ bước, động cơ một chiều

Mục đích chính của tôi trong việc giới thiệu các ví dụ dưới đây là nhằm giúp mọi người nhanh chóng nắm được kỹ thuật lập trình bằng CCS, thông qua các ví dụ mọi người sẽ hiểu các hàm của CCS, cách sử dụng trong từng ứng dụng cụ thể. Về chi tiết của mỗi hàm tôi sẽ không trình bày kỹ tại đây, để biết rõ ta có thể xem trong phần Trợ giúp của CCS hay tài liệu của tác giả Trần Xuân Trường, trong đó đã nói khá đầy đủ. Tôi nhấn mạnh một điều khi mọi người tìm hiểu về PIC và CCS đó là hãy tự mình tìm hiểu là chính, từ việc nghiên cứu tài liệu, tìm tài liệu cho đền thiết kế mạch và viết chương trình. Những gì tại đây chỉ là cơ bản, còn việc phát triển, sử dụng hết điểm mạnh của PIC và CCS là ở phía mọi người. Chúc thành công!

Một điều chú ý là tất cả các mạch điện và code tôi trình bày dưới đây tôi đều đã lắp mạch thật trên bo cắm và chạy tốt.

linhnc308
26-04-2006, 03:50 AM
3. Một số ví dụ cho lập trình CCS
Với mục tiêu giúp người đọc nhanh chóng lắm bắt được cách lập trình C cho PIC thông qua chương trình dịch CCS. Dưới đây tôi giới thiệu một vài bài lập trình đơn giản cho PIC, các bài mẫu này dựa theo tài liệu tutorial của Nigel như quét LED, LED 7 thanh, LCD, bàn phím…, cách dùng các giao tiếp của PIC để giao tiếp với thiết bị ngoại vi như Real Time IC, ADC, EEPROM…
· Yêu cầu về phần cứng tối thiểu cần có để thực hành:
- PIC16F877A ( hoặc 16F876A hay 16F88) = 50K (Tốt nhất là PIC16F877A)
- 1 Board cắm linh kiện (tối thiểu ) = 40K
- Thạch anh 20MHz, tụ 22pF, 10uF, trở 10K, 4K7, 330Ω, nút bấm = 10K
- 10 LED đơn xanh hay đỏ, 4 LED 7 thanh (loại 4 LED liền một đế ) = 15K
- MAX232 để giao tiếp máy tính () = 10K
Tổng cộng là: 125K
· Phần cứng mở rộng
- LCD 1602A loại 2 dòng 16 ký tự (Nếu có LCD 2002 càng tốt) = 65K (Minh Hà có bán)
- Real Time IC DS1307 hay DS1337 = 25K (có thể xin sample của Maxim-IC)
- EEPROM AT24Cxx
- ADC/DAC IC loại 12-bit trở nên (ADC 10-bit thì PIC cũng có)
- Sensor nhiêt LM335 hay LM35 = 13K
- Động cơ bước, động cơ một chiều

Mục đích chính của tôi trong việc giới thiệu các ví dụ dưới đây là nhằm giúp mọi người nhanh chóng nắm được kỹ thuật lập trình bằng CCS, thông qua các ví dụ mọi người sẽ hiểu các hàm của CCS, cách sử dụng trong từng ứng dụng cụ thể. Về chi tiết của mỗi hàm tôi sẽ không trình bày kỹ tại đây, để biết rõ ta có thể xem trong phần Trợ giúp của CCS hay tài liệu của tác giả Trần Xuân Trường, trong đó đã nói khá đầy đủ. Tôi nhấn mạnh một điều khi mọi người tìm hiểu về PIC và CCS đó là hãy tự mình tìm hiểu là chính, từ việc nghiên cứu tài liệu, tìm tài liệu cho đền thiết kế mạch và viết chương trình. Những gì tại đây chỉ là cơ bản, còn việc phát triển, sử dụng hết điểm mạnh của PIC và CCS là ở phía mọi người. Chúc thành công!

Một điều chú ý là tất cả các mạch điện và code tôi trình bày dưới đây tôi đều đã lắp mạch thật trên bo cắm và chạy tốt.

linhnc308
26-04-2006, 03:59 AM
Trích từ báo cáo về CCS.

minhpic
26-04-2006, 12:38 PM
Đúng là mọi người không chịu vào hết các trang mà mình quan tâm, địa chỉ các thanh ghi cũng như các thứ khác các bạn lấy ở đây.

minhpic
26-04-2006, 12:50 PM
Mình xem qua các chương trình cậu viết ở trên đều không sai nhưng chưa tối ưu, các cậu cứ xem phần chương trình bên asm thì rõ, vấn đề này cũng đã được thảo luận rất nhiều rồi mà. Các file mình đưa ra xẽ giúp chúng ta hỗ trợ thêm cách lập trình bằng C, và đến một lúc nào đó nếu các bạn đã thông tư tưởng của mình thì, lúc đấy viết trên HTpic hay CCs đều không khác nhau.

vnt3140
28-04-2006, 10:45 PM
Gửi nhh:
Bài : Giải mã bàn phím
Mạch quét 16 phím, hiện kết quả lên led 7 đoạn.
Trong chuong trinh thieu dinh nghia
#byte intcon=0x000B
và port xuất ra led 7 đoạn là PORTC không phải portd như hình vẽ.

nhh
29-04-2006, 10:22 AM
To vnt3140

Đúng là trong đó hình vẽ và chương trình có nhầm portc và portd, do khi chạy proteus và mạch thật thiết lập port ok nhưng khi vẽ ORCAD bị nhầm.
Các bạn chỉ thay đổi chút xíu thôi mà!

Còn chưa định nghĩa byte intcon, sao bạn chỉ phát hiện ra nó, còn các bít RBx nữa thì sao.....Nhưng tất cả đã được định nghĩa trong file defs_16F877A.h.Mình nhớ đã gởi file này lên rồi nhưng bây giờ tìm lại không thấy đâu cả.Pó tay luôn ! Dạo này sao lú lẫn quá!Mình sẽ gởi lên sau!
:D

hpecom
29-04-2006, 03:01 PM
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.
//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#use fast_io(d)
#byte portb=0x06
#byte portd=0x08
const unsigned char digital[]={0b00000110, 0b01011011, 0b01001111, 0b01100110,\
0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111};
// ma hoa digital duoi dang mang
// Chuong trinh ngat
#int_ext
void ngat_RB0()
{
int i;
if(i<9)
{
portd=digital[i];
++i;
}
if(i==9)
{
i=0;
}
}
// 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 !
}
}
http://www.freewebtown.com/nhhao/PIC/dem1_9dungngatngoai.gif
Theo tại hạ, hàm ngắt trên có vấn đề. Ở chỗ khai báo biến i. Biến i là biến cục bộ của hàm ngắt, vậy khi ra khỏi ngắt biến i sẽ bị mất khỏi bộ nhớ tức không được cấp phát ô nhớ. Lần sau ngắt xảy ra thì biến i này sẽ được khai báo lại. Tóm lại vần đề là tầm khai báo biến.
Bác nên khai báo biến i là biến toàn cục thì mới có khả năng đếm số lần ngắt.
Chúc khỏe.
hpecom.

hpecom
29-04-2006, 03:27 PM
Mạch quét 16 phím, hiện kết quả lên led 7 đoạn.
//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#use fast_io(c)
#byte portb = 0x06
#byte portc = 0x07
#bit RB0 = 0x06.0
#bit RB1 = 0x06.1
#bit RB2 = 0x06.2
#bit RB3 = 0x06.3
#bit RB4 = 0x06.4
#bit RB5 = 0x06.5
#bit RB6 = 0x06.6
#bit RB7 = 0x06.7
#bit RBIF=intcon.0 //dinh nghia co ngat RB
#bit RBIE=intcon.3 //dinh nghia bit cho phep ngat RB
int a;
const unsigned char dig[]={0b00111111,0b00000110, 0b01011011,0b01001111,\
0b01100110,0b01101101,0b01111101,0b00000111,0b0111 1111,0b01101111,0b01110111,\
0b01111100,0b00111001,0b01011110,0b11111001,0b1111 0001};
// ma hoa digital duoi dang mang
// Chuong trinh ngat
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
{
if(RB4&&RB0)
a=dig[0];
}
{
if(RB4&&RB1)
a=dig[4];
}
{
if(RB4&&RB2)
a=dig[8];
}
{
if(RB4&&RB3)
a=dig[12];
}
//.......
{
if(RB5&&RB0)
a=dig[1];
}
{
if(RB5&&RB1)
a=dig[5];
}
{
if(RB5&&RB2)
a=dig[9];
}
{
if(RB5&&RB3)
a=dig[13];
}
//........
{
if(RB6&&RB0)
a=dig[2];
}
{
if(RB6&&RB1)
a=dig[6];
}
{
if(RB6&&RB2)
a=dig[10];
}
{
if(RB6&&RB3)
a=dig[14];
}
//........
{
if(RB7&&RB0)
a=dig[3];
}
{
if(RB7&&RB1)
a=dig[7];
}
{
if(RB7&&RB2)
a=dig[11];
}
{
if(RB7&&RB3)
a=dig[15];
}
RBIF=0; //Xoa co ngat RB
}
}
// Chuong trinh chinh
main()
{
set_tris_b(0b11110000);
set_tris_c(0);
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
portb=0;
portc=0;
while(true)
{
portb=1;
portb=2;
portb=4;
portb=8;
portc=a;
}
}


http://www.freewebtown.com/nhhao/PIC/Giaimabanphim.gif
Bác nên treo các chân lên nguồn và quét mức thấp vì nếu bác bỏ hở chân như thế thì có khả năng nhiễu làm cho chương trình mất ổn định.
Chúc sức khỏe.
hpecom.

tuan2007
29-04-2006, 07:06 PM
minh dang lam ve de tai dieu khien ma tran led
da co ai nghien cuu ve van de nay chua
neu co tai lieu thi gui cho minh voi
cam on nhe

nhh
02-05-2006, 08:07 PM
Gửi nhh:
Bài : Giải mã bàn phím
Mạch quét 16 phím, hiện kết quả lên led 7 đoạn.
Trong chuong trinh thieu dinh nghia
#byte intcon=0x000B
và port xuất ra led 7 đoạn là PORTC không phải portd như hình vẽ.

Thật ra thì không thiếu định nghĩa này đâu bạn, mình đã định nghĩa các bit cần dùng của nó trong chương trình rồi.

Để cho việc viết chương trình được thuận lợi hơn, những lần sau nên include cái file DEFS_16F877A.h vào để không phải khai báo dài dòng nữa !

ncv
05-05-2006, 09:38 AM
Chương trình gửi ký tự ra 2x16 LCD dùng CCS C

#include "16F877A.h" // PIC16F877A header file
#use delay(clock=4000000) // for 4Mhz crystal
#fuses XT, NOWDT, NOPROTECT, NOLVP // for debug mode

#define WRITE_DATA 0
#define WRITE_COMMAND 1

#define NCHAR_PER_LINE 16 // max char numbers per line
#define MS10 10 // 10 milliseconds
#define US400 400 // 400 microseconds

#define LCD_RS PIN_A1
#define LCD_RW PIN_A2
#define LCD_E PIN_A3

///////////////////////////////////////////////////////////
//
/* private */ void lcd_write(byte dat, int1 option) {
delay_us(US400);
if (option == WRITE_DATA)
output_high(LCD_RS);
else // option == WRITE_COMMAND
output_low(LCD_RS);
output_low(LCD_RW);
output_b(dat);

output_high(LCD_E);
delay_us(US400);
output_low(LCD_E);
}

///////////////////////////////////////////////////////////
//
void lcd_init(void) {
output_low(LCD_E); // Let LCD E line low

lcd_write(0x38, WRITE_COMMAND); // Set LCD 16x2, 5x7, 8bits data
delay_ms(15);
lcd_write(0x01, WRITE_COMMAND); // Clear LCD display
delay_ms(MS10);
lcd_write(0x0f, WRITE_COMMAND); // Open display & current
delay_ms(MS10);
lcd_write(0x06, WRITE_COMMAND); // Window fixed (Character Entry Mode?)
delay_ms(MS10);
}

///////////////////////////////////////////////////////////
//
void lcd_display_char(int8 line, int8 pos, char ch) {
line = (line == 0) ? 0 : 1;
pos = (pos > NCHAR_PER_LINE) ? NCHAR_PER_LINE : pos;

lcd_write(0x80 + 0x40 * line + pos, WRITE_COMMAND);
lcd_write(ch, WRITE_DATA);
}

///////////////////////////////////////////////////////////
void lcd_display_str(int8 line, char str[], int8 nchars) {
int8 i;
for (i = 0; i < nchars; i++)
lcd_display_char(line, i, str[i]);
}

///////////////////////////////////////////////////////////
/**
* Display characters to a 2x16 LCD
*
* (1) LCD1 to GND
* (2) LCD2 to VDD 5 volts
* (3) LCD4 (RS) - LCD5 (RW) - LCD6 (E) to A1, A2, A3
* (4) LCD7-LCD14 to B0-B7 (bus data)
*
* Ref: http://pic16.com/bbs/dispbbs.asp?boardID=23&ID=5879&page=1
*/
void main(void) {
int8 i;
char LINE1[] = { "SGN Tech" };
char LINE2[] = { "Xin chao" };

lcd_init();

// use of lcd_display_char()
for (i = 0; i < 8; i++)
lcd_display_char(0, i, LINE1[i]);

// use of lcd_display_str
lcd_display_str(1, LINE2, 8);
}

ncv
05-05-2006, 11:48 AM
CCS C có một ví dụ hay hơn: Chỉ cần dùng 4 bits D4-D7 của LCD:

Examples\EX_LCDKB.C

Chương trình gửi ký tự ra 2x16 LCD dùng CCS C

#include "16F877A.h" // PIC16F877A header file
#use delay(clock=4000000) // for 4Mhz crystal
#fuses XT, NOWDT, NOPROTECT, NOLVP // for debug mode
...
}

ncv
06-05-2006, 10:28 AM
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/english/product/books/picbasicbook/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
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);
}

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.
//************************************************** ***************************
// 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ố 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ố 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
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ự.

http://i82.photobucket.com/albums/j257/nhhao/lcd216.jpg

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

1.Các chân VCC, VSS và VEE: 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
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:

http://i82.photobucket.com/albums/j257/nhhao/lcd.jpg
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
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
/*Để 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
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.
/*-----------------------------------------------------------------------------
* 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
http://i82.photobucket.com/albums/j257/nhhao/pvn.gif
Thêm một ví dụ khác, chương trình hiển thị dòng "HELLO PICVIETNAM!".
/*-----------------------------------------------------------------------------
* 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
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

/*-----------------------------------------------------------------------------
* 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
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.
/*-----------------------------------------------------------------------------
* 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
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
CCSC hỗ trợ LCD graphic cũng rất tốt,


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

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.

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

/*-----------------------------------------------------------------------------
* 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
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
cảm ơn anh hpecom đã chỉ giáo :D

boys3509_2006
13-08-2006, 03:48 PM
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
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 ?

bigtitan
19-08-2006, 09:17 PM
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:



Sao em thấy cái PICsimlator này nó tét ra kết quả lâu quá.ngồi đợi nó chạy ra hàng chữ HELLO muốn....tắt mày cho rồi.Mặc dù thiết lập mức độ chạy hết công suất(Ctrl+F5 thì phải) nhưng ó vẫn rề quá.Hay là còn chỗ nào nữa.Các bác chỉ giúp.

namqn
20-08-2006, 01:12 AM
Sao em thấy cái PICsimlator này nó tét ra kết quả lâu quá.ngồi đợi nó chạy ra hàng chữ HELLO muốn....tắt mày cho rồi.Mặc dù thiết lập mức độ chạy hết công suất(Ctrl+F5 thì phải) nhưng ó vẫn rề quá.Hay là còn chỗ nào nữa.Các bác chỉ giúp.
Lại nữa rồi, PIC Simulator để kiểm tra logic của chương trình, chứ không phải để thử xem máy tính của bạn chạy nhanh đến mức nào. Bạn vào đọc thêm trong luồng sau:
http://www.picvietnam.com/forum/showthread.php?t=330

Thân,

vtt
20-08-2006, 12:34 PM
Chào bác nhh!
Tôi copy nguyen bai delay1s_RB0 của bác về nạp thử, nhưng không hiểu sao nó không chạy, mà phải cắm chân RB3 (chân PGM) xuống đất thì nó mới chạy, bác có thể cho tôi biết tại sao không?
Cám ơn bác!

namqn
20-08-2006, 06:59 PM
Chào bác nhh!
Tôi copy nguyen bai delay1s_RB0 của bác về nạp thử, nhưng không hiểu sao nó không chạy, mà phải cắm chân RB3 (chân PGM) xuống đất thì nó mới chạy, bác có thể cho tôi biết tại sao không?
Cám ơn bác!
Ở một số chip, chân RB3 còn là chân PGM dùng để cấp nguồn cho chế độ nạp chip điện áp thấp (Low-Voltage Programming). Nếu chip của bạn còn mới, có thể nó đang được bật chế độ LVP (mặc định khi xuất xưởng), do đó bạn để hở RB3 sẽ không cho phép chip chạy chương trình, và bạn phải nối RB3 xuống 0V (nên nối qua một điện trở khoảng 1k) thì chip mới không đi vào chế độ LVP và mới chạy được chương trình đã có trong chip.

Thân,

hpecom
21-08-2006, 05:07 PM
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 ?

*Dấu :confused: thứ nhất:

a=a<<1; // dich trai a 1bit

Như tác giả đã chú thích đó là lệnh dịch trái 1 bit.
VD: trước khi dịch, a có giá trị 0 0 0 0 0 0 0 1 (0x01) thì sau lệnh dịch này giá trị biến a sẽ là 0 0 0 0 0 0 1 0 (0x02).
Vậy lệnh dịch trái sẽ làm tăng giá trị biến bị dịch lên 2 lần: 2 thành 4. Giống như bạn dịch trong hệ thập phân số 0500 thì được 5000 tức tăng 10 lần. Hệ nhị phân (2 số) dịch trái 1 bit sẽ tăng giá trị 2 lần, hệ thập phân (10 số) dịch trái một bit, số sẽ tăng giá trị 10 lần.
Vậy nhiều lệnh dịch sẽ làm cho a thay đổi như sau
0 0 0 0 0 1 0 0
0 0 0 0 1 0 0 0
0 0 0 1 0 0 0 0
0 0 1 0 0 0 0 0
0 1 0 0 0 0 0 0
1 0 0 0 0 0 0 0
* Dấu :confused: thứ 2:

setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2);

mode may be one or two of the constants defined in the devices .h file. RTCC_INTERNAL, RTCC_EXT_L_TO_H or RTCC_EXT_H_TO_L

RTCC_DIV_2, RTCC_DIV_4, RTCC_DIV_8, RTCC_DIV_16, RTCC_DIV_32, RTCC_DIV_64, RTCC_DIV_128, RTCC_DIV_256
Bạn hãy đọc Help và các ví dụ của nó thì bạn sẽ hiểu được cách tính.
Bạn hãy tìm hiều kỹ về bộ chia tần trong DataSheet của chip sẽ hiểu tại sao chỉ làm 2 mũ n.
* Dấu :confused: thứ 3:

portb=a;

Đây là lệnh xuất giá trị biến a ra PortB. a có 8 bit, PortB có 8 chân B7 đến B0.
Lệnh trên sẽ áp các bit của a vào PortB theo đúng trọng số.
Chúc bạn thành công. (và lần sau hỏi dễ xíu:D ).
hpecom.

lep
21-08-2006, 08:42 PM
làm thế naò để vi điêù khiển pic16f877a nhận biết số vong quay cuả motor động cợ? khi khởi động output chân BO cho mức cao high motor động cợ 1 quay 20 vong phát ra 20 xung vuông đến input chân D0 ,chan D0 nhan 20 xung xu li cho ra chan output BO muc thap low motor dong co thu 1 ngung quay va output B1 cao high motor dong co thu 2 quay 10 vong tao ra 10 xung vuong den chan D1 chan D1 nhan 10 xung thi B1 low dong co motor2 dung va B0 high dong co motor 1 quay va nguoc lai
Cho minh hoi cach lam mach dem vong quay motor dong co?xin cac huynh cho luon so do mach nay?va can mua nhung linh kien gi về ráp mạch?
Va xin cac huynh chi cho cach viet chay chuong trinh nay dung ngon ngu C _CCS_C
tan so 20Mhz
pic 16f877a

vtt
21-08-2006, 11:08 PM
Cảm ơn ngài trưởng lão Pic bang!
Bây giờ thì tôi đã hiểu, nhưng khi phải nối mass chân RB3 rồi thì coi như chân đó không thể dùng được nữa hả?

namqn
21-08-2006, 11:18 PM
Cảm ơn ngài trưởng lão Pic bang!
Bây giờ thì tôi đã hiểu, nhưng khi phải nối mass chân RB3 rồi thì coi như chân đó không thể dùng được nữa hả?
Bạn vẫn có thể dùng chân RB3 như bình thường khi chip đã ở chế độ chạy chương trình bình thường. Nhưng nếu bạn nối thẳng RB3 vào mức 0V và sau đó dùng RB3 như ngõ ra, thì khi bạn xuất mức cao ra RB3 sẽ gây ngắn mạch giữa các chân Vdd và Vss (vì bạn đã nối thẳng RB3 vào Vss, và sau đó lại yêu cầu ngõ ra RB3 được nối lên Vdd trong chương trình). Đó chính là lý do của lời khuyên nên nối RB3 xuống mức 0V thông qua một điện trở khoảng 1k, nếu bạn muốn RB3 khi dùng như ngõ ra được nhẹ tải hơn thì có thể dùng giá trị 4.7k hay 10k cho điện trở kéo xuống 0V đó.

Thân,

minhquancdt
23-08-2006, 09:48 AM
Luồng này sôi động gớm ta!
Sao không thấy bác nhh post bài nữa kà!
Anh em nào rảnh rỗi post tiếp cho bà con hào tham gia với....!:D

Sangcao
23-08-2006, 02:30 PM
Mình đang thử ctr điều khiển động cơ: Khi có tín hiệu từ chân RB0 thì động cỏ quay, nếu đang quay mà có tín hiệu từ RB1 thì động cơ quay ngược lại bằng thời gian no đã quay xuôi, bạn nào có thể viết cho mình một ví dụ như vậy bằng CCS được ko, cảm ơn nhiều.

vtt
24-08-2006, 09:19 PM
Cám ơn bác namqn!
Các bác ơi, tôi đang loay hoay với việc giao tiếp giữa PIC 16F877A với eeprom 24C64 mà chưa được, bác nào đã làm được hoạc có kinh nghiệm giao tiếp với bộ nhớ ngoài xin chỉ giùm.

namqn
24-08-2006, 10:03 PM
Bạn đọc tài liệu sau của Microchip về giao tiếp PIC16 với I2C EEPROM:
http://ww1.microchip.com/downloads/en/DeviceDoc/i2c.pdf

Thân,

nhh
26-08-2006, 10:00 PM
Mình đang thử ctr điều khiển động cơ: Khi có tín hiệu từ chân RB0 thì động cỏ quay, nếu đang quay mà có tín hiệu từ RB1 thì động cơ quay ngược lại bằng thời gian no đã quay xuôi, bạn nào có thể viết cho mình một ví dụ như vậy bằng CCS được ko, cảm ơn nhiều.

Bạn có thể dùng ngắt ngoài để điều khiển cái động cơ của bạn:
http://www.picvietnam.com/forum//showthread.php?t=357&page=2

son_um
04-10-2006, 01:38 AM
Đoạn mã hiển thị led 7 thanh này, dấu ^ có ý nghĩa là vì hả các bác
void display(int8 digit) {
output_c(DIGITS[digit] ^ 0xff);
off_on_led_transistor();
}
Thân.

minhquancdt
04-10-2006, 12:11 PM
Đoạn mã hiển thị led 7 thanh này, dấu ^ có ý nghĩa là vì hả các bác
void display(int8 digit) {
output_c(DIGITS[digit] ^ 0xff);
off_on_led_transistor();
}
Thân.

Ặc ặc...
Bác dùng mấy cái mảng + hàm con mà chẳng ai biết từ đâu ra thì ai mà hiểu được bác đang nghĩ gì !

Hãy post cả code hoàn thiện để mọi nguời cùng mổ xẻ !

son_um
04-10-2006, 10:10 PM
Thì đoạn chương trình đấy từ bài viết về hiển thị led7 thanh,post lại vậy:

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;
}

///////////////////////////////////////////////////////////
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);
}
}
}

namqn
04-10-2006, 10:31 PM
Đoạn mã hiển thị led 7 thanh này, dấu ^ có ý nghĩa là vì hả các bác
void display(int8 digit) {
output_c(DIGITS[digit] ^ 0xff);
off_on_led_transistor();
}
Thân.
Dấu "^" là ký hiệu phép toán XOR (exclusive OR) trong C.

Thân,

son_um
06-10-2006, 03:27 AM
Trong đoạn code về quét bàn phím, có lệnh sau e không hiếu,mong được các bác giải thích: IF((RBIF)&&(RBIE)....

#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
{
if(RB4&&RB0)
a=dig[0];
}
{
if(RB4&&RB1)
a=dig[4];
Thân.

nhh
06-10-2006, 05:40 PM
Trong đoạn code về quét bàn phím, có lệnh sau e không hiếu,mong được các bác giải thích: IF((RBIF)&&(RBIE)....

#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
{
if(RB4&&RB0)
a=dig[0];
}
{
if(RB4&&RB1)
a=dig[4];
Thân.
Phép toán && là phép and logic.Chắc là không phải giải thích về phép toán này.

phamvanthang
09-10-2006, 09:47 PM
Ban lam on cho biet cho tim may thu vien cua CCS C, vi du nhu lcd_lib_4bit.h hay def_877a.h. Cam on!

mp3pic
10-10-2006, 10:24 AM
cho biêt có sự khác nào giữa pic16f877-20p với 16f877a không

bantrang25
11-10-2006, 01:56 PM
Bác nào có chương trình mẫu viết cho ADC 16bit ngoài, và ctr viết cho Rom ngoài bằng CCS ko up lên cho anh em học với.Thêm nữa là chưa thấy bác namqn hướng dẫn về làm ctr Calibrate trong quá trình ghi vào Rom: Ví dụ như đo nhiệt độ bằng can nhiệt thì nên dung bảng calip để đo thực tế rồi ghi vào Rom hay hơn là dùng công thức . Mình nghĩ đây cũng là một vấn đề mọi người nên quan tâm, có ai đã làm rồi thì có thể hướng dẫn cho moi người nhé!

vdt
11-11-2006, 01:18 AM
cho biêt có sự khác nào giữa pic16f877-20p với 16f877a không

Bạn có thể tham khảo tài liệu sau http://ww1.microchip.com/downloads/en/DeviceDoc/39591a.pdf
Chúc vui

alamanda
04-12-2006, 11:20 AM
[QUOTE=nhh;2261]Còn đây là ứng dụng ngắt ngoài trên RB4 đến RB7 để thay đổi kiểu cũng như tốc độ chớp nháy mấy con led chỉ để....ngắm cho vui mắt !

Ấn sw1, led1 nhấp nháy với delay 250ms
Ấn sw2, led1,2 nhấp nháy với delay 200ms
Ấn sw3, led1,2,3 nhấp nháy với delay 150ms
Ấn sw4, led1,2,3,4 nhấp nháy với delay 100ms
[code]//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
Bác nhh ơi,tui đang đang dùng CCS C version 4.013 ( tui mới học PIC gần đây). Khi tui copy file của bác về chạy thử thì nó báo lỗi. Ở khai báo #byte portb=0x06, nó báo lỗi là Expecting an identifier và Expecting a declaration. Còn ở lệnh: portb=led;thì nó báo lỗi Expecting LVALUE such as a variable name or *expression. Cụ thể là bài của bác tui dịch ra là 8 lỗi. Tui pó tay:confused: .Rất mong sự chỉ giáo của bác,và các bậc tiền bối.

alamanda
04-12-2006, 01:26 PM
ha ha,tui gỡ version 4.013,và cài version 3.249,rồi dịch bài của bác nhh thì khg có lỗi nào cả.Pó tay.Có ai bít giải thích giùm.

tranhuyky
20-12-2006, 09:22 PM
Mạch quét 16 phím, hiện kết quả lên led 7 đoạn.
//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#use fast_io(c)
#byte portb = 0x06
#byte portc = 0x07
#bit RB0 = 0x06.0
#bit RB1 = 0x06.1
#bit RB2 = 0x06.2
#bit RB3 = 0x06.3
#bit RB4 = 0x06.4
#bit RB5 = 0x06.5
#bit RB6 = 0x06.6
#bit RB7 = 0x06.7
#bit RBIF=intcon.0 //dinh nghia co ngat RB
#bit RBIE=intcon.3 //dinh nghia bit cho phep ngat RB
int a;
const unsigned char dig[]={0b00111111,0b00000110, 0b01011011,0b01001111,\
0b01100110,0b01101101,0b01111101,0b00000111,0b0111 1111,0b01101111,0b01110111,\
0b01111100,0b00111001,0b01011110,0b11111001,0b1111 0001};
// ma hoa digital duoi dang mang
// Chuong trinh ngat
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
{
if(RB4&&RB0)
a=dig[0];
}
{
if(RB4&&RB1)
a=dig[4];
}
{
if(RB4&&RB2)
a=dig[8];
}
{
if(RB4&&RB3)
a=dig[12];
}
//.......
{
if(RB5&&RB0)
a=dig[1];
}
{
if(RB5&&RB1)
a=dig[5];
}
{
if(RB5&&RB2)
a=dig[9];
}
{
if(RB5&&RB3)
a=dig[13];
}
//........
{
if(RB6&&RB0)
a=dig[2];
}
{
if(RB6&&RB1)
a=dig[6];
}
{
if(RB6&&RB2)
a=dig[10];
}
{
if(RB6&&RB3)
a=dig[14];
}
//........
{
if(RB7&&RB0)
a=dig[3];
}
{
if(RB7&&RB1)
a=dig[7];
}
{
if(RB7&&RB2)
a=dig[11];
}
{
if(RB7&&RB3)
a=dig[15];
}
RBIF=0; //Xoa co ngat RB
}
}
// Chuong trinh chinh
main()
{
set_tris_b(0b11110000);
set_tris_c(0);
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
portb=0;
portc=0;
while(true)
{
portb=1;
portb=2;
portb=4;
portb=8;
portc=a;
}
}


http://www.freewebtown.com/nhhao/PIC/Giaimabanphim.gif
Chào bạn mình thay led 7 đoạn bằng LCD thì chương trình chạy không đúng, bạn có thể hướng dẫn cho mình dùng ngắt để giải mã phím xuất ra lcd được không, cám ơn bạn nhiều.

nhh
23-12-2006, 09:06 AM
LCD và led 7 đoạn tất nhiên là khác nhau rồi.

Để thực hiện tốt giải mã matrix phím, bác phải có giải pháp chống nhiễu (run phím) bằng phần cứng, hoặc phần mềm, thông thường là dùng phần mềm. Code bên trên chưa có chống nhiễu :D .Để khi nào tôi gởi code cho các bác !

LEO-XBS
24-12-2006, 05:03 PM
mình đang viết chương trình cho Robot bằng C nhưng khi chay thì có một số đoạn bị bỏ qua. Thỉnh thoảng thì lại chạy đúng. Các cao thủ về CCS C có thể giải thích giúp mình được ko?

minhpic
25-12-2006, 07:57 AM
bạn phải mói cụ thể hơn công việc của bạn cũng như chương trình thì mọi người mới có thể giúp đỡ chứ

LEO-XBS
01-01-2007, 02:07 PM
các bác xem thử một chương trình nhé. ở đây em chỉ viết các modul chương trình con thực hiện chức năng của robot còn chương trình chính thì sẽ gọi các chương trình con tùy theo mình muốn dùng chức năng nào của robot.
//************************************************** ************
/////////*FILENAME: CHUONG TRINH DIEU KHIEN ROBOT*//////////////
/////////*HARDWARE: PIC16F877 *//////////////
/////////*DATE: 19-Nov-06 09:40 *//////////////
/////////*CCS PCM C Compiler, Version 3.227 *//////////////
/////////*NGUOI THUC HIEN: LEO-XBS *//////////////
//************************************************** ************
#include <16F877A.h>
#include <DEFS_16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)
//****************************************
//////DINH NGHIA CAC CHAN VA CAC CONG/////
//****************************************
#define dc_trai1 rc1
#define dc_trai2 rb1
#define dc_phai1 rc2
#define dc_phai2 rb3
#define dc_nang1 rb4
#define dc_nang2 rb5
#define dc_day1 rb6
#define dc_day2 rb7
#define dc_kep1 rd0
#define dc_kep2 rd1
#define sw1 rc0
//*******************************************
///////KHAI BAO CAC HAM VA BIEN//////////////
//*******************************************
void setup();
void tien();
void lui();
void dung();
void dk_tien();
void sang_phai();
void sang_trai();
void quay_phai();
void quay_trai();
void dieu_khien();
int led_thu();
void nang();
void ha();
void kep();
void nha();
void day();
void thu();
void program1();
void program2();
int dem,led;
const unsigned char lech_phai[7]={0b00001000,0b00010000,0b00011000,0b00100000,0b00 101000,0b00110000,0b00111000};
const unsigned char lech_trai[7]={0b00000001,0b00000010,0b00000011,0b00000100,0b00 000101,0b00000110,0b00000111};
const unsigned char nhieu[50]={0b00000000,0b00001001,0b00001010,0b00001011,0b00 001100,0b00001101,0b00001110,0b00010001,\
0b00010010,0b00010011,0b00010100,0b00010101,0b0001 0110,0b00011001,0b00011010,\
0b00011100,0b00100001,0b00100010,0b00100011,0b0010 0100,0b00100101,0b00100110,\
0b00101001,0b00101010,0b00101100,0b00110001,0b0011 0010,0b00110100,0b00011110,\
0b00111111,0b00111011,0b00111101,0b00111110,0b0011 1001,0b00111010,0b00111100,\
0b00110111,0b00101111,0b00011111,0b00100111,0b0001 0111,0b00001111,0b00110011,\
0b00110101,0b00110110,0b00101011,0b00101101,0b0010 1110,0b00011011,0b00011101};
//************************************************** ************************************************** *************
/////////////////////////////////CHUONG TRINH CHINH////////////////////////////////////////////////////////////////
//************************************************** ************************************************** *************
void main()
{
setup();
}
//************************************************** ************************************************** *************
///////////////////////////////////CHUONG TRINH 1//////////////////////////////////////////////////////////////////
//************************************************** ************************************************** *************
void program1()
{
while(true)
{
dieu_khien();
}
}
//************************************************** ************************************************** ************
//////////////////////////CAC CHUONG TRINH CON////////////////////////////////////////////////////////////////////
//************************************************** ************************************************** ************
void setup()
{
set_tris_a(0b00111111);
set_tris_b(0b00000101);
set_tris_c(0b11111001);
set_tris_d(0);
set_tris_e(0b00000111);
portb=0;
portd=0;
led=0;
dem=0;
dc_trai1=0;
dc_phai1=0;
while(true){
if(sw1==0) program1();
}
}
//***********************************************
void dieu_khien()
{
led=led_thu();
switch(led)
{
case 0: dk_tien(); break;
case 01: sang_phai(); break;
case 02: sang_trai(); break;
}
if (re0) ++dem;
}
//*************************************************
void tien()
{
dc_trai1=1;
dc_trai2=0;
dc_phai1=1;
dc_phai2=0;
delay_ms(500);
}
//**************************************************
void dk_tien()
{
while(led_thu()==0)
{
dc_trai1=1;
dc_trai2=0;
dc_phai1=1;
dc_phai2=0;
}
}
//**************************************************
void lui()
{
dc_trai1=0;
dc_trai2=1;
dc_phai1=0;
dc_phai2=1;
delay_ms(1000);
}
//**************************************************
void sang_phai()
{
setup_ccp1(CCP_PWM);
setup_ccp2(CCP_PWM);
setup_timer_2(T2_DIV_BY_16, 127, 1);
while(led_thu()==1)
{
set_pwm2_duty(1023);
set_pwm1_duty(400);
}
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
}
//**************************************************
void sang_trai()
{
setup_ccp1(CCP_PWM);
setup_ccp2(CCP_PWM);
setup_timer_2(T2_DIV_BY_16, 127, 1);
while(led_thu()==2)
{
set_pwm2_duty(400);
set_pwm1_duty(1023);
}
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
}
//**************************************************
void quay_phai()
{
while(ra1>0){
dc_trai1=1;
dc_trai2=0;
dc_phai1=0;
dc_phai2=1;
}
}
//**************************************************
void quay_trai()
{
while(ra4>0){
dc_trai1=0;
dc_trai2=1;
dc_phai1=1;
dc_phai2=0;
}
}
//**************************************************
void dung()
{
dc_trai1=1;
dc_trai2=1;
dc_phai1=1;
dc_phai2=1;
delay_ms(1000);
}
//**************************************************
void nang()
{
dc_nang1=1;
dc_nang2=0;
delay_ms(1000);
}
//**************************************************
void ha()
{
dc_nang1=0;
dc_nang2=1;
delay_ms(1000);
}
//**************************************************
void day()
{
dc_day1=1;
dc_day2=0;
delay_ms(1000);
}
//*************************************************
void thu()
{
dc_day1=0;
dc_day2=1;
delay_ms(1000);
}
//*************************************************
void kep()
{
dc_kep1=1;
dc_kep2=0;
delay_ms(1000);
}
//*************************************************
void nha()
{
dc_kep1=0;
dc_kep2=1;
delay_ms(1000);
}
//*************************************************
int led_thu()
{
int i;
for (i=0;i<7;i++)
{
if (porta==lech_trai[i]) return(1);
else if (porta==lech_phai[i]) return(2);
}
for (i=0;i<50;i++)
{
if(porta==nhieu[i]) return(0);
}
}

namqn: bạn nhớ dùng các tag [ code] và [ /code] để bọc các đoạn mã nguồn, như vậy sẽ dễ đọc hơn (nhớ là các tag không có khoảng trắng nhé).

navy
20-01-2007, 03:29 PM
Ban nao co kinh nghiem ve dieu khien PID post len cho minh tham khao moi! Minh dang chuan bi lam voi PIC 877A.

nhh
23-01-2007, 11:49 AM
Đây là khai báo địa chỉ của thanh ghi portB và thanh ghi intcon. Thường thì mỗi thanh ghi có một địa chỉ, giống như số nhà ấy, bạn khai báo nhầm địa chỉ của nó, nghĩa là bạn vào nhầm nhà rồi còn gì.

Với 16F877A
PORTB : địa chỉ 06h
INTCON : địa chỉ 0Bh

Vì trong file 16F877A.h của CCS C không có khai báo tường tận như trong các file .inc của Microchip, muốn sử dụng cho tiện thì khai báo thêm vào. Bạn mở file .h của con pic đang làm việc ra xem người ta đã khai báo những gì rồi.

giaosucan
23-01-2007, 02:12 PM
Nguyên văn bởi ngoalongdochanh
Cho toi hoi tai sao khi khai bao:
#device PIC16F877 *=16 ADC=10

thi CCSC bao loi: "Can not change device type this far into the code"
Cach khac phuc

minh cung hay gap loi nay ,ko bit ly do la seo ????

nhh
25-01-2007, 11:01 AM
Nguyên văn bởi ngoalongdochanh
Cho toi hoi tai sao khi khai bao:
#device PIC16F877 *=16 ADC=10

thi CCSC bao loi: "Can not change device type this far into the code"
Cach khac phuc

minh cung hay gap loi nay ,ko bit ly do la seo ????
Nguyên nhân đây:

Nguyên văn bởi ngoalongdochanh
do lần trước mình khai báo chưa đúng cách giữa 16f877A và *=16 đúng ra phải viết liền như bạn minh lại viết cách ra như thế này "16f877A *=16".

giaosucan
26-01-2007, 12:59 AM
vậy giữa CCS và HT-pic thì phần mềm được đánh giá ưu việt hơn

nhh
27-01-2007, 09:21 AM
vậy giữa CCS và HT-pic thì phần mềm được đánh giá ưu việt hơn
Kha kha...Cái này mọi người tranh luận nhiều rồi ! Nói nhiều đâu có được gì đâu.Dùng trình biên dịch nào cũng được, ai viết C chuẩn tốt thì chọn HT PIC, tớ là thực dụng nên dùng CCS C cho đỡ khổ.

Bên điện tử Việt Nam có luồng so sánh hai cái này đó, bác hứng thú thì qua đó xem.

nhh
27-01-2007, 09:29 AM
To anhoa1608: porb = 1,2,4,8 để set từng hàng lên mức 1. Chương trình đó dùng ngắt RB, chưa có chống nhiễu, bạn xem thêm ở đây: http://www.picvietnam.com/forum//showthread.php?t=839

Còn cái LCD đó, hồi trước hứng chí gắp từng ảnh lại đó :p .Bạn nào có LCD, kiểm tra thử mấy chương trình đó, cái LCD tớ lấy của thằng bạn về chạy thử chẳng thấy có tín hiệu gì cả, load mấy chương trình mẫu vào cũng chẳng có gì nốt, không biết làm cách nào để kiểm tra LCD đã chết hay còn sống nữa...

anhthang
06-02-2007, 09:33 AM
Trong Pic16f877a có 3 timer :
+ Timer0 : 8 bit
+ Timer1 : 16 bit
+ Timer2 : 8 bit
Timer dùng cho nhiều ứng dụng : định thời, capture, pwm, ...

1.Timer0

Thanh ghi tác động:

Các lệnh:

Code:
setup_TIMER_0(mode);
setup_COUNTERS (rtcc_state, ps_state); // hay setup_WDT()
set_TIMER0(value); // hay set_RTCC(value) :xác định giá trị ban đầu (8bit) cho Timer0
get_TIMER0(); // hay get_RTCC() :trả về số nguyên (8bit) của Timer0
Trong đó mode là một hoặc hai constant (nếu dùng hai thì chèn dấu "|"ở giữa) được định nghĩa trong file 16F877A.h gồm :

RTCC_INTERNAL : chọn xung clock nội
RTCC_EXT_L_TO_H : chọn bit cạnh lên trên chân RA4
RTCC_EXT_H_TO_L : chọn bit cạnh xuống trên chân RA4

RTCC_DIV_2 :chia prescaler 1:2
RTCC_DIV_4 1:4
RTCC_DIV_8 1:8
RTCC_DIV_16 1:16
RTCC_DIV_32 1:32
RTCC_DIV_64 1:64
RTCC_DIV_128 1:128
RTCC_DIV_256 1:256

rtcc_state là một trong những constant sau:

RTCC_INTERNAL
RTCC_EXT_L_TO_H
RTCC_EXT_H_TO_L

ps_state là một trong những constant sau:

RTCC_DIV_2
RTCC_DIV_4
RTCC_DIV_8
RTCC_DIV_16
RTCC_DIV_32
RTCC_DIV_64
RTCC_DIV_128
RTCC_DIV_256
WDT_18MS
WDT_36MS
WDT_72MS
WDT_144MS
WDT_288MS
WDT_576MS
WDT_1152MS
WDT_2304MS

;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxx

Em thật sự không hiểu câu này:" (nếu dùng hai thì chèn dấu "|"ở giữa) " anh NHH có thể minh họa cho em được không? em mới tìm hiểu về Pic được một tuần, nhưng chắc chắn là anh chỉ rõ hơn thì em sẽ hiểu! cảm ơn anh và chúc anh vui!

anhthang
06-02-2007, 09:36 AM
xin lỗi vì Em không biết cách trích dẫn bài viết vào câu hỏi của em nên "copy" từ bài của anh NHH qua, nếu rãnh anh chỉ em luôn cách trích dẫn luôn nha!

anhthang
06-02-2007, 06:00 PM
Các Anh có thể giúp Thắng tải được trình biên dịch CCSC 3.242 không? Thắng tải hoài không được! chúc Các Anh vui khỏe!

anhthang
07-02-2007, 06:04 PM
Luồng này sao ế quá vậy! mình xui quá!

hanspkt
07-02-2007, 08:03 PM
Bạn vào đây http://kho.tailieuvietnam.net (hoặc click chuột vào góc phải phía trên đấy).

anhthang
08-02-2007, 07:47 AM
Cảm ơn bạn Hanspkt! mình cũng là dân spkt

nghaiha
09-02-2007, 04:22 PM
Các bác ơi cho em hỏi, vậy em muốn nhúng một đoạn ASM vào trong 1 function của CCS thì em phải nhúng như thế nào ạ?

namqn
09-02-2007, 06:48 PM
Các bác ơi cho em hỏi, vậy em muốn nhúng một đoạn ASM vào trong 1 function của CCS thì em phải nhúng như thế nào ạ?
Dùng các directive #ASM và #ENDASM để bọc đoạn code đó. Đọc thêm hướng dẫn về hai directive này trong tài liệu hướng dẫn của CCS, ở đó đã có ví dụ.

Thân,

nhh
11-02-2007, 03:28 PM
Em thật sự không hiểu câu này:" (nếu dùng hai thì chèn dấu "|"ở giữa) " anh NHH có thể minh họa cho em được không? em mới tìm hiểu về Pic được một tuần, nhưng chắc chắn là anh chỉ rõ hơn thì em sẽ hiểu! cảm ơn anh và chúc anh vui!

Chọn ví dụ như vầy nè : Ví dụ chọn Timer0, chia prescaler 1:2
setup_timer_0(CC_INTERNAL|RTCC_DIV_2);Đơn giản vậy thôi !

khangcodt
11-02-2007, 07:01 PM
Chào các anh em trong trang diễn đàn CCSC.
Mình cũng đang rất quan tâm đến mảng này.

Thấy mọi người bàn luận khá sôi nổi về các phần ngắt, timer hay giao tiếp LCD... Nhưng sao không thấy ai đề cập về EEPROM vậy?
Theo quan điểm của mình thì EEPROM chính là cải tiến đáng kể nhất của PIC (hay AVR) đối với các bậc MC tiền bối như kiểu 8051.

Tiện thể cũng xin nêu thêm 1 quan điểm nữa. (Nói chung hơi nhiều quan điểm!!!). Bác NHH nói một số ví dụ về các Timer theo kiểu 'định thời' có tác dụng như tạo một khoảng thời gian (thời gian trễ). Tất nhiên điều đó đúng và có thể đó chỉ là những ví dụ để anh em học hỏi, nhưng "tui" thì hay dùng nó như một "đồng hồ bấm giờ". Tức là nó sẽ bấm giờ cho thằng CPU. Thằng CPU đang làm gì mặc kệ, nhưng khi đến giờ của nó thì CPU phải làm việc của nó...

Kiến thức còn nông cạn, mong anh em chỉ giáo thêm!!!

À nếu anh em nào hứng thú với món EEPROM thì chúng ta cùng bàn luận nhé. Nếu có thời gian rảnh hơn mình cũng sẽ cố gắng 'Pót' bài về vấn đề này. (Cũng tỏ vẻ bận rộn một tẹo!!!).

Thanks to everyone.
____________________
PS: Maybe contact with me at Email: khangcodt@yahoo.com

falleaf
11-02-2007, 07:48 PM
Những vấn đề này đã được thảo luận rất nhiều và từ rất lâu rồi bạn ạ.

Tuy vậy, hoạt động của diễn đàn luôn là trao đổi liên tục, để những người mới có thể tham gia thảo luận, các bạn muốn thảo luận chuyên mục, sẽ có thể mở ra mục mới. Đừng viết lẫn lộn trong các luồng.

Chúc vui.

khangcodt
13-02-2007, 05:29 PM
Hỏi bác NHH (hoặc có cao thủ nào biết thì chỉ bảo giùm):
Khi dùng hàm delay_ms() trong chương trình con ngắt của các Timer (VD như #INT_TIMER1) hình như có vấn đề gì đó.

Khi dịch chương trình thì có cảnh báo " Interrupts disabled..." (Theo mình hiểu thì là mọi ngắt khác điều bị cấm)

Khi chạy, nếu chương trình chính có chạy thì thời gian gây ngắt (của Timer1) lại khác so với khi không chạy gì.
Đây là toàn bộ chương trình:

#include<16F877A.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=20000000)
int i;
int16 count;
#INT_TIMER1
void lapngat()
{
count++;
if (count==200)
while(true)
{
output_high(PIN_C1);
delay_ms(1000);
if(!input(PIN_B3)) break;
output_low(PIN_C1);
delay_ms(1000);
}
else set_timer1(0);
}
void main(void)
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_TIMER1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
set_timer1(0);
count=0;
while(true)
if(!input(PIN_B0)) break;
while(true)
{
if(!input(PIN_B1))
while(true)
{
output_high(PIN_C0);
for (i=1;i<=3;i++)
delay_ms(1000);
output_low(PIN_C0);
delay_ms(1000);
if(!input(PIN_B2)) break;
}
}
}

Thanks to everyone who is interested in.

khangcodt
01-03-2007, 12:47 PM
Đợi lâu quá không thấy ai trả lời ... Đành tự giải đáp vậy (Để nếu anh em nào mắc phải thì lờ mờ cũng có hướng giải quyết).
Sau khi vào trang Web của CCSC để tìm hiểu về vấn đề này mình lĩnh hội được một vài điều như sau:
- Thứ nhất, một thiết kế sẽ là không tối ưu nếu trong CTC ngắt lại gọi đến một hàm khác đã được sử dụng trong Main hay hàm khác, đặc biệt là khi bản thân hàm này lại gọi đến hàm khác nữa...(những hàm chứa trong các header thường gọi lẫn nhau như vậy).
- Thứ hai nếu sử dụng hàm như nêu trên thì chương trình chạy sẽ không theo đúng ý đồ lập trình (chẳng hạn như trong chương trình mà mình vừa Pót). Điều này xảy ra là do bộ nhớ Stack bị tràn (stack của PIC chỉ có 8 mức) khi gọi hàm chồng chéo (cả hàm Main và CTC ngắt đều gọi...).
- Thứ ba bên CCSC khuyên nếu buộc phải gọi hàm như vậy (chẳng hạn như hàm delay_ms như trên) thì hãy khai báo ở cà hàm Main và hàm ngắt ???.
Điều này thì mình không rõ vì đã thử nhưng không có hiệu quả.

hungnp
02-03-2007, 02:56 PM
Vấn đề của bạn như có thể giải thích một cách dễ hiểu như sau:
Nếu cả 2 hàm đều được gọi trong cả hàm ngắt và hàm main thì sẽ phát sinh ra lỗi. Tại sao lại thế. Các bạn thử suy nghĩ mà xem. khi hàm main đang chạy đến hàm mà nó và hàm ngắt cùng gọi. Nếu không có ngắt xẩy ra cùng thời điểm đó thì không có vấn đề gì cả. nhưng nếu có ngắt thì nó phải lưu các thông số hiện tại và nhảy vào ngắt, và khi nó nhảy ra khỏi ngắt thì các dữ liệu đã lưu sẽ bị chồng lên trong khi thực hiện hàm đó trong ngắt. vậy chương trình sẽ không đúng nữa.

Trong Keil C của 89 thì nó chỉ là warning nhưng trong css c thì nó là error. và theo quan điểm của tôi nó phải là một error.

hungnp
02-03-2007, 03:07 PM
Nếu bạn muốn dùng 2 cái delay_ms() trong cả ngắt và main thì mình nghĩ không có cách nào đâu. nếu bạn cứ muốn dùng nó thì hãy tạo ra 2 hàm delay_ms1() và delay_ms2() và trong ngắt gọi một hàm và trong main gọi hàm còn lại.

Còn có một cách nữa mình nghĩ nó sẽ pro hơn đấy là.

mình xin viết lại một đoạn chương trình của bạn trong:
bạn khai báo một biến toàn cục như thế này nhé.
//=======
int1 bit_timer0_status;

#INT_TIMER1
void lapngat()
{
bit_timer0_status =1;
}

//===========
// và đưa công việc của bạn muốn thực hiện khi có ngắt vào đây.
//===========
void isr_timer0(void)
{
count++;
if (count==200)
while(true)
{
output_high(PIN_C1);
delay_ms(1000);
if(!input(PIN_B3)) break;
output_low(PIN_C1);
delay_ms(1000);
}

//===========
//và trong hàm main bạn phải làm thế này
//===========
void main(void)
{
if(bit_timer0_status)
{
//có thể cấm ngắt timer0.
//gọi hàm thực hiện công việc.
isr_timer0();
bit_timer0_status=0;
//bật ngắt trở lại
}
}

//ok?

khangcodt
02-03-2007, 06:15 PM
Cảm ơn bạn hungnp rất nhiều.
Giải pháp của bạn rất hay, và thực ra sau khi mình tìm hiểu điều này trên chuyên trang của CCSC mình cũng có ý tưởng na ná như vậy.
Nhưng nó vẫn có những hạn chế nhất định. Mình sẽ phân tích cho bạn như sau:
Giả sử chương trình viết theo cách của bạn, khi nó kiểm tra đến lệnh 'if(bit_timer0_status)' mà chưa xảy ra ngắt thì nó sẽ không thực hiện hàm 'isr_timer0()', qua đó rồi ngắt mới xảy ra thì chương trình lại không test 'if(bit_timer0_status)' và không thực hiện hàm 'isr_timer0()', tức là không có ngắt.
Còn nếu trong chương trình mà luôn kiểm tra 'if(bit_timer0_status)' thì đang từ việc sử dụng phương pháp ngắt lại thành ra phương pháp thăm dò ???

Mong bạn có những góp ý thêm.

khangcodt
02-03-2007, 06:20 PM
À mình cũng muốn nói thêm vấn đề vừa rồi trong CCSC nó cũng chỉ là 'warning' chứ không phải 'error'

khangcodt
04-03-2007, 08:55 AM
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


Nhờ bác NCV chỉ giáo.
Có lẽ tại công lực của em còn non kém nên em đọc cái driver này mãi mà chẳng hiểu nó là cái gì, dùng vào đâu, tác dụng ra sao...???
Mong bác rọi đèn pin khai sáng cho em với.
Cảm ơn bác rất nhiều...nhiều!!!

khangcodt
04-03-2007, 09:29 AM
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

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?)

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.

Hôm nay rãnh rỗi Pót hơi nhiều...!!!

Trước hết xin lỗi bác NHH vì cắt dán bài của bác.
Sau đó cảm ơn bác vì em tin bác sẽ trả lời cho em bài này....(Hì hì...!!!)

Nếu sài LCD (theo kiểu gì cũng vậy) thì đều mất toi PortB, hay chính xác hơn là mất hết ngắt ngoài trên PortB. (Nếu sử dụng PIC ít chân thì hết ngắt ngoài...Phí quá!!!). May mà bác có nhắc đến điều này ở cuối bài.
Bác thương thì thương cho chót, bác bày luôn cho anh em cách sử dụng LCD trên các port khác, chẳng hạn portA (kết hợp B1-B3 của portB), portC,D...
Nội lực của em còn đuối, mặc dù đã thử tìm hiểu cấu hình kết nối với LCD trong driver 'LCD.c' nhưng "em chẳng biết, em chẳng thấy...Ở bên người ấy..."

Mong bác chỉ giáo giúp.
Thanks. Thanks. Thanks... And only know to say "thanks"!!!

nhh
05-03-2007, 03:23 PM
Bạn muốn kết nối chân LCD với pic theo kiểu nào cũng được, nhưng ko ai làm như vậy cả, lí do:

- Viết code khó, vì mỗi lần xuất dữ liệu điều khiển hay hiển thị đều có mã lệnh riêng, bạn kết nối lộn xộn dẫn đến khó lập trình và ko cơ động.
- Các chân của pic thường được kéo ra ngoài theo từng port. Nếu nối lộn xộn, ko thẩm mỹ.

Bạn muốn nối theo ý bạn, cứ theo nguyên lí hoạt động của LCD thôi. Bạn xem khi nào xuất lệnh điều khiển, khi nào xuất lệnh hiển thị,...kết hợp với thiết kế của bạn mà viết code.

vdt
05-03-2007, 08:11 PM
Hôm nay rãnh rỗi Pót hơi nhiều...!!!

Trước hết xin lỗi bác NHH vì cắt dán bài của bác.
Sau đó cảm ơn bác vì em tin bác sẽ trả lời cho em bài này....(Hì hì...!!!)

Nếu sài LCD (theo kiểu gì cũng vậy) thì đều mất toi PortB, hay chính xác hơn là mất hết ngắt ngoài trên PortB. (Nếu sử dụng PIC ít chân thì hết ngắt ngoài...Phí quá!!!). May mà bác có nhắc đến điều này ở cuối bài.
Bác thương thì thương cho chót, bác bày luôn cho anh em cách sử dụng LCD trên các port khác, chẳng hạn portA (kết hợp B1-B3 của portB), portC,D...
Nội lực của em còn đuối, mặc dù đã thử tìm hiểu cấu hình kết nối với LCD trong driver 'LCD.c' nhưng "em chẳng biết, em chẳng thấy...Ở bên người ấy..."

Mong bác chỉ giáo giúp.
Thanks. Thanks. Thanks... And only know to say "thanks"!!!

Đúng như NHH đã nói, k0 ai làm như bạn đâu. Nếu bạn định dùng Port nào để đ/k LCD thì bạn nên sử dụng nguyên Port đó nhé, như vậy vừa dễ lập trình, vừa dễ trong khi làm mạch, lại dễ dàng hơn trong việc kiểm soát lỗi nữa, tóm lại là nó thực tế hơn bạn ạ.
Còn việc thay vì sử dụng Port B, ta đổi sang dùng port khác thì quá dễ đúng không bạn, chắc không cần phải nói ra ở đây nhé. Bạn nên dung luôn các driver của CCS C cho dễ (ví dụ LCD420.c), sau đó có thể sửa đi đôi chút cho phù hợp với nhu cầu thực tế của bạn, ví dụ như bạn có thể tận dụng chân thiết lập chế độ đọc dữ liệu từ LCD xuống pic (vì k0 có nhu cầu đọc từ LCD xuống PIC) để làm việc khác.
Chúc bạn thành công

hungnp
06-03-2007, 09:00 AM
Chào bạn khangcodt,

Bạn chưa đọc kỹ chương trình của mình thì phải. Sẽ không có trường hợp ngắt xẩy ra mà không thực hiện công việc mà bạn mong muốn. Có chăng thì nó chậm hơn so với khi để công việc trong ngắt một chút. thời gian này không đáng kể chỉ khoảng vài 2ms. cái này không ảnh hưởng gì phải không?

Tại sao mình lại bảo không có chuyện như bạn nói.
Trong chương trình phục vụ ngắt mình đã sử dụng một bit 'bit_Timer0_Status', bit này có mục đích khi có ngắt thì bật nó lên để báo cho hàm main biết đã có ngắt xẩy ra. và kể cả khi hàm main đang làm những gì, ở đâu thì khi gặp lệnh if(bit_Timer0_Status) thì nó thực hiện công việc mong muốn. và khi thực hiện công việc này xong phải xóa bit này để dùng cho lần sau.

khangcodt
06-03-2007, 12:34 PM
Cám ơn bạn hungnp đã quan tâm.
Như mình đã nói nếu viết theo cách của bạn thì gần như chắc chắn sẽ không thực hiện được hàm ngắt theo mong muốn. Đã đành khi timer1 báo cho(bit_Timer0_Status) =1 (timer đã ngắt), nhưng có thể nói chắc chắn rằng khi chương trình đang kiểm tra 'if(bit_timer0_status)' thì timer chưa ngắt vì nó kiểm tra ngay bắt đầu hàm main. Sau khi đã kiểm tra như vậy rồi thì chương trình có quay lại để tiếp tục kiểm tra đâu mà gọi hàm 'ngắt phụ' như bạn viêt.

Nếu bạn không tin thì hãy lập thử một chương trình đơn giản sử dụng ngắt theo cách bạn viết và mô phỏng thử trên Proteus. (việc này đơn giản và không tốn nhiều thời gian,chắc không cần nói thêm!)

Tiện đây mình nói với bạn về các phương pháp trao đổi dữ liệu nói chung. Có 3 phương pháp chủ yếu là pp thăm dò (polling), pp ngắt (interrupt) và pp trao đổi trực tiếp (pp thú ba mình không nhớ rõ lắm). Làm như cách của bạn chính là chuyển từ pp ngắt sang pp thăm dò.

OKie???
__________
PS: maybe contact me at email:khangcodt@yahoo.com

hungnp
06-03-2007, 04:20 PM
Chào khangcodt,

Hóa ra bạn bảo mình là không cho cái if của mình vào trong cái while(true) của bạn. Thật ra cái đấy mình chỉ viết thí dụ thôi. Còn nếu bạn muốn sử dụng thì bạn phải tự làm thêm. Vì mình nghĩ trong một firmware cho vi điều khiển không có cái nào không có lệnh while(true){} cả. Còn nếu đọc đến đây mà bạn vẫn khăng khăng nó không thực hiện được ngắt thì... mình cũng bó tay rồi. Nếu cần mình sẽ cho bạn xem một chương trình của mình, mình đã viết và thành phẩm. Phải nói nó chạy phe phé.

Và cái thứ 2 mình muốn nói thêm. Mình chỉ đưa ra những phương án như trên cho bạn, để bạn tham khảo thôi chứ không phải hay ho gì. nên bạn không cần thiết phải so sánh nó với 3 cái mà bạn nói. Nói thật mình chả hiểu đếch gì về mấy cái đấy cả... hê hê.

Và thêm nữa. Nếu bạn có một sáng kiển nào hay hơn cho vấn đề của bạn thì mong được học hỏi. Thanks.

PIC_Phan
07-03-2007, 08:47 PM
Các bác cho em hỏi, Em dùng CCS C 4.014 có mục PROGRAMING A CHIP trong đó có tùy chọn ICD (enable) và MACHX (disable).Em không hiểu, nếu ta chọn ICD thì nạp cho PIC bằng mạch nạp theo chuẩn nào? Chẳng lẽ nó là mạch deburg? Trước giờ em chỉ dịch ra file hex sau đó dùng ic-prog nạp cho chip, nay hỏi để tăng vốn kiến thức 1 tẹo, mong các bác chỉ giúp.
(Xin lỗi trước nếu như vấn đề trên cũ rích và đặt sai chỗ)

namqn
08-03-2007, 02:58 AM
Các bác cho em hỏi, Em dùng CCS C 4.014 có mục PROGRAMING A CHIP trong đó có tùy chọn ICD (enable) và MACHX (disable).Em không hiểu, nếu ta chọn ICD thì nạp cho PIC bằng mạch nạp theo chuẩn nào? Chẳng lẽ nó là mạch deburg? Trước giờ em chỉ dịch ra file hex sau đó dùng ic-prog nạp cho chip, nay hỏi để tăng vốn kiến thức 1 tẹo, mong các bác chỉ giúp.
(Xin lỗi trước nếu như vấn đề trên cũ rích và đặt sai chỗ)
Hãng CCS có một mạch nạp/debug gọi tên là ICD, tương tự như ICD 2 của Microchip, nhưng hai loại này không tương thích với nhau. ICD của CCS cũng có cổng nối tiếp và USB, dùng giao thức riêng của CCS.

Thân,

PIC_Phan
08-03-2007, 02:55 PM
Cảm ơn bác namqn đã trả lời.Theo bác nói,em hiểu,nếu muốn nạp thẳng bằng CCS C thì ta phải dùng mạch của CCS C.Được, vừa biết vụ này thì tìm hiểu cho kĩ luôn.
Một lần nữa cám ơn bác namqn

namqn
08-03-2007, 09:42 PM
Cảm ơn bác namqn đã trả lời.Theo bác nói,em hiểu,nếu muốn nạp thẳng bằng CCS C thì ta phải dùng mạch của CCS C.Được, vừa biết vụ này thì tìm hiểu cho kĩ luôn.
Một lần nữa cám ơn bác namqn
Bạn có thể đọc thêm về ICD của CCS ở đây:
http://www.ccsinfo.com/content.php?page=ICD

CCS cũng có 1 mạch nạp gọi là MachX.

Thân,

manofpic
12-03-2007, 08:55 PM
eo ôi! Trang này cũng toàn bài ví dụ hay! Em cảm ơn các admin, THANKS

fdv
14-03-2007, 03:03 PM
cho mình hỏi nguồn 4,5 v pic có chạy được không
mình không tài nào tạo được nguồn 5v từ con 7805 được hết
Thanks nhiều

thaithienanh
14-03-2007, 06:02 PM
chắc bạn nói trừ hao thôi chứ thường thì áp sau 7805 khoảng 4,75V chạy tốt không vấn đề gì cả ;)

fdv
15-03-2007, 04:33 PM
mình mới hoc pic mình đang viết chương trình input output cho con 16f877a
chuong trinh mình viết như thế này không biết đúng không mà nó không chạy được

#include<16F877A.h>
#fuses NOWDT,PUT,HS,NOPROTECT,NOLVP,NOBROWNOUT
#use delay(clock=10000000)
#define SRAM_SCL PIN_C3
#define SRAM_SDA PIN_C4
#USE RS232(BAUD=9600,PARITY=N,XMIT=PIN_C6,RCV=PIN_C7,BI TS=9)
main()
{
/* setup_adc_ports(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_INTERNAL);
set_adc_channel(0);

setup_ccp1(CCP_CAPTURE_FE);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);

enable_interrupts(INT_CCP1);
enable_interrupts(INT_EXT1);
enable_interrupts(INT_TIMER1);
enable_interrupts(GLOBAL);*/

while(1)
{
IF(input(pin_a0))
{
output_low(pin_b0);
}
else
{
output_high(pin_b0);
}
}//while loop
}
chương trình nạp vào pic được nhưng lại không chạy được ,
mình muốn nhập tín hiệu vào port a,xuất ra portb ,không biết bị sai chỗ nào nữa
mong các bạn xem giúp mình
các bạn có thể cho mình một vài ví dụ về vấn đề này không
cám ơn nhiều

thaithienanh
15-03-2007, 05:28 PM
à cái này là do cấu hình bạn chọn là dao động nội (Cấu hình XT chạy mà HS không chạy thì có khả năng thạch anh bị overdrive khi cấu hình ở HS, theo Microchip thì có thể thêm vào một điện trở Rs giữa chân OSC2 và chân thạch anh (trong mấy cái datasheet đều có nói đến) nguyên văn của anh Namq), nếu có sẵn thạch anh ở đó bạn cấu hình dùng thạch anh là ok.

fdv
15-03-2007, 06:40 PM
cám ơn bạn,nhưng mình mới học pic ,nên không hiểu lắm ,bạn có thể cho mình biết cách sửa chữa cụ thể hơn không,mình xài thach anh 10000000,va sơ đồ mạch lắp đúng với chỉ dẩn của những bài đăng trước

namqn
15-03-2007, 07:07 PM
Bạn thiết lập AN0 là ngõ vào analog, nhưng lại dùng nó như ngõ vào digital trong chương trình. Bạn nói rõ hơn về ý định của bạn. 'không chạy được' theo bạn nói là như thế nào? (không thấy thay đổi gì ở portB chăng?)

Thân,

fdv
15-03-2007, 07:20 PM
em đang muốn lập trình cho robot bằng tay ,em muốn kick bằng tay cầm port a(hay 1 port bất kì nào cũng được) len mức cao ,tương ứng với các nút trên tay cầm em muốn xuất ra port b các mức thấp tương ứng để điều khiển động cơ
em lập trình pic lần đầu nên còn nhiều thứ căn bản chưa biết mong anh giúp đỡ

thaithienanh
15-03-2007, 07:35 PM
bạn đang dùng project phải không (mình ít dùng cái này vì trông nó có vẻ luộm thuộm quá), mình khoái tự khai báo hơn vì nó gọn, theo như bạn nói thì phần code chỉ bây nhiêu đây là đủ rồi :
#include<16F877A.h>
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=10000000)

void main(){
while(true){
IF (input(pin_a0)) output_low(pin_b0);
else output_high(pin_b0);
}

fdv
16-03-2007, 02:46 PM
chuong trình khi mình viết 1 cổng input thì chạy được ,còn viết input cho nhiều cổng thì lại chỉ chạy được 1 input đầu tiên thôi,chương trình mình viết như thế này mong các bạn xem giúp mình
#include<16F877A.h>
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=10000000)

void main(){
while(true){
IF (input(pin_a0)) output_low(pin_b0);
else output_high(pin_b0);
IF (input(pin_a1)) output_low(pin_b1);
else output_high(pin_b1);
}}

chương trình trên khi mình nạp thì chỉ chạy được input pina0 à
không biết sao nữa,mong các bạn sửa giúp mình
cám ơn

Sangcao
16-03-2007, 04:24 PM
Ban xem lai cau truc lenh, chu y su dung dau {} trong lenh IF
Vi du
if()
{thuc hien lenh;}
else ();
ok!

thaithienanh
16-03-2007, 06:26 PM
vậy thì lạ thật :confused: mình thấy code đúng rùi mà.

namqn
16-03-2007, 10:01 PM
chuong trình khi mình viết 1 cổng input thì chạy được ,còn viết input cho nhiều cổng thì lại chỉ chạy được 1 input đầu tiên thôi,chương trình mình viết như thế này mong các bạn xem giúp mình
#include<16F877A.h>
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=10000000)

void main(){
while(true){
IF (input(pin_a0)) output_low(pin_b0);
else output_high(pin_b0);
IF (input(pin_a1)) output_low(pin_b1);
else output_high(pin_b1);
}}

chương trình trên khi mình nạp thì chỉ chạy được input pina0 à
không biết sao nữa,mong các bạn sửa giúp mình
cám ơn
Để khẳng định nhận xét trên của bạn, bạn hãy thử viết code cho 1 input và 1 output, nhưng dùng RA1 thay vì RA0, xem PIC chạy ra sao.

Tôi cho rằng cần xác định thêm trạng thái cho các thanh ghi như ADCON1, TRISA, và TRISB nữa. Tôi không bao giờ viết code mập mờ như vậy, vì tôi không rõ CCS C có xác định trạng thái cho các thanh ghi đó hay không.

Thân,

tranvanthuong
17-03-2007, 02:34 PM
mấy anh ơi, em tai mấy phần mên MPLAP Luon phiên bản 7.20,7.50,752 nhưng không biết cách viết bằng CSS anh chi em voi(minh hoạ bằng hình ảnh em cám ơn nhiều

khangcodt
17-03-2007, 03:24 PM
Chào bạn tranvanthuong!..
Bạn tải CCSC (trong trang này, mục 'chương trình dịch & các công cụ mô phỏng') về rồi cài ra (tự động nó sẽ plug-in vào MPLAB). Sau đó chọn trong Project của bạn mục Project->Select language Toolsuite là CCSC là được.

khangcodt
17-03-2007, 03:42 PM
chuong trình khi mình viết 1 cổng input thì chạy được ,còn viết input cho nhiều cổng thì lại chỉ chạy được 1 input đầu tiên thôi,chương trình mình viết như thế này mong các bạn xem giúp mình
#include<16F877A.h>
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT
#use delay(clock=10000000)

void main(){
while(true){
IF (input(pin_a0)) output_low(pin_b0);
else output_high(pin_b0);
IF (input(pin_a1)) output_low(pin_b1);
else output_high(pin_b1);
}}

chương trình trên khi mình nạp thì chỉ chạy được input pina0 à
không biết sao nữa,mong các bạn sửa giúp mình
cám ơn

Chương trình của bạn viết không vấn đề gì đâu. Mình tin là nó chạy đúng theo 2 input. Có điều lưu ý viết từ khóa thôi. Bạn nên viết 'if' ... thì đúng hơn. (Mình không rõ 'IF' viết hoa thì ct dịch nó có hiểu là lệnh if không?).

Trivinhu
18-03-2007, 02:25 PM
help me!ai co chuong trinh viet bang CCS ve van de dieu khien nhiet do dung 16F877A co nhieu chu thich thi gui len mang di.tui cong luc thap kem moi tu luyen duoi qua

kysikodau
26-03-2007, 12:17 PM
chào các bác, em vừa cài MPLAB 7.51 thấy có nhúng sẵn CCS C nhưng ko biết là phiên bản mấy và CCS C mới nhất bi giừ là bao nhiêu rùi

tranvanthuong
09-04-2007, 03:33 PM
em tải phần mền ở trang 1 ở đâu bây giờ hở các anh?

hoanglinh23
10-04-2007, 02:42 PM
Mình viết chương trình ngắt cho các chân từ RB4-RB7.Khi có ngắt thì đọc ADC và gửi ra portc.Nhưng không hiểu sao nó cứ đọc liên tục và gửi ra liên tục như kiểu cờ ngắt không bị xóa đi sau khi thực hiện ngắt vậy.Bạn nào rõ về ngắt chỉ dùm mình với.

namqn
10-04-2007, 06:33 PM
Mình viết chương trình ngắt cho các chân từ RB4-RB7.Khi có ngắt thì đọc ADC và gửi ra portc.Nhưng không hiểu sao nó cứ đọc liên tục và gửi ra liên tục như kiểu cờ ngắt không bị xóa đi sau khi thực hiện ngắt vậy.Bạn nào rõ về ngắt chỉ dùm mình với.
Trong chương trình xử lý ngắt của bạn phải có thao tác xóa cờ ngắt sau khi đã xử lý xong. Các cờ ngắt không được PIC tự động xóa sau khi thoát khỏi chương trình xử lý ngắt.

Thân,

hawinter
13-04-2007, 03:14 PM
Em viết trương trinh CCS có đoạn mã sau:
#include<16f877.h>
#use delay(clock=20000000)
#device *=16 ADC=8
khi dich chương trình báo lỗi sau:
*** Error 23 "ADC877.c" Line 3(8,9): Can not change device type this far into the code
*** Error 43 "ADC877.c" Line 3(9,11): Expecting a declaration
*** Error 43 "ADC877.c" Line 3(11,13): Expecting a declaration
*** Error 48 "ADC877.c" Line 3(14,17): Expecting a (
*** Error 43 "ADC877.c" Line 3(18,19): Expecting a declaration
5 Errors, 0 Warnings.
dòng 3 lỗi là dòng :
#device *=16 ADC=8
Em dùng bản CCS v4.01 ko biết tại sao lỗi mong các sư huynh chỉ dúp ??

hoanglinh23
13-04-2007, 09:04 PM
các anh cho em hỏi tại sao khi em dùng ngắt các chân từ RB4-RB7 của pic 16f877a thì ngắt cứ xảy ra liên tục không thoát là sao với a.Em lập trình bằng CCSC.Cụ thể là chương trình ngắt các chân này em viết cứ khi nào có ngắt xảy ra thì đọc ADC và gửi ra portC.Nhưng khi em kich hoạt ngắt thử thì thấy nó cứ đọc ADC liên tục.Em cảm ơn các anh.

namqn: Bạn đã hỏi câu này ở trên, và tôi cũng đã trả lời ở trên rồi. Bạn đã xem lại những gì mình hỏi và được trả lời chưa?

nhh
16-04-2007, 01:19 PM
Em viết trương trinh CCS có đoạn mã sau:
#include<16f877.h>
#use delay(clock=20000000)
#device *=16 ADC=8
khi dich chương trình báo lỗi sau:
*** Error 23 "ADC877.c" Line 3(8,9): Can not change device type this far into the code
*** Error 43 "ADC877.c" Line 3(9,11): Expecting a declaration
*** Error 43 "ADC877.c" Line 3(11,13): Expecting a declaration
*** Error 48 "ADC877.c" Line 3(14,17): Expecting a (
*** Error 43 "ADC877.c" Line 3(18,19): Expecting a declaration
5 Errors, 0 Warnings.
dòng 3 lỗi là dòng :
#device *=16 ADC=8
Em dùng bản CCS v4.01 ko biết tại sao lỗi mong các sư huynh chỉ dúp ??
Có bạn từng gặp lỗi như bạn, xem ở đây:
http://www.picvietnam.com/forum//showthread.php?t=357&page=1

hawinter
19-04-2007, 02:02 AM
Cam ơn huynh đã quan tâm em khắc được lỗi đó rồi bằng cách đưa khai báo #device *=16 ADC=8 nằm ngay dưới include...

tranvanthuong
21-04-2007, 09:13 AM
các anh ơi giúp em nha!em caì mplab rồi nhưng khi viết chương trình theo hướng dẫn của mấy anh, em kiếm file soure của 16f877a không có(picc/device/..)chỉ có 16f54.. thoi em bây giờ làm sao ha anh!

khangcodt
21-04-2007, 12:25 PM
các anh ơi giúp em nha!em caì mplab rồi nhưng khi viết chương trình theo hướng dẫn của mấy anh, em kiếm file soure của 16f877a không có(picc/device/..)chỉ có 16f54.. thoi em bây giờ làm sao ha anh!

Phải cài CCSC rồi lấy trong device của thư mục PICC (thư mục cài ra của CCSC) thì mới có chứ!
Good luck!

tranvanthuong
25-04-2007, 02:56 PM
em hieu roi

tranvanthuong
25-04-2007, 02:59 PM
hi hi em cam on anh nhe!

em xai ccs khoi nhung mplab cho khoe, may anh co file def_16f877a.h cua anh Nguyen Chí Linh cho em với(linh308@yahoo.com) em đang rất cần vì em học từ các chương trình của anh ấy viết anh khangcodt có không? cho em nha! cám ơn anh trước nha

tranvanthuong
25-04-2007, 03:05 PM
lộn rồi anh linhnc308@yahoo.com mới đúng!

tranvanthuong
25-04-2007, 03:08 PM
help me!ai co chuong trinh viet bang CCS ve van de dieu khien nhiet do dung 16F877A co nhieu chu thich thi gui len mang di.tui cong luc thap kem moi tu luyen duoi qua

em có đề tài đó nè! nhưng của anh linhnc308 anh cho mail cua anh di em goi cho anh!
than chao anh!

Lattice
25-04-2007, 04:32 PM
Chương trình gửi ký tự ra 2x16 LCD dùng CCS C

#include "16F877A.h" // PIC16F877A header file
#use delay(clock=4000000) // for 4Mhz crystal
#fuses XT, NOWDT, NOPROTECT, NOLVP // for debug mode

#define WRITE_DATA 0
#define WRITE_COMMAND 1

#define NCHAR_PER_LINE 16 // max char numbers per line
#define MS10 10 // 10 milliseconds
#define US400 400 // 400 microseconds

#define LCD_RS PIN_A1
#define LCD_RW PIN_A2
#define LCD_E PIN_A3

///////////////////////////////////////////////////////////
//
/* private */ void lcd_write(byte dat, int1 option) {
delay_us(US400);
if (option == WRITE_DATA)
output_high(LCD_RS);
else // option == WRITE_COMMAND
output_low(LCD_RS);
output_low(LCD_RW);
output_b(dat);

output_high(LCD_E);
delay_us(US400);
output_low(LCD_E);
}

///////////////////////////////////////////////////////////
//
void lcd_init(void) {
output_low(LCD_E); // Let LCD E line low

lcd_write(0x38, WRITE_COMMAND); // Set LCD 16x2, 5x7, 8bits data
delay_ms(15);
lcd_write(0x01, WRITE_COMMAND); // Clear LCD display
delay_ms(MS10);
lcd_write(0x0f, WRITE_COMMAND); // Open display & current
delay_ms(MS10);
lcd_write(0x06, WRITE_COMMAND); // Window fixed (Character Entry Mode?)
delay_ms(MS10);
}

///////////////////////////////////////////////////////////
//
void lcd_display_char(int8 line, int8 pos, char ch) {
line = (line == 0) ? 0 : 1;
pos = (pos > NCHAR_PER_LINE) ? NCHAR_PER_LINE : pos;

lcd_write(0x80 + 0x40 * line + pos, WRITE_COMMAND);
lcd_write(ch, WRITE_DATA);
}

///////////////////////////////////////////////////////////
void lcd_display_str(int8 line, char str[], int8 nchars) {
int8 i;
for (i = 0; i < nchars; i++)
lcd_display_char(line, i, str[i]);
}

///////////////////////////////////////////////////////////
/**
* Display characters to a 2x16 LCD
*
* (1) LCD1 to GND
* (2) LCD2 to VDD 5 volts
* (3) LCD4 (RS) - LCD5 (RW) - LCD6 (E) to A1, A2, A3
* (4) LCD7-LCD14 to B0-B7 (bus data)
*
* Ref: http://pic16.com/bbs/dispbbs.asp?boardID=23&ID=5879&page=1
*/
void main(void) {
int8 i;
char LINE1[] = { "SGN Tech" };
char LINE2[] = { "Xin chao" };

lcd_init();

// use of lcd_display_char()
for (i = 0; i < 8; i++)
lcd_display_char(0, i, LINE1[i]);

// use of lcd_display_str
lcd_display_str(1, LINE2, 8);
}

Bạn có cách nào khai báo LINE1,LINE2 thành một biến không nhỉ, kiểu thế này, mình thử mà không được:
char LINE[] = { "SGN Tech" ,"Xin chao" };
for (i = 0; i < 8; i++)
lcd_display_char(0, i, LINE[i]);
for (i = 9; i < 16; i++)
lcd_display_char(1, i-8, LINE[i]);
À, bạn có bài nào trong C sử dụng kỹ thuật bảng giống bài trong MPLAB của bác Falleaf không, mình khai báo nhiều hằng kiểu char quá nên RAM tốn kinh khủng.

namqn
25-04-2007, 07:27 PM
Bạn có cách nào khai báo LINE1,LINE2 thành một biến không nhỉ, kiểu thế này, mình thử mà không được:
char LINE[] = { "SGN Tech" ,"Xin chao" };
for (i = 0; i < 8; i++)
lcd_display_char(0, i, LINE[i]);
for (i = 9; i < 16; i++)
lcd_display_char(1, i-8, LINE[i]);
À, bạn có bài nào trong C sử dụng kỹ thuật bảng giống bài trong MPLAB của bác Falleaf không, mình khai báo nhiều hằng kiểu char quá nên RAM tốn kinh khủng.
Thử thế này xem:

char LINE[] = {"SGN TechXin chao"};

Để dùng Flash thay vì dùng RAM như trên, bạn thêm từ khóa const vào khai báo:

char const LINE[] = {"SGN TechXin chao"};


Thân,

anh_gioi
28-04-2007, 10:40 AM
:
//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#use fast_io(d)
#byte portb=0x06
#byte portd=0x08
const unsigned char digital[]={0b00000110, 0b01011011, 0b01001111, 0b01100110,\
0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111};
// ma hoa digital duoi dang mang
// Chuong trinh ngat
#int_ext
void ngat_RB0()
{
int i;
if(i<9)
{
portd=digital[i];
++i;
}
if(i==9)
{
i=0;
}
}
// 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 !
}
}




cho mình hỏi trong chương trình này thì :
lệnh này :
#use fast_io(b)

#use fast_io(d)

#byte portb=0x06

#byte portd=0x08
có ý nghĩa là gì vậy?
và lệnh này nữa: #int_ext
chưa hết: enable_interrupts(global);

enable_interrupts(int_ext);

ext_int_edge(H_to_L);
cám ơn nha

nhh
28-04-2007, 04:17 PM
:
cho mình hỏi trong chương trình này thì :
lệnh này :
#use fast_io(b)

#use fast_io(d)

#byte portb=0x06

#byte portd=0x08
có ý nghĩa là gì vậy?
và lệnh này nữa: #int_ext
chưa hết: enable_interrupts(global);

enable_interrupts(int_ext);

ext_int_edge(H_to_L);
cám ơn nha
- #use fast_io(b): dùng cái này thì trình dịch chỉ set chân i/o với 1 lệnh duy nhất, nhớ là trong hàm main() phải dùng lệnh set_trix_x(); thì mới được.

- #byte portb=0x06: địa chỉ portb

- #int_ext: chỉ thị hàm ngắt ngoài trên chân RB0

- enable_interrupts(global);: cho phép ngắt toàn cục

- enable_interrupts(int_ext);: cho phép ngắt ngoài trên chân RB0

- ext_int_edge(H_to_L);: kiểu ngắt cạnh xung cao xuống thấp

Bạn cố gắng tìm hiểu trong help của trình biên dịch, có cả đó. Đừng hỏi những câu dạng như thế này vì sẽ không ai trả lời cho bạn đâu.

tranvanthuong
03-05-2007, 02:47 PM
[QUOTE=nhh;8442]- #use fast_io(b): dùng cái này thì trình dịch chỉ set chân i/o với 1 lệnh duy nhất, nhớ là trong hàm main() phải dùng lệnh set_trix_x(); thì mới được.

- #byte portb=0x06: địa chỉ portb

-tấc cả nhửng cái này đã được định nghĩa rất kĩ và dể hiểu bạn tìm các bài của anh linhnc308, tìm bài nói về file _def_877a.h ấy.
chúc may mắn!!!

anh_gioi
05-05-2007, 11:56 PM
- #use fast_io(b): dùng cái này thì trình dịch chỉ set chân i/o với 1 lệnh duy nhất, nhớ là trong hàm main() phải dùng lệnh set_trix_x(); thì mới được.

- #byte portb=0x06: địa chỉ portb

- #int_ext: chỉ thị hàm ngắt ngoài trên chân RB0

- enable_interrupts(global);: cho phép ngắt toàn cục

- enable_interrupts(int_ext);: cho phép ngắt ngoài trên chân RB0

- ext_int_edge(H_to_L);: kiểu ngắt cạnh xung cao xuống thấp

Bạn cố gắng tìm hiểu trong help của trình biên dịch, có cả đó. Đừng hỏi những câu dạng như thế này vì sẽ không ai trả lời cho bạn đâu.


vâng! em cám ơn anh.em cũng chưa kịp đọc help nên mới như vậy.

Jackie85
06-05-2007, 03:38 PM
Mọi người cho em hỏi chút ạ,

Em đang viết ct hiện số cho led 7 thanh như mạch dưới dùng polling nhưng ko sao chạy được T_T. Nhất là ko chọn được 2 chân Anode chung, lúc nào cũng hiện cả 2 led cùng lúc.

Đoạn code của em như sau:

int chuso[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
int i, j;

void main()
{
while(1){
output_b(0x00); //tat cac led
output_e(0xFF);
i = 0;
//output_e(0x00);
while(i<3){
output_e(i);
for(j = 0; j<=9; j++){
output_b(~chuso[j]);
delay_ms(10);
}
//delay_ms(30);
i++;
}
}
}


Mong các bác giúp em với ạ O:-)

huybo02
06-05-2007, 09:27 PM
Mọi người cho em hỏi chút ạ,

Em đang viết ct hiện số cho led 7 thanh như mạch dưới dùng polling nhưng ko sao chạy được T_T. Nhất là ko chọn được 2 chân Anode chung, lúc nào cũng hiện cả 2 led cùng lúc.

Mong các bác giúp em với ạ O:-)

Hình như bạn mắc mạch trans bị sai nên lúc nào chân anod của LED 7 đoạn luôn được đặt lên mức 1 làm cả 2 LED luôn sáng. Bạn mắc lại mạch trans đi. Dùng 2 NPN mắc C lên 5V qua 1 điện trở, E xuống 0 còn B thì nối giống bạn. 2 chân Anod nối với 2 E của 2 trans
Còn code khi tăng thời gian delay lên 1000 thì thấy rõ nhưng không hiểu bạn định làm gì.
Sao ko post được file đính kèm :(. Nhấn vào tải file từ máy rồi mà nó ko hiện ra

Jackie85
07-05-2007, 08:57 AM
Hình như bạn mắc mạch trans bị sai nên lúc nào chân anod của LED 7 đoạn luôn được đặt lên mức 1 làm cả 2 LED luôn sáng. Bạn mắc lại mạch trans đi. Dùng 2 NPN mắc C lên 5V qua 1 điện trở, E xuống 0 còn B thì nối giống bạn. 2 chân Anod nối với 2 E của 2 trans


Đúng đấy bạn ạ, đã thay thành npn và chạy được.

Dù sao cũng cám ơn bạn nhé.

meishun
07-05-2007, 04:19 PM
Mình viết chương trình đọc giá trị trả về từ bộ ADC của PIC, sau đó xử lý dữ liệu để xuất ra LED 7 đoạn. Khi chạy thử thì thấy hiển thị sai, hiển thị lung tung. Kiểm tra lại phần cứng và phần mềm thấy OK. Cho chạy Deburg thì phát hiện CCS thực hiện phép chia sai (kết quả luôn bằng 0 bất chấp kiểu của biến).Bó tay!
Có ai biết lí do xin chỉ giúp mình với.
Cảm ơn!

tranvanthuong
07-05-2007, 05:12 PM
Anh nào có phần mền viết font 32 x 16 cho em xin với em chân thành cám on

conanhung
09-05-2007, 11:36 AM
#include<16F876A.h>
#fuses NOLVP, NOWDT,PUT,HS,NOPROTECT
#use delay(clock=12000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#byte porta=0x5
#byte portb=0x6
#byte portc=0x7
#bit RB0=portb.0
#bit G1 = porta.0
#bit G2 = porta.1
#bit G3 = porta.2
#bit G4 = porta.3
#bit G5 = porta.4
#bit G6 = porta.5
#bit G7 = portc.0
#bit G8 = portc.1
#bit G9 = portc.2
#bit G10 = portc.3
#bit G11 = portc.4
#bit G12 = portc.5
#bit G13 = portc.6
#bit G14 = portc.7
#bit G15 = portb.1
#bit G16 = portb.2
#bit G17 = portb.3
#bit G18 = portb.4
#bit G19 = portb.5
#bit G20 = portb.6
#bit led = portb.7
main()
{
setup_adc( ADC_OFF );
set_tris_a(0);
set_tris_b(0b00000001);
set_tris_c(0);
while(true)
{
G1=1;
G2=1;
G3=1;
G4=1;
G5=1;
G6=1;
G7=1;
G8=1;
G9=1;
G10=1;
G11=1;
G12=1;
G13=1;
G14=1;
G15=1;
G16=1;
G17=1;
G18=1;
G19=1;
G20=1;
}
}

Mạch em mắc 20 đèn led vào 3 port thông qua 20 điện trở R=4k7 xuống GND, khi nạp cho PIC6F876A thì 19 đèn đều sáng, chỉ có đèn G5, tức là ở port RA4, mặc dù port này em đã kéo lên Vdd qua điện trở 4k7 rồi, mà đèn led nối ở RA4 vẫn ko sáng.

Ah, em đã thử thêm dòng lệnh

ADCON1 = 0x06;

vào hàm main() nhưng chương trình CSS C lại báo lỗi ADCON1 chưa khai báo và không dịch được.

Cho em hỏi chương trình em viết có thiếu gì không? và thiếu thì thêm như thế nào? Em xin cám ơn.

picpicpic
09-05-2007, 04:29 PM
#include<16F876A.h>
#fuses NOLVP, NOWDT,PUT,HS,NOPROTECT
#use delay(clock=12000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#byte porta=0x5
#byte portb=0x6
#byte portc=0x7
#bit RB0=portb.0
#bit G1 = porta.0
#bit G2 = porta.1
#bit G3 = porta.2
#bit G4 = porta.3
#bit G5 = porta.4
#bit G6 = porta.5
#bit G7 = portc.0
#bit G8 = portc.1
#bit G9 = portc.2
#bit G10 = portc.3
#bit G11 = portc.4
#bit G12 = portc.5
#bit G13 = portc.6
#bit G14 = portc.7
#bit G15 = portb.1
#bit G16 = portb.2
#bit G17 = portb.3
#bit G18 = portb.4
#bit G19 = portb.5
#bit G20 = portb.6
#bit led = portb.7
main()
{
setup_adc( ADC_OFF );
set_tris_a(0);
set_tris_b(0b00000001);
set_tris_c(0);
while(true)
{
G1=1;
G2=1;
G3=1;
G4=1;
G5=1;
G6=1;
G7=1;
G8=1;
G9=1;
G10=1;
G11=1;
G12=1;
G13=1;
G14=1;
G15=1;
G16=1;
G17=1;
G18=1;
G19=1;
G20=1;
}
}

Mạch em mắc 20 đèn led vào 3 port thông qua 20 điện trở R=4k7 xuống GND, khi nạp cho PIC6F876A thì 19 đèn đều sáng, chỉ có đèn G5, tức là ở port RA4, mặc dù port này em đã kéo lên Vdd qua điện trở 4k7 rồi, mà đèn led nối ở RA4 vẫn ko sáng.

Ah, em đã thử thêm dòng lệnh

ADCON1 = 0x06;

vào hàm main() nhưng chương trình CSS C lại báo lỗi ADCON1 chưa khai báo và không dịch được.

Cho em hỏi chương trình em viết có thiếu gì không? và thiếu thì thêm như thế nào? Em xin cám ơn.
RA4 là chân ngõ vào cực thu hở, bạn cho nó lên mức cao (5V), bạn lại mắc con trở kéo lên nguồn (5V). Như thế thì đèn nào sáng cho được.

Bạn cho G5 = 0; thì đèn sáng thôi.

conanhung
09-05-2007, 05:53 PM
Em viết lại đoạn code này và cho chạy:

#include<16F876A.h>
#fuses NOLVP, NOWDT,PUT,HS,NOPROTECT
#use delay(clock=12000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#byte adcon1=0x9F
#byte porta=0x5
#byte portb=0x6
#byte portc=0x7

#bit G5 = porta.4
#bit G6 = porta.5

main()
{
adcon1=0x06;
set_tris_a(0);
set_tris_b(0b00000001);
set_tris_c(0);
while(true)
{
G5=1;
G6=1;
delay_ms(2000);
G5=0;
G6=0;
delay_ms(2000);
}
}

Nếu như anh picpicpic nói thì đèn G5 (chân RA4) phải nhấp nháy chứ, đằng này chỉ có đèn G6 nhấp nháy. Em không hiểu tại sao?

2 lệnh

#byte adcon1=0x9F

adcon1=0x6;


để cài đặt tất cả các chân của port A là digital viết vậy có đúng không?

bien_van_khat
09-05-2007, 09:05 PM
Em viết lại đoạn code này và cho chạy:
Nếu như anh picpicpic nói thì đèn G5 (chân RA4) phải nhấp nháy chứ, đằng này chỉ có đèn G6 nhấp nháy. Em không hiểu tại sao?

Trên chân RA4 của bạn có 2 con điện trở, giữ nguyên con pull-up, bỏ con 4K7 mắc với LED xuống GND. Bạn để 2 con thế thành 10K, áp sụt trên con LED chừng 2V -> dòng qua LED chỉ có 0.3mA ko đủ cho led sáng.

Thông thường để hạn dòng bạn chỉ nên dùng 470 ohm.


RA4 là chân ngõ vào cực thu hở, bạn cho nó lên mức cao (5V), bạn lại mắc con trở kéo lên nguồn (5V). Như thế thì đèn nào sáng cho được.

Bạn cho G5 = 0; thì đèn sáng thôi.

So với các chân RA khác, trong sơ đồ mạch vào ra của chân RA4 không có con MOSFET P bên trên, chỉ có con MOSFET N bên dưới. Bạn set bit RA4=0 thì con FET bên dưới dẫn, làm áp trên chân RA4 về 0 vậy làm sao LED sáng được. Khi set 1, con FET N tắt, nếu có pull-up thì áp trên chân RA4 cao.

Đã lỡ sửa bạn thì sửa luôn, không có ngõ vào cực thu hở chỉ có ngõ ra cực thu hở. Ở đây gọi chính xác là cực máng hở - Open Drain, cực thu hở - Open Collector chỉ trong các mạch logic TTL.

2 lệnh

#byte adcon1=0x9F

adcon1=0x6;


để cài đặt tất cả các chân của port A là digital viết vậy có đúng không?

Bạn làm vậy đúng, nhưng CCS hỗ trợ hàm setup_adc_ports, dùng hàm này nhanh hơn.

conanhung
11-05-2007, 12:58 AM
ok, thanks các bác nhiều, thật ra em dùng điện trở hạn dòng 330, còn điện trở kéo lên Vcc là 4k7 mà ghi nhầm, sory. Thanks các bác.

anh_gioi
12-05-2007, 07:54 PM
em có đề tài đó nè! nhưng của anh linhnc308 anh cho mail cua anh di em goi cho anh!
than chao anh!

chào cậu! cậu có thể gửi cho mình cái đề tài đó được ko vay?
mail cua mình: anh_gioi@yhaoo.com
cám ơn cậu nha

An Hiep
18-05-2007, 12:29 PM
Đo tấn số
Xin chào! Tôi là thành viên mới. Thấy anh em trong diễn đàn tao đổi hay quá, tôi xin tham gia cùng.
Tôi gửi chương trình làm với PIC6F876A cho anh em tham khảo cùng. Mạch này đo được tần số lên đến 50MHz. Tôi muốn anh em giúp tôi khi muốn đo tần số sóng mang trong tín hiệu đã điều chế biên độ thì làm thế nào?


/*================================================= =============================
* Author :DRAGON(Hungnv0401@gmail.com)
* File Name :Do tan so den 50MHz va hien thi tren LCD
* Data :16/5/2007
* Hardware :PIC16F876A
* Compiler :CCS C 3.249
* Description :50MHz frequency Counter & Display on LCD, Input is PIN_C0(Pin11)
*================================================= ============================*/

#include <16F876A.h>

#fuses HS,NOWDT,NOPROTECT,NOLVP


#bit TMR1IF = 0x0C.0
#use delay(clock=20000000)
#define RS PIN_C4
#define RW PIN_C5
#define CE PIN_C7

int8 ch_tr, tr, tr_ngh, van, ngh; // chuc trieu, trieu, tram nghin, van, nghin
int8 cycles8, cycles;
int16 freqc_high;
int16 freqc_low;
int32 freq;
//-----------------------------------------------------------------------------//

//* --------------------- Khoi tao cho LCD -----------------------------------*//
void lcd_init()
{
output_low(RS);
output_low(RW);
output_low(CE);

OUTPUT_b(0x0f);
delay_us(100);
output_high(CE);
delay_us(100);
output_low(CE);
}
//-----------------------------------------------------------------------------//

//*---------------------- Dua byte ra LCD -----------------------------------*//
void lcd_put(byte data)
{
output_high(RS);
output_low(RW);
output_low(CE);

OUTPUT_b(data);
delay_us(500);
output_high(CE);
delay_us(500);
output_low(CE);
}
//-----------------------------------------------------------------------------//

//*-------------------------- Chon 2 dong cho LCD ---------------------------*//
void lcd_2lines()
{
output_low(RS);
output_low(RW);
output_low(CE);

OUTPUT_b(0x38);
delay_us(500);
output_high(CE);
delay_us(500);
output_low(CE);
}
//-----------------------------------------------------------------------------//


//*----------------------------- Gui dia chi cho LCD ------------------------*//
void lcd_add(byte add)
{
byte real_add;
real_add = 0x80 + add;

output_low(RS);
output_low(RW);
output_low(CE);

OUTPUT_b(real_add);
delay_us(500);
output_high(CE);
delay_us(500);
output_low(CE);
}
//-----------------------------------------------------------------------------//



//*--------------------------- Chuong trinh chinh ---------------------------*//

void main()
{
lcd_init();
lcd_2lines();

while (TRUE)
{
cycles8=0;
cycles=0;
freqc_high=0;
TMR1IF = 0;
set_timer1(0);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1);

//* -------------------------- Doi 1 giay ---------------------------------- *//
while (cycles!=0xFF)
{
cycles8=0;
while (cycles8!=0xFF)
{
if (TMR1IF)
{
TMR1IF = 0;freqc_high++;
}
else
{
delay_cycles(5);
}
delay_cycles(62);
cycles8++;
}
delay_cycles(216);
cycles++;
}
delay_cycles(211);
//*----------------------Ket thuc 1 giay ------------------------------------*//


//* ----------------Lay gia tri tu bo dem tan so ----------------------------*//

freqc_low = get_timer1();
freq=(65536*freqc_high + freqc_low)/5; //Vi thuc chat thach anh ta su dung
//o day la 4MHz = 1/5 cua 20MHz
ch_tr = freq/10000000 + 48;
tr = (freq%10000000)/1000000 + 48;
tr_ngh = ((freq%10000000)%1000000)/100000 + 48;
van = (((freq%10000000)%1000000)%100000)/10000 + 48;
ngh=((((freq%10000000)%1000000)%100000)%10000)/1000 + 48;

lcd_add(0x02);
lcd_put('F'); lcd_put('r'); lcd_put('e');lcd_put('q'); lcd_put(32);
lcd_put('C'); lcd_put('o'); lcd_put('u');lcd_put('n'); lcd_put('t');
lcd_put('e'); lcd_put('r'); lcd_put(32);lcd_put(32); lcd_put(32);

lcd_add(0x42);
lcd_put('F'); lcd_put('r'); lcd_put('e');lcd_put('q'); lcd_put(':');
lcd_put(ch_tr); lcd_put(tr); lcd_put('.'); lcd_put(tr_ngh);
lcd_put(van); lcd_put(ngh); lcd_put(32);
lcd_put('M'); lcd_put('H'); lcd_put('z');lcd_put(32);lcd_put(32);
lcd_put(32);lcd_put(32);lcd_put(32);
delay_ms(50);

}
} //End

An Hiep
18-05-2007, 02:54 PM
Chào anh nhh!
Cảm ơn anh đã post lên nhiều chương trình rất dễ hiểu. Anh cho hỏi: Tôi muốn vừa tiến hành đo điện áp và hiển thị lên LCD vừa định thời gian thì làm thế nào?. Cụ thể là tôi có bài tập tiến hành đo điện áp của 1 thiết bị sạc ác quy, vấn đề này thì không có gì, nhưng tôi muốn đo thời gian nó đã sạc nữa, đơn vị tính thời gian là phút. Mong anh nhh va các anh em trong diễn đàn giúp đỡ!
Thanks alot!

necati
19-05-2007, 03:29 AM
#include <16f628.H>
#use delay(clock=4000000)//
#fuses NOPROTECT,NOWDT,PUT,noBROWNOUT,noLVP,NOMCLR,xt
#BYTE PORT_A=0X05
#BYTE PORT_B=0X06
/***entegreterbiyecisi@yahoo.com***//***entegreterbiyecisi@yahoo.com***/
// LCD STUFF
#define LCD_RS PIN_b0
#define LCD_EN PIN_b1
#define LCD_D4 PIN_b2
#define LCD_D5 PIN_b3
#define LCD_D6 PIN_b4
#define LCD_D7 PIN_b5
#define FIRST_LINE 0x00
#define SECOND_LINE 0x40
#define CLEAR_DISP 0x01
#define CURS_ON 0x0e
#define CURS_OFF 0x0c
/***entegreterbiyecisi@yahoo.com***/
#use standard_io ( a )
#use standard_io ( b )
/***entegreterbiyecisi@yahoo.com***/
// proto statements
void LCD_Init ( void );
void LCD_SetPosition ( unsigned int cX );
void LCD_PutChar ( unsigned int cX );
void LCD_PutCmd ( unsigned int cX );
void LCD_PulseEnable ( void );
void LCD_SetData ( unsigned int cX );
/***entegreterbiyecisi@yahoo.com***//***entegreterbiyecisi@yahoo.com***/
/*************************entegreterbiyecisi@yahoo. com******************************/
int32 ab=0,hz=0;
int1 stept_say=0,data_bitti=0,step,aa=0;
int16 sayi=0,tr=20;
/*************************entegreterbiyecisi@yahoo. com******************************/
#int_timer1
tas(){
ab++;
}
#int_timer0
sn(){sayi=0;
set_timer0(61);//(255-60)*195*20=1000000us=dahili 1sn icin
if(tr){ tr--;}
else{delay_us ( 698 );
output_low(pin_a0);
disable_interrupts (global);
disable_interrupts(int_timer0);
disable_interrupts(int_timer1);
sayi=get_timer1();
aa=1;
hz=sayi+(65536*ab);
tr=20;
}}
/*************************entegreterbiyecisi@yahoo. com******************************/
void main() {

setup_timer_1(t1_external|t1_div_by_1);
setup_timer_0 (RTCC_INTERNAL|RTCC_DIV_256);
enable_interrupts(int_timer0); // timer0
enable_interrupts(int_timer1);
enable_interrupts(global);
lcd_init();
SET_TRIS_A(0b00100000);
SET_TRIS_B(0b11000000);
set_timer0(61);
set_timer1(0);

LCD_SetPosition(first_LINE+0);
printf(lcd_putchar,"\NECATi KIYLIOGLU ");
LCD_SetPosition(second_LINE+1);
printf(lcd_putchar,"\ 0532 613 65 87");
delay_ms (500);
LCD_PutCmd ( CLEAR_DISP );
sayi=0;
hz=0;
/*************************entegreterbiyecisi@yahoo. com******************************/
while(true){
if(aa==1){
//LCD_PutCmd ( CLEAR_DISP );
LCD_SetPosition(first_LINE+0);
printf(lcd_putchar,"\FREQUENCYMETER ");

if(999>=hz){
LCD_SetPosition(second_LINE+0);
printf(lcd_putchar,"\FRQ=%ldHz ",hz);}
//////////////////////////////////////////
if(hz>=1000){
if(999999>=hz){
LCD_SetPosition(second_LINE+0);
printf(lcd_putchar,"\FRQ=%3.3wKhz ",hz);}}
/////////////////////////////////////////////
if(hz>=1000000){
LCD_SetPosition(second_LINE+0);
printf(lcd_putchar,"\FRQ=%2.6wMhz ",hz);}
////////////////////////////////////////////
delay_ms (1);

set_timer1(0);
enable_interrupts(int_timer0);
enable_interrupts(int_timer1);
enable_interrupts (global);
aa=0;
ab=0;
}
}}
/*************************entegreterbiyecisi@yahoo. com******************************/
/***entegreterbiyecisi@yahoo.com***/ //lcd basla
void LCD_Init ( void ){
LCD_SetData ( 0x00 );
output_low ( LCD_RS );
LCD_SetData ( 0x03 ); // init with specific nibbles to start 4-bit mode
LCD_PulseEnable();
LCD_PulseEnable();
LCD_PulseEnable();
LCD_SetData ( 0x02 ); // set 4-bit interface
LCD_PulseEnable(); // send dual nibbles hereafter, MSN first
LCD_PutCmd ( 0x2C ); // function set (all lines, 5x7 characters)
LCD_PutCmd ( 0x0C ); // display ON, cursor off, no blink
LCD_PutCmd ( 0x01 ); // clear display
LCD_PutCmd ( 0x06 ); // entry mode set, increment
}
/***entegreterbiyecisi@yahoo.com***/
void LCD_SetPosition ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) | 0x08 );
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) );
LCD_PulseEnable();
}
/***entegreterbiyecisi@yahoo.com***/
void LCD_PutChar ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
output_high ( LCD_RS );
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
output_low ( LCD_RS );
}
/***entegreterbiyecisi@yahoo.com***/
void LCD_PutCmd ( unsigned int cX )
{
// this subroutine works specifically for 4-bit Port A
LCD_SetData ( swap ( cX ) ); // send high nibble
LCD_PulseEnable();
LCD_SetData ( swap ( cX ) ); // send low nibble
LCD_PulseEnable();
}
/***entegreterbiyecisi@yahoo.com***/
void LCD_PulseEnable ( void )
{
output_high ( LCD_EN );
delay_us ( 100 );
output_low ( LCD_EN );
delay_ms ( 5 );
}
/***entegreterbiyecisi@yahoo.com***/
void LCD_SetData ( unsigned int cX )
{
output_bit ( LCD_D4, cX & 0x01 );
output_bit ( LCD_D5, cX & 0x02 );
output_bit ( LCD_D6, cX & 0x04 );
output_bit ( LCD_D7, cX & 0x08 );
}
/***entegreterbiyecisi@yahoo.com***/ //lcd son
////////////////////////////////////////////////////////////////////////////

An Hiep
21-05-2007, 10:07 AM
Cảm ơn bạn Necati đã Post lên chương trình mà tôi và nhiều anh em đang quan tâm. Tôi muốn hỏi thêm là nếu muốn đo 1 tần số sóng mang nằm trong tín hiệu điều chế thì giải quyết như thế nào. Giả sử có 1 tín hiệu cần điều chế có f = 2KHz độ rộng xung là 2us, tín hiệu sóng mang có f0 = 20MHz, nghĩa là trong 2us của tín hiệu điều chế sẽ có 20*2 = 40 chu kỳ xung của sóng mang trong đó. Bài toán ở đây là đo được tần số 20MHz từ tín hiệu đã điều chế đó.
Rất mong anh Necati và các anh em trong diễn đàn giúp đỡ!
Thanks alot!

An Hiep
21-05-2007, 10:34 AM
Tôi đọc kỹ thì thấy chương trình của anh Necati cũng đo tần số liên tục, nhưng sử dụng thêm Timer0 để định thời 1 giây, và Timer1 cũng để lấy giá trị đếm số lần xuất hiện xung vào. Tất nhiên, chương trình viết rất chuyên nghiệp, đó cũng là điều mà tôi và nhiều anh em cần học hỏi thêm rất nhiều. Chân thành cảm ơn anh!

suongrong17
22-05-2007, 05:18 PM
Xin hỏi tại sao chương trình dùng ngắt timer0 em làm giống nhu hướng dẫn mà nó không chịu chạy?

suongrong17
22-05-2007, 05:36 PM
#include<18F4450.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=20000000)
#use fast_io(b)
#byte portb=0x6
#define led pin_B0
int8 a;
void ngat()
{
delay_ms(1000);
a=a<<1; // dich trai a 1bit
if(a==256)
a=1;
}
main()
{
a=1;
set_tris_b(0);
while(true)
{
ngat();
output_b(a);
}
}
Cách này thì PIC18F4550 cũng dịch leds vô tư. Nhưng mà muốn dùng TIMER0 như của bác nhh . Khi mình làm không hiểu tại sao lại không thể chạy. Nhờ bác chỉ giáo giùm nhé!
#include <18F4550.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=20000000) . Mình đã sửa lại code của nhh như vậy để phù hợp với PIC18F4550, nhưng không hiểu sao vẫn không chạy đơợc. Bạn có thể hướng dẫn kỹ hơn về Interrup và Timer không, cảm on bạn nhiều.

thaithienanh
22-05-2007, 08:52 PM
Úi code của bạn sai rồi nếu muốn sử dụng được ngắt thì trong hàm main bạn phải thực hiện cho phép ngắt timer_0 và ngắt toàn cục (global) hoạt động, định xung nhịp cho timer, và hàm ngắt() phải được đặt ngay bên dưới chỉ thị #int_timer0 để trình dịch có thể hiểu được đây là hàm phục vụ ngắt, hàm ngắt() này bạn không thể gọi đến giống như một hàm thông thường đuợc mà nó chỉ được máy gọi đến khi có xuất hiện cờ tràn timer_0, mà khi đã sử dụng ngắt timer (tức ngắt định thời) thì bạn không nên dùng delay trong nó (rất dở),vì ngắt timer được tạo ra để thay thế hoàn hảo cho delay, code của bạn mình sửa như sau :
#include<18F4450.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=4000000)
int16 count=0;
int8 a=1;

#int_timer0
void ngat(){
++count;
if(count==2000) {count=0;a=a<<1;} // dich trai a 1bit
if(a==256) {a=1;count=0; }}

void main(){
enable_interrupts(global);
enable_interrupts(int_timer0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); //xung timer = xung máy/2
while(true) {
output_b(a);
}}

như vậy ở hàm trên ta sẽ thấy sau mỗi lần tràn ngắt timer_0 (sau hai xung máy) biến đếm count sẽ tăng lên 1 đơn vị và cứ thế cho đến khi đạt giá trị 2000 (đây là giá trị mà bạn cần phải tính để chọn đúng thời gian cần làm làm trễ) khi đó biến a sẽ đuợc dịch bit sang trái,....rồi tiếp tục... chắc khúc này bạn hiểu rồi há.

An Hiep
23-05-2007, 11:37 AM
Giải thích như bạn thaithienanh là đúng đấy. Bạn phải khai báo thủ tục ngắt cho đúng và trong chương trình chính phải cho phép ngắt (hoặc không) đúng ý đồ thuật toán.
Tiện đây các bạn cho hỏi có cách nào đo được biên độ điện áp của xung vuông có độ rộng xung (thời gian tồn tại mức) nhỏ cỡ 0.4us không? Tôi định dùng ADC thông thường với xung clock nội (thạch anh 20MHz) và dùng thêm các chân phát hiện mức (sườn lên) của xung rồi cho phép lấy ADC nhưng không biết với độ rộng xung hẹp như vậy có khả thi không? Anh em nào biết phương pháp thì giúp tôi với.
Thanks!
-----------------------------------------------------------------------
An Hiệp

suongrong17
23-05-2007, 04:38 PM
Úi code của bạn sai rồi nếu muốn sử dụng được ngắt thì trong hàm main bạn phải thực hiện cho phép ngắt timer_0 và ngắt toàn cục (global) hoạt động, định xung nhịp cho timer, và hàm ngắt() phải được đặt ngay bên dưới chỉ thị #int_timer0 để trình dịch có thể hiểu được đây là hàm phục vụ ngắt, hàm ngắt() này bạn không thể gọi đến giống như một hàm thông thường đuợc mà nó chỉ được máy gọi đến khi có xuất hiện cờ tràn timer_0, mà khi đã sử dụng ngắt timer (tức ngắt định thời) thì bạn không nên dùng delay trong nó (rất dở),vì ngắt timer được tạo ra để thay thế hoàn hảo cho delay, code của bạn mình sửa như sau :
#include<18F4450.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=4000000)
int16 count=0;
int8 a=1;

#int_timer0
void ngat(){
++count;
if(count==2000) {count=0;a=a<<1;} // dich trai a 1bit
if(a==256) {a=1;count=0; }}

void main(){
enable_interrupts(global);
enable_interrupts(int_timer0);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_2); //xung timer = xung máy/2
while(true) {
output_b(a);
}}

như vậy ở hàm trên ta sẽ thấy sau mỗi lần tràn ngắt timer_0 (sau hai xung máy) biến đếm count sẽ tăng lên 1 đơn vị và cứ thế cho đến khi đạt giá trị 2000 (đây là giá trị mà bạn cần phải tính để chọn đúng thời gian cần làm làm trễ) khi đó biến a sẽ đuợc dịch bit sang trái,....rồi tiếp tục... chắc khúc này bạn hiểu rồi há.

Thật sự cảm ơn sự chỉ giáo của thaithienanh. Mình cũng đang tập tành chơi với PIC thôi. Trước giờ cũng chưa từng đụng đến các loại vi xử lý thành ra không nắm rõ, khi đọc tài liệu cũng cảm thấy khó hiểu ở phần ngắt. Mình đang dự định dùng con PIC này để làm thành Keyboard USB, viết cả driver cho nó. Nhưng bây giờ cơ bản cũng còn chưa biết, chỉ có ý tửong7 thôi. Nhờ bạn chỉ them cho mình với nhé. Thế nhưng khi đưa trình ngắt này cho chạy thử thì vẫn thấy bặt vô âm tín, không hiểu bị sao nữa.

tranvanthuong
23-05-2007, 09:23 PM
cho em hỏi, em đang làm thí nghiệm pic16f84a, làm led chớp tắt theo ý muốn nhưng em muốn dùng 1 biến trở để chỉnh tốc độ delay thì phải làm sao? nhờ các anh chỉ giáo! và em muốn dùng time 0 được không?
(xin lỗi mấy anh, mục này mà em hỏi F84a)

namqn
23-05-2007, 11:07 PM
cho em hỏi, em đang làm thí nghiệm pic16f84a, làm led chớp tắt theo ý muốn nhưng em muốn dùng 1 biến trở để chỉnh tốc độ delay thì phải làm sao? nhờ các anh chỉ giáo! và em muốn dùng time 0 được không?
(xin lỗi mấy anh, mục này mà em hỏi F84a)
Người ta thường dùng bộ ADC trong PIC (tất nhiên đang nói đến những chip có module ADC) để đọc giá trị của biến trở rồi điều chỉnh thời gian/tốc độ chớp tắt. Với PIC16F84A (không có module ADC), bạn vẫn có thể làm được điều đó, nhưng dùng một cách khác, được đề cập đến trong app. note 863 của Microchip. Bạn tìm đọc app. note đó trên web site của Microchip.

Thân,

suongrong17
24-05-2007, 07:15 PM
Cảm ơn anh thaithienanh nhiều, mình đã làm được rồi.Đã OK phần ngắt. Chiều nay mới quét và hiển thị 2x7 segment leds. Cho nó đếm, đã dần hiểu đựoc7 lập trình vi điầu khiển. Mong đựoc7 các bác chỉ giáo nhiều hơn nữa.

đây là chưong7 trình mà mình mới viết, mai sẽ sử dụng ngắt và timer để làm lại.


#include<18F4550.h>
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=10000000)
#use fast_io(b)
#use fast_io(a)
#byte portb=0x6

BYTE CONST LED_MAP[10] = {0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x58,0x00,0x10 };
int8 a,i,j;

void ngat()
{

a++;
if(a>=100)
a=0;
}
void main()
{set_tris_a(0);
a=0;
set_tris_b(0);
while(true)
{ i=0;while(i<=200)
{i++;
output_b(led_map[a/10]);
output_high(PIN_B7);
output_low(PIN_A0);
delay_ms(3);
output_high(PIN_A0);
output_b(led_map[a%10]);
output_low(PIN_A1);
delay_ms(3);
output_high(PIN_A1);
}
ngat();
}
return;
}

phamthaihoa
24-05-2007, 10:28 PM
cho em hỏi, em đang làm thí nghiệm pic16f84a, làm led chớp tắt theo ý muốn nhưng em muốn dùng 1 biến trở để chỉnh tốc độ delay thì phải làm sao? nhờ các anh chỉ giáo! và em muốn dùng time 0 được không?
(xin lỗi mấy anh, mục này mà em hỏi F84a)

Làm như anh namqn là ok roài, nhưng con 16F84A không có comparator nên bạn sẽ phải thêm một con comparator ngoài, ví dụ LM393

hawinter
29-05-2007, 06:38 PM
Em làm mạch đo nhiệt độ sử dụng LM335Z để hiển thị LCD .

#include <16F877A.h>
#include <DEFS_16F877A.h>
#device*=16 adc=10
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#define RS RB3
#define RW RB4
#define E RB5
#byte lcd_data = PORTD // Dia chi PORTD
int8 hight,low,i;
float value;
void convert_bcd(int8 a){
low=a%10;
hight=a/10;
low+=0x30;//doi ra ma ASCII de hien thi LCD
hight+=0x30;
}

byte lcd_read_byte()
{
byte read_byte;
set_tris_D(0xFF); // PORTD = input
RW = 1;
delay_cycles(1);
E = 1;
delay_cycles(1);
read_byte = lcd_data;
E = 0;
set_tris_D(0x00); // PORTD = 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_D(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]);
}
}
void lcd_gotoxy( BYTE x, BYTE y) {
BYTE address;

if(y!=1)
address=0x40;
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;
}
}
main()
{
set_tris_B(0);
set_tris_D(0);
set_tris_A(0xFF);
lcd_init();
delay_ms(100);
lcd_gotoxy(3,1);
lcd_putc("hello");
lcd_gotoxy(1,2);
lcd_putc("Welcom Everybody");
delay_ms(2000);
lcd_send_byte(0,1);//xoa LCD
lcd_send_byte(0,6);
setup_adc(ADC_CLOCK_INTERNAL);
setup_adc_ports(AN0);
set_adc_channel(0);
delay_ms(100);
value=(float)read_adc();
value=(value-558.5)/2.048;
convert_bcd((int8)value);
delay_us(20);
lcd_putc("nhiet do:");
while(1)
{
value=(float)read_adc();
value=(value-558.5)/2.048;
convert_bcd((int8)value);
delay_ms(1000);
lcd_gotoxy(2,4);
lcd_putc(hight);
lcd_putc(low);
lcd_putc(" do C");
//delay_ms(1000);
}
}


Chương trình có tham khảo từ các bài viết trên Picvietnam và dientuvietnam.
khi chay chương trình thì giá trị nhiệt độ hiển thị chỉ quanh các giá trị 50,52,54,56,48,58 em cũng không biết tại sao .Xin các bậc tiền bối giải đáp hộ .

hawinter
29-05-2007, 10:18 PM
Các sư huynh dúp em với đau đầu quá mà vẫn chưa tìm ra nguyên nhân ???
Cho em hỏi thêm là trong CCS để truy cập đến các thanh ghi thì làm thế nào nhỉ .

huybo02
30-05-2007, 09:28 PM
Bạn kiểm tra lại Vref trên LM335 thử xem. Chương trình trên ứng với Vref = 5V. Nếu Vref có giá trị khác bạn phải tính lại các số cho biểu thức
" value=(value-558.5)/2.048;"
Với 5V thì:
5V = 1024 muc (ADC 10bit 2^10 = 1024) => 10mV tuong ung voi 2.048 muc ADC
0oC = 273oK => 0oC ung voi muc dien the 2.73V ung voi 559 muc ADC
Nhiet do = dien the Analog/10 - 273
Tuong ung
Nhiet do = (adc -559)/2.024

Còn truy cập thanh ghi thì có lẽ giống như khai báo địa chỉ port I/O lúc đầu
VD: #byte portb = 0x06;
Lúc này ta có thể gán giá trị vào portb:
portb = 0xFF;
hay đọc giá trị từ portb ra ngoài:
data = portb;
Đối với các thanh ghi khác chắc cũng như vậy. Đặt tên thanh ghi, định nghĩa địa chỉ và truy xuất
Bạn thử xem <<< chưa thử :D

LeDuc
08-06-2007, 06:31 PM
cho em hoi trong ccs co ho tro vong lap " for" ko vay cac bac .. sao em lam hoai ma ko duoc vay .. bien dich van dung ma chay thi ko duoc...
--------------------------------
#include<16F877.h>
#device *=16 ADC=8
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=10000000)
#use fast_io(b)
#byte p3=0x06
#byte porta=0x05

void main()
{
int8 const led[]={1,2,4,8,16,32,64,128},a;
set_tris_b(0);
set_tris_a(0);
set_tris_c(0);
set_tris_d(0);

while(true)
{
for( a=0;a<8;a++)
p3=led[a];
delay_ms(100);
}

}

namqn
08-06-2007, 07:56 PM
Như thế nào là chạy không được?

Theo code của bạn, trong vòng while quá trình sau sẽ được thực hiện, nếu a là biến:
1. Xuất 8 lần dữ liệu ra p3 (địa chỉ 0x06)
2. Làm trễ 100 ms
3. Quay lại bước 1

Tôi không dùng CCS C nên bạn phải kiểm tra lại xem khai báo như bạn đã làm thì a là biến hay là hằng.

Thân,

LeDuc
10-06-2007, 12:21 AM
Em biet no sai o dau roi. Sau moi lan gia tri a tang len 1 . phai delay mot khoan thoi gian, neu ko no se chay den gia tri cuoi cung roi xuat ra portb , vay p3=led[7]=128; nhu vay xem nhu vong lap ko co tac dung(co vay thoi cugn so y thiet(~_~).. Vay doan code dung la :( 8 con led se chay duoi nhau hoai (^_^)..)
-----------------------------
#include<16F877.h>
#device *=16 ADC=8
#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=10000000)
#use fast_io(b)
#byte p3=0x06

void main()
{
int8 const led[]={1,2,4,8,16,32,64,128},a;
set_tris_b(0);
while(true)
{
for(a=0;a<8;a++)
{
p3=led[a];
delay_ms(20);
}
}
}

namqn: bạn nên đặt phần code của bạn giữa hai tag [ code] và [ /code] để định dạng cho phần code (hai tag không có khoảng trắng nào hết chứ không phải như được hiển thị ở đây).

LeDuc
11-06-2007, 03:08 PM
Các bác có thể chỉ rõ hơn về timer ko? ví dụ như khi nào timer sẽ tràn( reset ) . giống như 8051( la TF =0)
Và muốn định khỏan thời gian đếm cho timer phải làm sao?
Ví dụ như : tạo một xung vuông với tần số 1Hx, cách tính thời gian set timer như thế nào ? giá trị nạp cho timer là bao nhiêu ?
Còn timer 16 bit .. sau khi reset có cần phải nạp lại gia trị ban đầu ko?( giống như 8051 vậy ..).. Ai có the so sanh giữa 8051 va 16f877 kô?
Mong các bác giúp đỡ sớm để em mau biết rõ hơn ...
Cam ơn các bác !

nguyen.geo
21-06-2007, 06:53 PM
Các bác có thể chỉ rõ hơn về timer ko? ví dụ như khi nào timer sẽ tràn( reset ) . giống như 8051( la TF =0)
Và muốn định khỏan thời gian đếm cho timer phải làm sao?
Ví dụ như : tạo một xung vuông với tần số 1Hx, cách tính thời gian set timer như thế nào ? giá trị nạp cho timer là bao nhiêu ?
Còn timer 16 bit .. sau khi reset có cần phải nạp lại gia trị ban đầu ko?( giống như 8051 vậy ..).. Ai có the so sanh giữa 8051 va 16f877 kô?
Mong các bác giúp đỡ sớm để em mau biết rõ hơn ...
Cam ơn các bác !

Theo mình thì bạn cần xem lại datasheet của 16F877A Từ Trang 47-60.
Mỉnh thấy nó nói khá rõ mà.

An Hiep
26-06-2007, 11:54 AM
To LeDuc:
Bạn nên sử dụng ngắt sẽ rất dễ dàng.
1. Nạp cho Timer giá trị cần tạo ra
2. Cho phép ngắt Timer(Ví dụ Timer0(8bit) hoặc Timer1(16bit))
3. Xử lý ngắt(Không cho phép ngắt để lấy giá trị và tính toán)
4. Cho phép ngắt
Giá trị nạp cho Timer được tính tương tự như đối với 8051.

Chúc bạn thành công!

An Hiệp

An Hiep
26-06-2007, 12:01 PM
Bạn chú ý đối với từng Timer thì việc nạp giá trị là khác nhau.
Ví dụ Timer0: 8bit = 256 giá trị
Nếu bạn sử dụng lệnh set_timer0(10); thì thời gian bạn thu được là 256-10 = 246 giá trị. Còn set_timer1(10); thì thời gian bạn thu được là 65536-10 =65526 giá trị.

Chúc bạn thành công!


An Hiệp

dvnccbmacbt
27-06-2007, 10:32 AM
Em viết chương trình như sau: chương trình dùng để chạy led thuận trên portD, khi có ngắt trên RB7 thì chạy led ngược lại.

/#include <16F877A.h>
#device *=16
#fuses NOWDT,HS,NOPROTECT
#use delay(clock=20000000)
#use fast_io(b)
#use fast_io(c)
#use fast_io(a)
#use fast_io(d)
#use fast_io(e)

#byte intcon=0x000B
#bit RBIF=intcon.0

int8 const led[]={1,2,4,8,16,32,64,128};
int8 a=0,j=0,i=0;
int16 dem=0;
//========ham ngat timer0==========//
#int_rb
void ngat_rb()
{
for(j=8;j>0;j--)
{
output_d(led[j-1]);
delay_ms(10);
}output_d(0);RBIF=0;
}
//===========ham chinh=============//
void main()
{set_tris_d(0);
set_tris_b(0xff);
enable_interrupts(global);
enable_interrupts(int_rb);
ext_int_edge(L_TO_H );
while(1)
{ for(i=0;i<8;i++)
{
output_d(led[i]);
delay_ms(10);
}output_d(0);
}
}


còn đây là sơ đồ mạch:

http://img225.imageshack.us/img225/9474/untitledgq0.jpg

đầu tiên nó chạy thuận thì đúng rồii. khi bấm nut thì nó chạy ngược lại cũng đúng nhưng sau đó thì nó cứ chạy ngược mãi mà không chạy thuận lại. Em nghĩ khi nó chạy xong chương trình ngắt rồi thì nó sẽ thực hiện chương trình chính chứ. Ở đây hàm delay có gây ra lỗi ko?

Cho em Hỏi thêm 1 ý nữa: Ngắt sẽ xảy ra khi có chuyển trạng thái trên chân RB4-Rb7. vây nếu trong chương trinh ta thiêt lập là output và cho chuyển trạng thái bằng lệnh thì có xảy ra ngắt ko? Sự khác nhau giữa ngắt ngoài trên chân RBO và ngắt trên RB4->RB7 là gì?

anh_gioi
27-06-2007, 11:34 AM
Cám ơn nhh đã trả lời cho mình, do lần trước mình khai báo chưa đúng cách giữa 16f877A và *=16 đúng ra phải viết liền như bạn minh lại viết cách ra như thế này "16f877A *=16". Nhân tiện cho mình hỏi luôn ý nghĩa của việc khai báo "#fuses HS,NOWDT,NOPROTECT,NOLVP,NOBROWNOUT"

sao mình khai báo #device 16F877*=16 ADC=8 mà nó vẫn báo:
"can not change device type this far into the code"
thanhk!

anh_gioi
27-06-2007, 05:29 PM
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.
//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#use fast_io(d)
#byte portb=0x06
#byte portd=0x08
const unsigned char digital[]={0b00000110, 0b01011011, 0b01001111, 0b01100110,\
0b01101101, 0b01111101, 0b00000111, 0b01111111, 0b01101111};
// ma hoa digital duoi dang mang
// Chuong trinh ngat
#int_ext
void ngat_RB0()
{
int i;
if(i<9)
{
portd=digital[i];
++i;
}
if(i==9)
{
i=0;
}
}
// 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 !
}
}
http://www.freewebtown.com/nhhao/PIC/dem1_9dungngatngoai.gif

sao bai nay chỉ sủ dụng RB0 là chân vào thôi vậy.còn các chân khác sao lại không dc.
thank!

picpicpic
27-06-2007, 06:02 PM
Bác nhh này biến đi đâu lâu quá ko thấy xuất hiện, ko biết làm mod kiểu gì đây ???

To dvnccbmacbt: mô phỏng bằng proteus, bạn ko cần mắc thạch anh vào đâu.

To anh_gioi: thì chương trình đó chỉ viết cho ngắt RB0 mà bạn.

LeDuc
27-06-2007, 06:39 PM
#include <16F877A.h>
#device *=16 ADC=8
#fuses NOWDT,HS,NOPROTECT

#use delay(clock=20000000)
#use fast_io(b)
#use fast_io(c)
#use fast_io(a)
#use fast_io(d)
#use fast_io(e)

#byte intcon=0x000B
#byte portb=0x6

#bit RB7 =portb.7
#bit RBIF=intcon.0
#bit RBIE=intcon.3
//-----------------------------
int8 const led[]={1,2,4,8,16,32,64,128};
int8 j=0,i=0;

//========ham ngat tren RB ==========//
#int_rb
void ngat_rb()
{
if(rb7==0)
for(j=8;j>0;j--)
{
output_d(led[j-1]);
delay_ms(10);
}
}
//===========ham chinh=============//
void main()
{
set_tris_d(0);
set_tris_b(0xff);
enable_interrupts(global);
enable_interrupts(int_rb);
ext_int_edge(L_TO_H );
while(true)
{
for(i=0;i<8;i++)
{
output_d(led[i]);
delay_ms(10);
}
}
}



Mình đã sửa lại đoạn code của bạn rồi ..thay đổi một chút thôi.
Mình đã kiểm tra và chạy ok rồi... Nhưng có lẽ dùng delay trong hàm ngắt là ko nên . Nên tìm 1 giải thuật khác , dịch bit chẳng hạn ...
Còn sự khác biệt giữa các ngắt :" bạn xem lại phía trên các anh có chỉ dẫn đó ...
hy vọng mọi người sẽ cùng nhau tìm hiểu nhiều hơn...có sai nhiều .. có sửa nhiều ..--->> tiến bộ nhiều (^_^)!!!
Rất cảm ơn vì đã gởi thắc mắc lên đây.. qua bài trên mình đã tìm hiểu thêm được nhiều điều mới..

dvnccbmacbt
28-06-2007, 12:03 AM
Em đã làm thử một bài tập về RB4-Rb7. Có phải chỉ khi nào các chân từ RB4-Rb7 là chân input thì mới có thể tạo ra ngắt được đựoc không? Nếu là output thì dù có chuyển trạng thái cũng không tạo ra ngắt, đúng không? Nếu vậy tại sao các chân này không gọi là ngắt ngoài nhỉ? Các bác giải thích giùm em với. Nếu có 1 đoạn code mẫu thì càng tốt. Cảm ơn các bác nhiều.

picpicpic
28-06-2007, 12:14 AM
Em đã làm thử một bài tập về RB4-Rb7. Có phải chỉ khi nào các chân từ RB4-Rb7 là chân input thì mới có thể tạo ra ngắt được đựoc không? Nếu là output thì dù có chuyển trạng thái cũng không tạo ra ngắt, đúng không? Nếu vậy tại sao các chân này không gọi là ngắt ngoài nhỉ? Các bác giải thích giùm em với. Nếu có 1 đoạn code mẫu thì càng tốt. Cảm ơn các bác nhiều.
Tất nhiên, đã là ngắt RB4-RB7 thì nó phải là các ngõ input, ngắt RB0 cũng vậy. Ngắt RB0 đã gọi là ngắt ngoài rồi, chả lẽ lại gọi trùng tên, nên tiên sư microchip nó đặt là ngắt RB.
http://www.picvietnam.com/forum/showthread.php?t=357&page=2

dvnccbmacbt
28-06-2007, 01:10 AM
Các bác giúp em một câu nữa nhé. Em thắc mác chỗ TIMER1. Chế độ đếm đồng bộ là sao và không đồng bộ là sao? Em thấy trong các tài liệu và HELP giải thích dơn giản quá chẳng hiểu gì cả. Các bác cho em xin một ví dụ và ứng dụng của món này với. Cảm ơn các bác nhiều.

HL2
28-06-2007, 01:54 PM
Tuyệt vời, cảm ơn các bác nhiều lắm. Cảm ơn bác nhh đã khởi xướng ra chuyên mục này để anh em có cơ hội trao đổi kinh nghiệm, học hỏi.

anh_gioi
28-06-2007, 07:58 PM
Còn đây là ứng dụng ngắt ngoài trên RB4 đến RB7 để thay đổi kiểu cũng như tốc độ chớp nháy mấy con led chỉ để....ngắm cho vui mắt !

Ấn sw1, led1 nhấp nháy với delay 250ms
Ấn sw2, led1,2 nhấp nháy với delay 200ms
Ấn sw3, led1,2,3 nhấp nháy với delay 150ms
Ấn sw4, led1,2,3,4 nhấp nháy với delay 100ms
[code]//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#byte portb=0x06
#byte intcon=0x000B
#bit RB4=portb.4
#bit RB5=portb.5
#bit RB6=portb.6
#bit RB7=portb.7
#bit RBIF=intcon.0 //dinh nghia co ngat RB
#bit RBIE=intcon.3 //dinh nghia bit cho phep ngat RB
int led=0,speed;
// Chuong trinh ngat
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
//Kiem tra sw1
{
if(RB4==0)
{
led=0b00000001; //led1 sang
speed=250;
}
}
//Kiem tra sw2
{
if(RB5==0)
{
led=0b00000011; //led1,2 sang
speed=200;
}
}
//Kiem tra sw3
{
if(RB6==0)
{
led=0b00000111; //led1,2,3 sang
speed=150;
}
}
//Kiem tra sw4
{
if(RB7==0)
{
led=0b00001111; //led1,2,3,4 sang
speed=100;
}
}
RBIF=0; //Xoa co ngat RB
}
}
// Chuong trinh chinh
main()
{
set_tris_b(0b11110000);
portb=0b00001111;
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
while(true)
{
portb=led;
delay_ms(speed);
portb=0;
delay_ms(speed);
}
}

http://www.freewebtown.com/nhhao/PIC/thaydoichopleddungngatngoai.gif
các bác ơi kiểm tra hộ em nhé.
em viết lại bài này ,thông báo không có lỗi gì,nhưng khi mô phỏng proteus thì không nhấp nháy dc.các bác kiểm tra hộ em phát


//thay doi toc do nhap nhay LED theo cac bit vao RB4-RB7
//RB0-RB3 bit ra

//khai bao cong vao ra
#use fast_io(b)
#byte portb = 0x06
#byte intcon = 0x000B
#bit RB4 = portB.4
#bit RB5 = portB.5
#bit RB6 = portB.6
#bit RB7 = portB.7
#bit RBIF = intcon.0 //dinh nghia ham ngat RB
#bit RBIE = intcon.3 //dinh nghia bit ngat RB
int LED = 0,speed;

//tao ham ngat
#int_ext
void ngat_RB(){
IF((RBIE)&&(RBIF)){
if(RB4==0){
LED = 0x01;//den 1 sang
speed = 500;
}
if(RB5==0){
LED = 0x03;//den 1 va 2 sang
speed = 300;
}
if(RB6==0){
LED = 0x07;//den 1 2 3 sang
speed = 200;
}
if(RB7 ==0){
LED = 0x0f;
speed = 50;
}
RBIF = 0;
}
}

//ham chinh

void main(){

set_tris_b(0b11110000); //dinh nghia cong vao ra
portb = 0x00; //bit cao thap
enable_interrupts(int_ext);
ext_int_edge(H_to_L);
enable_interrupts(global);
while(true){
portB = LED;
delay_ms(speed);
portB = 0;
delay_ms(speed);
}
}

NBC
28-06-2007, 09:16 PM
Đây là đoạn chương trình có chức năng đọc giá trị ADC, sau đó ghi vào RAM ngoài, rồi đọc từ RAM ngoài để xử lí.
Có một vấn đề là khi tôi xóa dòng
output_high( PIN_D7 );
ở cuối hàm if thì các hàm này không thực thi được. Bác nào biết xin chỉ giúp tại sao.

anh_gioi
28-06-2007, 10:16 PM
Mạch quét 16 phím, hiện kết quả lên led 7 đoạn.
//************************************************** ***************************
// Author : nhh
// Date : 03/04/06
// Hardware: PIC16F877A
//************************************************** ***************************
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#use fast_io(c)
#byte portb = 0x06
#byte portc = 0x07
#bit RB0 = 0x06.0
#bit RB1 = 0x06.1
#bit RB2 = 0x06.2
#bit RB3 = 0x06.3
#bit RB4 = 0x06.4
#bit RB5 = 0x06.5
#bit RB6 = 0x06.6
#bit RB7 = 0x06.7
#bit RBIF=intcon.0 //dinh nghia co ngat RB
#bit RBIE=intcon.3 //dinh nghia bit cho phep ngat RB
int a;
const unsigned char dig[]={0b00111111,0b00000110, 0b01011011,0b01001111,\
0b01100110,0b01101101,0b01111101,0b00000111,0b0111 1111,0b01101111,0b01110111,\
0b01111100,0b00111001,0b01011110,0b11111001,0b1111 0001};
// ma hoa digital duoi dang mang
// Chuong trinh ngat
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
{
if(RB4&&RB0)
a=dig[0];
}
{
if(RB4&&RB1)
a=dig[4];
}
{
if(RB4&&RB2)
a=dig[8];
}
{
if(RB4&&RB3)
a=dig[12];
}
//.......
{
if(RB5&&RB0)
a=dig[1];
}
{
if(RB5&&RB1)
a=dig[5];
}
{
if(RB5&&RB2)
a=dig[9];
}
{
if(RB5&&RB3)
a=dig[13];
}
//........
{
if(RB6&&RB0)
a=dig[2];
}
{
if(RB6&&RB1)
a=dig[6];
}
{
if(RB6&&RB2)
a=dig[10];
}
{
if(RB6&&RB3)
a=dig[14];
}
//........
{
if(RB7&&RB0)
a=dig[3];
}
{
if(RB7&&RB1)
a=dig[7];
}
{
if(RB7&&RB2)
a=dig[11];
}
{
if(RB7&&RB3)
a=dig[15];
}
RBIF=0; //Xoa co ngat RB
}
}
// Chuong trinh chinh
main()
{
set_tris_b(0b11110000);
set_tris_c(0);
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
portb=0;
portc=0;
while(true)
{
portb=1;
portb=2;
portb=4;
portb=8;
portc=a;
}
}


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

portb=1;
portb=2;
portb=4;
portb=8;
portc=a;
lệnh gán này không biết có ý nghĩa gì nhỉ?
thank!

anh_gioi
28-06-2007, 11:53 PM
mình đánh lại chương trình trên ,CCS thông báo không có lỗi gì nhưng khi mô phỏng không chạy được.
mong mọi người tìm ra chỗ sai hộ mình!
thank!


#include "C:\Documents and Settings\Administrator\Desktop\thu\giai ma ban phim\giai ma ban phim.h"

#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=4000000)
//giai ma ban phim
#use fast_io(b)
#use fast_io(c)
#byte portb = 0x06
#byte portc = 0x07
#byte intcon = 0x000B
#bit RB0 = portB.0
#bit RB1 = portB.1
#bit RB2 = portB.2
#bit RB3 = portB.3
#bit RB4 = portB.4
#bit RB5 = portB.5
#bit RB6 = portB.6
#bit RB7 = portB.7
#bit RBIF = intcon.0 //dinh nghia ham ngat cong RB
#bit RBIE = intcon.3 //dinh nghia bit ngat RB
int a;
const unsigned char digital[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6 f\
0x77,0x7c,0x39,0x5e,0x79,0x71};

//tao ham ngat
#int_ext
void ngat_RB(){
IF((RBIF)&&(RBIE)){
if(RB4&&RB0)
{ a = digital[0];}

if(RB5&&RB0)
{a = digital[1];}

if(RB6&&RB0)
{ a = digital[2];}

if(RB7&&RB0)
{a = digital[3];}
////
if(RB4&&RB1)
{ a = digital[4];}

if(RB5&&RB1)
{a = digital[5];}

if(RB6&&RB1)
{a = digital[6];}

if(RB7&&RB1)
{a = digital[7];}
////
if(RB4&&RB2)
{a = digital[8];}

if(RB5&&RB2)
{a = digital[9];}

if(RB6&&RB2)
{a = digital[10];}

if(RB7&&RB2)
{a = digital[11];}
RBIF =0; //xoa co ngat
}
}



//tao ham chinh
void main(){
set_tris_b(0xf0);
set_tris_c(0x00);
portb = 0;
portc = 0;
enable_interrupts(int_ext); //ngat toan bo
ext_int_edge(H_to_L);
enable_interrupts(global);
while(true){
portb = 1;
portb = 2;
portb = 4;
portb = 8;
portc = a;
}
}

namqn
29-06-2007, 03:46 AM
portb=1;
portb=2;
portb=4;
portb=8;
portc=a;
lệnh gán này không biết có ý nghĩa gì nhỉ?
thank!
Lần lượt cấp điện cho từng cột bàn phím, nếu có cột nào có phím nhấn thì nó sẽ tạo ngắt. Quét xong các cột bàn phím thì xuất giá trị của a ra LED 7 đoạn 1 lần, sau đó tiếp tục vòng lặp (cấp điện từng cột bàn phím, rồi xuất ra LED).

Thân,

nhh
29-06-2007, 11:55 AM
mình đánh lại chương trình trên ,CCS thông báo không có lỗi gì nhưng khi mô phỏng không chạy được.
mong mọi người tìm ra chỗ sai hộ mình!
thank!

#include "C:\Documents and Settings\Administrator\Desktop\thu\giai ma ban phim\giai ma ban phim.h"

#fuses NOWDT,PUT,HS,NOPROTECT
#use delay(clock=4000000)
...
Ở đây có cả giải thuật và code, đã test trên mạch thật. Bạn tham khảo thêm:
http://www.picvietnam.com/forum/showthread.php?t=839

anh_gioi
29-06-2007, 12:43 PM
cam on anh rất nhiều !

anh_gioi
29-06-2007, 01:49 PM
Lần lượt cấp điện cho từng cột bàn phím, nếu có cột nào có phím nhấn thì nó sẽ tạo ngắt. Quét xong các cột bàn phím thì xuất giá trị của a ra LED 7 đoạn 1 lần, sau đó tiếp tục vòng lặp (cấp điện từng cột bàn phím, rồi xuất ra LED).

Thân,

anh có thể nói rõ hơn được không a? số: 1,2,4,6,8 nó mặc định cho cổng đấy a?

anh_gioi
30-06-2007, 01:44 AM
tui dốt tiếng anh quá, mọi người có thể dịch những từ dưới ra tiếng việt được ko? thanhk!
#FUSES NOWDT
#FUSES XT
#FUSES NOPUT
#FUSES NOPROTECT
#FUSES BROWNOUT
#FUSES LVP
#FUSES NOCPD
#FUSES NOWRT
#FUSES NODEBUG

namqn
30-06-2007, 02:01 AM
anh có thể nói rõ hơn được không a? số: 1,2,4,6,8 nó mặc định cho cổng đấy a?
- Xuất 1 ra PORTA thì chỉ có bit 0 (tức là chân RA0) ở mức 1, các bit (chân) khác là 0.
- Xuất 2 ra PORTA thì chỉ có bit 1 (tức là chân RA1) ở mức 1, các bit (chân) khác là 0.
- Xuất 4 ra PORTA thì chỉ có bit 2 (tức là chân RA2) ở mức 1, các bit (chân) khác là 0.
- Xuất 8 ra PORTA thì chỉ có bit 3 (tức là chân RA3) ở mức 1, các bit (chân) khác là 0.

Bạn nhìn vào sơ đồ mạch của nhh sẽ thấy các chân RA0 .. RA3 nối với các cột của bàn phím.

Thân,

anh_gioi
30-06-2007, 02:13 AM
cám ơn anh lần nữa nha
anh có thể dịch cho em masy nghĩa của từ trên kia được ko ạ.

namqn
30-06-2007, 02:14 AM
tui dốt tiếng anh quá, mọi người có thể dịch những từ dưới ra tiếng việt được ko? thanhk!
#FUSES NOWDT
#FUSES XT
#FUSES NOPUT
#FUSES NOPROTECT
#FUSES BROWNOUT
#FUSES LVP
#FUSES NOCPD
#FUSES NOWRT
#FUSES NODEBUG
Đây là những tên viết tắt đã được định nghĩa sẵn bởi trình biên dịch (thường thông qua tập tin include .h). Tôi không dịch (vì những từ đó là viết tắt) mà sẽ giải thích:

NOWDT - Không dùng watchdog timer (cái này không nên dịch ra)
XT - Dùng mức XT (mức công suất trung bình) cho bộ dao động với thạch anh ngoài
NOPUT - Không dùng power up timer (làm trễ khi bật nguồn)
NOPROTECT - Không bảo vệ code (không cấm đọc nội dung flash)
BROWNOUT - Dùng chức năng bảo vệ chống thấp áp
LVP - Cho phép chế độ nạp chương trình ở điện áp thấp
NOCPD - Không bảo vệ EEPROM dữ liệu (không cấm đọc nội dung EEPROM)
NOWRT - Không cấm ghi vào flash
NODEBUG - Không dành riêng các chân RB6 và RB7 cho debug

Thân,

dvnccbmacbt
30-06-2007, 11:50 AM
Đây là chưong trinh :

#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#device 16F877*=16 ADC=8
#use delay(clock=10000000)
#use fast_io(b)
int8 adc;
main()
{set_tris_b(0);
setup_adc(adc_clock_internal);
setup_adc_ports(AN0);
set_adc_channel(0);
delay_ms(10);
while(true)
{
adc=read_adc();
output_B(adc);
}
}

Còn đây là mạch :
http://img412.imageshack.us/img412/3863/up001lm7.jpg

sau khi chạy thì tất cả các led đều sáng.Em không hiểu tại sao. Do sai ở mạch hay do chương trình.
http://img412.imageshack.us/img412/4703/up002qa2.jpg

Có bác nào giúp em với

nhh
30-06-2007, 05:04 PM
http://i82.photobucket.com/albums/j257/nhhao/ADC.gif
Giữa biến trở và tụ C5 của bạn cần kéo xuống đất, nếu ko ngõ ra biến trở luôn ở mức cao 5V nên portB của bạn 8 đèn luôn sáng.

Thành thật cáo lỗi vì nhầm lẫn ngớ ngẩn này!

dvnccbmacbt
30-06-2007, 08:12 PM
Các bác ơi! Em gặp nhiều trường hợp vẽ orcad bị nhầm. Theo em biết thì proteus có thể mô phỏng và thiết kế mạch in nữa. Vậy tại sao không dùng Proteus? Có ai so sánh hai món này giúp em ko? Cho em hỏi thêm: Làm sao để tạo bus trong proteus. Cảm ơn các bác rất nhiều!

anh_gioi
01-07-2007, 01:27 AM
cái đoạn code này:
#include <16F877A.h>
#fuses HS,NOWDT,NOPROTECT,NOLVP
#device 16F877*=16 ADC=8
#use delay(clock=10000000)
#use fast_io(b)
int8 adc;
main()
{set_tris_b(0);
setup_adc(adc_clock_internal);
setup_adc_ports(AN0);
set_adc_channel(0);
delay_ms(10);
while(true)
{
adc=read_adc();
output_B(adc);
}
}

/////////////////////////////
setup_adc_ports(AN0);
//tại sao lại lại chọn chân AN0, mình có thể chọn chân khác được không.nếu chọn chân khác thì mình có phải thay thông số nào khác nữa không?
thank!

thaithienanh
01-07-2007, 04:22 AM
To anh giỏi @ : bạn phải nắm đuợc các tập lệnh sẵn của ccs :)

Như lệnh Setup_ADC_port (value) dùng để xác định chân nhận tín hiệu Analog và điện thế chuẩn sử dụng (Vref), thường thì mình hay dùng (all_analogs) tức là dùng hết các chân analog mà VDK cung cấp và điện thế chuẩn bằng VDD,
nhưng tuỳ vào nguời sử dụng muốn biến một chân Analog thành pin I/O và Vref từ một nguồn khác thì sẽ chọn value này khác đi :o .

Lệnh Set_ADC_channel (channel) dùng để chọn chân đọc giá trị ADC
channel là các số từ 0->n (n phụ thuộc vào từng loại vi điều khiển đuợc trang bị bao nhiêu cổng ADC) ví dụ như bạn nhìn thấy chân AN3, và bạn muốn đọc giá trị từ chân này thì bạn sẽ đánh vào là (3) rất đơn giản phải không :D

Ví dụ cho bạn chút nhá :
setup_adc(adc_clock_internal); // chọn xung lấy mẫu ADC = xung nội
setup_adc_ports(all_analogs); //sử dụng tất cả các chân ADC và vef=VDD
While(true){ // vòng lặp chính
while(true){
set_adc_channel(0); // chọn chân lấy mẫu là ANO
delay_ms(10); // tạo trễ để lấy mẫu ADC chuẩn xác
adc0=read_ADC(); // nạp giá trị đọc đuợc vào biến adc0
set_adc_channel(1); // chọn chân lấy mẫu là AN1
delay_ms(10);
adc1=read_ADC();
}
sau đó bạn muốn làm gì đó với các giá trị thu đuợc thì làm OK ;)
}

To dvnccbmacbt @ : Proteus hỗ trợ luôn cho nguời dùng tiện ích là Ares (thần nam tính theo ngữ hi lạp cổ :D), mình có thể dùng để vẽ mạch khá tốt, đồ hoạ khá bắt mắt (có hỗ trợ cả chức năng mô phỏng mạch 3D), giải thuật giải đẩy khi đi mạch của nó cũng khá thông minh (hơn cả Orcad tất nhiên là theo mình thui), nhưng nó có một điểm cực yếu là khi đi vào cấy hình chi tiết các thông số cho mạch in thì nó không có đủ :( , nên nếu là các mạch dơn giản thì Proteus là một trong những lựa chọn hàng đầu của mình, Orcad điểm mạnh là các thông số OK (quá chi tiết), trình nhiều nguời dùng nên có thể giao lưu học hỏi qua lại, phần help dễ nắm bắt..v.v... tuy nhiên điểm yếu của nó là cực kỳ dễ nhầm lẫn trong thiết kế (chỉ cần phần nguyên lý bạn không cẩn thận chồng dây hay gì đó là sinh chuyện rồi :mad:), đồ hoạ thì xấu hoắc, thuật đi mạch thì ngốc hết biết (thường thấy mấy anh dùng toàn vẽ tay :D),... Nên lựa chọn hàng đầu của mình hiện giờ là Protel hoàn hảo hết tất cả những gì mình muốn ,khuyên bạn nên dùng Protel nếu như cảm thấy mình có khả năng tự tiếp thu tốt (do tài liệu hiện rất ít và chẳng đầy đủ) và chọn Orcad khi muốn học hỏi lớp nguời đi trước ;),

Còn về vẽ Bus trong Proteus thì quá đơn giản rùi bạn chọn cái tool nào có hình giống như "sợi bus" vậy là xong, sau đó nối các đường dây từ linh kiện vào dùng tiếp tool net_label đặt nhãn cho từng đường để bus còn biết đâu là các đầu dây của cùng một dây :o , nếu vẫn chưa hiểu rõ về bus thì bạn phải tìm về một ví dụ nào đó rồi xem tại sao lại nối như vậy

Chú ý nếu bạn vẫn chưa rõ thì hãy rê chuột lên trên các tool chờ 1 lát trình sẽ hiện lên tên của từng tool (cái này giúp ích bạn rất nhiều khi mò mẫm một phần mềm nào đấy ;) )

dvnccbmacbt
01-07-2007, 08:49 PM
Tui có cuốn sách này về CCS. hi vọng có thể giúp cho cho 1 số bạn :
http://d3.myfreefilehosting.com/d1/CCS%20tieng%20Viet-update%20I.pdf

namqn
01-07-2007, 08:57 PM
To dvnccbmacbt @ : Proteus hỗ trợ luôn cho nguời dùng tiện ích là Ares (thần nam tính theo ngữ hi lạp cổ :D), mình có thể dùng để vẽ mạch khá tốt, đồ hoạ khá bắt mắt (có hỗ trợ cả chức năng mô phỏng mạch 3D), giải thuật giải đẩy khi đi mạch của nó cũng khá thông minh (hơn cả Orcad tất nhiên là theo mình thui), nhưng nó có một điểm cực yếu là khi đi vào cấy hình chi tiết các thông số cho mạch in thì nó không có đủ :( , nên nếu là các mạch dơn giản thì Proteus là một trong những lựa chọn hàng đầu của mình, ...
Cho ví dụ về những thông số cho mạch in mà Proteus không có đủ?

Thân,

cuopbienquin
09-07-2007, 08:12 PM
Các bạn coi gium` mình có sai chỗ nào không mà mình delay không được
Mình muốn khi đóng RB4 thì LED sẽ nháp nháy với delay 50ms chẳng hạn.
Phần ngắt chuyển chế độ thì mình làm được nhưng delay trong mỗi chế độ thì potay.
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=1000000)
#use fast_io(b)
#byte portb=0x06
#byte intcon=0x000B
#bit RB4=portb.4
#bit RB5=portb.5
#bit RBIF=intcon.0 //dinh nghia co ngat RB
#bit RBIE=intcon.3 //dinh nghia bit cho phep ngat RB

// Chuong trinh ngat
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
//Kiem tra sw1
{
if(RB4==0)
{

portb=0b00000001;

delay_ms(200);
portb=0b00001111;
delay_ms(200);

}
}
//Kiem tra sw2
{
if(RB5==0)
{
portb=0b00001000;
}
}

RBIF=0; //Xoa co ngat RB
}
}
// Chuong trinh chinh
main()
{
set_tris_b(0b11110000);
portb=0b11110000;
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
while(true)
{

}
}

nhh
09-07-2007, 08:53 PM
Các bạn coi gium` mình có sai chỗ nào không mà mình delay không được
Mình muốn khi đóng RB4 thì LED sẽ nháp nháy với delay 50ms chẳng hạn.
Phần ngắt chuyển chế độ thì mình làm được nhưng delay trong mỗi chế độ thì potay.
#include <16F877A.h>
...
}
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#byte portb=0x06
#byte intcon=0x000B
#bit RB4=portb.4
#bit RB5=portb.5
#bit RBIF=intcon.0 //dinh nghia co ngat RB
#bit RBIE=intcon.3 //dinh nghia bit cho phep ngat RB

// Chuong trinh ngat
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
//Kiem tra sw1
{
if(RB4==0)
{

portb=0b00000001;

delay_ms(50);
portb=0b00001111;
delay_ms(50);

}
}
//Kiem tra sw2
{
if(RB5==0)
{
portb=0b00001000;
}
}

RBIF=0; //Xoa co ngat RB
}
}
// Chuong trinh chinh
main()
{
set_tris_b(0b11110000);
portb=0b11110000;
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
while(true)
{
}
}
Đã sửa lại cho phù hợp file mô phỏng của bạn. Với code trên, kết thúc ngắt tất nhiên ko còn delay nữa. 50ms hơi ít, tăng lên 1000ms, thấy kết quả.

cuopbienquin
09-07-2007, 10:55 PM
Mình đã sữa lại thành 1000ms và đã chạy mô phỏng được,có điều khi chuyển chế độ (nhấn button tới 2 lần và mối làn nhấn phải giữ một thời gian) thì mới chuyển được .
Mình muốn nhấn button (1 lần) thì chế đọ 1 chạy,nhấn button 2 thi chế độ 2 chạy,vạy thôi.Mình hi vọng các bạn có thể sửa giùm mình thêm đoạn code đó nha.
#include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#byte portb=0x06
#byte intcon=0x000B
#bit RB4=portb.4
#bit RB5=portb.5
#bit RBIF=intcon.0 //dinh nghia co ngat RB
#bit RBIE=intcon.3 //dinh nghia bit cho phep ngat RB

// Chuong trinh ngat
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
//Kiem tra sw1
{
if(RB4==0)
while(RB5==1)
{

portb=0b00000001;
delay_ms(1000);
portb=0b00001111;
delay_ms(1000);

}
}
//Kiem tra sw2
{
if(RB5==0)
while(RB4==1)
{
portb=0b00001000;

delay_ms(1000);
portb=0b00001111;
delay_ms(1000);
}
}

RBIF=0; //Xoa co ngat RB
}
}
// Chuong trinh chinh
main()
{
set_tris_b(0b11110000);
portb=0b11110000;
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
while(true)
{
}
}

tranvanthuong
11-07-2007, 09:47 AM
BẠN SỪA LẠI #fuses NOWDT,PUT,XT,NOPROTECT THÀNH
#fuses NOWDT,PUT,HS,NOPROTECT LÀ CHƯƠNG TRÌNH ỔN RỒI

tranvanthuong
11-07-2007, 09:50 AM
Lúc Bạn Viết Chương Trình Ngắt Thì Trong Chương Trình Này Phải Cấm Ngắt Toàn Cục Xử Lí Xong Mới Cho Phép Ngắt Lại
Vài điều Trao đổi Cùng Bạn!