Operácie

Ovládanie vyklápacích svetiel: Rozdiel medzi revíziami

Zo stránky SensorWiki

StudentMIPS (diskusia | príspevky)
StudentMIPS (diskusia | príspevky)
Riadok 204: Riadok 204:
}
}
}
}
</syntaxhighlight ></tab>
</source></tab>
<tab name="sequences.h"><syntaxhighlight  lang="c++" style="background: LightYellow;">
<tab name="sequences.h"><syntaxhighlight  lang="c++" style="background: LightYellow;">
#ifndef SEQUENCES_H
#ifndef SEQUENCES_H
Riadok 231: Riadok 231:


#endif
#endif
</syntaxhighlight ></tab>
</source></tab>
<tab name="sequences.c"><syntaxhighlight  lang="c++" style="background: LightYellow;">
<tab name="sequences.c"><syntaxhighlight  lang="c++" style="background: LightYellow;">
#define F_CPU 16000000UL
#define F_CPU 16000000UL
Riadok 456: Riadok 456:
stopRight();
stopRight();
}
}
</syntaxhighlight ></tab>
</source></tab>
<tab name="uart.h"><syntaxhighlight  lang="c++" style="background: LightYellow;">
<tab name="uart.h"><syntaxhighlight  lang="c++" style="background: LightYellow;">
#ifndef UART_H_
#ifndef UART_H_
Riadok 469: Riadok 469:


#endif /* UART_H_ */
#endif /* UART_H_ */
</syntaxhighlight ></tab>
</source></tab>
<tab name="uart.c"><syntaxhighlight  lang="c++" style="background: LightYellow;">
<tab name="uart.c"><syntaxhighlight  lang="c++" style="background: LightYellow;">
#define F_CPU 16000000UL
#define F_CPU 16000000UL
Riadok 515: Riadok 515:
return UDR0;
return UDR0;
}
}
</syntaxhighlight ></tab>
</source></tab>


Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'':  
Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'':  

Verzia z 22:11, 16. máj 2025

Záverečný projekt predmetu MIPS / LS2025 - Martin Lenarth


Zadanie

Cieľom bolo navrhnúť mikropočítačový systém, ktorý reaguje na stlačenie tlačidla a umožňuje riadiť pohyb vyklápacích svetiel na aute. Svetlá sa ovládajú pomocou motorčekov (dva smery pohybu), a to buď:

  • pomocou jednoduchého alebo dvojitého zatlačenia tlačidla, alebo
  • pomocou príkazov cez UART (sériová linka) z počítača
Arduino NANO

Literatúra:


Analýza a opis riešenia

Hlavnou úlohou systému je riadiť pohyb výklopných svetiel nezávisle od seba. Každé svetlo je ovládané dvoma výstupmi – jeden pre pohyb hore a druhý pre pohyb dole. Týmto spôsobom je možné svetlá zdvíhať, spúšťať a vykonávať rôzne blikacie sekvencie. Svetlá je možné ovládať dvoma spôsobmi – mechanickým tlačidlom alebo príkazmi cez UART.

Použite komponenty:

  • Tlačidlo v aute
  • Motorčeky na vyklápanie svetiel
  • 4-Kanálová relé doska s optočlenom
Relé doska

Na detekciu klikov a časovanie pohybov sa využíva časovač TIMER0 v režime CTC, ktorý generuje prerušovanie každú 1 ms. Tým vzniká softvérový časovač pomocou premennej milliseconds.

Program rozlišuje:

  • Jedno kliknutie – slúži na zapnutie alebo vypnutie svetiel (pohyb hore alebo dole).
  • Dvojklik – spúšťa animovanú sekvenciu bliknutia svetiel.
  • UART príkazy – umožňujú spustiť rôzne preddefinované sekvencie

Funkcie pre ovládanie svetiel sú implementované v súbore sequences.c. Tieto funkcie priamo nastavujú piny výstupov podľa požadovaného smeru pohybu a obsahujú časové oneskorenia, ktoré simulujú fyzický pohyb svetiel.

Schéma zapojenia:

Schéma zapojenia.


Algoritmus a program

Program začína inicializáciou periférií:

  • Nastavenie vstupného pinu pre tlačidlo s pull-up rezistorom.
  • Nastavenie výstupných pinov pre ovládanie svetiel.
  • Spustenie UART a časovača TIMER0.
  • Povolenie globálnych prerušení.

Hlavná slučka vykonáva:

  1. Sleduje stav tlačidla, používa debounce a detekciu zmeny stavu.
  2. Rozlišuje jedno a dvojité kliknutie podľa časového odstupu medzi klikmi.
  3. Ovláda svetlá – pri jednom kliknutí sa svetlá zapnú/vypnú, pri dvojkliku sa spustí blikacia sekvencia.
  4. Spracováva znaky z UART – ak bol prijatý znak, vykoná sa príslušná funkcia


<tabs>

<syntaxhighlight lang="c++" style="background: LightYellow;">
  1. define F_CPU 16000000UL
  2. define BAUD 9600
  1. include <avr/io.h>
  2. include "uart.h"
  3. include "sequences.h"
  4. include <util/delay.h>
  5. include <avr/interrupt.h>
  6. include <stdio.h>

// Pin Definitions

  1. define SWITCH PD2
  2. define L_UP PB3
  3. define R_UP PD5
  4. define L_DOWN PB4
  5. define R_DOWN PD6

// Timing Constants

  1. define BUTTON_TIME 500 // button wait time for double click
  2. define DEBOUNCE_DELAY 50 // debounce duration

// Headlight State HeadlightStatus headlights = {0, 0};

// Toggle Pattern Tracking int lastSwitchState = 1; int firstToggleState = 1; volatile uint32_t firstToggleTime = 0; volatile uint8_t toggleSequenceActive = 0; volatile uint8_t handledSequence = 0;

// Millisecond Counter volatile uint32_t milliseconds = 0;

// Timer Setup void setup_timer0() { TCCR0A |= (1 << WGM01); // CTC OCR0A = 249; // 1ms TIMSK0 |= (1 << OCIE0A); // Enable interrupt TCCR0B |= (1 << CS01) | (1 << CS00); // Prescaler 64 }

ISR(TIMER0_COMPA_vect) { milliseconds++; }

unsigned long millis() { unsigned long ms; uint8_t oldSREG = SREG; cli(); ms = milliseconds; SREG = oldSREG; return ms; }

// Debounce uint8_t debounceSwitch(uint8_t pin) { uint8_t stableState = (PIND & (1 << pin)) ? 1 : 0; _delay_ms(DEBOUNCE_DELAY); uint8_t newState = (PIND & (1 << pin)) ? 1 : 0; return (stableState == newState) ? newState : stableState; }

// Main Loop int main(void) { // Switch input DDRD &= ~(1 << SWITCH); PORTD |= (1 << SWITCH); // Pull-up

// Outputs DDRB |= (1 << L_UP) | (1 << L_DOWN); DDRD |= (1 << R_UP) | (1 << R_DOWN);

uart_init(); setup_timer0(); sei(); stop();

while (1) { int current = debounceSwitch(SWITCH); unsigned long now = millis();

if (current != lastSwitchState) { if (!toggleSequenceActive) { toggleSequenceActive = 1; handledSequence = 0; firstToggleState = lastSwitchState; firstToggleTime = now; } else if ((now - firstToggleTime) <= (BUTTON_TIME - DEBOUNCE_DELAY) && current == firstToggleState) { if (firstToggleState == 1) { AlternateWink(); } else { Wink(); } handledSequence = 1; toggleSequenceActive = 0; } lastSwitchState = current; }

if (toggleSequenceActive && !handledSequence && (now - firstToggleTime) > (BUTTON_TIME - DEBOUNCE_DELAY)) { toggleSequenceActive = 0; if (lastSwitchState == 0 && !areHeadlightsUp()) { raiseHeadlights(); uart_puts("ON\n"); } else if (lastSwitchState == 1 && areHeadlightsUp()) { lowerHeadlights(); uart_puts("OFF\n"); } }

if (!toggleSequenceActive && !handledSequence) { if (current == 0 && !areHeadlightsUp()) { raiseHeadlights(); uart_puts("ON\n"); } else if (current == 1 && areHeadlightsUp()) { lowerHeadlights(); uart_puts("OFF\n"); } }

if (UCSR0A & (1 << RXC0)) { char command = uart_getc();

switch (command) { case 'M': if (areHeadlightsUp()) MexicanWink(); else AlternateMexicanWink(); break;

case 'W': if (areHeadlightsUp()) Wink(); else AlternateWink(); break;

case 'L': WinkLeft(); break;

case 'R': WinkRight(); break; } } } }

</source>
<syntaxhighlight lang="c++" style="background: LightYellow;">
  1. ifndef SEQUENCES_H
  2. define SEQUENCES_H
  1. include <stdint.h>

typedef struct { int leftUp  : 1; int rightUp : 1; } HeadlightStatus;

void moveHeadlight(uint8_t side, uint8_t direction); void raiseHeadlights(void); void lowerHeadlights(void); uint8_t areHeadlightsUp(void);

void Wink(void); void AlternateWink(void); void MexicanWink(void); void AlternateMexicanWink(void); void WinkLeft(void); void WinkRight(void);

void stop(void);

  1. endif
</source>
<syntaxhighlight lang="c++" style="background: LightYellow;">
  1. define F_CPU 16000000UL
  2. define BAUD 9600
  1. include <avr/io.h>
  2. include <util/delay.h>
  3. include "sequences.h"
  1. define UP 1
  2. define DOWN 0
  3. define LEFT 1
  4. define RIGHT 0
  1. define L_UP PB3
  2. define R_UP PD5
  3. define L_DOWN PB4
  4. define R_DOWN PD6
  1. define MOVE_TIME 750
  2. define SEQUENCE_TIME 150

extern HeadlightStatus headlights;

static void set_pin(volatile uint8_t *port, uint8_t pin, uint8_t high) { if (high) *port |= (1 << pin); else *port &= ~(1 << pin); }

void delay(int delay) { for (int i=1; i<=delay; i++) _delay_ms(1); }

void stop() { set_pin(&PORTB, L_UP, 1); set_pin(&PORTD, R_UP, 1); set_pin(&PORTB, L_DOWN, 1); set_pin(&PORTD, R_DOWN, 1); }

static void stopLeft() { set_pin(&PORTB, L_UP, 1); set_pin(&PORTB, L_DOWN, 1); }

static void stopRight() { set_pin(&PORTD, R_UP, 1); set_pin(&PORTD, R_DOWN, 1); }

void moveHeadlight(uint8_t side, uint8_t direction) { if (side == LEFT) { set_pin(&PORTB, L_UP, !direction); set_pin(&PORTB, L_DOWN, direction); headlights.leftUp = direction; } else { set_pin(&PORTD, R_UP, !direction); set_pin(&PORTD, R_DOWN, direction); headlights.rightUp = direction; } }

void raiseHeadlights() { if (!headlights.leftUp || !headlights.rightUp) { if (!headlights.leftUp) moveHeadlight(LEFT, UP); if (!headlights.rightUp) moveHeadlight(RIGHT, UP); delay(MOVE_TIME); stop(); headlights.leftUp = UP; headlights.rightUp = UP; } }

void lowerHeadlights() { if (headlights.leftUp || headlights.rightUp) { if (headlights.leftUp) moveHeadlight(LEFT, DOWN); if (headlights.rightUp) moveHeadlight(RIGHT, DOWN); delay(MOVE_TIME); stop(); headlights.leftUp = DOWN; headlights.rightUp = DOWN; } }

uint8_t areHeadlightsUp() { return headlights.leftUp && headlights.rightUp; }

void Wink() { moveHeadlight(LEFT, DOWN); delay(MOVE_TIME); stop();

moveHeadlight(LEFT, UP); moveHeadlight(RIGHT, DOWN); delay(MOVE_TIME); stop();

moveHeadlight(LEFT, DOWN); moveHeadlight(RIGHT, UP); delay(MOVE_TIME); stop();

moveHeadlight(LEFT, UP); moveHeadlight(RIGHT, DOWN); delay(MOVE_TIME); stop();

moveHeadlight(RIGHT, UP); delay(MOVE_TIME); stop();

headlights.leftUp = UP; headlights.rightUp = UP; }

void AlternateWink() { moveHeadlight(LEFT, UP); delay(MOVE_TIME); stop();

moveHeadlight(LEFT, DOWN); moveHeadlight(RIGHT, UP); delay(MOVE_TIME); stop();

moveHeadlight(LEFT, UP); moveHeadlight(RIGHT, DOWN); delay(MOVE_TIME); stop();

moveHeadlight(LEFT, DOWN); moveHeadlight(RIGHT, UP); delay(MOVE_TIME); stop();

moveHeadlight(RIGHT, DOWN); delay(MOVE_TIME); stop();

headlights.leftUp = DOWN; headlights.rightUp = DOWN; }

void MexicanWink() { for (int i = 0; i < 2; i++) { moveHeadlight(LEFT, DOWN); delay(SEQUENCE_TIME); moveHeadlight(RIGHT, DOWN); delay(MOVE_TIME - SEQUENCE_TIME); stopLeft(); delay(SEQUENCE_TIME); stopRight();

moveHeadlight(LEFT, UP); delay(SEQUENCE_TIME); moveHeadlight(RIGHT, UP); delay(MOVE_TIME - SEQUENCE_TIME); stopLeft(); delay (SEQUENCE_TIME); stopRight(); }

headlights.leftUp = UP; headlights.rightUp = UP; }

void AlternateMexicanWink() { for (int i = 0; i < 2; i++) { moveHeadlight(LEFT, UP); delay(SEQUENCE_TIME); moveHeadlight(RIGHT, UP); delay(MOVE_TIME - SEQUENCE_TIME); stopLeft(); delay(SEQUENCE_TIME); stopRight();

moveHeadlight(LEFT, DOWN); delay(SEQUENCE_TIME); moveHeadlight(RIGHT, DOWN); delay(MOVE_TIME - SEQUENCE_TIME); stopLeft(); delay(SEQUENCE_TIME); stopRight(); }

headlights.leftUp = DOWN; headlights.rightUp = DOWN; }

void WinkLeft() { if (headlights.leftUp) { moveHeadlight(LEFT, DOWN); delay(MOVE_TIME); stopLeft(); moveHeadlight(LEFT, UP); } else { moveHeadlight(LEFT, UP); delay(MOVE_TIME); stopLeft(); moveHeadlight(LEFT, DOWN); } delay(MOVE_TIME); stopLeft(); }

void WinkRight() { if (headlights.rightUp) { moveHeadlight(RIGHT, DOWN); delay(MOVE_TIME); stopRight(); moveHeadlight(RIGHT, UP); } else { moveHeadlight(RIGHT, UP); delay(MOVE_TIME); stopRight(); moveHeadlight(RIGHT, DOWN); } delay(MOVE_TIME); stopRight(); }

</source>
<syntaxhighlight lang="c++" style="background: LightYellow;">
  1. ifndef UART_H_
  2. define UART_H_

void uart_init( void );

void uart_putc( char c ); void uart_puts( const char *s );

char uart_getc( void );

  1. endif /* UART_H_ */
</source>
<syntaxhighlight lang="c++" style="background: LightYellow;">
  1. define F_CPU 16000000UL
  2. define BAUD 9600
  1. include <avr/io.h>
  2. include <util/setbaud.h>

void uart_init( void ) { UBRR0H = UBRRH_VALUE; UBRR0L = UBRRL_VALUE;

#if USE_2X UCSR0A |= _BV(U2X0); #else UCSR0A &= ~(_BV(U2X0)); #endif

UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */ UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */ }


void uart_putc(char c) { if (c == '\n') { uart_putc('\r'); } loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */ UDR0 = c; }


void uart_puts(const char *s) { while (*s) { uart_putc(*s++); } }

char uart_getc(void) { loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */ return UDR0; }

</source>

Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x zdrojaky.zip:

Zdrojový kód: zdrojaky.zip

Overenie

Ako ste overili funkciu, napríklad... Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia. Na konci uvádzame fotku hotového zariadenia.

Aplikácia.

Video:



Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.