środa, 30 sierpnia 2017

DS18B20 - budujemy bibliotekę inną niż wszyscy :)

Każdy szanujący się amator musi ujarzmić najpopularniejszy cyfrowy czujnik temperatury DS18B20, bez niego życie amatora byłoby nieciekawe.
W artykule skupię się na zbudowaniu biblioteki dla 16-bitowego mikrokontrolera PIC24HJ128GP502 firmy Microchip.



Prezentowana biblioteka będzie odbiegać od wszech-obecnych standardów w których wiele czujników wieszamy na jednym pinie mikrokontrolera. Biblioteka umożliwiać będzie podpięcie wielu czujników na osobnych wyjściach mikrokontrolera.
Teorii nie będę prezentował ponieważ jest tego od groma na necie, poniżej artykułu zebrałem kilka przydatnych linków w zakresie teorii.W artykule skupimy się na działaniu czyli co i jak połączyć oraz na testowaniu biblioteki.
Należy nadmienić, że czujnik DS18B20 ma potężną zaletę , mianowicie możemy tutaj dokonywać oddalonych pomiarów nawet o 200 m . Przy czym bardziej odporna na błędy będzie konfiiguracja w której każdy czujnik ma wydzielony pin mikrokontrolera. W praktyce wieszanie wielu czujników na jednej linii może generować problemy i skraca zasięg linii.

W zakresie połączeń posłużymy się poniższym schematem :




Aby zestawić zestaw testowy potrzebujemy :

1. Mikrokontroler PIC 24HJ128GP502 lub dowolny PIC 16 bitowy .
2. Wyświetlacz LCD na 3.3 V  w moim przypadku DOGM204-A (mój ulubiony i szybki jak przecinak)
3. Dwa czujniki DS18B20 podłączamy w trybie Parasite czyli minimalizujemy ilość kabli do czujnika,jeśli chcemy z większych odległości odczytywać temperaturę to rezystory podciągające R8 i R9 należy zmienić na 2.2 k.

Biblioteka gotowa i przetestowna na żywym organizmie.
Nie jest to może dzieło sztuki programistycznej (miejmy na uwadze , że pisze to hobbysta amator) ale generalnie jestem zadowolony z efektu końcowego. W programie jest kilka ciekawych trików m.in timery programowe, obsługa quasi wielowątkowości za pomocą operatora Modulo, dzięki czemu nie blokujemy pętli głównej programu. Do odczytu temperatury nie użyłem zmiennej typu float bo w takiej postaci dane są przechowywane w DS18B20. Nie wiem czemu tak wszyscy się boją tych floatów czy jedynym problemem jest ograniczenie  zasobów mikrokontrolera ? :), w PIC-ach 16-bitowych mamy elementy wspierające obsługę takich zmiennych choć FPU tutaj nie mamy.

Ilość czujników jakie możemy podłaczyć do jednego portu mikrokontrolera to 16 sztuk i takie jest ograniczenie programu co do ilości obsługiwanych czujników. Czujniki wieszamy na porcie B .Jeśli chcemy korzystać z więcej niż np 3 czujników to lepiej w jednym procesie odczytywać dane z wszystkich czujników , modyfikacja w tym zakresie programu jest banalnie prosta.




Jedna uwaga na koniec. Programowanie mikrokontrolerów PIC daje ogromną satysfakcję. Jeśli poprzednim wyborem były mikrokontrolery Atmega 8 bitowe to przejście na 16 bitów od Microchipa jest po prostu bajkowym światem pełnym nowych możliwości. Jest to świat który w bezbolesny sposób może przenieść nas wprost np. w objęcia ARM-ów. Znajomość PIC-ów uważam jest ważnym elementem, jeśli ktoś wiąże z tym swoja drogę zawodową, z tego co się zorientowałem w USA jest to pierwszy wybór a u nas w kraju widziałem oferty pracy dla programistów C/C++ ze znajomością mikrokontrolerów PIC w branży urządzeń medycznych i automotive. ARM-y znają wszyscy i jest to powszechna umiejętność więc aby się wyróżniać na rynku pracy to znajomość PIC-ów jest bardzo dobrym kierunkiem. Takie mam własnie przemyślenia wieczorową porą.


Pozdrawiam
picmajster.blog@gmail.com


Linki :

DS18B20 datasheets
Obsługa interfejsu 1-Wire na przykładzie DS18B20
Dekodowanie temperatury


Pliki projektu :

dogm204.h - plik deklaracji dla wyświetlacza firmy EA model DOGM204-A (4x20)
ds18b20.h - plik deklaracji dla obsługi czujnika DS18B20
onewire.h - plik deklaracji dla obsługi komunikacji Onewire
ustaw_zegar.h - plik deklaracji dla obsługi zegara wewnętrznego ok 40 MHz.

dogm204.c - plik definicji dla wyświetlacza firmy EA model DOGM204-A (4x20)
ds18b20.c - plik definicji dla obsługi czujnika DS18B20
onewire.c - plik definicji dla obsługi komunikacji Onewire
ustaw_zegar.c - plik definicji dla obsługi i konfiguracji zegara wewnętrznego ok 40 MHz.
main.c - główny plik programu


/*****************************************************************************
  FileName:        dogm204.h
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
******************************************************************************/
#ifndef DOGM204_H
#define DOGM204_H

/*_TRISB3 --> TRISBbits.TRISB3*/
#define TRIS_RESET   _TRISA0
#define TRIS_RW      _TRISB3
#define TRIS_RS      _TRISA2
#define TRIS_E       _TRISB2
#define TRIS_DB4     _TRISB12
#define TRIS_DB5     _TRISB13
#define TRIS_DB6     _TRISB14
#define TRIS_DB7     _TRISB15
/*_RB3 --> PORTBbits.RB3*/
#define RESET   _RA0
#define RW      _RB3
#define RS      _RA2
#define E       _RB2
#define DB4     _RB12
#define DB5     _RB13
#define DB6     _RB14
#define DB7     _RB15

/* przyporzadkowanie adresow pamieci DD-RAM do pol wyswietlacza*/
#define LCD_Line1 0x00 /*adres 1 znaku 1 wiersza */
#define LCD_Line2 0x20 /*adres 1 znaku 2 wiersza */
#define LCD_Line3 0x40 /*adres 1 znaku 3 wiersza */
#define LCD_Line4 0x60 /*adres 1 znaku 4 wiersza */

 void Wyslij_do_LCD(unsigned char bajt);
 void WlaczLCD();
 void WyswietlLCD(char *napis);
 void lcd_int(uint16_t val);
 void UstawKursorLCD(uint8_t y, uint8_t x);
 void CzyscLCD();
 void WpiszSwojeZnaki(void);
#endif  /* DOGM204_H */


/*****************************************************************************
  FileName:        ds18b20.h
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
******************************************************************************/

#ifndef DS18B20_h
#define DS18B20_h

#include <stdio.h>
#include <stdlib.h>
#include "onewire.h"

extern int DStemp ; /*split LSB + MSB*/
extern int DStemp_Znak ; /*tutaj badamy znak temperatury*/
extern int DStemp_Calkowita ; 
extern int DStemp_Ulamek ; 
extern char DStemp_Test ;
extern char test_czujnika ;

void ConvertT(int liczba);
void temperatura(int liczba);
void Selektor(int liczba);

typedef struct{
    /*znak temperatury*/
    int sign_temp;
    /*czesc calkowita*/
    int total_temp;
    /*czesc po przecinku*/
    int fraction_temp;
    /*test czujnika*/
    char test_czujnika;
        
}TEMPERATURA;

#endif
/*****************************************************************************
  FileName:        onewire.h
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
******************************************************************************/

#ifndef ONEWIRE_H_   /* Include guard */
#define ONEWIRE_H_

#define PinSetLow (PORTB &= ~(1<<nr_pinu))
#define PinDirectionSetOut (TRISB &= ~(1<<nr_pinu))
#define PinDirectionSetIn (TRISB |= (1<<nr_pinu))
#define TestBit (PORTB & (1<<nr_pinu))
#define SET_parasite (PORTB |= (1<<nr_pinu))
#define CLEAR_parasite (PORTB &= ~(1<<nr_pinu))

/*onewirePin set*/
#define czujnik_1 _PORTB_RB6_POSITION
#define czujnik_2 _PORTB_RB7_POSITION

