搜索
bottom↓
回复: 8

IO模拟PWM驱动无刷电机的程序,一朋友发给我的,

[复制链接]

出0入0汤圆

发表于 2010-12-1 17:03:37 | 显示全部楼层 |阅读模式
;**** **** **** **** ****
;
;Die Benutzung der Software ist mit folgenden Bedingungen verbunden:
;
;1. Da ich alles kostenlos zur Verf黦ung stelle, gebe ich keinerlei Garantie
;   und 黚ernehme auch keinerlei Haftung f黵 die Folgen der Benutzung.
;
;2. Die Software ist ausschlie遧ich zur privaten Nutzung bestimmt. Ich
;   habe nicht gepr黤t, ob bei gewerblicher Nutzung irgendwelche Patentrechte
;   verletzt werden oder sonstige rechtliche Einschr鋘kungen vorliegen.
;
;3. Jeder darf 膎derungen vornehmen, z.B. um die Funktion seinen Bed黵fnissen
;   anzupassen oder zu erweitern. Ich w黵de mich freuen, wenn ich weiterhin als
;   Co-Autor in den Unterlagen erscheine und mir ein Link zur entprechenden Seite
;   (falls vorhanden) mitgeteilt wird.
;
;4. Auch nach den 膎derungen sollen die Software weiterhin frei sein, d.h. kostenlos bleiben.
;
;!! Wer mit den Nutzungbedingungen nicht einverstanden ist, darf die Software nicht nutzen !!
;
; October 2004
; autor: Bernhard Konze
; email: bernhard.konze@versanet.de
;
;**** **** **** **** ****
; Device
;
;**** **** **** **** ****
.include "m8def.inc"
;
; 8K Bytes of In-System Self-Programmable Flash
; 512 Bytes EEPROM
; 1K Byte Internal SRAM
;**** **** **** **** ****
;**** **** **** **** ****
; fuses must be set to internal calibrated oscillator = 8 mhz
;**** **** **** **** ****
;**** **** **** **** ****

.equ MOT_BRAKE    = 0

.equ UART_CONTROL = 0
.equ RC_PULS           = 1

.equ RANGE533MS        = 0

.if RANGE533MS == 1
        .equ        MIN_RC_PULS        = 1250        ; 祍 (or lower) = NO_POWER
.else
        .equ        MIN_RC_PULS        = 1100        ; 祍 (or lower) = NO_POWER
.endif        ; RANGE533MS == 1

.include "tp-18a.inc"

.equ        CHANGE_TIMEOUT        = 1
.equ        CHANGE_TOT_LOW        = 1

.equ        POWER_RANGE        = 100                        ; full range of tcnt0 setting
.equ        MIN_DUTY        = 15                        ; no power
.equ        NO_POWER        = 256-MIN_DUTY                ; (POWER_OFF)
.equ        MAX_POWER        = 256-POWER_RANGE        ; (FULL_POWER)

.equ        PWR_MAX_RPM1        = POWER_RANGE/4
.equ        PWR_MAX_RPM2        = POWER_RANGE/2

.equ        PWR_STARTUP        = MIN_DUTY
.equ        PWR_MAX_STARTUP        = MIN_DUTY+5

.equ        timeoutSTART        = 48000
.equ        timeoutMIN        = 36000

.equ        T1STOP        = 0x00
.equ        T1CK8        = 0x02

.equ        EXT0_DIS        = 0x00        ; disable ext0int
.if RC_PULS == 1
.equ        EXT0_EN                = 0x40        ; enable ext0int
.else
.equ        EXT0_EN                = 0x00        ; disable ext0int
.endif

.equ        OCT1_RANGE1        = 16        ; ( ~2400 RPM )
.equ        OCT1_RANGE2        = 8        ; ( ~4800 RPM )

.equ        PWR_RANGE1        = 0x40        ; ( ~2400 RPM )
.equ        PWR_RANGE2        = 0x20        ; ( ~4800 RPM )

.equ        ENOUGH_GOODIES        = 60

;**** **** **** **** ****
; Register Definitions
.def        i_sreg                 = r1        ; status register save in interrupts
.def        tcnt0_power_on         = r2        ; timer0 counts nFETs are switched on
.def        tcnt0_change_tot = r3        ; when zero, tcnt0_power_on is changed by one (inc or dec)
;.def        ...                  = r4        ; upper 8bit timer1 (software-) register
.def        uart_cnt         = r5
.def        tcnt0_pwron_next = r6

.def        start_rcpuls_l         = r7
.def        start_rcpuls_h         = r8
;.def                          = r9
;.def                         = r10
.def        rcpuls_timeout         = r11
.equ        RCP_TOT                 = 100

.def        current_err         = r12        ; counts consecutive current errors
.equ        CURRENT_ERR_MAX  = 3        ; performs a reset after MAX errors

.def        sys_control         = r13
.def        t1_timeout         = r14
.def        run_control         = r15


.def        temp1        = r16                        ; main temporary
.def        temp2        = r17                        ; main temporary
.def        temp3        = r18                        ; main temporary
.def        temp4        = r19                        ; main temporary

.def        i_temp1        = r20                        ; interrupt temporary
.def        i_temp2        = r21                        ; interrupt temporary
.def        i_temp3        = r22                        ; interrupt temporary

.def        flags0        = r23        ; state flags
        .equ        OCT1_PENDING        = 0        ; if set, output compare interrunpt is pending
        .equ        UB_LOW                 = 1        ; set if accu voltage low
        .equ        I_pFET_HIGH        = 2        ; set if over-current detect
        .equ        GET_STATE        = 3        ; set if state is to be send
        .equ        C_FET                = 4        ; if set, C-FET state is to be changed
        .equ        A_FET                = 5        ; if set, A-FET state is to be changed
             ; if neither 1 nor 2 is set, B-FET state is to be changed
        .equ        I_OFF_CYCLE        = 6        ; if set, current off cycle is active
        .equ        T1OVFL_FLAG        = 7        ; each timer1 overflow sets this flag - used for voltage + current watch

.def        flags1        = r24        ; state flags
        .equ        POWER_OFF        = 0        ; switch fets on disabled
        .equ        FULL_POWER        = 1        ; 100% on - don't switch off, but do OFF_CYCLE working
        .equ        CALC_NEXT_OCT1        = 2        ; calculate OCT1 offset, when wait_OCT1_before_switch is called
        .equ        RC_PULS_UPDATED        = 3        ; new rc-puls value available
        .equ        EVAL_RC_PULS        = 4        ; if set, new rc puls is evaluated, while waiting for OCT1
        .equ        EVAL_SYS_STATE        = 5        ; if set, overcurrent and undervoltage are checked
        .equ        EVAL_RPM        = 6        ; if set, next PWM on should look for current
        .equ        EVAL_UART        = 7        ; if set, next PWM on should look for uart

.def        flags2        = r25
        .equ        RPM_RANGE1        = 0        ; if set RPM is lower than 1831 RPM
        .equ        RPM_RANGE2        = 1        ; if set RPM is between 1831 RPM and 3662 RPM
        .equ        SCAN_TIMEOUT        = 2        ; if set a startup timeout occurred
        .equ        POFF_CYCLE        = 3        ; if set one commutation cycle is performed without power
        .equ        COMP_SAVE        = 4        ; if set ACO was high
        .equ        STARTUP                = 5        ; if set startup-phase is active
        .equ        RC_INTERVAL_OK        = 6        ;
        .equ        GP_FLAG                = 7        ;

; here the XYZ registers are placed ( r26-r31)

; ZH = new_duty                ; PWM destination


;**** **** **** **** ****
; RAM Definitions
.dseg                                        ;EEPROM segment
.org SRAM_START

tcnt1_sav_l:        .byte        1        ; actual timer1 value
tcnt1_sav_h:        .byte        1
last_tcnt1_l:        .byte        1        ; last timer1 value
last_tcnt1_h:        .byte        1
timing_l:                .byte        1        ; holds time of 4 commutations
timing_h:                .byte        1
timing_x:                .byte        1

timing_acc_l:        .byte        1        ; holds the average time of 4 commutations
timing_acc_h:        .byte        1
timing_acc_x:        .byte        1

rpm_l:                        .byte        1        ; holds the average time of 4 commutations
rpm_h:                        .byte        1
rpm_x:                        .byte        1



wt_comp_scan_l:        .byte        1        ; time from switch to comparator scan
wt_comp_scan_h:        .byte        1      
com_timing_l:        .byte        1        ; time from zero-crossing to switch of the appropriate FET
com_timing_h:        .byte        1
wt_OCT1_tot_l:        .byte        1        ; OCT1 waiting time
wt_OCT1_tot_h:        .byte        1
zero_wt_l:                .byte        1
zero_wt_h:                .byte        1
last_com_l:                .byte        1
last_com_h:                .byte        1

stop_rcpuls_l:        .byte        1
stop_rcpuls_h:        .byte        1
new_rcpuls_l:        .byte        1
new_rcpuls_h:        .byte        1

duty_offset:        .byte        1
goodies:                .byte        1
comp_state:                .byte        1
gp_cnt:                        .byte        1

uart_data:        .byte        100                ; only for debug requirements


;**** **** **** **** ****
; ATmega8 interrupts

;.equ        INT0addr=$001        ; External Interrupt0 Vector Address
;.equ        INT1addr=$002        ; External Interrupt1 Vector Address
;.equ        OC2addr =$003        ; Output Compare2 Interrupt Vector Address
;.equ        OVF2addr=$004        ; Overflow2 Interrupt Vector Address
;.equ        ICP1addr=$005        ; Input Capture1 Interrupt Vector Address
;.equ        OC1Aaddr=$006        ; Output Compare1A Interrupt Vector Address
;.equ        OC1Baddr=$007        ; Output Compare1B Interrupt Vector Address
;.equ        OVF1addr=$008        ; Overflow1 Interrupt Vector Address
;.equ        OVF0addr=$009        ; Overflow0 Interrupt Vector Address
;.equ        SPIaddr =$00a        ; SPI Interrupt Vector Address
;.equ        URXCaddr=$00b        ; USART Receive Complete Interrupt Vector Address
;.equ        UDREaddr=$00c        ; USART Data Register Empty Interrupt Vector Address
;.equ        UTXCaddr=$00d        ; USART Transmit Complete Interrupt Vector Address
;.equ        ADCCaddr=$00e        ; ADC Interrupt Vector Address
;.equ        ERDYaddr=$00f        ; EEPROM Interrupt Vector Address
;.equ        ACIaddr =$010        ; Analog Comparator Interrupt Vector Address
;.equ        TWIaddr =$011        ; Irq. vector address for Two-Wire Interface
;.equ        SPMaddr =$012        ; SPM complete Interrupt Vector Address
;.equ        SPMRaddr =$012        ; SPM complete Interrupt Vector Address
;-----bko-----------------------------------------------------------------

;**** **** **** **** ****
.cseg
.org 0
;**** **** **** **** ****

;-----bko-----------------------------------------------------------------
; reset and interrupt jump table
                rjmp        reset
.if RC_PULS == 1
                rjmp        ext_int0
.else
                nop        ; int0
.endif        ; RC_PULS == 1
                nop        ; ext_int1
                nop        ; t2oc_int
                nop        ; t2ovfl_int
                nop        ; icp1
                rjmp        t1oca_int
                nop        ; t1ocb_int
                rjmp        t1ovfl_int
                rjmp        t0ovfl_int
                nop        ; spi_int
                nop        ; urxc
                nop        ; udre
.if UART_CONTROL == 1
                rjmp        utxc
.else
                nop        ; utxc
.endif        ; UART_CONTROL == 1
; not used        nop        ; adc_int
; not used        nop        ; eep_int
; not used        nop        ; aci_int
; not used        nop        ; wire2_int
; not used        nop        ; spmc_int


version:        .db        0x0d, 0x0a
                .db        "tp18a410r05 "
version_end:        .db        0x0d, 0x0a


;-----bko-----------------------------------------------------------------
; init after reset

reset:               
                ldi                temp1, high(RAMEND)        ; stack = RAMEND
                out                SPH, temp1
                ldi                temp1, low(RAMEND)
                out         SPL, temp1
        ; oscillator calibration byte is written into the uppermost position
        ; of the eeprom - by the script 1n1p.e2s an ponyprog
;CLEARBUFFER
;LOAD-PROG 1n1p.hex
;PAUSE "Connect and powerup the circuit, are you ready?"
;READ-CALIBRATION 0x21FF DATA 3     # <EEProm 8Mhz
;ERASE-ALL
;WRITE&VERIFY-ALL
                ldi         temp1,0x01
                out                EEARH,temp1
                ldi                temp1,$ff
                out                EEARL,temp1
                sbi                EECR,EERE
                in                temp1,EEDR
                out         osccal ,temp1  ;schreiben

        ; portB - all FETs off
                ldi                temp1, INIT_PB                ; PORTB initially holds 0x00
                out                PORTB, temp1
                ldi                temp1, DIR_PB
                out                DDRB, temp1

        ; portC reads comparator inputs
                ldi                temp1, INIT_PC
                out                PORTC, temp1
                ldi                temp1, DIR_PC
                out                DDRC, temp1

        ; portD reads rc-puls + AIN0 ( + RxD, TxD for debug )
                ldi                temp1, INIT_PD
                out                PORTD, temp1
                ldi                temp1, DIR_PD
                out                DDRD, temp1

        ; timer0: PWM + beep control = 0x02         ; start timer0 with CK/8 (1祍/count)
                ldi                temp1, 0x02
                out                TCCR0, temp1

        ; timer1: commutation control = 0x02        ; start timer1 with CK/8 (1祍/count)
                ldi                temp1, T1CK8
                out                TCCR1B, temp1

        ; reset state flags
                clr                flags0
                clr                flags1
                clr                flags2

        ; clear RAM
                clr                XH
                ldi                XL, low (SRAM_START)
                clr                temp1
clear_ram:
                st                X+, temp1
                cpi                XL, uart_data+1
                brlo        clear_ram

        ; power off
                rcall        switch_power_off

        ; reset rc puls timeout
                ldi                temp1, RCP_TOT
                mov                rcpuls_timeout, temp1
               
.if UART_CONTROL == 1

                ldi                ZH,high(version*2)
                ldi                ZL,low(version*2)

        ;**** UART Initialization ****
                ldi                temp1, 0        ; set to 38400baud (8MHz)
                out                UBRRH, temp1
                ldi                temp1, 12
                out                UBRRL, temp1
                ldi                temp1, 0x18
                out                UCSRB, temp1        ; enable rx+tx - no interrupts !
                in                 temp1, UDR        ; clear possibly pending rxc
                ldi                temp1, 0
                mov                uart_cnt, temp1

                lpm
                adiw        ZL,1                ;increment Z-pointer
                mov                temp1, r0        ; (1)
                rcall        send_byte
.endif
                rcall        wait260ms        ; wait a while
                rcall        wait260ms

.if UART_CONTROL == 1
                lpm
                adiw        ZL,1                ;increment Z-pointer
                mov                temp1, r0        ; (2)
                rcall        send_byte
.endif

                rcall        beep_f1
                rcall        wait30ms
                rcall        beep_f2
                rcall        wait30ms
                rcall        beep_f3
                rcall        wait30ms

.if UART_CONTROL == 1
                lpm
                adiw        ZL,1                ;increment Z-pointer
                mov                temp1, r0        ; b (3)
                rcall        send_byte
                lpm
                adiw        ZL,1                ;increment Z-pointer
                mov                temp1, r0        ; k (4)
                rcall        send_byte
.endif

control_start:        ; init variables
                ldi                temp1, CHANGE_TIMEOUT
                mov                tcnt0_change_tot, temp1
                ldi                temp1, NO_POWER
                mov                tcnt0_power_on, temp1

                ldi                temp1, 0                ; reset error counters
                mov                current_err,temp1
                mov                sys_control, temp1

        ; init registers and interrupts
                ldi                temp1, (1<<TOIE1)+(1<<OCIE1A)+(1<<TOIE0)
                out                TIFR, temp1                ; clear TOIE1,OCIE1A & TOIE0
                out                TIMSK, temp1                ; enable TOIE1,OCIE1A & TOIE0 interrupts

.if UART_CONTROL == 1
                lpm
                adiw        ZL,1                ;increment Z-pointer
                mov                temp1, r0        ; (5)
                rcall        send_byte
.endif

                sei                                ; enable all interrupts

.if RC_PULS == 1
; init rc-puls
                ldi                temp1, (1<<ISC01)+(1<<ISC00)
                out                MCUCR, temp1                ; set next int0 to rising edge
                ldi                temp1, EXT0_EN                ; enable ext0int
                out                GIMSK, temp1
i_rc_puls1:       
                ldi                temp3, 10                ; wait for this count of receiving power off
i_rc_puls2:       
                sbrs        flags1, RC_PULS_UPDATED
                rjmp        i_rc_puls2
                lds                temp1, new_rcpuls_l           ;新的占空比数据
                lds                temp2, new_rcpuls_h
                cbr                flags1, (1<<RC_PULS_UPDATED) ; rc impuls value is read out
                subi        temp1, low  (MIN_RC_PULS)        ; power off received ?
                sbci        temp2, high (MIN_RC_PULS)
                brcc        i_rc_puls1                ; no - reset counter
                dec                temp3                        ; yes - decrement counter
                brne        i_rc_puls2                ; repeat until zero
                cli                                ; disable all interrupts
                rcall        beep_f4                        ; signal: rcpuls ready
                rcall        beep_f4
                rcall        beep_f4
                sei                                ; enable all interrupts
.endif

.if UART_CONTROL == 1
                ldi                temp2, (version_end*2)-(version*2)-3
v_str_rest:        lpm
                adiw        ZL,1                ;increment Z-pointer
                mov                temp1, r0
                rcall        send_byte
                dec                temp2
                brne        v_str_rest

                cli                                ; disable all interrupts
                rcall        wait260ms
                rcall        beep_f4                        ; signal: rcpuls ready
                rcall        beep_f4
                rcall        beep_f4
                sei                                ; enable all interrupts
.endif

                ldi                temp1, 30
                sts                duty_offset, temp1

                rcall        set_all_timings

                rjmp        init_startup
               
;-----bko-----------------------------------------------------------------
; external interrupt0 = rc pulse input
.if RC_PULS == 1
ext_int0:
                in                i_sreg, SREG
                clr                i_temp1                        ; disable extint edge may be changed
                out                GIMSK, i_temp1

; evaluate edge of this interrupt
                in                i_temp1, MCUCR
                sbrs        i_temp1, ISC00
                rjmp        falling_edge                ; bit is clear = falling edge

; should be rising edge - test rc impuls level state for possible jitter
                sbis        PIND, rcp_in
                rjmp        extint1_exit                ; jump, if low state

; rc impuls is at high state
                ldi                i_temp1, (1<<ISC01)
                out                MCUCR, i_temp1                ; set next int0 to falling edge

; get timer1 values
                in                i_temp1, TCNT1L
                in                i_temp2, TCNT1H
                mov                start_rcpuls_l, i_temp1
                mov                start_rcpuls_h, i_temp2
; test rcpulse interval
                cbr                flags2, (1<<RC_INTERVAL_OK) ; preset to not ok
                lds                i_temp3, stop_rcpuls_l
                sub                i_temp1, i_temp3
                lds                i_temp3, stop_rcpuls_h
                sbc                i_temp2, i_temp3
                cpi                i_temp1, low (25000)
                ldi                i_temp3, high(25000)        ; test range high
                cpc                i_temp2, i_temp3
                brsh        extint1_fail                ; through away
                cpi                i_temp1, low (15000)
                ldi                i_temp3, high(15000)        ; test range low
                cpc                i_temp2, i_temp3
                brlo        extint1_fail                ; through away
                sbr                flags2, (1<<RC_INTERVAL_OK) ; set to rc impuls value is ok !
                rjmp        extint1_exit

extint1_fail:       
                tst                rcpuls_timeout
                breq        extint1_exit
                dec                rcpuls_timeout
                rjmp        extint1_exit

; rc impuls is at low state
falling_edge:       
                sbic        PIND, rcp_in                ; test level of rc impuls
                rjmp        extint1_exit                ; seems to be a spike

                ldi                i_temp1, (1<<ISC01)+(1<<ISC00)
                out                MCUCR, i_temp1                ; set next int0 to rising edge
                sbrc        flags1, RC_PULS_UPDATED
                rjmp        extint1_exit

; get timer1 values
                in                i_temp1, TCNT1L
                in                i_temp2, TCNT1H
                sts                stop_rcpuls_l, i_temp1        ; prepare next interval evaluation
                sts                stop_rcpuls_h, i_temp2

                sbrs        flags2, RC_INTERVAL_OK
                rjmp        extint1_exit
                cbr                flags2, (1<<RC_INTERVAL_OK) ; flag is evaluated

                sub                i_temp1, start_rcpuls_l
                sbc                i_temp2, start_rcpuls_h

        ; save impuls length
                sts                new_rcpuls_l, i_temp1
                sts                new_rcpuls_h, i_temp2
                cpi                i_temp1, low (2200)
                ldi                i_temp3, high(2200)        ; test range high
                cpc                i_temp2, i_temp3
                brsh        extint1_fail                ; through away
                cpi                i_temp1, low (800)
                ldi                i_temp3, high(800)        ; test range low
                cpc                i_temp2, i_temp3
                brlo        extint1_fail                ; through away
                sbr                flags1, (1<<RC_PULS_UPDATED) ; set to rc impuls value is ok !
                mov                i_temp1, rcpuls_timeout
                cpi                i_temp1, RCP_TOT
                breq        extint1_exit
                inc                rcpuls_timeout

; enable int1 again -  also entry for spike detect
extint1_exit:
                ldi                i_temp2, EXT0_EN
                out                GIMSK, i_temp2
                out                SREG, i_sreg
                reti
.endif  ; RC_PULS == 1
;-----bko-----------------------------------------------------------------
; output compare timer1 interrupt
t1oca_int:
                in                i_sreg, SREG
                cbr                flags0, (1<<OCT1_PENDING) ; signal OCT1 passed
                out                SREG, i_sreg
                reti
;-----bko-----------------------------------------------------------------
; overflow timer1 / happens all 65536祍
t1ovfl_int:
                in                i_sreg, SREG
                sbr                flags0, (1<<T1OVFL_FLAG)
                tst                t1_timeout
                breq        t1ovfl_10
                dec                t1_timeout
t1ovfl_10:
.if RC_PULS == 1
                tst                rcpuls_timeout
                breq        t1ovfl_99
                dec                rcpuls_timeout
.endif

t1ovfl_99:       
                out                SREG, i_sreg
                reti
;-----bko-----------------------------------------------------------------
; timer0 overflow interrupt
t0ovfl_int:
                in                i_sreg, SREG
                sbrc        flags0, I_OFF_CYCLE
                rjmp        t0_on_cycle

t0_off_cycle:
                sbr                flags2, (1<<COMP_SAVE)  ;中断里查询比较器状态,
                sbic        ACSR, ACO                ; mirror inverted ACO to bit-var
                cbr                flags2, (1<<COMP_SAVE)

        ; changes in PWM ?
                mov                i_temp1, tcnt0_power_on
                mov                i_temp2, tcnt0_pwron_next
                cp                i_temp2, i_temp1
                brsh        lower_pwm                ; 大于等于跳转next power-on-time is lower or same
higher_pwm:
                dec                tcnt0_change_tot        ; change-timeout passed ?
                brne        nFET_off                    ; .. no
                ldi                i_temp2, CHANGE_TIMEOUT        ; .. yes - change-timeout for more power
                mov                tcnt0_change_tot, i_temp2 ; reset change-timeout and decrement
                dec                i_temp1                                    ; <dec> increases power-on-time
                rjmp        set_next_pwm

lower_pwm:
                breq        nFET_off                ; pwm is unchanged 相等跳转
                dec                tcnt0_change_tot        ; change-timeout passed ?
                brne        nFET_off                ; .. no
                ldi                i_temp2, CHANGE_TOT_LOW ; .. yes - change-timeout for lower power
                mov                tcnt0_change_tot, i_temp2 ; reset change-timeout and increment
                inc                i_temp1                        ; <inc> decreases power-on-time

set_next_pwm:
                mov                tcnt0_power_on, i_temp1

nFET_off:
                sbr                flags0, (1<<I_OFF_CYCLE) ; PWM state = off cycle  PWM关断周期
        ; switch appropriate nFET off
                sbrs        flags0, C_FET
                rjmp        test_AnFET
; C_FET is active
                sbrs        flags1, FULL_POWER  
                CnFET_off                ; Cn off
                rjmp        reload_t0_off_cycle
test_AnFET:
                sbrs        flags0, A_FET
                rjmp        switch_BnFET
; A_FET is active
switch_AnFET:
`                sbrs        flags1, FULL_POWER
                AnFET_off                ; An off
                rjmp        reload_t0_off_cycle
; B_FET is active
switch_BnFET:
                sbrs        flags1, FULL_POWER
                BnFET_off                ; Bn off
        ; reload timer0 with the appropriate value
reload_t0_off_cycle:
                mov                i_temp1, tcnt0_power_on
                subi        i_temp1, -POWER_RANGE        ; adi i_temp1, POWER_RANGE
                com                i_temp1                        ; timer0 increments
                out                TCNT0, i_temp1
                rjmp        t0_int_exit
; reload timer90 + switch appropriate nFET on
t0_on_cycle:
                mov                i_temp1, tcnt0_power_on
                out                TCNT0, i_temp1                ; reload t0
                cbr                flags0, (1<<I_OFF_CYCLE) ; PWM state = on cycle (no off cycle)
; switch appropriate nFET on
nFET_on:
                sbrs        flags0, C_FET                ; is Cn choppered ?
                rjmp        test_AnFET_on                        ; .. no - test An
                sbrs        flags1, POWER_OFF
                CnFET_on                ; Cn on
                rjmp        eval_power_state
test_AnFET_on:
                sbrs        flags0, A_FET                ; is An choppered ?
                rjmp        sw_BnFET_on                        ; .. no - Bn has to be choppered
                sbrs        flags1, POWER_OFF
                AnFET_on                ; An on
                rjmp        eval_power_state
sw_BnFET_on:
                sbrs        flags1, POWER_OFF
                BnFET_on                ; Bn on

        ; evaluate power state
eval_power_state:
                cpi                i_temp1, MAX_POWER+1
                brsh        not_full_power
                ; FULL POWER
                sbr                flags1, (1<<FULL_POWER)        ; tcnt0_power_on = MAX_POWER means FULL_POWER
                cbr                flags1, (1<<POWER_OFF)  ;;100%
                rjmp        t0_int_exit
not_full_power:

                cpi                i_temp1, NO_POWER
                brlo        neither_full_nor_off
                ; POWER OFF
                cbr                flags1, (1<<FULL_POWER)        ; tcnt0_power_on = NO_POWER means power off
                sbr                flags1, (1<<POWER_OFF)   ;;停转,
                rjmp        t0_int_exit

neither_full_nor_off:
                cbr                flags1, (1<<FULL_POWER)        ; tcnt0_power_on = MAX_POWER means FULL_POWER
                cbr                flags1, (1<<POWER_OFF)   ;;1% --- 99%

t0_int_exit:
                sbrc        flags2, POFF_CYCLE
                sbr                flags1, (1<<POWER_OFF)
                out                SREG, i_sreg
                reti
;-----bko-----------------------------------------------------------------
.if UART_CONTROL == 1
utxc:       
                in                i_sreg, SREG
                ld                i_temp1,X+
                out                UDR, i_temp1
                dec                uart_cnt
                brne        utxc_90
                cbi                UCSRB, TXCIE                ; disable irq
utxc_90:       
                out                SREG, i_sreg
                reti
.endif        ; UART_CONTROL == 1
;-----bko-----------------------------------------------------------------
; beeper: timer0 is set to 1祍/count
beep_f1:
                ldi                temp4, 200
                ldi                temp2, 80
                rjmp        beep

beep_f2:
                ldi                temp4, 180
                ldi                temp2, 100
                rjmp        beep

beep_f3:       
                ldi                temp4, 160
                ldi                temp2, 120
                rjmp        beep

beep_f4:       
                ldi                temp4, 100
                ldi                temp2, 200
                rjmp        beep

beep:               
                clr                temp1
                out                TCNT0, temp1
                BpFET_on                ; BpFET on
                AnFET_on                ; CnFET on
beep_BpCn10:
                in                temp1, TCNT0
                cpi                temp1, 32                ; 32祍 on
                brne        beep_BpCn10
                BpFET_off                ; BpFET off
                AnFET_off                ; CnFET off
                ldi                temp3, 8                ; 2040祍 off
beep_BpCn12:
                clr                temp1
                out                TCNT0, temp1
beep_BpCn13:
                in                temp1, TCNT0
                cp                temp1, temp4
                brne        beep_BpCn13
                dec                temp3
                brne        beep_BpCn12
                dec                temp2
                brne        beep
                ret

wait30ms:
                ldi                temp2, 15
beep_BpCn20:
                ldi                temp3, 8
beep_BpCn21:
                clr                temp1
                out                TCNT0, temp1
beep_BpCn22:
                in                temp1, TCNT0
                cpi                temp1, 255
                brne        beep_BpCn22
                dec                temp3
                brne        beep_BpCn21
                dec                temp2
                brne        beep_BpCn20
                ret

        ; 128 periods = 261ms silence
wait260ms:
                ldi                temp2, 128
beep2_BpCn20:
                ldi                temp3, 8
beep2_BpCn21:
                clr                temp1
                out                TCNT0, temp1
beep2_BpCn22:
                in                temp1, TCNT0
                cpi                temp1, 255
                brne        beep2_BpCn22
                dec                temp3
                brne        beep2_BpCn21
                dec                temp2
                brne        beep2_BpCn20
                ret
;-----bko-----------------------------------------------------------------
tcnt1_to_temp:
                ldi                temp4, EXT0_DIS                ; disable ext0int
                out                GIMSK, temp4
                ldi                temp4, T1STOP                ; stop timer1
                out                TCCR1B, temp4
                ldi                temp4, T1CK8                ; preload temp with restart timer1
                in                temp1, TCNT1L                ;  - the preload cycle is needed to complete stop operation
                in                temp2, TCNT1H
                out                TCCR1B, temp4
                ret                                ; !!! ext0int stays disabled - must be enabled again by caller
        ; there seems to be only one TEMP register in the AVR
        ; if the ext0int interrupt falls between readad LOW value while HIGH value is captured in TEMP and
        ; read HIGH value, TEMP register is changed in ext0int routine
;-----bko-----------------------------------------------------------------
.if RC_PULS == 1
evaluate_rc_puls:
                cbr                flags1, (1<<EVAL_RC_PULS)
                sbrs        flags1, RC_PULS_UPDATED
                rjmp        eval_rc_p90
                lds                temp1, new_rcpuls_l
                lds                temp2, new_rcpuls_h
                cbr                flags1, (1<<RC_PULS_UPDATED) ; rc impuls value is read out
                subi        temp1, low  (MIN_RC_PULS)
                sbci        temp2, high (MIN_RC_PULS)
                brcc        eval_rc_p00
                clr                temp1
                clr                temp2
eval_rc_p00:
                lsr                temp2
                ror                temp1
                lsr                temp2
                ror                temp1

.if RANGE533MS == 1        ; full rc-pulse-range is lower than 800ms - make 533ms range
        ; actual (0-533) -> (0-133)
                mov                temp3, temp1        ; (0-133) -> (0-100)
                lsr                temp3
                lsr                temp3
                sub                temp1, temp3
.else
        ; actual (0-800) -> (0-200)
                lsr                temp2                ; (0-200) -> (0-100)
                ror                temp1

.endif        ; RANGE533MS == 1

                mov                temp3, temp1               
                subi        temp1, POWER_RANGE
                brcs        eval_rc_p10
                ldi                temp3, POWER_RANGE
eval_rc_p10:
                mov                ZH, temp3
eval_rc_p90:
                ret
.endif        ; RC_PULS == 1
;-----bko-----------------------------------------------------------------
evaluate_uart:
                cbr                flags1, (1<<EVAL_UART)
.if UART_CONTROL == 1
                sbic        UCSRA, RXC
                rcall        read_uart
.endif        ; UART_CONTROL == 1
                ret
;-----bko-----------------------------------------------------------------
evaluate_sys_state:
                cbr                flags1, (1<<EVAL_SYS_STATE)
                sbrs        flags0, T1OVFL_FLAG
                rjmp        eval_sys_s99

        ; do it not more often as every 65祍
                cbr        flags0, (1<<T1OVFL_FLAG)

        ; control current
eval_sys_i:
                sbrs        flags0, I_pFET_HIGH
                rjmp        eval_sys_i_ok
                cbr                flags0, (1<<I_pFET_HIGH)
                mov                i_temp1, current_err
                cpi                i_temp1, CURRENT_ERR_MAX
                brcc        panic_exit
                inc                current_err
                rjmp        eval_sys_ub

eval_sys_i_ok:
                tst                current_err
                breq        eval_sys_ub
                dec                current_err

        ; control voltage
eval_sys_ub:
                sbrs        flags0, UB_LOW
                rjmp        eval_sys_ub_ok
                cbr                flags0, (1<<UB_LOW)
                mov                i_temp1, sys_control
                cpi                i_temp1, POWER_RANGE
                brcc        eval_sys_s99
                inc                sys_control
                rjmp        eval_sys_s99

eval_sys_ub_ok:
                tst                sys_control
                breq        eval_sys_s99
                dec                sys_control
               
eval_sys_s99:
                rcall        set_new_duty
                ret

panic_exit:        ; !!!!!! OVERCURRENT !!!!!!!!
                cli
                rjmp        reset
;-----bko-----------------------------------------------------------------
evaluate_rpm:
                cbr                flags1, (1<<EVAL_RPM)
                lds                temp3, rpm_x
                lds                temp2, rpm_h

                lds                temp1, rpm_l        ; subtract 1/256
                sub                temp1, temp2
                sts                rpm_l, temp1
                lds                temp1, rpm_h
                sbc                temp1, temp3
                sts                rpm_h, temp1
                lds                temp1, rpm_x
                sbci        temp1, 0
                sts                rpm_x, temp1

                lds                temp3, timing_acc_x
                lds                temp2, timing_acc_h
                lds                temp1, timing_acc_l
                lsr                temp3                ; make one complete commutation cycle
                ror                temp2
                ror                temp1
                lsr                temp3
                ror                temp2
                ror                temp1
        ; temp3 is zero now - for sure !!
                sts                timing_acc_x, temp3
                sts                timing_acc_h, temp3
                sts                timing_acc_l, temp3
        ; and add the result as 1/256
                lds                temp3, rpm_l
                add                temp3, temp1
                sts                rpm_l, temp3
                lds                temp3, rpm_h
                adc                temp3, temp2
                sts                rpm_h, temp3
                ldi                temp1, 0
                lds                temp3, rpm_x
                adc                temp3, temp1
                sts                rpm_x, temp3

                ret
;-----bko-----------------------------------------------------------------
set_all_timings:
                ldi                YL, low  (timeoutSTART)
                ldi                YH, high (timeoutSTART)
                sts                wt_OCT1_tot_l, YL
                sts                wt_OCT1_tot_h, YH
                ldi                temp3, 0xff
                ldi                temp4, 0x1f
                sts                wt_comp_scan_l, temp3
                sts                wt_comp_scan_h, temp4
                sts                com_timing_l, temp3
                sts                com_timing_h, temp4

set_timing_v:
                ldi                ZL, 0x01
                sts                timing_x, ZL
                ldi                temp4, 0xff
                sts                timing_h, temp4
                ldi                temp3, 0xff
                sts                timing_l, temp3
                ret
;-----bko-----------------------------------------------------------------
update_timing:
                rcall        tcnt1_to_temp
                sts                tcnt1_sav_l, temp1
                sts                tcnt1_sav_h, temp2
                add                temp1, YL
                adc                temp2, YH
                ldi                temp4, (1<<TOIE1)+(1<<TOIE0)
                out                TIMSK, temp4
                out                OCR1AH, temp2   ;;设定比较器值
                out                OCR1AL, temp1
                sbr                flags0, (1<<OCT1_PENDING)
                ldi                temp4, (1<<TOIE1)+(1<<OCIE1A)+(1<<TOIE0) ; enable interrupt again
                out                TIMSK, temp4       //打开比较中断
                ldi                temp4, EXT0_EN                ; ext0int enable
                out                GIMSK, temp4                ; enable ext0int

        ; calculate next waiting times - timing(-l-h-x) holds the time of 4 commutations
                lds                temp1, timing_l
                lds                temp2, timing_h
                lds                ZL, timing_x

                sts                zero_wt_l, temp1        ; save for zero crossing timeout
                sts                zero_wt_h, temp2
                tst                ZL
                breq        update_t00
                ldi                temp4, 0xff
                sts                zero_wt_l, temp4        ; save for zero crossing timeout
                sts                zero_wt_h, temp4
update_t00:
                lsr                ZL                        ; build a quarter
                ror                temp2
                ror                temp1

                lsr                ZL
                ror                temp2
                ror                temp1
                lds                temp3, timing_l                ; .. and subtract from timing
                lds                temp4, timing_h
                lds                ZL, timing_x
                sub                temp3, temp1
                sbc                temp4, temp2
                sbci        ZL, 0

                lds                temp1, tcnt1_sav_l        ; calculate this commutation time
                lds                temp2, tcnt1_sav_h
                lds                YL, last_tcnt1_l
                lds                YH, last_tcnt1_h
                sts                last_tcnt1_l, temp1
                sts                last_tcnt1_h, temp2
                sub                temp1, YL
                sbc                temp2, YH
                sts                last_com_l, temp1
                sts                last_com_h, temp2

                add                temp3, temp1                ; .. and add to timing
                adc                temp4, temp2
                ldi                temp2, 0
                adc                ZL, temp2

        ; limit RPM to 120.000
                tst                ZL
                brne        update_t90
                tst                temp4
                breq        update_t10
                cpi                temp4, 1
                brne        update_t90
                cpi                temp3, 0x4c                ; 0x14c = 120.000 RPM
                brcc        update_t90
        ; set RPM to 120.000
update_t10:
                ldi                temp4, 0x01
                ldi                temp3, 0x4c
                tst                run_control
                brne        update_t90                ; just active
                ldi                temp1, 0xff                ; not active - reactivate
                mov                run_control, temp1

update_t90:
                sts                timing_l, temp3
                sts                timing_h, temp4
                sts                timing_x, ZL
                cpi                ZL, 2                ; limit range to 0x1ffff
                brcs        update_t99
                rcall        set_timing_v

update_t99:
                lds                temp1, timing_acc_l
                add                temp1, temp3
                sts                timing_acc_l, temp1
                lds                temp1, timing_acc_h
                adc                temp1, temp4
                sts                timing_acc_h, temp1
                lds                temp1, timing_acc_x
                adc                temp1, ZL
                sts                timing_acc_x, temp1

                lsr                ZL                        ; a 16th is the next wait before scan
                ror                temp4
                ror                temp3
                lsr                ZL
                ror                temp4
                ror                temp3
                lsr                ZL
                ror                temp4
                ror                temp3
                lsr                ZL
                ror                temp4
                ror                temp3
                sts                wt_comp_scan_l, temp3
                sts                wt_comp_scan_h, temp4

        ; use the same value for commutation timing (15?
                sts                com_timing_l, temp3
                sts                com_timing_h, temp4

                ret
;-----bko-----------------------------------------------------------------
calc_next_timing:
                lds                YL, wt_comp_scan_l        ; holds wait-before-scan value
                lds                YH, wt_comp_scan_h
                rcall        update_timing
                ret

wait_OCT1_tot:
                sbrc        flags0, OCT1_PENDING
                rjmp        wait_OCT1_tot

set_OCT1_tot:
;                cbi        ADCSRA, ADEN                ; switch to comparator multiplexed
;                in        temp1, SFIOR
;                ori        temp1, (1<<ACME)
;                out        SFIOR, temp1

                lds                YH, zero_wt_h
                lds                YL, zero_wt_l
                rcall        tcnt1_to_temp
                add                temp1, YL
                adc                temp2, YH
                ldi                temp4, (1<<TOIE1)+(1<<TOIE0)
                out                TIMSK, temp4
                out                OCR1AH, temp2
                out                OCR1AL, temp1
                sbr                flags0, (1<<OCT1_PENDING)
                ldi                temp4, (1<<TOIE1)+(1<<OCIE1A)+(1<<TOIE0)
                out                TIMSK, temp4
                ldi                temp4, EXT0_EN                ; ext0int enable
                out                GIMSK, temp4                ; enable ext0int

                ret
;-----bko-----------------------------------------------------------------
wait_OCT1_before_switch:
                rcall        tcnt1_to_temp
                lds                YL, com_timing_l
                lds                YH, com_timing_h
                add                temp1, YL
                adc                temp2, YH
                ldi                temp3, (1<<TOIE1)+(1<<TOIE0)
                out                TIMSK, temp3
                out                OCR1AH, temp2
                out                OCR1AL, temp1
                sbr                flags0, (1<<OCT1_PENDING)
                ldi                temp3, (1<<TOIE1)+(1<<OCIE1A)+(1<<TOIE0)
                out                TIMSK, temp3
                ldi                temp4, EXT0_EN                ; ext0int enable
                out                GIMSK, temp4                ; enable ext0int

        ; don't waste time while waiting - do some controls, if indicated
.if RC_PULS == 1
                sbrc        flags1, EVAL_RC_PULS
                rcall        evaluate_rc_puls
.endif
                sbrc        flags1, EVAL_SYS_STATE
                rcall        evaluate_sys_state

.if UART_CONTROL == 1
                sbrc        flags1, EVAL_UART
                rcall        evaluate_uart
.endif
                sbrc        flags1, EVAL_RPM
                rcall        evaluate_rpm

OCT1_wait:        sbrc        flags0, OCT1_PENDING
                rjmp        OCT1_wait
                ret
;-----bko-----------------------------------------------------------------
start_timeout:
                lds                YL, wt_OCT1_tot_l
                lds                YH, wt_OCT1_tot_h
                rcall        update_timing
                in                temp1, TCNT1L
                andi        temp1, 0x0f
                sub                YH, temp1
                cpi                YH, high (timeoutMIN)
                brcc        set_tot2
                ldi                YH, high (timeoutSTART)               
set_tot2:
                sts                wt_OCT1_tot_h, YH
                rcall        sync_with_poweron        ; wait at least 100+ microseconds
                rcall        sync_with_poweron        ; for demagnetisation - one sync may be added
                ret
;-----bko-----------------------------------------------------------------
set_new_duty:
                mov                temp1, ZH
                sub                temp1, sys_control
                brcc        set_new_duty10
                ldi                temp1, MIN_DUTY-1
set_new_duty10:
                lds                temp2, timing_x
                tst                temp2
                brne        set_new_duty12
                lds                temp2, timing_h        ; get actual RPM reference high
                cpi                temp2, PWR_RANGE1        ; lower range1 ?
                brcs        set_new_duty20                ; on carry - test next range
set_new_duty12:
                sbr                flags2, (1<<RPM_RANGE1)
                sbr                flags2, (1<<RPM_RANGE2)
                ldi                temp2, PWR_MAX_RPM1        ; higher than range1 power max ?
                cp                temp1, temp2
                brcs        set_new_duty31                ; on carry - not higher, no restriction
                mov                temp1, temp2                ; low (range1) RPM - set PWR_MAX_RPM1
                rjmp        set_new_duty31
set_new_duty20:
                sbrs        flags2, STARTUP
                rjmp        set_new_duty25
                ldi                temp3, PWR_MAX_STARTUP        ; limit power in startup phase
                cp                temp1, temp3
                brcs        set_new_duty25                ; on carry - not higher, test range 2
                mov                temp1, temp3                ; set PWR_MAX_STARTUP limit
                rjmp        set_new_duty31
set_new_duty25:
                cpi                temp2, PWR_RANGE2        ; lower range2 ?
                brcs        set_new_duty30                ; on carry - not lower, no restriction
                cbr                flags2, (1<<RPM_RANGE1)
                sbr                flags2, (1<<RPM_RANGE2)
                ldi                temp2, PWR_MAX_RPM2        ; higher than range2 power max ?
                cp                temp1, temp2
                brcs        set_new_duty31                ; on carry - not higher, no restriction
                mov                temp1, temp2                ; low (range2) RPM - set PWR_MAX_RPM2
                rjmp        set_new_duty31
set_new_duty30:
                cbr                flags2, (1<<RPM_RANGE1)+(1<<RPM_RANGE2)
set_new_duty31:
                com                temp1                        ; down-count to up-count (T0)
                mov                tcnt0_pwron_next, temp1        ; save in next
        ; tcnt0_power_on is updated to tcnt0_pwron_next in acceptable steps
                ret
;-----bko-----------------------------------------------------------------
.if UART_CONTROL == 1
read_uart:
                tst                uart_cnt
                breq        read_uart_00
                clr                temp1
                rjmp        read_uart_99

read_uart_00:
                clr                XH                ; prepare sendbuffer
                ldi                XL, uart_data
                in                temp1,UDR        ; read data - clear rxc-flag

                cpi                temp1,'+'
                brne        read_uart_10
        ; do (+) job
                st                X+,temp1
                cpi                ZH, POWER_RANGE
                brsh        read_uart_01
                inc                ZH
                rcall        set_new_duty
read_uart_01:        mov        temp1, ZH
                rcall        hex2buf
                rjmp        read_uart_90
read_uart_10:        cpi        temp1,'-'
                brne        read_uart_20
        ; do (-) job
                st                X+,temp1
                cpi                ZH, MIN_DUTY-1
                breq        read_uart_11
                dec                ZH
                rcall        set_new_duty
read_uart_11:        mov        temp1, ZH
                rcall        hex2buf
                rjmp        read_uart_90
read_uart_20:
                cpi                temp1,'#'
                brne        read_uart_30
        ; do (#) job
                rcall        send_state
                rjmp        read_uart_90
read_uart_30:        cpi        temp1,'1'
                brne        read_uart_40
        ; do (1) job
                st                X+,temp1
                lds                temp2, duty_offset
                ldi                ZH, MIN_DUTY
                add                ZH, temp2
                mov                temp1, ZH
                rcall        hex2buf
                rcall        set_new_duty
                rjmp        read_uart_90
read_uart_40:        cpi        temp1,'2'
                brne        read_uart_50
        ; do (2) job
                st                X+,temp1
                ldi                ZH, MIN_DUTY-1
                rcall        set_new_duty
                rjmp        read_uart_90
read_uart_50:        cpi        temp1,'.'
                brne        read_uart_89
                rjmp        read_uart_99                ; return with '.' in temp1
read_uart_89:        ldi        temp1,'?'
                st                X+,temp1
read_uart_90:
                subi        XL,uart_data                ; build data count
                mov                uart_cnt,XL
                ldi                XL,uart_data                ; point to first byte
                sbi                UCSRA, TXC                ; clear flag
                sbi                UCSRB, TXCIE                ; enable irq
                ldi                temp1,'~'                ; start transmission
                out                UDR,temp1
read_uart_99:        ret
;-----bko-----------------------------------------------------------------
send_state:
                ldi                temp2, 0x0d
                st                X+, temp2
                ldi                temp2, 0x0a
                st                X+, temp2
                st                X+, temp1
                mov                temp1, flags0
                rcall        hex2buf
                mov                temp1, flags1
                rcall        hex2buf
                mov                temp1, flags2
                rcall        hex2buf
                mov                temp1, tcnt0_power_on
                rcall        hex2buf
                ldi                temp1,':'
                st                X+, temp1
                lds                temp1, timing_x
                rcall        hex2buf
                lds                temp1, timing_h
                rcall        hex2buf
                lds                temp1, timing_l
                rcall        hex2buf
                ldi                temp1,'-'
                st                X+, temp1
                lds                temp1, com_timing_h
                rcall        hex2buf
                lds                temp1, com_timing_l
                rcall        hex2buf
                ldi                temp1,':'
                st                X+, temp1
                lds                temp1, rpm_x
                rcall        hex2buf
                lds                temp1, rpm_h
                rcall        hex2buf
                ldi                temp1,'+'
                st                X+, temp1
                lds                temp1, goodies
                rcall        hex2buf
                ret
;-----bko-----------------------------------------------------------------
send_byte:
                sbi                UCSRA,TXC        ; clear flag
                out                UDR,temp1
send_b20:
                sbis        UCSRA,TXC
                rjmp        send_b20
                ret
;-----bko-----------------------------------------------------------------
hex2buf:
                mov                temp2,temp1
                swap        temp1
                rcall        nibble2buf
                mov                temp1,temp2
nibble2buf:
                andi        temp1,0x0f
                ori                temp1,0x30
                cpi                temp1,0x3a
                brlo        nibble2buf_10
                subi        temp1,-7
nibble2buf_10:
                st                X+,temp1
                ret
.endif                ; UART_CONTROL == 1
;-----bko-----------------------------------------------------------------
switch_power_off:
                ldi                ZH, MIN_DUTY-1                ; ZH is new_duty
                ldi                temp1, NO_POWER                ; lowest tcnt0_power_on value
                mov                tcnt0_power_on, temp1
                mov                tcnt0_pwron_next, temp1
                ldi                temp1, INIT_PB                ; all off
                out                PORTB, temp1
                ldi                temp1, INIT_PD                ; all off
                out                PORTD, temp1
                ldi                temp1, CHANGE_TIMEOUT        ; reset change-timeout
                mov                tcnt0_change_tot, temp1
                sbr                flags1, (1<<POWER_OFF)        ; disable power on
                cbr                flags2, (1<<POFF_CYCLE)
                sbr                flags2, (1<<STARTUP)
                ret                                ; motor is off
;-----bko-----------------------------------------------------------------
wait_if_spike:
                ldi                temp1, 4
wait_if_spike2:
                dec                temp1
                brne        wait_if_spike2
                ret
;-----bko-----------------------------------------------------------------
sync_with_poweron:
                sbrc        flags0, I_OFF_CYCLE        ; first wait for power on
                rjmp        sync_with_poweron
wait_for_poweroff:
                sbrs        flags0, I_OFF_CYCLE        ; now wait for power off
                rjmp        wait_for_poweroff
.if RC_PULS == 0
;                sbrs        flags2, COMP_SAVE        ; mirror saved ACO to rc_puls, if not used
                sbis        PORTD, rcp_in
                rjmp        qwert1
                cbi                PORTD, rcp_in
                rjmp        qwert2
qwert1:
;                sbrc        flags2, COMP_SAVE
                sbi                PORTD, rcp_in
qwert2:
.endif        ; RC_PULS == 0
                ret
;-----bko-----------------------------------------------------------------
motor_brake:      ;;马达制动
.if MOT_BRAKE == 1
                ldi                temp2, 40                ; 40 * 0.065ms = 2.6 sec
                ldi                temp1, BRAKE_PB                ; all N-FETs on
                out                PORTB, temp1
mot_brk10:
                sbrs        flags0, T1OVFL_FLAG
                rjmp        mot_brk10
                cbr                flags0, (1<<T1OVFL_FLAG)
.if RC_PULS == 1
                push        temp2
                rcall        evaluate_rc_puls
                pop                temp2
                cpi                ZH, MIN_DUTY+3                ; avoid jitter detect
                brcs        mot_brk20
                rjmp        mot_brk90
mot_brk20:
.endif
                dec                temp2
                brne        mot_brk10
.if RC_PULS == 1
mot_brk90:
.endif
                ldi                temp1, INIT_PB                ; all off
                out                PORTB, temp1
                ldi                temp1, INIT_PD                ; all off
                out                PORTD, temp1
.endif        ; MOT_BRAKE == 1
                ret
;-----bko-----------------------------------------------------------------
; **** startup loop ****
init_startup:
                rcall        switch_power_off
                rcall        motor_brake
wait_for_power_on:

.if RC_PULS == 1
                rcall        evaluate_rc_puls
.endif

.if UART_CONTROL == 1
                sbic        UCSRA, RXC
                rcall        read_uart
.endif

                cpi                ZH, MIN_DUTY
                brcs        wait_for_power_on
;=================电机启动=========================
                ldi                temp1, PWR_STARTUP        ; begin startup with low power
                com                temp1
                mov                tcnt0_pwron_next, temp1

                cbi                ADCSRA, ADEN                ; switch to comparator multiplexed
                in                temp1, SFIOR
                sbr                temp1, (1<<ACME)
                out                SFIOR, temp1        ;;打开比较器功能

                clr                temp4
                ldi                temp1, INIT_PB                ; all off
                out                PORTB, temp1
                ldi                temp1, INIT_PD                ; all off
                out                PORTD, temp1
                ldi                temp1, 27                ; wait about 5mikosec
FETs_off_wt:
                dec                temp1
                brne        FETs_off_wt

                rcall        com5com6        
                rcall        com6com1

                cbr                flags2, (1<<SCAN_TIMEOUT)
                ldi                temp1, 0
                sts                goodies, temp1

                ldi                temp1, 40        ; x 65msec
                mov                t1_timeout, temp1

                rcall        set_all_timings

                rcall        start_timeout

        ; fall through start1

;-----bko-----------------------------------------------------------------
; **** start control loop ****
;启动前:  1( Bp-ON , Cn-ON )---2( Ap-ON ,Cn-ON )---3( Ap-ON , Bn-ON )--4( Cp1-ON , Bn-ON )--
                ;5( Cp1_ON , An-ON )---6( Bp-ON ,An-ON )---1( Bp-ON , Cn_on)

; state 1 = B(p-on) + C(n-choppered) - comparator A evaluated
; out_cA changes from low to high

start1:               
                sbrs        flags2, COMP_SAVE        ; high ?
                rjmp        start1_2                ; .. no - loop, while high

start1_0:       
                sbrc        flags0, OCT1_PENDING
                rjmp        start1_1
                sbr                flags2, (1<<SCAN_TIMEOUT)  ;置位
                rjmp        start1_9
start1_1:       
                rcall        sync_with_poweron
                sbrc        flags2, COMP_SAVE        ; low ?
                rjmp        start1_0                ; .. no - loop, while high
; do the special 120?switch
                ldi                temp1, 0
                sts                goodies, temp1
                rcall        com1com2    ;; Ap ON ,Bp off
                rcall        com2com3    ;; Bn ON, Cn off
                rcall        com3com4    ;; Cp ON, Ap off
.if RC_PULS == 1
                rcall        evaluate_rc_puls
.endif
                rcall        evaluate_uart
                rcall        start_timeout
                rjmp        start4
       
start1_2:
                sbrc        flags0, OCT1_PENDING
                rjmp        start1_3
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start1_9
start1_3:
                rcall        sync_with_poweron
                sbrs        flags2, COMP_SAVE        ; high ?
                rjmp        start1_2                ; .. no - loop, while low

start1_9:
                rcall        com1com2   ;; Ap ON ,Bp off
                rcall        start_timeout

; state 2 = A(p-on) + C(n-choppered) - comparator B evaluated
; out_cB changes from high to low

start2:               
                sbrc        flags2 , COMP_SAVE
                rjmp        start2_2

start2_0:       
                sbrc        flags0 , OCT1_PENDING
                rjmp        start2_1
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start2_9
start2_1:       
                rcall        sync_with_poweron   ;;等待一个PWM周期
                sbrs        flags2 , COMP_SAVE
                rjmp        start2_0
                rjmp        start2_9

start2_2:       
                sbrc        flags0, OCT1_PENDING
                rjmp        start2_3
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start2_9
start2_3:       
                rcall        sync_with_poweron   ;;等待一个PWM周期
                sbrc        flags2, COMP_SAVE  ;;;PWM OFF期间查询比较器的输出
                rjmp        start2_2

start2_9:
                rcall        com2com3    ;; Bn ON, Cn off
.if RC_PULS == 1
                rcall        evaluate_rc_puls
.endif
                rcall        start_timeout

; state 3 = A(p-on) + B(n-choppered) - comparator C evaluated
; out_cC changes from low to high

start3:
                sbrs        flags2, COMP_SAVE
                rjmp        start3_2

start3_0:
                sbrc        flags0, OCT1_PENDING
                rjmp        start3_1
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start3_9
start3_1:
                rcall        sync_with_poweron
                sbrc        flags2, COMP_SAVE
                rjmp        start3_0
                rjmp        start3_9

start3_2:
                sbrc        flags0, OCT1_PENDING
                rjmp        start3_3
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start3_9
start3_3:
                rcall        sync_with_poweron
                sbrs        flags2, COMP_SAVE
                rjmp        start3_2

start3_9:
                rcall        com3com4    ;; Cp ON, Ap off
                rcall        evaluate_uart
                rcall        start_timeout

; state 4 = C(p-on) + B(n-choppered) - comparator A evaluated
; out_cA changes from high to low

start4:
                sbrc        flags2, COMP_SAVE
                rjmp        start4_2

start4_0:
                sbrc        flags0, OCT1_PENDING
                rjmp        start4_1
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start4_9
start4_1:
                rcall        sync_with_poweron
                sbrs        flags2, COMP_SAVE
                rjmp        start4_0
                rjmp        start4_9

start4_2:
                sbrc        flags0, OCT1_PENDING
                rjmp        start4_3
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start4_9
start4_3:
                rcall        sync_with_poweron
                sbrc        flags2, COMP_SAVE
                rjmp        start4_2

start4_9:
                rcall        com4com5     ;;An ON,Bn off
                rcall        start_timeout

; state 5 = C(p-on) + A(n-choppered) - comparator B evaluated
; out_cB changes from low to high


start5:
                sbrs        flags2, COMP_SAVE
                rjmp        start5_2

start5_0:
                sbrc        flags0, OCT1_PENDING
                rjmp        start5_1
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start5_9
start5_1:
                rcall        sync_with_poweron
                sbrc        flags2, COMP_SAVE
                rjmp        start5_0
                rjmp        start5_9

start5_2:
                sbrc        flags0, OCT1_PENDING
                rjmp        start5_3
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start5_9
start5_3:
                rcall        sync_with_poweron
                sbrs        flags2, COMP_SAVE
                rjmp        start5_2

start5_9:
                rcall        com5com6    ;;Bp on ,Cp off
                rcall        evaluate_sys_state
                rcall        start_timeout

; state 6 = B(p-on) + A(n-choppered) - comparator C evaluated
; out_cC changes from high to low

start6:
                sbrc        flags2, COMP_SAVE
                rjmp        start6_2

start6_0:
                sbrc        flags0, OCT1_PENDING
                rjmp        start6_1
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start6_9
start6_1:
                rcall        sync_with_poweron
                sbrs        flags2, COMP_SAVE
                rjmp        start6_0
                rjmp        start6_9

start6_2:
                sbrc        flags0, OCT1_PENDING
                rjmp        start6_3
                sbr                flags2, (1<<SCAN_TIMEOUT)
                rjmp        start6_9
start6_3:
                rcall        sync_with_poweron
                sbrc        flags2, COMP_SAVE
                rjmp        start6_2

start6_9:
                rcall        com6com1   ;;Cn on ,An off
                mov                temp1, tcnt0_power_on
                cpi                temp1, NO_POWER
                brne        s6_power_ok
                rjmp        init_startup

s6_power_ok:        tst        rcpuls_timeout
                brne        s6_rcp_ok
                rjmp        restart_control

s6_rcp_ok:        tst        t1_timeout
                brne        s6_test_rpm
                rjmp        init_startup
               
s6_test_rpm:
                lds                temp1, timing_x
                tst                temp1
                brne        s6_goodies
                lds                temp1, timing_h                ; get actual RPM reference high
;                cpi                temp1, PWR_RANGE1
                cpi                temp1, PWR_RANGE2
                brcs        s6_run1

s6_goodies:
                lds                temp1, goodies
                sbrc        flags2, SCAN_TIMEOUT
                clr                temp1
                inc                temp1
                sts                goodies,  temp1
                cbr                flags2, (1<<SCAN_TIMEOUT)
                cpi                temp1, ENOUGH_GOODIES
                brcs        s6_start1       

s6_run1:
                ldi                temp1, 0xff
                mov                run_control, temp1
                rcall        calc_next_timing
                rcall        set_OCT1_tot

                cbr                flags2, (1<<STARTUP)
                cbr                flags2, (1<<GP_FLAG)        ; OCT1-timeout
                rjmp        run1                        ; running state begins

s6_start1:
                rcall        start_timeout                ; need to be here for a correct temp1=comp_state
                rjmp        start1                        ; go back to state 1

;-----bko-----------------------------------------------------------------
; **** running control loop ****

; run 1 = B(p-on) + C(n-choppered) - comparator A evaluated
; out_cA changes from low to high

run1:
                rcall        wait_for_low
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
                rcall        wait_for_high
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
.if RC_PULS == 0
                cbi                PORTD, rcp_in
.endif        ; RC_PULS == 0
                sbr                flags1, (1<<EVAL_RPM)
                rcall        wait_OCT1_before_switch
                rcall        com1com2
                rcall        calc_next_timing
                rcall        wait_OCT1_tot
.if RC_PULS == 0
                sbi                PORTD, rcp_in
.endif        ; RC_PULS == 0

               
; run 2 = A(p-on) + C(n-choppered) - comparator B evaluated
; out_cB changes from high to low

run2:
                rcall        wait_for_high
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
                rcall        wait_for_low
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
.if RC_PULS == 0
                cbi                PORTD, rcp_in
.endif        ; RC_PULS == 0
                sbr                flags1, (1<<EVAL_RC_PULS)
                rcall        wait_OCT1_before_switch
                rcall        com2com3
                rcall        calc_next_timing
                rcall        wait_OCT1_tot
.if RC_PULS == 0
                sbi                PORTD, rcp_in
.endif        ; RC_PULS == 0

; run 3 = A(p-on) + B(n-choppered) - comparator C evaluated
; out_cC changes from low to high

run3:
                rcall        wait_for_low
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
                rcall        wait_for_high
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
.if RC_PULS == 0
                cbi                PORTD, rcp_in
.endif        ; RC_PULS == 0
                sbr                flags1, (1<<EVAL_UART)
                rcall        wait_OCT1_before_switch
                rcall        com3com4
                rcall        calc_next_timing
                rcall        wait_OCT1_tot
.if RC_PULS == 0
                sbi                PORTD, rcp_in
.endif        ; RC_PULS == 0

; run 4 = C(p-on) + B(n-choppered) - comparator A evaluated
; out_cA changes from high to low
run4:
                rcall        wait_for_high
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
                rcall        wait_for_low
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
.if RC_PULS == 0
                cbi        PORTD, rcp_in
.endif        ; RC_PULS == 0
                rcall        wait_OCT1_before_switch
                rcall        com4com5
                rcall        calc_next_timing
                rcall        wait_OCT1_tot
.if RC_PULS == 0
                sbi        PORTD, rcp_in
.endif        ; RC_PULS == 0

; run 5 = C(p-on) + A(n-choppered) - comparator B evaluated
; out_cB changes from low to high

run5:
                rcall        wait_for_low
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
                rcall        wait_for_high
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
.if RC_PULS == 0
                cbi                PORTD, rcp_in
.endif        ; RC_PULS == 0
                sbr                flags1, (1<<EVAL_SYS_STATE)
                rcall        wait_OCT1_before_switch
                rcall        com5com6
                rcall        calc_next_timing
                rcall        wait_OCT1_tot
.if RC_PULS == 0
                sbi        PORTD, rcp_in
.endif        ; RC_PULS == 0

; run 6 = B(p-on) + A(n-choppered) - comparator C evaluated
; out_cC changes from high to low

run6:
                rcall        wait_for_high
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
                rcall        wait_for_low
                sbrs        flags0, OCT1_PENDING
                rjmp        run_to_start
.if RC_PULS == 0
                cbi        PORTD, rcp_in
.endif        ; RC_PULS == 0
                rcall        wait_OCT1_before_switch
                rcall        com6com1
                rcall        calc_next_timing
                rcall        wait_OCT1_tot

                tst                rcpuls_timeout
                breq        restart_control

                lds                temp1, timing_x
                tst                temp1
                breq        run6_2                        ; higher than 610 RPM if zero
                sbr                flags2, (1<<GP_FLAG)        ; mark low RPM
run_to_start:        sbr        flags2, (1<<STARTUP)
                cbr                flags2, (1<<POFF_CYCLE)
                rjmp        wait_for_power_on

run6_2:
                cbr                flags2, (1<<POFF_CYCLE)
                tst                run_control                ; only once !
                breq        run6_9
                dec                run_control
                breq        run6_3                        ; poweroff if 0
                mov                temp1, run_control
                cpi                temp1, 1                ; poweroff if 1
                breq        run6_3
                cpi                temp1, 2                ; poweroff if 2
                brne        run6_9
run6_3:
                sbr                flags2, (1<<POFF_CYCLE)

run6_9:
.if RC_PULS == 0
                sbi        PORTD, rcp_in
.endif        ; RC_PULS == 0
                rjmp        run1                        ; go back to run 1

restart_control:
                cli                                ; disable all interrupts
                rcall        switch_power_off
                rjmp        reset


;-----bko-----------------------------------------------------------------
; *** scan comparator utilities ***
;
wait_for_low:       
                sbrs        flags0, OCT1_PENDING
                ret
                sbis        ACSR, ACO                ; low ?
                rjmp        wait_for_low                ; .. no - loop, while high
                rcall        wait_if_spike                ; .. yes - look for a spike
                sbis        ACSR, ACO                ; test again
                rjmp        wait_for_low                ; .. is high again, was a spike
                ret

wait_for_high:       
                sbrs        flags0, OCT1_PENDING
                ret
                sbic        ACSR, ACO                ; high ?
                rjmp        wait_for_high                ; .. no - loop, while low
                rcall        wait_if_spike                ; .. yes - look for a spike
                sbic        ACSR, ACO                ; test again
                rjmp        wait_for_high                ; .. is low again, was a spike
                ret
;-----bko-----------------------------------------------------------------
; *** commutation utilities ***
com1com2:
                BpFET_off                ; Bp off
                sbrs        flags1, POWER_OFF
                ApFET_on                ; Ap on
                ldi                temp1, mux_b                ; set comparator multiplexer to phase B
                out                ADMUX, temp1
                cbi                ADCSRA, ADEN                ; disable ADC
                in                temp1, SFIOR
                sbr                temp1, (1<<ACME)        ; switch to comparator multiplexed
                out                SFIOR, temp1
                ret

com2com3:
                ldi                temp1, (1<<OCIE1A)+(1<<TOIE1) ; stop timer0 interrupt
                out                TIMSK, temp1                ;  .. only ONE should change these values at the time
                nop
                cbr                flags0, (1<<A_FET)        ; next nFET = BnFET
                cbr                flags0, (1<<C_FET)
                sbrc        flags1, FULL_POWER
                rjmp        c2_switch
                sbrc        flags0, I_OFF_CYCLE        ; was power off ?
                rjmp        c2_done                        ; .. yes - futhermore work is done in timer0 interrupt
c2_switch:
                CnFET_off                ; Cn off
                sbrs        flags1, POWER_OFF
                BnFET_on                ; Bn on
c2_done:
                ldi                temp1, (1<<TOIE1)+(1<<OCIE1A)+(1<<TOIE0) ; let timer0 do his work again
                out                TIMSK, temp1
                in                temp1, SFIOR
                cbr                temp1, (1<<ACME)        ; set to AN1
                out                SFIOR, temp1
                sbi                ADCSRA, ADEN                ; enable ADC
                ret

com3com4:
                ApFET_off                ; Ap off
                sbrs        flags1, POWER_OFF
                CpFET_on                ; Cp on
                ldi                temp1, mux_a                ; set comparator multiplexer to phase A
                out                ADMUX, temp1
                cbi                ADCSRA, ADEN                ; disable ADC
                in                temp1, SFIOR
                sbr                temp1, (1<<ACME)        ; switch to comparator multiplexed
                out                SFIOR, temp1
                ret

com4com5:
                ldi                temp1, (1<<OCIE1A)+(1<<TOIE1) ; stop timer0 interrupt
                out                TIMSK, temp1                ;  .. only ONE should change these values at the time
                nop       
                sbr                flags0, (1<<A_FET)        ; next nFET = AnFET
                cbr                flags0, (1<<C_FET)
                sbrc        flags1, FULL_POWER
                rjmp        c4_switch
                sbrc        flags0, I_OFF_CYCLE        ; was power off ?
                rjmp        c4_done                        ; .. yes - futhermore work is done in timer0 interrupt
c4_switch:
                BnFET_off                ; Bn off
                sbrs        flags1, POWER_OFF
                AnFET_on                ; An on
c4_done:
                ldi                temp1, (1<<TOIE1)+(1<<OCIE1A)+(1<<TOIE0) ; let timer0 do his work again
                out                TIMSK, temp1
                ldi                temp1, mux_b                ; set comparator multiplexer to phase B
                out                ADMUX, temp1
                cbi                ADCSRA, ADEN                ; disable ADC
                in                temp1, SFIOR
                sbr                temp1, (1<<ACME)        ; switch to comparator multiplexed
                out                SFIOR, temp1
                ret

com5com6:
                CpFET_off                ; Cp off
                sbrs        flags1, POWER_OFF
                BpFET_on                ; Bp on
                in                temp1, SFIOR
                cbr                temp1, (1<<ACME)        ; set to AN1
                out                SFIOR, temp1
                sbi                ADCSRA, ADEN                ; enable ADC
                ret

com6com1:
                ldi                temp1, (1<<OCIE1A)+(1<<TOIE1) ; stop timer0 interrupt
                out                TIMSK, temp1                ;  .. only ONE should change these values at the time
                nop
                cbr                flags0, (1<<A_FET)        ; next nFET = CnFET 关掉 An_FET
                sbr                flags0, (1<<C_FET)
                sbrc        flags1, FULL_POWER   ;;是否100%占空比
                rjmp        c6_switch                         ;yes
                sbrc        flags0, I_OFF_CYCLE        ; was power off ?
                rjmp        c6_done                        ; .. yes - futhermore work is done in timer0 interrupt
c6_switch:                                                                 ;;I_OFF_CYCLE == 1 ,PWM off CYCLE
                AnFET_off                ; An off               
                sbrs        flags1, POWER_OFF
                CnFET_on                ; Cn on                       
c6_done:
                ldi                temp1, (1<<TOIE1)+(1<<OCIE1A)+(1<<TOIE0) ; let timer0 do his work again
                out                TIMSK, temp1          ;;开中断

                ldi                temp1, mux_a                ; set comparator multiplexer to phase A
                out                ADMUX, temp1
                cbi                ADCSRA, ADEN                ; disable ADC
                in                temp1, SFIOR
                sbr                temp1, (1<<ACME)        ; switch to comparator multiplexed
                out                SFIOR, temp1                ;;开比较妻功能
                ret

.exit

阿莫论坛20周年了!感谢大家的支持与爱护!!

曾经有一段真挚的爱情摆在我的面前,我没有珍惜,现在想起来,还好我没有珍惜……

出0入0汤圆

 楼主| 发表于 2010-12-1 17:05:54 | 显示全部楼层
工程文件ourdev_601591OLT6S4.rar(文件大小:71K) (原文件名:ppm_r05.rar)

出0入0汤圆

发表于 2010-12-1 17:56:13 | 显示全部楼层
LZ太用心了

出0入0汤圆

发表于 2010-12-1 19:26:47 | 显示全部楼层
晕倒,为什么不用硬件的,M8有三路硬件PWM

出0入0汤圆

 楼主| 发表于 2010-12-2 09:28:07 | 显示全部楼层
为啥不用硬件?这个不是我设计的,我也没法回答你,不过有新的方法总是件好事,能提供一个思路,据说这是商用电调的程序,能量产的,应该不会差,所以发上,有心的人研究研究,一起交流一下,Q:30339598

出0入0汤圆

发表于 2010-12-2 11:58:46 | 显示全部楼层
asm的就像看天书一样……看了两行开始晕了……

出0入0汤圆

发表于 2010-12-2 12:15:40 | 显示全部楼层
我也看晕了

出0入0汤圆

发表于 2010-12-2 12:28:32 | 显示全部楼层
这个程序的目的是什么?是不是有些特殊的要求,否则为何不用硬件的PWM?

出0入0汤圆

 楼主| 发表于 2010-12-2 14:01:46 | 显示全部楼层
我看了几天,还没完全看懂
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片。注意:要连续压缩2次才能满足要求!!】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-8-26 23:22

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表