1. Trang chủ
  2. » Kỹ Thuật - Công Nghệ

ngôn ngữ lập trình mplab c18

70 1,7K 8

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 70
Dung lượng 1,82 MB

Nội dung

Đây là phần mềm rất hữu ích trong việc lập trình vi điều khiển PIC. Việc phát triển các trình ứng dụng lớn và chuyên nghiệp thì các trình biên dịch như CSS, Keil C chưa phù hợp. Vì thế Phần mềm MPLAB C18 sẽ giúp giải quyết các vấn đề đó một cách tốt nhất. 70 trang tài liệu sẽ giúp bạn học cách lập trình với phần mềm này một cách khá nhuần nhuyễn.

Trang 1

Mở đầu

Sau nhiều năm có mặt tại Việt Nam, hiện nay dòng vi điều khiểnPIC vẫn thể hiện ưu thế của nó Từ các ứng dụng nhỏ tới các ứng dụnglớn ta đều có thể chọn loại PIC phù hợp với ứng dụng của mình mà giáthành vẫn phù hợp

Ở Việt Nam hiện nay phát triển các ứng dụng thường sử dụng các

trình biên dịch ngôn ngữ C cho vi điều khiển như CSS, Keil C

compiler… Bởi vì lí do đơn giản là các hàm, các thư vi ện mà các trình

dịch này cung cấp tương đối đầy đủ và khá dễ sử dụng Tuy nhiên việcphát triển các trình ứng dụng lớn và mang tính chuyên nghi ệp hơn thìcác trình dịch này hầu như vẫn chưa mang lại 1 đặc tính nữa là trìnhdịch này không phải do chính hãng sản xuất phần cứng Microchipcung cấp do vậy tính mới và tính chuyên nghiệp sẽ không được cao

như chính do nhà sản xuất cung cấp

MPLAB là môi trường lập trình tích hợp do chính Microchip cung

cấp, đi kèm với nó ngôn ngữ lập trình phù hợp với từng dòng vi điềukhiển Pic16 có ngôn ngữ C16, Pic 18 có ngôn ngữ C18, Pic 30 có

C30…Theo tôi thấy các thư viện hàm, các ví dụ ứng dụng do

Microchip cung cấp khá đầy đủ và chuyên nghiệp Hiện nay việc pháttriển các ứng dụng trên nền MPLAB ở nước ta vẫn chưa phổ biến Vớimong muốn góp 1 phần nhỏ và rút ngắn thời gian học tập của các bạnmới làm quen với môi trường này Trong tài liệu này tôi xin giới thiệunhững nét chính về ngôn ngữ C18 và các ứng dụng trên dòng Pic18 sửdụng ngôn ngữ này

Trang 2

M c l c

P hần I : Ngô n Ng ữ C1 8 3

1 K i ể u dữ l i ệ u v à các g i ới hạn 3

2 Sự m ở r ộn g c ủa C1 8 9

3. #pragm a s ect i ont ype 11

4 #P ragm a i nt errupt l o w và #P ragm a i nt errupt 17

5 #P ragm a t m pdat a [ s e ct i on - nam e] 26

6 #pragm a varl oc at e ba nk vari a bl e nam e và #pragm a v arl ocat e " s ect i on -nam e" vari abl e - n am e Error! Bookmark not defined 7 #pragm a conf i g 31

8 P roces s or - Speci f i c Header F i l es 33

9 Processor-Specific Register Definitions Files 37

P hần I I : Lập t rì nh P I C18 b ằng M P L AB C1 8 38

1 Sử d ụng M P L AB 38

1.1 Q uản l í P roj ect 38

1.2 Các b ư ớ c t ạo ra f i l e.he x 40

1.3 Cửa s ổ t i ệ n í ch s ử d ụ ng t ro ng M P LAB 54

2 Ví dụ l ậ p t rì nh P i c18 b ằng C18 55

2.1 I / O cơ b ả n và del ay 56

2.2 RES ET 63

2.3 Sl eep 70

Trang 3

Phần I: Ngôn Ngữ C18

Ngôn ngữ này được xây dựng trên nền ngôn ngữ C cơ sở Chính vìvậy đối với những ai đã quen câu lệnh lập trình C rồi thì việc nắm bắt

và sử dụng nó sẽ trở nên đơn giản hơn rất nhiều

1 Kiểu dữ liệu và các giới hạn

Giống như ngôn ngữ lập trình C cơ sở và các ngôn ngữ lập trìnhkhác kiểu dữ liệu là cơ sở trong lập trình C18 có các kiểu dữ liệu sau:

Kiểu số nguyên: bảng sau trình bày các kiểu số nguyên ( tên, độ

rộng, giới hạn max-min )sử dụng trong C18

Kiểu char là kiểu mặc định trong C18 nếu ta ko khai báo kiểu dữ liệu

phía trước

Hình 1.1

Trang 4

Kiểu dấu phảy động

C18 hỗ trợ khai báo 2 kiểu dấu phảy động là float và double với chitiết về độ động, giới hạn min-max ( hình 1.2)

Ví dụ: ta khai báo

C18 lưu dữ liệu kiểu endianness

Endianness là khái niệm cơ bản trong điện tử mà ta đã làm quentrong cấu trúc máy tính: nó có nghĩa là lưu những byte ít quan trọngnhất ở vùng địa chỉ thấp nhất, và ngược lại những byte quan trọng nhấtthì ở vùng cao nhất

Ví dụ: trong trình dịch C18 ta có đoạn mã sau

Hình 1.2

Trang 5

Ta có thể thấy rằng biến l có byte DD thấp nhất thì được lưu vàotrong vùng nhớ thấp nhất, byte AA cao nhất thì được lưu vào vùng nhớcao nhất

Các lớp của vùng lưu trữ

MPLAB C18 hỗ trợ các lớp lưu trữ chuẩn ANSI như auto, extern,

register, static và typedef Chúng ra nhắc lại 1 chút về các chuẩn lưu

trữ này:

khi 1 hàm thực thi xong nó sẽ mất

là biến được khai báo kiểu extern trong file1.* có thể sử dụng

trong file2.* khi trong file2.* có l ệnh #include<file1.*>

Trang 6

x=1234; // sử dụ n g x m à ko c ần kh ai báo l ại

dụng nhiều và vì thế biến đó được lưu trong thanh ghi v ới mục

đích làm truy cập dữ liệu nhanh Khai báo này chỉ được sử dụng

trong biến formal của hàm và biến auto, nếu khai báo biến extern

dạng này thì trình dịch sẽ bỏ qua và coi như không có khai báo

register

register int x; // kh ai báo n à y t rình dịch

register char c; // sẽ coi nh ư ko có k hai b áo regist er

tron g b iến fo rmal

{

}

chỗ là lifetime (thời gian tồn tại) trong toàn bộ thời gian chạy

của chương trình Nhưng lại khác so với biến extern ở chỗ là nó

được cấp phát tĩnh (allocated statically) còn biến extern được

Trang 7

trình, tức là biến đó được cấp phát vùng nhớ trước khi chương trìnhcủa ta được chạy Còn ngược lại, cấp phát động thì biến được cấp phát

bộ nhớ trong khi thực hiện chương trình Để trực quan ta xem ví dụ:

Ngoài các định nghĩa vùng lưu trữ chuẩn ở trên MPLAB còn cung

cấp thêm 1 khai báo lưu tr ữ nữa là overlay Kiểu này chỉ áp dụng khi trình dịch hoạt động trong chế độ Non-extended và chỉ áp dụng cho biến địa phương (biến auto) Như ở trên tôi trình bày phần biến static,

vấn đề gặp phải của biến x là khi gọi lại hàm biến x giữ lại giá trị

Trang 8

được tính toán (tức là ko khởi tạo lại giá trị =0 khi gọi hàm) nhưng đôi

khi ta không muốn điều đó, vì thế biến kiểu overlay chính là giải quyết vấn đề này Tóm lại biến kiểu overlay là biến cấp phát tĩnh nhưng khi

gọi hàm thì nó sẽ được khởi tạo lại Ta xem ví dụ dưới sẽ hiểu rõ:

Ta cũng có section ( đo ạn dữ liệu lưu ở trong bộ nhớ) có thể khai

báo đặc tính kiểu overlay Tác dụng của khai báo này như th ế nào tôi

sẽ nhắc lại phía dưới

MPLAB C18 giới thiệu các qualifier far, near, rom, ram Phạm vi và

vùng nhớ dựa trên Qualifiers theo bảng sau:

Trang 9

Ví dụ:

Nếu ta khai báo:

near ram char var_mta // có nghĩa là biến var-mta lưu trong bộ nhớ ram có thể truy cập được.

Tới đây lại xuất hiện khái niệm mới về như thế nào là bộ nhớ có thểcập được và không thể Để hiểu rõ khái niệm này các bạn có thể đọc

trong cuốn PICmicro™ Mid-Range MCU Family Reference Manual Có

thể download tại đây

thường

Tóm lại: ta có thể hiểu điều này giống như lập trình C thông

thường ta có struct lồng vào trong union nhưng sự khác biệt là

struct ở đây có thể nặc danh ( tức là ko tên) Việc truy cập tới các biến trong union như cấu trúc C thông thường Thể hiện ở ví

dụ sau:

Trang 10

Nhúng code assembly vào trong chươ ng trình

MPLAB C18 cung cấp trình dịch assembler sử dụng cú pháp giống vớitrình dịch assembler MPASM Để sử dụng đoạn mã assem ta phải khai

báo như sau:

_asm [lab el :] [<instr uct io n> [ar g1[ , a rg2[ , a r g3] ] ] ]

• Ko có mặc định toán hạng mà chúng phải ghi rõ trong lệnh, nếu

ko khi dịch chương trình sẽ báo lỗi

• Hệ số mặc định là cơ số 10

Sử dụng các ký hiệu của C ví dụ: số hexa phải được viết là

0x1234 chứ ko phải là H ‘1234’ như assem thông thường

• Sau label có dấu ‘:’

Trang 11

Cú pháp định địa chỉ theo chỉ số không được hỗ trợ ở đây (nghĩa

là không được dùng []) mà phải chỉ rõ bit truy cập Ví dụ như assem thường ta viết CLRF[2] nhưng giờ phải viết CLRF 2,0

Cú pháp và tất cả các luật nhúng code assem trong code C v ừa trìnhbày ở trên được thể hiện ở ví dụ sau:

[ a t t r i b u t e - l i s t ] : là thuộc tính của section tôi sẽ nói r õ ở phần dưới

s e c t i o n - n a m e : tên của section ( do ng ười lập trình đặt)

[ = a d d r e s s ] : địa chỉ đầu tiên của section

Tất cả thuộc tính, tên, địa chỉ của section có thể có hoặc ko (đặttrong dấu ngoặc vuông), nếu khi lập tr ình không chỉ rõ (specified) thì

Trang 12

trình dịch sẽ tự động làm thay Tôi sẽ trình bày chi tiết từng phần ở

section cho mỗi kiểu bộ nhớ:

• Bộ nhớ chương trình

qualifier rom)

• Bộ nhớ dữ liệu

1 section absolute là section có địa chỉ rõ ràng thông qua khai báo

=address.

1 section assigned được gán là section đặc trưng với khai báoSECTION

1 section unassigned không phải là section absolute và assigned

Nghe có vẻ khó hiểu Ví dụ sau thể hiện các đối tượng được đặttrong bộ nhớ như thế nào để bạn có thể hiểu được sự khác nhau củacác đoạn dữ liệu:

Trang 14

ii idata bar_ic idata

Tới đây ta có thể hiểu được các kiểu bộ nhớ của Pic18 mà ta có thểchủ động lưu trữ dữ liệu vào trong đó qua các khai báo như trên

Khá là mệt khi ta phải nắm chắc được những điều này, với những

chương trình nhỏ đôi khi điều đó là không cần thiết nhưng thực

hiện những project lớn thì điều đó là cần thiết và nhất là nắm

được những điều này mới hiểu được các đoạn mã gốc mà

Microchip cung cấp cho chúng ta vì thế mới sử dụng được tốt

OK, let’s go…

• Các section mặc định

ở trên phần khai báo #pragma tôi có nói tên section có th ể ko được

khai báo bởi người lập trình Nếu điều đó xảy ra trình dịch sẽ tự động

đặt tên cho section phụ thuộc vào đó là kiểu section nào theo bảng

filename: là tên file của ta

Ví dụ: nếu tên file chương trình của ta là first_pro và kiểu section làcode thì đoạn mặc đinh sẽ có tên là code_first_pro

Trang 15

• Thuộc tính (attribute) của section

Thuộc tính của section gồm có access và overlay

