|
Tài trợ cho PIC Vietnam |
MPASM Lập trình bằng hợp ngữ là một việc làm vô cùng vất vả, tuy nhiên, để hiểu và làm việc với vi điều khiển, hợp ngữ trở thành một công cụ khá đắc lực ... |
|
Ðiều Chỉnh | Xếp Bài |
18-08-2008, 02:05 PM | #1 |
Nhập môn đệ tử
Tham gia ngày: Mar 2008
Bài gửi: 6
: |
Macro delay cho Pic18, sai số 1 chu kỳ lệnh
Thông thường sau khi viết chương trình bằng ASM, để sử dụng lại đoạn code đã viết cho một chương trình khác ta thường copy và paste. Bài viết này hướng dẫn viết một macro thư viện, tiện cho việc sử dụng lại các module đã viết. Và mình sẽ bắt đầu với module delay cho Pic18
Một số điểm lưu ý với macro delay này: 1. Thời gian: 1 cycles = 4 xung clock. Ví dụ: Pic hoạt động ở tần số 20Mhz tức là một giây Pic thực hiện 20*10^6 xung clock. 2. Lệnh Goto address: Lệnh này là 1 lệnh 2 words, thời gian thực hiện là 2 cycles. Khi dịch ra hex nó bao gồm 1 word... mà mình không biết (hi hi) và 1 word là lệnh NOP. Ta quan tâm đến cái NOP này. Ví dụ: Goto $+d'4' movlw d'10' Do MPASM định offset theo byte. 2 words=4bytes. Lệnh này sẽ nhảy đến vị trí lệnh kế tiếp là lệnh movlw d'10', mất 2 cycles Nếu thay lệnh trên là "Goto $+d'2' thì nó sẽ nhảy đến cái word thứ 2 của nó là NOP. Do đó lúc này để đến được lệnh movlw d'10' nó mất 3 cycles. 3. Lệnh decfsz f,d,a: Trừ thanh ghi f cho 1. Bỏ qua lệnh kế tiếp nếu kết quả bằng 0. Nếu d=0, kết quả chứa trong WREG, d=1 thì chứa trong thanh ghi f. a=0 sử dụng access bank, a=1 sử dụng BSR để tham khảo bank hiện tại. Thời gian thực hiện: f!=0--> 1cycles. f=0 -->Lệnh tiếp theo nếu là 1 word thì 2 cycles; còn nếu lệnh tiếp theo là 2 word, thời gian thực hiện sẽ là 3 cycles. Ví dụ: với d1=1 decfsz d1,d'1',d'0' Goto address Sau khi trừ thì d1=0 nó sẽ bỏ qua lệnh kế tiếp tức là word thứ 1 của lệnh goto, nó sẽ thực hiện word thứ 2 của lệnh goto... Nhưng mà hehe... mình đã nói ở trên word thứ 2 là NOP. Cho nên lúc này nó cần tới 3 cycles. Như vậy, trong cả 2 trường hợp là d1=0 và d1!=0 thì tổng thời gian thực hiện đoạn lệnh nhỏ ở trên là 3 cycles. Rồi, đủ rồi... Here we go. Các link tham khảo: http://www.piclist.com/techref/picli...egen/delay.htm http://www.piclist.com/techref/micro...ayTutorial.htm Chúng ta sẽ làm gì đầu tiên? Đầu tiên tất nhiên là suy nghĩ roài. Haizzz, giả sử như-việc viết một chương trình delay mà khi được gọi đến nó sẽ delay đúng thời gian mà ta qui định-là khả thi. Như vậy, lúc này nó bao gồm thêm một lệnh call hoặc rcall và 1 lệnh return. 2 lệnh này mỗi lệnh thực hiện trong 2 cycles. Như vậy để sử dụng được delay thì khoảng thời gian ít nhất phải là 4 cycles. Việc này tạm thời gác lại vì nó hoàn toàn có thể giải quyết được bằng macro. Vấn đề bây giờ là tìm được thuật toán để delay một khoảng thời gian thích hợp với thuật toán đó (hix...). Xét đoạn chương trình sau: decfsz d1,d'1',d'0' Goto $-d'2' Nếu d1!=0 thì nó sẽ nhảy về lệnh decfsz. Như vậy đoạn code mất tổng cộng là 3*d1 cycles. Để sử dung được lệnh này làm chương trình con tất nhiên phải có thêm: Code:
delay_1l ; nhãn của chương trình con decfsz d1,d'1',d'0' Goto $-d'2' return .... .... movlw gtth1 movwf d1 call delay_1l Xét đoạn chương trình tiếp theo: Code:
decfsz d1,d'1',d'0' Goto $-d'2' decfsz d2,d'1',d'0' Goto $-d'8' Code:
delay_2l ; nhãn của chương trình con decfsz d1,d'1',d'0' Goto $-d'2' decfsz d2,d'1',d'0' Goto $-d'8' return .... .... movlw gtth1 movwf d1 movlw gtth2 movwf d2 call delay_2l Thời gian delay thích hợp cho đoạn chương trình delay_2l là: 14 cycles<=cycles_need<=197384 cycles. .................................................. ............. Bây giờ nói đến macro. Cái macro dùng để làm gì? Nói nôm na thì nó được sử dụng để sinh mã đúng với mong muốn của người lập trình. Trong trường hợp này là: nếu cycles_need có giá trị trong một đoạn nào đó thì ta đặt một đoạn code delay tương ứng. _ Với 0<= cycles_need<= 8: ta sử dụng các lệnh goto và nop để tạo delay _ Với 9<= cycles_need<=774: ta sử dụng delay_1l _ Với 775<= cycles_need<=197384: ta sử dụng delay_2l Tham khảo về macro, các directives if...else...end, while...endw và các chỉ dẫn dành cho biên dịch trong phần help. Macro delay_cycles sẽ gọi 1 macro tương ứng tùy theo giá trị của cycles cần delay Code:
delay_cycles macro cycles if ((d'0'<=cycles)&&(cycles<=d'8')) delay_0l cycles endif if (d'9'<=cycles)&&(cycles<=d'774') delay_1l cycles endif if (d'775'<=cycles)&&(cycles<=d'197384') delay_2l cycles endif endm Code:
delay_0l macro cycles primary=cycles/d'3' remainder=cycles%d'3' while primary>d'0' goto $+d'2' primary-=d'1' endw if remainder==d'0' endif if remainder==d'1' nop endif if remainder==d'2' goto $+d'4' endif endm Code:
delay_1l macro cycles primary1=cycles/d'3' remainder=cycles%d'3' movlw primary1 movwf d1 decfsz d1 goto $-d'2' delay_0l remainder endm Code:
delay_2l macro cycles primary2=(cycles+d'768')/d'771' remainder=(cycles+d'768')%d'771' if remainder<d'3' primary2-=d'1' primary1=d'256' remainder+=d'3' else primary1=remainder/d'3' remainder=remainder%d'3' endif movlw primary2 movwf d2 movlw primary1 movwf d1 decfsz d1 goto $-d'2' decfsz d2 goto $-d'8' delay_0l remainder endm Code:
label macro [arg1,arg2...] ifndef loc_label bra end_loc_label #define loc_label location_label .... ; Đặt đoạn code cố định của macro .... .... return d'0' endif end_loc_label .... ; Đoạn code thay đổi của macro .... call location_label endm Code:
decfsz d1 goto $-d'2' decfsz d2 goto $-d'8' Code:
movlw primary2 movwf d2 movlw primary1 movwf d1 Phần việc còn lại là hoàn thiện đoạn Macro delay_0l, delay_1l, delay_2l , thêm vào delay_3l với thời gian delay lớn hơn. Thêm macro delay_us, delay_ms, và delay_s bằng cách quy đổi thời gian cần delay ra cycles. Muốn vậy thì phải thêm 1 macro được người dùng sử dụng để cho biết tần số của Pic18 được sử dụng, ta đạt là macro use_delay Code:
use_delay macro _fosc fosc=_fosc endm delay_us macro us cycles=(us*fosc)/d'4' delay_cycles cycles endm delay_ms macro ms cycles=(d'1000'*ms*fosc)/d'4' delay_cycles cycles endm delay_s macro s cycles=(d'1000000'*s*fosc)/d'4' delay_cycles cycles endm Có 3 lưu ý nhỏ khi sử các Macro này: 1> Sai số 1 cycles là do khi qui đổi từ thời gian us, ms, s; sang cycles. 2> Sau khi sử dụng các Macro này thì thanh ghi WREG bị thay đổi 3> Do chỉ sử dung "movwf f_reg" nên theo mặc định trong MPASM thì chỉ sử dụng access bank dể tham khảo đến thanh ghi d1,d2,d3. Do đó cần phải đặt 3 thanh ghi này ở bank thích hợp 4> Thời gian delay tối đa là 50,529,034 cycles. Nếu muốn thêm bạn có thể viết lại hoặc viết thêm macro delay_4l 5> Cách sử dụng Macro trên cho Pic18: sử dụng đơn giản, trước tiên phải chỉ định tần số hoạt động của Pic18, tất nhiên là không quên phần include file vào use_delay d'20' ; nếu tần số hoạt động là 20Mhz delay_us d'50' ; delay khoảng thời gian là 50 us Do không thể giải thích chi tiết về các dòng lệnh trong macro nên nếu bạn nào có thắc mắc thì cứ tự nhiên đặt câu hỏi. Thân namqn: bạn chú ý tránh sử dụng Unicode tổ hợp. thay đổi nội dung bởi: namqn, 18-08-2008 lúc 05:44 PM. Lý do: Unicode tổ hợp -> Unicode |
|
|