Advertisement
milanmetal

[AVR/C] Zadatak / Brojac -999 do 999 (TIMER0 Interrupt)

Jan 14th, 2018
218
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 8.29 KB | None | 0 0
  1. /*
  2.  *
  3.  * Brojac koji broji od -999 do 999, postoji mod brzog bojanja koji ubrzano broji
  4.  * i ispisuje na displej u zavisnosti od podesene brzine (promenjiva u vrhu)
  5.  *
  6.  * Bez ikakvih delaya, koriscen interrupt koji se aktivira svakih 1ms
  7.  *
  8.  * Tasteri bi trebalo da su realizovani pomocu PIN CHANGE interrupta ali ne radi bas
  9.  * najbolje u ovoj situaciji, pa sam izostavio. Ko voli nek izvoli.
  10.  *
  11.  * Video prezentacija: https://photos.app.goo.gl/136HhUbY4pe7gweT2
  12.  * Mozda totalno grijesim po pitanju objasnjenja zasto ne radi sa PIN CHANGE interapta...
  13.  *
  14.  * 15.01.2018, 03:59
  15.  *
  16.  * */
  17.  
  18.  
  19. #include <avr/io.h>
  20. #include <avr/interrupt.h>
  21. #include <stdlib.h>             // funkcija abs();
  22.                                 // -123 npr daje problem kada ga koristim sa % i ostalom logikom
  23.                                 // koja priprema cifre za ispis na dipslej, pa sam ukljucio ovo radi
  24.                                 // te funkcije abs()
  25.  
  26. ///////////////////////////////////////////////////////////////////////////////////////
  27.  
  28. // moze i ovako da se implementira ova zajebavancija sa tasterima.
  29. #define KEY_UP          3                               // redni broj PIN-a na portu za tastere
  30. #define KEY_RIGHT       2
  31. #define KEY_DN          1
  32.  
  33. // PINC je ulazni port koji ocitava tastere
  34. #define KEY_PINS        PINC
  35.  
  36. // Macroi koji definisu tastere
  37. #define KEY_DN_PRESS    (~(KEY_PINS) & (1 << KEY_DN))       // ~(PINC) & 1 << 1
  38. #define KEY_RIGHT_PRESS (~(KEY_PINS) & (1 << KEY_RIGHT))    // ~(PINC) & 1 << 2
  39. #define KEY_UP_PRESS    (~(KEY_PINS) & (1 << KEY_UP))       // ~(PINC) & 1 << 3
  40.  
  41. // Nabrajanje ocekivanih stanja tastera.
  42. enum BUTTONS {NONE = 0, DOWN = 1, RIGHT = 2, UP = 3};
  43. enum ZNAKBROJACA {POZITIVAN = 1, NEGATIVAN = 2};
  44.  
  45. enum ZNAKBROJACA znak;
  46. ///////////////////////////////////////////////////////////////////////////////////////
  47.  
  48. const unsigned char simboli[] = {
  49.         0x0c, 0xa4, 0x27, 0xc4
  50. }; //look-up tabela sa simbolima
  51.  
  52. unsigned char DISP_BAFER[4] = {
  53.         //0xfe, 0xfe, 0xfe, 0xfe
  54.         0xff, 0xff, 0xff, 0xff      // brisem displej na pocetku.
  55. }; //bafer displeja
  56. unsigned long millis = 0;
  57. unsigned char disp = 3;
  58.  
  59.  
  60. ///////////////////////////////////////////////////////////////////////////////////////
  61. unsigned char jedinice = 1;
  62. unsigned char desetice = 1;
  63. unsigned char stotice = 0;
  64.  
  65. unsigned char taster;
  66. unsigned char enable = 0;   // sluzi za implementaciju debouncera.
  67. unsigned char fastCounting = 0;
  68. unsigned char intBrzogBrojanja = 70;    // 70ms je interval brzog brojanja.
  69.  
  70. unsigned char minus = 0xfe;
  71.  
  72.  
  73.                             //  0     1     2     3     4     5     6     7     8     9
  74. const unsigned char cifre[] = { 0x05, 0xdd, 0x46, 0x54, 0x9c, 0x34, 0x24, 0x5d, 0x04, 0x14 };
  75.  
  76. long brojac = 7;             // treba mi integer jer ocekujem broj do 999
  77.  
  78.  
  79. // vraca vrednosti iz enumeracije u zavisnosti od pritisnutog tastera.
  80. unsigned char ocitajTaster(){
  81.  
  82.     enum BUTTONS btn;
  83.     if(KEY_DN_PRESS){       // pogledati makroe na vrhu...
  84.         btn = DOWN;
  85.     } else if(KEY_UP_PRESS){
  86.         btn = UP;
  87.     } else if(KEY_RIGHT_PRESS){
  88.         btn = RIGHT;
  89.     } else {
  90.         btn = NONE;
  91.     }
  92.     return btn;
  93. }
  94.  
  95. // Ovo provjeravanje znaka je zbog problema koji se javio pri radu sa negativnim brojevima
  96. // kada od cifarskih vrednosti pravim broj, gubio se znak brojaca pa nikada nije mogao
  97. // uci u negativni segment brojanja. Na ovaj nacin provjerim da li se nalazim
  98. // u negativnom dijelu brojanja i "vjestacki" napravim negativan broj mnozenjem sa -1
  99. void azurirajBrojac() {
  100.     if(znak == POZITIVAN) {
  101.         brojac = jedinice + (desetice * 10) + (stotice * 100);
  102.     } else if (znak == NEGATIVAN) {
  103.         brojac = (jedinice + (desetice * 10) + (stotice * 100)) * (-1);
  104.     } else {
  105.         brojac = jedinice + (desetice * 10) + (stotice * 100);
  106.     }
  107.  
  108. }
  109.  
  110. // univerzalna funkcija za upisa karaktera u bafer za slanje na displej.
  111. void dispBuffer(unsigned char disp0, unsigned char disp1, unsigned char disp2, unsigned char disp3){
  112.     DISP_BAFER[0] = disp0;
  113.     DISP_BAFER[1] = disp1;
  114.     DISP_BAFER[2] = disp2;
  115.     DISP_BAFER[3] = disp3;
  116. }
  117.  
  118. // Ispotavlja se da je ova funkcija prepunjena
  119. void budziNaDisplej(){
  120.  
  121.     // npr brojac = 123;
  122.     stotice = abs(brojac) / 100;            // (1234 % 1000) / 100 = 234 / 100 = 2
  123.     desetice = (abs(brojac) % 100) / 10;    // ((1234 % 1000) % 100) / 10 = (234 % 100) / 10 = 34 / 10 = 3
  124.     jedinice = (abs(brojac) % 100) % 10;    // 1234 % 1000 = 234 % 100 = 34 % 10 = 4
  125.  
  126.     dispBuffer(0xff, 0xff, 0xff, cifre[jedinice]);
  127.  
  128.     // Podesavam kada da ispisujem znak minus ispred prve znacajne cifre.
  129.     if(brojac < 0 && brojac >= -9)  dispBuffer(0xff, 0xff, minus, cifre[jedinice]);
  130.     if(brojac < 0 && brojac >= -99 && brojac < -9) {
  131.         dispBuffer(0xff, minus, cifre[desetice], cifre[jedinice]);
  132.     }
  133.  
  134.     if(brojac < 0 && brojac < -99) {
  135.         dispBuffer(minus, cifre[stotice], cifre[desetice], cifre[jedinice]);
  136.     }
  137.  
  138.     // Pozitivni dio brojaca
  139.     if(brojac > 9) {
  140.         dispBuffer(0xff, 0xff , cifre[desetice], cifre[jedinice]);
  141.     }
  142.  
  143.     if (brojac > 99) {
  144.         dispBuffer(0xff, cifre[stotice], cifre[desetice], cifre[jedinice]);
  145.     }
  146. }
  147.  
  148.  
  149. void uvecajBrojac(unsigned char koliko){
  150.  
  151.     if(brojac + koliko <= 999) brojac += koliko;
  152.     if(brojac > 0) znak = POZITIVAN;
  153. }
  154.  
  155. void umanjiBrojac(unsigned char koliko){
  156.     if(brojac - koliko > -999) brojac -= koliko; //
  157.     if(brojac < 0) znak = NEGATIVAN;
  158. }
  159.  
  160. void radSaTasterima(){
  161.     taster = ocitajTaster();
  162.  
  163.     if(!taster) enable = 1;
  164.     if(enable == 1) {
  165.         // odradjeno kao na vezbama iz cistog Arduina.
  166.         // + koriscenje enumeracije.
  167.         switch(taster){
  168.             case UP:
  169.                 uvecajBrojac(1);
  170.                 enable = 0;                             // zabrani ponovni ulazak u ovaj scope
  171.                                                         // i samim tim sprijeci unedogled uvecavanje brojaca
  172.                                                         // dok se drzi taster
  173.             break;
  174.  
  175.             case DOWN:
  176.                 enable = 0;                             // zabrani ponovni ulazak u ovaj scope...
  177.                 umanjiBrojac(1);
  178.             break;
  179.  
  180.             case RIGHT:                                 // omoguci ubrzano brojanje
  181.                 switch(fastCounting){
  182.                     case 0: fastCounting = 1; break;
  183.                     case 1: fastCounting = 0; break;
  184.                 }
  185.                 enable = 0;
  186.             break;
  187.         }
  188.  
  189.     // millis % intBrzogBrojanja == 0 odobrava ulazak u ove else dijelove svakih npr. 100ms, tako da brojac ne
  190.     // trci previse brzo...
  191.     // dakle else if dijelovi se izvrsavaju svakih intBrzogBrojanja ms samo ako je enable iskljucen
  192.     // (drzis taster pritisnut) aktivan je fastCounting ili pritisnut neki od DOWN ili UP tastera.
  193.     } else if (enable == 0 && fastCounting == 1 && KEY_UP_PRESS && millis % intBrzogBrojanja == 0){
  194.         uvecajBrojac(1);
  195.     } else if (enable == 0 && fastCounting == 1 && KEY_DN_PRESS && millis % intBrzogBrojanja == 0){
  196.         umanjiBrojac(1);
  197.     }
  198. }
  199. ////////////////////////////////////////////////////////////////////////////////////////
  200.  
  201. // Ovo je los pristup, funkcija radSaTasterima poziva gomilu drugih funkcija
  202. // i u nekoj izvedbi bi moglo biti dosta sporo rjesavanje problema na ovaj nacin.
  203. // Interrupt Service Routine treba da se izvrsava sto je brze moguce kako bi procesor
  204. // sto kvalitetnije radio svoj posao. Ovde slusi svrsi vise nego dobro, ali treba imati na umu.
  205. ISR(TIMER0_COMPA_vect)
  206. {
  207.     //prekid tajmera 0 usled dostizanja vrednosti registra OCR0A
  208.     if (++disp > 3)
  209.     disp = 0;
  210.  
  211.     PORTB = ~(1 << (3-disp)); //ukljucenje tranzistora
  212.     PORTD = DISP_BAFER[disp]; //ispis na trenutno aktivan displej
  213.  
  214.     // Zakljucak, displeji su blinkali kada su ove tri linije ispod bile u WHILE(1)
  215.     // Vjerovatno mu treba neko vrijeme da on to izvrsi kako treba, ovo se izvrsava svakih 1ms
  216.     // Tako da mu je to dovoljno vremena da odradi posao kako treba.
  217.     azurirajBrojac();
  218.     radSaTasterima();
  219.     budziNaDisplej();
  220.  
  221.     millis++; //sistemsko vreme
  222. }
  223.  
  224. int main()
  225. {
  226.     //unsigned long t0;
  227.     //unsigned char i;
  228.  
  229.     //inicijalizacija portova:
  230.     DDRB = 0x0f; //PB3-PB0 -> izlazi
  231.     DDRC = 0x00; //port C -> ulaz
  232.     DDRD = 0xff; //port D -> izlaz
  233.  
  234.     //PCICR = (1 << PCIE1); //dozvola prekida usled promene stanja
  235.     //PCMSK1 = 0x05; //pina PCINT10, ili pina PCINT8
  236.  
  237.     //inicijalizacija tajmera 0:
  238.     TCCR0A = 0x02; //tajmer 0: CTC mod
  239.     TCCR0B = 0x03; //tajmer 0: fclk = fosc/64
  240.     OCR0A = 249; //perioda tajmera 0: 250 Tclk (OCR0A + 1 = 250)
  241.     TIMSK0 = 0x02; //dozvola prekida tajmera 0
  242.  
  243.     //usled dostizanja vrednosti registra OCR0A
  244.     sei(); //I = 1 (dozvola prekida)
  245.  
  246.     while(1);       // sprecava da odlaskom u return 0; izadje iz programa.
  247.  
  248.     return 0;
  249. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement