Pripojenie viacero tlačidiel cez A/D prevodník: Rozdiel medzi revíziami
Zo stránky SensorWiki
Bez shrnutí editace |
Bez shrnutí editace |
||
| (15 medziľahlých úprav od rovnakého používateľa nie je zobrazených.) | |||
| Riadok 11: | Riadok 11: | ||
*merať hodnotu napätia pomocou A/D prevodníka, | *merať hodnotu napätia pomocou A/D prevodníka, | ||
*zobrazovať zmeny hodnôt v konzole programu AVR Studio. | *zobrazovať zmeny hodnôt v konzole programu AVR Studio. | ||
'''Literatúra:''' | '''Literatúra:''' | ||
| Riadok 22: | Riadok 20: | ||
== Analýza a opis riešenia == | == Analýza a opis riešenia == | ||
=== Teoretický úvod === | === Teoretický úvod === | ||
Mikrokontrolér ATmega328P obsahuje vstavaný 10-bitový A/D prevodník (ADC – Analog to Digital Converter), ktorý prevádza analógové napätie na digitálnu hodnotu v rozsahu 0 – 1023. | |||
Každé tlačidlo bolo pripojené cez rezistor s odlišnou hodnotou. Po stlačení konkrétneho tlačidla vznikne na analógovom vstupe iné napätie, ktoré ADC prevedie na inú digitálnu hodnotu. | |||
Vďaka tomu je možné pomocou jediného analógového vstupu rozlišovať viacero tlačidiel. | |||
Výhody riešenia: | |||
*úspora vstupných pinov mikrokontroléra, | |||
*jednoduché zapojenie, | |||
*možnosť rozšírenia o ďalšie tlačidlá. | |||
Nevýhody: | |||
*menšia presnosť pri väčšom počte tlačidiel, | |||
*citlivosť na toleranciu rezistorov, | |||
*možnosť nepresných hodnôt pri súčasnom stlačení viacerých tlačidiel. | |||
=== Použité komponenty === | |||
[[Súbor: | *Arduino / ATmega328P | ||
*5 tlačidiel | |||
*rezistory | |||
*prepojovacie vodiče | |||
*AVR Studio | |||
=== Schéma zapojenia === | |||
Tlačidlá boli pripojené cez rezistorový delič na jeden analógový vstup mikrokontroléra. Každé tlačidlo malo vlastný rezistor, čím vznikla jedinečná hodnota napätia pre každé tlačidlo. | |||
Princíp zapojenia: | |||
*bez stlačenia tlačidla je na vstupe základná hodnota, | |||
*po stlačení tlačidla sa zmení napätie, | |||
*ADC prevedie napätie na digitálnu hodnotu, | |||
*program vyhodnotí rozsah hodnoty a určí stlačené tlačidlo. | |||
[[Súbor:ZapojenieADC.jpg|400px|thumb|center|Celkový pohľad na zariadenie.]] | |||
=== Algoritmus a program === | === Algoritmus a program === | ||
Hlavné časti programu: | |||
1. Inicializácia A/D prevodníka | |||
*nastavenie referenčného napätia, | |||
*nastavenie prescalera, | |||
*povolenie ADC. | |||
2. Čítanie analógovej hodnoty | |||
*spustenie konverzie, | |||
*čakanie na dokončenie prevodu, | |||
*načítanie hodnoty z registra ADC. | |||
3. Vyhodnotenie tlačidiel | |||
*porovnanie načítanej hodnoty s intervalmi, | |||
*určenie stlačeného tlačidla. | |||
4. Výpis do konzoly | |||
*zobrazenie aktuálnej hodnoty ADC, | |||
*zobrazenie informácie o stlačenom tlačidle. | |||
<tabs> | <tabs> | ||
<tab name="AVR C-code"><syntaxhighlight lang="c++" style="background: LightYellow;"> | <tab name="AVR C-code"><syntaxhighlight lang="c++" style="background: LightYellow;"> | ||
#include <stdio.h> | |||
#include <avr/io.h> | #include <avr/io.h> | ||
#include <avr/interrupt.h> | |||
#include <util/delay.h> | |||
#include "hardware.h" | |||
#include "uart.h" | |||
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT)) | |||
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT)) | |||
#define toggle_bit(ADDRESS,BIT) (ADDRESS ^= (1<<BIT)) | |||
FILE uart_stream = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW); | |||
volatile unsigned int oldICR = 0; | |||
volatile unsigned int Ton = 0; | |||
volatile unsigned int Toff = 0; | |||
volatile unsigned char edge = 0; // 0=rising, 1=falling | |||
void timer1_init(void) | |||
{ | |||
TCCR1A = 0x00; // normal mode | |||
TCCR1B = (1<<CS12) | (1<<CS10); // prescaler 1024 | |||
TCCR1B |= (1<<ICES1); // rising edge first | |||
TCNT1 = 0; | |||
TIMSK1 = (1<<ICIE1); | |||
} | |||
ISR(TIMER1_CAPT_vect) | |||
{ | |||
unsigned int diff = ICR1 - oldICR; | |||
oldICR = ICR1; | |||
if(edge == 0) | |||
{ | |||
Toff = diff; | |||
TCCR1B &= ~(1<<ICES1); | |||
edge = 1; | |||
} | |||
else | |||
{ | |||
Ton = diff; | |||
TCCR1B |= (1<<ICES1); | |||
edge = 0; | |||
unsigned long Ton_us = (unsigned long)Ton * 64; | |||
unsigned long Toff_us = (unsigned long)Toff * 64; | |||
unsigned long Ttotal = Ton_us + Toff_us; | |||
unsigned long period_ms = Ttotal / 1000; | |||
unsigned long duty = (Ton_us * 100) / Ttotal; | |||
printf("Period: %lu ms | Duty: %lu %%\n", period_ms, duty); | |||
} | |||
} | |||
int main(void) | int main(void) | ||
{ | { | ||
hw_init(); | |||
hw_init1(); | |||
uart_init(); | |||
stdout = &uart_stream; | |||
timer1_init(); | |||
sei(); | |||
printf("Ready to measure...\n"); | |||
while(1) | |||
{ | |||
} | |||
return 0; | |||
} | } | ||
</syntaxhighlight ></tab> | </syntaxhighlight></tab> | ||
<tab name=" | <tab name="uart.h"><syntaxhighlight lang="c++" style="background: LightYellow;"> | ||
#define set_bit(ADDRESS, BIT)(ADDRESS |= (1 << BIT)) | |||
#define clear_bit(ADDRESS, BIT)(ADDRESS &= ~(1 << BIT)) | |||
#ifndef UART_H_ | |||
#define UART_H_ | |||
#include <stdio.h> | |||
#define BAUD_PRESCALE(((F_CPU / (BAUDRATE * 16 UL))) - 1) | |||
void uart_init(void); | |||
int uart_putc(char c, FILE * stream); | |||
void uart_puts(const char * s); | |||
char uart_getc(void); | |||
void delay(int delay); | |||
#endif /* UART_H_ */ | |||
</syntaxhighlight></tab> | |||
<tab name="uart.c"><syntaxhighlight lang="c++" style="background: LightYellow;"> | |||
#include <avr/io.h> | #include <avr/io.h> | ||
#include <util/delay.h> | |||
#include "uart.h" | |||
</ | |||
< | void uart_init(void) { | ||
#include <util/setbaud.h> | |||
UBRR0H = UBRRH_VALUE; | |||
UBRR0L = UBRRL_VALUE; | |||
#if USE_2X | |||
UCSR0A |= (1 << U2X0); | |||
#else | |||
UCSR0A &= ~(1 << U2X0); | |||
#endif | |||
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); | |||
UCSR0B = _BV(RXEN0) | _BV(TXEN0); | |||
} | |||
int uart_putc(char c, FILE * stream) { | |||
if (c == '\n') { | |||
loop_until_bit_is_set(UCSR0A, UDRE0); | |||
UDR0 = '\r'; | |||
} | |||
loop_until_bit_is_set(UCSR0A, UDRE0); | |||
UDR0 = c; | |||
return 0; | |||
} | |||
void uart_puts(const char * s) {} | |||
char uart_getc(void) { | |||
loop_until_bit_is_set(UCSR0A, RXC0); | |||
return UDR0; | |||
} | |||
void delay(int delay) { | |||
for (int i = 1; i <= delay; i++) | |||
_delay_ms(1); | |||
} | |||
</syntaxhighlight></tab> | |||
</tabs> | |||
Zdrojový kód: [[Médiá:ProjektKristianRostupytskyi.zip|zdrojaky.zip]] | |||
=== Overenie === | |||
'''Video:''' | '''Video:''' | ||
<center><youtube> | <center><youtube>dBDQtYJwiQc</youtube></center> | ||
== Výsledok projektu == | |||
Projekt úspešne preukázal možnosť pripojenia viacerých tlačidiel pomocou jedného analógového vstupu a A/D prevodníka mikrokontroléra ATmega328P. Pri stlačení tlačidiel sa správne menila hodnota signálu a program dokázal rozpoznať jednotlivé tlačidlá podľa nameraných hodnôt ADC. | |||
== Čo by som urobil inak == | == Čo by som urobil inak == | ||
Počas realizácie projektu sa mi nepodarilo hneď správne nastaviť hodnoty rezistorov pre všetkých 5 tlačidiel. Pri pripojení 4. tlačidla vznikol problém, pretože konzola nevedela spoľahlivo rozlíšiť rozdiel medzi signálom 3. a 4. tlačidla. Hodnoty ADC boli príliš podobné, a preto bolo potrebné použiť ďalší rezistor, aby vznikol väčší rozdiel napätí medzi jednotlivými tlačidlami. Nabudúce by som si vopred lepšie vypočítal alebo odmeral vhodné hodnoty rezistorov. | |||
Taktiež som sa pokúšal namiesto výpisu hodnôt do konzoly použiť žiarovku alebo LED diódu a meniť jej jas podľa stlačeného tlačidla. Tento spôsob sa mi však nepodarilo správne sprevádzkovať. Pravdepodobne boli rozdiely medzi jednotlivými hodnotami signálu príliš malé, a preto zmena jasu nebola viditeľná. Nabudúce by som použil väčšie rozdiely napätí alebo PWM reguláciu jasu, aby boli zmeny lepšie viditeľné. | |||
[[Category:AVR]] [[Category:MIPS]] | [[Category:AVR]] [[Category:MIPS]] | ||
Aktuálna revízia z 15:57, 12. máj 2026
Záverečný projekt predmetu MIPS / LS2026 - Kristian Rostupytskyi
Zadanie
Cieľom projektu bolo pripojiť viacero tlačidiel k mikrokontroléru Arduino s čipom ATmega328P pomocou jedného analógového vstupu a A/D prevodníka. Projekt demonštruje možnosť rozlišovania viacerých stavov tlačidiel podľa rôznych hodnôt napätia získaných cez rezistorovú sieť.
Úlohou bolo:
- pripojiť 5 tlačidiel cez rezistory,
- využiť iba jeden analógový vstup mikrokontroléra,
- merať hodnotu napätia pomocou A/D prevodníka,
- zobrazovať zmeny hodnôt v konzole programu AVR Studio.
Literatúra:
Analýza a opis riešenia
Teoretický úvod
Mikrokontrolér ATmega328P obsahuje vstavaný 10-bitový A/D prevodník (ADC – Analog to Digital Converter), ktorý prevádza analógové napätie na digitálnu hodnotu v rozsahu 0 – 1023.
Každé tlačidlo bolo pripojené cez rezistor s odlišnou hodnotou. Po stlačení konkrétneho tlačidla vznikne na analógovom vstupe iné napätie, ktoré ADC prevedie na inú digitálnu hodnotu.
Vďaka tomu je možné pomocou jediného analógového vstupu rozlišovať viacero tlačidiel.
Výhody riešenia:
- úspora vstupných pinov mikrokontroléra,
- jednoduché zapojenie,
- možnosť rozšírenia o ďalšie tlačidlá.
Nevýhody:
- menšia presnosť pri väčšom počte tlačidiel,
- citlivosť na toleranciu rezistorov,
- možnosť nepresných hodnôt pri súčasnom stlačení viacerých tlačidiel.
Použité komponenty
- Arduino / ATmega328P
- 5 tlačidiel
- rezistory
- prepojovacie vodiče
- AVR Studio
Schéma zapojenia
Tlačidlá boli pripojené cez rezistorový delič na jeden analógový vstup mikrokontroléra. Každé tlačidlo malo vlastný rezistor, čím vznikla jedinečná hodnota napätia pre každé tlačidlo.
Princíp zapojenia:
- bez stlačenia tlačidla je na vstupe základná hodnota,
- po stlačení tlačidla sa zmení napätie,
- ADC prevedie napätie na digitálnu hodnotu,
- program vyhodnotí rozsah hodnoty a určí stlačené tlačidlo.

Algoritmus a program
Hlavné časti programu:
1. Inicializácia A/D prevodníka
- nastavenie referenčného napätia,
- nastavenie prescalera,
- povolenie ADC.
2. Čítanie analógovej hodnoty
- spustenie konverzie,
- čakanie na dokončenie prevodu,
- načítanie hodnoty z registra ADC.
3. Vyhodnotenie tlačidiel
- porovnanie načítanej hodnoty s intervalmi,
- určenie stlačeného tlačidla.
4. Výpis do konzoly
- zobrazenie aktuálnej hodnoty ADC,
- zobrazenie informácie o stlačenom tlačidle.
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "hardware.h"
#include "uart.h"
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
#define toggle_bit(ADDRESS,BIT) (ADDRESS ^= (1<<BIT))
FILE uart_stream = FDEV_SETUP_STREAM(uart_putc, uart_getc, _FDEV_SETUP_RW);
volatile unsigned int oldICR = 0;
volatile unsigned int Ton = 0;
volatile unsigned int Toff = 0;
volatile unsigned char edge = 0; // 0=rising, 1=falling
void timer1_init(void)
{
TCCR1A = 0x00; // normal mode
TCCR1B = (1<<CS12) | (1<<CS10); // prescaler 1024
TCCR1B |= (1<<ICES1); // rising edge first
TCNT1 = 0;
TIMSK1 = (1<<ICIE1);
}
ISR(TIMER1_CAPT_vect)
{
unsigned int diff = ICR1 - oldICR;
oldICR = ICR1;
if(edge == 0)
{
Toff = diff;
TCCR1B &= ~(1<<ICES1);
edge = 1;
}
else
{
Ton = diff;
TCCR1B |= (1<<ICES1);
edge = 0;
unsigned long Ton_us = (unsigned long)Ton * 64;
unsigned long Toff_us = (unsigned long)Toff * 64;
unsigned long Ttotal = Ton_us + Toff_us;
unsigned long period_ms = Ttotal / 1000;
unsigned long duty = (Ton_us * 100) / Ttotal;
printf("Period: %lu ms | Duty: %lu %%\n", period_ms, duty);
}
}
int main(void)
{
hw_init();
hw_init1();
uart_init();
stdout = &uart_stream;
timer1_init();
sei();
printf("Ready to measure...\n");
while(1)
{
}
return 0;
}
#define set_bit(ADDRESS, BIT)(ADDRESS |= (1 << BIT))
#define clear_bit(ADDRESS, BIT)(ADDRESS &= ~(1 << BIT))
#ifndef UART_H_
#define UART_H_
#include <stdio.h>
#define BAUD_PRESCALE(((F_CPU / (BAUDRATE * 16 UL))) - 1)
void uart_init(void);
int uart_putc(char c, FILE * stream);
void uart_puts(const char * s);
char uart_getc(void);
void delay(int delay);
#endif /* UART_H_ */
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
void uart_init(void) {
#include <util/setbaud.h>
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= (1 << U2X0);
#else
UCSR0A &= ~(1 << U2X0);
#endif
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00);
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
}
int uart_putc(char c, FILE * stream) {
if (c == '\n') {
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = '\r';
}
loop_until_bit_is_set(UCSR0A, UDRE0);
UDR0 = c;
return 0;
}
void uart_puts(const char * s) {}
char uart_getc(void) {
loop_until_bit_is_set(UCSR0A, RXC0);
return UDR0;
}
void delay(int delay) {
for (int i = 1; i <= delay; i++)
_delay_ms(1);
}
Zdrojový kód: zdrojaky.zip
Overenie
Video:
Výsledok projektu
Projekt úspešne preukázal možnosť pripojenia viacerých tlačidiel pomocou jedného analógového vstupu a A/D prevodníka mikrokontroléra ATmega328P. Pri stlačení tlačidiel sa správne menila hodnota signálu a program dokázal rozpoznať jednotlivé tlačidlá podľa nameraných hodnôt ADC.
Čo by som urobil inak
Počas realizácie projektu sa mi nepodarilo hneď správne nastaviť hodnoty rezistorov pre všetkých 5 tlačidiel. Pri pripojení 4. tlačidla vznikol problém, pretože konzola nevedela spoľahlivo rozlíšiť rozdiel medzi signálom 3. a 4. tlačidla. Hodnoty ADC boli príliš podobné, a preto bolo potrebné použiť ďalší rezistor, aby vznikol väčší rozdiel napätí medzi jednotlivými tlačidlami. Nabudúce by som si vopred lepšie vypočítal alebo odmeral vhodné hodnoty rezistorov. Taktiež som sa pokúšal namiesto výpisu hodnôt do konzoly použiť žiarovku alebo LED diódu a meniť jej jas podľa stlačeného tlačidla. Tento spôsob sa mi však nepodarilo správne sprevádzkovať. Pravdepodobne boli rozdiely medzi jednotlivými hodnotami signálu príliš malé, a preto zmena jasu nebola viditeľná. Nabudúce by som použil väčšie rozdiely napätí alebo PWM reguláciu jasu, aby boli zmeny lepšie viditeľné.