Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- *
- * Ne moze da radi najbolje, u sustini njeno stanje mijenjam, ali posto ostale periferije
- * komuniciraju preko njenog pina, cak i kada je ugasen, dodje sledeca periferija
- * i aktivira ju nezeljeno, tako da ona nema kada da se vizuelno iskljuci, iako joj je napon
- * nuliran. Nezeljeni PWM
- *
- * Autor: Milan Nedic
- * 27.12.2017
- *
- * Ovde mozete pogledati demo ovog koda:
- * https://www.youtube.com/watch?v=RTINMCzFO0U&feature=youtu.be
- * https://www.youtube.com/watch?v=RTINMCzFO0U&feature=youtu.be
- * https://www.youtube.com/watch?v=RTINMCzFO0U&feature=youtu.be
- * https://www.youtube.com/watch?v=RTINMCzFO0U&feature=youtu.be
- *
- * Video je UNLISTED, vide ga samo ljudi koji dobiju link.
- *
- * */
- #include <avr/io.h>
- #include <util/delay.h>
- ///////////////////////////////////////////////////////////////////////////////////////
- #define KEY_L 0
- #define KEY_D 1 // ovo su tezine koju ovaj tasteri zauzimaju na portu.
- #define KEY_R 2
- #define KEY_U 3
- #define KEY_PINS PINC // port na koji su nakaceni
- // Ovo su makroi sa uslovima definisam preko bit-maski.
- // Onaj nacin sa vezbi mi nesto nije sljakao kako treba pa sam iskopao
- // i dopunio na ovaj nacin.
- #define KEY_L_PRESS (~(KEY_PINS) & (1 << KEY_L))
- #define KEY_D_PRESS (~(KEY_PINS) & (1 << KEY_D))
- #define KEY_R_PRESS (~(KEY_PINS) & (1 << KEY_R))
- #define KEY_U_PRESS (~(KEY_PINS) & (1 << KEY_U))
- // Povecava citljivost koda. Vrednosti su random, moze sta god hoces
- // sem ovog NONE, to treba biti nula.
- enum BUTTONS {NONE = 0, LEFT = 10, DOWN = 11, RIGHT = 12, UP = 13};
- // Sluzi za implementaciju debouncera.
- unsigned char enable = 0;
- // Vrednost koju vrati funkcija koja ocitava pritisnuti taster.
- unsigned char taster = 0;
- ///////////////////////////////////////////////////////////////////////////////////////
- //makroi za kontrolu pinova preko kojih je kontroler povezan sa 74HC165:
- #define SCL_HI (PORTC |= (1<<5))
- #define SCL_LO (PORTC &= ~(1<<5))
- #define SDA (PINC & (1 << 4))
- #define SHLD_HI (PORTB |= (1<<5))
- #define SHLD_LO (PORTB &= ~(1<<5))
- ///////////////////////////////////////////////////////////////////////////////////////
- // 0 1 2 3 4 5 6 7 8 9
- const unsigned char cifre[] = { 0x05, 0xdd, 0x46, 0x54, 0x9c, 0x34, 0x24, 0x5d, 0x04, 0x14 };
- const unsigned char iskljucen = 0xff;
- // _3.14 kao pocetna vrednost :)
- unsigned char trenutniIspis[] = {0x00, 0x50, 0xdd, 0x9c};
- // da ne bih prosledjivao nekakve nizove karaktera i fakticki pravio stringove,
- // zatim pljuvao krv da uporedim ono sto imam sa onim sta sam proslijedio,
- // ovo ce funkcionalno odglumiti taj proslijedjeni string tj dace kodu smisao na prvi pogled
- // a sustinski je to zapravo najobicniji unsigned char iliti osmobitni int.
- // Kompajler ce sve ove kljucne rijeci da zamjeni sa njihovim vrijednostima i prakticno
- // ce vrijednosti koje se kriju iza rijeci biti i proslijedjene i ocitane (kod funkcija)
- enum LABELE {init = 1, update = 2, LED = 11, displej7SEG = 12, TASTERI = 13, PREKIDACI = 14, BROJAC = 15};
- // Ovo ispod su look-up tabele koje sadrze pocetna stanja registara kao i
- // nacine inicijalizacije portova pojedinih periferija...
- // PORTB PORTC PORTD DDRB DDRC DDRD
- unsigned char STATE_7SEG[] = {0x00, 0x00, 0x00, 0x0f, 0x00, 0xff};
- unsigned char STATE_LED[] = {~(1 << 4), 0x00, 0x00, 0x00, 0x00, 0xff}; // ovaj prvi pokazuje da i ovo moze i zbunjuje citaoce.
- unsigned char STATE_SWITCHES[] = {0x00, 0x00, 0xfe, 0x20, 0x20, 0xff}; // DDRB ako je 0x30 onda ce biti PB5 --> Q0 aktivan
- unsigned char STATE_BUTTONS[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- unsigned char STATE_INTERRUPT[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
- ///////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////
- // 16MHz Clock
- #define F_CPU 16000000UL
- // Calculate the value needed for
- // the CTC match value in OCR1A.
- #define CTC_MATCH_OVERFLOW ((F_CPU / 1000) / 8)
- #include <avr/interrupt.h>
- #include <util/atomic.h>
- volatile unsigned long timer1_millis;
- long milliseconds_since;
- ISR (TIMER1_COMPA_vect)
- {
- timer1_millis++;
- /////////////////// ja dodao
- if(timer1_millis > 1000) {
- timer1_millis = 0;
- }
- ///////////////////
- }
- unsigned long millis ()
- {
- unsigned long millis_return;
- // Ensure this cannot be disrupted
- ATOMIC_BLOCK(ATOMIC_FORCEON) {
- millis_return = timer1_millis;
- }
- return millis_return;
- }
- void flash_led ()
- {
- unsigned long milliseconds_current = millis();
- //if (milliseconds_current - milliseconds_since > 1000 ) {
- if (milliseconds_current > 500 && milliseconds_current < 900 ){
- // LED connected to PC0/Analog 0
- PORTD ^= (1 << PD4);
- milliseconds_since = milliseconds_current;
- } else {
- PORTD = 0xef;
- }
- }
- void initCounterStuff() {
- // CTC mode, Clock/8
- TCCR1B |= (1 << WGM12) | (1 << CS11);
- // Load the high byte, then the low byte
- // into the output compare
- OCR1AH = (CTC_MATCH_OVERFLOW >> 8);
- OCR1AL = CTC_MATCH_OVERFLOW;
- // Enable the compare match interrupt
- TIMSK1 |= (1 << OCIE1A);
- // PC0/Analog 0 to Output
- DDRD |= (1 << PD4);
- // Now enable global interrupts
- sei();
- DDRB = ~0xef;
- PORTB = 0xef;
- //PORTD = 0xf7;
- }
- ///////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////////
- void ispis_7SEG (unsigned char karakter, unsigned char pozicija)
- {
- PORTB = ~(0x01 << (4-pozicija)); // ukljucenje displeja na zeljenoj
- // poziciji
- PORTD = karakter; // prikaz karaktera
- _delay_ms(2); // pauza 2ms
- }
- // Switch-o-ception...
- // Trenutno mi ne pada elegantniji nacin da se obavi ovoliko dodjeljivanje. Polu brute-force pristup.
- void execute(unsigned char operacija, unsigned char periferija){
- switch(operacija) {
- case init:
- switch(periferija) {
- case LED:
- DDRB = STATE_LED[3];
- DDRC = STATE_LED[4];
- DDRD = STATE_LED[5];
- PORTB = STATE_LED[0];
- PORTC = STATE_LED[1];
- PORTD = STATE_LED[2];
- break;
- case displej7SEG:
- DDRB = STATE_7SEG[3];
- DDRC = STATE_7SEG[4];
- DDRD = STATE_7SEG[5];
- PORTB = STATE_7SEG[0];
- PORTC = STATE_7SEG[1];
- PORTD = STATE_7SEG[2];
- break;
- case TASTERI:
- DDRB = STATE_BUTTONS[3];
- DDRC = STATE_BUTTONS[4];
- DDRD = STATE_BUTTONS[5];
- PORTB = STATE_BUTTONS[0];
- PORTC = STATE_BUTTONS[1];
- PORTD = STATE_BUTTONS[2];
- break;
- case PREKIDACI:
- DDRB = STATE_SWITCHES[3];
- DDRC = STATE_SWITCHES[4];
- DDRD = STATE_SWITCHES[5];
- PORTB = STATE_SWITCHES[0];
- PORTC = STATE_SWITCHES[1];
- PORTD = STATE_SWITCHES[2];
- break;
- case BROJAC:
- DDRB = STATE_INTERRUPT[3];
- DDRC = STATE_INTERRUPT[4];
- DDRD = STATE_INTERRUPT[5];
- PORTB = STATE_INTERRUPT[0];
- PORTC = STATE_INTERRUPT[1];
- PORTD = STATE_INTERRUPT[2];
- break;
- }
- break;
- // sada ponovo sve u slucaju UPDATE operacije.
- case update:
- switch(periferija) {
- case LED:
- STATE_LED[0] = PORTB;
- STATE_LED[1] = PORTC;
- STATE_LED[2] = PORTD;
- break;
- case displej7SEG:
- STATE_7SEG[0] = PORTB;
- STATE_7SEG[1] = PORTC;
- STATE_7SEG[2] = PORTD;
- break;
- case TASTERI:
- STATE_BUTTONS[0] = PORTB;
- STATE_BUTTONS[1] = PORTC;
- STATE_BUTTONS[2] = PORTD;
- break;
- case PREKIDACI:
- STATE_SWITCHES[0] = PORTB;
- STATE_SWITCHES[1] = PORTC;
- STATE_SWITCHES[2] = PORTD;
- break;
- case BROJAC:
- STATE_INTERRUPT[0] = PORTB;
- STATE_INTERRUPT[1] = PORTC;
- STATE_INTERRUPT[2] = PORTD;
- break;
- }
- break;
- }
- }
- unsigned char ocitaj_prekidace()
- {
- unsigned char i, tmp = 0, mask = 0x80;
- //impuls za upis stanja prekidaca u registar
- SHLD_HI;
- SHLD_LO;
- SHLD_HI;
- for (i=0; i<8; i++)
- {
- SCL_LO;
- SCL_HI; //generisanje aktivne ivice takta
- if (SDA) //provera stanja ulaznog pina
- tmp |= mask;
- mask >>= 1;
- }
- return tmp;
- }
- // Proverava uslove definisane kao MACRO i vraca odgovarajucu enumerisanu vrijednost.
- unsigned char ocitajTaster(){
- enum BUTTONS btn;
- if(KEY_L_PRESS) {
- btn = LEFT;
- } else if (KEY_D_PRESS){
- btn = DOWN;
- } else if (KEY_R_PRESS){
- btn = RIGHT;
- } else if (KEY_U_PRESS){
- btn = UP;
- } else {
- btn = NONE;
- }
- return btn;
- }
- int main(void)
- {
- unsigned char prekidaci = 0;
- /*
- * Rad sa periferijom je ogradjen izmedju dva poziva funkcije execute
- *
- * execute(init, PERIFERIJA); // inicijalizujem registre
- *
- * // ovde ide kod koji radi sa tom periferijom
- *
- * execute(update, PERIFERIJA); // cuvam njihovo stanje za sledeci prolaz petlje.
- *
- * Ovo je zapravo implementacija slozenijeg VREMENSKOG MULTIPLEKSA
- * gdje se ne vrsi multipleks nad jednim portom u jednoj ulozi,
- * nego nad svim portovima koji obavljaju visestruke funkcije...
- * Kontam za neke brze operacije i bez delaya, moze maaali milion razlicitih stvari
- * da se radi na ovaj nacin :D :D :D
- *
- * */
- while(1) {
- ///////////////////////////////////////////////////////////////////////////////////
- execute(init, BROJAC);
- initCounterStuff();
- flash_led();
- execute(update, BROJAC);
- // Inicijalizujem registre za koriscenje prekidaca
- // prije je ovde bila: initSwitches(); sada 6 starih funkcija zamjenila ova jedna
- execute(init, PREKIDACI);
- // Ovdje budzis svoj kod koji zelis da se vozi nad registrima
- // postavljenim za rad sa prekidacima.
- //------------------------
- prekidaci = ocitaj_prekidace();
- trenutniIspis[0] = prekidaci;
- //------------------------
- // Na kraju upotrebe, vratim trenutno stanje registara u LUT
- execute(update, PREKIDACI);
- ///////////////////////////////////////////////////////////////////////////////////
- execute(init, BROJAC);
- initCounterStuff();
- flash_led();
- execute(update, BROJAC);
- // Dio koji obavlja sve poslove vezane za tastere.
- execute(init, TASTERI);
- taster = ocitajTaster();
- if(!taster) enable = 1;
- if(enable == 1) {
- switch(taster) {
- case LEFT:
- // Prvi karakter se brise vracanjem svih prekidaca na NULU.
- // Radi nesto...
- enable = 0;
- break;
- case DOWN:
- // Drugi brises pomocu tastera.
- trenutniIspis[1] = iskljucen;
- enable = 0;
- break;
- case RIGHT:
- // Treci...
- trenutniIspis[2] = iskljucen;
- enable = 0;
- break;
- case UP:
- // Cetvrti...
- trenutniIspis[3] = iskljucen;
- enable = 0;
- break;
- }
- }
- execute(update, TASTERI);
- execute(init, BROJAC);
- initCounterStuff();
- flash_led();
- execute(update, BROJAC);
- ///////////////////////////////////////////////////////////////////////////////////
- // Isto radim sa 7SEG displejima kao i sa prekidacima
- // Ucitam u registre njihova poslednja stanja i radim nad njima nesto
- // Na kraju to samo vratim u LUT i ovaj proces se ponavlja stotinama
- // i hiljadama puta u sekundi recimo... brzinom while(1)
- execute(init, displej7SEG);
- ispis_7SEG (trenutniIspis[0], 1);
- ispis_7SEG (trenutniIspis[1], 2);
- ispis_7SEG (trenutniIspis[2], 3);
- ispis_7SEG (trenutniIspis[3], 4);
- execute(update, displej7SEG);
- execute(init, BROJAC);
- initCounterStuff();
- flash_led();
- execute(update, BROJAC);
- ///////////////////////////////////////////////////////////////////////////////////
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement