-
Notifications
You must be signed in to change notification settings - Fork 0
/
progetto.c
629 lines (572 loc) · 16.2 KB
/
progetto.c
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
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
#include <c8051f020.h> // SFR definitions
//---------------------------------------------------VARIABILI GENERALI-----------------------------------------------------------------------
//quante volte va in overflow
unsigned char t3_overflow_display = 0;
unsigned char t3_overflow_temp = 0;
//flag che indicano che va servito l'smbus per le varie periferiche
unsigned char flag_mma = 0;
unsigned char flag_temp = 0;
unsigned char flag_display = 0;
//indica che il bus è occupato da una periferica
unsigned char smBusy = 0;
//tipo di azione che deve fare smbus
// 0 = mma, 1 = display, 2 = temperatura
unsigned char interrupt_type = 0;
//---------------------------------------------------VARIABILI PWM----------------------------------------------------------------------------
//bottone e retroilluminazione
sbit button = P3^7;
sbit backlight = P0^6;
//contatore per overflow timer1
unsigned char t1overFlow = 0;
// 0 = bottone non premuto, 1 = bottone premuto
unsigned char premuto = 0;
//se è passato più di un secondo da quando il bottone è stato premuto
unsigned char unSec = 0;
//schermo accesso o spento
unsigned char acceso = 1;
//variabili per controllare la luminosità
unsigned char lumi;
char lumiStep = 1;
//-------------------------------------------------COSTANTI PERIFERICHE-----------------------------------------------------------------------
#define SMB_START 0x08 //ricevuto start
#define SMB_RESTART 0x010 //ricevuto restart
#define SMB_FIRSTWRITE 0x18 //scrivo il primo valore
#define SMB_WRITE 0x28 // scrivo gli altri valori
#define SMB_FIRSTREAD 0x40 //primo read
#define SMB_READ 0x50 //altri read
#define SMB_READ_NACK 0x58 //dopo che ho dato AA = 0
#define MMA_WRITE 0x98 //indirizzo per scrivere sull'accelerometro
#define MMA_READ 0x99 //indirizzo per leggere dall'accelerometro
#define TEMP_READ 0x91 //indirizzo per leggere dal termometro
#define DISPLAY_WRITE 0x7c //indirizzo per leggere dal display
//-------------------------------------------------VARIABILI ACCELEROMETRO--------------------------------------------------------------------
//definizione registri accelerometro
#define XOUT 0x00
#define YOUT 0x01
#define ZOUT 0x02
#define MODE 0x07
//valori per inizializzare accelerometro
unsigned char mma_init [] = {MODE, 0x01};
unsigned char mma_pos = 0;
unsigned char mma_init_finished = 0;
//mma può iniziare a leggere
unsigned char mma_read_ready = 0;
//buffer per i valori letti dall'accelerometro
char buffer_x[8] = {0, 0, 0, 0, 0, 0, 0, 0};
char buffer_y[8] = {0, 0, 0, 0, 0, 0, 0, 0};
char buffer_z[8] = {0, 0, 0, 0, 0, 0, 0, 0};
unsigned char buffer_pos = 0;
int mma_value_read = 0;
int i = 0;
//memorizzazione temporanea di x y z
float xyz[3];
unsigned char xyz_mma_pos = 0;
//variabili per la media
unsigned char avg_cont = 0;
int avg_x = 0;
int avg_y = 0;
int avg_z = 0;
//array per la conversione dei valori letti dall'accelerometro
float TILT_XY[64] = {0, 2.69, 5.38, 8.08, 10.81, 13.55, 16.33, 19.16, 22.02, 24.95, 27.95, 31.04, 34.23, 37.54, 41.01, 44.68, 48.59, 52.83, 57.54, 62.95, 69.64, 79.86, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, -79.86, -69.64, -62.95, -57.54, -52.83, -48.59, -44.68, -41.01, -37.54, -34.23, -31.04, -27.95, -24.95, -22.02, -19.16, -16.33, -13.55, -10.81, -8.08, -5.38, -2.69};
float TILT_Z[64] = {90.00, 87.31, 84.62, 81.92, 79.19, 76.45, 73.67, 70.84, 67.98, 65.05, 62.05, 58.96, 55.77, 52.46, 48.99, 45.32, 41.41, 37.17, 32.46, 27.05, 20.36, 10.14, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -10.14, -20.36, -27.05, -32.46, -37.17, -41.41, -45.32, -48.99, -52.46, -55.77, -58.96, -62.05, -65.05, -67.98, -70.84, -73.67, -76.45, -79.19, -81.92, -84.62};
//--------------------------------------------------------VARIABILI DISPLAY-------------------------------------------------------------------
//valori per inizializzare il display
unsigned char display_init_values[] = {0x38, 0x39, 0x14, 0x74, 0x54, 0x6F, 0x0C, 0x01};
//valori prima riga
unsigned char display_values[] = {0x80, 0x01, 0x40, 'T',':', '0', '0', 0xF2, 'C'};
//valori seconda riga
unsigned char display_values2[] = {0x80, 0xC0, 0x40, 'X', ':', '0' , '0', ' ', 'Y', ':', '0', '0', ' ', 'Z', ':', '0', '0'};
//variabile che indica se l'init è finito
unsigned char display_init = 0;
unsigned char display_init_pos = 0;
unsigned char cont = 0;
unsigned char write_finished = 0;
//indica se devo scrivere sulla prima o sulla seconda linea
unsigned char second_line = 0;
//-------------------------------------------------VARIABILI TEMPERATURA----------------------------------------------------------------------
//parte alta e bassa della temperatura
int tempH = 0;
int tempL = 0;
//variabile che indica se ho letto la parte alta della temperatura
unsigned char readH = 0;
float temp_float = 0;
int temp_int = 0;
int decine = 0;
int unita = 0;
/*
**********************************************************************************************************************************************
*********************************************************PROGRAMMA****************************************************************************
**********************************************************************************************************************************************
*/
void init (void)
{
//abilita iinterrupt globali
EA = 1;
//disabilita watchdog timer
WDTCN = 0xde;
WDTCN = 0xad;
//oscillatore
OSCICN &= 0x14;
//clock interno
XBR0 = 0x00;
//abilita smbus e uart ( per spostare i pin)
XBR0 |= 0x05;
//crossbar, gestisce i pin
XBR1 = 0x00;
XBR2 = 0x40;
//push-pull
P1MDOUT |= 0x40;
//push pull display
P0MDOUT |= 0x40;
//per l'interrupt del bottone
EIE2 |= 0x20;
//iinterrupt del smbus
EIE1 |= 0x02;
//abilita smbus
ENSMB = 1;
AA = 1;
}
void timer3_init()
{
TMR3H = 0xbe;
TMR3L = 0xe6;
//abilita iinterrupt timer3
EIE2 |= 0x01;
//fa partire il timer 3
TMR3CN |= 0x04;
}
void mma_initialize()
{
flag_mma = 1;
STA = 1;
while(!mma_init_finished);
mma_init_finished = 2;
flag_mma = 0;
smBusy = 0;
//corrisponde a nessuna azione da fare su smbus
interrupt_type = 99;
}
void timer3() interrupt 14
{
t3_overflow_display ++;
t3_overflow_temp ++;
//ogni volta che va in overflow (100ms)
flag_mma = 1;
//quando passano 300ms
if(t3_overflow_display == 3)
{
flag_display = 1;
t3_overflow_display = 0;
}
//quando passa 1 secondo
if(t3_overflow_temp == 10)
{
flag_temp = 1;
t3_overflow_temp = 0;
}
TMR3H = 0xbe;
TMR3L = 0xe6;
//resetta flag overflow
TMR3CN &= 0x7f;
}
/*
**********************************************************************************************************************************************
*********************************************************GESTIONE PWM*************************************************************************
**********************************************************************************************************************************************
*/
//resetta il timer 2 senza fermarlo
void resetTimer2()
{
TF2 = 0;
TH2 = 0xf9;
TL2 = 0x7e;
}
void setLumi()
{
resetTimer2();
TR2 = 1;
}
//quando il timer va in iinterrupt sono passati 200 ms, incrementa di poco la luminosità del display
void timer2() interrupt 5
{
lumi = lumi + lumiStep;
if(lumi == 255)
lumiStep = -1;
else if (lumi == 0)
lumiStep = 1;
resetTimer2();
}
//resetta il timer per contare 200ms, e t1overFlow a 0 per contare 1 secondo
void resetTimer1()
{
t1overFlow = 0;
TF1 = 0;
TH1 = 0x7d;
TL1 = 0xcb;
TR1 = 0;
}
//imposta il necessario per il programma
void pwm_setup()
{
//timer 0 a 8 bit, timer 1 a 16 bit
TMOD = 0x10;
//clock intero per il timer0
CKCON = 0x8;
//luminosità iniziale del display, 0 = luminosità massima
lumi = 0;
//abilita gli interrupt di timer0, timer1 e timer2
ET0 = 1;
ET1 = 1;
ET2 = 1;
//imposta il valore iniziale del timer 1 (conta 200 ms)
TH1 = 0x7d;
TL1 = 0xcb;
//fa partire il timer 0 che gestisce pwm
TR0 = 1;
}
//interrupt del timer0
void timer0() interrupt 1
{
//il backlight lampeggia solo se la variabile è a 1
if (acceso == 1)
{
if (!backlight) {
backlight = 1; // cambia stato display
TH0 = lumi;
TF0 = 0;
}
else {
backlight = 0;
TH0 = 255 - lumi;
TF0 = 0;
}
}
}
void buttonInt() interrupt 19
{
//se non stavo premendo il bottone e lo premo
if(premuto == 0)
{
//fa partire il timer che deve contare 1 secondo
TR1 = 1;
//resetta l'interrupt
EIE2 |= 0x20;
P3IF &= 0x7f;
//cambia in rising edge per avere un interruptt al rilascio del bottone
P3IF |= 0x08;
premuto = 1;
}
//se sto premendo il bottone e quando rilascio non è passato un secondo, deve cambiare lo stato del display
else if (premuto == 1 && unSec == 0)
{
//resetto l'interrupt
EIE2 |= 0x20;
P3IF &= 0x7f;
//rimette in falling edge il bottone
P3IF &= 0x77;
//cambio stato display
acceso = !acceso;
backlight = 0;
premuto = 0;
unSec = 0;
//resetto e disabilito il timer
resetTimer1();
}
//se lascio il bottone ma è passato più di un secondo
else if (premuto == 1 && unSec == 1)
{
//devo fermare il timer2 usato per regolare la luminosità
TR2 = 0;
resetTimer2();
premuto = 0;
unSec = 0;
//resetta e disabilito il timer
resetTimer1();
//resetta l'interrupt
EIE2 |= 0x20;
P3IF &= 0x7f;
//rimette in falling edge il bottone
P3IF &= 0x77;
}
}
void timer1() interrupt 3
{
t1overFlow++;
//se il contatore è a 5 significa che è passato 1 secondo
if(t1overFlow == 5)
{
//fermo il timer
resetTimer1();
unSec = 1;
//imposto la luminosità solo se il bottone è acceso
if (acceso == 1)
{
setLumi();
}
}
else
{
TF1 = 0;
TH1 = 0x7d;
TL1 = 0xcb;
}
}
/*
**********************************************************************************************************************************************
*********************************************************ACCELEROMETRO************************************************************************
**********************************************************************************************************************************************
*/
void accelerometer_interrupt()
{
if(mma_pos == sizeof(mma_init))
{
mma_pos = 0;
mma_init_finished = 1;
STO = 1;
}
switch(SMB0STA)
{
case SMB_START:
SMB0DAT = MMA_WRITE;
STA = 0;
break;
//gli devo dare indirizzo del registro da leggere
case SMB_RESTART:
SMB0DAT = MMA_READ;
STA = 0;
break;
case SMB_FIRSTWRITE:
case SMB_WRITE:
//se sta facendo l'init
if(mma_init_finished == 0)
{
SMB0DAT = mma_init[mma_pos];
mma_pos++;
}
//se sta leggendo x y z
else if(mma_init_finished == 2)
{
if(!mma_read_ready)
{
SMB0DAT = XOUT;
//dice che mma è pronto a leggere
mma_read_ready = 1;
}
else
STA = 1;
}
break;
case SMB_FIRSTREAD:
STA = 0;
break;
case SMB_READ:
mma_value_read = SMB0DAT;
mma_value_read &= 00111111;
//converte i valori letti in gradi
xyz[xyz_mma_pos] = TILT_XY[mma_value_read];
if(xyz_mma_pos == 1)
AA = 0;
xyz_mma_pos++;
break;
// legge z e inserisce nel buffer x y z
case SMB_READ_NACK:
mma_value_read &= 00111111;
xyz[xyz_mma_pos] = TILT_Z[mma_value_read];
STO = 1;
AA = 1;
//reset flag e variabili
smBusy = 0;
flag_mma = 0;
mma_read_ready = 0;
xyz_mma_pos = 0;
buffer_x[buffer_pos] = xyz[0];
buffer_y[buffer_pos] = xyz[1];
buffer_z[buffer_pos] = xyz[2];
if(buffer_pos == 7)
buffer_pos = 0;
else
buffer_pos ++;
}
SI = 0;
}
/*
**********************************************************************************************************************************************
*********************************************************DISPLAY******************************************************************************
**********************************************************************************************************************************************
*/
void display_interrupt()
{
switch(SMB0STA)
{
case SMB_START:
cont = 0;
SMB0DAT = DISPLAY_WRITE; // carica indirizzo slave display
STA = 0;
break;
case SMB_FIRSTWRITE:
case SMB_WRITE:
//se sta facendo l'init
if(display_init == 0)
{
SMB0DAT = display_init_values[display_init_pos];
display_init_pos++;
}
//scritture successive all'init
else if (display_init == 2)
{
//scrittura prima riga
if(second_line == 0)
{
SMB0DAT = display_values[cont];
if(cont == sizeof(display_values))
{
STO = 1;
STA = 1;
second_line = 1;
}
cont++;
}
//scrittura seconda riga
else
{
SMB0DAT = display_values2[cont];
if(cont == sizeof(display_values2))
{
STO = 1;
smBusy = 0;
flag_display = 0;
second_line = 0;
}
cont++;
}
}
break;
}
SI = 0;
if (display_init == 1)
{
display_init = 2;
smBusy = 0;
}
else if (display_init_pos == sizeof(display_init_values))
{
display_init_pos = 0;
display_init = 1;
STO = 1;
flag_display = 0;
}
}
/*
**********************************************************************************************************************************************
*********************************************************TERMOMETRO***************************************************************************
**********************************************************************************************************************************************
*/
void temp_interrupt()
{
switch(SMB0STA)
{
case SMB_START:
SMB0DAT = TEMP_READ;
STA = 0;
break;
case SMB_FIRSTREAD:
STA = 0;
break;
case SMB_READ:
//se sta leggendo la parte alta della temperatura
if(readH == 0)
{
tempH = SMB0DAT;
readH = 1;
}
else
{
//calcola la parte bassa della temperatura
tempL = SMB0DAT;
temp_int = (tempH << 8 | tempL);
//converte la temperatura in gradi centigradi
temp_float = (float)( temp_int >> 3 ) / 16;
//per scrivere sul display estraggo decine e unità
decine = (int)temp_float / 10 + 48;
unita = (int)temp_float % 10 + 48;
//sostituisco i valori nell'array della prima riga del display
display_values[5] = (char)decine;
display_values[6] = (char)unita;
STO = 1;
smBusy = 0;
readH = 0;
flag_temp = 0;
}
break;
}
SI = 0;
}
//viene servito l'interrupt in base al settaggio dei flag
void smBus() interrupt 7
{
if(interrupt_type == 0)
accelerometer_interrupt();
else if (interrupt_type == 1)
display_interrupt();
else if (interrupt_type == 2)
temp_interrupt();
}
//media delle ultime 8 misure di x, y e z
void average_xyz()
{
//somma i valori nei buffer
for(avg_cont = 0; avg_cont < sizeof(buffer_x); avg_cont++)
{
avg_x += buffer_x[avg_cont];
avg_y += buffer_y[avg_cont];
avg_z += buffer_z[avg_cont];
}
//fa la media di ogni asse
avg_x /= sizeof(buffer_x);
avg_y /= sizeof(buffer_y);
avg_z /= sizeof(buffer_z);
//scrive i valori nell'array della seconda riga del display
display_values2[5] = (char)(avg_x / 10 + 48);
display_values2[6] = (char)(avg_x % 10 + 48);
display_values2[10] = (char)(avg_y / 10 + 48);
display_values2[11] = (char)(avg_y % 10 + 48);
display_values2[15] = (char)(avg_z / 10 + 48);
display_values2[16] = (char)(avg_z % 10 + 48);
}
/*
**********************************************************************************************************************************************
*********************************************************MAIN*********************************************************************************
**********************************************************************************************************************************************
*/
void main()
{
//init vari
init();
pwm_setup();
mma_initialize();
timer3_init();
//serve la periferica solo se il suo flag è a 1, e se il bus è libero
while(1)
{
if(flag_mma && !smBusy){
interrupt_type = 0;
STA = 1;
smBusy = 1;
}
if (flag_display && !smBusy){
interrupt_type = 1;
STA = 1;
smBusy = 1;
}
if (flag_temp && !smBusy){
interrupt_type = 2;
STA = 1;
smBusy = 1;
}
//se nessun flag è alzato c'è tempo per fare la media
if(!flag_mma && !flag_display && !flag_temp)
average_xyz();
}
}