Sari la conținut
ELFORUM - Forumul electronistilor

Invatat programare de la zero


Postări Recomandate

Sunt ceva incertitudini in logica enuntata aici:

 

 

Nu inteleg: "Deci dupa 15 minute acesta sa se opreasca" Cine sa se opreasca? hidroforului sa i se taie comanda

 

Si nu inteleg nici:

" insa repornirea sa o faca dupa alte 30 minute

in mod automat(revenirea apei in fantana)"

Cine reporneste? - repornirea sa o faca tot uC, dupa 15 minute se opreste apoi dupa inca 30 minute reporneste

Link spre comentariu

Ok. Incet, incet se face lumina.

Cand vorbim de timp, ne intereseaza nu doar durata dar si momentul de inceput.

 

Bun, ce am inteles eu pana acum este asa:

- Prin apasarea butonului se porneste pompa si simultan se declanseaza un ciclu de 15 minute in care pompa si hidroforul functioneaza amandoua. Deci avem un moment T0 cand apasam butonul si astfel porneste pompa.

- Daca butonul se apasa (oprim astfel pompa) intre momentul T0 si T0+15min atunci hidroforul va continua sa functioneze un timp nedefinit, programul revine la inceput, asteptand un nou moment T0. Ramane o incertitudine ca la urmatorul moment T0, cand butonul porneste pompa, daca fantana este plina sau nu.

- Daca se depaseste momentul T0+15min si pompa inca functioneaza, atunci hidroforul se opreste si ramane oprit pana la momentul T0+15min+30min adica pana la momentul T0+45min.

- De asemenea, daca se depaseste momentul T0+15min si pompa inca functioneaza, pompa va ramane pornita pana la momentul T0+30min, moment in care pompa se opreste si va putea fi repornita doar prin actionarea butonului.

- In orice moment dintre T0 si T0+30min butonul sa poata porni/opri pompa dar indiferent de starea sa (pornita sau oprita) in momentul T0+30, pompa se opreste si va putea fi pornita doar prin apasarea butonului.

 

In algoritm probabil ca trebuie completat ca daca dupa intervalul T0+30min cand obligatoriu pompa se opreste, se incearca apasarea butonului pentru pornire pompa, pompa ar trebui sa ramana totusi oprita pana la momentul T0+45min cand teoretic fantana este iar plina, moment in care de altfel si hidroforul porneste.

 

Intrebarea este: se tine cont de o eventuala apasare a butonului din momentul T0+30min si momentul T0+45min? Adica o apasare in acest interval sa insemne ca se doreste ca atunci cand expira perioada de T0+45min, odata cu hidroforul sa porneasca si pompa?

 

Probabil ca aceasta problema se rezolva cu o masina de stari si cu un Timer.

Editat de mars01
Link spre comentariu

Ok. Incet, incet se face lumina.

Cand vorbim de timp, ne intereseaza nu doar durata dar si momentul de inceput.

 

Bun, ce am inteles eu pana acum este asa:

- Prin apasarea butonului se porneste pompa si simultan se declanseaza un ciclu de 15 minute in care pompa si hidroforul functioneaza amandoua. Deci avem un moment T0 cand apasam butonul si astfel porneste pompa.

- Daca butonul se apasa (oprim astfel pompa) intre momentul T0 si T0+15min atunci hidroforul va continua sa functioneze un timp nedefinit, programul revine la inceput, asteptand un nou moment T0. Ramane o incertitudine ca la urmatorul moment T0, cand butonul porneste pompa, daca fantana este plina sau nu.

- Daca se depaseste momentul T0+15min si pompa inca functioneaza, atunci hidroforul se opreste si ramane oprit pana la momentul T0+15min+30min adica pana la momentul T0+45min.

- De asemenea, daca se depaseste momentul T0+15min si pompa inca functioneaza, pompa va ramane pornita pana la momentul T0+30min, moment in care pompa se opreste si va putea fi repornita doar prin actionarea butonului.

- In orice moment dintre T0 si T0+30min butonul sa poata porni/opri pompa dar indiferent de starea sa (pornita sau oprita) in momentul T0+30, pompa se opreste si va putea fi pornita doar prin apasarea butonului.

 

In algoritm probabil ca trebuie completat ca daca dupa intervalul T0+30min cand obligatoriu pompa se opreste, se incearca apasarea butonului pentru pornire pompa, pompa ar trebui sa ramana totusi oprita pana la momentul T0+45min cand teoretic fantana este iar plina, moment in care de altfel si hidroforul porneste.

 

Intrebarea este: se tine cont de o eventuala apasare a butonului din momentul T0+30min si momentul T0+45min? Adica o apasare in acest interval sa insemne ca se doreste ca atunci cand expira perioada de T0+45min, odata cu hidroforul sa porneasca si pompa?

 

Probabil ca aceasta problema se rezolva cu o masina de stari si cu un Timer.

Da....ati inteles corect ceea ce doresc....eu inca nu am ajuns inca la stadiul de a face timer-e , stiu sa scriu pe lcd, sa setez intrari iesiri, sa fac un pwm, sa citesc un analogic si inca ceva chestii elementare.

Acum referitor la intrebarile dvs.:

- Daca butonul se apasa (oprim astfel pompa) intre momentul T0 si T0+15min atunci hidroforul va continua sa functioneze un timp nedefinit, programul revine la inceput, asteptand un nou moment T0. Ramane o incertitudine ca la urmatorul moment T0, cand butonul porneste pompa, daca fantana este plina sau nu.

 

Momentan nu as dori sa se tina cont de acest lucru, familia stie ca oprirea se face automata, si daca se reporneste pompa ar mai fi 10-20 de litri sa traga, plus ca dupa oprire incepe sa se incarce:deci momentan asta nu este problema.Deci pompa se va opri cu mult inainte de golirea totala a fantanii, si nu este necesara asteptarea ca la hidrofor...

In rest totul s-a inteles perfect!

Link spre comentariu

Cam asa arata programul pentru un PIC 18F1220. In cazul in care se schimba controller-ul atunci trebuie schimbate #define-urile in mod corespunzator cat si functiile hw_init() si interrupt().

/* 
   Project: Hydrophore - garden pump usage
   Microcontroller:  Microchip 18F1220 running at 8MHz on internal osc
   Datasheet: https://store.comet.bg/download-file.php?id=3564
   Programmer: mars01 on elforum.ro
   Date: 15 - Sept - 2017
*/

#define pompa        LATA0_bit
#define pompa_dir    TRISA0_bit
#define hidro        LATA1_bit
#define hidro_dir    TRISA1_bit

#define buton        RA4_bit
#define buton_dir    TRISA4_bit

#define INPUT        1;
#define OUTPUT       0;

// anonymous enumeration to store possible states of the outputs
enum
{
   OFF = 0,
   ON  = 1
};

// enumeration to store the states of the FSM
typedef enum States {
   IDLE ,
   RUN,
   HIDRO_OFF
} state_t;

state_t state;                            // variable of type state_t
volatile unsigned long timer_cnt = 0;     // variable to store time in multiples of 0.1sec
unsigned long initial_time;               // var to store the initial time

// LCD setup
sbit LCD_RS at LATB3_bit;
sbit LCD_EN at LATB2_bit;
sbit LCD_D7 at LATB4_bit;
sbit LCD_D6 at LATB5_bit;
sbit LCD_D5 at LATB6_bit;
sbit LCD_D4 at LATB7_bit;

sbit LCD_RS_Direction at TRISB3_bit;
sbit LCD_EN_Direction at TRISB2_bit;
sbit LCD_D7_Direction at TRISB4_bit;
sbit LCD_D6_Direction at TRISB5_bit;
sbit LCD_D5_Direction at TRISB6_bit;
sbit LCD_D4_Direction at TRISB7_bit;
// End LCD setup

// clear the watchdog timer
void clrwdt() {
   asm CLRWDT;
}

void hw_init(void) {

   clrwdt();
   // make sure that the oscillator is running at 8MHz
   IRCF2_bit = 1;
   IRCF1_bit = 1;
   IRCF0_bit = 1;
   
   ADON_bit = 0x00;              // disable ADC
   ADCON1 = 0xFF;             // set all ADC pins as digital
   
   Lcd_Init();                // Initialize LCD
   Lcd_Cmd(_LCD_CLEAR);       // Clear display
   Lcd_Cmd(_LCD_CURSOR_OFF);  // Cursor off
   
   pompa_dir = OUTPUT;
   hidro_dir = OUTPUT;
   buton_dir = INPUT;
   
   pompa = OFF;
   hidro = ON;
   
   //init timer
   T1CKPS1_bit = 1;
   T1CKPS0_bit = 0;
   TMR1ON_bit = 1;            // start Timer1
   TMR1IF_bit         = 0;          // clear Timer1 interrupt flag
   TMR1H         = 0x3C;
   TMR1L         = 0xB0;
   TMR1IE_bit         = 1;
   PEIE_bit = 1;
   GIE_bit = 1;               // start interrupts
   
   SWDTEN_bit = 1;            // enable watchdog; the watchdog postscaler was set at 1:256 that means an reset interval of 4ms x 256 = 1024ms = 1.024sec

}

void Interrupt(){
   // Timer1 one Interrupt rate is 100ms = 0.1s
   if (TMR1IF_bit && TMR1ON_bit){
      TMR1IF_bit = 0;
      TMR1H         = 0x3C;
      TMR1L         = 0xB0;
      timer_cnt++;
   }
}

// check the state of the button
unsigned char check_button (void) {
   static unsigned char anterior_buton = 1; // initial state of the button is OFF

   clrwdt();
   if (buton == 1) {
      anterior_buton = 1;
   }

   if (buton == 0 && anterior_buton == 1) {
      delay_ms(10);
      if (buton == 0) {
         anterior_buton = 0;
         return 1;
      }
   }
   else return 0;
}

// initialize the timer_cnt variable
void init_timer() {
   timer_cnt = 0;
}

// return the timer_cnt variable value
unsigned long timer_func () {
   volatile unsigned long temp;           // declared as volatile so it will not be optimized
   
   clrwdt();
   GIE_bit = 0;                           // disable interrupts
   temp = timer_cnt;                      // copy the value of timer variable into the shadow variable named temp
   GIE_bit = 1;                           // enable interrupts
   
   return timer_cnt;                      // return the timer variable
}

void idle_func () {
   hidro = ON;
   pompa = OFF;
   clrwdt();
   
   if (check_button() == ON) {
      state = RUN;
      init_timer();
      initial_time = timer_func();
   }
}

void run_func() {
   pompa = ON;
   
   clrwdt();
   // if time is less than 15'
   if ((timer_func() - initial_time) < 9000) {
      if (check_button() == ON) {
         state = IDLE;
      }
   }
   else {
      state = HIDRO_OFF;
   }
}

void hidro_off_func() {
   hidro = OFF;
   
   clrwdt();
    // if the time is less than 30'
   if ((timer_func() - initial_time) < 18000) {
      if (check_button() == ON) {
         pompa = !pompa;
      }
   }
   else pompa = OFF;
   
   // if the time is more than 45'
   if ((timer_func() - initial_time) >= 27000) {
      state = IDLE;
   }
}

void main() {

   hw_init();
   state = IDLE;
   clrwdt();
   
   while (1) {
      clrwdt();
      
      switch (state) {
         case IDLE:
            idle_func();
            break;
         case RUN:
            run_func();
            break;
         case HIDRO_OFF:
            hidro_off_func();
            break;
      }
   
   }

}

Fantana.zip

Editat de mars01
Link spre comentariu

Am inteles....multumesc, modificarile o stiu sa le fac...insa cred ca am un milion deintrebari...cel putin....

 

// anonymous enumeration to store possible states of the outputs
enum
{
OFF = 0,
ON = 1
};

// enumeration to store the states of the FSM
typedef enum States {
IDLE ,
RUN,
HIDRO_OFF
} state_t;

 

ce inseamna FSM?

ce inseamnna enum states?

ce face state_t si typedef?

 

multimesc...ma intereseaza ce fac, hidro_off de ce nu are ;?

Editat de catalin004
Link spre comentariu

Pai, nu cred ca am discutat despre cam multe din cele mentionate in tutorialul din paginile precedente. Probabil ca trebuia sa il termin, prezentand toate conceptele.

Dar .... viata, timpul ....

 

Am sa incerc sa raspund punctual si in cateva cuvinte, mai mult trebuie studiat...

 

 

------------------------------------------------------------------------------------------------------------------------------------------------------------------

ENUMERARILE

 

Enumerarile, realizate cu ajutorul cuvantului cheie enum, sunt colectii de constante. Separatia intre membrii unei enumerari se face cu virgula, ultimul membru nu necesita virgula. Cum membrii enumerarii sunt incadrati intre acolade, nu este necesar ca sa fie scrisi pe acelasi linie, dar se poate si asa.

 

Cu alte cuvinte o enumerare (anonima pentru ca nu i-am dat un nume) se poate scrie asa:

enum {
   OFF = 0,
   ON  = 1
};

sau asa:

enum {OFF = 0, ON  = 1};

sau mai putin explicit, asa:

enum {OFF, ON};

Toate 3 formularile sunt echivalente.

 

De ce a 3-a?

Pentru ca in mod default, primului element i se atribuie valoarea 0, la al doilea i se atribuie valoarea 1 si tot asa. Practic este o lista de constante (care pot fi numai intregi daca nu ma insel) care in mod default pleaca de la 0, incrementand valorile cu 1.

 

Cum spuneam, in mod default. Dar daca noi dorim, atunci putem sa asignam valori (intregi) in ce ordine vrem. Adica asa:

enum {
   OFF = 500,
   ON  = 7
};

Faptul ca eu am explicitat facand atribuirile cu 0 si cu 1, a fost deoraece am vrut sa fie clar ce se intampla acolo, daca lasam doar:

enum {OFF, ON};

ar fi aparut mai multe intrebari.

 

In program, de fiecare data cand apare o instanta a lui ON, se va inlocui cu constanta 1 si oriunde apare o instanta a lui OFF, se inlocuieste cu constanta 0.

 

Ceva pe aproape, ca si functionalitate, se putea scrie si cu #define (e totusi altceva, dar efectul final este tot pe acolo):

#define OFF   0
#define ON    1

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

TYPEDEF

 

Am vorbit despre tipurile de variabile. Cum ar fi INT, UNSIGNED INT, CHAR, UNSIGNED CHAR, BYTE, LONG, FLOAT samd.

Dar daca vrem sa ne cream propriul tip?

Daca dorim ca de exemplu sa numai facem referire la tipul de variabila FLOAT cu cuvantul cheie FLOAT, ci cu cuvantul cheie (creat de noi) numit sa zicem, REAL?

 

Aici apare in discutie TYPEDEF.

 

Formularea este asa:

typedef FLOAT REAL;

Ce se intampla cum este ca atunci cand scriem:

real PI = 3.1415;

este totuna cu a declara (+definire in acest caz):

float PI = 3.1415;

Destul de frecvent, cand nu am acces la libraria stdint.h, ma folosesc pentru usurinta de asemenea schimbari, ca si exemplu: in loc de a scrie:

unsigned char a;

eu prefer sa scriu,

uint8_t a;

Pentru aceasta scriu undeva in partea de sus a programului:

typedef unsigned char uint8_t

Compilatorul C recunoaste cuvintele cheie unsigned char si le inlocuieste de fiecare data cand identifica uint8_t in program. De fapt mai exact aloca in memorie un spatiu de 8biti pentru o variabila de tip unsigned char. In continuare se pot folosi in program ambele formulari: unsigned char sau uint8_t.

 

 

In cazul particular cand am folosit:

typedef enum States {
   IDLE ,
   RUN,
   HIDRO_OFF
} state_t;

ce am facut eu este sa creez un nou tip de variabila, tip caruia i-am dat in mod aleator numele state_t.

I-am pus underscore t la final ca sa stiu in program ca este vorba de un tip. Altfel puteam sa scriu cam ce vroiam eu (intre anumite limite).

 

Practic am creat o enumerare cu 3 elemente (IDLE, RUN si HIDRO_OFF) care de fapt sunt 3 constante unde IDLE = 0 si RUN = 1 si HIDRO_OFF = 2 (cum spuneam, fiindca eu nu am interferat, compilatorul se ocupa el si le da valori in background, in ordine, incepand cu 0 si apoi incrementand cu 1).

 

Dupa creare enumerare, prin folosirea typedef, am creat astfel in aceasi comanda si o asociere cu un tip nou de variabila numit state_t.

 

Din acest moment pot sa declar un nou tip de variabila numit state_t.

 

Asa cum la un moment dat scriu:

unsigned int bau_bau;

acum pot scrie si:

state_t stare;

iar in acest moment efectul este ca variabila stare, atentie, poate lua NUMAI valorile: IDLE, RUN sau HIDRO_OFF. Sau valorile din spatele acestora adica respectiv 0, 1 sau 2.

 

Cu alte cuvinte, putem scrie:

stare = IDLE;

sau

stare = 0;

sau atribuire valori RUN, HIDRO_OFF si valorile din spatele lor (numai stau sa le insirui aici).

 

Dar primim eroare la compilare daca incercam sa scriem ceva de genul (valoare aleasa aleator, dar una care nu face parte din valorile enumerarii):

stare = 52;

----------------------------------------------------------------------------------------------------------------------------------------

 

FSM este un acronim de la Finite State Machine. Adica, masina cu stari finite.

 

Este o tehnica de programare in care se identifica in algoritmul care urmeaza sa fie implementat in program, asa numite stari stabile cat si tranzitiile intre stari. Masinile cu stari finite pot fi de tip Mealy sau Moore.

 

Cine vrea sa cunoasca mai mult despre aceste masini de stari finite poate citi tutoriale pe internet, este un subiect vast si tratat in cursuri in facultate deoarece este o tehnica foarte folosita.

De exemplu este folosita frecvent si in programare jocuri pe calculator/consola.

 

Implemetarea masinii de stari finite este in aceasta sectiune:

switch (state) {
    case IDLE:
       idle_func();
       break;
    case RUN:
       run_func();
       break;
    case HIDRO_OFF:
       hidro_off_func();
       break;
}

Practic este intr-un switch - case si functiile apelate aici.

Editat de mars01
Link spre comentariu

ERRATA

 

In functia:

// return the timer_cnt variable value
unsigned long timer_func () {
   volatile unsigned long temp;           // declared as volatile so it will not be optimized
   
   clrwdt();
   GIE_bit = 0;                           // disable interrupts
   temp = timer_cnt;                      // copy the value of timer variable into the shadow variable named temp
   GIE_bit = 1;                           // enable interrupts
   
   return timer_cnt;                      // return the timer variable
}