access: báo cho trình dịch biết rằng section được đặt trong vùng có thể

truy cập của bộ nhớ dữ liệu ( xem chi tiết về như thế nào là bộ nhớ cóthể truy cập trong PIC 18C MCU Family Reference Manual) Biến đặt

trong access section phải được khai báo với từ khóa near Ví dụ:

# p r a g m a u d a t a a c c e s s m y _ a c c e s s

/ * a l l a c c e s s e s t o t h e s e w i l l b e u n b a n k e d * /

n e a r u n s i g n e d c h a r a v 1 , a v 2 ;

overlay: là thuộc tính cho phép section khác đư ợc đặt tại cùng địa chỉ

vật lí Thuộc tính này có thể sử dụng cùng với thuộc tính access.

Có 4 điều kiện phải thỏa mãn để có thể overlay:

1 Mỗi section phải được đặt trong file nguồn khác nhau

2 Cả 2 section phải có tên giống nhau

3 Nếu đoạn 1 được khai báo có thuộc tính access thì đoạn

2 cũng phải khai báo thuộc tính này

4 Nếu gán địa chỉ tuyệt đối cho 1 section, thì section cònlại cũng phải gán địa chỉ tuyệt đối đó

Trang 16

địa chỉ được gán sẽ là nơi lưu tr ữ đoạn mã.

Trang 17

4 #Pragma interruptlow và #Pragma interrupt

Ngắt là 1 phần quan trọng trong vi điều khiển (VĐK) giúp cho

chương trình của chúng ta rẽ nhánh và thực hiện các công việc khác

nhau, khi xảy ra ngắt VĐK con trỏ chương trình sẽ trỏ tới địa chỉ của

chương trình ngắt tương ứng ( địa chỉ của chương trình ngắt tùy thuộc

vào loại ngắt và loại VĐK, khi thực hiện lập trình với VĐK nào thì taxem datasheet của nó là biết) và thực hiện chương trình ngắt được lưu

ở đó, khi thực hiện chương trình ngắt xong nó sẽ trở lại thực hiệnchương trình main() tại địa chỉ lúc nó dừng lại ( địa chỉ này được lưu

trong stack) Vậy ta sẽ xem xét cách khai báo, khai báo mức ưu vàthực hiện chương trình ngắt trong C18 như th ế nào, go on…

#Pragma interrupt fname: khai báo hàm phục vụ ngắt mức ưu tiên

cao (high-priority ISR)

Trang 18

#Pragma interruptlow fname: khai báo chương trình phục vụ ngắt

mức ưu tiên thấp(low-priority ISR)

temporary của ISR

[s av e=s a v e - l i s t ] : Sử dụng để lưu các biến, các section Trong đó

s a v e - l i s t là danh sách các biến, các section được lưu

[n os av e=n o s a v e - l i s t ] : sử dụng để chỉ rằng compiler ko cần lưu cácbiến, các section n o s a v e - l i s t là danh sách các biến, các section ko cần

lưu

Ta sẽ tìm hiểu dần dần chi tiết từng đối tượng ở phía dưới

Với khai báo này trình dịch sẽ tạo ra biến kiểu temporary (thế nào

là biến, section kiểu temporaty tôi sẽ chỉ rõ phía dưới ) trong udata

section có tên là fname_tmp Ví dụ:

Trang 19

Với chương trình này các biến giành cho chương trình ngắt sẽ được

đặt ở trong udata section có tên là foo_tmp.

Trang 20

Như tôi đã nói ở trên biến, section kiểu temporary (nhất thời) tức là

nó chỉ xuất hiện nhất thời trong quá trình thực hiện chương trình Ví

dụ với chương trình sau:

Section kiểu temporary là dùng đ ể lưu lại các biến trung gian trongquá trình tính toán, thực hiên chương trình và các biến tmp_1, tmp_2

trong chương trình là biến kiểu temporary Và section kiểu temporary

là section có thể dùng chung giữa các hàm với nhau ( theo thuật ngữcủa C18 đó chính là section ki ểu overlay mà tôi trình bày ở trên)

Trang 21

ISR Context Saving (lưu trạng thái chương trình ngắt) sử dụng

[save=s a v e - l i s t ]

Cú pháp:

#pragma interrupt isr save=myint, section("mydata") // lệ nh này sẽ lư u biế n ‘ myint’ và section có tên là ’mydata’.

Ok, câu hỏi đặt ra cho chúng ta là t ại sao lại phải lưu trạng thái

chương trình ngắt? Và câu hỏi đầu tiên sẽ là trạng thái chương trình

ngắt là gì?

Trong khoa học máy tính, context đồng nghĩa với trạng thái (state) của

chương trình Nhiều người còn cho rằng nó là tài nguyên của CPU màchương trình đang sử dụng tại 1 thời điểm Tài nguyên này có thể là

các thanh ghi, bộ nhớ và ngoại vi

Tại sao phải lưu trạng thái chương trình ngắt???

Trong thực hiện chương trình có các tài nguyên có đặc tínhvulnerable (tính dễ bị tổn thương, hay nói cách khác là nó d ễ bị thay

đổi giá trị Ở đây tôi xin được giữ nguyên thuật ngữ vulnerable mà ko

dịch ra tiếng việt) Tài nguyên này là loại tài nguyên mà thường dùngchung giữa ISR và code chương tr ình chính Bởi vậy nếu ta ko tiến

hành lưu lại các tài nguyên này trư ớc khi thực hiện code của ISR thì

sau khi thực hiện chương trình nó sẽ thay đổi và những dữ liệu bị thay

đổi này lại được code của chương trình chính thực hiện và như vậychương trình chúng ta sau khi thực hiện ngắt sẽ chạy sai

Ví dụ: tài nguyên có tên là WREG có chức năng lưu những tính toántrung gian Giả sử khi đang thực hiện chương trình chính mà xảy rangắt mà ta ko tiến hành lưu lại WREG thì chương trình ngắt sẽ thay đổigiá trị trong tài nguyên này Vậy khi thực hiện xong chương trình ngắt

Trang 22

mà trở lại thực hiện chương trình main thì khi chương trình main đọccác dữ liệu trong này ra để thực hiện tính toán tiếp sẽ là những dữ liệusai Do vậy kết quả cuối cùng là chương trình của chúng ta thực hiệnsai.

Vậy cách giải quyết cho vấn đề này là như thế nào?

Ta có thể ngay rằng muốn chương trình ngắt ISR không làm thay

đổi giá trị các section tmpdata gốc của chương trình chính thì ta phải

có section tmpdata riêng cho nó Mà như tôi đ ã trình bày ở trên khai

báo # p r a g m a i n t e r r u p t sẽ tự động tạo ra section tmpdata cho riêngnó

Bởi vậy nên ta phải tiến hành lưu trạng thái chương trình ngắt

Tài nguyên có tính vulnerability trong thu ật ngữ của C18 chính làtài nguyên quản lí bởi trình dịch (compiler managed resource) Cónghĩa rằng là các tài nguyên này d ễ bị thay đổi trong khi thực hiện

chương trình ngắt làm sai chương trình chính vì thế cần phải quản lí

(với ý nghĩa như vậy theo tôi các loại tài nguyên này có th ể gọi là tài

nguyên được che bởi trình dịch – compiler masked sources) Bảngdưới là danh sách các tài nguyên qu ản lí bởi trình dịch:

Trang 23

7 thanh ghi đầu tiên được gọi là ‘vital’ có ngh ĩa rằng nó mặc địnhđược lưu lại trước khi thực hiện ngắt, nay nói cách khác chương tr ình

thực hiện ngắt chắc chắn sẽ thay đổi giá trị 7 thanh ghi này

Tiếp theo là các thanh ghi TBLPTR và TABLAT ( các thanh ghi

được sử dụng để truy cập bộ nhớ chương trình) Nếu bạn biết rằng ISR

ko truy cập dữ liệu rom thì bạn có thể bảo vệ trình dịch ko lưu cácthanh ghi này (phía dưới tôi sẽ trình bày cách làm thế nào để ko lưucác dữ liệu nếu ko cần thiết phải lưu)

Giống như vậy, nếu bạn biết ISR ko sử dụng con trỏ hàm, bạn cóthể ko lưu các thanh ghi PCLATH và PCLATU

MATHDATA là 1 section đ ặc biệt được sử dụng bởi thư việc math,ngoài ra nó được sử dụng trong chế độ truyền thống để thực thi những

giao diện hàm Section này nhỏ và thường bạn ko cần lo lắng về nó

Trang 24

Cuối cùng là section tmpdata ch ứa những giá trị trung gian chonhững tính toán phức tạp mà tôi đã trình bày như thế nào là sectiontemporary (.tmpdata) ở phần trên Section loại này lớn lên trong quátrình thực hiện chương trình mà chúng ta không kiểm soát được sự lớnlên của nó trong từng thời điểm.

Ta đã thấy rằng tại sao phải lưu trạng thái chương trình ngắt.Nhưng vấn đề đi kèm với lưu trạng thái ngắt sẽ là thời gian phục vụ

ngắt bị tăng lên Bởi vì trước khi thực hiện code ngắt thì phải lưu lạitrạng thái và sau khi thực hiện ngắt lại phải tiến hành khôi phục trạng

thái đã lưu lại đó Công việc này tốn khá nhiều thời gian nếu dữ liệu

cần lưu lớn Đặc biệt là trình dịch v3.0 và phiên bản cao hơn, trìnhdịch nhận dạng tài nguyên vulnerable 1 cách dè dặt(conservative), cónghĩa là nếu nó ko chứng mình được tài nguyên đó là tài nguyênvulnerable hay ko thì nó s ẽ lưu tài nguyên đó Ta xem ví d ụ sau:

Trang 25

ISR đầu tiên ko gọi hàm khác Bởi vậy trình dịch có thể phân tích

hàm isr và nhận ra các tài nguyên được sửa là các thanh ghi WREG,BSR, STATUS, TBLPTR và TABLAT Vì th ế trình dịch sẽ tự động lưucác thanh ghi này và cũng chỉ lưu các thanh ghi này

Trong chương trình thứ 2, có gọi hàm khác vì thế trình dịch không

biết rằng nó đang và sẽ sửa cái gì trong hàm foo Trong thực tế hàmfoo có thể là module riêng rẽ Bởi vậy trình dịch lưu tất cả tài nguyênquản lí bởi trình dịch (compiler managed resources) Với cơ chế hoạt

động này thì nếu section kiểu tmpdata có dữ liệu lớn thì sẽ tốn nhiều

thời gian lưu và khôi phục vì như tôi đã chỉ ra ở trên rằng section kiểu

này tăng lên trong quá tr ình thực hiện chương trình và ta ko kiểm soátđược điều này

Trang 26

Vậy nhiệm vụ tiếp theo của ta chính là phải tối ưu quá trình lưu dữliệu, tức là lưu những dữ liệu cần thiết còn những dữ liệu ko cần thiếtthì ko lưu Nó được thực hiện bằng [nos av e=n o s a v e - l i s t ]

• Chỉ rõ biến và dữ liệu ko cần lưu trong trạng thái ngắt bằng

[nosave=n o s a v e - l i s t ]

Như tôi đã trình bày ở trên khai báo này sẽ chỉ ra rằng các biến và

section trong n o s a v e - l i s t sẽ ko được lưu

#pragma interrupt foo nosave=TBLPTR, TABLAT // khai báo này sẽ ko lư u

2 thanh ghi TBLPTR, TABLAT, bở i vì 2 thanh ghi này ko đư ợ c sử dụ ng trong chư ơ ng trình main() và nó chỉ sử dụ ng trong chư ơ ng trình ngắ t vì thế ko cầ n lư u lạ i (ko

cầ n bả o vệ )

Với ngắt mức ưu tiên cao (khai báo b ằng #pragma interrupt) các vị trítài nguyên có thể không cần lưu bảo vệ là: FSR0 , TBLPTR , TBLPTRU , TABLAT ,

PCLATH , PCLATU , PROD , section(".tmpdata") , or section("MATH_DATA")

Với ngắt mức ưu tiên thấp (khai báo bằng #pragma interruptlow) các

vị trí tài nguyên có thể là không cần lưu bảo vệ là những tài nguyênvừa kể trên và thêm WREG , BSR , or STATUS

Vấn đề tiếp theo là ta xác đ ịnh section hoặc thanh ghi nào bị thay

đổi, hoặc ko bị thay đổi để có thể save hoặc nosave Chẳng nhẽ ta lại

phải đọc mã máy mà trình dịch tạo ra để xác định xem section nào bị

thay đổi Nếu bắt buộc phải làm công việc đó thì chắc chắn rằng ta

muốn tối ưu tài nguyên th ì phải mất nhiều thời gian, công sức, và nhưvậy có lẽ chẳng ai sử dụng C18 để lập trình Vậy cách giải quyết sẽ là

như thế nào Ta tìm hiểu vấn đề này tiếp sau:

5 #Pragma tmpdata [section-name]

Trang 27

Câu lệnh này sẽ thay đổi section thành section lo ại dữ liệu tmpdata

Cú pháp:

#pragma tmpdata [section-name]

[section-name] tên của section dữ liệu mà trình dịch tạo các biếntemporary

Ví dụ:

#pragma tmpdata user_tmp

// câu lệnh bên trong sẽ tạo ra các biến dạng tmpdata lưu trong section có tên làuser_tmp

#pragma tmpdata

Ta xem xét xem vấn đề tôi vừa gợi ý là làm thế nào để xác định

section nào ko thay đ ổi để không cần phải lưu Ta xét ví d ụ sau:

Trang 28

Lệnh #pragma tmpdata setporttmp….#pragma tmpdata : sẽ tạothêm 1 section kiểu tmpdata để lưu trữ dữ liệu trung gian khi thựchiện hàm SetPort().

Ở lệnh tiếp theo #pragma interruptlow low_isr nonsave(“.tmpdata”)

tạo ra section tmpdata cho chương tr ình ngắt và bảo vệ section có tên

là ‘setPorttmp’ b ởi chính vì thế mà hàm setPort() có thể được dùng

cho cả chương trình chính mà ko bị lỗi khi thực hiện Hay nói cách

khác section ‘setPorttmp’ đư ợc dùng chung cho cả chương trình ngắt

và chương trình chính

Việc tận dụng tài nguyên ở mọi nơi trong chương trình là vấn đềkhá quan trọng giúp chúng thực hiện được các Project lớn mà khôngtốn nhiều tiền chi cho tài nguyên ( Tài nguyên tôi mu ốn nói tới chính

là bộ nhớ và tốc độ xử lí) Dưới đây ta xem xét cách t ối ưu sử dụng tài

nguyên như thế nào

Tiết kiệm tài nguyên khi xử lí nhiều ngắt mức ưu tiên cao

Trong chương trình có nhiều ngắt ưu tiên cao (#pragma interrupt

), vì các

chương trình ngắt mức ưu tiên cao thì chỉ có thể kích hoạt ở 1 thờiđiểm nên có thể dùng chung các section kiểu tmpdata

Ví dụ:

void increment (int counter);

void isr1 (void);

void isr2 (void);

#pragma interrupt isr1 isr_tmp nosave=section(".tmpdata")

void isr1 (void)

Trang 29

void isr2 (void)

#pragma tmpdata isr_tmp

void increment (int counter)

{

}

#pragma tmpdata

Trong chương trình ví dụ trên ta thấy 2 chương trình ngắt mức ưu

tiên cao dùng chung section tpmdata tên là isr_tmp B ởi vì các

chương trình ngắt mức ưu tiên cao ở 1 thời điểm chỉ có thể kích hoạt 1chương trình Ta tưởng tượng rằng nếu ko có đặc tính này khi ngắt

isr1 xảy ra và chương trình phục vụ ngắt của nó đang thực hiện,

chương trình isr1() chạy vẫn chưa xong thì ngắt 2 sẽ được kích hoạtthì section ‘isr_tmp’ b ị thay đổi Như thế sau khi thực hiện xong isr2()chương trình quay lại thực hiện isr1() và sử dụng các giá trị trongsection ‘isr_tmp’ đ ã bị thay đổi chương trình isr1() thực hiện không

chính xác

Vậy với ngắt có mức ưu tiên khác nhau ở trong cùng 1 chương trình

mà chương trình ngắt ở mức ưu tiên thấp hơn thì chúng ta phải xử línhư thế nào để đảm bảo chương trình vẫn tận dụng được tài nguyên và

chức năng chương trình vẫn được đảm bảo chính xác

Ngắt lồng nhau (Nested Interrupts)

Ta xét và phân tích ví d ụ sau:

void increment (int counter);

void isr1 (void);

void isr2 (void);

Trang 30

#pragma interrupt isr1 isr_tmp save=section("isr_tmp")

#pragma tmpdata isr_tmp

void increment (int counter)

{

}

#pragma tmpdata

Ta thấy rằng section ‘isr_tmp’ ph ải được lưu lại trước khi thực hiện

chương trình ngắt vì ngắt isr2 là loại ngắt có mức ưu tiên thấp nên

trong khi thực hiện chương trình ngắt isr2() nó có thể bị ngắt đoạn

Đến đây chắc các bạn có thể tự phân tích được tại sao lại phải khaibáo chương trình như thế, tôi ko phân tích rõ chương trình này, các

bạn tự phân tích như ví d ụ trên tôi vừa phân tích sẽ thấy và hiểu rõ

Tip: tới đây bạn tự đặt câu hỏi tại sao lại phải lằng nhằng như

vậy Việc quản lí tài nguyên sao ko đ ể trình dịch tự làm Như tôi

đã phân tích ở trên rằng hiểu rõ được những điều tôi vừa trình

bày sẽ tận dụng được tối đa tài nguyên Gi ả sử ta thực hiện 1Project thì phải làm sao tận dụng tối đa tài nguyên ta có, t ức làlàm sao mà tài nguyên nh ỏ nhất ta dùng để giải quyết được bài

toán đó Như tôi đã nói ở trên tài nguyên ở đây là dung lượng bộ

Trang 31

nhớ và tốc độ xử lí chương trình Nếu ta ko hiểu rõ và ko thựchiện được những khai báo để tận dụng tối đa thì có thể ta sẽ phải

dùng VĐK có tài nguyên l ớn hơn, và như thế tốn tiền, và đôi khi

thậm chí là nhiều khi có tiền cũng ko mua được

6.#pragma config

Khai báo này cài đ ặt cấu hình để sử dụng trong các ứng dụng khác

nhau Và có thể sử dụng nhiều khai báo để cấu hình cho thiết bị

setti ng -na m e = valu e-na m e

settin g-n am e = va l ue-na m e: ứng với từng thiết bị, để tra chúng ta sử

dụng tài liệu PIC18 Configuration Settings online help Bạn có thể

dowload tài liệu tại đây

Ví dụ với P IC 18 F2 220 tra trong tài liệu ta có:

Trang 32

Dựa vào đó ta cấu hình cho P IC 18 F2 220 như sau:

Trang 33

7 Processor-Specific Header Files

Là loại file chứa những khai báo cho những thanh ghi chức năng

Trang 34

Khai báo đầu tiên nghĩa rằng PORTA là 1 byte ( kiểu unsigned

char) Modiffer extern cần thiết để khi gọi file header trong file khác thì biến mới có hiệu lực, near có nghĩa là biến PORTA được đặt trong

bộ nhớ RAM có thể truy cập Dùng khai báo này đ ể thiết lập giá trịPortA

Ví dụ:

P O R T A = 0 x 3 4 ; / * g á n g i á t r ị 0 x 3 4 t ớ i c ổ n g A * /

Tiếp theo là khai báo thứ 2 là cấu trúc nặc danh mà tôi đã trình bày

ở trên, vậy ta hiểu khai báo này như th ế nào Bạn có thể thấy các nhãnRA0, RA1….; AN0, AN1…giống với nhãn mà trong datasheet ghi Tức

là dùng khai báo này chúng ta có th ể truy cập từng bit trong portA

Ví dụ:

Trang 35

Ngoài việc sử dụng tên trực tiếp khai báo đó ta có th ể sử dụng lệnh

header của VĐK tương ứng

Trong các file header còn định nghĩa sẵn cho chúng ta các Macroassembly và ta sẵn sử dụng chúng trong lập trình Danh sách cácMacro và chức năng của chúng tôi liệt kê dưới bảng sau:

Nop()

Không thực hiện gì, chỉ là delay 1 chu kì dao

động thạch anh, thường sử dụng trong viết hàm

delayClrWdt() Clear watchdog timer

Ngày đăng: 20/10/2014, 23:22

HÌNH ẢNH LIÊN QUAN

Hình biể u thị thự c hi ệ n lệ nh Rlcf() - ngôn ngữ lập trình mplab c18
Hình bi ể u thị thự c hi ệ n lệ nh Rlcf() (Trang 36)

TỪ KHÓA LIÊN QUAN

TRÍCH ĐOẠN

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN

w