Operácie

Maticový displej 8x8 s driverom MAX7219: Rozdiel medzi revíziami

Z SensorWiki

(Algoritmus a program)
 
(73 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 6: Riadok 6:
 
Zostrojte animáciu pohyblivéj šípky, na spôsob smerovky. Pri stlačení tlačidla do prava, alebo do ľava sa vytvorí animácia ukazujúca smer.  
 
Zostrojte animáciu pohyblivéj šípky, na spôsob smerovky. Pri stlačení tlačidla do prava, alebo do ľava sa vytvorí animácia ukazujúca smer.  
  
[[Obrázok:nano-pinnout.jpg|400px|thumb|center|Vývojová doska ACROB.]]
+
[[Obrázok:nano-pinnout.jpg|400px|thumb|center|Vývojová doska Arduino Nano.]]
  
 
'''Literatúra:'''  
 
'''Literatúra:'''  
 
* [https://docs.arduino.cc/resources/datasheets/A000005-datasheet.pdf Dokumentácia k doske Arduino Nano]
 
* [https://docs.arduino.cc/resources/datasheets/A000005-datasheet.pdf Dokumentácia k doske Arduino Nano]
 
+
* [https://www.analog.com/media/en/technical-documentation/data-sheets/MAX7219-MAX7221.pdf Dokumentácia k MAX7219]
  
  
Riadok 17: Riadok 17:
 
== Analýza  a opis riešenia ==
 
== Analýza  a opis riešenia ==
  
Opíšte sem čo a ako ste spravili, ak treba, doplňte obrázkami...
+
V projekte sme využil maticový diplej so 64 LED diódami usporiadanými do matice 8x8, na displej sme pripojili radič MAX7219, ktorý zjednodušuje komunikáciu s Arduinom.
 +
Celý modul sa pripájal pomocu 5-tich pinov:
 +
::*VCC - napájanie 5V
 +
::*GND - uzemnenie
 +
::*DIN(data in, pin 11) - MOSI(master out slave in) pin použtý na odosielanie dát z mastera (Arduino Nano) do slave zariadenia (displeja s radičom MAX7219)
 +
::*CS(chip select, pin 10)  - slúži na vybratie konkrétneho slave zariadenia, s ktorým má master komunikovať
 +
::*CLK(alebo SCK - serial clock, pin 13) - je signál generovaný masterom, ktorý určuje synchronizačnú frekvenciu pre prenos dát medzi masterom a slave zariadením
 +
 
 +
Displej funguje na princípe '''multiplexingu''', teda sa prepína jeden riadok displeja v ktorom rozsvedsuje len tie diódy, ktoré chceme aby svietili. Potom prejdem na ďalší riadok a urobí to isté. Tento proces sa opakuje pre všetky riadky na displeji. Ak to robí dostatočne rýchlo (viac ako 100 krát za sekundu), naše oči to vnímajú ako stabilné svetlo, aj keď sa v skutočnosti každý riadok zapína a vypína postupne. Týmto spôsobom môžeme teda zobraziť rôzne informácie na displeji.
 +
[[Súbor:multiplexingGif.gif|400px|thumb|center|Princíp multiplexingu.]]
 +
 
 +
# Prvým krokom v projekte bolo pripojenie displeja s radičom ku Arduinu, pomocou SPI(Serial Peripheral Interface) zbernice.
 +
:::'''SPI zbernica''' - je sériová synchrónna komunikačná zbernica, ktorá sa používa na prenos dát medzi mikrokontrolérmi a  rôznymi zariadeniami.
 +
::::''Princíp fungovania SPI komunikácie:''
 +
::::* Synchrónnu komunikáciu zabezpečuje synchronizačný signál, ktorý určuje kedy majú byť odosielané a prijímané dáta.
 +
::::* Využíva master-slave komunikáciu, čo znamená, že v tejto komunikácií existuje zvyčajne jeden master(nadriadený) a viacero slave(podriadený) prvkov. Master teda zodpovedná za riadenie komunikácie a slaves reagujú na jeho príkazy.
 +
::::* Uplatňuje sa full duplex komunikácia, teda umožňuje plný obojsmerný prenos dát, čo znamená, že master môže posielať dáta slave zariadeniu a súčasne prijímať od neho dáta.
  
[[Súbor:ledRGB.jpg|400px|thumb|center|RGB LED.]]
+
# Druhým krokom bolo vytvorenie programovéj časti projektu, v ktoréj bolo potrebné inicializovať komunikáciu, vyvoriť funkciu na odosieľanie dát z Arduina, nastavenie displeja pomocou registrov a vytvorenie funkcií, ktoré zobrazovali animáciu šípok.
  
Nezabudnite doplniť schému zapojenia!
+
[[Obrázok:8x8.jpg|400px|thumb|center|8x8 maticový displej s radičom MAX7219.]]
  
[[Súbor:schd.png|400px|thumb|center|Schéma zapojenia LCD displeja.]]
+
Schéma zapojenia
 +
 
 +
[[Súbor:schemaNagy.png|400px|thumb|center|Schéma zapojenia 8x8 displeja s radičom max7219.]]
  
  
 
=== Algoritmus a program ===
 
=== Algoritmus a program ===
  
Algoritmus programu je....
+
Program pre displej je tvorený z hlavného programu ''main.c'' a dvoch pomocných knižníc ''SPIinit.c'' a ''uart.c''. Obsahuje aj dva hlavičkové súbory pre komunikáciu UART (''urat.h'') a SPI komunikáciu (''SPIinit.h'').
 +
::*V knižnici ''SPIinit.c'' je prevažne definovaná inicializácia displeja pomocou funkcií,  sú tu definované piny, ktorými je modul pripojený k Arduinu a taktiež sa tu nachádzajú animácie, ktoré sa následne volajú v hlavnom programe.
 +
::*Knižnica ''uart.c'' slúži na inicializáciu sériovej komunikácie pomocou UART, teda dokážeme zobrazovať napríklad stav tlačítok v programe Putty.
 +
::*Na začiatku hlavného programu ''main.c'' sú definované potrebné makrá a enumy pre určenie stavu tlačidiel. Nastavujú sa tu piny PD2 a PD3(tlačidlá) ako vstupy, teda sú povolené interné pull-up rezistory. V cykle while sa nachádza časť pre ošetrenie kmitania pri stlačení tlačítok a program pre čítanie stavu tlačítok, podľa ních mení stav enumov. Je tu nastavená podmienka, pre stlačenie pravého, alebo ľavého tlačidla a podľa toho sa spustí príslušná animácia. 
 +
Pri spustení programu sa na displeji zobrazí animácia smajlíka, po ktoréj je možné nastavovať smer šípok, tento smer sa následne zobrazuje v programe Putty.
 +
 
 +
<tabs>
 +
<tab name="main.c"><source lang="c++" style="background: LightYellow;">
 +
#define F_CPU 16000000UL
 +
#define BAUDRATE      9600
 +
#include <avr/io.h>
 +
#include <util/delay.h>
 +
#include "uart.h"
 +
#include "SPIinit.h"
 +
 
 +
#define switchL  PD3
 +
#define switchR  PD2
 +
 
 +
FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
 +
 
 +
enum states { Off, Down, On, Up }; // Stavy tlačítok
 +
volatile enum states buttonL = Off;
 +
volatile enum states buttonR = Off;
  
  
<tabs>
+
int main(void) {
<tab name="AVR C-code"><source lang="c++" style="background: LightYellow;">
+
uart_init();
 +
stdout = &mystdout; // printf() funkcia je zapnutá
 +
    SPI_init(); // Inicializácia SPI
 +
    MAX7219_init(); // Inicializácia MAX7219
 +
 +
    // Nastavenie tlačidiel ako vstupov a povolenie interných pull-up rezistorov
 +
    DDRD &= ~((1 << switchL) | (1 << switchR));
 +
    PORTD |= (1 << switchL) | (1 << switchR);
 +
 +
clearDisp();
 +
smileAnimation();
 +
clearDisp();
 +
printf("Smer sipok sa da menit tlacitkami na nepajivom poli.\n");
 +
   
 +
    while (1) {
 +
if ( (buttonL == Off) &&  bit_is_clear(PIND, switchL)  )
 +
  {
 +
delay(15);               
 +
if ( bit_is_clear(PIND, switchL) )
 +
buttonL = Down;            
 +
  }
 +
  else if ( (buttonL == Down) &&  bit_is_clear(PIND, switchL)  )
 +
  {
 +
  buttonL = On;
 +
  }
 +
  else if  ( (buttonL == On) &&  bit_is_clear(PIND, switchL) )  
 +
  { 
 +
buttonL = Up;
 +
  }
 +
  else if (  (buttonL == Up) &&  bit_is_clear(PIND, switchL) )
 +
  {
 +
delay(15);               
 +
if ( bit_is_clear(PIND, switchL) )
 +
buttonL = Off;
 +
  }
 +
 
 +
 
 +
  if ( (buttonR == Off) &&  bit_is_clear(PIND, switchR)  )
 +
  {
 +
delay(15);               
 +
if ( bit_is_clear(PIND, switchR) )
 +
buttonR = Down;            
 +
  }
 +
  else if ( (buttonR == Down) &&  bit_is_clear(PIND, switchR)  )
 +
  {
 +
  buttonR = On;
 +
  }
 +
  else if  ( (buttonR == On) &&  bit_is_clear(PIND, switchR) )  
 +
  { 
 +
buttonR = Up;
 +
  }
 +
  else if (  (buttonR == Up) &&  bit_is_clear(PIND, switchR) )
 +
  {
 +
delay(15);               
 +
if ( bit_is_clear(PIND, switchR) )
 +
buttonR = Off;
 +
  }
 +
 
 +
        if (buttonL == Down) { 
 +
printf("Smer sipok: <--\r");
 +
vlavo();
 +
buttonL = Up; // Nastav stav tlačidlo L na Up po animácii
 +
}
 +
        if (buttonR == Down) {
 +
printf("Smer sipok: -->\r"); 
 +
vpravo();
 +
buttonR = Up; // Nastav stav tlačidlo R na Up po animácii
 +
}
 +
    }
 +
}
 +
 
 +
</source></tab>
 +
 
 +
<tab name="SPIinit.c"><source lang="c++" style="background: LightYellow;">
 
#include <avr/io.h>
 
#include <avr/io.h>
 +
#include <util/delay.h>
 +
#include "uart.h"
 +
 +
// Definícia pinov
 +
#define DIN_PIN    3    // Pripojenie Arduina k pinu DIN(data in -  odosielanie dát z mastera) na MAX7219  (pin 11)
 +
#define CLK_PIN    5    // Pripojenie Arduina k pinu CLK(alebo SCK - určuje synchronizačnú frekvenciu pre prenos dát) na MAX7219  (pin 13)
 +
#define CS_PIN      2    // Pripojenie Arduina k pinu CS(chip select - slúži na vybratie konkrétneho slave zariadenia) na MAX7219  (pin 10)
 +
#define switchL  PD3
 +
#define switchR  PD2
  
int main(void)
+
void delay(int delay)    
 
{
 
{
   unsigned int measuredValue;
+
   for (int i=1; i<=delay; i++)
 +
  _delay_ms(1);
 +
}
 +
 
 +
// Inicializácia SPI komunikácie
 +
void SPI_init() {
 +
    DDRB |= (1 << DIN_PIN) | (1 << CLK_PIN) | (1 << CS_PIN); // Nastavenie pinov DIN, CLK, CS ako výstupy
 +
    PORTB |= (1 << CS_PIN); // Nastavenie CS pinu na HIGH (deaktivovaný stav)
 +
    SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Zapnutie SPI, Master módu a nastavenie hodinového deliča na Fosc/16
 +
}
 +
 
 +
// Funkcia pre odoslanie dát na MAX7219
 +
void MAX7219_send(unsigned char reg, unsigned char data) {
 +
    PORTB &= ~(1 << CS_PIN); // Aktivácia čipu, nastavenie CS na LOW
 +
    SPDR = reg; // Odoslanie adresy registra
 +
    while (!(SPSR & (1 << SPIF))); // Čakanie na dokončenie odosielania
 +
    SPDR = data; // Odoslanie dát
 +
    while (!(SPSR & (1 << SPIF))); // Čakanie na dokončenie odosielania
 +
    PORTB |= (1 << CS_PIN); // Deaktivácia čipu, nastavenie CS na HIGH
 +
}
 +
 
 +
// Funkcia na inicializáciu MAX7219
 +
void MAX7219_init() {
 +
    MAX7219_send(0x09, 0x00); // Nastavenie Decode Mode na "no decode"
 +
    MAX7219_send(0x0a, 0x01); // Intenzita svetla (0x00 - 0x0f)
 +
    MAX7219_send(0x0b, 0x07); // Nastavenie Scan Limit (0x07 = zobrazenie 8 riadkov)
 +
    MAX7219_send(0x0c, 0x01); // Nastavenie Shutdown režimu na "normal operation"
 +
    MAX7219_send(0x0f, 0x00); // Test mode off
 +
}
  
  while (1)
+
// Funkcia na zobrazenie sipky do prava
  {
+
void vpravo() {
     /*  relax  */ 
+
    unsigned char sipkaVpravo[] = {
  }
+
        0x00, 0x10, 0x18, 0xfc, 0xfe, 0xfc, 0x18, 0x10
 +
     };
  
  return(0);
+
    for (int repeat = 0; repeat < 10; repeat++) { // Vonkajší cyklus pre opakovanie animácie 10-krát
 +
        for (int posun = 0; posun <= 12; posun++) { // "ako daleko sipka prejde"
 +
            for (int i = 1; i <= 8; i++) {  // Prechod všetkých 8 riadkov
 +
                MAX7219_send(i, sipkaVpravo[i - 1]>>posun);
 +
                _delay_ms(9); // Oneskor prí v každom kroku, aby sa zobrazil pohyb
 +
if (bit_is_clear(PIND, switchL)) {
 +
printf("Smer sipok: <--\r");
 +
return 0;
 +
}
 +
            }
 +
        }
 +
    }
 +
}
 +
 
 +
// Funkcia na zobrazenie sipky do ľava
 +
void vlavo() {
 +
    unsigned char sipkaVlavo[] = {
 +
        0x00,0x08,0x18,0x3f,0x7f,0x3f,0x18,0x08
 +
    };
 +
for (int repeat = 0; repeat < 10; repeat++) { // Vonkajší cyklus pre opakovanie animácie 10-krát
 +
for (int posun = 0; posun <= 12; posun++) {
 +
for (int i = 1; i <= 8; i++) {
 +
MAX7219_send(i, sipkaVlavo[i - 1]<<posun);
 +
delay(9);
 +
if (bit_is_clear(PIND, switchR)) {
 +
printf("Smer sipok: -->\r"); 
 +
return 0;
 +
}
 +
}
 +
}
 +
}
 +
}
 +
// Funkcia na vyčistenie displeja
 +
void clearDisp() {
 +
    for (int i = 1; i <= 8; i++) { // Prechod cez všetky riadky displeja
 +
        MAX7219_send(i, 0x00); // Nastavenie všetkých bitov v riadku na 0 (vymazanie)
 +
    }
 +
}
 +
 
 +
// Funkcia na počiatočnú animáciu
 +
void smileAnimation() {
 +
    unsigned char happy[] = {
 +
        0x3c,0x42,0xa5,0x81,0xa5,0x99,0x42,0x3c
 +
    };
 +
unsigned char normal[] = {
 +
        0x3c,0x42,0xa5,0x81,0x81,0xbd,0x42,0x3c
 +
    };
 +
unsigned char sad[] = {
 +
        0x3c,0x42,0xa5,0x81,0x99,0xa5,0x42,0x3c
 +
    };
 +
 +
for (int repeat = 0; repeat < 3; repeat++) { // Vonkajší cyklus pre opakovanie animácie 3-krát
 +
for (int i = 1; i <= 8; i++) {
 +
MAX7219_send(i, happy[i - 1]);
 +
delay(9);
 +
}
 +
delay(700);
 +
for (int i = 1; i <= 8; i++) {
 +
MAX7219_send(i, normal[i - 1]);
 +
delay(9);
 +
}
 +
delay(700);
 +
for (int i = 1; i <= 8; i++) {
 +
MAX7219_send(i, sad[i - 1]);
 +
delay(9);
 +
}
 +
delay(700);
 +
}
 
}
 
}
  
 
</source></tab>
 
</source></tab>
<tab name="filename.h"><source lang="c++" style="background: LightYellow;">
+
<tab name="SPIinit.h"><source lang="c++" style="background: LightYellow;">
 +
#ifndef SPIinit_H_
 +
#define SPIinit_H_
 +
 
 +
#include <stdio.h>
 +
 
 +
#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)  // vzorček z datasheetu
 +
void delay(int delay);
 +
void SPI_init();
 +
void MAX7219_send(unsigned char reg, unsigned char data);
 +
void MAX7219_init();
 +
void clearDisp();
 +
void vpravo();
 +
void vlavo();
 +
void smileAnimation();
 +
#endif /* SPIinit_H_ */
 +
</source></tab>
 +
<tab name="uart.c"><source lang="c++" style="background: LightYellow;">
 
#include <avr/io.h>
 
#include <avr/io.h>
 +
#include <util/delay.h>
 +
#include "uart.h"
 +
 +
void uart_init( void )
 +
{
 +
//  for different BAUD rate change the project settings, or uncomment
 +
//  following two lines:
 +
// #undef  BAUD          // avoid compiler warning
 +
//  #define BAUD 115200
 +
 +
  #include <util/setbaud.h>  // requires defined BAUD
 +
 
 +
  UBRR0H = UBRRH_VALUE;
 +
  UBRR0L = UBRRL_VALUE;
 +
  #if USE_2X                // defined in setbaud.h
 +
    UCSR0A |= (1 << U2X0);
 +
  #else
 +
    UCSR0A &= ~(1 << U2X0);
 +
  #endif
 +
 +
 +
    UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
 +
    UCSR0B = _BV(RXEN0) | _BV(TXEN0);  /* Enable RX and TX */
 +
}
 +
  
void adc_init(void);                                   // A/D converter initialization
+
int uart_putc( char c, FILE *stream )
 +
{
 +
  if (c == '\n')
 +
      uart_putc('\r',stream);
 +
 
 +
  loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
 +
  UDR0 = c;
 +
  return 0;
 +
}
 +
 
 +
 
 +
void uart_puts(const char *s)
 +
{
 +
  /* toto je vasa uloha */
 +
}
 +
 
 +
char uart_getc(void)
 +
{
 +
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
 +
    return UDR0;
 +
}
  
unsigned int adc_read(char a_pin);
 
 
</source></tab>
 
</source></tab>
</tabs>
+
<tab name="uart.h"><source 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 * 16UL))) - 1)  // vzorček z datasheetu
 +
 
 +
void hw_init( void );
 +
void uart_init( void );
 +
   
 +
int uart_putc( char c, FILE *stream );
 +
void uart_puts( const char *s );
 +
 
 +
char uart_getc( void );
  
Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x ''zdrojaky.zip'':
+
void delay(int delay);
  
Zdrojový kód: [[Médiá:projektMenoPriezvisko.zip|zdrojaky.zip]]
+
#endif /* UART_H_ */
 +
</source></tab>
 +
</tabs>
  
 +
Zdrojový kód: [[Médiá:projektNagyL.zip|projektNagyL.zip]]
  
 
=== Overenie ===
 
=== Overenie ===
  
Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia.  
+
Funkčnosť projektu sme overili, ako môžeme vidieť videu. Na začiatku sa zobrazí animácia smajlíka a následne sa dá šípkami prepínať smer animácie.  
Na konci uvádzame fotku záverečnej obrazovky pred resetom. Vypísaný je tu priemerný čas a najlepší čas.  
 
  
[[Súbor:fotka.jpg|400px|thumb|center|Aplikácia.]]
+
<gallery mode="slideshow">
 +
Image:smajlik.jpg|''Overenie funkčnosti a aplikácia 8x8 displeja''
 +
Image:sipkaL.jpg|''Overenie funkčnosti a aplikácia 8x8 displeja''
 +