este o greseala, ma rog, protectia pe care am inclus-o nu am folosit-o :(

 

Functia trebuie sa arate asa:

// return the timer_cnt variable value
unsigned long timer_func () {
   volatile unsigned long temp;           // declared as volatile so it will not be optimized
   
   clrwdt();
   GIE_bit = 0;                           // disable interrupts
   temp = timer_cnt;                      // copy the value of timer variable into the shadow variable named temp
   GIE_bit = 1;                           // enable interrupts
   
   return temp;                           // return the timer variable
} 
Editat de mars01
Link spre comentariu

In caz ca cineva este interesat, varianta (fara initializare LCD) care se poate compila cu MPLABX + compilatorul XC8

(am modificat in #define-ul butonului cu o metoda de a testa bitul 4 din PORTA care sa nu implice folosirea simbolulu RA4; ma freca la cap ca este deprecated adica in viitor nu se va mai folosi - dar nici nu dadeau o alternativa asa ca am facut eu ceva acolo folosind operatorul ternar). Am mai optimizat putin functia butonului (era un return 0 implicit care l-am rezolvat).

Oricum si programul in mikroC postat anterior merge bine-merci.

 

Am facut programul acesta pentru XC8 ca sa pot simula in Proteus si sa fac si debugging daca este cazul (fisierul .cof generat de mikroC nu este compatibil cu Proteus pentru ca nu are fuse-urile incluse in fisierul .cof dar lipsesc si altele). Oricum imi place mai mult sa lucrez in MPLABX + XC8.

In final, programul se simuleaza asa cum trebuie in toate cazurile.

 

Listing-ul pentru XC8:

/* 
   Project: Hydrophore - garden pump usage
   Microcontroller:  Microchip 18F1220 running at 8MHz on internal osc
   Datasheet: https://store.comet.bg/download-file.php?id=3564
   Programmer: mars01 on elforum.ro
   Date: 15 - Sept - 2017
*/


// PIC18F1220 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1H
#pragma config OSC = INTIO2     // Oscillator Selection bits (Internal RC oscillator, port function on RA6 and port function on RA7)
#pragma config FSCM = OFF       // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOR = OFF        // Brown-out Reset Enable bit (Brown-out Reset disabled)
// BORV = No Setting

// CONFIG2H
#pragma config WDT = OFF        // Watchdog Timer Enable bit (WDT disabled (control is placed on the SWDTEN bit))
#pragma config WDTPS = 256      // Watchdog Timer Postscale Select bits (1:256)

// CONFIG3H
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (RA5 input pin enabled, MCLR disabled)

// CONFIG4L
#pragma config STVR = ON        // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Low-Voltage ICSP Enable bit (Low-Voltage ICSP disabled)

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (00200-0007FFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (000800-000FFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot Block (000000-0001FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (00200-0007FFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (000800-000FFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot Block (000000-0001FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (00200-0007FFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (000800-000FFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot Block (000000-0001FFh) not protected from table reads executed in other blocks)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.


#include <xc.h>

#define _XTAL_FREQ   8000000

#define pompa        LATA0
#define pompa_dir    TRISA0
#define hidro        LATA1
#define hidro_dir    TRISA1

#define buton        (((PORTA & 0x10) > 0)? 1:0 )   // testing RA4
#define buton_dir    TRISA4

#define INPUT        1;
#define OUTPUT       0;

// anonymous enumeration to store possible states of the outputs
enum
{
   OFF = 0,
   ON  = 1
};

// enumeration to store the states of the FSM
typedef enum States {
   IDLE ,
   RUN,
   HIDRO_OFF
} state_t;

state_t state;                            // variable of type state_t
volatile unsigned long timer_cnt = 0;     // variable to store time in multiples of 0.1sec
unsigned long initial_time;               // var to store the initial time


// clear the watchdog timer
void clrwdt() {
   asm ("CLRWDT");
}

void hw_init(void) {

   clrwdt();
   // make sure that the oscillator is running at 8MHz
   IRCF2 = 1;
   IRCF1 = 1;
   IRCF0 = 1;
   
   ADON = 0x00;           // disable ADC
   ADCON1 = 0xFF;             // set all ADC pins as digital
      
   pompa_dir = OUTPUT;
   hidro_dir = OUTPUT;
   buton_dir = INPUT;
   
   pompa = OFF;
   hidro = ON;
   
   //init timer
   T1CKPS1 = 1;
   T1CKPS0 = 0;
   TMR1ON = 1;            // start Timer1
   TMR1IF = 0;            // clear Timer1 interrupt flag
   TMR1H = 0x3C;
   TMR1L = 0xB0;
   TMR1IE = 1;
   PEIE = 1;
   GIE = 1;               // start interrupts
   
   SWDTEN = 1;            // enable watchdog; the watchdog postscaler was set at 1:256 that means an reset interval of 4ms x 256 = 1024ms = 1.024sec

}

void __interrupt ISR(){
   // Timer1 one Interrupt rate is 100ms = 0.1s
   if (TMR1IF && TMR1ON){
      TMR1IF = 0;
      TMR1H = 0x3C;
      TMR1L = 0xB0;
      timer_cnt++;
   }
}

// check the state of the button
unsigned char check_button (void) {
   static unsigned char anterior_buton = 1; // initial state of the button is OFF

   clrwdt();
   if (buton == 1) {
      anterior_buton = 1;
   }

   if (buton == 0 && anterior_buton == 1) {
      __delay_ms(10);
      if (buton == 0) {
         anterior_buton = 0;
         return 1;
      }
   }

   return 0;
}

// initialize the timer_cnt variable
void init_timer() {
   timer_cnt = 0;
}

// return the timer_cnt variable value
unsigned long timer_func () {
   volatile unsigned long temp;           // declared as volatile so it will not be optimized
   
   clrwdt();
   GIE = 0;                           // disable interrupts
   temp = timer_cnt;                      // copy the value of timer variable into the shadow variable named temp
   GIE = 1;                           // enable interrupts
   
   return temp;                           // return the timer variable
}

void idle_func () {
   hidro = ON;
   pompa = OFF;
   clrwdt();
   
   if (check_button() == ON) {
      state = RUN;
      init_timer();
      initial_time = timer_func();
   }
}

void run_func() {
   pompa = ON;
   
   clrwdt();
   // if time is less than 15'
   if ((timer_func() - initial_time) < 9000) {
      if (check_button() == ON) {
         state = IDLE;
      }
   }
   else {
      state = HIDRO_OFF;
   }
}

void hidro_off_func() {
   hidro = OFF;
   
   clrwdt();
    // if the time is less than 30'
   if ((timer_func() - initial_time) < 18000) {
      if (check_button() == ON) {
         pompa = !pompa;
      }
   }
   else pompa = OFF;
   
   // if the time is more than 45'
   if ((timer_func() - initial_time) >= 27000) {
      state = IDLE;
   }
}

void main() {
   hw_init();
   state = IDLE;
   clrwdt();
   
   while (1) {
      clrwdt();
      
      switch (state) {
         case IDLE:
            idle_func();
            break;
         case RUN:
            run_func();
            break;
         case HIDRO_OFF:
            hidro_off_func();
            break;
      }

   }

}
Editat de mars01
Link spre comentariu

Am studiat ce mi-ati spus insa...am inteles partea cu enumerari...si interesanta...cam greu de la inceput cu acele stari...eu inteleg bine din exemple insa...

 

deci:

IDLE=0;

RUN=1;

HIDRO_OFF=2; - ce valoare ia pana la urma aceasta? 1 sau 0? sau 1+0? ca aici nu inteleg...

 

A doua intrebare ar fi despre timere....tot timpul timerele sunt legate cu intreruperi?adica dupa timer imediat interupt?

Editat de catalin004
Link spre comentariu

Intrebarea 1:

 

In enumerare, in spatele la fiecare element (membru) este o constanta. Ea poate fi ascunsa atunci cand nu o explicitam si atunci primul element are valoarea 0, al 2-lea element are valoarea 1, al 3-lea element are valoarea 2 si asa mai departe.

SIncer nu ne intereseaza prea mult ce valoarea au, atat timp cat ma folosesc de etichetele respective, adica de IDLE, RUN si HIDRO_OFF.

 

Ideea masinilor cu stari finite este ca se intra mai intai in starea default (in acest caz este IDLE), cand ceva se intampla (in acest caz se pasa butonul) se face tranzitie la starea urmatoare din lista (adica RUN), cand se intampla ceva aici (expira timpul de functionare) se trece in starea urmatoare din lista (adica HIDRO_OFF) si cand ceva se intampla aici (au trecut 45 minute) se trece din nou in starea default (IDLE). Si o ia din nou de la capat. Evident mai sunt si alte variante de ajuns in IDLE (apasam butonul cand suntem in starea RUN).

 

Intrebarea 2:

 

Timerele poti sa ti le imaginezezi ca niste cronometre care pornesc de la o valoare (poate fi zero sau orice valoare intre 0 si valoarea maxima) si cand ajung la valoarea maxima (se incrementeaza pe un clock care se seteaza din prescalere, postscalere (unde este cazul)) dau o intrerupere si o iau de la capat. Timerele lucreaza autonom in ceea ce priveste ALU-ul controller-ului (in ceea ce priveste incrementarea).

 

Intreruperea este semnalizata de catre un bit intr-un registru si astfel se poate identifica cine a generat intreruperea (in caz ca ai mai multe intreruperi activate: poate mai multe timere, poate UART-ul, poate ADC-ul etc).

Intrerupere inseamna ca programul se opreste in acel moment (ma refer la programul principal, cel din functia main() ) se executa ce este in functia apelata de intrerupere si apoi se face resume la programul din main().

 

Atentie, daca vei folosi alt microcontroller, atunci configurarea Timer-ului de mai sus este posibil sa fie diferita.

Link spre comentariu

Ideea este ca ne alegem un interval la care sa apara intreruperea. Sa zicem ca avem nevoie ca la fiecare 1ms sa apara o intrerupere si sa fie executata functia asociata intreruperii (se foloseste un cuvant special, in mikroC o functie numita void Interrupt() este functia aceea speciala care este executata).

 

Mai intai ne alegem un timer din cele disponibile in hardware-ul uC-ului.

Unele din cele disponibile sunt pe 8 biti, altele sunt pe 16bit.

 

Functie de frecventa la care lucreaza uC-ul nu orice perioada se poate selecta. In principiu timer-ul pe 16bit e mai flexibil (numara pana la 65535) asa ca e un candidat bun ca sa nu avem dureri de cap.

 

Dupa acea, setam din registrii asociati prescalerele/postacalerele si incarcam in prealabil registrii TMR1L si TMR1H cu unele valori care atunci cand atingem cele 1ms urmarite de noi sa umple cei doi registri( TMR1L = 0b11111111 si TMR1H = 0b11111111) moment in care se declanseaza intreruperea.

 

Practic avem o ecuatie cu cateva necunoscute. Ne jucam cu ele pana obtinem ce dorim. Oricum trebuie avut in vedere si ca declansarea intreruperii si incarcarea registrilor TMR1x dureaza un numar de cicli de ceas si trebuie tinut cont si ciclii acestia pierduti.

 

Sau mai usor :limb: ne folosim de aplicatia Timer Calculator realizata de mikroElectronika. https://libstock.mikroe.com/projects/view/398/timer-calculator

Selectam familia de controlere, frecventa de lucru a uC-ului, timer-ul folosit si zbang, ne ofera codul mura-n gura. :reytre

 

Un exemplu de cod pentru acelasi controller PIC18F1220 in care ne folosim de Timer0 (un timer pe 8 bit, mai limitat) si aprindem si stingem un LED aflat pe RB0 la un interval de 500ms.

Timer-ul il setam la 1ms (asa, fiindca merge) si incrementam o variabila counter pana la 500, adica au trecut 500 x 1ms = 500ms, moment cand schimbam starea pinului.

// uC is PIC 18F1220 running at 8MHz on internal oscillator

#define OFF 0
#define ON  1

#define OUTPUT 0

#define LED          LATB0_bit
#define LED_DIR      TRISB0_bit

// variable to count time (in 1ms increments)
unsigned int timer_counter = 0;

//Timer0
//Prescaler 1:8; TMR0 Preload = 6; Actual Interrupt Time : 1 ms

//Place/Copy this part in declaration section
void InitTimer0(){
  T0CON = 0xC2;         // start Timer0 and set prescaler at 1:8
  TMR0L = 0x06;         // load an initial value so the final interrupt time is at 1ms
  GIE_bit = 1;          // start general interrupts
  TMR0IE_bit = 1;       // enable Timer0 interrupt
}

void Interrupt(){
  if (TMR0IF_bit){               // if Timer0 interrupt bit is set then
    TMR0IF_bit = 0;              // make sure to first clear it to wait the next interrupt
    TMR0L = 0x06;                // load the timer0 register with the value for the next count
    //Enter your code here
    if (timer_counter >= 500){   // if timer_counter var reached 500 so 500ms passed
      timer_counter = 0;         // init the variable so it can count again
      LED = !LED;                // change the state of the LED pin
    }
    else {
      timer_counter++;           // increase the value by 1
    }
  }
}

void hw_init() {
   // make sure that the oscillator is running at 8MHz
   IRCF2_bit = 1;
   IRCF1_bit = 1;
   IRCF0_bit = 1;

   ADON_bit = 0x00;     // disable ADC
   ADCON1 = 0xFF;       // set all ADC pins as digital
   
   LED_DIR = OUTPUT;    // the pin with LED is OUTPUT
   
   InitTimer0();        // init timer
}


void main() {
   hw_init();
   
   while (1) {
   
   }
}
Editat de mars01
Link spre comentariu

Am facut modificari pentru 16F73 si nu merge...

#define OFF 0
#define ON  1

#define LED1_dir TRISC.F3
#define LED1 PORTC.F3
#define output 0


unsigned int timer_counter = 0;

//Place/Copy this part in declaration section
void InitTimer0()
{
  INTCON = 0xC2;         // start Timer0 and set prescaler at 1:8
  TMR0 = 96;         // load an initial value so the final interrupt time is at 1ms
  GIE_bit = 1;          // start general interrupts
  TMR0IE_bit = 1;       // enable Timer0 interrupt
}


void Interrupt()
{
  if (TMR0IF_bit)     // if Timer0 interrupt bit is set then
  {     

    TMR0IF_bit = 0;              // make sure to first clear it to wait the next interrupt
    TMR0 = 96;                // load the timer0 register with the value for the next count
    //Enter your code here
    if (timer_counter >= 500)
    {  
     // if timer_counter var reached 500 so 500ms passed
      timer_counter = 0;         // init the variable so it can count again
     LED1 = !LED1;                // change the state of the LED pin
    }
    else 
    {
      timer_counter++;           // increase the value by 1
    }
  } }
  
  void hw_init() 
  {
   // make sure that the oscillator is running at 8MHz
  // IRCF2_bit = 1;
  // IRCF1_bit = 1;
   //IRCF0_bit = 1;

  // ADON_bit = 0x00;     // disable ADC
  // ADCON1 = 0xFF;       // set all ADC pins as digital

   LED1_dir = output;    // the pin with LED is OUTPUT

   InitTimer0();        // init timer
}

  void main()
  {
  hw_init();
   while (1)
   {
   }
  }
Link spre comentariu

Creează un cont sau autentifică-te pentru a adăuga comentariu

Trebuie să fi un membru pentru a putea lăsa un comentariu.

Creează un cont

Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!

Înregistrează un nou cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum
×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări