Lo scopo di questo tutorial è quello di fornire una soluzione per rilevare la tensione di rete con un microcontrollore. In questo esempio ho scelto il PIC16F628A ma potete scegliere qualsiasi altro microcontrollore.
Per isolare la rete dal microcontrollore ho utilizzato un foto accoppiatore e nello specifico ho scelto l' SFH620A. Lo schema elettrico è il seguente:
Funzionamento.
Quando sul morsetto J1 è presente la tensione di rete, nel semiperiodo positivo dell'onda, l'uscita V1 sul collettore del transistor interno al fotoaccoppiatore commuterà da 5V a 0V come evidenziato nel grafico. Questo avverrà non appena la corrente nel fotodiodo sarà sufficiente per saturare il transistor interno. La corrente necessaria dipende dal CTR del fotoaccoppiatore e tenendo conto che il valore minimo si attesta intorno 13, allora il transistor saturerà quando la tensione in ingresso arriverà a circa 10V.
Poichè all'interno del fotoaccoppiatore sono presenti 2 foto diodi in antiparallelo, la commutazione avverrà anche durante il semiperiodo dell'onda negativa.
Da quanto descritto si intuisce che le commutazioni avvengono in circa 10 msec (ogni T/2), con T periodo dell'onda sinusoidale pari all'inverso della frequenza T=1/f.
Sapendo che ogni commutazione avviene in 10 msec circa, possiamo attivare un'uscita del microcontrollore (LED D1) sul primo fronte di discesa rilevato e caricare un timer con un valore superiore a T/2.
Ogni volta che il microcontrollore rileverà un fronte di discesa ricaricherà il timer al suo valore massimo impedendo il suo azzeramento fino a quando non verranno rilevati più fronti.
Quando non ci saranno più commutazioni per più di 20-30 msec allora il timer si azzererà e l'uscita LED D1 si porterà a 0. Spero di essere stato chiaro, in caso contrario potete contattarmi.
Codice C:
/*
* File: main.c
* Author: v.primoceri
*
* Created on 14 ottobre 2021, 14.04
* XC8 compiler Microchip V 2.31
* */
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator: High-speed crystal/resonator on RA6/OSC2/CLKOUT and RA7/OSC1/CLKIN)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = ON // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = ON // Brown-out Detect Enable bit (BOD enabled)
#pragma config LVP = OFF // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
#define DivTimer1 3 //
#define DivTimer0 5000 //
#define LED1 PORTBbits.RB3
#define ST_MAINS_VOLTAGE_DETECTION 1
#define ST_WAIT 0
#define _XTAL_FREQ 10000000 //Frequenza quarzo
#include "xc.h"
#include <pic16f628a.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
volatile unsigned int IncTimer1=0;
volatile unsigned int IncTimer0=0;
volatile unsigned char Main_Voltage_Detection=0;
volatile unsigned char Timeout_Main_Voltage_Detection=0;
unsigned char State;
void __interrupt () isr(void){
if((INTCONbits.INTF)&&(INTCONbits.INTE)) {//Fronte di discesa su RB0
if(State==ST_WAIT) {
Main_Voltage_Detection=1;
}
IncTimer1=DivTimer1;
INTCONbits.INTF=0;
}
//----------------------------------------------------------------------------
if(INTCONbits.TMR0IF){//Timer0
if(--IncTimer0==0){//ogni secondo
IncTimer0=DivTimer0;////Variabile per divisione contatore per ottenere 1 sec
//....
}
TMR0=5;
TMR0IF=0;
}
//----------------------------------------------------------------------------
if(PIR1bits.TMR1IF==1){// interrupt ogni 20 millesec
if(IncTimer1>0){
if(--IncTimer1==0){
Timeout_Main_Voltage_Detection=1;
}
}
TMR1=0x9E58;//40536
PIR1bits.TMR1IF=0;
}//Fine if(PIR1bits.TMR1IF==1){
}
int main(void) {
OPTION_REGbits.PSA=0;//0 = Prescaler is assigned to the Timer0 module
OPTION_REGbits.T0CS=0;//0= Internal instruction cycle clock (FOSC/4)
OPTION_REGbits.T0SE=0;//=0 Increment on low-to-high transition
OPTION_REGbits.PS=0;// prescaler 1:2
OPTION_REGbits.INTEDG=0;//0 = Interrupt on falling edge of RB0/INT pin
INTCONbits.T0IE=0;//Timer0 Overflow Interrupt Enable bit
INTCONbits.GIE=1;//Global Interrupt Enable bit
INTCONbits.PEIE=1;//Disables all peripheral interrupts
INTCONbits.T0IF=0;//Timer0 Overflow Interrupt Flag bit
INTCONbits.INTE=1;//Se=1 abilta INT0
INTCONbits.RBIE=0;//
CMCON=0b00000111;//Comparatori spenti
VRCON=0b00000000;//Vref off
T1CON=0b00000001;//Timer1 ON
TMR1=0x9E58;//40536 -->65536 -25000=40536 per 20 msec
PIE1bits.TMR1IE=1;//Interrupt abilitato
T2CON=0b00000000;//Timer2 OFF
PIR1bits.TMR1IF=0;
PORTB=0b00000000;
TRISB=0b00000001;
PORTA=0b00000000;
TRISA=0;
TMR0=5;//impostare per 1 sec
IncTimer0=DivTimer0;
State=ST_WAIT;
while(1){
switch (State){
case ST_WAIT:
if(Main_Voltage_Detection==1){
Main_Voltage_Detection=0;
LED1=1;
State=ST_MAINS_VOLTAGE_DETECTION;
}
break;
case ST_MAINS_VOLTAGE_DETECTION:
if(Timeout_Main_Voltage_Detection==1){
Timeout_Main_Voltage_Detection=0;
LED1=0;
State=ST_WAIT;
}
break;
}
}
return 0;
}
Grazie per la vostra attenzione al prossimo tutorial.
Saluti V.Primoceri.