habrahabr

Светофор в гараже. Настоящий

  • суббота, 1 ноября 2014 г. в 02:11:21
http://habrahabr.ru/post/242097/

Шел мелкий и противный дождь. Настроение было гнусным.
Он лежал на обочине и тихо ржавел. Рядом на столбе сверкал огнями молодой собрат.
Я остановился и положил его в багажник.
Я уже не один.
И он не один.

Привез на дачу, разобрал, отмыл от грязи и покрасил из баллончика.

Применение нашлось сразу. Новая машина оказалась шире предыдущей и заезд в гараж стал более проблематичным. Всякие «колокольчики-на-веревочках» — это не для нас. Итак – стационарный парктроник.

Аппаратура

1. Широко распространенные ультразвуковые датчики HC-SR04. 2 штуки, по одному на каждую стенку. В интернете полно информации о них. Описание ниже.

Ultrasonic Ranging Module HC — SR04

Product features:

Ultrasonic ranging module HC — SR04 provides 2cm — 400cm non-contact measurement function, the ranging accuracy can reach to 3mm. The modules includes ultrasonic transmitters, receiver and control circuit. The basic principle of work:
Using IO trigger for at least 10us high level signal.
The Module automatically sends eight 40 kHz and detect whether there is a pulse signal back.
IF the signal back, through high level, time of high output IO duration is the time from sending ultrasonic to returning.
Test distance = (high level time × velocity of sound (340M/S) / 2


Wire connecting direct as following:

5V Supply
Trigger Pulse Input
Echo Pulse Output
0V Ground

Electric Parameter

Working Voltage DC 5 V
Working Current 15mA
Working Frequency 40Hz
Max Range 4m
Min Range 2cm
Measuring Angle 15 degree
Trigger Input Signal 10uS TTL pulse
Echo Output Signal Input TTL lever signal and the range in proportion
Dimension 45*20*15mm


image

Timing diagram

The Timing diagram is shown below. You only need to supply a short 10uS pulse to the trigger input to start the ranging, and then the module will send out an 8 cycle burst of ultrasound at 40 kHz and raise its echo. The Echo is a distance object that is pulse width and the range in proportion .You can calculate the range through the time interval between sending trigger signal and receiving echo signal. Formula: uS / 58 = centimeters or uS / 148 =inch; or: the range = high-level time * velocity (340M/S) / 2; we suggest to use over 60ms measurement cycle, in order to prevent trigger signal to the echo signal.

image

Закреплены на боковых стенках на въезде в гараж с помощью полосок из оцинкованной жести. Крепление должно позволить отрегулировать датчики «по месту» в зависимости от габаритов авто (высота, ширина капота, форма крыльев…).

image

2. Контроллер – PIC16f84a. Почему этот:
а) их есть у меня;
б) у него 2 порта ввода-вывода, суммарно 13 разрядов, как раз столько и надо. 3шт. – управление светофором (Красный – Желтый – Зеленый), 6шт. – левый и правый светодиоды (К-Ж-З), 2шт. – импульс локации (Trig) на левый и правый датчики, 2шт. – отраженный импульс (Echo) от левого и правого датчиков.

3. Два трехцветных светодиода, по одному на каждую стенку. Светодиодов Красный – Желтый – Зеленый не нашел. Может и не бывает их, а может плохо искал. Поэтому роль желтого у светодиодов играет синий цвет. Для полной идентичности, конечно, можно было использовать раздельные светодиоды. И не было бы с желтым проблем. Но такой компромисс я счел допустимым.

image

4. Блоки управления лампами светофора. 3шт., по одному на каждую лампу.
Идеально подходит блок управления включением-выключением телевизора.

image

