среда, 10 декабря 2014 г.

Измерение длительности импульса

В этой статья рассказывается об устройстве, которое можно подключить вместо сервопривода или параллельно с сервоприводом к тестеру, приемнику и пр. Это приспособление будет измерять длительность управляющего импульса, а результат измерения будет отображаться на ЖК экранчике.


Прежде всего, нужно сказать несколько слов о том, как осуществляется управление сервоприводами. Всё просто. На управляющей линии сервопривода устанавливается логическая единица. Через некоторое время логическая единица сменяется логическим нолем. Ещё через какое то время логический ноль сменяется логической единицей. А затем логическую единицу опять сменяет логический ноль. И так снова и снова. Именно продолжительность присутствия логической единицы является определяющей. Обычно этот временной интервал находится в пределах от 1000 до 2000 микросекунд. А общее время присутствия на линии логической единицы и следующего за ней логического ноля составляет около 20 миллисекунд. Иначе говоря, частота управляющих импульсов равна 50 Гц. На графике представленном ниже отображен один период этого управляющего сигнала.


Прибор, которому посвящена эта статья, измеряет время в течении которого на управляющей линии присутствует логическая единица.

Сделано устройство на основе Arduino Nano (ATmega168).


Помимо ардуино необходим ЖК экран. Я использовал весьма распространенный символьный экранчик WH1602 (KS0066).


Для управления контрастом экрана я использовал ардуино модуль с переменным резистором.


Подключается всё согласно приведенным ниже инструкциям.

Arduino Nano --- LCD

GND --- VSS (1)
5V --- VDD (2)
D8 --- RS (4)
D9 --- RW (5)
D10 --- E (6)
D0 (RX) --- D0 (7)
D1 (TX) --- D1 (8)
D2 --- D2 (9)
D3 --- D3 (10)
D4 --- D4 (11)
D5 --- D5 (12)
D6 --- D6 (13)
D7 --- D7 (14)

Variable Resistor --- LCD

S --- V0 (3)

Arduino Nano --- Variable Resistor

5V --- +
GND --- -

Приведу пример подключения этого измерительного устройства к приемнику.

Arduino Nano --- Receiver

A0 --- CH1
5V --- VCC
GND --- GND

В этом примере мое устройство получает питание от приемника. А на приемник ток подается с ESC. Стабилизатор ESC должен давать 5 вольт. Не помешает это проверить прежде, чем подключать приемник к ESC.

Программа написана на ассемблере в Atmel Studio.

;---------------------------------------------
; Program      : Tester
; Compiler     : AVR Studio
; Chip type    : ATmega168
; System Clock : 16 MHz
; Date         :
;---------------------------------------------

.include "m168def.inc"

;---------------------------------------------
; Interrupt vectors

        .cseg

        .org 0x0000    ; Reset
        jmp RESET
        .org 0x0002    ; External Interrupt Request 0
        reti
        .org 0x0004    ; External Interrupt Request 1
        reti
        .org 0x0006    ; Pin Change Interrupt Request 0
        reti
        .org 0x0008    ; Pin Change Interrupt Request 1
        reti
        .org 0x000A    ; Pin Change Interrupt Request 2
        reti
        .org 0x000C    ; Watchdog Time-out Interrupt
        reti
        .org 0x000E    ; Timer/Counter 2 Compare Match A
        reti
        .org 0x0010    ; Timer/Counter 2 Compare Match B
        reti
        .org 0x0012    ; Timer/Counter 2 Overflow
        reti
        .org 0x0014    ; Timer/Counter 1 Capture Event
        reti
        .org 0x0016    ; Timer/Counter 1 Compare Match A
        reti
        .org 0x0018    ; Timer/Counter 1 Compare Match B
        reti
        .org 0x001A    ; Timer/Counter 1 Overflow
        reti
        .org 0x001C    ; Timer/Counter 0 Compare Match A
        reti
        .org 0x001E    ; Timer/Counter 0 Compare Match B
        reti
        .org 0x0020    ; Timer/Counter 0 Overflow
        reti
        .org 0x0022    ; SPI Serial Transfer Complete
        reti
        .org 0x0024    ; USART, Rx Complete
        reti
        .org 0x0026    ; USART, UDR Empty
        reti
        .org 0x0028    ; USART, Tx Complete
        reti
        .org 0x002A    ; ADC Conversion Complete
        reti
        .org 0x002C    ; EEPROM Ready
        reti
        .org 0x002E    ; Analog Comparator
        reti
        .org 0x0030    ; Two-wire Serial Interface
        reti
        .org 0x0032    ; Store Program Memory Read
        reti

        .org INT_VECTORS_SIZE

;---------------------------------------------

RESET:

;---------------------------------------------
; Steck initialization

        ldi R16, Low(RAMEND)
        out SPL, R16
        ldi R16, High(RAMEND)
        out SPH, R16

;---------------------------------------------
; USART

        ldi R16, 0
        sts UBRR0H, R16
        sts UBRR0L, R16
        sts UCSR0A, R16
        sts UCSR0B, R16
        sts UCSR0C, R16

;---------------------------------------------
; Timer/Counter 1

        ldi R16, 0
        sts TCNT1H, R16
        sts TCNT1L, R16
        sts TCCR1A, R16
        sts TCCR1B, R16
        sts TCCR1C, R16
        sts TIMSK1, R16
        out TIFR1, R16

;---------------------------------------------
; Input/Output Ports

        ldi R16, 0b00000000
        out PORTB, R16

        ldi R16, 0b00000000
        out DDRB, R16

        ldi R16, 0b00000000
        out PORTC, R16

        ldi R16, 0b00000000
        out DDRC, R16

        ldi R16, 0b00000000
        out PORTD, R16

        ldi R16, 0b00000000
        out DDRD, R16