extern int nr_pinu;

void onewireWriteBit(int b);
unsigned char onewireReadBit();
unsigned char onewireInit();
unsigned char onewireReadByte();
void onewireWriteByte(char data);

#endif
/*****************************************************************************
  FileName:        ustaw_zegar.h
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
******************************************************************************/

#ifndef USTAW_ZEGAR_H
#define USTAW_ZEGAR_H

#define FCY 40000000 /* podajemy wartosc ustawionego zegara (40 MHz), wazne 
aby przed includowaniem <libpic30.h>, potrzebne to jest do wyliczania delay-i*/
/*deklaracja funkcji*/
void ustaw_zegar(void) ;

#endif  /* USTAW_ZEGAR_H */


/*****************************************************************************
  FileName:        dogm204.c
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
******************************************************************************/
#include "xc.h" /* wykrywa rodzaj procka i includuje odpowiedni plik*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h> /*dyrektywy uint8_t itp*/
#define FCY 40000000UL /* podajemy wartosc ustawionego zegara (40 MHz), wazne 
aby przed includowaniem <libpic30.h>, potrzebne to jest to wyliczania delay-i*/
#include <libpic30.h> /*biblioteka dajaca dostepp do delay-i.*/
#include "dogm204.h"

/*definicje funkcji*/
void Wyslij_do_LCD(unsigned char bajt)
{
    /*ustaw linie EN, przed wysylka danych*/

    E = 1;
    /*wyslanie 4 najstarszych bitow danych*/
    if(bajt & 0x80) DB7 = 1else DB7 = 0;
    if(bajt & 0x40) DB6 = 1else DB6 = 0;
    if(bajt & 0x20) DB5 = 1else DB5 = 0;
    if(bajt & 0x10) DB4 = 1else DB4 = 0;
    __delay_us(1);
    /*potwierdzenie wyslania danych (opadajacym zboczem EN)*/
    E = 0;
        
    /*ustawienie EN*/
    __delay_us(1);
    E = 1;
    /*wyslanie 4 najmlodszych bitow danych*/    
    if(bajt & 0x08) DB7 = 1else DB7 = 0;
    if(bajt & 0x04) DB6 = 1else DB6 = 0;
    if(bajt & 0x02) DB5 = 1else DB5 = 0;
    if(bajt & 0x01) DB4 = 1else DB4 = 0;
    __delay_us(1);
    /*potwierdz wysylke danych opadajacym zboczem EN*/
    E = 0;

    __delay_us(16);
    
}   

void WlaczLCD()
{
    /*ustawienie kierunku wyjsciowego linii podlaczonych do LCD*/
    TRIS_RESET = 0 ;
    TRIS_RW = 0 ;
    TRIS_RS = 0;
    TRIS_E = 0;
    TRIS_DB7 = 0;
    TRIS_DB6 = 0;
    TRIS_DB5 = 0;
    TRIS_DB4 = 0;

    /*zerowanie linii*/
    RESET = 1 ; /* 0 - Stan aktywny*/
    RW = 0 ;
    RS = 0/* 0 - wskazuje na rejestr rozkazow / 1 - wskazuje na rejestr danych*/
    E = 0;
    DB7 = 0;
    DB6 = 0;
    DB5 = 0;
    DB4 = 0;

    /*Start Inicjalizacji DOGM204 tryb 4-bity*/
    /*zaczekaj co najmniej 5 ms na ustabilizowanie sie napiecia*/
    __delay_ms(5);
    /*Hardware Reset 10ms*/
    RESET = 0 ;
    __delay_ms(10);
    RESET = 1 ;
    __delay_ms(1);
    
  /*Sekwencja startowa dla trybu 4-bit, patrz mini-datasheet str 5*/
  Wyslij_do_LCD(0x33);//wysylamy instrukcje do rejestru rozkazow
  Wyslij_do_LCD(0x32);
  Wyslij_do_LCD(0x2A);
  Wyslij_do_LCD(0x09);
  Wyslij_do_LCD(0x06);
  Wyslij_do_LCD(0x1E);
  Wyslij_do_LCD(0x29);
  Wyslij_do_LCD(0x1B);
  Wyslij_do_LCD(0x6E);
  Wyslij_do_LCD(0x57);
  Wyslij_do_LCD(0x72);
  Wyslij_do_LCD(0x28);
  Wyslij_do_LCD(0x0F); /*Display on, cursor on, blink on*/
  CzyscLCD();
RS = 1 ; /*przelacz na rejestr danych*/  
        
 /*Koniec inicjalizacji i ustawien wyswietlacza DOGM204*/      
}

void WyswietlLCD(char *napis)
{
    while(*napis){
    Wyslij_do_LCD(*napis++);
    }
         
}
// wyslanie liczby dziesietnej
    void lcd_int(uint16_t val)
    {
    char bufor[17];
    sprintf(bufor,"%i",val);
    WyswietlLCD(bufor);
    }

void UstawKursorLCD(uint8_t y, uint8_t x)
{
    uint8_t n ;
    /*y (wiersze) = 1 do 4*/
    /*x (kolumna) = 1 do 20*/
    /*ustal adres poczatku znaku w wierszu*/
    switch(y)
    {
        case 1: y = LCD_Line1 ;break;
        case 2: y = LCD_Line2 ;break;
        case 3: y = LCD_Line3 ;break;
        case 4: y = LCD_Line4 ;break;
    
    }
    /*ustal nowy adres pami?ci DD RAM*/
    /*ustaw bajt do Set DDRAM adres*/
    /* x odejmujemy jeden aby przekonwertowa? z 0-19 na 1-20 */
    n = 0b10000000 + y + (x-1) ;
    
    /*wy?lij rozkaz ustawienia nowego adresu DD RAM*/
    RS = 0/*stan niski na lini? RS, wybieramy rejestr instrukcji*/
    Wyslij_do_LCD(n);
    RS = 1;  /*przelacz na rejestr danych */ 
}

void CzyscLCD()
{
    RS = 0/*przelacz na rejestr rozkazow*/
    Wyslij_do_LCD(1);
    RS = 1/*przelacz na rejestr danych*/
    __delay_us(1);

void WpiszSwojeZnaki(void) {
    /*definicja wlasnych znaków maks 8 szt*/
    char znak1[]= {0,0,14,17,31,16,14,2}; /* definicja literki e z ogonkiem */
    int i; 
    /* adresy poczatku definicji znaku to wielokrotnosc osmiu DEC(0,8,16,24,32,40,48,56)
     * ale uwaga wazne ! adresy kodowane sa na 6 mlodszych bitach dwa najstarsze bity
     * to zawsze  01 (01AAAAAA-gdzie A adres).Uwzgledniajac wartosc calego bajtu
     * adresy poczatku beda wygladal tak HEX(0x40,0x48,0x50,0x58,0x60,0x68,0x70,0x78)
     * Aby wpisac do pamieci wyswietlacza zdefiniowany znak nalezy najpierw wyslac 
     * do rejestru rozkazów (RS na 0) adres poczatku definicji znaku 
     * a w drugim kroku przesylamy dane (RS=1) 8 x bajt (tablica) definjujace obraz znaku*/
    
    RS = 0 ;/*stan niski na linii RS, wybieramy rejestr instrukcji*/
     /*wysylamy instrukcje do rejestru rozkazow (ustaw adres poczatkowy w CGRAM 
      na nasz znak w tym przypadku znak na pozycji drugiej) */
    Wyslij_do_LCD(0x48);/*wysylamy instrukcje do rejestru rozkazow 
     (ustaw adres poczatkowy w CGRAM na nasz znak w tym przypadku znak na pozycji drugiej) */
    
    RS = 1 ;/*stan wysoki na linii RS, wybieramy rejestr danych*/
    /*wysylamy 8 x bajt zdefiniowanego w tablicy znak1[] znaku*/
    for(i=0;i<=7;i++)
    {
       Wyslij_do_LCD(znak1[i]);
    }
   
    RS = 0 ;/*stan niski na lini RS, wybieramy rejestr instrukcji*/
    /*ustawiamy adres DDRAM na pierwszy znak w pierwszej linii, nie zapomnijmy
     o tym poniewaz inaczej zostaniemy w pamieci CGRAM*/
    Wyslij_do_LCD(0x80);
    RS = 1 ; /*stan wysoki na linii RS, wybieramy rejestr danych*/



/*****************************************************************************
  FileName:        ds18b20.c
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
******************************************************************************/


#include "xc.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> /*dyrektywy uint8_t itp*/
#include <string.h>
#include "ustaw_zegar.h" /*tutaj m.in ustawione FCY*/
#include <libpic30.h> /*dostep do delay-i,musi byc po zaincludowaniu ustaw_zegar.h*/
#include "dogm204.h"
#include "ds18b20.h"
#include "onewire.h"

int DStemp ;            /*split LSB + MSB*/
int DStemp_Znak ;       /*tutaj badamy znak temperatury*/
int DStemp_Calkowita ; 
int DStemp_Ulamek ; 
char test_czujnika ;    /*czy jest czujnik*/
void Selektor(int liczba) {
    /*wybieramy aktualny numer pinu*/
    switch (liczba) {
        case czujnik_1 :
            nr_pinu = czujnik_1 ;
            break ;
        case czujnik_2 :
            nr_pinu = czujnik_2 ;
            break ;
        }
    
}
/*Convert temperature*/
void ConvertT(int liczba) {
  /*wybieramy aktualny numer pinu*/  
  Selektor(liczba) ;
  onewireInit();
  onewireWriteByte(0xCC); /*skip ROM*/
  onewireWriteByte(0x44); /*CONVERT Temp*/
    
  PinDirectionSetOut ;    
  SET_parasite ;
 }

/*retrieve temperatures from sensors*/
void temperatura(int liczba)    
    {
    unsigned char sprawdz ;
    char temp1 = 0, temp2 = 0 ;
    
    Selektor(liczba) ;
    
    CLEAR_parasite ;
    sprawdz = onewireInit() ;         /*impuls resetu*/
    if (sprawdz == 1)
    {                   
        onewireInit() ;               /*impuls resetu*/
        onewireWriteByte(0xCC) ;      /*skip ROM*/
        onewireWriteByte(0xBE) ;      /*READ SCRATCHPAD*/
        
        temp1 = onewireReadByte() ;   /*odczytanie LSB*/
        temp2 = onewireReadByte() ;   /*odczytanie MSB*/

        onewireInit() ;               /*impuls resetu*/

        DStemp = (temp2<<8) | temp1 ; /*split LSB and MSB*/
        DStemp_Znak = temp2 >> 7 ;    /*znak temperatury*/
        
        if (DStemp_Znak) {
            DStemp = ~DStemp + 1/*wyciagamy wartosc bezwgledna z liczby ujemnej w kodzie U2*/
        }
        DStemp_Calkowita = (int) ((DStemp >> 4) & 0x7F); /*przesuwamy o 4 bity i maskujemy*/
        DStemp_Ulamek = (int) (((DStemp & 0xF) * 625) / 1000); /*jedna cyfra po przecinku, jesli chcemy 2 cyfry do dzielimy przez 100*/
      
        test_czujnika = 1/*czujnik jest OK*/
        }
        else {test_czujnika = 0;} /*brak czujnika lub jakis problem*/
    }
/*****************************************************************************
  FileName:        onewire.c
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
******************************************************************************/

#include "xc.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> /*dyrektywy uint8_t itp*/
#include <string.h>
#include "ustaw_zegar.h" /*tutaj m.in ustawione FCY*/
#include <libpic30.h> /*dostep do delay-i,musi byc po zaincludowaniu ustaw_zegar.h*/
#include "onewire.h"

int nr_pinu;

void onewireWriteBit(int b) {
  b = b & 0x01;
  if (b) {
    /*Write '1' bit*/
    PinDirectionSetOut ;     /*Direction set 0*/
    PinSetLow ;              /*Pin set 0*/  
    __delay_us(5);
    PinDirectionSetIn ;      /*Direction set 1*/
    __delay_us(60);
  } else {
    /*Write '0' bit*/
    PinDirectionSetOut ;     /*Direction set 0*/
    PinSetLow ;              /*Pin set 0*/    
    __delay_us(70);
    PinDirectionSetIn ;      /*Direction set 1*/
    __delay_us(2);
  }
}

unsigned char onewireReadBit() {
  unsigned char result;
  PinDirectionSetOut ;     /*Direction set 0*/
  PinSetLow ;              /*Pin set 0*/
  __delay_us(1);
  PinDirectionSetIn ;      /*Direction set 1*/
  __delay_us(5);
  TestBit ? (result=1) : (result=0) ; /*nr_pinu is set 1 ?*/
  __delay_us(55);
  return result;

}

unsigned char onewireInit() {
  PinDirectionSetOut ;     /*Direction set 0*/
  PinSetLow ;              /*Pin set 0*/
  __delay_us(480);
   PinDirectionSetIn ;      /*Direction set 1*/
  __delay_us(60);
   if(!(TestBit)) {/*nr_pinu is set 0 ?*/
      __delay_us(100);
      return 1;
  }
  return 0;
}

unsigned char onewireReadByte() {
  unsigned char result = 0;
  unsigned char loop ;
  for (loop = 0; loop < 8; loop++) {
    /*shift the result to get it ready for the next bit*/
    result >>= 1;

    /*if result is one, then set MS bit*/
    if (onewireReadBit())
      result |= 0x80;
  }
  return result;
}

void onewireWriteByte(char data) {
  unsigned char loop ;
    /*Loop to write each bit in the byte, LS-bit first*/
  for (loop = 0; loop < 8; loop++) {
    onewireWriteBit(data & 0x01);

    /*shift the data byte for the next bit*/
    data >>= 1;
  }
}
/*****************************************************************************
  FileName:        ustaw_zegar.c
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
 *****************************************************************************/
    /*Ustawiamy zegar wewnetrzny na ok 40 MHz (dokladnie na 39.61375 MHz*/
    #include "xc.h" /* wykrywa rodzaj procka i includuje odpowiedni plik 
    naglówkowy "p24HJ128GP502.h"*/
    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h> /*dyrektywy do uint8_t itp*/
    #include "ustaw_zegar.h" /*z uwagi na FCY musi byc przed #include <libpic30.h>*/

    /*definicja funkcji*/
    void ustaw_zegar(void) {
    /*
    * to co mozemy ustawic za pomoca '#pragma' jest dostepne w pliku 
    * xc16/docs/config_index.html
    */
    #pragma config JTAGEN = OFF
    // Watchdog timer enable/disable by user software
    #pragma config FWDTEN = OFF 

    //********************Start Ustawien Zegara************************
    /* 
    * Fcy - zegar instrukcji , Fosc - zegar rdzenia (jest zawsze dwa razy wiekszy 
    * od zegara instrukcji)) Ustawiamy zegar instrukcji na 40 Mhz z wewnetrznego 
    * oscylatora Fin=7.37 MHz w/g wzoru Fcy=Fosc/2 gdzie Fosc=Fin x (M/(N1+N2))
    * gdzie M=43, N2=2, N1=2 ustawiane w rejestrach PLLFBD/PLLPOST/PLLPRE
    */
    //Select Internal FRC (Fast RC Oscillator)
    #pragma config FNOSC = FRC // FOSCSEL-->FNOSC=0b000 (Fast RC Oscillator (FRC))
    //Enable Clock Switching and Configure
    #pragma config FCKSM = CSECMD //FOSC-->FCKSM=0b01 - wlacz zegar
    #pragma config OSCIOFNC = OFF //FOSC-->OSCIOFNC=1 - Fcy b?dzie na pinie OSCO

    /*Config PLL prescaler, PLL postscaler, PLL divisor*/
    PLLFBD = 41 ; //M=43 (0 bit to 2 st?d 41 = 43 patrz w rejestrze), tutaj 3.685 x 43 = 158.455MHz
    CLKDIVbits.PLLPRE=0 ;  //N1=2, tutaj 7.37 MHz / 2 = 3.685 MHz
    CLKDIVbits.PLLPOST=0 ; //N2=2, tutaj 158.455 MHz / 2 = 79.2275 MHz (Fosc)
    /*   
    * UWAGA przerwania musza byc wylaczone podczas wywolywania ponizszych 
    * dwóch funkcji __builtin_write_...brak definicji w pliku naglówkowym
    * to wewnetrzne funkcje kompilatora patrz help M-LAB IDE
    * i datasheet str 140(11.6.3.1 Control Register Lock)
    */
    /*Initiate Clock Switch to Internal FRC with PLL (OSCCON-->NOSC = 0b001)*/
      __builtin_write_OSCCONH(0x01); //tutaj argumentem jest wartosc z NOSC
    /*Start clock switching*/
      __builtin_write_OSCCONL(0x01);

    /*Wait for Clock switch to occur*/
      while(OSCCONbits.COSC !=0b001);

      /*Wait for PLL to lock*/
      while(OSCCONbits.LOCK !=1) {};

    }
/*****************************************************************************
  FileName:        main.c
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
******************************************************************************/

#include "xc.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h> /*dyrektywy uint8_t itp*/
#include <string.h>
#include "ustaw_zegar.h" /*tutaj m.in ustawione FCY*/
#include <libpic30.h> /*dostep do delay-i,musi byc po zaincludowaniu ustaw_zegar.h*/
#include "dogm204.h"
#include "ds18b20.h"
#include "onewire.h"

/*******************************************************************************
 DEKLARACJE FUNKCJI
 ******************************************************************************/
void InitTimer1(void);
/*******************************************************************************
 DEKLARACJE/DEFINICJE ZMIENNYCH
 ******************************************************************************/
/*Timery Programowe*/
volatile uint8_t Timer1_Programowy , Timer2_Programowy ;
uint8_t licznik ;
/*powolujemy dwa obiekty typu struktura do przechowywania danych o temperaturze z dwóch czujnikow*/
TEMPERATURA temperatura1 ;
TEMPERATURA temperatura2 ;

int main(void) {
    ustaw_zegar(); /*odpalamy zegar wewnetrzny na ok 40MHz*/
    __delay_ms(50) ; /*stabilizacja napiec*/
    /*
    * wylaczamy ADC , wszystkie piny chcemy miec cyfrowe
    * pojedynczo piny analogowe wylaczamy w rejestrze AD1PCFGL 
    * Po resecie procka piny oznaczone ANx sa w trybie analogowych wejsc.
    */
      PMD1bits.AD1MD=1 ; /*wylaczamy ADC*/
      /* 
       * ustawiamy wszystkie piny analogowe (oznacznone ANx) jako cyfrowe
       * do zmiany mamy piny AN0-AN5 i AN9-AN12 co daje hex na 16 bitach = 0x1E3F
       */
    AD1PCFGL = 0x1E3F ;
    InitTimer1(); /*Timer 1 Init*/
    WlaczLCD();   /*LCD Init*/
    licznik = 0;  
    /*Petla glowna programu*/
    while (1) {
         /*co 1 sekunde wykonaj czynnosc*/
            if(!Timer1_Programowy) {
             Timer1_Programowy = 10 ; /*Timer1 sprzetowy x Timer1_Programowy = 100ms x 10 = 1 s*/
             
             if(licznik > 3) licznik = 0/*mamy 4 procesy od 0 do 3, po zakonczonej sekwencji procesow zerujemy licznik*/
            
            /*za pomoca operacji modulo sterujemy czterema procesami, kazdy niezaleznie wykonuje sie co 1 sekunde*/
            /*w kazdej pierwszej sekundzie inicjujemy konwersje w czujnikach DS18B20*/
            if(0 == licznik%4) {
             ConvertT(czujnik_1);
             ConvertT(czujnik_2);}
           
          
/*w kazdej drugiej sekundzie odczytujemy z DS18B20 temperature z czujnika nr 1
             i zapamietujemy ja w strukturze temperatura1*/
            if(1 == licznik%4) {
             /*zerujemy dane*/
             DStemp_Calkowita = 0;
             DStemp_Ulamek = 0;
             temperatura(czujnik_1); /*pobieramy temperature dla czujnika nr 1*/
             /*przepisujemy dane do struktury odpowiedzialnej za czujnik nr 1*/
             temperatura1.sign_temp = DStemp_Znak ;
             temperatura1.total_temp = DStemp_Calkowita;
             temperatura1.fraction_temp = DStemp_Ulamek ;
             temperatura1.test_czujnika = test_czujnika ;}
            /*w kazdej trzeciej sekundzie odczytujemy z DS18B20 temperature z czujnika nr 2
            i zapamietujemy ja w strukturze temperatura2*/
            if(2 == licznik%4) {
             /*zerujemy dane*/
             DStemp_Calkowita = 0;
             DStemp_Ulamek = 0;
             temperatura(czujnik_2); /*pobieramy temperature dla czujnika nr 2*/
            /*przepisujemy dane do struktury odpowiedzialnej za czujnik nr 2*/
             temperatura2.sign_temp = DStemp_Znak ;
             temperatura2.total_temp = DStemp_Calkowita;
             temperatura2.fraction_temp = DStemp_Ulamek ;
             temperatura2.test_czujnika = test_czujnika ;}
             /*w kazdej czwartej sekundzie wyswietlamy dane zapamietane w strukturach*/
            if(3 == licznik%4) {
             /*wyswietlamy temperature z czujnika nr 1*/
             UstawKursorLCD(1,1);
             WyswietlLCD("Czujnik 1: ");
             if(temperatura1.test_czujnika) {/*wykonaj jesli jest czujnik*/
             (temperatura1.sign_temp == 0) ? WyswietlLCD("+") : WyswietlLCD("-");
             lcd_int(temperatura1.total_temp);
             Wyslij_do_LCD(44); /*przecinek*/
             lcd_int(temperatura1.fraction_temp);
              }
             else {WyswietlLCD(" ____");} /*jesli problem z czujnikiem*/
             /*wyswietlamy temperature z czujnika nr 2*/  
             UstawKursorLCD(2,1);
             WyswietlLCD("Czujnik 2: ");
             if(temperatura2.test_czujnika) {/*wykonaj jesli jest czujnik*/
             (temperatura2.sign_temp == 0) ? WyswietlLCD("+") : WyswietlLCD("-");
             lcd_int(temperatura2.total_temp);
             Wyslij_do_LCD(44); /*przecinek*/
             lcd_int(temperatura2.fraction_temp);
                }
             else {WyswietlLCD(" ____");} /*jesli problem z czujnikiem*/
             }
             licznik++ ;  /*licznik na potrzeby wyliczania modulo*/
        }
   }
}

/*Inicjacja/konfiguracja Timera1*/
void InitTimer1(void){
    /*konfiguracja Timer1*/
    T1CONbits.TON = 0 ; /*Stop the timer1*/
    TMR1 = 0x0000 ;/*Clear timer register*/
    /*Zegar ok 40 MHz Prescaler 1:64; PR1 Preload = 61897; Actual Interrupt Time = 100 ms*/
    T1CONbits.TCKPS = 0b10 ; /*Prescaler 1:64*/
   
    /*konfiguracja przerwa?*/
    IFS0bits.T1IF    = 0/*Clear Timer1 Interrupt Flag*/
    IEC0bits.T1IE    = 1/*Enable Timer1 Interrupt*/
    
    /*ustaw priorytet dla przerwania*/
    IPC0bits.T1IP = 0b100 ; /*Set Timer1 Interrupt Prioryty Level 4*/

/*TMR1 zlicza do wartosci ustawionej w PR1 jesli TMR1=PR1 zglaszane jest przerwanie*/
/*40MHz / Prescaler / PR1 = ok 10 Hz (100ms)*/    
    PR1      = 61897/*Load period value*/
    T1CONbits.TON = 1 ; /*Start the timer1*/    
}

/*Obsluga wektora przerwania dla Timer1*/
void __attribute__((interrupt, no_auto_psv))_T1Interrupt(void)
{
/*kod uzytkownika do obslugi przerwania*/
    uint8_t x;
    x = Timer1_Programowy ;
    if (x) Timer1_Programowy = --x ;
    x = Timer2_Programowy ;
    if (x) Timer2_Programowy = --x ;

    /* Clear Timer1 interrupt */
IFS0bits.T1IF = 0 ; /*Clear Timer1 Interrupt Flag*/
}

2 komentarze:

  1. Czy wyświetlacz nie powinien mieć podpiętego VDD do +3,3V?

    OdpowiedzUsuń