Состоит из маломощного силового трансформатора (220 в 7 вольт), диодного выпрямителя, стабилизатора на КР142ЕН5х (или аналог), транзисторного ключа и реле. При подаче на вход логической «1» ключ открывается, реле срабатывает и 220в подается на выход. Кроме того, поскольку КРЕН обеспечивает стабилизированные 5в, от одного из этих блоков резонно запитать микроконтроллер. Их полно на любом радиорынке. Если кого-то раздражает щёлканье реле, несложно сделать схему на тиристорах.

5. Кварцевый резонатор на 4мгц.
Это весьма удобная частота для тех микроконтроллеров, что у меня есть. Легко считать временны́е параметры. Период тактовых импульсов = 250нс, машинный цикл состоит из четырех тактов, следовательно, равен 1мкс. Команды в RISC-контроллерах выполняются за 1 или 2 машинных цикла, так что с вычислением времени, которое пройдет «от того, как…до того, как» проблем нет. Можно использовать другой в пределах допустимых частот, но придется пересчитывать таймауты. Это совсем небольшая проблема.

6. Несколько резисторов и конденсаторов, рекомендуемых типовой схемой включения PIC16f84a и два токоограничивающих резистора для светодиодов. Даташит смотреть, например, здесь: ссылка.

Общий вид собранного девайса:

image
image

Плата с микроконтроллером:

image

Принципиальная схема

image

Алгоритм

Простой, практически линейный. По включении питания проводится тест аппаратуры. Якобы тест, больше для красоты. С интервалом в 1сек переключаются красный-желтый-зеленый, затем с тем же интервалом три раза включаются все лампы светофора. После этого — переход к бесконечному циклу опроса левого и правого каналов. При проходе каждого канала, в зависимости от полученного результата, устанавливается соответствующий бит (флаг) PORTB и включается один из светодиодов данного канала. По окончании полного цикла производится анализ состояния флагов Red-Yellow-Green обоих каналов и на основании этого включается соответствующая лампа светофора. Таблица истинности выглядит так:

Любой канал Красный. Светофор — Красный.
Оба канала Зеленый. Светофор — Зеленый.
Все остальные случаи. Светофор — Желтый.

В нескольких словах сердцевина алгоритма «по шагам»:

1. Формируем импульс Trig;
2. Ожидаем прихода ответного импульса Echo;
3. Запускаем таймаут 1ms;
4. По истечении таймаута проверяем есть ли еще «лог.1» на входе Echo;
5. Если нет, значит мы на опасном приближении к датчику соответствующего канала. Включаем красный флаг данного канала и переходим на другой канал;
6. Если Echo еще есть, повторяем п.п.3 и 4;
7. Если нет, значит мы на среднем удалении от датчика. Включаем желтый флаг и переходим на другой канал;
8. Если Echo еще есть, значит мы далеко. Дожидаемся его окончания, включаем зеленый флаг и переходим на другой канал.

image

В чем суть? Нам не нужно вычислять точное расстояние до объекта. То есть не надо длительность импульса Echo делить на 58, как указано в описании датчика. Мы, не дальномер строим. Нам нужно узнать всего лишь положение объекта по отношению к двум одинаковым диапазонам расстояний от объекта до датчика. Для этого используется таймаут 1ms (см.п.3), что в итоге дает: 1000µs: 58 = 17см. Итак – ближе 17см – красный, от 17 до 34см – желтый, дальше 34см – зеленый. Меняя константы в подпрограмме “Pause 1ms”, можно варьировать расстояния в зависимости от размеров авто, ширины ворот и навыков вождения.

Микропрограмма

Листинг микропрограммы приведен ниже. Ассемблер. Константы, кроме тех, что в таймаутах, – в двоичной системе, поскольку устройство, бит-ориентированное. И при отладке или анализе все равно пришлось бы переводить в двоичную систему. Для предотвращения зависаний в программе используется Watchdog Timer.
Листинг
	list      p=16F84A            ; list directive to define processor
	#include <p16F84A.inc>        ; processor specific variable definitions


	__CONFIG   _CP_OFF & _WDT_ON & _PWRTE_ON & _XT_OSC


;********************** Contact Assignment *****************************

;	Contact #	Name		Function
; 	17		RA0		output 	TrigLeft
; 	18		RA1		output 	TrigRight
;	01		RA2		input	EchoLeft
;	02		RA3		input	EchoRight
;	03		RA4		output	GenRed
;	06		RB0		output	RedLeft
;	07		RB1		output	YellowLeft
;	08		RB2		output	GreenLeft
;	09		RB3		output	RedRight
;	10		RB4		output	YellowRight
;	11		RB5		output	GreenRight
;	12		RB6		output	GenYellow
;	13		RB7		output	GenGreen
;
;******************* Constants **************************
;	Red	00000001	Left channel
;	Yellow	00000010	Left channel
;	Green	00000100	Left channel
;	
;	Red	00001000	Right channel
;	Yellow	00010000	Right channel
;	Green	00100000	Right channel

;***** VARIABLE DEFINITIONS *****************************
		CBLOCK		0x0C
Reg_1					; 0x0C use within Pause subroutine					
Reg_2					; 0x0D use within Pause subroutine
Reg_3					; 0x0E use within Pause subroutine
		ENDC

#define	bank0		bcf	STATUS,RP0	; set bank0
#define bank1		bsf	STATUS,RP0	; set bank1
#define TrigLeft_1	bsf	PORTA,0		; set Trigleft
#define TrigLeft_0	bcf	PORTA,0		; clean Trigleft
#define TrigRight_1	bsf	PORTA,1		; set Trigright
#define TrigRight_0	bcf	PORTA,1		; clean Trigright
#define	EchoLeft	PORTA,2
#define	EchoRight	PORTA,3
#define RedLeft		b'00000001
#define YellowLeft	b'00000010
#define GreenLeft	b'00000100
#define RedRight	b'00001000
#define YellowRight	b'00010000
#define GreenRight	b'00100000
;**********************************************************************
		ORG     0x000             ; processor reset vector
		goto    main              ; go to beginning of program
;----------------------------------------------------------------------
		

;------------------ SUBROUTINE Pulse --------
;delay = 10 machine cycles = 10 µs    
Pulse	    movlw       .3
            movwf       Reg_1
wr0         decfsz      Reg_1,F
            goto        wr0
		return
;------------------ SUBROUTINE Pause 1ms --------
;delay = 1'000 machine cycles
Pause       movlw       .75
            movwf       Reg_1
            movlw       .3
            movwf       Reg_2
wr1         decfsz      Reg_1,F
            goto        wr1
            clrwdt
            decfsz      Reg_2,F
            goto        wr1
            nop
		return
;-------------------- SUBROUTINE Pause 1sec ---
;delay = 1'000'000 machine cycles
Pause1      movlw       .254
            movwf       Reg_1
            movlw       .17
            movwf       Reg_2
            movlw       .6
            movwf       Reg_3
wr2         decfsz      Reg_1,F
            goto        wr2
            clrwdt
            decfsz      Reg_2,F
            goto        wr2
            decfsz      Reg_3,F
            goto        wr2
            nop
            nop
	    	return
;-------------------- SUBROUTINE Pause 50ms --------
;delay = 50'000 machine cycles
Pause2      movlw       .216
            movwf       Reg_1
            movlw       .65
            movwf       Reg_2
wr3         decfsz      Reg_1,F
            goto        wr3
            clrwdt
            decfsz      Reg_2,F
            goto        wr3
            return
;--------------------- SUBROUTINE General Red ---------------
GenRed		bsf	PORTA,4
		bcf	PORTB,6
		bcf	PORTB,7
		return
;--------------------- SUBROUTINE General Green -------------
GenGreen	bsf	PORTB,7
		bcf	PORTA,4
		bcf	PORTB,6
		return
;--------------------- SUBROUTINE General Yellow ------------
GenYellow	bsf	PORTB,6
		bcf	PORTA,4
		bcf	PORTB,7
		return
;--------------------- SUBROUTINE General All ------------
GenAll		bsf	PORTA,4
		bsf	PORTB,6
		bsf	PORTB,7
		return
;---------------------------------------------------------
main
		bank1			; set Bank 1	
		movlw	0x00
		movwf	TRISB		; PORTB - out
		movlw	b'00001100
		movwf	TRISA		; RA2,RA3 - input; RA0,RA1,RA4 - output
		bank0			; return to Bank 0
		clrf	PORTA
		clrf	PORTB		; turn off all lights

;---------------------- TEST -----------------------------
		call	GenRed
		call	Pause1
		call	GenYellow
		call	Pause1
		call	GenGreen
		call	Pause1
		bcf	PORTA,4
		bcf	PORTB,6
		bcf	PORTB,7
		call	Pause1
		call	GenAll
		call	Pause1
		bcf	PORTA,4
		bcf	PORTB,6
		bcf	PORTB,7
		call	Pause1
		call	GenAll
		call	Pause1
		bcf	PORTA,4
		bcf	PORTB,6
		bcf	PORTB,7
		call	Pause1
		call	GenAll
		call	Pause1
		bcf	PORTA,4
		bcf	PORTB,6
		bcf	PORTB,7
		call	Pause1

		goto SoundRight

;------------------LEFT----------------------
SoundLeft	TrigLeft_1	
		call Pulse
		TrigLeft_0
		btfss EchoLeft
		goto $-1
		call	Pause
		btfss	EchoLeft
		goto SetRedLeft
		call Pause
		btfss EchoLeft
		goto SetYellowLeft
		goto SetGreenLeft
				
SetRedLeft	movlw RedLeft
		iorwf PORTB,1
		bcf PORTB,1
		bcf PORTB,2
		goto SoundRight

SetYellowLeft	movlw YellowLeft
		iorwf PORTB,1
		bcf PORTB,0
		bcf PORTB,2
		goto SoundRight

SetGreenLeft	movlw GreenLeft
		iorwf PORTB,1
		bcf PORTB,0
		bcf PORTB,1
				
		clrwdt
		btfsc EchoLeft	; wait Echo end
		goto $-2
		goto SoundRight

;----------------RIGHT---------------------
SoundRight	call Pause2
		TrigRight_1	
		call Pulse
		TrigRight_0
		btfss EchoRight
		goto $-1
		call	Pause
		btfss	EchoRight
		goto SetRedRight
		call Pause
		btfss EchoRight
		goto SetYellowRight
		goto SetGreenRight
						
SetRedRight	movlw RedRight
		iorwf PORTB,1
		bcf PORTB,4
		bcf PORTB,5
		goto SetGenLight

SetYellowRight	movlw YellowRight
		iorwf PORTB,1
		bcf PORTB,3
		bcf PORTB,5
		goto SetGenLight

SetGreenRight	movlw GreenRight
		iorwf PORTB,1
		bcf PORTB,3
		bcf PORTB,4
				
		clrwdt
		btfsc EchoRight	; wait Echo end
		goto $-2
				
;------------------------ Set General Lights ----------------
SetGenLight	btfss	PORTB,0		; check RedLeft
		goto 	CheckRedRight
		call	GenRed
		goto	SoundLeft

CheckRedRight	btfss	PORTB,3
		goto	CheckGreenLeft
		call	GenRed
		goto	SoundLeft

CheckGreenLeft	btfss	PORTB,2
		goto	SetGenYellow
		btfss	PORTB,5
		goto	SetGenYellow
		call	GenGreen
		goto	SoundLeft

SetGenYellow	call	GenYellow
		goto	SoundLeft

			END			



Видео

Автор выражает благодарность своей жене, которая во время реальных испытаний бесстрашно стояла в воротах гаража и следила за тем, чтобы автор не въехал ни левым, ни правым крылом авто в стену на въезде. Если найдутся бесстрашные последователи, желающие повторить проект, автор с удовольствием ответит всем.