piątek, 22 września 2017

MCP3424 + MCP9700A - zabawa z przetwornikiem 18-bitowym.


Zapowiadałem we wpisie o MCP3424, że wezmę się za niego w praktyce. Brakowało mi tylko natchnienia z czym to przetestować. Myślałem na początku , może z popularnym czujnikiem analogowym LM35 ale tutaj zong, czujnik ten działa od 4V czyli elastyki napięciowej nie reprezentuje sobą żadnej.
Problemem z tymi czujnikami jest po za tym uzyskanie temperatur ujemnych, trzeba dodatkowo stosować diody krzemowe w obwodzie. Sięgnąłem zatem w przestworza oferty Microchipa i tutaj miła niespodzianka w postaci MCP9700A.


Nie dość , że MCP9700A jest 2 razy tańszy od LM35 to bije go w kilku punktach, m.in do uzyskania temperatur ujemnych nie trzeba żadnych dodatkowych elementów i nie trzeba angażować dwóch kanałów ADC.

MCP9700A zakupiłem w obudowę TO92 czyli w takiej jak DS18B20.
Garść informacji potrzebnych do działania z  MCP9700A (ta literka A jest istotna) :
- zakres mierzonych temperatur -40 do +125 ( w innych obudowach -40 do +150)
- napięcie zasilania od 2,3 do 5.5V
- skok 10mV na 1stC
- 0 stC daje 500mV na wyjściu
- zakres graniczny napięć Vout : 100mV (dla -40stC) do 1,75V (dla +125stC)

Wzorek na napięcie wyjściowe Vout dla czujnika MCP9700A :


np 

dla +25 stC   Vout wynosi = 10mV x 25 + 500mV = 750mV

dla -40 stC  Vout wynosi =  10mV x (-40) + 500mV= 100mV

Jak widzimy napięcie Vout dla MCP9700A wylicza się prosto i przyjemnie.
A poniżej wykres z całym dostępnym zakresem zależności Vout od temperatury.




Przejdźmy zatem do przetwornika MCP3424. Tutaj będzie trochę więcej zabawy z wzorkami.
Najpierw musimy przyjać z jaką rodzielczością ADC będziemy działać. Do wyboru mamy 12 , 14 , 16 , 18 bitów (ustawiane w rejestrze konfiguracyjnym przetwornika) . Z racji tego , że działam na mikrokontrolerze 16-bitowym PIC dlatego cyfra 16 jest dla mnie wyborem optymalnym :)

Musimy wiedzieć o jednej ważnej żeczy dotyczącej przetwornika MCP3424, z racji tego , że przetwornik ten ma możliwość przetwarzania napięć ujemnych i dodatnich równocześnie na kanale ,dlatego ma nóżki oznaczone CH1+ i CH1-. To implikuje fakt, że w próbce ADC musi zmieścić się informacja o znaku. W efekcie tracimy jeden bit, jeśli wybranym trybem ADC jest 16 bitów to w efekcie mam 15 bitów dane (LSB) + 1 bit znak (MSB). Bit znaku jest najstarszym bitem.
Czy jesteśmy z tego powodu bardzo źli ?? ano biorąc pod uwagę , że jednak jest do dyspozycji możliwość określania znaku w mierzonym sygnale i że tracimy na tę opcję 1 bit to ja myślę, że psów na tym przetworniku nie będziemy wieszać.

Na początek zobrazujmy sobie prostym wzorkiem jaką zmianę uzyskamy za pomocą 1 ADC. Czyli krótko mówiąc jeśli z przetwornika odczytamy wartość 1 (ADC) to jaki to będzie reprezentować krok napięcia.

Wzorek :

LSB (wartość danych z przetwornika bez bitu znaku) :
MSB - bit znaku (we wzorku nie będzie ale miejmy pojęcie bo tak w datasheet jest to oznaczane)

LSB = Vref / (2 do potęgi (n-1)) 

gdzie n wybrana rodzielczość przetwornika, w naszym przypadku 16.
a Vref to napięcie referencyjne do którego przetwornik odnosi swoje działanie w przypadku MCP3424 jest to napięcie 2048 mV (takie jest na pokładzie).

stąd :
LSB = 2048 / (2 do potęgi (16-1)) = 0,0625 V = 62,5 uV.

Taka wartość dla 1 ADC umożliwi nam odczyt temperatury z dokładnością do setnej części, ponieważ schodzimy poniżej 1 mV który reprezentuje w MCP9700A zmianę temperatury o 0,1. Jaki jest sens odczytywać setne części temperatury no nie wiem ale cieszy taka możliwość :)

Warto jeszcze nadmienić, że tamdem MCP9700A + MCP3424 góruje czasem konwersji temperatury nad czujnikim cyfrowym DS18B20. Pamietamy , że w czujniku cyfrowym dla konwersji 12 bitowej potrzeba było aż 750 ms zwłoki.
W naszym przypadku dla 16 bitów czas konwersji to ok 60 ms. Czyli ponad 10 razy szybciej uzyskujemy dane o temperaturze niż w DS18B20.
Tam gdzie krytycznym parametrem jest czas to nasz tandem nie ma sobie równych, no może i ma ale moja wiedza jest na ten temat ograniczona :).

Dobra wracamy do wzorków na podstawie , których chcemy się dogrzebać do wyliczenia temperatury na podstawie odczytanej wartości z przetwornika.
Zatem lećmy po zależnościach jakie nam się uda dostrzec :

Vref = Zakres ADC
Vout = X

gdzie

Vref - 2,048 V (napięcie referencyjne zaszyte w MCP3424)
Zakres ADC- 32767 (15 bitów uwzględniając 1 bit na znak)
Vout - napięcie na wyjściu czujnika MCP9700A
X - ADC odczytane z przetwornika

stąd

X = (Vout x 32767) / 2,048V  
a
Vout = (X x 2,048V) /  32767  ***

ufff ta matematyka widać teraz po co trzeba było jej się uczyć :)

z datasheetu znamy inny wzór na Vout mianowicie :

Vout = Tc x Ta + V0stC

gdzie

Tc - współczynnik temperaturowy czyli te 10 mV(0,01V)  dającą zmianę  o 1 stC
Ta - temperatura mierzona
V0stC - to 500mV(0,5V) dla 0 stC

z powyższego wzoru drogą przekształceń otrzymamy :

Ta = (Vout - 0,5V) / 0,01V

za Vout podstawmy nasze wypociny oznaczone *** powyżej i otrzymujemyw efekcie końcowym drogą przekształceń matematycznych ostateczny wzorek na temperaturę mierzoną :

Ta = (100 x (X x 32767) - 50) = (X x 204.8) / 32767) - 50

Teraz trzeba chwilę zastanowić jak to będzie wyglądało w praktyce. Załóżmy, że wartość odczytana z przetwornika będzie trafiała do zmiennej wynik_ADC. Wtedy aby otrzymać z tej danej temperaturę musimy zrobić trzy kroki :

wynik_ADC = wynik_ADC x 204.8

wynik_ADC = wynik_ADC / 32767

wynik_ADC = wynik_ADC - 50

Powyższe operacje trzeba będzie robić na zmiennych typu float i bardzo dobrze bo po wuja mamy tak mocny procek aby bidolić , że float jest be.


Teraz nadeszła wiekopomna chwila aby zbudować zestaw testowy na razie zmajstrowałem tylko schemat. Warto nadmienić ,że schemat jest zrobiony za pomocą EasyEDA . Polubiłem te bajecznie prostą aplikację webową, Eagle'a to mi się nawet już nie chce odpalać.



Zestaw testowy składać się będzie z :

- mikrokontroler 16 bitowy PIC 24HJ128GP502 (pracujący na 40 MHz z zegarem wewnętrznym czyli bez zewnętrznęgo kwarca)
- MCP9700A w obudowie TO92
- MCP3424 w obudowie SOIC (potrzebujemy płytki konwertera z SOIC14 na DIP14)
- DOGM204A wyświetlacz LCD 4x20 (mój ulubiony m.in z racji mega szybkości, subtelnego wyglądu i pięknego oświetlenia nie walącego po ślipiach)
- zasilacz +3.3V



Sama część sprzętowa nie była przyczynkiem  problemów no po zatym , że baran ze mnie i zapomniałem dać na linię I2C rezystorów podciagających. Problem z komunikacją wykryła mi obsługa błędów I2C zaimplementowana przy wykorzystaniu Timera2 i diody LED.

Najważniejsze elementy programu to :

- właściwa sekwencja zapisu do rejestru MCP3424
- właściwa sekwencja odczytu danych z MCP3424
- gimnastyka z konwersją danych celem przekazania ich do wyświetlacza LCD.

Pobieranie danych z przetwornika ustaliłem na 70 ms (1000 / 15(SPS) = 66ms) .
Dane nie potrzebujemy tak szybko wyświetlać  dlatego czas odświeżania na LCD przyjąłem sobie na 700ms. Do odmierzania podstawy czasu (10ms) użyłem Timer1 (16 bitowy) a do tykania wewnątrz pętli głównej programu użyłem timera programowego.
Nie zaimplementowałem w programie wykrywanie znaku temperatury ale jest to trywialnie proste, dla trybu 16 bit należy wykryć wskazania ADC poniżej 8000 (jeśli dobrze policzyłem) i wyświetlić wtedy znak "-".

Przetwornik za pomocą odpowiedniego wpisu do rejestru ustawiłem na pracę ciągłą , dane z kanału nr 1, tryb 16 bit (15SPS), wzmocnienie na 1.





Wszystko pięknie działa, przetwornik MCP3424 zdał egzamin w boju. Co do MCP9700A mam jedną uwagę mianowicie wskazania temperatury były ok +1 stC za wysokie czyli czujnik jest optymistą :), można to jednak skorygować w prosty sposób.

Kolejny projekcik zaliczony . Z dużą lekkością robi się te projekciki przy użyciu mikrokontrolerów 16-bitowych PIC. Jest to czysta przyjemność.

Ostatnio zacząłem się rozglądać z ciekawości za 32-bitowcami Microchipa w tym celu zamówiłem potężny i mocny mikrokontroler PIC32MZEF  (wydajność aż 330 DMPIS) można by rzec zabójca ARM-ów. Ale ARM-om chwały nie ujmujemy. Czekam na dostawę , najwyżej sobie go na ścianę powieszę :).


Pozdrawiam
picmajster.blog@gmail.com


Linki :
MCP9700A - datasheet
MCP3424 - datasheet
Projekt na GitHub

Pliki projektu :

dogm204.h     - plik deklaracji dla wyświetlacza firmy EA model DOGM204-A (4x20)
i2c.h         - plik deklaracji dla obsługi i2c
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)
i2c.c         - plik definicji dla obsługi i2c
ustaw_zegar.c - plik definicji dla obsługi i konfiguracji zegara wewnętrznego ok 40 MHz.
main.c        - główny plik programu

/*****************************************************************************
  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:        i2c.h
  Processor:       PIC24HJ128GP502
  Compiler:        XC16 ver 1.30
******************************************************************************/

#ifndef I2C_H
#define I2C_H
extern uint8_t error_flag ;
/*deklaracja funkcji*/
void ustaw_I2C1(void);  /*Init the I2C module*/
void i2c_start(void);   /*generates an I2C Start condition*/
void i2c_restart(void); /*generates an I2C Restart condition (for reads)*/
void i2c_stop(void);    /*generates an I2C Stop condition*/
void i2c_write(unsigned char i2c_data); /*writes a byte to the I2C bus*/
unsigned char i2c_read(void);    /*reads a byte from the I2C bus*/
void i2c_ack(void);     /*generates a Master Acknowledge*/
void i2c_nack(void);    /*generates a Master No Acknowledge*/
void obsluga_error(void);
void i2c_write_bufuint8_t adr_device, uint8_t adr, uint8_t len, uint8_t *buf);
void i2c_read_buf(uint8_t adr_device, uint8_t adr, uint8_t len, uint8_t *buf);
/*dedykowana obsluga EEPROM*/
void EEPROM_sequential_read_buf(uint8_t adr_device, uint16_t subAddr, uint16_t len, char *buf);
void EEPROM_write_buf(uint8_t adr_device, uint16_t subAddr,  uint16_t len, char *buf);
void EEPROM_write_buf_page_write(uint8_t adr_device, uint8_t numer_strony, uint8_t numer_komorki, uint16_t len, char *buf);
/*dedykowana obsluga EERAM*/
void EERAM_write_STATUS_REGISTER(uint8_t adr_device, uint16_t subAddr,  unsigned char i2c_data);
void EERAM_write_buf(uint8_t adr_device, uint16_t subAddr,  uint16_t len, char *buf);
void EERAM_write_byte(uint8_t adr_device, uint16_t subAddr,  unsigned char i2c_data);
unsigned char EERAM_read_byte(uint8_t adr_device, uint16_t subAddr);
/*zapis i odczyt struktur*/
void EERAM_write_structure(uint8_t adr_device, uint16_t subAddr,  uint16_t len, void *struktura);
void EERAM_sequential_read_structure(uint8_t adr_device, uint16_t subAddr, uint16_t len, void *struktura);
#endif  /* I2C_H */
/*****************************************************************************
  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 */

#define CGRAM_SET 0x40
 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);
 void DefineCharacter(int8_t nr, char *znak);
#endif  /* DOGM204_H */


/*****************************************************************************
  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:        i2c.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> /*biblioteka dajaca dostep do delay-i,musi byc po zaincludowaniu ustaw_zegar.h*/
#include "i2c.h"

uint8_t error_flag ;
/*definicje funkcji*/
void ustaw_I2C1(void){
    /*pin 17(SCL) i 18(SDA) sa cyfrowe na starcie, nie trzeba tutaj wylaczac wejsc analogowych*/
    I2C1BRG = 391 ; /*przy FCY ok 40 MHz dla bitrate 100 kHz I2C1BRG = 391 dla 400 kHz I2C1BRG=91*/
    I2C1STAT = 0x0000/*Status Register - pasuje wszystko na zero */
    I2C1CON = 0x1200/*Control Register - Relase SCL clock / Slew rate control disabled / 7-bit slave address*/ 
    /*zerujemy rejestr nadawczy i odbiorczy*/
    I2C1RCV = 0;
    I2C1TRN = 0;
    /*Enable I2C1 module*/
    I2C1CONbits.I2CEN = 1;
    
}

void obsluga_error(void){
    /*Timer2 zlicza przez ok 13 ms przy FCY 40MHz*/
    TMR2 =0/*clear Timer1*/
    IFS0bits.T2IF=0 ; /*zeruj flage od przepelnienia Timer1*/
    T2CONbits.TCKPS = 0b01 ; /*Prescaler 1:8 , daje nam 5 MHz*/
    T2CONbits.TON=1;    /*start Timer1*/
    /*czekaj na flage MI2C1IF po zakonczeniu poprawnie dowolnej operacji przez Mastera na I2c
      lub na przepelnienie Timer1 czyli ok 13ms*/ 
    while(!(IFS1bits.MI2C1IF | IFS0bits.T2IF ));  
    if(IFS0bits.T2IF){ /*jesli Timer1 przepelniony*/
        IFS0bits.T2IF=0 ; /*zeruj flage od przepelnienia Timer1*/
        IFS1bits.MI2C1IF=0/*clear the I2C general flag*/
        error_flag = 1/*set the error flag*/
        PORTAbits.RA1 = 1 ; /*LED ON*/
        /*tutaj kod uzytkownika do obslugi bledu, np zapalenie diody LED etc*/
    }
    else {error_flag = 0/*clear the error flag*/
        IFS1bits.MI2C1IF=0/*clear the I2C general flag*/
        PORTAbits.RA1 = 0/*LED OFF*/
    }
    T2CONbits.TON=0/*stop Timer1*/
    TMR2 =0/*clear Timer1*/
}


void i2c_start(void){
   while(I2C1STATbits.TRSTAT); /*czekaj az linia bedzie wolna */
   I2C1CONbits.SEN = 1;        /*generuj sygnal start*/
   obsluga_error();            
}

void i2c_restart(void){
    while(I2C1STATbits.TRSTAT); /*czekaj az linia bedzie wolna */
    I2C1CONbits.RSEN=1/*generuj restart*/
    obsluga_error();  
}

void i2c_stop(void){
    while(I2C1STATbits.TRSTAT); /*czekaj az linia bedzie wolna */
    I2C1CONbits.PEN=1/*generuj stop*/
    obsluga_error();  
}

void i2c_write(unsigned char i2c_data){
    while(I2C1STATbits.TRSTAT); /*czekaj az linia bedzie wolna */
    I2C1TRN=i2c_data; /*load byte in the transmiter buffer*/
    obsluga_error();
}

unsigned char i2c_read(void){
    while(I2C1STATbits.TRSTAT); /*czekaj az linia bedzie wolna */
    I2C1CONbits.RCEN=1/*enable Master receive*/
    obsluga_error();
    return(I2C1RCV); /*return data in buffer*/
}

void i2c_ack(void){
    I2C1CONbits.ACKDT=0/*clear the related flag for ACK*/
    I2C1CONbits.ACKEN=1/*start ACK sequence*/
    obsluga_error();
}

void i2c_nack(void){
    I2C1CONbits.ACKDT=1/*set the related flag for NotACK*/
    I2C1CONbits.ACKEN=1/*start ACK sequence*/
    obsluga_error();
    I2C1CONbits.ACKDT=0/*clear the related flag for ACK*/
}

void i2c_write_bufuint8_t adr_device, uint8_t adr, uint8_t len, uint8_t *buf ) {
    i2c_start();
    i2c_write(adr_device); /*wyslanie adresu urzadzenia z bitem R/W w stanie niskim*/
    i2c_write(adr);
    while (len--) i2c_write(*buf++);
    i2c_stop();
}

void i2c_read_buf(uint8_t adr_device, uint8_t adr, uint8_t len, uint8_t *buf) {
    i2c_start();
    i2c_write(adr_device);/*wyslanie adresu urzadzenia z bitem R/W w stanie niskim*/
    i2c_write(adr);
    i2c_start();
    i2c_write(adr_device + 1);/*zapisuje adres urzadzenia z bitem R/W ustawionym na 1 czyli o 1 zwiekszamy adres urzadzenia*/
    while (len--){
     if(len) {
     *buf++ = i2c_read();
     i2c_ack();
        }
     else {
     *buf++ = i2c_read();
     i2c_nack();
         }
     }
    i2c_stop();
}
/*Funkcje dedykowane do obslugi pamieci EEPROM PIC 24LCxxx*/
/*odczyt sekwencyjny danych z pamieci EEPROM.*/
void EEPROM_sequential_read_buf(uint8_t adr_device, uint16_t subAddr, uint16_t len, char *buf) {

        i2c_start();
        i2c_write(adr_device); /*wyslanie adresu urzadzenia z bitem R/W w stanie niskim*/
        i2c_write((subAddr & 0xFF00) >> 8) ; /*wyslanie starszego bajtu adresu pamieci*/
        i2c_write(subAddr & 0x00FF)  ;       /*wyslanie mlodszego bajtu adresu pamieci*/
        i2c_start();
        i2c_write(adr_device + 1);/*zapisuje adres urzadzenia z bitem R/W ustawionym na 1 czyli o 1 zwiekszamy adres urzadzenia*/
        i2c_ack();
        while(len--)
        {
        *buf++ = i2c_read();
        i2c_ack();
        }
        i2c_nack();
        i2c_stop();
}

/*zapis danych do pamieci EEPROM w pojedynczych bajtach*/
void EEPROM_write_buf(uint8_t adr_device, uint16_t subAddr,  uint16_t len, char *buf) {

    while (len--) {
        i2c_start();
        i2c_write(adr_device); /*wyslanie bajtu adresu z bitem R/W ustawionym na zero*/
        i2c_write((subAddr & 0xFF00) >> 8);  /*wyslanie starszego bajtu adresu pamieci*/
        i2c_write(subAddr & 0x00FF);         /*wyslanie mlodszego bajtu adresu pamieci*/
        i2c_write(*buf++);
        i2c_stop();
        __delay_ms(5); /*oczekiwanie na zapis*/
        subAddr++;
    }
}

/*zapis danych do pamieci EEPROM w trybie PAGE WRITE czyli maksymalnie 128 bajty w obrembie jednej strony*/
void EEPROM_write_buf_page_write(uint8_t adr_device, uint8_t numer_strony, uint8_t numer_komorki, uint16_t len, char *buf) {
      uint16_t subAddr;
      /*subAddr sklada sie z :
        numer komorki to numer w obrebie jednej strony czyli od 0 do 127 
        numer strony to numer jednej z 512 stron od 0 do 511
        24LC512 ma 512 stron 128 bajtowych co lacznie daje 65536 bajtow*/
        i2c_start();
        i2c_write(adr_device); /*wyslanie bajtu adresu Slave z bitem R/W ustawionym na zero*/
        /*wyliczamy adres poczatku uwzgledniajac numer strony 0-511 i numer komorki na stronie 0-127*/
        subAddr = (numer_strony*128) + numer_komorki;
        
        i2c_write((subAddr & 0xFF00) >> 8);  /*wyslanie starszego bajtu adresu pamieci*/
        i2c_write(subAddr & 0x00FF);         /*wyslanie mlodszego bajtu adresu pamieci*/
        
        while (len--) {
        /*inkrementujemy tylko tablice z danymi,adres w obrebie strony 0-127 bajtow jest inkrementowany automatycznie przez eeprom*/
            i2c_write(*buf++); 
            }
        i2c_stop();
        __delay_ms(5); /*oczekiwanie na zapis*/
        }

/*Funkcje dedykowane do obslugi pamieci EERAM PIC 47L04 lub 47L16*/
/*zapis danych do rejestru pamieci EERAM*/
void EERAM_write_STATUS_REGISTER(uint8_t adr_device, uint16_t subAddr,  unsigned char i2c_data) {

        i2c_start();
        i2c_write(adr_device); /*wyslanie bajtu adresu z bitem R/W ustawionym na zero*/
        i2c_write((subAddr & 0xFF00) >> 8);  /*wyslanie starszego bajtu adresu pamieci*/
        i2c_write(subAddr & 0x00FF);         /*wyslanie mlodszego bajtu adresu pamieci*/
        i2c_write(i2c_data);
        i2c_stop();
    __delay_ms(1); /*oczekiwanie na zapis do STATUS REGISTER*/
}

/*zapis danych do pamieci EERAM - tryb sekwencyjny czyli ciag bajtow*/
    void EERAM_write_buf(uint8_t adr_device, uint16_t subAddr,  uint16_t len, char *buf) {
        i2c_start();
        i2c_write(adr_device); /*wyslanie bajtu adresu z bitem R/W ustawionym na zero*/
        i2c_write((subAddr & 0xFF00) >> 8);  /*wyslanie starszego bajtu adresu pamieci*/
        i2c_write(subAddr & 0x00FF);         /*wyslanie mlodszego bajtu adresu pamieci*/
        while (len--) {
        /*inkrementujemy tylko dane,adres jest inkrementowany automatycznie przez EERAM*/
            i2c_write(*buf++); 
            }
        i2c_stop();
     }
/*zapis danych do pamieci EERAM - tryb pojedynczego bajtu*/
void EERAM_write_byte(uint8_t adr_device, uint16_t subAddr,  unsigned char i2c_data) {
    
        i2c_start();
        i2c_write(adr_device); /*wyslanie bajtu adresu z bitem R/W ustawionym na zero*/
        i2c_write((subAddr & 0xFF00) >> 8);  /*wyslanie starszego bajtu adresu pamieci*/
        i2c_write(subAddr & 0x00FF);         /*wyslanie mlodszego bajtu adresu pamieci*/
        i2c_write(i2c_data);
        i2c_stop();
    }
/*odczyt jednego bajtu z pamieci EERAM.*/
unsigned char EERAM_read_byte(uint8_t adr_device, uint16_t subAddr) {
        unsigned char i2c_data;
        i2c_start();
        i2c_write(adr_device); /*wyslanie adresu urzadzenia z bitem R/W w stanie niskim*/
        i2c_write((subAddr & 0xFF00) >> 8) ; /*wyslanie starszego bajtu adresu pamieci*/
        i2c_write(subAddr & 0x00FF)  ;       /*wyslanie mlodszego bajtu adresu pamieci*/
        i2c_start();
        i2c_write(adr_device + 1);/*zapisuje adres urzadzenia z bitem R/W ustawionym na 1 czyli o 1 zwiekszamy adres urzadzenia*/
        i2c_ack();
        i2c_data = i2c_read();
        i2c_nack();
        i2c_stop();
        return(i2c_data);
}

 /*funkcje do zapisu i odczytu struktur*/
    /*zapis danych do pamieci EERAM - tryb sekwencyjny czyli ciag bajtow*/
    void EERAM_write_structure(uint8_t adr_device, uint16_t subAddr,  uint16_t len, void *struktura) {
        /*tworzymy wskaznik ktory wskazuje na pierwszy element struktury zrzutowanej do typu uint8_t*/
        uint8_t *wsk = (uint8_t*)struktura;
        i2c_start();
        i2c_write(adr_device); /*wyslanie bajtu adresu z bitem R/W ustawionym na zero*/
        i2c_write((subAddr & 0xFF00) >> 8);  /*wyslanie starszego bajtu adresu pamieci*/
        i2c_write(subAddr & 0x00FF);         /*wyslanie mlodszego bajtu adresu pamieci*/
        while (len--) {
        /*inkrementujemy tylko dane,adres jest inkrementowany automatycznie przez EERAM*/
            i2c_write(*wsk++); 
            }
        i2c_stop();
     }
    
    /*odczyt sekwencyjny danych z pamieci EERAM.*/
    void EERAM_sequential_read_structure(uint8_t adr_device, uint16_t subAddr, uint16_t len, void *struktura) {
        /*tworzymy wskaznik ktory wskazuje na pierwszy element struktury zrzutowanej do typu uint8_t*/
        uint8_t *wsk = (uint8_t*)struktura;
        i2c_start();
        i2c_write(adr_device); /*wyslanie adresu urzadzenia z bitem R/W w stanie niskim*/
        i2c_write((subAddr & 0xFF00) >> 8) ; /*wyslanie starszego bajtu adresu pamieci*/
        i2c_write(subAddr & 0x00FF)  ;       /*wyslanie mlodszego bajtu adresu pamieci*/
        i2c_start();
        i2c_write(adr_device + 1);/*zapisuje adres urzadzenia z bitem R/W ustawionym na 1 czyli o 1 zwiekszamy adres urzadzenia*/
        i2c_ack();
        while(len--) {
        /*inkrementujemy tylko dane,adres jest inkrementowany automatycznie przez EERAM*/
        *wsk++ = i2c_read();
        i2c_ack();
        }
        i2c_nack();
        i2c_stop();
    }
/*****************************************************************************
  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 pocz?tku 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;  /*prze??cz na rejestr danych */ 
}

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

/*funkcja definiuje jeden znak*/
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 */
    char znak1[]= {0x0C,0x12,0x12,0x0C,0,0,0,0};/*definicja stC*/
    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*/
}
/*funkcja uniwersalna do definiowania znaku*/
void DefineCharacter(int8_t nr, char *znak)/*nr 0...7, *znak to wskaznik na tablice z danymi*/
{
    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*/
    Wyslij_do_LCD((nr*8)|CGRAM_SET);/*ustaw adres poczatkowy w CGRAM na nasz znak*/
    
    RS = 1 ;/*stan wysoki na linii RS, wybieramy rejestr danych*/
    /*wysylamy 8 x bajt zdefiniowanego w tablicy znak[] znaku*/
    for(i=0;i<=7;i++)
    {
       Wyslij_do_LCD(*znak++);
    }
   
    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*/ 
    
    /*definiowanie znaku DefineCharacter(1,tablica) gdzie nr 0...7 a tablica to 
     np char tablica[]= {0x0C,0x12,0x12,0x0C,0,0,0,0} definicja stC*/
    
    /*wywolanie zdefiniowanego znaku Wyslij_do_LCD(nr) gdzie nr to 0...7 lub
     WyswietlLCD("\nr"*/
}
/*****************************************************************************
  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 <math.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 "i2c.h"

/*******************************************************************************
 DEKLARACJE FUNKCJI
 ******************************************************************************/
 void Set_MCP3424(void);
 int read_MCP3424(void);
 void InitTimer1(void);
/*******************************************************************************
 DEKLARACJE/DEFINICJE ZMIENNYCH
 ******************************************************************************/
#define AdressMCP3424 0x0 /*A0,A1 --> 00*/
volatile uint8_t Timer1_Programowy , Timer2_Programowy ;
float wynik, wynikTotal, wynikFraction;
int wynikADC;
char tablica[16];
int licznik;

int main(void) {
    ustaw_zegar(); /*odpalamy zegar wewnetrzny na ok 40MHz (39.61375 MHz)*/
    __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 ;
    TRISAbits.TRISA1 = 0 ; /*RA1 jako wyjscie, tu mamy podpieta LED*/
    
    InitTimer1(); /*Timer 1 Init*/
    ustaw_I2C1(); /*I2C1 Init*/
    WlaczLCD();   /*LCD Init*/
    WpiszSwojeZnaki(); /*znak stopnia definjujemy*/
    Set_MCP3424(); /*konfiguracja przetwornika*/
    
    licznik = 0;     
    while (1) {
        /*w trybie 16 bitow mamy 1 probke po ok 66 ms (15SPS) (1000ms / 15) odczyt zrobimy co 70ms*/
        /*co 70ms wykonaj czynnosc*/
            if(!Timer1_Programowy) {
             Timer1_Programowy = 7 ; /*Timer1 sprzetowy x Timer1_Programowy = 10ms x 7 = 70ms*/
             if(licznik > 10) licznik = 0/*10 x 70ms = 700ms*/
             wynikADC = read_MCP3424();/*pobieramy dane do zmiennej  celem dalszych przeksztalcen*/
             /*tutaj wstawi? trzeba jeszcze wykrywanie znaku temp. na podstawie ADC, 0st to 7999,75 dla tryby 16bit*/
             wynik = wynikADC; 
             wynik *= 204.8 ;
             wynik /= 32767.0 ;
             wynik -= 50.0 ;
             /*rozdziel wynik na czesc calkowita (wynikTotal) i ulamkowa (wynikFraction), przygotuj do wyswietlania na LCD*/
             wynikFraction = modff(wynik, &wynikTotal);/*operacja rodzielania na czesc calkowita i ulamkowa*/
             wynikFraction *= 10.0;  /*interesuje nas 1 cyfra czesci ulamkowej, przenosimy ja na czesc calkowita*/
             wynikFraction = floorf(wynikFraction);   /*wyodrebnij przeniesiona z czesci ulamkowej czesc calkowita*/
             wynikADC = (int)wynikTotal; 
             sprintf(tablica,"%i",wynikADC);  /*zmienna int konwertujemy na char i umieszczamy ja w tablicy*/
             /*dane mamy gotowe do wyswietlania*/
             /*wyswietlamy dane co ok 700ms, nie ma potrzeby szybciej*/
             if(++licznik == 10) {
             UstawKursorLCD(1,1);
             WyswietlLCD("Temperatura: ");
             WyswietlLCD(tablica); /*wyswietlamy czesc calkowita temperatury*/
             Wyslij_do_LCD(44); /*przecinek*/
             wynikADC = (int)wynikFraction; /*czesc ulamkowa (1 cyfra)*/
             sprintf(tablica,"%i",wynikADC);/*alternatywa dla znanej z Atmeg funkcji itoa, konwertuj z int na char*/
             WyswietlLCD(tablica); /*wyswietlamy czesc ulamkowa temperatury*/
             WyswietlLCD("\x01""C"); /*wyswietlamy zdefiniowany znak stC, po \ podajemy kod ASCII nowego znaku*/
              }   
            }
            
    }
    return 0;
}


void Set_MCP3424(void)
{
  
    i2c_start(); 
  
   /*MCP3421 ADDRESS BYTE - MSB first*/
  
   /* 1 - 1 - 0 - 1 - A2 - A1 - A0 - R/W*/
    
   i2c_write(0b11010000); /*wysylamy bajt z adresem MCP3424 R/W - 0*/
   __delay_us(10); /*zwloka na ustawienie ACK przez MCP3424*/
   
   /*MCP3421 CONFIGURATION REGISTER - MSB first*/
   /*RDY - C1 - C0 - O/C - S1 - S0 - G1 - G0*/
   /*RDY - ready bit,
     C1-C0 - channel selection bit
     O/C - conversion mode bit
     S1-S0 - sample rate
     G1-G0 - PGA gain selection*/
   i2c_write(0b00011000); /*wysylamy bajt konfiguracyjny Continuous conversion - 16bit - channel 0 - PGA = 1*/
   __delay_us(10); /*zwloka na ustawienie ACK przez MCP3424*/
   i2c_stop(); 
}

/*funkcja odczytu danych z MCP3424*/
int read_MCP3424(void)
{
   uint16_t readADC=0;
         
   i2c_start(); 
   i2c_write(0b11010001);/*wysylamy bajt z adresem MCP3424 R/W - 1*/
    __delay_us(10); /*zwloka na ustawienie ACK przez MCP3424*/
   readADC=i2c_read(); /*odczytujemy starszy bajt z danymi*/
   i2c_ack();
   readADC<<=8/*przesuwamy odebrany bajt na pozycje starszego bajtu w slowie 16 bitowym*/
   readADC+=i2c_read(); /*odczytujemy mlodszy bajt z danymi i sumujemy go z poprzednia wartoscia*/
   /*konczymy odczyt, pomijamy odczyt bajtu konfiguracyjnego*/
   i2c_nack();
   i2c_stop(); 
      
   return(readADC);
}

/*Inicjacja/konfiguracja Timera1*/
void InitTimer1(void){
    /*konfiguracja Timer1*/
    T1CONbits.TON = 0 ; /*Stop the timer1*/
    TMR1 = 0x0000 ;/*Clear timer register*/
    /*Zegar ok 40 MHz(39.61375 MHz) Prescaler 1:64; PR1 Preload = 61897; Actual Interrupt Time = 100 ms*/
    T1CONbits.TCKPS = 0b10 ; /*Prescaler 1:64*/
   
    /*konfiguracja przerwania*/
    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.10Hz (100ms*/    
 //PR1       = 61897; /*Load period value*/
 //T1CONbits.TON = 1 ; /*Start the timer1*/    
  
 /*ok.100Hz (10ms)*/    
   PR1       = 6189/*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*/
}


Brak komentarzy:

Prześlij komentarz