Simons Inserito: 9 settembre 2007 Segnala Inserito: 9 settembre 2007 Salve a tutti dovrei realizzare un piccolo PWM con il 16f876a e ho notato con gran gioia che il pic in questione possiede già il modulo PWM integrato!ho provato a settare i parametri per avere la frequenza 1khz (usando il CCS C COMPILER con il wizard) però ho visto che posso impostare frequenze tipo 1.250hz e simili...ho visto che il pwm usa l'interrupt del timer2. Per avere una frequenza di 1khz, come posso impostare i vari parametri?qualcuno mi dà una mano? D:
dlgcom Inserita: 9 settembre 2007 Segnala Inserita: 9 settembre 2007 Ciao,Per il pwm , hai due parametri da configurare .Il periodo che ti da la frequenza del pwmquesto lo regoli con la formulaPWM Period = [(PR2) + 1] • 4 • TOSC • (TMR2 Prescale Value)Poi devi regolare il duty cycle che in base alla risoluzione del tuo pwm saraPWM Duty Cycle =(CCPR1L:CCP1CON<5:4>) •TOSC • (TMR2 Prescale Value)Nota che il registro CCPR1L e i bit 4,5 del CCP1CON diventano un registro a 10 bit.trovi tutto nel DATASHEETSe hai dubbi chiedi.
walterword Inserita: 17 settembre 2007 Segnala Inserita: 17 settembre 2007 se usi il compilatore CCS avrai sicuramente delle funzioni predisposteIo avevo le stesse cose nel C30 , ma poi alla fine ho preferito leggermi il datasheet ed i manuali reference e conoscere i registri , i bit ect e farmelo Fai come ti consiglia DLGCOMciao walter
Simons Inserita: 24 settembre 2007 Autore Segnala Inserita: 24 settembre 2007 vi ringrazio delle risposte...ho controllato i datasheet del 16f876a e ha 2 moduli ccp però pilotabili entrambi contemporaneamente con la stessa frequenza.io avrei bisogno di 4 uscite pwm (tutte alla stessa frequenza di 1-2Khz o comunque vicina) però che variano il duty.suppongo che vada fatto tutto via software...ora vi chiedo: per fare il pwm sfrutto l'interrupt dei vari timer (ad es il tmr0 o il tmr1 o tmr2 del pic oppure gestisco in altro modo?utilizzando un quarzo a 20Mhz, la frequenza utile è 5mhz e l'interrupt con prescaler a 1 dovrebbe essere intorno ai 51 microsecondi. Come sfrutto questa cosa a mio vantaggio?grazie 1000 a tutti
Simons Inserita: 24 settembre 2007 Autore Segnala Inserita: 24 settembre 2007 utilizzo CCS C Compiler (PCW)non è che potreste postare qualche routine di esempio per più di 2 pwm?grazie 1000
Simons Inserita: 25 settembre 2007 Autore Segnala Inserita: 25 settembre 2007 (modificato) ho provato a sviluppare una routine in CCS C per 3 servi usando l'interrupt del timer2 settato in modo che faccia l'interrupt ogni 10us così contando fino a 100 ho 1khz (giusto? )la routine è questa:ditemi se si può migliorare T1,T2,T3 sono i dutycyclei vari txon e off sono i tempi relativi alle varie forme d'onda.T1,T2 e T3 le imposto dal main e txon e off vengono assegnati da una routine CalcolaDuty che non fa altro che assegnare, ad es, a t1on=T1 e t1off=100-T1 TIMER2_isr() { //ogni 10 us fa un interrupt if(t1on>0) { output_high(SERVO1); t1on--; } else { if(t1off<=0) { t1on=T1; t1off=100-T1; } else { output_low(SERVO1); t1off--; } } if(t2on>0) { output_high(SERVO2); t2on--; } else { if(t2off<=0) { t2on=T2; t2off=100-T2; } else { output_low(SERVO2); t2off--; } } if(t3on>0) { output_high(SERVO3); t3on--; } else { if(t3off<=0) { t3on=T3; t3off=100-T3; } else { output_low(SERVO3); t3off--; } } }grazie 1000 Modificato: 25 settembre 2007 da Simons
Simons Inserita: 26 settembre 2007 Autore Segnala Inserita: 26 settembre 2007 Ho provato la routine che avevo scritto prima e funziona. non ho avuto modo di controllare la precisione della frequenza degli impulsi, stasera controllerò anche quella.l'unico errore è questo:in ognuna delle mini-routine per ogni servo, c'è da togliere la riga commentata in grassetto altrimenti quando raggiunge lo zero farà un microimpulso della durata dell'interrupt. if(t1on>0) { output_high(SERVO1); t1on--; } else { if(t1off<=0) { t1on=T1; t1off=100-T1; //output_high(SERVO1); } else { output_low(SERVO1); t1off--; } }per il resto ho fatto in modo di avere già su T1 il duty settando l'interrupt a 10us così se metto 50 su T1 la frequenza è 1khz con d.c. 50%saluti
Simons Inserita: 26 settembre 2007 Autore Segnala Inserita: 26 settembre 2007 mi sono accorto di un problema.Siccome nella scheda che sto usando ci sono un display LCD e una tastiera a matrice, quando faccio l'interrupt a 10us col timer2, questo mi impegna tutte le risorse bloccando qualsiasi altra operazione (scrittura LCD, lettura tastiera ecc...)ho aumentato l'interrupt a 100us però a discapito della precisione del duty cycle. adesso ho 10 passi di regolazione invece che 100. per averne 100 ho provato a lavorare con i float, ma il programma diventa pesante e non gira come dovrebbe.avete qualche suggerimento utile?grazie 1000
Simons Inserita: 27 settembre 2007 Autore Segnala Inserita: 27 settembre 2007 ho effettuato le misure con un oscilloscopio dell'onda risultante con l'interrupt a 100us.la frequenza effettiva è intorno agli 880 hertz e il duty se imposto la variabile a 50 è sempre 40% .. per il problema del duty credo sia perchè fa il conteggio una volta in meno per t1onper la frequenza sballata: è possibile che con un interrupt a 100us (così mi dice il wizard di CCS compiler) abbia così tanta differenza da 1khz?qualcuno mi aiuta please?
Livio Orsini Inserita: 29 settembre 2007 Segnala Inserita: 29 settembre 2007 Che cosa usi per generare il clock? Quarzo? Risonatore? RC?Come hai programmato il timer? Se hai sbaglaito programmazione del timer è normale che succeda il fenomeno che descrivi. Io solitamente lavoro con quarzo a 20mHz e ti grantisco che non ho mai avuto errori sui timer, a meno di errori di programamzione.
Simons Inserita: 30 settembre 2007 Autore Segnala Inserita: 30 settembre 2007 (modificato) Livio Orsini+29/09/2007, 16:57--> (Livio Orsini @ 29/09/2007, 16:57)grazie della risposta uso un quarzo a 20Mhz l'interrupt lo prendo dal timer2 settato con risoluzione 0.2us overflow=50 interrupt period=10 e su ccs compiler veniva scritto "100us"può dipendere dal fatto che il pic ci mette troppo a fare le istruzioni nella routine di interrupt?edit: una soluzione alternativa: mettendo la risoluzione del timer0 a 0.4us viene fuori un interrupt di 102.4us se nella routine di interrupt imposto il timer0 a 6 ogni volta fa 6 conti in meno ovvero 6*0.4=2.4us no? c'è la funzione set_timer0(6) che setta il timer a 6.se riesci ad aiutarmi questo problema te ne sarò molto grato Modificato: 30 settembre 2007 da Simons
Livio Orsini Inserita: 30 settembre 2007 Segnala Inserita: 30 settembre 2007 // 20 mhz clock, no prescaler, set timer 0 // to overflow in 35us set_timer0(81); // 256-(.000035/(4/20000000)) Questo è un esempio trato dal manuale CCS, genera un interrupt ogni 35us. Il timer conta gli impulsi per arrivare a 256 e generare un interrpt, poi riparte da 0 quindi devi ricaricarlo. Nel tuo caso, dovendo contare 500 impulsi e, se ricordo bene, timer2 ha solo un registro da 8 bits, devi fare due conteggi: uno da 256 impulsi e uno da 244 impulsi; quindi carichi 12, attendi interrupt senza ricaricare e sul secondo interrupt ricarichi 12, ottieni 100us.Attenzione che ogni istruzione asm impiega 0.2us quindi tra un interrupt e l'altro da 100us puoi eseguire complessivamente <500 istruzioni. Io uso asm nelle routines di interupts dei timer, proprio per minimizzare l'impiego di CPU
Simons Inserita: 1 ottobre 2007 Autore Segnala Inserita: 1 ottobre 2007 Livio Orsini+30/09/2007, 11:57--> (Livio Orsini @ 30/09/2007, 11:57) grazie.. però pensavo.. l'interrupt che mi serve è 50us e non 100us altrimenti non riesco a generare 1kh ma 500hzquindicon il timer settato a 0.2usse nella routine di interrupt imposto il timer0 a 6 ogni volta fa 6 conti in meno ovvero 6*0.4=1.2us no? quindi 51.2-1.2=50us di interrupt.in questo modo riesco a suddividere l'onda quadra in 20 "parti" così da avere un duty variabile del 5% anzichè del 10%.rimane però il problema della durata dell'interrupt. se le istruzioni eccedono il tempo dell'interrupt cosa succede?
Livio Orsini Inserita: 1 ottobre 2007 Segnala Inserita: 1 ottobre 2007 Se imposti timer2 a 6 (tanto per usare il tuo timer) questo conterà 250 impulsi (250+6 = 256), poi genererà l'interrupt di overflow. In questo Interrupt dovrai ricaricare 6, in modo da avere sempre 50us di intervallo (250*0.2us = 50us).Due consigli.Primo. leggiti bene il manuale del 16F877 al capitolo dei timer.Secondo. Nella routine di interrupt, alla prima riga, scrivi #ASM e prosegui con istruzioni in assembler, poi termina con #endasm el'ultima grafa, così sei sicuro di aver minimizzato le istruzioni. Ricorda che tra due interrupt da 50us di intervallo il micro eseguirà solo 250 istruzioni in tutto.
Simons Inserita: 1 ottobre 2007 Autore Segnala Inserita: 1 ottobre 2007 Livio Orsini+1/10/2007, 12:41--> (Livio Orsini @ 1/10/2007, 12:41) dunque.. ho cambiato timer. sto usando il timer0...allora... inserendo nella routine di servizio l'istruzione set_rtcc(6); il periodo dell'interrupt viene modificato.addirittura seguendo le righe di codice del manuale CCS l'interrupt non è a 35us ma a 43 e rotti.settando il timer con RTCC_INTERNAL e RTCC_DIV_1nell'interrupt eseguo queste semplici operazioni giusto per fare un test:#int_RTCCRTCC_isr(){ set_rtcc(6); output_high(SERVO2); output_low(SERVO2);}se tolgo set_rtcc(6); l'interrupt è preciso spaccato a 51.2 usse invece metto set_rtcc(6); l'interrupt si allarga a 57us, quasi come se prima facesse l'interrupt e accodasse ai 256 conteggi altri 6 conteggi.ho scoperto dal manuale che modificando manualmente il valore del rtcc, il prescaler si resetta. ma non capisco allora cosa ci sta a fare la funzione set_rtcc();chiedo lumi... ho i fuses settati così:#device adc=8#use delay(clock=20000000)#fuses NOWDT,HS, NOPUT, NOPROTECT, NODEBUG, BROWNOUT, NOLVP, NOCPD, NOWRTcosa sbaglio? non riesco a capire
Simons Inserita: 4 ottobre 2007 Autore Segnala Inserita: 4 ottobre 2007 ho provato a sostituire le funzioni setup_rtcc() e le altre con le corrispettive in assembler, ma non è cambiato nulla...suggerimenti?
Livio Orsini Inserita: 5 ottobre 2007 Segnala Inserita: 5 ottobre 2007 ..... setup_counters(RTCC_INTERNAL,RTCC_DIV_4); setup_timer_1(T1_INTERNAL); set_timer1(0x3caf); //Caricato 65.535 - 50.000 = 15.535(0x3CAF) //==> 50.000 * 4 * 50nsec = 10msec ...... #int_timer1 void Timer10ms() { set_timer1(0x3caf); // Caricato 15535 ==> // 50.000 * 4 * 50nsec = 10msec // 65535 - 50000 = 15535(0x3caf) .... Questo è il codice di inizializzazione e l'incipit di una routine di interrutpt a tempo che uso io da sempre. Il compilatore è CCS, il quarzo è da 20MHz. Ti garantisco che non ci sono variazioni di tempo apprezzabili. Usando altri timer devi verificare se sono da 8 o da 16 bit.
Simons Inserita: 8 ottobre 2007 Autore Segnala Inserita: 8 ottobre 2007 mi spiace rompere ancora con questo cavolo di timer...ho usato la tua routine e l'interrupt lo fa preciso a 10msecho fatto un paio di test dimezzando via via il tempo e sono arrivato a 250microsecondi netti.ho provato a farlo a 100microsecondi settando il timer a:65535-(100us/(50ns*4))=65035 (FE0B)con risultato un interrupt a 108microsecondi. ho provato a riportarlo a 500microsecondi e ho ottenuto 508microsecondi. portato a 200 e ho 208microsecondi...questa la mia routine:#int_TIMER1TIMER1_isr(){ set_timer1(0xFE0B); //Setto il timer output_high(PIN_A2); //alzo la linea output_low(PIN_A2); //la abbasso subito}non so più dove sbattere la testa... sto cominciando a dare di fuori...vi farò un monumento se risolvo il problema
Livio Orsini Inserita: 9 ottobre 2007 Segnala Inserita: 9 ottobre 2007 (modificato) Ma tu stai programmando il timer a 400.8 us. FE0B ==> 65035 ==> 65536 - 65035 = 501 ==> 501*4*200ns = 400.8us Modificato: 9 ottobre 2007 da Livio Orsini
Simons Inserita: 9 ottobre 2007 Autore Segnala Inserita: 9 ottobre 2007 Livio Orsini+9/10/2007, 11:56--> (Livio Orsini @ 9/10/2007, 11:56) non capisco il conto che hai fatto...io ho fatto 65535-65035=500e secondo il conto che hai postato prima: //==> 50.000 * 4 * 50nsec = 10msecverrebbe 500*4*50nsec = 100us
Livio Orsini Inserita: 9 ottobre 2007 Segnala Inserita: 9 ottobre 2007 Hai ragione, ho fatto un po' di confusione con il clock, moltiplicando 2 volte per 4 ecomplementando a 0 e non a FFFF; si vede che questa mattina pensavo a chissà che cosa.Gli 8us in più sembrano 40 istruzioni, però il timer lo ricarichi subito....Prova, come verifica, a scrivere#int_TIMER1TIMER1_isr(){set_timer1(0xFE0B); //Setto il timerif( bit_test(x,y) ) { //x==porta usata per test, y== bit usato per test bit_clear(x,y); //abbasso l'uscita }else { bit_set(x,y); //alzo l'uscita }}Così realizzi un flip-flop con semiperiodo 500usPer cusiosità come misuri il tempo?
Simons Inserita: 9 ottobre 2007 Autore Segnala Inserita: 9 ottobre 2007 Livio Orsini+9/10/2007, 16:00--> (Livio Orsini @ 9/10/2007, 16:00) il tempo lo misuro con un oscilloscopio digitale HP 100Mhz direi piuttosto preciso perchè riesce a vedere la sovraelongazione di qualche nanosecondo che c'è al momento in cui il pin va alto o basso Proverò come mi hai detto e ti farò sapere...ti ringrazio tantissimo del tempo dedicatomi
Livio Orsini Inserita: 10 ottobre 2007 Segnala Inserita: 10 ottobre 2007 Curiosone, pensa al nuovo lavoro piuttosto Come va? Spero bene visto che hai ancora il tempo di curiosare sul forum di elettronica.
Messaggi consigliati
Crea un account o accedi per commentare
Devi essere un utente per poter lasciare un commento
Crea un account
Registrati per un nuovo account nella nostra comunità. è facile!
Registra un nuovo accountAccedi
Hai già un account? Accedi qui.
Accedi ora