Welcome & Happy Holidays!
Kết quả 1 đến 1 của 1
  1. #1
    Ngày tham gia
    Sep 2015
    Bài viết
    0

    Một số hàm tính toán AVR-Assembler

    Ngôn ngữ Assembler là ngôn ngữ cơ bản nhất, gần với các tập lệnh cho phép của các vi xử lý.
    Trong lập trình ứng dụng, đôi khi cần đến một số hàm tính toán mà chưa có sẵn trong vi xử lý đó,
    Mình sưu tầm vài hàm cơ bản dùng với AVR, code bằng ASM. (MUL, DIV, SQRT, ROOT...)

    Code ASM có ưu điểm là có thể tính được khá chính xác tốc độ tính toán, và có thể lựa chọn ưu tiên:
    hoặc là code nhỏ gọn (chiếm ít bộ nhớ chương trình), hoặc là tốc độ tính toán nhanh.
    Việc lựa chọn hoàn toàn do người lập trình chủ động, không phụ thuộc vào trình biên dịch.
    Hạn chế của ASM là không có cấu trúc rõ ràng như các ngôn ngữ bậc cao khác, người lập trình phải xây dựng và nắm rõ cái "khung" của chương trình định viết !

    như 2 ví dụ dưới đây:
    VD 1: hàm chia 2 số nguyên 16 bit, ưu tiên code nhỏ gọn
    (code chỉ chiếm 19 word, thực hiện trong 235-251 chu kỳ máy)


    Mã:
                                        ;***************************************************************************
                                        ;*
                                        ;* "div16u" - 16/16 Bit Unsigned Division
                                        ;*
                                        ;* This subroutine divides the two 16-bit numbers
                                        ;* "dd8uH:dd8uL" (dividend) and "dv16uH:dv16uL" (divisor).
                                        ;* The result is placed in "dres16uH:dres16uL" and the remainder in
                                        ;* "drem16uH:drem16uL".
                                        ;*
                                        ;* Number of words    :19
                                        ;* Number of cycles    :235/251 (Min/Max)
                                        ;* Low registers used    :2 (drem16uL,drem16uH)
                                        ;* High registers used  :5 (dres16uL/dd16uL,dres16uH/dd16uH,dv16uL,dv16uH,
                                        ;*                dcnt16u)
                                        ;*
                                        ;***************************************************************************
                                     
                                        ;***** Subroutine Register Variables
                                     
                                        .def    drem16uL=r14
                                        .def    drem16uH=r15
                                        .def    dres16uL=r16
                                        .def    dres16uH=r17
                                        .def    dd16uL    =r16
                                        .def    dd16uH    =r17
                                        .def    dv16uL    =r18
                                        .def    dv16uH    =r19
                                        .def    dcnt16u    =r20
                                     
                                        ;***** Code
                                     
                                        div16u:    clr    drem16uL    ;clear remainder Low byte
                                            sub    drem16uH,drem16uH;clear remainder High byte and carry
                                            ldi    dcnt16u,17    ;init loop counter
                                        d16u_1:    rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            dec    dcnt16u        ;decrement counter
                                            brne    d16u_2        ;if done
                                            ret            ;    return
                                        d16u_2:    rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_3        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_1        ;else
                                        d16u_3:    sec            ;    set carry to be shifted into result
                                            rjmp    d16u_1
    VD 2: hàm chia 2 số nguyên 16 bit, ưu tiên tốc độ tính toán - cần thiết trong một số ứng dụng
    (thực hiện trong 148-196 chu kỳ máy)


    Mã:
                                        ;***************************************************************************
                                        ;*
                                        ;* "div16u" - 16/16 Bit Unsigned Division
                                        ;*
                                        ;* This subroutine divides the two 16-bit numbers
                                        ;* "dd8uH:dd8uL" (dividend) and "dv16uH:dv16uL" (divisor).
                                        ;* The result is placed in "dres16uH:dres16uL" and the remainder in
                                        ;* "drem16uH:drem16uL".
                                        ;*
                                        ;* Number of words    :196 + return
                                        ;* Number of cycles    :148/173/196 (Min/Avg/Max)
                                        ;* Low registers used    :2 (drem16uL,drem16uH)
                                        ;* High registers used  :4 (dres16uL/dd16uL,dres16uH/dd16uH,dv16uL,dv16uH)
                                        ;*
                                        ;***************************************************************************
                                     
                                        ;***** Subroutine Register Variables
                                     
                                        .def    drem16uL=r14
                                        .def    drem16uH=r15
                                        .def    dres16uL=r16
                                        .def    dres16uH=r17
                                        .def    dd16uL    =r16
                                        .def    dd16uH    =r17
                                        .def    dv16uL    =r18
                                        .def    dv16uH    =r19
                                     
                                        ;***** Code
                                     
                                        div16u:    clr    drem16uL    ;clear remainder Low byte
                                            sub    drem16uH,drem16uH;clear remainder High byte and carry
                                     
                                            rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_1        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_2        ;else
                                        d16u_1:    sec            ;    set carry to be shifted into result
                                     
                                        d16u_2:    rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_3        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_4        ;else
                                        d16u_3:    sec            ;    set carry to be shifted into result
                                     
                                        d16u_4:    rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_5        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_6        ;else
                                        d16u_5:    sec            ;    set carry to be shifted into result
                                     
                                        d16u_6:    rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_7        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_8        ;else
                                        d16u_7:    sec            ;    set carry to be shifted into result
                                     
                                        d16u_8:    rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_9        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_10        ;else
                                        d16u_9:    sec            ;    set carry to be shifted into result
                                     
                                        d16u_10:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_11        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_12        ;else
                                        d16u_11:sec            ;    set carry to be shifted into result
                                     
                                        d16u_12:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_13        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_14        ;else
                                        d16u_13:sec            ;    set carry to be shifted into result
                                     
                                        d16u_14:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_15        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_16        ;else
                                        d16u_15:sec            ;    set carry to be shifted into result
                                     
                                        d16u_16:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_17        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_18        ;else
                                        d16u_17:    sec            ;    set carry to be shifted into result
                                     
                                        d16u_18:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_19        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_20        ;else
                                        d16u_19:sec            ;    set carry to be shifted into result
                                     
                                        d16u_20:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_21        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_22        ;else
                                        d16u_21:sec            ;    set carry to be shifted into result
                                     
                                        d16u_22:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_23        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_24        ;else
                                        d16u_23:sec            ;    set carry to be shifted into result
                                     
                                        d16u_24:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_25        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_26        ;else
                                        d16u_25:sec            ;    set carry to be shifted into result
                                     
                                        d16u_26:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_27        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_28        ;else
                                        d16u_27:sec            ;    set carry to be shifted into result
                                     
                                        d16u_28:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_29        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_30        ;else
                                        d16u_29:sec            ;    set carry to be shifted into result
                                     
                                        d16u_30:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            rol    drem16uL    ;shift dividend into remainder
                                            rol    drem16uH
                                            sub    drem16uL,dv16uL    ;remainder = remainder - divisor
                                            sbc    drem16uH,dv16uH    ;
                                            brcc    d16u_31        ;if result negative
                                            add    drem16uL,dv16uL    ;    restore remainder
                                            adc    drem16uH,dv16uH
                                            clc            ;    clear carry to be shifted into result
                                            rjmp    d16u_32        ;else
                                        d16u_31:sec            ;    set carry to be shifted into result
                                     
                                        d16u_32:rol    dd16uL        ;shift left dividend
                                            rol    dd16uH
                                            ret
    Và một số hàm khác trong file kèm theo.
    Tham khảo thêm nhiều code ASM mẫu (ADC, ISP, PWM, LCD...) tại đây,

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

 

 

Quyền viết bài

  • Bạn Không thể gửi Chủ đề mới
  • Bạn Không thể Gửi trả lời
  • Bạn Không thể Gửi file đính kèm
  • Bạn Không thể Sửa bài viết của mình
  •  
Múi giờ GMT +7. Bây giờ là 04:43 PM. Diễn đàn sử dụng vBulletin® Phiên bản 4.2.5.
Bản quyền của 2019 vBulletin Solutions, Inc. Tất cả quyền được bảo lưu.
Ban quản trị không chịu trách nhiệm về nội dung do thành viên đăng.