;---------------------------------------------
; LCD initialization

        ldi R16, 0b11111111
        out DDRD, R16

        ldi R16, 0b11111111
        out PORTD, R16

        sbi DDRB, 0
        sbi DDRB, 1
        sbi DDRB, 2

        sbi PORTB, 0
        sbi PORTB, 1
        sbi PORTB, 2

        cbi PORTB, 1

        rcall delay_40_ms

        ldi R16, 0b00111000
        rcall LcdWriteCom

        ldi R16, 0b00001100
        rcall LcdWriteCom

        rcall LcdClear

        ldi R16, 0b00000110
        rcall LcdWriteCom

;---------------------------------------------
; Global interrupt disable

        cli

;---------------------------------------------
; main

main:

        ldi R16, 0
        sts TCNT1H, R16
        sts TCNT1L, R16

l_1:

        sbis PINC, 0
        rjmp l_1

        ldi R16, (1<<CS11)
        sts TCCR1B, R16

l_2:

        sbic PINC, 0
        rjmp l_2

        ldi R16, 0
        sts TCCR1B, R16

        lds R17, TCNT1L
        lds R18, TCNT1H

        ; Divide R18:R17 by two
        lsr R18
        ror R17

        ; 1000
        ldi R20, 0x03 ; High Byte
        ldi R19, 0xE8 ; Low Byte

        rcall divide

        cpi R16, 0 ; Compare R16 to 0
        breq l_3 ; Branch if R16 == 0

        mov R21, R16 ; Copy R16 to R21
        ldi R16, '0' ; Load '0' to R16
        add R21, R16 ; Add R16 to R21 (R21=R21+R16)

        rjmp l_4

l_3:

        ldi R21, ' ' ; Load ' ' to R21

l_4:

        ; 100
        ldi R20, 0x00 ; High Byte
        ldi R19, 0x64 ; Low Byte

        rcall divide

        mov R22, R16 ; Copy R16 to R22
        ldi R16, '0' ; Load '0' to R16
        add R22, R16 ; Add R16 to R22 (R22=R22+R16)

        ; 10
        ldi R20, 0x00 ; High Byte
        ldi R19, 0x0A ; Low Byte

        rcall divide

        mov R23, R16 ; Copy R16 to R23
        ldi R16, '0' ; Load '0' to R16
        add R23, R16 ; Add R16 to R23 (R23=R23+R16)

        mov R24, R17 ; Copy R17 to R24
        ldi R16, '0' ; Load '0' to R16
        add R24, R16 ; Add R16 to R24 (R24=R24+R16)

        rcall LcdClear

        mov R16, R21 ; Copy R21 to R16
        rcall LcdWriteData
        mov R16, R22 ; Copy R22 to R16
        rcall LcdWriteData
        mov R16, R23 ; Copy R23 to R16
        rcall LcdWriteData
        mov R16, R24 ; Copy R24 to R16
        rcall LcdWriteData

        rjmp main

;---------------------------------------------
; divide

divide:

        clr R16 ; Clear R16

l_00:

        ; Compare R18:R17 with R20:R19
        cp R17, R19 ; Compare low byte
        cpc R18, R20 ; Compare high byte
        brlo l_01 ; Branch if R18:R17 < R20:R19 (unsigned)

        ; Subtract R20:R19 from R18:R17
        sub R17, R19 ; Subtract low byte
        sbc R18, R20 ; Subtract high byte


        inc R16 ; Increment R16

        rjmp l_00

l_01:

        ret

;---------------------------------------------
; 40 ms

delay_40_ms:

        ldi R16, 0x00 ; Low byte
        ldi R17, 0xF4 ; Middle byte
        ldi R18, 0x01 ; High byte

l_10:

        subi R16, 1
        sbci R17, 0
        sbci R18, 0
        brcc l_10

        ret

;---------------------------------------------
; 2 ms

delay_2_ms:

        ldi R16, 0x40 ; Low byte
        ldi R17, 0x1F ; High byte

l_20:

        subi R16, 1
        sbci R17, 0
        brcc l_20

        ret

;---------------------------------------------
; 2 us

delay_2_us:

        ldi R16, 11

l_30:

        subi R16, 1
        brcc l_30

        ret

;---------------------------------------------
; 40 us

delay_40_us:

        ldi R16, 214

l_40:

        subi R16, 1
        brcc l_40

        ret

;---------------------------------------------
; Lcd Write Com

LcdWriteCom:

        cbi PORTB, 0 ; Clear RC
        out PORTD, R16
        sbi PORTB, 2 ; Set E
        rcall delay_2_us
        cbi PORTB, 2 ; Clear E
        rcall delay_40_us

        ret

;---------------------------------------------
; Lcd Write Data

LcdWriteData:

        sbi PORTB, 0 ; Set RC
        out PORTD, R16
        sbi PORTB, 2 ; Set E
        rcall delay_2_us
        cbi PORTB, 2 ; Clear E
        rcall delay_40_us

        ret

;---------------------------------------------
; Lcd Clear

LcdClear:

        ldi R16, 0b00000001
        rcall LcdWriteCom
        rcall delay_2_ms

        ret

;---------------------------------------------

Готовая прошивка для Arduino Nano (ATmega168) https://yadi.sk/d/T39TlbFsdHWKa

Загружать прошивку в ардуино нужно до подключения экранчика. Иначе ничего не получится. Экранчик будет мешать записи программы в микроконтроллер ардуино.