Operácie

7-segmentový displej na futbal: Rozdiel medzi revíziami

Z SensorWiki

(Analýza a opis riešenia)
(Algoritmus a program)
 
(35 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 10: Riadok 10:
 
'''Literatúra:'''  
 
'''Literatúra:'''  
 
* [http://ap.urpi.fei.stuba.sk/sensorwiki/index.php/Acrob_technical_description Dokumentácia k doske Acrob]
 
* [http://ap.urpi.fei.stuba.sk/sensorwiki/index.php/Acrob_technical_description Dokumentácia k doske Acrob]
 +
* [https://github.com/avishorp/TM1637 Dokumentacia k TM1637 displeji]
 +
* [https://github.com/TeWu/TM1637 Kniznice k TM1637 displeji]
  
  
Riadok 18: Riadok 20:
 
Princíp fungovania bol jednoduchý, ak stlačíme tlačidlo príslušné k prvému tímu, meníme skóre prvého tímu a ak stlačíme tlačidlo príslušné k druhému tímu, meníme skóre druhého tímu. Takisto máme tlačidlo RESET, ktoré celé skóre resetuje. Na správne fungovanie sme si vytvorili knižnicu, v ktorej sme zadefinovali čísla od 0-9 pomocou zapnutých a vypnutých segmentov na 7 segmentovke.
 
Princíp fungovania bol jednoduchý, ak stlačíme tlačidlo príslušné k prvému tímu, meníme skóre prvého tímu a ak stlačíme tlačidlo príslušné k druhému tímu, meníme skóre druhého tímu. Takisto máme tlačidlo RESET, ktoré celé skóre resetuje. Na správne fungovanie sme si vytvorili knižnicu, v ktorej sme zadefinovali čísla od 0-9 pomocou zapnutých a vypnutých segmentov na 7 segmentovke.
  
[[Súbor:ledRGB.jpg|400px|thumb|center|RGB LED.]]
+
[[Súbor:TM1637-Display-Module-Parts.jpg|600px|thumb|center|TM1637 displej]]
  
Nezabudnite doplniť schému zapojenia!
 
  
[[Súbor:schd.png|400px|thumb|center|Schéma zapojenia LCD displeja.]]
+
[[Súbor:zapojenie_futbal.jpg|800px|thumb|center|Schéma zapojenia TM1637 7 segmentového displeja]]
  
  
 
=== Algoritmus a program ===
 
=== Algoritmus a program ===
  
Algoritmus programu je....
+
Tento program sme vytvorili na ovládanie 7 segmentového displeja pomocou tlačidiel a následného zobrazovania futbalového skóre pomocou tlačidiel. Najprv sme si vytvorili knižnicu do ktorej sme uložili čísla od 0-9 na zobrazenie čísiel pomocou svietiacich a zhasnutých segmentov. Následne sme si vytvorili funkcie na zapnutie a vypnutie komunikácie. Potom sme si vytvorili funkcie na inicializáciu, nastavenie segmentov a ich následné zobrazenie. Všetky tieto funkcie sme uložili do uart.c (resp. SemProj_uart.c).
 +
 
 +
Nakoniec sme pre INT0 a INT1 spravili funkcie, jedna pre ľavú stranu a druhá pre pravú stranu, v ktorých po stlačení tlačidla nastalo zvýšenie hodnoty o 1, kde ak sme dosiahli číslo 99 a zvýšili sme ho, číslo sa nám resetovalo naspäť na 0, keďže na číselné hodnoty sme mali iba 2 7 - segmentové displeje. Keď sme mali všetky tieto funkcie zadefinované, v hlavnej časti programu sme CLK, DIO aj všetky ostatné piny  nastavili opäť ako input, povolili sme INT0 a INT1 takisto sei().
 +
 
 +
Následne vo while funkcii sme už len dané čísla, ktoré boli uložené v counter_left a counter_right zobrazovali pomocou našej funkcie pre zobrazenie čísla na 7 segmentovke, kde sme pozíciu čísel nastavili na pravú 7 segmentovku z dvojice (čiže celkovo 2. a 4. 7 segmentovka) a po zvýšení čísla na 10 a viac sa začali využívať obe 7 segmentové displeje pre daný tím. Po stlačení tlačidla RESET sa hodnoty v counter_left a counter_right vynulovali a opäť sa využívali iba pravé 7 segmentovky z dvojice. Takto to funguje donekonečna.
  
  
 
<tabs>
 
<tabs>
 
<tab name="SemProj"><source lang="c++" style="background: LightYellow;">
 
<tab name="SemProj"><source lang="c++" style="background: LightYellow;">
#include <avr/io.h>
 
 
#define F_CPU 16000000UL  // Define CPU frequency
 
 
 
// Required libraries
 
// Required libraries
#include <stdio.h>
 
 
#include <avr/io.h>
 
#include <avr/io.h>
 
#include <util/delay.h>
 
#include <util/delay.h>
 
#include <avr/interrupt.h>
 
#include <avr/interrupt.h>
 +
#include "uart.h"
 +
 +
#define CLK  PD5  // CLK -> pin 5
 +
#define DIO  PD4  // DIO -> pin 4
  
  
 
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
 
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
 
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
 
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
 +
 +
 +
#define LEFT_START_STOP_PIN PD2 // Tlacidlo pre lavy tim
 +
#define RIGHT_START_STOP_PIN PD3 // Tlacidlo pre pravy tim
 +
#define RESTART_PIN PD6 // Tlacidlo na vynulovanie skore
 +
 +
 +
 +
 +
 +
volatile uint8_t count_left = 0;  // Pocitadlo skore pre lavu dvojicu 7 segmentoviek
 +
volatile uint8_t count_right = 0; // Pocitadlo skore pre pravu dvojicu 7 segmentoviek
 +
 +
 +
 +
// External interrupt 0 (Tlacidlo pre lavy tim)
 +
ISR (INT0_vect)
 +
{
 +
 +
 +
    _delay_ms(10);
 +
    if(bit_is_clear(PIND, LEFT_START_STOP_PIN)){
 +
        // Zvysuje skore laveho time a pri dosiahnuti hodnoty 100 zresetuje hodnotu na 0
 +
        count_left++;
 +
 +
        if (count_left >= 100) count_left = 0;
 +
    }
 +
    _delay_ms(150);
 +
}
 +
 +
// External interrupt 1 (tlacidlo pre pravy tim)
 +
ISR (INT1_vect)
 +
{
 +
    _delay_ms(10);
 +
    if(bit_is_clear(PIND, RIGHT_START_STOP_PIN)){
 +
        // Zvysuje skore praveho time a pri dosiahnuti hodnoty 100 zresetuje hodnotu na 0
 +
        count_right++;
 +
        if (count_right >= 100) count_right = 0;
 +
    }
 +
    _delay_ms(150);
 +
}
 +
 +
 +
int main(void){
 +
   
 +
    clear_bit(DDRD, CLK);  // Nastavenie CLK ako input
 +
    set_bit(PORTD, CLK);  // CLK ako input pull-up on
 +
   
 +
    clear_bit(DDRD, DIO);  // Nastavenie DIO ako input
 +
    set_bit(PORTD, DIO);  // DIO ako input pull-up o
 +
   
 +
    clear_bit(DDRD, LEFT_START_STOP_PIN);  // Nastavenie LEFT_START_STOP_PIN ako input
 +
    set_bit(PORTD, LEFT_START_STOP_PIN);    // LEFT_START_STOP_PIN ako input pull-up on
 +
   
 +
    clear_bit(DDRD, RIGHT_START_STOP_PIN);  // Nastavenie RIGHT_START_STOP_PIN ako input
 +
    set_bit(PORTD, RIGHT_START_STOP_PIN);  // RIGHT_START_STOP_PIN ako input pull-up on
 +
 +
clear_bit(DDRD, RESTART_PIN);  // Nastavenie RESET_PIN ako input
 +
set_bit(PORTD, RESTART_PIN);  // RESET_PIN ako input pull-up on
 +
 +
    uint8_t data[] = { 0, 0, 0, 0 };
 +
    set_segments(data, 4, 0);
 +
 +
   
 +
    EIMSK = 0b00000011; // Povolenie INT0, INT1
 +
    EICRA = 0b00001010;      // Zaznamenanie dobeznej hrany na oboch pinoch
 +
   
 +
    sei();  // Povolit prerusenia
 +
   
 +
 +
   
 +
    while (1) {
 +
if (bit_is_clear(PIND, RESTART_PIN)) {
 +
// Spusti reset
 +
 +
count_left = 0; // Resetuje skore laveho timu
 +
count_right = 0; // Resetuje skore praveho timu
 +
 +
}
 +
 +
// Zobrazenie skore laveho timu na lavych 2 7 segmentovkach a skore praveho timu na pravych 2 7 segmentovkach
 +
 +
display_number_segment(count_right, 0, 2, 2);
 +
 +
display_number_segment(count_left, 0, 2, 0);
 +
 +
    }
 +
   
 +
    return 0;
 +
}
 +
</source></tab>
 +
<tab name="SemProj_uart.c"><source lang="c++" style="background: LightYellow;">
 +
#include <avr/io.h>
 +
#include <util/delay.h>
 +
#include "uart.h"
  
 
#define CLK  PD5  // CLK -> pin 5 portD.5
 
#define CLK  PD5  // CLK -> pin 5 portD.5
 
#define DIO  PD4  // DIO -> pin 4 portD.4
 
#define DIO  PD4  // DIO -> pin 4 portD.4
 
#define LEFT_START_STOP_PIN PD2 // Left team score button
 
#define RIGHT_START_STOP_PIN PD3 // Right team score button
 
#define RESTART_PIN PD6 // Restart button
 
  
 
#define BIT_DELAY 100  // Delay 100ms
 
#define BIT_DELAY 100  // Delay 100ms
Riadok 60: Riadok 155:
 
#define TM1637_I2C_COMM3    0x80
 
#define TM1637_I2C_COMM3    0x80
  
// 7-segment display digit mapping
+
// Nastavenie cisiel na 7 segmentovom displeji
 
const uint8_t digitToSegment[] = {
 
const uint8_t digitToSegment[] = {
 
     // XGFEDCBA
 
     // XGFEDCBA
Riadok 80: Riadok 175:
 
     0b01110001    // F
 
     0b01110001    // F
 
};
 
};
 
static const uint8_t minusSegments = 0b01000000;
 
  
 
uint8_t brightness = (0x7 & 0x7) | 0x08;
 
uint8_t brightness = (0x7 & 0x7) | 0x08;
  
 
+
static const uint8_t minusSegments = 0b01000000;
void comunication_start(){
 
    set_bit(DDRD, DIO);   // Set DIO as output
 
    clear_bit(PORTD, DIO); // Set DIO as output
 
    _delay_us(BIT_DELAY);
 
}
 
 
 
void comunication_stop(){
 
    set_bit(DDRD, DIO);    // Set DIO as output
 
    clear_bit(PORTD, DIO); // Set DIO as output
 
    _delay_us(BIT_DELAY);
 
   
 
    clear_bit(DDRD, CLK);  // Set CLK as input
 
    set_bit(PORTD, CLK);  // CLK as input pull-up on
 
    _delay_us(BIT_DELAY);
 
   
 
    clear_bit(DDRD, DIO);  // Set DIO as input
 
    set_bit(PORTD, DIO);  // DIO as input pull-up on
 
    _delay_us(BIT_DELAY);
 
}
 
  
 
int inicialize_bit(uint8_t byte){
 
int inicialize_bit(uint8_t byte){
Riadok 118: Riadok 192:
 
         // Set data bit
 
         // Set data bit
 
         if (data & 0x01){
 
         if (data & 0x01){
             clear_bit(DDRD, DIO);  // Set DIO as input
+
             clear_bit(DDRD, DIO);  // Nastavenie DIO ako input
             set_bit(PORTD, DIO);  // DIO as input pull-up on
+
             set_bit(PORTD, DIO);  // DIO ako input pull-up on
 
         } else{
 
         } else{
             set_bit(DDRD, DIO);    // Set DIO as output
+
             set_bit(DDRD, DIO);    // Nastavenie DIO ako output
             clear_bit(PORTD, DIO); // Set DIO low
+
             clear_bit(PORTD, DIO); // Nastavenie DIO low
 
         }
 
         }
 
          
 
          
Riadok 128: Riadok 202:
 
          
 
          
 
         // CLK high
 
         // CLK high
         clear_bit(DDRD, CLK);  // Set CLK as input
+
         clear_bit(DDRD, CLK);  // Nastavenie CLK ako input
         set_bit(PORTD, CLK);  // CLK as input pull-up on
+
         set_bit(PORTD, CLK);  // CLK ako input pull-up on
 
         _delay_us(BIT_DELAY);
 
         _delay_us(BIT_DELAY);
 
         data = data >> 1;
 
         data = data >> 1;
Riadok 136: Riadok 210:
 
     // Wait for acknowledge
 
     // Wait for acknowledge
 
     // CLK to zero
 
     // CLK to zero
     set_bit(DDRD, CLK);    // Set CLK as output
+
     set_bit(DDRD, CLK);    // Nastavenie CLK ako output
     clear_bit(PORTD, CLK);  // Set CLK low
+
     clear_bit(PORTD, CLK);  // Nastavenie CLK low
 
      
 
      
     clear_bit(DDRD, DIO);  // Set DIO as input
+
     clear_bit(DDRD, DIO);  // Nastavenie DIO ako input
     set_bit(PORTD, DIO);    // DIO as input pull-up on
+
     set_bit(PORTD, DIO);    // DIO ako input pull-up on
 
     _delay_us(BIT_DELAY);
 
     _delay_us(BIT_DELAY);
 
      
 
      
 
     // CLK to high
 
     // CLK to high
     clear_bit(DDRD, CLK);  // Set CLK as input
+
     clear_bit(DDRD, CLK);  // Nastavenie CLK ako input
     set_bit(PORTD, CLK);    // Set CLK high
+
     set_bit(PORTD, CLK);    // Nastavenie CLK high
 
     _delay_us(BIT_DELAY);
 
     _delay_us(BIT_DELAY);
 
     uint8_t ack = !bit_is_clear(PIND, DIO);
 
     uint8_t ack = !bit_is_clear(PIND, DIO);
 
     if (ack == 0)
 
     if (ack == 0)
         set_bit(DDRD, DIO);  // Set DIO as output
+
         set_bit(DDRD, DIO);  // Nastavenie DIO ako output
     clear_bit(PORTD, DIO);  // Set DIO low
+
     clear_bit(PORTD, DIO);  // Nastavenie DIO low
 
      
 
      
 
     _delay_us(BIT_DELAY);
 
     _delay_us(BIT_DELAY);
     set_bit(DDRD, CLK);    // Set CLK as output
+
     set_bit(DDRD, CLK);    // Nastavenie CLK ako output
     clear_bit(PORTD, CLK); // Set CLK low
+
     clear_bit(PORTD, CLK); // Nastavenie CLK low
 
     _delay_us(BIT_DELAY);
 
     _delay_us(BIT_DELAY);
 
      
 
      
 
     return ack;
 
     return ack;
 
}
 
}
 +
 +
 +
void comunication_start(){
 +
    set_bit(DDRD, DIO);    // Nastavenie DIO ako output
 +
    clear_bit(PORTD, DIO); // Nastavenie DIO ako output
 +
    _delay_us(BIT_DELAY);
 +
}
 +
 +
void comunication_stop(){
 +
    set_bit(DDRD, DIO);    // Nastavenie DIO ako output
 +
    clear_bit(PORTD, DIO); // Nastavenie DIO ako output
 +
    _delay_us(BIT_DELAY);
 +
   
 +
    clear_bit(DDRD, CLK);  // Nastavenie CLK ako input
 +
    set_bit(PORTD, CLK);  // CLK ako input pull-up on
 +
    _delay_us(BIT_DELAY);
 +
   
 +
    clear_bit(DDRD, DIO);  // Nastavenie DIO ako input
 +
    set_bit(PORTD, DIO);  // DIO ako input pull-up on
 +
    _delay_us(BIT_DELAY);
 +
}
 +
  
 
void displayShowDots(uint8_t dots, uint8_t* digits){
 
void displayShowDots(uint8_t dots, uint8_t* digits){
Riadok 168: Riadok 264:
 
}
 
}
  
void set_segments(const uint8_t segments[], uint8_t length, uint8_t pos){
+
 
     // Write COMM1
+
// Funkcia na zobrazenie cisla
    comunication_start();
+
void display_middle_dots(int num, uint8_t dots, const int leading_zero, uint8_t length, uint8_t pos){
    inicialize_bit(TM1637_I2C_COMM1);
+
     display_number(num < 0? -10 : 10, num < 0? -num : num, dots, leading_zero, length, pos);
    comunication_stop();
 
   
 
    // Write COMM2 + first digit address
 
    comunication_start();
 
    inicialize_bit(TM1637_I2C_COMM2 + (pos & 0x03));
 
   
 
    // Write the data bytes
 
    for (uint8_t k=0; k < length; k++)
 
        inicialize_bit(segments[k]);
 
   
 
    comunication_stop();
 
   
 
    // Write COMM3 + brightness
 
    comunication_start();
 
    inicialize_bit(TM1637_I2C_COMM3 + (brightness & 0x0f));
 
    comunication_stop();
 
 
}
 
}
  
 
+
// Funkcia na zobrazenie cisla v danom zaklade
// Function to display a number in a given base with custom options
+
void display_number(int8_t base, uint16_t num, uint8_t dots, const int leading_zero, uint8_t length, uint8_t pos)
void display_number(int8_t base, uint16_t num, uint8_t dots, const int leading_zero,
 
                              uint8_t length, uint8_t pos)
 
 
{
 
{
 
     int negative = 0; // False
 
     int negative = 0; // False
Riadok 204: Riadok 282:
 
      
 
      
 
     if (num == 0 && !leading_zero) {
 
     if (num == 0 && !leading_zero) {
        // Singular case - take care separately
 
 
         for(uint8_t i = 0; i < (length-1); i++)
 
         for(uint8_t i = 0; i < (length-1); i++)
 
             digits[i] = 0;
 
             digits[i] = 0;
Riadok 215: Riadok 292:
 
              
 
              
 
             if (digit == 0 && num == 0 && leading_zero == 0)
 
             if (digit == 0 && num == 0 && leading_zero == 0)
                // Leading zero is blank
 
 
                 digits[i] = 0;
 
                 digits[i] = 0;
 
             else
 
             else
Riadok 237: Riadok 313:
 
}
 
}
  
// Function to display a middle dots
+
// Funkcia na zobrazenie cisla s default nastaveniami
void display_middle_dots(int num, uint8_t dots, const int leading_zero,
 
                            uint8_t length, uint8_t pos){
 
    display_number(num < 0? -10 : 10, num < 0? -num : num, dots, leading_zero, length, pos);
 
}
 
 
 
// Function to display a decimal number with default options
 
 
void display_number_segment(int num, const int leading_zero, uint8_t length, uint8_t pos){
 
void display_number_segment(int num, const int leading_zero, uint8_t length, uint8_t pos){
 
     display_middle_dots(num,  0x40, leading_zero, length, pos);
 
     display_middle_dots(num,  0x40, leading_zero, length, pos);
 
}
 
}
  
volatile uint8_t count_left = 0; // Counter for the left displays
+
void set_segments(const uint8_t segments[], uint8_t length, uint8_t pos){
volatile uint8_t count_right = 0; // Counter for the right displays
+
    // Zapis COMM1
 
+
    comunication_start();
 +
    inicialize_bit(TM1637_I2C_COMM1);
 +
    comunication_stop();
 +
   
 +
    // Zapis COMM2 + prvu cislicu adresy
 +
    comunication_start();
 +
    inicialize_bit(TM1637_I2C_COMM2 + (pos & 0x03));
 +
   
 +
    // Zapis datove bajty
 +
    for (uint8_t k=0; k < length; k++)
 +
        inicialize_bit(segments[k]);
 +
   
 +
    comunication_stop();
 +
   
 +
    // Zapis COMM3 + brightness
 +
    comunication_start();
 +
    inicialize_bit(TM1637_I2C_COMM3 + (brightness & 0x0f));
 +
    comunication_stop();
 +
}
  
  
// External interrupt 0 (button for the left team)
 
ISR (INT0_vect)
 
{
 
 
 
    _delay_ms(10);
 
    if(bit_is_clear(PIND, LEFT_START_STOP_PIN)){
 
        // Increase left count and reset if it reaches 100
 
        count_left++;
 
 
        if (count_left >= 100) count_left = 0;
 
    }
 
    _delay_ms(150);
 
}
 
  
// External interrupt 1 (button for the right team)
 
ISR (INT1_vect)
 
{
 
    _delay_ms(10);
 
    if(bit_is_clear(PIND, RIGHT_START_STOP_PIN)){
 
        // Increase right count and reset if it reaches 100
 
        count_right++;
 
        if (count_right >= 100) count_right = 0;
 
    }
 
    _delay_ms(150);
 
}
 
  
 +
</source></tab>
 +
<tab name="SemProj_uart.h"><source lang="c++" style="background: LightYellow;">
 +
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
 +
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
  
int main(void){
+
#ifndef UART_H_
   
+
#define UART_H_
    clear_bit(DDRD, CLK);  // Set CLK as input
 
    set_bit(PORTD, CLK);  // CLK as input pull-up on
 
   
 
    clear_bit(DDRD, DIO);  // Set DIO as input
 
    set_bit(PORTD, DIO);  // DIO as input pull-up o
 
   
 
    clear_bit(DDRD, LEFT_START_STOP_PIN);  // Set LEFT_START_STOP_PIN as input
 
    set_bit(PORTD, LEFT_START_STOP_PIN);    // LEFT_START_STOP_PIN as input pull-up on
 
   
 
    clear_bit(DDRD, RIGHT_START_STOP_PIN);  // Set RIGHT_START_STOP_PIN as input
 
    set_bit(PORTD, RIGHT_START_STOP_PIN);  // RIGHT_START_STOP_PIN as input pull-up on
 
 
clear_bit(DDRD, RESTART_PIN);  // set RESET_PIN as input
 
set_bit(PORTD, RESTART_PIN);  // RESET_PIN as input pull-up on
 
 
    uint8_t data[] = { 0, 0, 0, 0 };
 
    set_segments(data, 4, 0);
 
  
   
+
void comunication_start();
    EIMSK = 0b00000011; // Enable INT0, INT1
+
void comunication_stop();
    EICRA = 0b00001010;       // Detect falling edge on both pins
+
void displayShowDots(uint8_t dots, uint8_t* digits);
   
+
int inicialize_bit(uint8_t byte);
    sei(); // Enable interrupts
+
void display_middle_dots(int num, uint8_t dots, const int leading_zero, uint8_t length, uint8_t pos);
   
+
void display_number(int8_t base, uint16_t num, uint8_t dots, const int leading_zero, uint8_t length, uint8_t pos);
    set_bit(DDRB, PB5);
+
void display_number_segment(int num, const int leading_zero, uint8_t length, uint8_t pos);
   
+
void set_segments(const uint8_t segments[], uint8_t length, uint8_t pos);
    while (1) {
 
if (bit_is_clear(PIND, RESTART_PIN)) {
 
// Perform reset operation
 
 
count_left = 0; // Reset the left count
 
count_right = 0; // Reset the right count
 
 
}
 
  
// Display left count on left two displays and right count on right two displays
 
 
display_number_segment(count_right, 0, 2, 2);
 
 
display_number_segment(count_left, 0, 2, 0);
 
  
    }
+
#endif /* UART_H_ */
   
+
</source></tab>
    return 0;
 
}</source></tab>
 
 
</tabs>
 
</tabs>
  
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: [[Médiá:SemProj_Žula.zip|zdrojaky.zip]]
 
 
Zdrojový kód: [[Médiá:projektMenoPriezvisko.zip|zdrojaky.zip]]
 
  
 
=== Overenie ===
 
=== Overenie ===
Riadok 338: Riadok 371:
 
Na zobrazovanie aktuálneho skóre používame dve tlačidlá, jedným, ktorý je vľavo meníme skóre tímu vľavo, a druhým, ktorý je v strede meníme skóre tímu ktorý je napravo, posledným tlačidlom ktoré je vpravo skóre resetujeme.
 
Na zobrazovanie aktuálneho skóre používame dve tlačidlá, jedným, ktorý je vľavo meníme skóre tímu vľavo, a druhým, ktorý je v strede meníme skóre tímu ktorý je napravo, posledným tlačidlom ktoré je vpravo skóre resetujeme.
  
[[Súbor:projektfoto.jpg|400px|thumb|center|Aplikácia.]]
+
[[Súbor:projektfoto.jpg|400px|thumb|center|Zapojenie 7 - segmentového displeja pre zobrazenie futbalového skóre spolu s tlačidlami]]
  
 
'''Video:'''
 
'''Video:'''
 
<center><youtube>nTv-t7sA78s</youtube></center>
 
<center><youtube>nTv-t7sA78s</youtube></center>
 
Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.
 
  
 
[[Category:AVR]] [[Category:MIPS]]
 
[[Category:AVR]] [[Category:MIPS]]

Aktuálna revízia z 13:47, 6. máj 2024

Záverečný projekt predmetu MIPS / LS2024 - Daniel Žula


Zadanie

Pripojenie 7 - segmentového LED displeja k vývojovej doske, vytvorenie potrebných knižníc a funkcií. Cieľom je, aby sme dokázali zobraziť skóre futbalového zápasu, ktoré dokážeme meniť podľa potreby pomocou tlačidiel.

Vývojová doska ACROB.

Literatúra:


Analýza a opis riešenia

Princíp fungovania bol jednoduchý, ak stlačíme tlačidlo príslušné k prvému tímu, meníme skóre prvého tímu a ak stlačíme tlačidlo príslušné k druhému tímu, meníme skóre druhého tímu. Takisto máme tlačidlo RESET, ktoré celé skóre resetuje. Na správne fungovanie sme si vytvorili knižnicu, v ktorej sme zadefinovali čísla od 0-9 pomocou zapnutých a vypnutých segmentov na 7 segmentovke.

TM1637 displej


Schéma zapojenia TM1637 7 segmentového displeja


Algoritmus a program

Tento program sme vytvorili na ovládanie 7 segmentového displeja pomocou tlačidiel a následného zobrazovania futbalového skóre pomocou tlačidiel. Najprv sme si vytvorili knižnicu do ktorej sme uložili čísla od 0-9 na zobrazenie čísiel pomocou svietiacich a zhasnutých segmentov. Následne sme si vytvorili funkcie na zapnutie a vypnutie komunikácie. Potom sme si vytvorili funkcie na inicializáciu, nastavenie segmentov a ich následné zobrazenie. Všetky tieto funkcie sme uložili do uart.c (resp. SemProj_uart.c).

Nakoniec sme pre INT0 a INT1 spravili funkcie, jedna pre ľavú stranu a druhá pre pravú stranu, v ktorých po stlačení tlačidla nastalo zvýšenie hodnoty o 1, kde ak sme dosiahli číslo 99 a zvýšili sme ho, číslo sa nám resetovalo naspäť na 0, keďže na číselné hodnoty sme mali iba 2 7 - segmentové displeje. Keď sme mali všetky tieto funkcie zadefinované, v hlavnej časti programu sme CLK, DIO aj všetky ostatné piny nastavili opäť ako input, povolili sme INT0 a INT1 takisto sei().

Následne vo while funkcii sme už len dané čísla, ktoré boli uložené v counter_left a counter_right zobrazovali pomocou našej funkcie pre zobrazenie čísla na 7 segmentovke, kde sme pozíciu čísel nastavili na pravú 7 segmentovku z dvojice (čiže celkovo 2. a 4. 7 segmentovka) a po zvýšení čísla na 10 a viac sa začali využívať obe 7 segmentové displeje pre daný tím. Po stlačení tlačidla RESET sa hodnoty v counter_left a counter_right vynulovali a opäť sa využívali iba pravé 7 segmentovky z dvojice. Takto to funguje donekonečna.


// Required libraries
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>
#include "uart.h"

#define CLK  PD5  // CLK -> pin 5 
#define DIO  PD4  // DIO -> pin 4 


#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))


#define LEFT_START_STOP_PIN PD2 // Tlacidlo pre lavy tim
#define RIGHT_START_STOP_PIN PD3 // Tlacidlo pre pravy tim
#define RESTART_PIN PD6 // Tlacidlo na vynulovanie skore





volatile uint8_t count_left = 0;  // Pocitadlo skore pre lavu dvojicu 7 segmentoviek
volatile uint8_t count_right = 0; // Pocitadlo skore pre pravu dvojicu 7 segmentoviek



// External interrupt 0 (Tlacidlo pre lavy tim)
ISR (INT0_vect)
{
	

    _delay_ms(10);
    if(bit_is_clear(PIND, LEFT_START_STOP_PIN)){
        // Zvysuje skore laveho time a pri dosiahnuti hodnoty 100 zresetuje hodnotu na 0
        count_left++;
		
        if (count_left >= 100) count_left = 0;
    }
    _delay_ms(150);
}

// External interrupt 1 (tlacidlo pre pravy tim)
ISR (INT1_vect)
{
    _delay_ms(10);
    if(bit_is_clear(PIND, RIGHT_START_STOP_PIN)){
        // Zvysuje skore praveho time a pri dosiahnuti hodnoty 100 zresetuje hodnotu na 0
        count_right++;
        if (count_right >= 100) count_right = 0;
    }
    _delay_ms(150);
}


int main(void){
    
    clear_bit(DDRD, CLK);  // Nastavenie CLK ako input
    set_bit(PORTD, CLK);   // CLK ako input pull-up on
    
    clear_bit(DDRD, DIO);  // Nastavenie DIO ako input
    set_bit(PORTD, DIO);   // DIO ako input pull-up o
    
    clear_bit(DDRD, LEFT_START_STOP_PIN);   // Nastavenie LEFT_START_STOP_PIN ako input
    set_bit(PORTD, LEFT_START_STOP_PIN);    // LEFT_START_STOP_PIN ako input pull-up on
    
    clear_bit(DDRD, RIGHT_START_STOP_PIN);  // Nastavenie RIGHT_START_STOP_PIN ako input
    set_bit(PORTD, RIGHT_START_STOP_PIN);   // RIGHT_START_STOP_PIN ako input pull-up on
	
	clear_bit(DDRD, RESTART_PIN);  // Nastavenie RESET_PIN ako input
	set_bit(PORTD, RESTART_PIN);  // RESET_PIN ako input pull-up on
	
    uint8_t data[] = { 0, 0, 0, 0 };
    set_segments(data, 4, 0);

    
    EIMSK = 0b00000011; // Povolenie INT0, INT1
    EICRA = 0b00001010;       // Zaznamenanie dobeznej hrany na oboch pinoch
    
    sei();  // Povolit prerusenia
    

    
    while (1) {
		if (bit_is_clear(PIND, RESTART_PIN)) {
			// Spusti reset
			
			count_left = 0; // Resetuje skore laveho timu
			count_right = 0; // Resetuje skore praveho timu
			
			}

			// Zobrazenie skore laveho timu na lavych 2 7 segmentovkach a skore praveho timu na pravych 2 7 segmentovkach
			
			display_number_segment(count_right, 0, 2, 2);
			
			display_number_segment(count_left, 0, 2, 0);

    }
    
    return 0;
}
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"

#define CLK  PD5  // CLK -> pin 5 portD.5
#define DIO  PD4  // DIO -> pin 4 portD.4

#define BIT_DELAY 100  // Delay 100ms

// Define for TM1637
#define TM1637_I2C_COMM1    0x40
#define TM1637_I2C_COMM2    0xC0
#define TM1637_I2C_COMM3    0x80

// Nastavenie cisiel na 7 segmentovom displeji
const uint8_t digitToSegment[] = {
    // XGFEDCBA
    0b00111111,    // 0
    0b00000110,    // 1
    0b01011011,    // 2
    0b01001111,    // 3
    0b01100110,    // 4
    0b01101101,    // 5
    0b01111101,    // 6
    0b00000111,    // 7
    0b01111111,    // 8
    0b01101111,    // 9
    0b01110111,    // A
    0b01111100,    // b
    0b00111001,    // C
    0b01011110,    // d
    0b01111001,    // E
    0b01110001     // F
};

uint8_t brightness = (0x7 & 0x7) | 0x08;

static const uint8_t minusSegments = 0b01000000;

int inicialize_bit(uint8_t byte){
    uint8_t data = byte;
    
    // 8 Data Bits
    for(uint8_t i = 0; i < 8; i++) {
        // CLK low
        set_bit(DDRD, CLK);
        clear_bit(PORTD, CLK);
        _delay_us(BIT_DELAY);
        
        // Set data bit
        if (data & 0x01){
            clear_bit(DDRD, DIO);  // Nastavenie DIO ako input
            set_bit(PORTD, DIO);   // DIO ako input pull-up on
        } else{
            set_bit(DDRD, DIO);    // Nastavenie DIO ako output
            clear_bit(PORTD, DIO); // Nastavenie DIO low
        }
        
        _delay_us(BIT_DELAY);
        
        // CLK high
        clear_bit(DDRD, CLK);  // Nastavenie CLK ako input
        set_bit(PORTD, CLK);   // CLK ako input pull-up on
        _delay_us(BIT_DELAY);
        data = data >> 1;
    }
    
    // Wait for acknowledge
    // CLK to zero
    set_bit(DDRD, CLK);     // Nastavenie CLK ako output
    clear_bit(PORTD, CLK);  // Nastavenie CLK low
    
    clear_bit(DDRD, DIO);   // Nastavenie DIO ako input
    set_bit(PORTD, DIO);    // DIO ako input pull-up on
    _delay_us(BIT_DELAY);
    
    // CLK to high
    clear_bit(DDRD, CLK);   // Nastavenie CLK ako input
    set_bit(PORTD, CLK);    // Nastavenie CLK high
    _delay_us(BIT_DELAY);
    uint8_t ack = !bit_is_clear(PIND, DIO);
    if (ack == 0)
        set_bit(DDRD, DIO);  // Nastavenie DIO ako output
    clear_bit(PORTD, DIO);  // Nastavenie DIO low
    
    _delay_us(BIT_DELAY);
    set_bit(DDRD, CLK);    // Nastavenie CLK ako output
    clear_bit(PORTD, CLK); // Nastavenie CLK low
    _delay_us(BIT_DELAY);
    
    return ack;
}


void comunication_start(){
    set_bit(DDRD, DIO);    // Nastavenie DIO ako output
    clear_bit(PORTD, DIO); // Nastavenie DIO ako output
    _delay_us(BIT_DELAY);
}

void comunication_stop(){
    set_bit(DDRD, DIO);    // Nastavenie DIO ako output
    clear_bit(PORTD, DIO); // Nastavenie DIO ako output
    _delay_us(BIT_DELAY);
    
    clear_bit(DDRD, CLK);  // Nastavenie CLK ako input
    set_bit(PORTD, CLK);   // CLK ako input pull-up on
    _delay_us(BIT_DELAY);
    
    clear_bit(DDRD, DIO);  // Nastavenie DIO ako input
    set_bit(PORTD, DIO);   // DIO ako input pull-up on
    _delay_us(BIT_DELAY);
}


void displayShowDots(uint8_t dots, uint8_t* digits){
    for(int i = 0; i < 4; ++i)
    {
        digits[i] |= (dots & 0x80);
        dots <<= 1;
    }
}


// Funkcia na zobrazenie cisla
void display_middle_dots(int num, uint8_t dots, const int leading_zero, uint8_t length, uint8_t pos){
    display_number(num < 0? -10 : 10, num < 0? -num : num, dots, leading_zero, length, pos);
}

// Funkcia na zobrazenie cisla v danom zaklade
void display_number(int8_t base, uint16_t num, uint8_t dots, const int leading_zero, uint8_t length, uint8_t pos)
{
    int negative = 0; // False
    if (base < 0) {
        base = -base;
        negative = 1; // True
    }
    
    uint8_t digits[4];
    
    if (num == 0 && !leading_zero) {
        for(uint8_t i = 0; i < (length-1); i++)
            digits[i] = 0;
        digits[length-1] = digitToSegment[0 & 0x0f];;
    }
    else {
        for(int i = length-1; i >= 0; --i)
        {
            uint8_t digit = num % base;
            
            if (digit == 0 && num == 0 && leading_zero == 0)
                digits[i] = 0;
            else
                digits[i] = digitToSegment[digit & 0x0f];;
            
            if (digit == 0 && num == 0 && negative) {
                digits[i] = minusSegments;
                negative = 0;
            }
            
            num /= base;
        }
    }
    
    if(dots != 0)
    {
        displayShowDots(dots, digits);
    }
    
    set_segments(digits, length, pos);
}

// Funkcia na zobrazenie cisla s default nastaveniami
void display_number_segment(int num, const int leading_zero, uint8_t length, uint8_t pos){
    display_middle_dots(num,  0x40, leading_zero, length, pos);
}

void set_segments(const uint8_t segments[], uint8_t length, uint8_t pos){
    // Zapis COMM1
    comunication_start();
    inicialize_bit(TM1637_I2C_COMM1);
    comunication_stop();
    
    // Zapis COMM2 + prvu cislicu adresy
    comunication_start();
    inicialize_bit(TM1637_I2C_COMM2 + (pos & 0x03));
    
    // Zapis datove bajty
    for (uint8_t k=0; k < length; k++)
        inicialize_bit(segments[k]);
    
    comunication_stop();
    
    // Zapis COMM3 + brightness
    comunication_start();
    inicialize_bit(TM1637_I2C_COMM3 + (brightness & 0x0f));
    comunication_stop();
}
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))

#ifndef UART_H_
#define UART_H_

void comunication_start();
void comunication_stop();
void displayShowDots(uint8_t dots, uint8_t* digits);
int inicialize_bit(uint8_t byte);
void display_middle_dots(int num, uint8_t dots, const int leading_zero, uint8_t length, uint8_t pos);
void display_number(int8_t base, uint16_t num, uint8_t dots, const int leading_zero, uint8_t length, uint8_t pos);
void display_number_segment(int num, const int leading_zero, uint8_t length, uint8_t pos);
void set_segments(const uint8_t segments[], uint8_t length, uint8_t pos);


#endif /* UART_H_ */

Zdrojový kód: zdrojaky.zip

Overenie

Na zobrazovanie aktuálneho skóre používame dve tlačidlá, jedným, ktorý je vľavo meníme skóre tímu vľavo, a druhým, ktorý je v strede meníme skóre tímu ktorý je napravo, posledným tlačidlom ktoré je vpravo skóre resetujeme.

Zapojenie 7 - segmentového displeja pre zobrazenie futbalového skóre spolu s tlačidlami

Video: