# [Moved] Ac voltage controller using pic microcontroller

Status
Not open for further replies.

#### faiz khan

##### Member level 1
Friends can any one help me how to control the firing angle by using a external push button to pic controller.....if anybody having code means please send.

THANK YOU

#### KlausST

##### Super Moderator
Staff member
Hi,

Look for "phase control". Read about the technology. Study application notes. Look for hardware and software.
Then try to build it for your own by using and modifying the given informations.

If you encounter any problems, then show us what you did, what you expect and give a detailed error description.

Klaus

pic.programmer

### pic.programmer

Points: 2

#### faiz khan

##### Member level 1
The code which i used is below.my objective is to program pic controller such that if we press push buttons the firing angle OF TRIAC should increase or decrease .please help me by correcting the code.
THANK YOU

Code:
unsigned char FlagReg;
sbit ZC at FlagReg.B0;
int x;
void interrupt()
{
int i;
if (INTCON.INTF)
{          //INTF flag raised, so external interrupt occured
//  ZC = 1;
INTCON.INTF = 0;
//  }
//if (ZC){ //zero crossing occurred

for(i=1;i<=x;i++)
{
delay_ms(1);
}
PORTD.B0 = 1; //Send a pulse
delay_us(250);
PORTD.B0 = 0;
//ZC = 0;
// }
}
}

void main() {
x=1;
PORTB = 0;
TRISB = 0x01;              //RB0 input for interrupt
PORTA = 0;
TRISA = 0xFF;                                //Make all PORTA inputs
PORTD = 0;
TRISD = 0;                 //PORTD all output
OPTION_REG.INTEDG = 0;      //interrupt on falling edge
INTCON.INTF = 0;           //clear interrupt flag
INTCON.INTE = 1;           //enable external interrupt
INTCON.GIE = 1;            //enable global interrupt

while (1)
{
if((RC5==0))
{
x=x+1;
//delay_ms(1);
}
if((RC6==0))
{
x=x-1;
//delay_ms(1);
}
}
}

Last edited by a moderator:

#### KlausST

##### Super Moderator
Staff member
Hi,

You tell nothing about your hardware so it is hard for us to guess what you want to do.

****

You know ho it should work? Do you have a zero cross hardware? How does it work?

***

A busy wait within an interrupt is no good idea.
It´s better to start a timer/counter, maybe in waveform generation mode, to generate the firing pulse without software.

***

Post schematic, and additional informations like controller type, frequency, pahse adjust range and -resolution and so on.

Klaus

pic.programmer

### pic.programmer

Points: 2

#### faiz khan

##### Member level 1
I am doing a project on TRIAC based voltage controller with resistive load.
the components i am using are BT137(TRIAC),MOC3041(OPTOISOLATOR-WITH ZCD).

by using PIC16F877A i want to control the firing angle of TRIAC for which i am using 2 push buttons,one for incrementing and one for decrementing firing angle....

THANK YOU

#### pic.programmer

I can help you with the code for your project but I have to know which compiler you are using. From the code that you have posted it seems you are using mikroC PRO PIC Compiler. Is it right ?

Have a look at this thread.

#### faiz khan

##### Member level 1
yes am using mikroc PRO PIC compiler and PIC16F877A
THANK YOU

#### pic.programmer

Did you see the link I posted in post #7. How many steps do you need. Is 10 steps of power control enough ? Are you simulating in Proteus or testing in hardware. Please provide the circuit.

Should the least power turn of the device or do you want another button to turn ON/OFF the device ?

What is your AC frequency ? 50 Hz or 60 Hz ?

#### betwixt

##### Super Moderator
Staff member
1. get rid of the delay in the interrupt.
2. note that your steps are set to 1mS minimum, that gives you no more than 20 levels at 50Hz and 16 levels at 60Hz.
3. limit your number of steps, you can currently go from -32767 (!) to +32768 when it should be 0 to +20 or 0 to +16

You would do better to configure a hardware timer to count to maximum in one half AC cycle, pre-set it with your 'x' value and fire the triac as the timer overflows. It gives greater control accuracy, more steps although you can decide their size in software and also leaves the PIC able to do some other task at the same time.

The frequency can easily be measured by counting between zero crossings so it isn't really necessary to know it beforehand.

Brian.

pic.programmer

### pic.programmer

Points: 2

#### faiz khan

##### Member level 1
Did you see the link I posted in post #7. How many steps do you need. Is 10 steps of power control enough ? Are you simulating in Proteus or testing in hardware. Please provide the circuit.

Should the least power turn of the device or do you want another button to turn ON/OFF the device ?

What is your AC frequency ? 50 Hz or 60 Hz ?

YES i saw that post ....my circuit is also same as that circuit.first i am simulating in Proteus and then has to implement hardware.

my circuit is same what is there in the link in post#7 but with pic16f877a.

i want to use 2 push buttons for incrementing and decrementing firing angle ...9 steps are enough for both push buttons

THANK YOU

Last edited by a moderator:

#### pic.programmer

I made the code but Proteus is not showing the TRIAC signal. Maybe betwixt can help.

@betwixt

Please check the code I have attached. If you have Proteus then please check why TRIAC signal is not showing.

#### Attachments

• PIC16F877A Based Dimmer.rar
39.2 KB · Views: 82

#### faiz khan

##### Member level 1
it is not opening friend...please send in pdf format

#### pic.programmer

Here is the circuit. TRIAC is firing but TRIAC signal is not present. maybe it is a Proteus problem. Test it in hardware.

#### Attachments

• dimmer.png
79.1 KB · Views: 105

#### faiz khan

##### Member level 1
thank you can you send the code please.....

#### pic.programmer

Here is the code. Compiled for 4 MHz XT Oscillator.

Code C - [expand]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
unsigned char milliSec = 0, count = 0;

//Timer0
//Actual Interrupt Time : 1 ms
//Place/Copy this part in declaration section
void InitTimer0() {
OPTION_REG = 0x81;
TMR0 = 6;
TMR0IE_bit = 1;
}

void interrupt() {
if(INTF_bit) {
INTF_bit = 0;
INTE_bit = 0;
InitTimer0();
INTEDG_bit = ~INTEDG_bit;
}

if(TMR0IF_bit) {
TMR0IF_bit = 0;
TMR0 = 6;
if(++count == (milliSec + 1)) {
TMR0IE_bit = 0;
PORTD.F0 = 1;
//Delay_us(200);
PORTD.F0 = 0;
count = 0;
INTE_bit = 1;
}
}
}

void main() {

CMCON = 0x07;

TRISA = 0xC0;
TRISB = 0x07;
TRISC = 0x00;
TRISD = 0x00;
TRISE = 0x00;

PORTA = 0x00;
PORTB = 0x07;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;

INTEDG_bit = 0;
INTF_bit = 0;
INTE_bit = 1;

GIE_bit = 1;

while (1){

if(RB1_bit) {
Delay_ms(50);
while(RB1_bit);
if(milliSec < 8)++milliSec;
}

if(RB2_bit) {
Delay_ms(50);
while(RB2_bit);
if(milliSec > 0)--milliSec;
}
}
}

#### faiz khan

##### Member level 1
thanks friend i will try it...

#### pic.programmer

Replace 4N37 with MOC3021 in the TRIAC firing circuit.

Try this code in Proteus.

Code C - [expand]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
unsigned char milliSec = 0, count = 0;

//Timer0
//Actual Interrupt Time : 1 ms
//Place/Copy this part in declaration section
void InitTimer0() {
OPTION_REG = 0x81;
TMR0 = 6;
TMR0IE_bit = 1;
}

void interrupt() {
if(INTF_bit) {
INTF_bit = 0;
INTE_bit = 0;
InitTimer0();
INTEDG_bit = ~INTEDG_bit;
}

if(TMR0IF_bit) {
TMR0IF_bit = 0;
TMR0 = 6;
if(++count == (milliSec + 1)) {
TMR0IE_bit = 0;
PORTD.F0 = 1;
Delay_us(200);
PORTD.F0 = 0;
count = 0;
INTE_bit = 1;
}
}
}

void main() {

CMCON = 0x07;

TRISA = 0xC0;
TRISB = 0x07;
TRISC = 0x00;
TRISD = 0x00;
TRISE = 0x00;

PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;

INTEDG_bit = 0;
INTF_bit = 0;
INTE_bit = 1;

PEIE_bit = 1;
GIE_bit = 1;

while (1){

if(RB1_bit) {
Delay_ms(50);
while(RB1_bit);
if(milliSec < 9)++milliSec;
}

if(RB2_bit) {
Delay_ms(50);
while(RB2_bit);
if(milliSec > 0)--milliSec;
}
}
}

- - - Updated - - -

Working project attached. See image for circuit. This is the code. Compile it for 4 MHz XT Oscillator. Test in Proteus and also hardware and reply.

The problem with the previous codes were because of using Timer0. I changed it to Timer1 and everything started working as needed.

Code C - [expand]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
unsigned char milliSec = 0, count = 0;

//Timer1
//Prescaler 1:1; TMR1 Preload = 64536; Actual Interrupt Time : 1 ms
//Place/Copy this part in declaration section
void InitTimer1(){
T1CON = 0x01;
TMR1IF_bit = 0;
TMR1H = 0xFC;
TMR1L = 0x18;
TMR1IE_bit = 1;
}