Image:sipkaR.jpg|''Overenie funkčnosti a aplikácia 8x8 displeja''
 +
</gallery>
  
 
'''Video:'''
 
'''Video:'''
<center><youtube>_l02MBu41n0</youtube></center>
+
<center><youtube>_EbV-PpgXp0</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 09:31, 3. máj 2024

Záverečný projekt predmetu MIPS / LS2024 - Ladislav Nagy


Zadanie

Zostrojte animáciu pohyblivéj šípky, na spôsob smerovky. Pri stlačení tlačidla do prava, alebo do ľava sa vytvorí animácia ukazujúca smer.

Vývojová doska Arduino Nano.

Literatúra:


Analýza a opis riešenia

V projekte sme využil maticový diplej so 64 LED diódami usporiadanými do matice 8x8, na displej sme pripojili radič MAX7219, ktorý zjednodušuje komunikáciu s Arduinom. Celý modul sa pripájal pomocu 5-tich pinov:

  • VCC - napájanie 5V
  • GND - uzemnenie
  • DIN(data in, pin 11) - MOSI(master out slave in) pin použtý na odosielanie dát z mastera (Arduino Nano) do slave zariadenia (displeja s radičom MAX7219)
  • CS(chip select, pin 10) - slúži na vybratie konkrétneho slave zariadenia, s ktorým má master komunikovať
  • CLK(alebo SCK - serial clock, pin 13) - je signál generovaný masterom, ktorý určuje synchronizačnú frekvenciu pre prenos dát medzi masterom a slave zariadením

Displej funguje na princípe multiplexingu, teda sa prepína jeden riadok displeja v ktorom rozsvedsuje len tie diódy, ktoré chceme aby svietili. Potom prejdem na ďalší riadok a urobí to isté. Tento proces sa opakuje pre všetky riadky na displeji. Ak to robí dostatočne rýchlo (viac ako 100 krát za sekundu), naše oči to vnímajú ako stabilné svetlo, aj keď sa v skutočnosti každý riadok zapína a vypína postupne. Týmto spôsobom môžeme teda zobraziť rôzne informácie na displeji.

Princíp multiplexingu.
  1. Prvým krokom v projekte bolo pripojenie displeja s radičom ku Arduinu, pomocou SPI(Serial Peripheral Interface) zbernice.
SPI zbernica - je sériová synchrónna komunikačná zbernica, ktorá sa používa na prenos dát medzi mikrokontrolérmi a rôznymi zariadeniami.
Princíp fungovania SPI komunikácie:
  • Synchrónnu komunikáciu zabezpečuje synchronizačný signál, ktorý určuje kedy majú byť odosielané a prijímané dáta.
  • Využíva master-slave komunikáciu, čo znamená, že v tejto komunikácií existuje zvyčajne jeden master(nadriadený) a viacero slave(podriadený) prvkov. Master teda zodpovedná za riadenie komunikácie a slaves reagujú na jeho príkazy.
  • Uplatňuje sa full duplex komunikácia, teda umožňuje plný obojsmerný prenos dát, čo znamená, že master môže posielať dáta slave zariadeniu a súčasne prijímať od neho dáta.
  1. Druhým krokom bolo vytvorenie programovéj časti projektu, v ktoréj bolo potrebné inicializovať komunikáciu, vyvoriť funkciu na odosieľanie dát z Arduina, nastavenie displeja pomocou registrov a vytvorenie funkcií, ktoré zobrazovali animáciu šípok.
