Simons Inserito: 9 settembre 2007 Segnala Share 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: Link al commento Condividi su altri siti More sharing options...
dlgcom Inserita: 9 settembre 2007 Segnala Share 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. Link al commento Condividi su altri siti More sharing options...
walterword Inserita: 17 settembre 2007 Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 24 settembre 2007 Autore Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 24 settembre 2007 Autore Segnala Share Inserita: 24 settembre 2007 utilizzo CCS C Compiler (PCW)non è che potreste postare qualche routine di esempio per più di 2 pwm?grazie 1000 Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 25 settembre 2007 Autore Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 26 settembre 2007 Autore Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 26 settembre 2007 Autore Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 27 settembre 2007 Autore Segnala Share 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? Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 29 settembre 2007 Autore Segnala Share Inserita: 29 settembre 2007 nessun aiuto? pliiis Link al commento Condividi su altri siti More sharing options...
Livio Orsini Inserita: 29 settembre 2007 Segnala Share 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. Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 30 settembre 2007 Autore Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Livio Orsini Inserita: 30 settembre 2007 Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 1 ottobre 2007 Autore Segnala Share 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? Link al commento Condividi su altri siti More sharing options...
Livio Orsini Inserita: 1 ottobre 2007 Segnala Share 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. Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 1 ottobre 2007 Autore Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 4 ottobre 2007 Autore Segnala Share 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? Link al commento Condividi su altri siti More sharing options...
Livio Orsini Inserita: 5 ottobre 2007 Segnala Share 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. Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 8 ottobre 2007 Autore Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Livio Orsini Inserita: 9 ottobre 2007 Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 9 ottobre 2007 Autore Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
Livio Orsini Inserita: 9 ottobre 2007 Segnala Share 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? Link al commento Condividi su altri siti More sharing options...
Simons Inserita: 9 ottobre 2007 Autore Segnala Share 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 Link al commento Condividi su altri siti More sharing options...
walterword Inserita: 10 ottobre 2007 Segnala Share Inserita: 10 ottobre 2007 a cosa pensavi boss? Link al commento Condividi su altri siti More sharing options...
Livio Orsini Inserita: 10 ottobre 2007 Segnala Share 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. Link al commento Condividi su altri siti More sharing options...
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