Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Need Help: Integrating lamps dimmer with blinds (using stepper motor)

Status
Not open for further replies.

ArdyNT

Full Member level 2
Joined
Nov 6, 2012
Messages
126
Helped
7
Reputation
14
Reaction score
7
Trophy points
1,298
Activity points
2,304
I can dim/brightening AC lamps by implementing the concept of phase firing angle. Zero crossing circuit is used to give external interrupt into the uC so that triac firing can be done accurately. Now, I want to integrate it with some motor stepper to open/close the blinds.

In this case, blinds(stepper motor) will have higher priority than the lamps. For example, if the light intensity is decreasing below the predetermined set-point, first, the motor will turn to open the blinds. If it is not enough yet, then the lamps will ON brighter and brighter till the set-point is reached. If only by opening the blinds is enough, then the lamps don't need to be ON. The principle is something like this.

For now I can also control the steps of the motor. The problem is I just don't know how to combine both of them into one to work synchronously. I have the code but first I want some suggestions of what I should do to mix them.

Any helps will be very appreciated.

Thank you.
 

I'm not sure what you mean about having them work "synchronously". Could you explain? If you "have the code", then what do you need from us? Or do you have code that doesn't work?
 

Well, sorry, I just got confuse to combine the two codes that I have. Both of them already WORKING anyway but independently.
Somebody in this forum also helped me so I can come up with the following code to set the triac firing delay:


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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#include <mega8535.h>
 #include <stdio.h>
 #include <delay.h>
 #include <stdint.h>
 #include <lcd.h>
 #asm
 .equ __lcd_port=0x15 ;PORTC
 #endasm
 
 unsigned char buf[10];
 volatile unsigned int a1;
 volatile unsigned int b1;
 volatile unsigned int c1;
 unsigned int count = 0;
 volatile unsigned int x = 2;
 volatile unsigned int y = 2;
 volatile unsigned int z = 2;
    
 // External Interrupt 0 service routine
 interrupt [EXT_INT0] void ext_int0_isr(void)
 {
        // Start  Timer 0
        TCCR0 = 0x02;    
 }
 
 // Timer 0 overflow interrupt service routine
 interrupt [TIM0_OVF] void timer0_ovf_isr(void)
 {
    // Local variables initialization
    static uint8_t pulse_flag = 0;
    
    // Reinitialize Timer 0 value
    TCNT0=0xD3;
    
    // Increment count every 50 us
    count++; 
    
    // Front lamp
    if(count == x)
        {
            PORTB.0 = 0;
        }
    else
        if(count == x + 1)
            {
                PORTB.0 = 1;
                pulse_flag++;
            }
                
    // Middle lamp        
    if(count == y)
        {
            PORTB.1 = 0;
        }
    else
        if(count == y + 1)
            {
                PORTB.1 = 1;
                pulse_flag++;
            }
 
    // Back lamp
    if(count == z)
        {
            PORTB.2 = 0;
        }
    else
        if(count == z + 1)
            {
                PORTB.2 = 1;
                pulse_flag++;
            }
     
    // Stop timer when all pulses have completed
    if(pulse_flag == 3)
        {
            // Clear flag
            pulse_flag = 0;
             
            // Stop the timer
            TCCR0 = 0;
            
            // Reset the timer
            TCNT0 = 0;
                  
            // Clear count
            count = 0; 
        }  
 }
 
 
#define ADC_VREF_TYPE 0x40
 
 // Read the AD conversion result
 unsigned int read_adc(unsigned char adc_input)
 {
    ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
    
    // Delay needed for the stabilization of the ADC input voltage
    delay_us(10);
    
    // Start the AD conversion
    ADCSRA|=0x40;
    
    // Wait for the AD conversion to complete
    while ((ADCSRA & 0x10)==0);
    ADCSRA|=0x10;
    return ADCW;
 }
 
 
 void display_lux()
 {
    a1=read_adc(0);
    lcd_gotoxy(0,0);
    sprintf(buf,"L1:%d%d%d%d",a1/1000,(a1%1000)/100,(a1%1000%100)/10,a1%1000%100%10);
    lcd_puts(buf);
        
    b1=read_adc(1);
    lcd_gotoxy(9,0);
    sprintf(buf,"L2:%d%d%d%d",b1/1000,(b1%1000)/100,(b1%1000%100)/10,b1%1000%100%10);
    lcd_puts(buf);
        
    c1=read_adc(2);
    lcd_gotoxy(0,1);
    sprintf(buf,"L3:%d%d%d%d",c1/1000,(c1%1000)/100,(c1%1000%100)/10,c1%1000%100%10);
    lcd_puts(buf);    
 }
 
 
 void set_delay()
 {
    // If light intensity below the setpoint, shorten the firing delay
    if((PORTB.0 == 1) && (a1 <= 875))
    {
        if(x > 1)
        {  
            x = x - 1;
        }
    }
        
    // If light intensity greater than the setpoint, increase the firing delay
    if((PORTB.0 == 1) && (a1 >= 890))
    {
        if(x < 280)
        { 
            x = x + 1;
        }
    }
           
    // If light intensity below the setpoint, shorten the firing delay
    if((PORTB.1 == 1) && (b1 <= 875))
    {
        if(y > 1)
        {
            y = y - 1;
        }
    }
        
    // If light intensity greater than the setpoint, increase the firing delay
    if((PORTB.1 == 1) && (b1 >= 890))
    {
        if(y < 280)
        {
            y = y + 1;
        }
    }
          
    // If light intensity below the setpoint, shorten the firing delay
    if((PORTB.2 == 1) && (c1 <= 875))
    {
        if(z > 1)
        {
            z = z - 1;
        }
    }
           
    // If light intensity greater than the setpoint, increase the firing delay
    if((PORTB.2 == 1) && (c1 >= 890))
    {
        if(z < 280)
        {
            z = z + 1;
        }
    } 
 }
 
 
 void main(void)
 {
    PORTA=0xFF;
    DDRA=0x00;
    PORTB=0xFF;
    DDRB=0xFF;
    PORTC=0x00;
    DDRC=0x00;
    PORTD=0x00;
    DDRD=0x00;
 
    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: 1500.000 kHz
    // Mode: Normal top=0xFF
    // OC0 output: Disconnected
    TCCR0=0x02;
    TCNT0=0xD3;
    OCR0=0x00;
 
    // External Interrupt(s) initialization
    // INT0: On
    // INT0 Mode: Falling Edge
    GICR|=0x40;
    MCUCR=0x02;
    MCUCSR=0x00;
    GIFR=0x40;
 
    // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK=0x01;
 
    // Analog Comparator initialization
    // Analog Comparator: Off
    // Analog Comparator Input Capture by Timer/Counter 1: Off
    ACSR=0x80;
    SFIOR=0x00;
 
    ADMUX=ADC_VREF_TYPE & 0xff;
    ADCSRA=0x84;
    SFIOR&=0xEF;
 
    lcd_init(16);
 
    // Global enable interrupts
    #asm("sei")
 
    while (1)
      {
        display_lux();
        #asm("cli")
        set_delay();
        #asm("sei")     
      }
 }



Then the following are the second code used to drive the motor stepper. Actually there should be three motors too.


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
#include <mega8535.h>
#include <delay.h>
#define LEFT 1
#define RIGHT 0
unsigned int motor_step[4] = {0b00101000, 0b00110000, 0b01010000, 0b01001000};
 
void turn(unsigned char direction, int step)
{
    static unsigned char i = 0;
    unsigned int j = 0;
 
    while(j <= step)
    {
        j++;
 
        if(direction)
        {
            i++;
        }
        else
        {
            i--;
        }
 
        if(i == 255)
        {
            i = 3;
        }
        else
            if(i == 4)
            {
                i = 0;
            }
 
        PORTB = motor_step[i];
        delay_ms(50);
    }
}
 
 
void main(void)
{
    PORTB = 0x00;
    DDRB = 0xF8;
 
    while(1)
    {
        turn(LEFT, 95);        // This is just for testing purpose
        delay_ms(1000);
        turn(RIGHT, 95);
        delay_ms(1000);
    }
}



What I need now is something like this:

Code:
If(adc is smaller than 875)     // means the light intensity below setpoint
{
      turn(LEFT, 48)              // blind open half
      If(adc is still smaller than 875)
      {
          turn(LEFT,48)           // blind open full
          if(adc still smaller than 875)
          {
                decrease the firing delay    // lamp ON and getting brighter
          }
      }
}

If(adc is greater than 890)
{
      increase the firing delay          // dim the lamp first, left the blind open
      If(adc is still greater than 890)
      {
          turn(RIGHT,48)                  // blind closed half
          if(adc still greater than 890)
          {
                turn(RIGHT, 48)           // blind fully closed
          }
      }
}

This seem complicated to me. Really need help.

Any suggestions now?
 
Last edited:

Anybody can help me?
 

I think you are making this harder than it has to be. If the room is too dark, then run the stepper to brighten it with the blinds. If the blinds are fully open and it's still too dark, turn the triac on. Done.
 

I think you are making this harder than it has to be. If the room is too dark, then run the stepper to brighten it with the blinds. If the blinds are fully open and it's still too dark, turn the triac on. Done.

That was what actually I want. With the codes that I have posted, what should I do? Please guide me.
 

I'm not really a programmer, so I'm not going to try to answer your question with specifics. But I think it would be a simple matter to have some top-level code that monitors the brightness, and then calls either the blinds function or the lamp function depending on the status of the blinds. Just draw a state diagram and it should be pretty evident how to do this.
 

I mean no diss to the poster but doesn't anyone use flowcharts anymore?

jack
 

Somebody help me please:-(

I have combined them together but it didn't operate as it should be.


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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
#include <mega8535.h>
 #include <stdio.h>
 #include <delay.h>
 #include <stdint.h>
 #include <lcd.h>
 #define LEFT 1
 #define RIGHT 0
 #asm
 .equ __lcd_port=0x15 ;PORTC
 #endasm
 
 bit ZC = 0;
 unsigned char buf[10];
 volatile unsigned int a1;
 volatile unsigned int b1;
 volatile unsigned int c1;
 
 unsigned int count = 0;
 
 volatile unsigned int x = 2;
 volatile unsigned int y = 2;
 volatile unsigned int z = 2;
 unsigned int motor_step[4] = {0b00101000, 0b00110000, 0b01010000, 0b01001000};
    
 // External Interrupt 0 service routine
 interrupt [EXT_INT0] void ext_int0_isr(void)
 {   
    if(ZC==1)
    {
              // Start  Timer 0
              TCCR0 = 0x02;  
    } 
}
 
 // Timer 0 overflow interrupt service routine
 interrupt [TIM0_OVF] void timer0_ovf_isr(void)
 {
    // Local variables initialization
    static uint8_t pulse_flag = 0;
    
    // Reinitialize Timer 0 value
    TCNT0=0xD3;
    
    // Increment count every 50 us
    count++; 
    
    // Front lamp
    if(count == x)
        {
            PORTB.0 = 0;
        }
    else
        if(count == x + 1)
            {
                PORTB.0 = 1;
                pulse_flag++;
            }
                
    // Middle lamp        
    if(count == y)
        {
            PORTB.1 = 0;
        }
    else
        if(count == y + 1)
            {
                PORTB.1 = 1;
                pulse_flag++;
            }
 
    // Back lamp
    if(count == z)
        {
            PORTB.2 = 0;
        }
    else
        if(count == z + 1)
            {
                PORTB.2 = 1;
                pulse_flag++;
            }
     
    // Stop timer when all pulses have completed
    if(pulse_flag >= 3)
        {
            // Clear flag
            pulse_flag = 0;
             
            // Stop the timer
            TCCR0 = 0;
            
            // Reset the timer
            TCNT0 = 0;
                  
            // Clear count
            count = 0; 
        }  
 }
 
 
#define ADC_VREF_TYPE 0x40
 
 // Read the AD conversion result
 unsigned int read_adc(unsigned char adc_input)
 {
    ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
    
    // Delay needed for the stabilization of the ADC input voltage
    delay_us(10);
    
    // Start the AD conversion
    ADCSRA|=0x40;
    
    // Wait for the AD conversion to complete
    while ((ADCSRA & 0x10)==0);
    ADCSRA|=0x10;
    return ADCW;
 }
 
 void turn(unsigned char direction, int step)
 {
    static unsigned char i = 0;
    unsigned int j = 0;
 
    while(j <= step)
    {
        j++;
 
        if(direction)
        {
            i++;
        }
        else
        {
            i--;
        }
 
        if(i == 255)
        {
            i = 3;
        }
        else
            if(i == 4)
            {
                i = 0;
            }
 
        PORTB = motor_step[i];
        delay_ms(50);
    }
 }
 
 void display_lux()
 {
    a1=read_adc(0);
    lcd_gotoxy(0,0);
    sprintf(buf,"L1:%d%d%d%d",a1/1000,(a1%1000)/100,(a1%1000%100)/10,a1%1000%100%10);
    lcd_puts(buf);
        
    b1=read_adc(1);
    lcd_gotoxy(9,0);
    sprintf(buf,"L2:%d%d%d%d",b1/1000,(b1%1000)/100,(b1%1000%100)/10,b1%1000%100%10);
    lcd_puts(buf);
        
    c1=read_adc(2);
    lcd_gotoxy(0,1);
    sprintf(buf,"L3:%d%d%d%d",c1/1000,(c1%1000)/100,(c1%1000%100)/10,c1%1000%100%10);
    lcd_puts(buf);    
 }
 
 void motor_turn()                                           // I really need help in this part
 {
    static uint8_t blinds_flag = 0;
        
    if (a1 <= 500)
    {
        turn(RIGHT,96);
        blinds_flag++;
        
        if((a1 <= 500) && (blinds_flag == 1))
        {
            ZC = 1;
        }
    }
 
    if(a1 >= 550)
    {
        ZC = 1;
        
        if((a1 >= 550) && (blinds_flag == 1))
        {
            turn(LEFT,96);
            blinds_flag = 0;
        }
    }
 }
 
 
 void set_delay()
 {    
    // If light intensity below the setpoint, shorten the firing delay
    if((PORTB.0 == 1) && (a1 <= 500))
    {
        if(x > 1)
        {  
            x = x - 1;
        }
    }
        
    // If light intensity greater than the setpoint, increase the firing delay
    if((PORTB.0 == 1) && (a1 >= 550))
    {
        if(x < 280)
        { 
            x = x + 1;
        } 
    }
           
    // If light intensity below the setpoint, shorten the firing delay
    if((PORTB.1 == 1) && (b1 <= 500))
    {
        if(y > 1)
        {
            y = y - 1;
        }
    }
        
    // If light intensity greater than the setpoint, increase the firing delay
    if((PORTB.1 == 1) && (b1 >= 550))
    {
        if(y < 280)
        {
            y = y + 1;
        }
    }
          
    // If light intensity below the setpoint, shorten the firing delay
    if((PORTB.2 == 1) && (c1 <= 500))
    {
        if(z > 1)
        {
            z = z - 1;
        }
    }
           
    // If light intensity greater than the setpoint, increase the firing delay
    if((PORTB.2 == 1) && (c1 >= 550))
    {
        if(z < 280)
        {
            z = z + 1;
        }
    } 
 }
 
 
 void main(void)
 { 
    PORTA=0x07;
    DDRA=0x00;
    PORTB=0x07;
    DDRB=0xFF;
    PORTC=0x00;
    DDRC=0x00;
    PORTD=0x00;
    DDRD=0x00;
 
    TCCR0=0x02;
    TCNT0=0xD3;
    OCR0=0x00;
 
    ASSR=0x00;
    TCCR2=0x00;
    TCNT2=0x00;
    OCR2=0x00;
 
    GICR|=0x40;
    MCUCR=0x02;
    MCUCSR=0x00;
    GIFR=0x40;
 
    TIMSK=0x01;
 
    ACSR=0x80;
    SFIOR=0x00;
 
    ADMUX=ADC_VREF_TYPE & 0xff;
    ADCSRA=0x84;
    SFIOR&=0xEF;
 
    lcd_init(16);
 
    #asm("sei")
 
    while (1)
      {
        display_lux();
        #asm("cli")
        set_delay();
        motor_turn();
        #asm("sei")     
      }
 }

 
Last edited:

Why have you disabled interrupts during motor_turn() ?
There was a specific reason for doing that with set_delay() and it meant disabling the interrupts just for a few us but for some reason you decided to do the same for motor_turn() which in turn calls turn() which applies delay_ms(50); for each step.

What that means is that when motor_turn() calls turn(RIGHT,96); your interrupts are disabled for 96 * 50ms = 4.8 sec 8-O
 

Why have you disabled interrupts during motor_turn() ?
There was a specific reason for doing that with set_delay() and it meant disabling the interrupts just for a few us but for some reason you decided to do the same for motor_turn() which in turn calls turn() which applies delay_ms(50); for each step.

What that means is that when motor_turn() calls turn(RIGHT,96); your interrupts are disabled for 96 * 50ms = 4.8 sec

Right!, I've been thinking about this. I read also about atomicity, but I just don't know what to do again. If I don't disable it, when motor start, the lamps will be blinking like mad. Then I realize my decision is wrong. By disabling it, all lamps off while the motor turns:-(.

By the way, I've change the code into:

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
#include <mega8535.h>
 #include <stdio.h>
 #include <delay.h>
 #include <stdint.h>
 #define ALEFT 0
 #define ARIGHT 1
 
 unsigned char buf[10];
 volatile unsigned int ldr1;
 volatile unsigned int ldr2;
 volatile unsigned int ldr3;
 
 unsigned int count = 0;
 
 volatile unsigned int x = 2;
 volatile unsigned int y = 2;
 volatile unsigned int z = 2;
 
 unsigned int motor_stepA[4] = {0b00101000, 0b00110000, 0b01010000, 0b01001000};
 // Next there willl be stepB and step C, since there are three motors
    
 // Alphanumeric LCD functions
 #include <lcd.h>
 #asm
 .equ __lcd_port=0x15 ;PORTC
 #endasm
 
 // External Interrupt 0 service routine
 interrupt [EXT_INT0] void ext_int0_isr(void)
 {
    // Start  Timer 0
    TCCR0 = 0x02;
 }
 
 // Timer 0 overflow interrupt service routine
 interrupt [TIM0_OVF] void timer0_ovf_isr(void)
 {
    // Local variables initialization
    static unsigned int pulse_flag = 0;
    // Reinitialize Timer 0 value
    TCNT0=0xD3;
    // Increment count every 50 us
    count++; 
    // Front lamp
    if(count == x)
        {
            PORTB.0 = 0;
        }
    else
        if(count == x + 1)
            {
                PORTB.0 = 1;
                pulse_flag++;
            }
                
    // Middle lamp        
    if(count == y)
        {
            PORTB.1 = 0;
        }
    else
        if(count == y + 1)
            {
                PORTB.1 = 1;
                pulse_flag++;
            }
 
    // Back lamp
    if(count == z)
        {
            PORTB.2 = 0;
        }
    else
        if(count == z + 1)
            {
                PORTB.2 = 1;
                pulse_flag++;
            }
     
    // Stop timer when all pulses are completed
    if(pulse_flag >= 3)                          // if == 3, they don't work well
        {
            // Clear flag
            pulse_flag = 0;
            // Clear count
            count = 0;
            // Stop the timer
            TCCR0 = 0;
            // Reset the timer
            TCNT0 = 0;
        }  
 }
 
 #define ADC_VREF_TYPE 0x40
 // Read the AD conversion result
 unsigned int read_adc(unsigned char adc_input)
 {
    ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
    // Delay needed for the stabilization of the ADC input voltage
    delay_us(10);
    // Start the AD conversion
    ADCSRA|=0x40;
    // Wait for the AD conversion to complete
    while ((ADCSRA & 0x10)==0);
    ADCSRA|=0x10;
    return ADCW;
 }
 
 void turn_A(unsigned char directionA, int stepA)
 {
    static unsigned char i = 0;
    unsigned int j = 0;
 
    while(j <= stepA)
    {
        j++;
 
        if(directionA)
        {
            i++;
        }
        else
        {
            i--;
        }
 
        if(i == 255)
        {
            i = 3;
        }
        else
            if(i == 4)
            {
                i = 0;
            }
 
        PORTB = motor_stepA[i];
        delay_ms(50);
    }
 }
 
 void display_adc()
 {
        ldr1=read_adc(0);
        lcd_gotoxy(0,0);
        sprintf(buf,"L1:%d%d%d%d",ldr1/1000,(ldr1%1000)/100,(ldr1%1000%100)/10,ldr1%1000%100%10);
        lcd_puts(buf);
        
        ldr2=read_adc(1);
        lcd_gotoxy(9,0);
        sprintf(buf,"L2:%d%d%d%d",ldr2/1000,(ldr2%1000)/100,(ldr2%1000%100)/10,ldr2%1000%100%10);
        lcd_puts(buf);
        
        ldr3=read_adc(2);
        lcd_gotoxy(0,1);
        sprintf(buf,"L3:%d%d%d%d", ldr3/1000,( ldr3%1000)/100,( ldr3%1000%100)/10, ldr3%1000%100%10);
        lcd_puts(buf);
 }
 
 
 void change_intensity()                             // The problem is here, it works well if not connected with motors
 {
        static unsigned int motor_flagA;
        static unsigned int inten_flagA;
        
        // If light intensity below the setpoint, open blinds, and shorten the firing delay
        if((ldr1 <= 500) && (motor_flagA < 1))
        {
            turn_A(ARIGHT,23);
            motor_flagA++;
        }
        
        if((PORTB.0 == 1) && (ldr1 <= 500) && (motor_flagA == 1))
        {
            if(x > 1)
                {  
                    x = x - 1;
                }
        }
        
        // If light intensity greater than the setpoint, increase the firing delay, and close blinds        
        if((PORTB.0 == 1) && (ldr1 >= 550))
        {
            if(x < 280)
                { 
                    x = x + 1;
                    inten_flagA++;
                }
        }
        
        if((ldr1 >= 550) && (inten_flagA == 1) && (motor_flagA == 1))
        {
            turn_A(ALEFT,23);
            motor_flagA = 0;
            inten_flagA = 0;    
        }
           
        // If light intensity below the setpoint, open blinds, and shorten the firing delay
        if((PORTB.1 == 1) && (ldr2 <= 500))
        {
            if(y > 1)
                {
                    y = y - 1;
                }
        }
        
        // If light intensity greater than the setpoint, increase the firing delay, and close blinds
        if((PORTB.1 == 1) && (ldr2 >= 550))
        {
            if(y < 280)
                {
                    y = y + 1;
                }
        }
          
        // If light intensity below the setpoint, open blinds, and shorten the firing delay
        if((PORTB.2 == 1) && (ldr3 <= 500))
        {
            if(z > 1)
                {
                    z = z - 1;
                }
        }
           
        // If light intensity greater than the setpoint, increase the firing delay, and close blinds
        if((PORTB.2 == 1) && (ldr3 >= 550))
        {
            if(z < 280)
                {
                    z = z + 1;
                }
        }
 }
 
 void main(void)
 {
    PORTA=0xFF;
    DDRA=0x00;
    PORTB=0xFF;
    DDRB=0xFF;
    PORTC=0x00;
    DDRC=0x00;
    PORTD=0x00;
    DDRD=0x00;
 
    TCCR0 = 0x02;
    TCNT0 = 0xD3;
    OCR0 = 0x00;
 
    GICR|=0x40;
    MCUCR=0x02;
    MCUCSR=0x00;
    GIFR=0x40;
 
    TIMSK=0x01;
 
    ACSR=0x80;
    SFIOR=0x00;
 
    ADMUX=ADC_VREF_TYPE & 0xff;
    ADCSRA=0x84;
    SFIOR&=0xEF;
 
    lcd_init(16);
 
    // Global enable interrupts
    #asm("sei")
 
    while (1)
      {
      display_adc();
      change_intensity();
      }
 }



But still, when motor is turning, all pulses are disturbed.
 
Last edited:

Great , not you have enabled interrupts everywhere which creates the same atomicity problem for the x, y, z variables :roll:
You got this problem when you decides to move the part that changes x, y, z out of the interrupt and we keep having this problem over and over again.

Study change_intensity() and disable interrupts in the parts that modify x, y, z , I have already explained that in the previous thread
 

You got this problem when you decides to move the part that changes x, y, z out of the interrupt

Well, if I include the part that changes x, y, z back into the interrupt routines, then I don't need to make it atomically anymore? Is that what you mean?

Then, I just confuse, which part of that code I should cut to insert my motors?

One question, can three motors work together at the same time the same as what the three pulses do?
 

So when you read what I wrote https://www.edaboard.com/threads/277411/#post1190420 you can't figure out in which parts of change_intensity() you have to disable interrupts?

One question, can three motors work together at the same time the same as what the three pulses do?

why not if the pulses drive the motor ?
The mcu can do one thing at a time but it can do them so fast that can appear as doing many things simultaneously
 

Ok, I started back again from that point. From this code:

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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
#include <mega8535.h>
 #include <stdio.h>
 #include <delay.h>
 #include <stdint.h>
 #define ALEFT 0
 #define ARIGHT 1
 
 unsigned char buf[10];
 volatile unsigned int ldr1;
 volatile unsigned int ldr2;
 volatile unsigned int ldr3;
 
 unsigned int count = 0;
 volatile bit check_adc = 0;
 
 volatile unsigned int x = 2;
 volatile unsigned int y = 2;
 volatile unsigned int z = 2;
 
 unsigned int motor_stepA[4] = {0b00101000, 0b00110000, 0b01010000, 0b01001000};
 // Next there willl be stepB and step C, since there are three motors
    
 #include <lcd.h>
 #asm
 .equ __lcd_port=0x15 ;PORTC
 #endasm
 
 interrupt [EXT_INT0] void ext_int0_isr(void)
 {
    TCCR0 = 0x02;
 }
 
 interrupt [TIM0_OVF] void timer0_ovf_isr(void)
 {
    static unsigned int pulse_flag = 0;
    TCNT0=0xD3;     
    count++;
    
    // Front lamp
    if(count == x)
        {
            PORTB.0 = 0;
        }
    else
        if(count == x + 1)
            {
                PORTB.0 = 1;
                pulse_flag++;
            }
                
    // Middle lamp        
    if(count == y)
        {
            PORTB.1 = 0;
        }
    else
        if(count == y + 1)
            {
                PORTB.1 = 1;
                pulse_flag++;
            }
 
    // Back lamp
    if(count == z)
        {
            PORTB.2 = 0;
        }
    else
        if(count == z + 1)
            {
                PORTB.2 = 1;
                pulse_flag++;
            }
     
    // Stop timer when all pulses are completed
    if(pulse_flag >= 3)
        {
            // Clear flag
            pulse_flag = 0;
            // Clear count
            count = 0;
            // Stop the timer
            TCCR0 = 0;
            // Reset the timer
            TCNT0 = 0;
            // Update
            check_adc = 1;
        }  
 }
 
 #define ADC_VREF_TYPE 0x40
 unsigned int read_adc(unsigned char adc_input)
 {
    ADMUX=adc_input | (ADC_VREF_TYPE & 0xff);
    delay_us(10);
    ADCSRA|=0x40;
    while ((ADCSRA & 0x10)==0);
    ADCSRA|=0x10;
    return ADCW;
 }
 
 void turn_A(unsigned char directionA, int stepA)
 {
    static unsigned char i = 0;
    unsigned int j = 0;
 
    while(j <= stepA)
    {
        j++;
 
        if(directionA)
        {
            i++;
        }
        else
            {
                i--;
            }
 
        if(i == 255)
        {
            i = 3;
        }
        else
            if(i == 4)
            {
                i = 0;
            }
 
        PORTB = motor_stepA[i];
        delay_ms(50);
    }
 }
 
 void display_adc()
 {
    ldr1=read_adc(0);
    lcd_gotoxy(0,0);
    sprintf(buf,"L1:%d%d%d%d",ldr1/1000,(ldr1%1000)/100,(ldr1%1000%100)/10,ldr1%1000%100%10);
    lcd_puts(buf);
        
    ldr2=read_adc(1);
    lcd_gotoxy(9,0);
    sprintf(buf,"L2:%d%d%d%d",ldr2/1000,(ldr2%1000)/100,(ldr2%1000%100)/10,ldr2%1000%100%10);
    lcd_puts(buf);
        
    ldr3=read_adc(2);
    lcd_gotoxy(0,1);
    sprintf(buf,"L3:%d%d%d%d", ldr3/1000,( ldr3%1000)/100,( ldr3%1000%100)/10, ldr3%1000%100%10);
    lcd_puts(buf);
 }
 
 void change_intensity()
 {
    if(check_adc == 1)
    {
        // If light intensity below the setpoint, open blinds, and shorten the firing delay    
        if((PORTB.0 == 1) && (ldr1 <= 300))
        {
            if(x > 1)
            {  
                x = x - 1;
            }
        }
        
        // If light intensity greater than the setpoint, increase the firing delay, and close blinds        
        if((PORTB.0 == 1) && (ldr1 >= 350))
        {
            if(x < 280)
            { 
                x = x + 1;
            }
        }
 
           
        // If light intensity below the setpoint, open blinds, and shorten the firing delay
        if((PORTB.1 == 1) && (ldr2 <= 300))
        {
            if(y > 1)
            {
                y = y - 1;
            }
        }
        
        // If light intensity greater than the setpoint, increase the firing delay, and close blinds
        if((PORTB.1 == 1) && (ldr2 >= 350))
        {
            if(y < 280)
            {
                y = y + 1;
            }
        }
          
        // If light intensity below the setpoint, open blinds, and shorten the firing delay
        if((PORTB.2 == 1) && (ldr3 <= 300))
        {
            if(z > 1)
            {
                z = z - 1;
            }
        }
           
        // If light intensity greater than the setpoint, increase the firing delay, and close blinds
        if((PORTB.2 == 1) && (ldr3 >= 350))
        {
            if(z < 280)
            {
                z = z + 1;
            }
        }
         
        check_adc = 0;
    }
 }
 
 void main(void)
 {
    PORTA=0xFF;
    DDRA=0x00;
    PORTB=0xFF;
    DDRB=0xFF;
    PORTC=0x00;
    DDRC=0x00;
    PORTD=0x00;
    DDRD=0x00;
 
    TCCR0 = 0x02;
    TCNT0 = 0xD3;
    OCR0 = 0x00;
 
    GICR|=0x40;
    MCUCR=0x02;
    MCUCSR=0x00;
    GIFR=0x40;
    TIMSK=0x01;
 
    ADMUX=ADC_VREF_TYPE & 0xff;
    ADCSRA=0x84;
    SFIOR&=0xEF;
 
    lcd_init(16);
    #asm("sei")
 
    while (1)
      {
        display_adc();
        #asm("cli")
        change_intensity();         // It contains only the part that change x, y, and z for the lamps. Now I need to add something so that before changing x, y, or z, it will turn the motor first. Do I need to make new function then call it or make combination here ??
        #asm("sei")
      }
 }




The pulses are used to trigger the triacs (3 triacs). Now, I need to add three stepper motor so it will work like:

Code:
If(adc <= setpoint)     // means the light intensity below setpoint
{
      turn(LEFT, 48)               // motor turn 48 step first
      If(adc is still <= setpoint)
      {
          turn(LEFT,48)            // motor turn 48 step again
          if((adc still <= setpoint) and (motor already turned 96 steps)), then change x, or, y, or z
          {
                decrease the firing delay    // lamp ON and getting brighter
          }
      }
}

If(adc >= setpoint)
{
      increase the firing delay          // dim the lamp first change x, or, y, or z, left the motor not work
      If((adc is still >= setpoint) and (x, or y, or z, already in their max value))
      {
          turn(RIGHT,48)                  // motor turn 48 step in other direction
          if(adc still greater than 890)
          {
                turn(RIGHT, 48)           // motor turn 48 step again in other direction
          }
      }
}

Do I need to make more pulses to drive the motors?
 

#asm("cli")
change_intensity();
#asm("sei")

That is not what I told you to do , I told you to identify which parts of the function need to run without being interrupted and disable interrupts for them but you have removed half the code from the function and applied cli() for the complete function and now you are searching again where to place the moved code.
 

All of these should not be interrupted right ??

Code:
        if((PORTB.0 == 1) && (ldr1 <= 300))
        {
            if(x > 1)
            {  
                x = x - 1;
            }
        }
        
        if((PORTB.0 == 1) && (ldr1 >= 350))
        {
            if(x < 280)
            { 
                x = x + 1;
            }
        }
 
        if((PORTB.1 == 1) && (ldr2 <= 300))
        {
            if(y > 1)
            {
                y = y - 1;
            }
        }
        
        if((PORTB.1 == 1) && (ldr2 >= 350))
        {
            if(y < 280)
            {
                y = y + 1;
            }
        }
      
        if((PORTB.2 == 1) && (ldr3 <= 300))
        {
            if(z > 1)
            {
                z = z - 1;
            }
        }

        if((PORTB.2 == 1) && (ldr3 >= 350))
        {
            if(z < 280)
            {
                z = z + 1;
            }
        }
 

Yes, but that doesn't mean to remove everything else from the function and apply cli() to the complete function, just place the parts that need it between cli() sei()
 

Ok, if so then:

Code:
 void change_intensity()     // Will only containing the part that should not be interrupted
 {
        if((PORTB.0 == 1) && (ldr1 <= 300))
        {
            if(x > 1)
            {  
                x = x - 1;
            }
        }
        
        if((PORTB.0 == 1) && (ldr1 >= 350))
        {
            if(x < 280)
            { 
                x = x + 1;
            }
        }
 
        if((PORTB.1 == 1) && (ldr2 <= 300))
        {
            if(y > 1)
            {
                y = y - 1;
            }
        }
        
        if((PORTB.1 == 1) && (ldr2 >= 350))
        {
            if(y < 280)
            {
                y = y + 1;
            }
        }
      
        if((PORTB.2 == 1) && (ldr3 <= 300))
        {
            if(z > 1)
            {
                z = z - 1;
            }
        }

        if((PORTB.2 == 1) && (ldr3 >= 350))
        {
            if(z < 280)
            {
                z = z + 1;
            }
        }
 }



and next it will be ok to use:
Code:
#asm("cli")
change_intensity(); // since now it's only containing the part that should not be interrupted and need only about 17 us
#asm("sei")

Am I right?

Next, how do I make this works like post #15 ? the second part.
 

This still leaves you wondering where to place the motor code.
Revert the function as it was in post #11 and just place the parts that need it inside cli() sei().
Use then in selected parts inside the function.
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top