8x8 maticový displej s radičom MAX7219.

Schéma zapojenia

Schéma zapojenia 8x8 displeja s radičom max7219.


Algoritmus a program

Program pre displej je tvorený z hlavného programu main.c a dvoch pomocných knižníc SPIinit.c a uart.c. Obsahuje aj dva hlavičkové súbory pre komunikáciu UART (urat.h) a SPI komunikáciu (SPIinit.h).

  • V knižnici SPIinit.c je prevažne definovaná inicializácia displeja pomocou funkcií, sú tu definované piny, ktorými je modul pripojený k Arduinu a taktiež sa tu nachádzajú animácie, ktoré sa následne volajú v hlavnom programe.
  • Knižnica uart.c slúži na inicializáciu sériovej komunikácie pomocou UART, teda dokážeme zobrazovať napríklad stav tlačítok v programe Putty.
  • Na začiatku hlavného programu main.c sú definované potrebné makrá a enumy pre určenie stavu tlačidiel. Nastavujú sa tu piny PD2 a PD3(tlačidlá) ako vstupy, teda sú povolené interné pull-up rezistory. V cykle while sa nachádza časť pre ošetrenie kmitania pri stlačení tlačítok a program pre čítanie stavu tlačítok, podľa ních mení stav enumov. Je tu nastavená podmienka, pre stlačenie pravého, alebo ľavého tlačidla a podľa toho sa spustí príslušná animácia.

Pri spustení programu sa na displeji zobrazí animácia smajlíka, po ktoréj je možné nastavovať smer šípok, tento smer sa následne zobrazuje v programe Putty.

#define F_CPU 16000000UL
#define BAUDRATE       9600
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"
#include "SPIinit.h"

#define switchL   PD3
#define switchR   PD2

FILE mystdout = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);

enum states { Off, Down, On, Up }; // Stavy tlačítok
volatile enum states buttonL = Off;
volatile enum states buttonR = Off;


int main(void) {
	uart_init();
	stdout = &mystdout; // printf() funkcia je zapnutá
    SPI_init(); // Inicializácia SPI
    MAX7219_init(); // Inicializácia MAX7219
	
    // Nastavenie tlačidiel ako vstupov a povolenie interných pull-up rezistorov
    DDRD &= ~((1 << switchL) | (1 << switchR));
    PORTD |= (1 << switchL) | (1 << switchR);
	
	clearDisp();
	smileAnimation();
	clearDisp();
	printf("Smer sipok sa da menit tlacitkami na nepajivom poli.\n");
    
    while (1) {
		if ( (buttonL == Off) &&  bit_is_clear(PIND, switchL)  )
	  {
		 delay(15);                 
		 if ( bit_is_clear(PIND, switchL) ) 
		 buttonL = Down;	            
	  }
	  else if ( (buttonL == Down) &&  bit_is_clear(PIND, switchL)  )
	  { 
  		 buttonL = On;
	  }
	  else if  ( (buttonL == On) &&  bit_is_clear(PIND, switchL) ) 	  
	  {  
		 buttonL = Up;
	  }
	  else if (  (buttonL == Up) &&  bit_is_clear(PIND, switchL) )
	  {
		 delay(15);                 
		 if ( bit_is_clear(PIND, switchL) ) 
		 buttonL = Off;
	  }
	  
	  
	  if ( (buttonR == Off) &&  bit_is_clear(PIND, switchR)  )
	  {
		 delay(15);                 
		 if ( bit_is_clear(PIND, switchR) ) 
		 buttonR = Down;	            
	  }
	  else if ( (buttonR == Down) &&  bit_is_clear(PIND, switchR)  )
	  { 
  		 buttonR = On;
	  }
	  else if  ( (buttonR == On) &&  bit_is_clear(PIND, switchR) ) 	  
	  {  
		 buttonR = Up;
	  }
	  else if (  (buttonR == Up) &&  bit_is_clear(PIND, switchR) )
	  {
		 delay(15);                 
		 if ( bit_is_clear(PIND, switchR) ) 
		 buttonR = Off;
	  }
	  
        if (buttonL == Down) {  
			printf("Smer sipok: <--\r");
			vlavo(); 
			buttonL = Up; // Nastav stav tlačidlo L na Up po animácii
		}
        if (buttonR == Down) {
			printf("Smer sipok: -->\r");  
			vpravo(); 
			buttonR = Up; // Nastav stav tlačidlo R na Up po animácii
		}
    }
}
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"

// Definícia pinov
#define DIN_PIN     3    // Pripojenie Arduina k pinu DIN(data in -  odosielanie dát z mastera) na MAX7219  (pin 11)
#define CLK_PIN     5    // Pripojenie Arduina k pinu CLK(alebo SCK - určuje synchronizačnú frekvenciu pre prenos dát) na MAX7219  (pin 13)
#define CS_PIN      2    // Pripojenie Arduina k pinu CS(chip select - slúži na vybratie konkrétneho slave zariadenia) na MAX7219   (pin 10)
#define switchL   PD3
#define switchR   PD2

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

// Inicializácia SPI komunikácie
void SPI_init() {
    DDRB |= (1 << DIN_PIN) | (1 << CLK_PIN) | (1 << CS_PIN); // Nastavenie pinov DIN, CLK, CS ako výstupy
    PORTB |= (1 << CS_PIN); // Nastavenie CS pinu na HIGH (deaktivovaný stav)
    SPCR |= (1 << SPE) | (1 << MSTR) | (1 << SPR0); // Zapnutie SPI, Master módu a nastavenie hodinového deliča na Fosc/16
}

// Funkcia pre odoslanie dát na MAX7219
void MAX7219_send(unsigned char reg, unsigned char data) {
    PORTB &= ~(1 << CS_PIN); // Aktivácia čipu, nastavenie CS na LOW
    SPDR = reg; // Odoslanie adresy registra
    while (!(SPSR & (1 << SPIF))); // Čakanie na dokončenie odosielania
    SPDR = data; // Odoslanie dát
    while (!(SPSR & (1 << SPIF))); // Čakanie na dokončenie odosielania
    PORTB |= (1 << CS_PIN); // Deaktivácia čipu, nastavenie CS na HIGH
}

// Funkcia na inicializáciu MAX7219
void MAX7219_init() {
    MAX7219_send(0x09, 0x00); // Nastavenie Decode Mode na "no decode"
    MAX7219_send(0x0a, 0x01); // Intenzita svetla (0x00 - 0x0f)
    MAX7219_send(0x0b, 0x07); // Nastavenie Scan Limit (0x07 = zobrazenie 8 riadkov)
    MAX7219_send(0x0c, 0x01); // Nastavenie Shutdown režimu na "normal operation"
    MAX7219_send(0x0f, 0x00); // Test mode off
}

// Funkcia na zobrazenie sipky do prava
void vpravo() {
    unsigned char sipkaVpravo[] = {
        0x00, 0x10, 0x18, 0xfc, 0xfe, 0xfc, 0x18, 0x10
    };

    for (int repeat = 0; repeat < 10; repeat++) { // Vonkajší cyklus pre opakovanie animácie 10-krát
        for (int posun = 0; posun <= 12; posun++) { // "ako daleko sipka prejde"
            for (int i = 1; i <= 8; i++) {  // Prechod všetkých 8 riadkov
                MAX7219_send(i, sipkaVpravo[i - 1]>>posun);
                _delay_ms(9); // Oneskor prí v každom kroku, aby sa zobrazil pohyb
				if (bit_is_clear(PIND, switchL)) {
					printf("Smer sipok: <--\r");
					return 0;
				}
            }
        }
    }
}

// Funkcia na zobrazenie sipky do ľava
void vlavo() {
    unsigned char sipkaVlavo[] = {
        0x00,0x08,0x18,0x3f,0x7f,0x3f,0x18,0x08
    };
	for (int repeat = 0; repeat < 10; repeat++) { // Vonkajší cyklus pre opakovanie animácie 10-krát
		for (int posun = 0; posun <= 12; posun++) {
			for (int i = 1; i <= 8; i++) {
				MAX7219_send(i, sipkaVlavo[i - 1]<<posun);
				delay(9);
				if (bit_is_clear(PIND, switchR)) {
					printf("Smer sipok: -->\r");  
					return 0;
				}					
			}
		}
	}	
}
// Funkcia na vyčistenie displeja
void clearDisp() {
    for (int i = 1; i <= 8; i++) { // Prechod cez všetky riadky displeja
        MAX7219_send(i, 0x00); // Nastavenie všetkých bitov v riadku na 0 (vymazanie)
    }
}

// Funkcia na počiatočnú animáciu
void smileAnimation() {
    unsigned char happy[] = {
        0x3c,0x42,0xa5,0x81,0xa5,0x99,0x42,0x3c
    };
	unsigned char normal[] = {
        0x3c,0x42,0xa5,0x81,0x81,0xbd,0x42,0x3c
    };
	unsigned char sad[] = {
        0x3c,0x42,0xa5,0x81,0x99,0xa5,0x42,0x3c
    };
	
	for (int repeat = 0; repeat < 3; repeat++) { // Vonkajší cyklus pre opakovanie animácie 3-krát
			for (int i = 1; i <= 8; i++) {
				MAX7219_send(i, happy[i - 1]);
				delay(9);
			}
			delay(700);
			for (int i = 1; i <= 8; i++) {
				MAX7219_send(i, normal[i - 1]);
				delay(9);
			}
			delay(700);
			for (int i = 1; i <= 8; i++) {
				MAX7219_send(i, sad[i - 1]);
				delay(9);
			}
			delay(700);
	}
}
#ifndef SPIinit_H_
#define SPIinit_H_

#include <stdio.h>

#define BAUD_PRESCALE  (((F_CPU / (BAUDRATE * 16UL))) - 1)  // vzorček z datasheetu
void delay(int delay); 
void SPI_init();
void MAX7219_send(unsigned char reg, unsigned char data);
void MAX7219_init();
void clearDisp();
void vpravo();
void vlavo();
void smileAnimation();
#endif /* SPIinit_H_ */
#include <avr/io.h>
#include <util/delay.h>
#include "uart.h"

void uart_init( void ) 
{
//  for different BAUD rate change the project settings, or uncomment 
//  following two lines:	
//	#undef  BAUD           // avoid compiler warning
//  #define BAUD 115200
	
   #include <util/setbaud.h>  // requires defined BAUD
   
   UBRR0H = UBRRH_VALUE;
   UBRR0L = UBRRL_VALUE;
   #if USE_2X                 // defined in setbaud.h 
    UCSR0A |= (1 << U2X0);
   #else
    UCSR0A &= ~(1 << U2X0);
   #endif


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


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


void uart_puts(const char *s)
{
  /* toto je vasa uloha */
}

char uart_getc(void) 
{
    loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
    return UDR0;
}
#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 * 16UL))) - 1)  // vzorček z datasheetu

void hw_init( void );
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_ */

Zdrojový kód: projektNagyL.zip

Overenie

Funkčnosť projektu sme overili, ako môžeme vidieť videu. Na začiatku sa zobrazí animácia smajlíka a následne sa dá šípkami prepínať smer animácie.

Video: