Elektroda.pl
Elektroda.pl
X
CControls
Proszę, dodaj wyjątek www.elektroda.pl do Adblock.
Dzięki temu, że oglądasz reklamy, wspierasz portal i użytkowników.

PIC16F883 - Obsługa uSWITCH z diodami / RS232

crosman 16 Lip 2013 14:46 4941 30
  • #1 16 Lip 2013 14:46
    crosman
    Poziom 6  

    Na płytce podłączone mam
    wyjścia: RA0, RA1, RB4, RB5 - jako diody podłączone do Vcc - świecą dla 0 na wyjściu
    wejścia: RA2, RA3, RB2, RB3 - uSWITCHE uziemiające, czyli dla niewciśniętych na wejściu mam 0x0C
    pRXX - zmienne pomocnicze ustawiane, gdy dany przycisk jest wciśnięty

    Program miał na celu aby po naciśnięciu jednego z przycisków zapalała się odpowiadająca mu dioda

    Code:

    #include <pic.h>
    __CONFIG(LVP_OFF&PWRTE_OFF&WDTE_OFF&MCLRE_ON&DEBUG_ON&FCMEN_ON&IESO_OFF&CPD_OFF&CP_OFF&FOSC_INTRC_NOCLKOUT);

    main()
        {
        /* oscylator config */
        SCS=0;
        IRCF2=1;
        IRCF1=1;
        IRCF0=1;

        /* I/O config */
        TRISA=0x0C;
        TRISB=0x0C;
        ANSEL=0;
       ANSELH=0;


       char inputA, inputB;
       int pRA2, pRA3, pRB2, pRB3;
       

        while(1)
            {
             inputA=PORTA;
             inputA=inputA&0x0C;
             inputB=PORTB;
             inputB=inputB&0x0C;
                if(inputA==0x0C && inputB==0x0C)
                {
                    pRA2=0;
                    pRA3=0;
                    pRB2=0;
                    pRB3=0;
                }
                else
                {
                    if(inputA==0x08 || inputA==0x00) pRA2=1;
                    if(inputA==0x04 || inputA==0x00) pRA3=1;
                    if(inputB==0x08 || inputB==0x00) pRB2=1;
                    if(inputB==0x04 || inputB==0x00) pRB3=1;
                }
                /* nacisniety przycisk - zapalona dioda
                przycisk RA2 - dioda RA0
                przycisk RA3 - dioda RA1
                przycisk RB2 - dioda RB4
                przycisk RB3 - dioda RB5
                */
                if(pRA2==1 && pRA3==0) PORTA=0x02;




                else if(pRA3==1 && pRA2==0) PORTA=0x01;
             else if(pRA2==1 && pRA3==1) PORTA=0x0C;
             else PORTA=0x00;
                if(pRB2==1 && pRB3==0) PORTB=0x20;
                else if(pRB3==1 && pRB2==0) PORTB=0x10;
             else if(pRB2==1 && pRB3==1) PORTB=0xC0;
             else PORTB=0x00;
            }

        return 0;
        }


    Dla takiego programu wszystkie diody palą się cały czas ;/ co zrobić, żeby działał tak jak chce?

    Wcześniejszy program gasił odpowiednią diodę i działał poprawnie:
    Code:

    #include <pic.h>
    __CONFIG(LVP_OFF&PWRTE_OFF&WDTE_OFF&MCLRE_ON&DEBUG_ON&FCMEN_ON&IESO_OFF&CPD_OFF&CP_OFF&FOSC_INTRC_NOCLKOUT);

    main()
        {
        /* oscylator config */
        SCS=0; /* oscylator ustawiony w FOSC */
        IRCF2=1;
        IRCF1=1;
        IRCF0=1; /* oscylator 8MHz */
       
        /* I/O config */
        TRISA=0x0C;
        TRISB=0x0C;
        ANSEL=0;
       ANSELH=0;
       
       char inputA, inputB;

        while(1)
            {
             inputA=PORTA;
             inputA=inputA&0x0C;
             if(inputA==0x0C)   PORTB=0x00;
             if(inputA==0x08)    PORTB=0x10;
             if(inputA==0x04)    PORTB=0x20;
             if(inputA==0x00)   PORTB=0xF0;
             inputB=PORTB;
             inputB=inputB&0x0C;
             if(inputB==0x0C)   PORTA=0x00;
             if(inputB==0x08)    PORTA=0x01;
             if(inputB==0x04)    PORTA=0x02;
             if(inputB==0x00)   PORTA=0x0F;
            }

        return 0;
        }

    Po modyfikacji programu (0x00 na 0x0F, 0x01 na 0x02, 0x02 na 0x01 itd) pojawiał się taki sam problem, czyli diody świecą cały czas ;/ w tym przypadku jednak wybrana dioda świeci mocniej od pozostałych ;) już nie mam pomysłów jak zrobić to zadanie, aby działało poprawnie

    0 29
  • CControls
  • Pomocny post
    #2 16 Lip 2013 15:13
    BlueDraco
    Specjalista - Mikrokontrolery

    Np. testuj każdy przycisk osobno i zapalaj każdą diodę osobno wg stanu przycisku. Wcześniej zdefiniuj maski bitowe przycisków i diod.

    if (inputB & PRZYCISK1)
    PORTA |= LED1;
    else
    PORTA &= ~LED1;

    0
  • Pomocny post
    #3 16 Lip 2013 15:19
    atom1477
    Poziom 43  

    A dlaczego program jest taki dziwaczny?
    Np to:

    Code:
    if(inputA==0x08 || inputA==0x00) pRA2=1;

    Zrób to normalnie czyli tak:
    Code:
    if((inputA & 0x08) == 0)
    
        PORTB &= ~0x10;
    else
        PORTB |= 0x10;

    0
  • #4 16 Lip 2013 15:28
    crosman
    Poziom 6  

    BlueDraco napisał:
    Np. testuj każdy przycisk osobno i zapalaj każdą diodę osobno wg stanu przycisku. Wcześniej zdefiniuj maski bitowe przycisków i diod.

    if (inputB & PRZYCISK1)
    PORTA |= LED1;
    else
    PORTA &= ~LED1;


    maski bitowe? chodzi o coś takiego?
    #define LED_A0 5.0
    #define LED_A1 5.1
    #define LED_B4 6.4
    #define LED_B5 6.5

    #define SW_A2 5.2
    #define SW_A3 5.3
    #define SW_B2 6.2
    #define SW_B3 6.3?

    jak wtedy wyglądałoby warunki? albo chociaż jeden?

    Code:
    if(!SW_A2)
    
    {
    LED_A0 =1;
    }
    else
    {
    LED_A0=0;
    }

    0
  • CControls
  • Pomocny post
    #5 16 Lip 2013 16:02
    BlueDraco
    Specjalista - Mikrokontrolery

    Logicznie chodzi o to, tylko ze składnią C to, co napisałeś, ma niewiele wspólnego.

    Raczej np.
    #define SW_B3 8
    #define LED_B5 0x20

    0
  • #6 16 Lip 2013 16:31
    crosman
    Poziom 6  

    BlueDraco napisał:
    Np. testuj każdy przycisk osobno i zapalaj każdą diodę osobno wg stanu przycisku. Wcześniej zdefiniuj maski bitowe przycisków i diod.

    if (inputB & PRZYCISK1)
    PORTA |= LED1;
    else
    PORTA &= ~LED1;


    a czy dla danego przypadku (gdzie przyciski uziemiają) nie powinienem zrobić warunku if(~inputB & PRZYCISK1)? gdzie definicją tego przycisku będzie
    #define PRZYCISK1 0x04 dla przycisku RA4
    bo gdy przyciski nie są załączone to na wejsciu są 1-ki

    truje trochę, ale od wczoraj ruszyłem z PIC, a dopiero dziś przebrnąłem przez problemy przerwań i tim0 :P

    0
  • Pomocny post
    #7 16 Lip 2013 17:10
    BlueDraco
    Specjalista - Mikrokontrolery

    Możesz tak zrobić, jeśli chcesz, żeby dioda zapalała się przy zwolnionym przycisku. Popatrz - masz tu blok then i blok else. Możesz zanegować warunek i zamienić bloki miejscami, tylko po co?

    0
  • Pomocny post
    #8 17 Lip 2013 12:27
    PDT
    Poziom 24  

    Zamiast na początek ćwiczyć 'mieszańce' w C, lepiej spróbować rasowo:

    Kod: asm
    Zaloguj się, aby zobaczyć kod


    Pzdr

    0
  • #9 17 Lip 2013 18:55
    crosman
    Poziom 6  

    Tamto zadanie udało mi się wykonać ;) teraz próby ze zmianą diody po każdym naciśnięciu jednego wejścia ;D

    Program miał za zadanie po każdym kliknięciu switcha B2 zmieniać stan diody ;) w pierwszym cyklu wykrycia wejścia ustawiam zmienną pomocniczą (unsigned int, wiec nie przepełnia się przy 40000). W każdym kolejnym cyklu zmienna jest inkrementowana, aż do osiągnięcia 40k (dla 8MHz taktowania / 4 = 2MHz czas syklu * 40000 daje 20ms czyli maksymalny czas trwania drgania styków). Po 20ms badany jest stan wejścia do czasu, gdy zostanie ono puszczone, a wtedy pomocnicza jest zerowana.

    Code:

             if ((inputB & SW_B2) && !pomocnicza)
             {
                    pomocnicza=1;
                    PORTA^=LED_A0;
             }
             else if ((inputB & SW_B2) && pomocnicza>0 && pomocnicza<40000)
                pomocnicza++;
             else if((inputB & SW_B2) && pomocnicza==40000)
             {
                if(inputB & SW_B2)
                   ;
                    else
                   pomocnicza=0;
             }

    Problem? Tylko przy pierwszym przyciśnięciu zmieniony jest stan diody :)

    dla programu
    Code:

             if (inputB & SW_B2)
             {
                    PORTA^=LED_A0;
             }

    widoczna jest losowość stanu wyjścia, więc PORTA^=LED_A0; działa

    0
  • Pomocny post
    #10 17 Lip 2013 18:59
    atom1477
    Poziom 43  

    Błędnie zakłądasz że inkrementacja zachodzi z prędkością taktowania (w uproszczeniu).
    A przecież procesor robi 100 innych rzeczy jeszcze.

    0
  • #11 17 Lip 2013 19:26
    crosman
    Poziom 6  

    i co to znaczy? muszę dłuuuugo trzymać i spróbować wtedy jeszcze raz przycisnąć?

    czyli wystarczyłoby zmniejszyć np na 1000 i zostawić te warunki i powinno działać?

    da się jakoś zbadać czas cyklu? czy tylko w przybliżeniu watchdogiem?

    jest jakiś łatwiejszy sposób załatwienia problemu?

    0
  • Pomocny post
    #12 17 Lip 2013 21:17
    Urgon
    Poziom 36  

    AVE...

    1. Zmniejsz sobie wartość tego licznika eksperymentalnie, aż dojdziesz do takiej wartości, gdy kod będzie działać poprawnie.
    2. Spróbuj użyć funkcji delay_ms, czy jak ona się zwie w Twoim kompilatorze(to złe rozwiązanie z punktu widzenia praktyki programistycznej).
    3. Masz trzy timery, użyj któregoś z nich.
    4. Użyj pinu z Interrupt_On_Change.
    Masz obwód RC przyłączony do przycisku by robić debouncing sprzętowy?

    0
  • #13 17 Lip 2013 22:16
    crosman
    Poziom 6  

    Urgon napisał:
    AVE...

    1. Zmniejsz sobie wartość tego licznika eksperymentalnie, aż dojdziesz do takiej wartości, gdy kod będzie działać poprawnie.
    2. Spróbuj użyć funkcji delay_ms, czy jak ona się zwie w Twoim kompilatorze(to złe rozwiązanie z punktu widzenia praktyki programistycznej).
    3. Masz trzy timery, użyj któregoś z nich.
    4. Użyj pinu z Interrupt_On_Change.
    Masz obwód RC przyłączony do przycisku by robić debouncing sprzętowy?


    1. czyli oznacza to, ze sam kod jest ok?
    2. delaya sam sobie robiłem na timerze0, dla przećwiczenia przerwań, ale on blokuje dalszą prace programu (zatrzymujemy sie na czas delaya w danej linii) :) a inkrementacja pozwala na stały obrót petli
    3. timery? to spróbuje ;) ale to też łączy sie z przerwaniami :)
    4. przerwania zewnetrzne planuję w następnym etapie porobić :) a obsługa przycisków i tak mnie nie ominie ;/

    RC brak, bo by nie było problemu :) a i tak kiedyś można na niego trafic

    0
  • Pomocny post
    #14 17 Lip 2013 23:03
    Urgon
    Poziom 36  

    AVE...

    Co do kodu, to nie wiem, bo jestem podchmielony lekko winem herbacianym...
    Program podziel na dwa kawałki: pętlę główną i przerwania. W pętli głównej za pomocą if-then sprawdzasz sobie jakieś tam flagi bitowe związane z przyciskami. I zachowujesz się adekwatnie, w sensie zmieniasz status zapalenia diod. W przerwaniu sprawdzasz po kolei dwie rzeczy:
    1. Czy wywołał je wybrany przez Ciebie timer?
    2. Czy zmienna pomocnicza ma wartość niezerową i czy stosowny przycisk był wciśnięty(jeśli tak, to przypisujesz to zdarzenie do zmiennej pomocniczej). Jeśli jednocześnie zmienna ma wartość związaną ze stosownym przyciskiem i stosowny przycisk jest nadal wciśnięty, ustawiasz odpowiednią flagę zdarzenia.

    0
  • #17 17 Lip 2013 23:41
    BlueDraco
    Specjalista - Mikrokontrolery

    Szybciej i łatwiej jest w takim przypadku w ogóle nie używać przerwań, bo w końcu zgłoszenie przerwanie następuje w wyniku ustawienia znacznika sprzętowego, który pętla główna może odczytać programowo bez marnowania czasu na praktycznie pustą obsługę przerwania. Jeden drobiazg - usypianie procesora w niepustej pętli głównej niesie ze sobą ryzyko zgubienia zdarzenia, o czym niedawno dyskutowaliśmy. Nie wiem, na czym polega elegancja rowiązania ze zbędnymi przerwaniami i procesorem czekającym aktywnie w pętli głównej. ;)

    0
  • #18 18 Lip 2013 00:10
    Urgon
    Poziom 36  

    AVE...

    Jestem obecnie dość mocno "nasączony" winem, więc będę pisać w miarę prosto.
    Nauczano mnie, by w przerwaniach obsługiwać zdarzenia tylko do generowania flag, a w pętli głównej realizować właściwy program. Nie jest to optymalne rozwiązanie dla pewnych sytuacji, ale na pewno pozwala łatwiej rozbudować i kontrolować program. Nauczono mnie też, iż każda funkcja licząca czas na podstawie cykli zegara w sofcie jest zła. Dlatego zalecałem użycie timera i przerwań. Przerwanie wywołane timerem pozwala nam sprawdzać status różnych rzeczy w stałych odstępach czasu. Pętla główna może kończyć się wtedy uśpieniem mikrokontrolera, lub pętlą wait(). Pamiętać należy o tym, ile instrukcji na sekundę wykonuje procesor, i ile z nich to program w pętli głównej. Dla PIC16F883 jedna instrukcja to 200ns. W ciągu 20ms jest ich 100 tysięcy, w 1s jest ich pięć milionów. Pisząc kod w sposób przeze mnie sugerowany procesor przez większość czasu może być uśpiony, a i tak się ze wszystkim wyrobi, i pozwoli na łatwą rozbudowę kodu o kolejne funkcje...

    0
  • #19 18 Lip 2013 08:57
    BlueDraco
    Specjalista - Mikrokontrolery

    źle Cię uczono z tym ustawianiem znaczników - taka technika programowania nie ma ani sensu, ani uzasadnienia praktycznego. To taki mikrokontrolerowy zabobon. Obsługa przerwania nie ma być "jak najkrótsza". Ma być "nie za długa", tak, aby nie kolidowała z innymi przerwaniami. Jeśli obsługa przerwani polega tylko na ustawieniu znacznika, to lepiej wyłączyć to przerwanie, a w pętli testować bit, który powoduje zgłoszenie przerwania.

    Struktura oprogramowania z pętlą główną chyba nigdy nie jest optymalna, chociaż czasem jest to uzasadniony kompromis pomiędzy nakładem pracy programisty i poprawnością działania programu. Im dłużej programuję, tym więcej widzę problemów i bezsensowności w takiej budowie programu. Największy problem w urządzeniach energooszczędnych - to brak możliwości poprawnego uśpienia procesora (za wyjątkiem ograniczonej klasy przypadków, w których pętla zdarzeń jest całkowicie zbędna).

    Jeżeli mamy w systemie jedno przerwanie i całe działanie programu jest reakcją na to przerwanie, której czas nie przekracza odstępu pomiędzy przerwaniami, nie ma powodu, by pętla główna zawierała cokolwiek - wszystko robimy w obsłudze przerwania.

    Problem z pętlą główną polega na tym, że takiego oprogramowania nie daje się rozbudowywać z zachowaniem możliwości uśpienia procesora. Jeśli są dwa przerwania - usypianie w niepustej pętli głównej grozi zgubieniem zdarzenia.

    0
  • Pomocny post
    #20 18 Lip 2013 12:04
    PDT
    Poziom 24  

    A może by tak jednak w "asm":

    Kod: asm
    Zaloguj się, aby zobaczyć kod


    Kod zawarty w pętli głównej pomiędzy etykietami 'loop' i 'cont' można (bez zmian) przenieść do procedury przerwania od timera wywoływanej co ok. 2ms. Idea pozostaje bez zmian.
    Pzdr

    0
  • #21 18 Lip 2013 19:10
    Urgon
    Poziom 36  

    AVE...

    @BlueDraco...
    Dzięki za rozjaśnienie. Ale mam taką sugestię ewentualnej pętli, którą można rozbudowywać. W pętli głównej cała seria testów dla flag zdarzeń, i każde zdarzenie powoduje skok do stosownej procedury. Procedura kasuje flagę. Po wykonaniu całej pętliusypiasz mikrokontroler i czekasz, aż go przerwanie obudzi. Krytyczne przerwania robisz w procedurze ich obsługi, resztę za pomocą flag, bo po przerwaniu mikrokontroler nie jest usypiany i wraca do pętli głównej. W ten sposób nie gubi się zdarzeń, zwłaszcza jeśli w obsłudze zamiast ustawiać flagę, będzie się inkrementowało zmienną flagową. W ten sposób można w pętli głównej lub w procedurze sprawdzać, ile razy zdarzenie się zdarzyło nim je obsłużono...

    @PDT...
    Rozumiem, iż jesteś fanem pisania w ASM. Czy ma to sens w obecnych czasach? Moim niezwykle skromnym zdaniem tylko tam, gdzie czas wykonywania kodu ma znaczenie i trza walczyć o każdy cykl. Lepiej jednak opanować język wysokopoziomowy, bo można pisać dla wielu rodzin mikrokontrolerów bez większych problemów...

    0
  • #22 18 Lip 2013 19:28
    BlueDraco
    Specjalista - Mikrokontrolery

    Po sprawdzeniu, że nie wystąpiło zdarzenia A, przechodzisz do sprawdzenia, czy nastąpiło zdarzenie B. W tym czasie zostaje zgłoszone przerwanie generujące zdarzeie A, a ty spokojnie usypiasz procesor. Procesor zostanie obudzony po kolejnmy wystąpieniu zdarzenia (np. A). W ten oto zgrabny sposów zgubiłeś jedno zdarzenie A.
    Pożytek z tego, że dzięki licznikowi (zamiast zmiennej boolowskiej) dowiesz się, ile znaków z UARTa zgubiłeś, nie będzei zbyt wielki.
    Podsatwowym problemem z pętlą jest właśnie to, że nie daje się jej rozbudowywać bez błędów, a kiedy obsługuje tylko jedno zdarzenie, to nie ma sensu jej stosować.

    0
  • Pomocny post
    #23 18 Lip 2013 19:47
    PDT
    Poziom 24  

    Urgon napisał:
    @PDT...
    Rozumiem, iż jesteś fanem pisania w ASM. Czy ma to sens w obecnych czasach?


    Piszę w bardzo wielu językach programowania. Często w sprzętowych problemach mieszam C/asm. A czasy nie mają tu nic do rzeczy: w moim rozwiązaniu istotna część obsługi zamyka się w 9 rozkazach. Przy operacjach bitowo zorientowanych zwykle zapis w asm jest też bardziej zwarty.

    Pzdr

    0
  • #24 22 Lip 2013 15:34
    crosman
    Poziom 6  

    ostatecznie zrobiłem to na zmiennej globalnej inkrementowanej w przerwaniu od timera :)

    przerwanie:

    Code:

    volatile unsigned int int_cnt;
    void interrupt int_t0(void)
       {
          if(T0IF)
             {

                 int_cnt++;
                 TMR0=131; /* przerwanie co 1ms */
                 T0IF=0;
             }
       }


    w programie użyłem dwóch zmiennych key i n_key aby móc wykonywać coś na załączenie przycisku jak i wyłączenie ;) w programie mrugam diodą A0 przy przyciskaniu i A1 przy puszczaniu przycisku. Dodatkowa zmienna pomocnicza w zależności od czasu przytrzymania przycisku pozwala na zmianę sposobu świecenia innych diodek, co załatwiam w dalszej części programu przez switch/case
    stan key && !n_key - przycisk puszczony / !key && n_key - przycisk wciśnięty :) !key && !n_key / key && n_key użyte jako pomocnicze dla uzyskania opóźnienia 20ms dla usunięcia drgań ;) takie rozwiązanie programu pozwala pętli ciągłą pracę, bez zbędnych delay i funkcji

    Code:

    if ((inputB & SW_B2) && !key && n_key) /* off>on */
             {
                PORTA^=LED_A0;
                pom=int_cnt;
                key=1;
             }
    else if ((inputB & SW_B2) && key && n_key) /* on delay */
             {
                 if(int_cnt-pom>20)
                 {
                     n_key=0;
                 }
             }
    else if ((inputB & SW_B2) && key && !n_key) /* when on */
             {
                 if (0<=int_cnt-pom && int_cnt-pom<500)
                 {
                     tryb=1;
                 }
                 else if(500<int_cnt-pom && int_cnt-pom<1000)
                 {
                     tryb=2;
                 }
                 else if(1000<int_cnt-pom && int_cnt-pom<1500)
                 {
                     tryb=3;
                 }
                else if(1500<int_cnt-pom && int_cnt-pom<2000)
                 {
                     tryb=4;
                 }
             else if(2000<int_cnt-pom)
                {
                    pom=int_cnt;
                }

             }
    else if (!(inputB & SW_B2) && key && !n_key) /* on>off */
             {
             PORTA^=LED_A1;
             pom=int_cnt;
             key=0;
             }
    else if (!(inputB & SW_B2) && !key && !n_key) /* off delay */
             {
                 if(int_cnt-pom>20)
                 {
                     n_key=1;
                 }
             }


    żeby nie zaśmiecać forum nowymi tematami o rs232 prosiłbym o małą pomoc jak ugryźć ten problem ;) znalazłem kilka tematów na forum, ale większość była rozwiązywana przez asemblera, a ja chciałbym to porobić w C :)

    0
  • #25 23 Lip 2013 16:50
    crosman
    Poziom 6  

    Tym razem ma problem z RS232. Spróbowałem na początek skorzystać z gotowego przykładu HiTech, a nie udało mi się podczas kompilacji
    main.c

    Code:

    #include <stdio.h>
    #include <htc.h>
    #include "usart.h"

    void main(void){
       unsigned char input;

       INTCON=0;   // purpose of disabling the interrupts.

       init_comms();   // set up the USART - settings defined in usart.h

       // Output a message to prompt the user for a keypress   
       printf("\rPress a key and I will echo it back:\n");
       while(1){
          input = getch();   // read a response from the user
          printf("\rI detected [%c]",input);   // echo it back
       }
    }

    usart.c
    Code:

    #include <htc.h>
    #include <stdio.h>
    #include "usart.h"

    void
    putch(unsigned char byte)
    {
       /* output one byte */
       while(!TXIF)   /* set when register is empty */
          continue;
       TXREG = byte;
    }

    unsigned char
    getch() {
       /* retrieve one byte */
       while(!RCIF)   /* set when register is not empty */
          continue;
       return RCREG;   
    }

    unsigned char
    getche(void)
    {
       unsigned char c;
       putch(c = getch());
       return c;
    }

    usart.h
    Code:

    #ifndef _SERIAL_H_
    #define _SERIAL_H_

    #define BAUD 9600     
    #define FOSC 4000000L
    #define NINE 0     /* Use 9bit communication? FALSE=8bit */

    #define DIVIDER ((int)(FOSC/(16UL * BAUD) -1))
    #define HIGH_SPEED 1

    #if NINE == 1
    #define NINE_BITS 0x40
    #else
    #define NINE_BITS 0
    #endif

    #if HIGH_SPEED == 1
    #define SPEED 0x4
    #else
    #define SPEED 0
    #endif

    #if defined(_16F87) || defined(_16F88)
       #define RX_PIN TRISB2
       #define TX_PIN TRISB5
    #else
       #define RX_PIN TRISC7
       #define TX_PIN TRISC6
    #endif

    /* Serial initialization */
    #define init_comms()\
       RX_PIN = 1;   \
       TX_PIN = 1;        \
       SPBRG = DIVIDER;        \
       RCSTA = (NINE_BITS|0x90);   \
       TXSTA = (SPEED|NINE_BITS|0x20)

    void putch(unsigned char);
    unsigned char getch(void);
    unsigned char getche(void);

    #endif

    Podczas kompilaci wyświetla się błąd
    Error [500] ; 0. undefined symbols:
    _getch(RS232.obj) _putch(RS232.obj)
    Pracuje nadal na PIC16F883.
    Jak zmienić i sprawdzić czy cokolwiek działa? Niestety jeżeli chodzi o RS232 to moja wiedza jest znikoma ;/
    Znalazłem również takie rozwiązanie
    http://www.mcuexamples.com/PIC-Serial-Communication.php
    Które z nich będzie łatwiejsze i lepiej działające?

    chciałbym pobierać znak i po zapisaniu go odesłać na PC

    0
  • Pomocny post
    #26 30 Lip 2013 11:28
    94075
    Użytkownik usunął konto  
  • #27 30 Lip 2013 15:26
    crosman
    Poziom 6  

    aktualnie próbuje wykorzystać kod http://www.mcuexamples.com/PIC-Serial-Communication.php w swoim programie:) jednak mam problem z doborem wartości SPBRG/H ;/ bity konfiguracyjne:

    Code:

        CREN=1;
        SYNC=0;
        SPEN=1;
        ANSEL=0;
        ANSELH=0; 
        BRG16=1;
       
        SPBRGH  = ???
        SPBRG   = ???

        BRGH=1;
        TXEN=1;

        GIE=1;
        RCIE=1


    oscylator ustawiłem na 8MHz ;) w pdf jest jakiś wzór do obliczeń jednak nie za bardzo wiem jak go używać ;/ jak dobrać wartości SPBRGH i SPBRG?

    0
  • Pomocny post
    #28 31 Lip 2013 08:33
    94075
    Użytkownik usunął konto  
  • #29 31 Lip 2013 16:29
    crosman
    Poziom 6  

    Jak to liczyłeś?

    albertb napisał:
    crosman napisał:

    Code:

        SPBRGH  = 0;
        SPBRG   = 207;




    Kolejny problem :D ADC
    Code:

    #include <htc.h>
    #include <stdio.h>
    #include <stdlib.h>


    __CONFIG(LVP_OFF&PWRTE_ON&WDTE_OFF&MCLRE_ON&DEBUG_ON&FCMEN_ON&IESO_OFF&CPD_OFF&CP_OFF&FOSC_INTRC_NOCLKOUT);
    /* def */
    #define SW_B2 0x04
    #define SW_B3 0x08
    #define LED_A0 0x01
    #define LED_A1 0x02
    #define LED_B4 0x10
    #define LED_B5 0x20
    /* pomocnicza zmienna */
    volatile unsigned int int_cnt;
    /* przerwanie */
    void interrupt int_t0(void);
    /* delay ms */
    void delay_ms(unsigned int time);
    /* ADC data */
    int ADC_value;

    main()
    {
        /* oscylator config */
        SCS=0; /* oscylator ustawiony w FOSC */
        IRCF2=1;
        IRCF1=1;
        IRCF0=1; /* oscylator 8MHz */
        /* TIMER0 */
        T0CS=0; /* zliczanie wewnetrznych impulsow */
        PSA=0; /* przypisanie prescalera */
        PS2=0;
        PS1=1;
        PS0=1; /* prescaler 1:16 */
        /* przerwania */
        GIE=1;
        T0IE=1;
        /* I/O config */
        TRISA=0x0C;
        TRISB=0x0D; /* RB0 input */
        ANSEL=0;
        ANSELH=0x10; /* RB0/ANS12 analog input */
        /* ADC config */
        ADON=1;
        CHS3=1;
        CHS2=1;
        CHS1=0;
        CHS0=0; /* AN12 channel */
        ADCS1=1;
        ADCS0=0; /* FOSC/32 recomended */
        ADFM=1; /* right justified */
        ADIE=0; /* disable ADC interrupt */
        ADIF=0; /* ADC interrupt flag cleared */
        ADRESL=0;
        ADRESH=0;
       
        char inputB;
       unsigned int key=0, n_key=1, pom=0;
       
        while (1)
        {
            GO_nDONE=1;
            while(GO_nDONE) continue;
           
                ADC_value=ADRESL;
                ADC_value+=(ADRESH << 8); /* odczyt ADC */
               
                inputB=~PORTB;
             inputB=inputB&0x0C; /* odczyt switch PORTB */
             
            if ((inputB & SW_B2) && !key && n_key) /* off>on */
             {
                pom=int_cnt;
                key=1;
             }
             else if ((inputB & SW_B2) && key && n_key) if(int_cnt-pom>20) n_key=0; /* on delay */
             else if ((inputB & SW_B2) && key && !n_key) /* when on */
             {
                while((inputB & SW_B2) && key && !n_key)
                {
                    PORTA=0x00;
                    delay_ms(ADC_value);
                    PORTA=0xFF;
                    delay_ms(ADC_value);
                }
             }
             else if (!(inputB & SW_B2) && key && !n_key) /* on>off */
             {
             pom=int_cnt;
             key=0;
             }
            else if (!(inputB & SW_B2) && !key && !n_key) if(int_cnt-pom>20) n_key=1;
           
        }
       
        return 0;
    }
    void interrupt int_t0(void)
    {
        if(T0IF)
            {
                /* przerwanie co ms
                8000000/(4*16*1000)=125
                spr: 8000000/(4*16*125)=1000
                */
                int_cnt++;
                TMR0=131;
                T0IF=0;
            }
    }
    void delay_ms(unsigned int time)
    {
        unsigned int start=int_cnt;
        while((int_cnt-start)<time)
        {
            ;
        }
    }


    Odczyt z RB0 wartości, według której mają mrugać diody na porcie A (RA0 i RA1 podciągnięte do +, czyli świecą dla 0) gdy przycisniety jest SW2. Po zaprogramowaniu cały czas świeci dioda RA1 niezaleznie od napięcia na RB0. Proszę o pomoc

    0
  • Pomocny post
    #30 01 Sie 2013 07:51
    94075
    Użytkownik usunął konto