void interrupt() {
if(INTF_bit) {
INTF_bit = 0;
INTEDG_bit = ~INTEDG_bit;
//INTE_bit = 0;
InitTimer1();

}

if(TMR1IF_bit) {
TMR1IF_bit = 0;
TMR1H = 0xFC;
TMR1L = 0x18;
if(++count == (milliSec + 1)) {
TMR1ON_bit = 0;
PORTD.F0 = 1;
Delay_us(200);
PORTD.F0 = 0;
count = 0;
//INTE_bit = 1;
}
}
}

void main() {

CMCON = 0x07;

TRISA = 0xC0;
TRISB = 0x07;
TRISC = 0x00;
TRISD = 0x00;
TRISE = 0x00;

PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;

INTEDG_bit = 0;
INTF_bit = 0;
INTE_bit = 1;

PEIE_bit = 1;
GIE_bit = 1;

while (1){

if(RB1_bit) {
Delay_ms(50);
while(RB1_bit);
if(milliSec < 9)++milliSec;
}

if(RB2_bit) {
Delay_ms(50);
while(RB2_bit);
if(milliSec > 0)--milliSec;
}
}
}

Try this code. Changed the Timer delay value. Earlier it was 1 ms and now it is 875 us.

Code C - [expand]1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
unsigned char milliSec = 0, count = 0;

//Timer1
//Prescaler 1:1; TMR1 Preload = 64711; Actual Interrupt Time : 825 us
//Place/Copy this part in declaration section
void InitTimer1(){
T1CON = 0x01;
TMR1IF_bit = 0;
TMR1H = 0xFC;
TMR1L = 0x95;
TMR1IE_bit = 1;
}

void interrupt() {
if(INTF_bit) {
INTF_bit = 0;
INTEDG_bit = ~INTEDG_bit;
//INTE_bit = 0;
InitTimer1();

}

if(TMR1IF_bit) {
TMR1IF_bit = 0;
TMR1H = 0xFC;
TMR1L = 0x95;
if(++count == (milliSec + 1)) {
TMR1ON_bit = 0;
PORTD.F0 = 1;
Delay_us(100);
PORTD.F0 = 0;
count = 0;
//INTE_bit = 1;
}
}
}

void main() {

CMCON = 0x07;

TRISA = 0xC0;
TRISB = 0x07;
TRISC = 0x00;
TRISD = 0x00;
TRISE = 0x00;

PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
PORTE = 0x00;

INTEDG_bit = 0;
INTF_bit = 0;
INTE_bit = 1;

PEIE_bit = 1;
GIE_bit = 1;

while (1){

if(RB1_bit) {
Delay_ms(50);
while(RB1_bit);
if(milliSec < 9)++milliSec;
}

if(RB2_bit) {
Delay_ms(50);
while(RB2_bit);
if(milliSec > 0)--milliSec;
}
}
}

#### Attachments

• PIC16F877A Based Dimmer Working.rar
138 KB · Views: 89
• dimmer working.png
110.5 KB · Views: 103
Last edited:
faiz khan

### faiz khan

Points: 2

#### betwixt

##### Super Moderator
Staff member
@betwixt

Please check the code I have attached. If you have Proteus then please check why TRIAC signal is not showing.

I don't use Proteus or MikroC but I keep a copy of Mikro programs (trial versions) for helping people on here. For 'production' use I wouldn't touch it!

Suggestion: move the resistor in series with the ZCD opto-coupler so it is in series with the AC to the bridge rather than the opto itself. You can then use smaller diodes and if necessary add a small capacitor across the bridge AC points to reduce interference pick up. Obviously, use an opto-triac instead of U2 and I suggest using the circuit in the triac data sheet rather than just feeding the gate current through a 1K resistor.

Brian.

Points: 2

### pic.programmer

Points: 2

#### pic.programmer

OK betwixt.

Can I use this circuit for ZCD ? Is it safe ? I have used 5.1V zener diodes. If mains voltage increases above 240 or 260V then Zener has to bypass it.

See the attached video. It shows the Proteus simulation.

#### Attachments

• ZCD.png
97 KB · Views: 91
• Phase Angle Control Proteus Simulation.rar
295.3 KB · Views: 80
Last edited:
faiz khan

### faiz khan

Points: 2

#### betwixt

##### Super Moderator
Staff member
If you use that for ZCD, why not use ordinary Schottky signal diodes? Wired between ground and VDD they will clamp the incoming AC to within VSS-0.25V and VDD+0.25V which is better than the Zeners will achieve. For safety sake, I would add a resistor of say 10K in series with the PIC input and make the resistor in series with the AC something like 150K or more. The current into the PIC is almost zero so you can safely use quite high value resistors.

AC ---> 150K ---> diodes to VSS & VDD ---> 10K ---> PIC pin.

Suggest diode type BAT85 or equivalent. Be careful with supply to the PIC, your schematics show it connected to one side of the AC so make sure you can't touch anything, especially the switch wiring!

Brian.

Points: 2

Points: 2