Thứ Sáu, 19 tháng 10, 2012

Cortex là gì? Kiến trúc co bản của SMT32 - ARM Cortex M3

Trong vài nam trở lại đây, một trong những xu huớng chủ yếu trong các thiết kế với vi điều khiển là sử dụng các chip ARM7 và ARM9 nhu một vi điều khiển đa dụng. 

Ngày nay các nhà sản xuất IC đưa ra thị truờng hon 240 dòng vi điều khiển sử dụng lõi ARM. Tập đoàn ST Microelectronic vừa cho ra mắt dòng STM32, vi điều khiển đầu tiên dựa trên nền lõi ARM Cortex-M3 thế hệ mới do hãng ARM thiết kế, lõi ARM Cortex-M3 là sự cải tiến của lõi ARM7 truyền thống, từng mang lại sự thành công vang dội cho công ty ARM.

Dòng STM32 thiết lập các tiêu chuẩn mới về hiệu suất, chi phí, cung nhu khả nang đáp ứng các ứng dụng tiêu thụ nang luợng thấp và tính điều khiển thời gian thực khắc khe.



1.1 Cortex là gì?

Dòng ARM Cortex là một bộ xử lí thế hệ mới đua ra một kiến trúc chuẩn cho nhu cầu đa dạng về công nghệ. Không giống nhu các chip ARM khác, dòng Cortex là một lõi xử lí hoàn thiện, dua ra một chuẩn CPU và kiến trúc hệ thống chung.

Dòng Cortex gồm có 3 phân nhánh chính: dòng A dành cho các ứng dụng cao cấp, dòng R dành cho các ứng dụng thời gian thực nhu các đầu đọc và dòng M dành cho các ứng dụng vi điều khiển và chi phí thấp. STM32 đuợc thiết kế dựa trên dòng Cortex-M3, dòng Cortex-M3 đuợc thiết kế đặc biệt để nâng cao hiệu suất hệ thống, kết hợp với tiêu thụ nang luợng thấp, CortexM3 đuợc thiết kế trên nền kiến trúc mới, do đó chi phí sản xuất đủ thấp để cạnh tranh với các dòng vi điều khiển 8 và 16-bit truyền thống.

Các chip ARM7 và ARM9 đuợc các nhà sản xuất bán dẫn thiết kế với giải pháp riêng của mình, đặc biệt là phần xử lí các các ngắt đặc biệt (exception) và các ngắt thông thuờng (interrupt). Cortex-M3 đưa ra một lõi vi điều khiển chuẩn nhằm cung cấp phần tổng quát, quan trọng nhất của một vi điều khiển, Trang 6 Author: ARMVN Kiến trúc co bản của SMT32 - ARM Cortex M3 www.arm.vn bao gồm hệ thống ngắt (interrupt system), SysTick timer (đuợc thiết kế cho hệ điều hành thời gian thực), hệ thống kiểm lỗi (debug system) và memory map. Không gian địa chỉ 4Gbyte của Cortex-M3 đuợc chia thành các vùng cho mã chuong trình, SRAM, ngoại vi và ngoại vi hệ thống.

Không giống với ARM7 đuợc thiết kế theo kiến trúc Von Neumann (bộ nhớ chuong trình và bộ nhớ dữ liệu chung với nhau), Cortex-M3 đuợc thiết kế dựa theo kiến trúc Harvard (bộ nhớ chuong trình và bộ nhớ dữ liệu tách biệt với nhau), và có nhiều bus cho phép thực hiện các thao tác song song với nhau, do đó làm tang hiệu suất của chip. Không giống với các kiến trúc ARM truớc đó, dòng Cortex cho phép truy cập dữ liệu không xếp hàng (unaligned data, vì chip ARM là kiến trúc 32bit, do đó tất cả các dữ liệu hoặc mã chuong trình đều đuợc sắp sếp khít với vùng bộ nhớ là bội số của 4byte). Ðặc điểm này cho phép sử dụng hiệu quả SRAM nội. Dòng Cortex còn hỗ trợ việc đặt và xoá các bit bên trong hai vùng 1Mbyte của bộ nhớ bằng phuong pháp gọi là bit banding. Ðặc điểm này cho phép truy cập hiệu quả tới các thanh ghi ngoại vi và các cờ đuợc dùng trên bộ nhớ SRAM mà không cần một bộ xử lí luận lí (Boolean processor).

Khối trung tâm của STM32 là bộ xử lí Cortex-M3. Bộ xử lí Cortex-M3 là một vi diều khiển duợc tiêu chuẩn hoá gồm một CPU 32bit, cấu trúc bus (bus structure), don vị xử lí ngắt có hỗ trợ tính nang lồng ngắt vào nhau (nested interrupt unit), hệ thống kiểm lỗi (debug system) và tiêu chuẩn bố trí bộ nhớ (standard memory layout). Một trong những thành phần chính của lõi Cortex-M3 là NVIC (Nested Vector Interrupt Controller). NVIC cung cấp một cấu trúc ngắt chuẩn cho tất cả các vi diều khiển duợc thiết kế dựa trên lõi Cortex và cách xử lí các ngắt dặc biệt (exceptional interrupt). NVIC cung cấp các vector ngắt chuyên dụng lên tới 240 nguồn ngắt từ ngoại vi, mỗi nguồn ngắt dó có thể duợc uu tiên hoá với các mức riêng biệt. NVIC duợc thiết kế dể xử lí các ngắt dòi hỏi thời gian dáp ứng cực kì nhanh (extremely fast interrupt).



Thời gian từ lúc nhận một tín hiệu ngắt cho tới khi thực thi dòng lệnh dầu tiên trong trình phục vụ ngắt chỉ là 12 chu kì xung nhịp. Công việc này duợc thực hiện tự dộng bởi một vi chuong trình (microcode) duợc cài sẵn trong CPU. Trong truờng hợp xuất hiện các interrupt lồng nhau (tức là xảy ra ngắt khi dang xử lí ngắt truớc dó), NVIC sử dụng một phuong thức gọi là “tail chain” cho phép ngắt liên tiếp duợc phục vụ với dộ trễ chỉ có 6 chu kì xung nhịp. Trong suốt giai doạn luu trữ dữ liệu lên vùng nhớ stack dể bắt dầu thực thi chuong trình phục vụ ngắt, một ngắt có mức uu tiên cao hon ngắt hiện tại có thể cạnh tranh với (pre-empt) ngắt hiện tại mà không chịu bất kì trì hoãn nào. Cấu trúc ngắt cung di kèm với chế dộ tiết kiệm nang luợng của trong lõi Cortex-M3. CPU có thể duợc cấu hình tự dộng vào chế dộ tiết kiệm nang luợng sau khi thoát khỏi ngắt. Sau dó lõi tiếp tục ngủ cho dến khi một exception (ngắt dặc biệt) xuất hiện. Mặc dù Cortex-M3 duợc thiết kế nhu là một lõi chi phí thấp (low cost core), nhung nó vẫn là một CPU 32-bit và vẫn hỗ trợ hai chế dộ hoạt dộng: Thread và Handler, mỗi chế dộ có thể duợc cấu hình với mỗi vùng stack riêng biệt của nó, diều này cho phép thiết kế các phần mềm phức tạp và hỗ trợ các hệ diều Trang 8 Author: ARMVN Kiến trúc co bản của SMT32 - ARM Cortex M3 www.arm.vn hành thời gian thực. Lõi Cortex có hỗ trợ một timer 24-bit tự dộng nạp lại giá trị, nó sẽ cung cấp một ngắt timer dều dặn cho một nhận RTOS (Real Time Operating System). Các chip ARM7 vả ARM9 có hai tập lệnh (tập lệnh ARM 32-bit và tập lệnh Thumb 16-bit), trong khi dó dòng Cortex duợc thiết kế hỗ trợ tập lệnh ARM Thumb-2, tập lệnh này duợc pha trộn giữa tập lệnh 16 và 32bit, nhằm dạt duợc hiệu suất cao của của tập lệnh ARM 32-bit với mật dộ mã chuong trình tối uu của tập lệnh Thumb 16-bit. Tập lệnh Thumb-2 duợc thiết kế dặc biệt dành cho trình biên dịch C/C++, tức là các ứng dụng dựa trên nền Cortex hoàn toàn có thể duợc viết bằng ngôn ngữ C mà không cần dến chuong trình khởi dộng viết bằng assembler nhu ARM7 và ARM9. 1.2 Một vài dặc diểm nổi bật của STM32 ST dã dua ra thị truờng 4 dòng vi diều khiển dựa trên ARM7 và ARM9, nhung STM32 là một buớc tiến quan trọng trên duờng cong chi phí và hiệu suất (price/performance), giá chỉ gần 1 Euro với số luợng lớn, STM32 là sự thách thức thật sự với các vi diều khiển 8 và 16-bit truyền thống. STM32 dầu tiên gồm 14 biến thể khác nhau, duợc phân thành hai nhóm: dòng Performance có tần số hoạt dộng của CPU lên tới 72Mhz và dòng Access có tần số hoạt dộng lên tới 36Mhz. Các biến thể STM32 trong hai nhóm này tuong thích hoàn toàn về cách bố trí chân (pin) và phần mềm, dồng thời kích thuớc bộ nhớ FLASH ROM có thể lên tới 128K và 20K SRAM.

Kiến trúc của STM32 nhánh Performance và Access Trang 9 Author: ARMVN Kiến trúc co bản của SMT32 - ARM Cortex M3 www.arm.vn Dòng STM32 có hai nhành, nhánh Performance hoạt động với xung nhịp lên đến 72Mhz và có đầy đủ các ngoại vi, nhánh Access hoạt động với xung nhịp tối đa 36Mhz và có ít ngoại vi hon so với nhánh Performance.

1.2.1 Sự tinh vi
Thoạt nhìn thì các ngoại vi của STM32 cung giống nhu những vi điều khiển khác, nhu hai bộ chuyển đổi ADC, timer, I2C, SPI, CAN, USB và RTC. Tuy nhiên mỗi ngoại vi trên đều có rất nhiều đặc điểm thú vị. Ví dụ nhu bộ ADC 12-bit có tích hợp một cảm biến nhiệt độ để tự động hiệu chỉnh khi nhiệt độ thay đổi và hỗ trợ nhiều mode chuyển đổi. Mỗi bộ timer có 4 khối capture compare, mỗi khối timer có thể liên kết với các khối timer khác để tạo ra một mảng các timer tinh vi. Một timer cao cấp chuyên hỗ trợ điều khiển động cơ, với 6 đầu ra PWM với dead time lập trình đuợc và một đuờng break input sẽ buộc tín hiệu PWM sang một trạng thái an toàn đã đuợc cài sẵn. Ngoại vi nối tiếp SPI có một khối kiểm tổng CRC bằng phần cứng cho 8 và 16 word hỗ trợ tích cực cho giao tiếp thẻ nhớ SD hoặc MMC. STM32 có hỗ trợ thêm 7 kênh DMA (Direct Memory Access).

Mỗi kênh có thể đuợc dùng để truyền dữ liệu đến các thanh ghi ngoại vi hoặc từ các thanh ghi ngoại vi đi với kích thuớc từ (word) dữ liệu truyền đi có thể là 8/16 hoặc 32-bit. Mỗi ngoại vi có thể có một bộ điều khiển DMA (DMA controller) đi kèm dùng để gửi hoặc đòi hỏi dữ liệu nhu yêu cầu. Một bộ phân xử bus nội (bus arbiter) và ma trận bus (bus matrix) tối thiểu hoá sự tranh chấp bus giữa truy cập dữ liệu thông qua CPU (CPU data access) và các kênh DMA. Ðiều dó cho phép các don vị DMA hoạt động linh hoạt, dễ dùng và tự động điều khiển các luồng dữ liệu bên trong vi điều khiển. STM32 là một vi điều khiển tiêu thụ nang luợng thấp và đạt hiệu suất cao.

Nó có thể hoạt động ở điện áp 2V, chạy ở tần số 72MHz và dòng tiêu thụ chỉ có 36mA với tất cả các khối bên trong vi điều khiển đều đuợc hoạt động. Kết hợp với các chế độ tiết kiệm nang luợng của Cortex, STM32 chỉ tiêu thụ 2µA khi ở Trang 10 Author: ARMVN Kiến trúc co bản của SMT32 - ARM Cortex M3 www.arm.vn chế độ standby. Một bộ dao động nội RC 8MHz cho phép chip nhanh chóng thoát khỏi chế độ tiết kiệm nang luợng trong khi bộ dao động ngoài đang khởi động.

Khả nang nhanh đi vào và thoát khỏi các chế độ tiết kiệm nang luợng làm giảm nhiều sự tiêu thụ nang luợng tổng thể.

1.2.2 Sự an toàn
Ngày nay các ứng dụng hiện đại thuờng phải hoạt động trong môi truờng khắc khe, đòi hỏi tính an toàn cao, cung nhu đòi hỏi sức mạnh xử lý và càng nhiều thiết bị ngoại vi tinh vi. Ðể dáp ứng các yêu cầu khắc khe đó, STM32 cung cấp một số tính nang phần cứng hỗ trợ các ứng dụng một cách tốt nhất. Chúng bao gồm một bộ phát hiện điện áp thấp, một hệ thống bảo vệ xung clock và hai bộ watchdogs. Bộ đầu tiên là một watchdog cửa sổ. Watchdog này phải đuợc làm tuoi trong một khung thời gian xác dịnh. Nếu nhấn nó quá sớm, hoặc quá muộn, thì watchdog sẽ kích hoạt. Bộ thứ hai là một watchdog độc lập, có bộ dao động bên ngoài tách biệt với xung nhịp hệ thống chính. Hệ thống bảo vệ xung nhịp có thể phát hiện lỗi của bộ dao động chính bên ngoài (thuờng là thạch anh) và tự động chuyển sang dùng bộ dao động nội RC 8MHz.

1.2.3 Tính bảo mật
Một trong những yêu cầu khắc khe khác của thiết kế hiện đại là nhu cầu bảo mật mã chuong trình để ngan chặn sao chép trái phép phần mềm. Bộ nhớ Flash của STM32 có thể duợc khóa dể chống truy cập đọc Flash thông qua cổng debug. Khi tính nang bảo vệ đọc đuợc kích hoạt, bộ nhớ Flash cung đuợc bảo vệ chống ghi để ngan chặn mã không tin cậy đuợc chèn vào bảng vector ngắt.

Hướng dẫn lập trình cho PIC bằng CCS ver3.242

1. Tổng quan về CCS


1.1. Vì sao ta sử dụng 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 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ủangô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 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…


2. Tạo PROJECT đầu tiên trong CCS


Để tạo một Project trong CCS có nhiều cách, có thể dùng Project Wizard, Manual Creat, hay đơn giản là tạo một Files mới và thêm vào đó các khai báo ban đầu cần thiết và “bắt buộc”.
Dưới đây sẽ trình bày cách tạo một project hợp lệ theo cả 3 phương pháp. Một điều ta cần chú ý khi tạo một Project đó là: khi tạo bắt cứ một Project nào mới thì ta nên tạo một thư mục mới với tên liên quan đến Project ta định làm, rồi lưu các files vào đó. Khi lập trình và biên dịch, CCS sẽ tạo ra rất nhiều files khác nhau, do đó nếu để chung các Project trogn một thư mục sẽ rất mất thời gian trong việc tìm kiếm sau này. Đây cũng là quy tắc chung khi ta làm việc với bất kỳ phần mềm nào, thiết kế mạch hay lập trình.
Việc đầu tiên bạn cần làm là khởi động máy tính và bật chương trình PIC C Compiler.


2.1. Tạo một PROJECT sử dụng PIC Wizard


Trước hết bạn khởi động chương trình làm việc PIC C Compiler. Từ giao diện chương trình bạn di chuột chọn Project ‐> New ‐> PIC Wizard nhấn nút trái chuột chọn.























Sau khi nhấn chuột, một cửa sổ hiện ra yêu cầu ban nhập tên Files cần tạo. Bạn tạo một
thư mục mới, vào thư mục đó và lưu tên files cần tạo tại đây.




























Cửa sổ Save As




Như vậy là xong bước đầu tiên. Sau khi nhấn nút Save, một cửa sổ New Project hiện ra. Trong của sổ này bao gồm rất nhiều Tab, mỗi Tab mô tả về một vài tính năng của con PIC. Ta sẽ chọn tính năng sử dụng tại các Tab tương ứng.
Dưới đây sẽ trình bày ý nghĩa từng mục chọn trong mỗi Tab. Các mục chọn này chính là đề cập đến các tính năng của một con PIC, tùy theo từng loại mà sẽ có các Tab tương ứng. Đối với từng dự án khác nhau, khi ta cần sử dụng tính năng nào của con PIC thì ta sẽ chọn mục đó. Tổng cộng có 13 Tab đẻ ta lưa chọn. Tôi giới thiệu những Tab chính thường hay được sử dụng.


2.1.1. Tab General


Tab General cho phép ta lựa chọn loại PIC mà ta sử dụng và một số lựa chọn khác như chọn tần số thạch anh dao động, thiết lập các bit CONFIG nhằm thiết lập chế độ hoạt động cho PIC.































Tab General




‐ Device: Liệt kê danh sách các loại PIC 12F, 16F, 18F… Ta sẽ chọn tên Vi điều khiển PIC mà ta sử dụng trong dự án. Lấy ví dụ chọn PIC16F877A.
‐ Oscilator Frequency: Tần số thạch anh ta sử dụng, chọn 20 MHz (tùy từng loại)
‐ Fuses: Thiết lập các bit Config như: Chế độ dao động (HS, RC, Internal ), chế độ bảo vệ Code, Brownout detected…
‐ Chọn kiểu con trỏ RAM là 16‐bit hay 8‐bit.


2.1.2. Tab Communications


Tab Communications liệt kê các giao tiếp nối tiếp mà một con PIC hỗ trợ, thường là RS232 và I2C, cùng với các lựa chọn để thiết lập chế độ hoạt động cho từng loại giao tiếp.

Giao tiếp RS232


Mỗi một Vi điều khiển PIC hỗ trợ một cổng truyền thông RS232 chuẩn. Tab này cho phép ta lựa chọn chân Rx, Tx, tốc độ Baud, Data bit, Bit Parity…


Giao tiếp I2C


Để sử dụng I2C ta tích vào nút chọn Use I2C, khi đó ta có các lựa chọn: Chân SDA, SCL, Tốc độ truyền (Fast ‐ Slow), chế độ Master hay Slave, địa chỉ cho Salve.































Tab Communications






2.1.3. Tab SPI and LCD


Tab này liệt kê cho người dùng các lựa chọn đối với giao tiếp nối tiếp SPI, chuẩn giao tiếp tốc độ cao mà PIC hỗ trợ về phần cứng. Chú ý khi ta dùng I2C thì không thể dùng SPI và ngược lại. Để có thể sử dụng cả hai giao tiếp này cùng một lúc thì buộc một trong 2 giao tiếp phải lập trình bằng phần mềm (giồng như khi dùng I2C cho các chip AT8051, không có hỗ trợ phần cứng SSP).
Phần cấu hình cho LCD dành cho các chíp dòng 18F và 30F.































Tab SPI and LCD






2.1.4. Tab Timer


Liệt kê các bộ đếm/định thời mà các con PIC dòng Mid‐range có: Timer0, timer1, timer2, WDT…
Trong các lựa chọn cấu hình cho các bộ đếm /định thời có: chọn nguồn xung đồng hồ (trong/ngoài), khoảng thời gian xảy ra tràn…































Tab Timer






2.1.5. Tab Analog


Liệt kê các lựa chọn cho bộ chuyển đổi tương tự/số (ADC) của PIC. Tùy vào từng IC cụ thể mà có các lựa chọn khác nhau, bao gồm:
‐ Lựa chọn cổng vào tương tự
‐ Chọn chân điện áp lấy mẫu (Vref)
‐ Chọn độ phân giải: 8‐bit = 0 ~ 255 hay 10‐bit = 0~1023
‐ Nguồn xung đồng hồ cho bộ ADC (trong hay ngoài), từ đó mà ta có được tốc độ lấy mẫu, thường ta chọn là internal 2‐6 us.
‐ Khi không sử dụng bộ ADC ta chọn none































Tab Analog






2.1.6. Tab Other


Tab này cho phép ta thiết lập các thông số cho các bộ Capture/Comparator/PWM.


Capture ‐ Bắt giữ


‐ Chọn bắt giữ xung theo sườn dương (rising edge) hay sườn âm (falling edge) của xung vào
‐ Chọn bắt giữ sau 1, 4 hay 16 xung (copy giá trị của TimerX vào thanh ghi lưu trữ CCCPx sau 1, 4 hay 16 xung).


Compare ‐ So sánh


‐ Ta có các lựa chọn thực hiện lệnh khi xayư ra bằng nhau giữa 2 đối tượng so sánh là giá trị của Timer1 với giá trị lưu trong thanh ghi để so sánh. Bao gồm:
o Thực hiện ngắt và thiết lập mức 0
o Thực hiện ngắt và thiết lập mức 1
o Thực hiện ngắt nhưng không thay đổi trạng thái của chân PIC.
o Đưa Timer1 về 0 nhưng không thay đổi trạng thái chân.


PWM ‐ Điều chế độ rộng xung


‐ Lựa chọn về tần số xung ra và duty cycle. Ta có thể lựa chọn sẵn hay tự chọn tần số, tất nhiên tần số ra phải nằm trong một khoảng nhất định.


Comparator ‐ So sánh điện áp


‐ Lựa chọn mức điện áp so sánh Vref. Có rất nhiều mức điện áp để ta lựa chọn. Ngoài ra ta còn có thể lựa chọn cho đầu vào của các bộ so sánh.































Tab Other






2.1.7. Tab Interrupts và Tab Driver


Tab Interrupts cho phép ta lựa chọn nguồn ngắt mà ta muốn sử dụng. Tùy vào từng loại PIC mà số lượng nguồn ngắt khác nhau, bao gồm: ngắt ngoài 0(INT0), ngắt RS232, ngắt Timer, ngắt I2C‐SPI, ngắt onchange PORTB.v.v…
Tab Drivers được dùng để lựa chọn những ngoại vi mà trình dịch đã hỗ trợ các hàm giao tiếp. Đây là nhưng ngoại vi mà ta sẽ kết nối với PIC, trong các IC mà CCS hỗ trợ, đáng chú ý là các loại EEPROM như 2404, 2416, 2432, 9346, 9356…Ngoài ra còn có IC RAM PCF8570, IC thời gian thực DS1302, Keypad 3x4, LCD, ADC… Chi tiết ta có thể xem trong thư mục Driver của chương trình: \...\PICC\Drivers





























Tab Interrupts































Tab Driver












Sau các bước chọn trên, ta nhấn OK để kết thúc quả trình tạo một Project trong CCS, một Filesten_project.c được tạo ra, chứa những khai báo cần thiết cho PIC trong một Files ten_project.h.







Sau đây là ví dụ về cấu trúc 1 chương trình trong CCS :




#include < 16F877 .h >
#device PIC6f877 *=16 ADC=10
#use delay(clock=20000000)
. . . .
Int16 a,b;
. . . .
Void xu_ly_ADC ( )
{ . . .
. . .
}


#INT_TIMER1
Void xu_ly_ngat_timer ( )
{ . . .
. . .
}


Main ( )
{ . . .
. . .
}


+ Đầu tiên là các chỉ thị tiền xử lý : # . . . có nhiệm vụ báo cho CCS cần sử dụng những gì trong chương trình C như dùng VXL gì , có dùng giao tiếp PC qua cổng COM không , có dùng ADC không , có dùng DELAY không , có biên dịch kèm các file hay không . . .
+ Các khai báo biến .
+ Các hàm con do ta viết : xu_ly_ADC () , . . .
+ Các hàm phục vụ ngắt theo sau bởi 1 chỉ thị tiền xử lý cho biết dùng ngắt nào.
+ Chương trình chính .
+ Một chương trình C có thể được viết luôn tuồn trong hàm main () , nếu chúng rất ngắn và đơn giản. Nhưng khi chương trình bắt đầu dài ra , phức tạp lên 1 chút thì phải phân chia trong các hàm con .


Các hàm này có thể là :


1/ Hàm không trả về trị.
Ví dụ :


Void xu_ly( )
{
z= x+y ;
}


Hàm trên chỉ thực hiện các lệnh trong thân hàm , khi gọi hàm này chỉ đơn giản viết :


Xu_ly( ) ;


2/ Hàm có trả về trị.
Ví dụ :


int xu_ly ( int a , int b)
{
. . . . . .
Return (a+b) ;
}


Hàm trên sẽ trả về tổng (a+b) . khi sử dụng , ví dụ tính tổng 2 biến e ,f , chương trình như sau (trong hàm main() ) :


Main()
{
Int e ,f ,g ;
e=7 ;
f= 4;
g = xu_ly(e ,f ); // giá trị g=28
}


+ Mỗi hàm con nên được viết để thực hiện 1 chức năng chuyên biệt nào đó . Bên trong 1 hàm con có thể gọi 1 hay nhiều hàm khác . Cách thức hoạt động như viết 1 chương trình C trên máy tính .
+ Nếu chương trình lớn hơn nữa có thể làm file c rất dài và do đó rất khó kiểm soát , nên sẽ cần phân chia ra các file c . trong đó file chính chứa hàm main sẽ được biên dịch . Các file c khác chứa các hàm phục vụ chuyên biệt như : cho LCD , . . .Trong file chính chỉ cần thêm dòng #include < filex.c > là tất cả hàm cần dùng chứa trong file x sẽ được biên dịch vào file hex chung. Các ví dụ trong thư mục của CCS nếu có sử dụng LCD sẽ chèn 1 dòng #include <lcd.c> và do đó sẽ gọi được các hàm trong file này mà không cần phải viết lại . điều này có nghĩa là ta có thể viết các file c chứa mã tổng quát có thể dùng chung cho nhiều project , tức là tái sử dụng mã , thay vì phải viết lại chuyên biệt cho từng project . Đây là cách làm chuyên nghiệp cho những project lớn .

Code mẫu cho PIC - Nháy LED đơn

Nhấp nháy LED có thể coi là một chương trình “Kinh điển”. Mỗi người khi bắt tay vào
học VĐK thì bài học đầu tiên là làm nhấp nháy một hay vài con LED trên chân VĐK. Trong
tài liệu này tôi cũng chọn bài tập đó để bắt đầu.
Mục đích của bài như trên đã nói: Làm nhấp nháy 8 LED tại PORTB của PIC 16F877A,
thời gian trễ do người lập trình định trước.
Những điều thu được qua bài học:
‐ Vẽ một mạch điện tử hoàn chỉnh dùng OrCad 9.2
‐ Tạo một Dự án trong CCS (cái này đã nói trong phần 2)
‐ Tệp định nghĩa các thanh ghi của PIC do người dùng tạo ra
‐ Thiết lập chế độ vào ra cho một cổng của PIC
‐ Sử dụng hàm tạo trễ thời gian

Dưới đây là sơ đồ phần cứng. Trong sơ đồ các LED được mắc chung lên dương nguồn
thông qua điện trở. Gia trị điện trở thay đổi trong khoảng 100Ω cho đến 560Ω tùy theo độ
sáng của LED mà ta muốn và cũng để đảm bảo dòng qua mỗi LED không quá 20mA khi
nguồn cấp là 5V. Như vậy để làm sáng LED ta chỉ việc đưa mức 0 ra các chân PIC và ngược
lại để tắt ta đưa mức 1.


Sơ đồ mạch nháy 8 LED tại PORTB





Sơ đồ mạch nguồn cho PIC



Mã nguồn chương trình nạp vào PIC


//================================================= =======
// Ten chuong trinh : Mach nhay den LED
// Mo ta phan cung : Dung PIC16F877A ‐ thach anh 20MHz
// : LED giao tiep voi PORTB
// : Cuc am cua LED noi voi PORTB
// : RB0 ‐ RB7 la cac chan output
//‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
// Chu thich : dung che do Power On Reset, PORTB = 00000000
// : chuong trinh viet cho PIC Tutorial
// : chuong trinh nay hoan toan mien phi va co the dung cho
// : moi muc dich khac nhau
//================================================= =======


#include <16f877a.h>
#include <def_877a.h>
#device *=16 ADC=8
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT,
NOLVP, NOCPD, NOWRT
#use delay(clock=20000000)


void main()

{
// Thiet lap che do cho PORTB
TRISB = 0x00; // Tat ca PORTB deu la cong xuat du lieu
PORTB = 0xFF; // Tat het cac LED
While(1)
{
PORTB = 0; // Cho các LED sáng
delay_ms(250); // Tạo thời gian trễ 250ms
PORTB = 0xFF;
delay_ms(250);
}
}


Qua ví dụ đơn giản trên bạn hiểu cách xuất dữ liệu ra một cổng của PIC và dùng các
hàm tạo trễ.
Thủ tục thiết lập vào ra cho một cổng hay một chân của PIC
‐ Ghi giá trị vào thanh ghi điều khiển chế độ của cổng tương ứng là TRISx
o Bit 0 ứng với chân xuất dữ liệu
o Bit 1 ứng với nhận dữ liệu
o Thanh ghi TRISx có thể câu hình theo từng bit
‐ Khi muốn xuất dữ liệu, ví dụ ra PORTB, câu lệnh là: PORTB = gia_tri;
‐ Khi muôn nhận dữ liệu từ PORTB, câu lệnh là: data_in = PORTB;
Về các hàm tạo trễ, trong CCS hỗ trọ sẵn 3 loại hàm tạo trễ là:
‐ delay_cycles(gia_tri): gia_tri là thời gian trễ tính theo số chu kỳ máy
‐ delay_us(gia_tri): Tạo trễ Micro giây
‐ delay_ms(gia_trị): Tạo trễ Mili giây
Bản chất của các hàm tạo trễ là đưa Vi điều khiển vào một vòng lặp chẳng làm gì cả cho
đủ số thời gian mà ta cần. Ngoài việc dùng hàm tạo trễ có sẵn ta có thể tự viết hàm tạo trễ
dùng bộ Timer.

Code mẫu cho PIC - Đo nhiệt độ, Hiển thị lên LCD 16x2

Bộ chuyển đổi từ tương tự sang số là một khối mạch điện tử quan trọng, có mặt trong rất nhiều thiết kế điện tử. Các bộ ADC thực tế được đóng gói trong những IC chuyên dụng, do nhiều hãng sản xuất. Điểm quan trong cần lưu ý ở các bộ ADC này là độ phân giải và tốc độ lấy mẫu tìn hiệu. Độ phân giải của bộ ADC có thể là 8‐bít, 10‐bít, 12‐bít, 16‐bít, 24‐bít… Tốc độ lấy mẫu của ADC có thể nhanh hay chậm, tùy từng ứng dụng mà ta chọn tốc độ thích hợp.
Vi điều khiển PIC là một trong những dòng Vi điều khiển có phần giao tiếp ngoại vi mạnh và đa dạng. Bên trong PIC đã được tích hợp sẵn một bộ ADC có độ phân giải tối đa là 10‐bít (tùy chon là 8‐bit hay 10‐bit). Với bộ ADC trong PIC ta có thể làm được khá nhiều công việc, dưới đây tôi trình bày một ứng dụng của bộ ADC trong việc thiết kế mạch đo nhiệt độ sử dụng sensor nhiệt LM335.

Dưới đây là phần code mạch đo nhiệt dộ, hiển thị trên LCD.


//================================================= =======
// Ten chuong trinh : Mach do nhiet do
// Mo ta phan cung : Dung PIC16F877A ‐ thach anh 20MHz
// : LCD giao tiep voi PORTD
// : Dau ra LM335 dua vao chan AN0
//‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
// Chu thich : hoac cac chu thich khac
// : dung che do Power On Reset
// : chuong trinh viet cho PIC Tutorial
//================================================= =======
#include <16F877A.h>
#include <def_877a.h>
#device *=16 adc=10
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT,
NOLVP, NOCPD, NOWRT
#use delay(clock=20000000)
#use rs232(baud=115200,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)
#include <lcd_lib_4bit.c> // Thu vien ham cho LCD
int8 low,high,key,mode,min,max,mode1,i;
int1 do_F;
void convert_bcd(int8 x);
void bao_dong();
void test();
//‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
void main()
{

float value;
on_off =1;
min =15; //nhiet do min default
max =35; //nhiet do max default
do_F =0 ;
i = 50 ;
mode =0 ;
mode1 = 0 ;
trisa = 0xFF;
trisb = 0x01;
trisd = 0x00;
LCD_init();
Printf(LCD_putchar,ʺLop DT8 ‐ BKHNʺ);
LCD_putcmd(0xC0);
Printf(LCD_putchar,ʺKhoi tao...ʺ);
// Khoi tao cho ngat ngoai
enable_interrupts (INT_EXT);
ext_int_edge(H_TO_L);
enable_interrupts (GLOBAL);
// Khoi tao che do cho bo ADC
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
delay_us(10);
// Lay mau nhiet do lan dau tien
value=(float)read_adc();
value = (value ‐ 558.5)/2.048; // For 5V supply
// value = (value ‐ 754.8)/2.048; // For 3.7V Supply
// value = (value ‐ 698.2)/2.048; // For 4V supply
convert_bcd((int8)value); // Tach so tram, chuc, donvi de hien thi len LED 7
delay_ms(1000);
LCD_putcmd(0xC0);
Printf(LCD_putchar,ʺKhoi tao xongʺ);
while(1)
{
if (i==50)
{
value = read_adc();

value=(value‐558.5)/2.048;
if (do_F==1) value=1.8*value+32;
convert_bcd((int8)value);
printf(ʺ\n\rNhiet do phong: %uʺ,value);// Gui gia tri len may tinh
LCD_putcmd(0xC0);
printf(LCD_putchar,ʺ Temp = ʺ);
LCD_putchar(high); LCD_putchar(low);
if (do_F==0) printf(LCD_putchar,ʺ Cʺ);
else printf(LCD_putchar,ʺ Fʺ);
i=0;
}
i++;
if(((int8)value > 40) || ((int8)value < 15)) on_off=1;
else
{
on_off = 0;
LCD_Putcmd(0xCF);
LCD_putchar(ʺ ʺ);
blink=0;
}
if (on_off==1)
{
if (blink==0) {
LCD_Putcmd(0xCF);LCD_putchar(ʺ!ʺ);blink=1;delay_ms(250);}
else {LCD_Putcmd(0xCF);LCD_putchar(ʺ ʺ);blink=0;delay_ms(250);}
}
}
}//end main‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐
#INT_EXT
void test()
{
if (do_F == 1) do_F=0;
else do_F=1;
}
void convert_bcd(int8 x)
{
low=x%10; //chia lay phan du, so hang don vi

high=x/10; //tach hang tram va hang chuc
low = low + 0x30;
high = high + 0x30;
}
void bao_dong(){
int8 i;
if (blink == 0) blink = 1;
else blink=0;
for(i=0;i<50;i++)
{
LCD_Putcmd(0xCF);
if (blink==0) LCD_putchar(ʺ!ʺ);
else LCD_putchar(ʺ ʺ);
}
}

Dưới đây là một sơ đồ dùng PIC và LM335 để đo nhiệt độ, hiển thị trên LCD. Trong chương trình bạn thấy có hàm chuyển đổi nhiệt độ từ ía trị độ K về độ C. Nguyên nhân có hàm đó là do con LM335 thay đổi 10mV/K, ta cần hiển thị là độ C. Nhận thấy 0oC = 273K, như vậy tại 0oC con LM335 sẽ xuất ra một điện áp là 2.73V và với điện áp này, ADC trong PIC sẽ cho giá trị số là: (2.73*1023)/5 = 558 . 5585 . Như vậy khi tính toán giá trị nhiệt độ ta cần trừ đi giá trị 558.558 này. Công thức đầy đủ là:

Do_C= [(adc_value)- 558.558] / 2.048Giá trị 2.048 có là do ta dùng ADC 10‐bit, điện áp lấy mẫu là 5V, như vậy mỗi mức lượng tử sẽ tương ứng với 5V/1024 = 4.883mV.
LM335 thay dổi 10mV/K do đó ứng với sụ thay đổi 1 độ C sẽ thay đổi 2.048 mức lượng tử (10mV/4.883mV = 2.048). Công thức trên là cho ADC 10‐bit, với các bộ ADC 8‐bit hay 12‐bit việc tính toán chuyển đổi giá trị cũng tương tự.


Mạch đo nhiệt độ LM335 hiển thị trên LCD 16x2

Code mẫu cho PIC - Truyền thông nối tiếp RS232

Việc giao tiếp giữa Vi điều khiển và máy tính là bài lập trình khá quan trọng khi ta làm việc với các dòng Vi điều khiển khác nhau. Với Vi điều khiển PIC cũng vậy, trong mỗi IC PIC đều có tích hợp một khối giao tiếp máy tính USART. Ta sử dụng khối giao tiếp này để truyền dữ liệu lên máy tính và xử lý dữ liệu đó tùy vào mục đích của người lập trình. Để nhận dữ liệu do Vi điều khiển truyền lên máy tính ta có thể sử dụng các phần mềm giao tiếp COM có sẵn hay viết một chương trình mới, sử dụng các ngôn ngữ lập trình như C++, VB hay Delphi… Trong chương trình ví dụ dưới đây tôi sử dụng công cụ sẵn có của CCS là Serial Port Monitor để truyền và nhận dữ liệu từ PIC.

Sơ đồ mạch điện ORCAD. Mạch sử dụng IC MAX232 để kết nối đến cổng COM của
máy tính. Mạch đơn giản chỉ nhằm mục đích giới thiệu khối giao tiếp máy tính của PIC và
cách lập trình cho nó trong CCS.


Trong chương trình ta có sử dụng hàm xử lý ngắt nối tiếp để xử lý ký tự nhân được từ máy
tính. Khi có ngắt xảy ra, ta gọi hàm getc() sẽ trả về ký tự vừa nhận được. Trên màn hình LCD
sẽ hiển thị ký tự mà ta gõ từ bàn phím máy tính.




Mạch giao tiếp máy tính, hiển thị LCD



Mã nguồn chương trình:


#include <16f877a.h>
#include <def_877a.h>
#use delay(clock=20000000)
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT,
NOLVP, NOCPD, NOWRT
// Khai báo sử dụng giao tiếp nối tiếp RS232
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=9)


#include <lcd_lib_4bit.c>


int8 count=0;
char string_in[16];


#INT_RDA // Hàm xử lý ngắt nối tiếp
Receive_isr() {
char c;
int8 i;
count++;
c = getc();
putc(c);
if (c==ʹcʹ | c==ʹCʹ)
{
LCD_putcmd(0x01); //Clear Screen
c=ʹcʹ;
count=0;
}
if ((count<=16) && (c!=ʹcʹ)) LCD_putchar(c);
if (count > 16)
{
count=0;
LCD_putcmd(0xC0);
}
}
void main()
{

enable_interrupts(int_rda);
enable_interrupts(GLOBAL);

lcd_init(); // Khởi tạo cho LCD
lcd_putcmd(0x01);
lcd_putcmd(line_1);
printf(ʺEnter a String.ʺ);
printf(ʺOr anything you want!ʺ);
while (1) {}
}


Mô tả chương trình: Trên đây là chương trình giao tiếp với máy tính, ta thấy trong CCS để sử dụng giao tiếp nối tiếp ta chỉ cần khai báo #use rs232(). Các hàm giao tiếp với máy tính mà CCS hỗ trợ là:
‐ putc(char ky_tu) : Gửi một ký tự ASCII lên máy tính
‐ getc() : Hàm trả về một ký tự nhận được từ máy tính
‐ printf(string): hàm gửi một chuỗi ký tự lên máy tính
DBS M05479
Quang Cao