CCS C for PIC16F877A

Collapse
This topic is closed.
X
This is a sticky topic.
X
X
 
  • Giờ
  • Show
Clear All
new posts
  • nhh
    Đệ tử 9 túi
    • Feb 2006
    • 174

    #1

    CCS C for PIC16F877A

    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:



    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:



    Link download trình biên dịch CCS C ở đây: http://www.tailieuvietnam.net/downlo...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!
    Last edited by nhh; 30-06-2007, 04:58 PM.
    Ngày mai bắt đầu từ ngày hôm nay

    Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
    http://www.picvietnam.com/forum//showthread.php?t=1263
  • nhh
    Đệ tử 9 túi
    • Feb 2006
    • 174

    #2
    I/O + Delay _ Delay 1s RB0

    Chương trình này làm nhấp nháy con led ở chân RB0 1s sáng, 1s tắt.
    Code:
    #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:
    Code:
    #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 đó!
    Code:
    #fuses NOWDT,PUT,HS,NOPROTECT
    Thiết lập các config
    Code:
    #use delay(clock=10000000)
    Khai báo tần số dao động cấp cho PIC
    Code:
    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.
    Code:
    output_low(PIN_B0)
    Ngược lại
    Code:
    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):
    Code:
    {
    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....
    Attached Files
    Last edited by nhh; 17-12-2006, 12:00 PM. Lý do: Update
    Ngày mai bắt đầu từ ngày hôm nay

    Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
    http://www.picvietnam.com/forum//showthread.php?t=1263

    Comment

    • ntc
      Đệ tử 7 túi
      • Oct 2005
      • 257

      #3
      Hihi.

      Sợ ASM rồi hả!

      Comment

      • nhh
        Đệ tử 9 túi
        • Feb 2006
        • 174

        #4
        Ah ..ah!
        Sợ thì không hẳn nhưng viết nó phức tạp quá.... 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....
        Ngày mai bắt đầu từ ngày hôm nay

        Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
        http://www.picvietnam.com/forum//showthread.php?t=1263

        Comment

        • nhh
          Đệ tử 9 túi
          • Feb 2006
          • 174

          #5
          Delay 1s portB

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

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

          Code:
          #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);
          }
          }
          Code:
          #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
          Code:
          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:
          Code:
          #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!

          Attached Files
          Last edited by nhh; 17-12-2006, 11:59 AM.
          Ngày mai bắt đầu từ ngày hôm nay

          Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
          http://www.picvietnam.com/forum//showthread.php?t=1263

          Comment

          • nhh
            Đệ tử 9 túi
            • Feb 2006
            • 174

            #6
            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
            Code:
            #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);
            }
            }
            Attached Files
            Last edited by nhh; 24-09-2007, 01:36 PM. Lý do: Nhầm tí
            Ngày mai bắt đầu từ ngày hôm nay

            Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
            http://www.picvietnam.com/forum//showthread.php?t=1263

            Comment

            • ngoalongdochanh
              Nhập môn đệ tử
              • Mar 2006
              • 2

              #7
              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"

              Comment

              • nhh
                Đệ tử 9 túi
                • Feb 2006
                • 174

                #8
                Nguyên văn bởi ngoalongdochanh
                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:
                Code:
                "#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!
                Last edited by nhh; 01-04-2006, 12:41 PM.
                Ngày mai bắt đầu từ ngày hôm nay

                Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
                http://www.picvietnam.com/forum//showthread.php?t=1263

                Comment

                • ntc
                  Đệ tử 7 túi
                  • Oct 2005
                  • 257

                  #9
                  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.


                  Comment

                  • nhh
                    Đệ tử 9 túi
                    • Feb 2006
                    • 174

                    #10
                    Thank you!
                    Đúng là mình ko chú ý chỗ này!Mình sẽ sửa và up lên lại!
                    Last edited by nhh; 29-05-2006, 12:53 PM.
                    Ngày mai bắt đầu từ ngày hôm nay

                    Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
                    http://www.picvietnam.com/forum//showthread.php?t=1263

                    Comment

                    • batos
                      Nhập môn đệ tử
                      • Apr 2006
                      • 1

                      #11
                      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

                      Comment

                      • falleaf
                        PIC Bang chủ
                        • May 2005
                        • 2627

                        #12
                        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.
                        Công ty TNHH Thương mại và Giao nhận R&P
                        store.hn@rpc.vn - store.hcm@rpc.vn

                        Học PIC như thế nào?

                        Comment

                        • nhh
                          Đệ tử 9 túi
                          • Feb 2006
                          • 174

                          #13
                          Timer

                          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:

                          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

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

                          2.Timer1

                          Thanh ghi tác động:

                          Các lệnh:
                          Code:
                          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:

                          Các lệnh:
                          Code:
                          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.
                          Last edited by nhh; 02-04-2006, 10:34 AM.
                          Ngày mai bắt đầu từ ngày hôm nay

                          Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
                          http://www.picvietnam.com/forum//showthread.php?t=1263

                          Comment

                          • nhh
                            Đệ tử 9 túi
                            • Feb 2006
                            • 174

                            #14
                            Intterupt

                            INTERRUPT

                            Các lệnh dùng cho ngắt:
                            Code:
                            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:
                            Code:
                            #INT_EXT
                            void ngat_ngoai()
                            {
                            //Chương trình ngắt tại đây
                            }
                            Ngày mai bắt đầu từ ngày hôm nay

                            Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
                            http://www.picvietnam.com/forum//showthread.php?t=1263

                            Comment

                            • nhh
                              Đệ tử 9 túi
                              • Feb 2006
                              • 174

                              #15
                              Ngắt Timer0

                              Đâ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.
                              Code:
                              #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;
                                 }
                              }
                              Attached Files
                              Last edited by nhh; 22-09-2007, 09:37 AM. Lý do: Update
                              Ngày mai bắt đầu từ ngày hôm nay

                              Bạn có thắc mắc, bạn cần sự hỗ trợ của các thành viên. Hãy đọc luồng này:
                              http://www.picvietnam.com/forum//showthread.php?t=1263

                              Comment

                              Working...