Bienvenue aux nouveaux arrivants sur FantasPic !
- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.
--- L’équipe FantasPic ---
- Pensez à lire les règles durant votre visite, il n'y en a pas beaucoup, mais encore faut-il les respecter .
- N’hésitez pas à faire des remarques et/ou suggestions sur le Forum, dans le but de l'améliorer et de rendre vos prochaines visites plus agréables.
- Vous pouvez regarder votre "panneau de l'utilisateur" afin de configurer vos préférences.
- Un passage par "l'utilisation du forum" est recommandé pour connaître les fonctionnalités du forum.
--- L’équipe FantasPic ---
Modérateur : Jérémy
Generateur DTMF 18F27K42
Bonsoir,
Une explication sur ce problème d'amplitude du signal PWM ?
Pourquoi le fait d'avoir une consigne sur 10 bits au lieu de 8 bits est gênante. Si les données sont sur 8 bits, il suffit de les multiplier par 4 pour utiliser toute la plage PWM, non ?
Je viens de faire un essai PWM avec CCP1, à FOSC=64MHz, Fpwm=62500Hz, le duty cycle va de 32ns à 16us, par pas de 16ns.
Merci :)
Une explication sur ce problème d'amplitude du signal PWM ?
Pourquoi le fait d'avoir une consigne sur 10 bits au lieu de 8 bits est gênante. Si les données sont sur 8 bits, il suffit de les multiplier par 4 pour utiliser toute la plage PWM, non ?
Je viens de faire un essai PWM avec CCP1, à FOSC=64MHz, Fpwm=62500Hz, le duty cycle va de 32ns à 16us, par pas de 16ns.
Merci :)
Code : Tout sélectionner
T2CLK = 0x01; // timer2, clock FOSC/4
//T2CON = 0x00; // timer2, off, prescaler 1, postscaler 1
T2PR = 255; // timer2, step 62,5ns, overflow 16us
CCP1CON = 0x8c; // ccp1, on, mode pwm right aligned
CCPR1 = 500; // ccp1, duty cycle
//CCPTMRS0 = 0x55; // ccp1, pwm on Timer2
RB1PPS = 0x09; // pps ccp1_out -> B1
TRISB1 = 0; // B1 ouput
T2ON = 1 ; // timer2 on
Generateur DTMF 18F27K42
- paulfjujo
Expert- Messages : 2589
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
bonsoir Satinas,
Oui, c'est bien ce que j'ai fait ... multiplié par 4 !
( ne plus diviser par 2 et en plus , multiplier par 2)
=> pwm valeur maxi=400
mais sous mikroC , je divise par 2 !
( je suis betement l'algo de roman balck!)
uniquement .. valeur maxi=100 !
moyenne des 2 amplitudes des 2 sinus
et mon amplitude analogique apres filtrage est OK
j'ai verifier le comportement du PWM5 associé à Timer2 62500Hz sortie RC4
dans le detail avec analyser logique ..
il se comporte tout à fait correctement .. avec une consigne 10 bits .. 0 à 1023
demain je vais faire le test comparatif avec MikroC ..CCP1 et Timer2 ..
cadré à droite , .... la commande Mikro C etant PWM1_Set_Duty(pwm);
..resultat équivalent à un PWM 8 bits !!
si on a CCPR1H et CCPR1L .. on devrait gerer CCP1 uttilisé en PWM , en 10 bits !
si j'envoie 100 en 10 bits ,le duty maxi serait < 10%
ce n'est pas le cas !
nota : j'ai bien essayé les combinaisons avec FMT=0 ou FMT=1 !
mikroC gere differement CCP1 PWM et les PWM 5,6,7,8
Attendons mes tests avec analyser coté MikroC pour verifier ...
Oui, c'est bien ce que j'ai fait ... multiplié par 4 !
( ne plus diviser par 2 et en plus , multiplier par 2)
=> pwm valeur maxi=400
mais sous mikroC , je divise par 2 !
( je suis betement l'algo de roman balck!)
uniquement .. valeur maxi=100 !
moyenne des 2 amplitudes des 2 sinus
et mon amplitude analogique apres filtrage est OK
j'ai verifier le comportement du PWM5 associé à Timer2 62500Hz sortie RC4
dans le detail avec analyser logique ..
il se comporte tout à fait correctement .. avec une consigne 10 bits .. 0 à 1023
demain je vais faire le test comparatif avec MikroC ..CCP1 et Timer2 ..
cadré à droite , .... la commande Mikro C etant PWM1_Set_Duty(pwm);
..resultat équivalent à un PWM 8 bits !!
si on a CCPR1H et CCPR1L .. on devrait gerer CCP1 uttilisé en PWM , en 10 bits !
si j'envoie 100 en 10 bits ,le duty maxi serait < 10%
ce n'est pas le cas !
nota : j'ai bien essayé les combinaisons avec FMT=0 ou FMT=1 !
mikroC gere differement CCP1 PWM et les PWM 5,6,7,8
Attendons mes tests avec analyser coté MikroC pour verifier ...
Vous n’avez pas les permissions nécessaires pour voir les fichiers joints à ce message.
Generateur DTMF 18F27K42
Bonjour à tous,
Si la fonction MikroC PWM_Set_Duty() marche bien avec 8 bits, c'est qu'elle multiplie par 4 avant de renseigner PWM5DC. Seulement si PR est à 255. Elle fait une règle de trois pour adapter le rapport cyclique selon la valeur de PR, en passant pas une multiplication 16 bits. Le but est de décrire toute la plage PWM du pic en entrant une valeur de 0 à 255.
Si on fait PWM_Set_Duty(130) elle fait le calcul suivant : dc = (130*4*(PR+1))/256 simplifié en (130*(PR+1))/64
Avec un PR de 255 : (130*256)/64 -> 520
Avec un PR de 100 : (130*101)/64 -> 205
Je vais regarder l'algo Roman Black. Au niveau rapidité, voilà ta fonction LoadDutyValue(pwm_1) en alignement gauche.
En alignement droite, PWM5DC = pwm_1; devrait suffire. Problème, il le transforme en nop :)
Cela prend bien 4 cycles car pwm_1 et PWM5DC sont en mémoire access, alors où sont les instructions ?
Pourtant le programme marche :)
Si la fonction MikroC PWM_Set_Duty() marche bien avec 8 bits, c'est qu'elle multiplie par 4 avant de renseigner PWM5DC. Seulement si PR est à 255. Elle fait une règle de trois pour adapter le rapport cyclique selon la valeur de PR, en passant pas une multiplication 16 bits. Le but est de décrire toute la plage PWM du pic en entrant une valeur de 0 à 255.
Si on fait PWM_Set_Duty(130) elle fait le calcul suivant : dc = (130*4*(PR+1))/256 simplifié en (130*(PR+1))/64
Avec un PR de 255 : (130*256)/64 -> 520
Avec un PR de 100 : (130*101)/64 -> 205
Je vais regarder l'algo Roman Black. Au niveau rapidité, voilà ta fonction LoadDutyValue(pwm_1) en alignement gauche.
Code : Tout sélectionner
413: void PWM5_LoadDutyValue(uint16_t dutyValue)
11FD4 C02C MOVFF __pcstackCOMRAMh, src
11FD6 F02E NOP
11FD8 C02D MOVFF 0x2D, 0x2F
11FDA F02F NOP
11FDC 90D8 BCF 0xFD8, 0, ACCESS
11FDE 322F RRCF 0x2F, F, ACCESS
11FE0 322E RRCF src, F, ACCESS
11FE2 90D8 BCF 0xFD8, 0, ACCESS
11FE4 322F RRCF 0x2F, F, ACCESS
11FE6 322E RRCF src, F, ACCESS
11FE8 502E MOVF src, W, ACCESS
11FEA 6E6D MOVWF 0xF6D, ACCESS
414: {
415: // Writing to 8 MSBs of PWM duty cycle in PWMDCH register
416: PWM5DCH = (dutyValue & 0x03FC)>>2;
417:
418: // Writing to 2 LSBs of PWM duty cycle in PWMDCL register
419: PWM5DCL = (dutyValue & 0x0003)<<6;
11FEC C02C MOVFF __pcstackCOMRAMh, src
11FEE F02E NOP
11FF0 0E03 MOVLW 0x3
11FF2 162E ANDWF src, F, ACCESS
11FF4 0E06 MOVLW 0x6
11FF6 6E2F MOVWF 0x2F, ACCESS
11FF8 90D8 BCF 0xFD8, 0, ACCESS
11FFA 362E RLCF src, F, ACCESS
11FFC 2E2F DECFSZ 0x2F, F, ACCESS
11FFE EFFC GOTO 0x11FF8
12000 F08F NOP
12002 502E MOVF src, W, ACCESS
12004 6E6C MOVWF 0xF6C, ACCESS
420: }
12006 0012 RETURN 0
421:
En alignement droite, PWM5DC = pwm_1; devrait suffire. Problème, il le transforme en nop :)
Cela prend bien 4 cycles car pwm_1 et PWM5DC sont en mémoire access, alors où sont les instructions ?
Pourtant le programme marche :)
Code : Tout sélectionner
507: PWM5DC = pwm_1;
1025E F2F7 NOP
10260 FF6C NOP
10264 F2FB NOP
10266 FF6D NOP
Generateur DTMF 18F27K42
- paulfjujo
Expert- Messages : 2589
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
bonjour satinas,
merçi d'avoir décortiqué la fonction mikroc
mais dans mon cas ,(MikroC) c'est CCP1 qui est utilisé comme PWM générateur et non PWM5
donc usage aussi de CCP1RL et CCPR1H, au détail pres de la possibité d'utiliser le cadrage à gauche ou droite suivant l'etat du bit FMT 'CCP1CON)
qui est d'ailleur la principale difference avec PWM5 (sans ce bit FMT)
ou on retrouve aussi les 2 registres PWM5 DCH et DCL , MAIS sans choix du cadrage à gauche ou droite
doc mikroc
void PWMx_Set_Duty(unsigned short duty_ratio);
Sets PWM duty ratio. Parameter duty takes values from 0 to 255, where 0 is 0%, 127 is 50%, and 255 is 100% duty ratio.
Other specific values for duty ratio can be calculated as (Percent*255)/100
test mikroC avec SQA analyser :
et PWM1_Set_Duty(pwm1);
on couvre bien 0 à100% avec pwm1= 0 à 255
on est bien sur PWM1 ( donc sur un CCP1 utilisé en PWM)
j'ai verifié que :
CCP1EN_bit=1; active la sortie PWM1
CCP1EN_bit=0; inhibe la sortie PWM1
code du test
RA3 trigger pour SQA
RC4 sortie PWM1
terminal YAT
merçi d'avoir décortiqué la fonction mikroc
mais dans mon cas ,(MikroC) c'est CCP1 qui est utilisé comme PWM générateur et non PWM5
donc usage aussi de CCP1RL et CCPR1H, au détail pres de la possibité d'utiliser le cadrage à gauche ou droite suivant l'etat du bit FMT 'CCP1CON)
qui est d'ailleur la principale difference avec PWM5 (sans ce bit FMT)
ou on retrouve aussi les 2 registres PWM5 DCH et DCL , MAIS sans choix du cadrage à gauche ou droite
doc mikroc
void PWMx_Set_Duty(unsigned short duty_ratio);
Sets PWM duty ratio. Parameter duty takes values from 0 to 255, where 0 is 0%, 127 is 50%, and 255 is 100% duty ratio.
Other specific values for duty ratio can be calculated as (Percent*255)/100
test mikroC avec SQA analyser :
et PWM1_Set_Duty(pwm1);
on couvre bien 0 à100% avec pwm1= 0 à 255
on est bien sur PWM1 ( donc sur un CCP1 utilisé en PWM)
j'ai verifié que :
CCP1EN_bit=1; active la sortie PWM1
CCP1EN_bit=0; inhibe la sortie PWM1
code du test
Code : Tout sélectionner
CCP1EN_bit=1; // enable/active PWM output
T2CON.T2ON=1;
do
{
CPrint(" Test CCP1 en mode PWM associé à TMR2, pwm 16 à 240 \r\n");
for (pwm1=16;pwm1<240;pwm1=pwm1+16)
{
ByteToStr(pwm1,CRam1);
CPrint(" pwm1 = ");
Print(CRam1);CRLF1();
SQA=1;
PWM1_Set_Duty(pwm1);
SQA=0;
Delay_ms(1);
}
CPrint(" saisir Q pour quitter le test\r\n");
Raz_Buffer1();
Delay_ms(2000);
if (*(Buffer1)=='0')
{
CPrint(" Disable CCP1 \r\n");
CCP1EN_bit=0;
}
if (*(Buffer1)=='1')
{
CPrint(" Enable CCP1 \r\n");
CCP1EN_bit=1;
}
}
while(*(Buffer1)!='Q');
CPrint(" ..fin de test\r\n");
CRLF1();
RA3 trigger pour SQA
RC4 sortie PWM1
terminal YAT
Test CCP1 en mode PWM associé à TMR2, pwm 16 à 224
pwm1 = 16
pwm1 = 32
pwm1 = 48
pwm1 = 64
pwm1 = 80
pwm1 = 96
pwm1 = 112
pwm1 = 128
pwm1 = 144
pwm1 = 160
pwm1 = 176
pwm1 = 192
pwm1 = 208
pwm1 = 224
saisir Q pour quitter le test
0
Disable CCP1
Test CCP1 en mode PWM associé à TMR2, pwm 16 à 240
pwm1 = 16 <-- PAS de sortie signal
pwm1 = 32
pwm1 = 48
pwm1 = 64
pwm1 = 80
pwm1 = 96
pwm1 = 112
pwm1 = 128
pwm1 = 144
pwm1 = 160
pwm1 = 176
pwm1 = 192
pwm1 = 208
pwm1 = 224
saisir Q pour quitter le test
1
Enable CCP1
Test CCP1 en mode PWM associé à TMR2, pwm 16 à 240
pwm1 = 16 <-- OK presence signal
pwm1 = 32
pwm1 = 48
pwm1 = 64
pwm1 = 80
pwm1 = 96
pwm1 = 112
pwm1 = 128
pwm1 = 144
pwm1 = 160
pwm1 = 176
pwm1 = 192
pwm1 = 208
pwm1 = 224
Generateur DTMF 18F27K42 [Solved]
Ok, j'avais juste recompilé ton programme sans le lancer, mes essais ont aussi été faits avec CCP1 sur un programme test.
Tu peux aussi faire CCPR1 = pwm_1 directement. Ces fonctions MikroC sont trop lentes. Après, l'adaptation aux données sinus, j'ai pas encore tout compris, mais c'est pas grave :)
Explication pour le programme fantôme. Le listing ne désassemble pas l'instruction MOVFFL du 18F27K42. Il manque le premier des 3 octets de cette instruction. En regardant le fichier HEX, on retrouve bien les instructions complètes, 12 octets et 6 cycles. c'est faisable en 8 octets et 4 cycles avec MOVF/MOVWF si pwm_1 était en mémoire access, ce qui n'est pas le cas, elle est en 0xBD/0xBE.
Tu peux aussi faire CCPR1 = pwm_1 directement. Ces fonctions MikroC sont trop lentes. Après, l'adaptation aux données sinus, j'ai pas encore tout compris, mais c'est pas grave :)
Explication pour le programme fantôme. Le listing ne désassemble pas l'instruction MOVFFL du 18F27K42. Il manque le premier des 3 octets de cette instruction. En regardant le fichier HEX, on retrouve bien les instructions complètes, 12 octets et 6 cycles. c'est faisable en 8 octets et 4 cycles avec MOVF/MOVWF si pwm_1 était en mémoire access, ce qui n'est pas le cas, elle est en 0xBD/0xBE.
Code : Tout sélectionner
507: PWM5DC = pwm_1;
1025C 0060 ; MOVFFL pwm_1L,PWM5DCL
1025E F2F7 NOP ;
10260 FF6C NOP ;
10262 0060 ; MOVFFL pwm_1H,PWM5DCH
10264 F2FB NOP ;
10266 FF6D NOP ;
Modifié en dernier par satinas le lun. 21 nov. 2022 18:43, modifié 1 fois.
Generateur DTMF 18F27K42
- paulfjujo
Expert- Messages : 2589
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
je confirme, tests avec SQA analyser comme temoin.
avec FMT=0 cadrage à droite
si on travaille avec CCPR1L= pwm (8 bits value) et donc CCPR1H=0
maxima = 22% pour Pwm=224
... normal CCP1 travaille en 10 bits ! c'est le probleme que je constatais avec CCP1 sur XC8 !
avec FMT=1 cadrage à gauche
CCPR1L=0
CCPR1H= pwm1
comportement SEMBLABLE qu'avec la fonction MikroC PWM1_Set_Duty(pwm1);
// avec FMT=1
SQA=1; // debut de la 1ere capture
CCPR1L=0;
CCPR1H=pwm1;
while(TMR2IF_bit==0);
TMR2IF_bit=0;
Delay_ms(1); // encadrement de la mesure signal pwm sur l'analyser
SQA=0;
Par contre, surprise !
si FMT1=1
PWM1_Set_Duty(pwm1); NE MARCHE PLUS!
il faut FMT=0 !
sacré salade , pourquoi faire simple quand on peut faire compliqué!
rappel: FMT est à 0 au reset !
remarque :
The CCPRxH:CCPRxL register pair can be written to at any
time; however the duty cycle value is not latched into
the 10-bit buffer until after a match between T2PR and T2TMR.
avec l'analyser logique , je ne vois pas de difference
au changement de valeur ! avec ou sans synchro Timer2
synchro utile ??
The alignment of the 10 bits from the CCPR register is determined by the CCPxFMT bit.
FIGURE 23-5: PWM 10-BIT ALIGNMENT
FMT=0
CCPRxH bits 9 et 8 = MSB
CCPRxL bit 7..0 = LSB
si FMT=1
CCPRxH = bit 9...2
CCPRxL = bits 1..0
avec FMT=0 cadrage à droite
si on travaille avec CCPR1L= pwm (8 bits value) et donc CCPR1H=0
maxima = 22% pour Pwm=224
... normal CCP1 travaille en 10 bits ! c'est le probleme que je constatais avec CCP1 sur XC8 !
avec FMT=1 cadrage à gauche
CCPR1L=0
CCPR1H= pwm1
comportement SEMBLABLE qu'avec la fonction MikroC PWM1_Set_Duty(pwm1);
// avec FMT=1
SQA=1; // debut de la 1ere capture
CCPR1L=0;
CCPR1H=pwm1;
while(TMR2IF_bit==0);
TMR2IF_bit=0;
Delay_ms(1); // encadrement de la mesure signal pwm sur l'analyser
SQA=0;
Par contre, surprise !
si FMT1=1
PWM1_Set_Duty(pwm1); NE MARCHE PLUS!
il faut FMT=0 !
sacré salade , pourquoi faire simple quand on peut faire compliqué!
rappel: FMT est à 0 au reset !
remarque :
The CCPRxH:CCPRxL register pair can be written to at any
time; however the duty cycle value is not latched into
the 10-bit buffer until after a match between T2PR and T2TMR.
avec l'analyser logique , je ne vois pas de difference
au changement de valeur ! avec ou sans synchro Timer2
synchro utile ??
Generateur DTMF 18F27K42 [Solved]
C'est un mécanisme interne, il n'y a rien à faire après le réglage des 2 consignes PR et CCPR.
La période PWM démarre après overflow TMR=PR du timer FOSC/4.
- TMR = 0, CCPR est latché, signal haut, TMR s'incrémente (+2 bits avec FOSC)
- lorsque (4*TMR)+(0 à 3) = CCPR signal bas.
- lorsque TMR = PR signal haut
Ensuite en réglant le postscaler, on a un évènement TMRIF et une interruption possible toutes les 1 à 16 périodes PWM. CCPR peut être modifié à tout moment, la valeur sera prise en compte au prochain overflow timer.
La période PWM démarre après overflow TMR=PR du timer FOSC/4.
- TMR = 0, CCPR est latché, signal haut, TMR s'incrémente (+2 bits avec FOSC)
- lorsque (4*TMR)+(0 à 3) = CCPR signal bas.
- lorsque TMR = PR signal haut
Ensuite en réglant le postscaler, on a un évènement TMRIF et une interruption possible toutes les 1 à 16 périodes PWM. CCPR peut être modifié à tout moment, la valeur sera prise en compte au prochain overflow timer.
Generateur DTMF 18F27K42 [Solved]
Bonjour tout le monde,
Je viens me greffer sur ce sujet, car je tente de porter le code de Roman Black vers le 16F876A.
Environnement est MPLAB X et le compilateur XC8.
Je rencontre quelques problèmes de fonctionnement... J'ai bien tenté de décortiquer votre discussion pour trouver le loup, mais je suis quelque peu largué
Donc avec ce code, j'ai bien du PWM sur CCP1 (et même sur CCP2 soit dit en passant). Par contre j'ai la très nette impression qu'il n'y a qu'une seule fréquence présente. De plus, je suis censé faire défiler les 16 tonalités par les 2 boucles FOR imbriquées, mais à l'oreille c'est toujours la même...
Si quelqu'un pouvait me donner une piste ce serait merveilleux
Bonne journée.
Bruno
Je viens me greffer sur ce sujet, car je tente de porter le code de Roman Black vers le 16F876A.
Environnement est MPLAB X et le compilateur XC8.
Je rencontre quelques problèmes de fonctionnement... J'ai bien tenté de décortiquer votre discussion pour trouver le loup, mais je suis quelque peu largué
Donc avec ce code, j'ai bien du PWM sur CCP1 (et même sur CCP2 soit dit en passant). Par contre j'ai la très nette impression qu'il n'y a qu'une seule fréquence présente. De plus, je suis censé faire défiler les 16 tonalités par les 2 boucles FOR imbriquées, mais à l'oreille c'est toujours la même...
Si quelqu'un pouvait me donner une piste ce serait merveilleux
Bonne journée.
Bruno
Code : Tout sélectionner
// Portage du code source de génération DTMF Roman Black pour le 16F876A
//
#define _XTAL_FREQ 24000000
// CONFIG
#pragma config FOSC = HS // Oscillator Selection bits (HS oscillator)
#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = ON // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3/PGM pin has PGM function; low-voltage programming enabled)
#pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off)
#pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control)
#pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
#include <xc.h>
// Global Variables
unsigned long waveA __at( 0x15 ); // 32bit accumulators for the 2 sinewaves
unsigned char waveA_2 __at( 0x17 ); // overload for fast access to byte 2
unsigned long waveB __at( 0x19 );
unsigned char waveB_2 __at( 0x1B ); // overload for fast access to byte 2
unsigned long BDA_periodA; // 32bit periods for the 2 sinewaves
unsigned long BDA_periodB;
uint8_t drow=0; // DTMF selected row and column
uint8_t dcol=0;
uint8_t u8_NbCycleTimer0;
__bit bitFinTempoDTMF;
// defines for the DTMF sine frequencies
// Sinewave is a lookup table of 64 steps, to generate 1633 Hz each step is 1633 * 64
// 24bit Binary divider uses byte2 (/65536)
// PWM freq is 128 PIC instructions (8Mhz xtal *PLL) = 62500 Hz
// So the math is; Fout * 64 * 65536 / Fpwm
// we can use a constant Fout * (64 * 65536 / 62500) = Fout * 67.108864
#define Frow0 46775 // 697 Hz DTMF rows
#define Frow1 51674 // 770 Hz
#define Frow2 57177 // 852 Hz
#define Frow3 63149 // 941 Hz
#define Fcol0 81135 // 1209 Hz DTMF columns
#define Fcol1 89657 // 1336 Hz
#define Fcol2 99120 // 1477 Hz
#define Fcol3 109589 // 1633 Hz
// sinewave table, range 0-99, 64 entries
const unsigned char sine64[64] = {
50,54,59,64,68,73,77,81,85,88,91,93,95,97,98,99,99,99,98,97,95,93,91,88,85,81,77,73,68,64,59,54,
50,45,40,35,31,26,22,18,14,11,8,6,4,2,1,0,0,0,1,2,4,6,8,11,14,18,22,26,31,35,40,45 };
//=============================================================================
// MAKE DTMF TONE
//=============================================================================
void make_DTMF_tone(void)
{
//-------------------------------------------------------
// this generates the 2 accurate sinewaves together.
// a DDS algorithm calculation is done once every PWM cycle,
// then the 2 sinewaves are generated by the PIC PWM module.
// For a full description of algorithm; www.RomanBlack.com/one_sec.htm#BDA
// NOTE! for good speed PWM TMR2 is manually polled, not an interrupt.
//-------------------------------------------------------
unsigned char pwm;
bitFinTempoDTMF=0;
u8_NbCycleTimer0 = 0;
INTCONbits.GIE = 1;
TMR0 = 0;
RB1 = 1; // led on
INTCONbits.T0IE = 1; // start timer
// loop and generate dual sinewave DTMF tone
while(bitFinTempoDTMF==0)
{
while(PIR1bits.TMR2IF==0);
PIR1bits.TMR2IF = 0;
// calc the A sinewave,
waveA += BDA_periodA; // zero-error Accumulation
pwm = sine64[waveA_2 & 0x3F]; // Binary Divide output (/65536) and keep 6 bits
if(drow == 4) pwm = 0; // disable if row is OFF
// calc the B sinewave, and ADD the 2 waves together
waveB += BDA_periodB;
if(dcol != 4) pwm += sine64[waveB_2 & 0x3F]; // only enable if col is ON
// scale the summed sinewaves and place in PWM module
pwm = (pwm >> 1); // scale 0-200 back to 0-100 for PWM
pwm += 14; // offset to centre waveform (100 into centre of 128)
CCPR2L = pwm; // load added sinewaves into PWM module
}
}
//-----------------------------------------------------------------------------
void main()
{
CMCON = 0x07; // turn off comparators (make all pins digital)
OPTION_REGbits.T0CS = 0; // 0: Timer0 incrémenté par horloge interne 1: horloge externe sur RA4
OPTION_REGbits.PSA=0; // 0-préscaler assigné au Timer0 1-affecté au watchdog (pour ne pas diviser par 2))
// on fixe le prescaler
OPTION_REGbits.PS2=1;
OPTION_REGbits.PS1=1;
OPTION_REGbits.PS0=1;
//TRISE = 0b01111111; // RE7 is ouput for PWM
//-------------------------------------------------------
// startup delay, let the PSU voltage stabilise etc.
__delay_ms(10);
// setup PWM module
// Marche à suivre pour faire du PWM :
// - Ecrire dans PR2 la valeur permettant d'obtenir la Période désirée.
// - Ecrire dans CCPR1L la valeur donnant la durée du Duty cycle.
// - Configurer la broche d'utilisation en sortie ( bit = 0 dans TRISC).
// - Initialiser le Timer 2 par T2CON ( prédiv, TMR2 on).
// - Initialiser le CCP par CCP1CON (mode PWM, 2 bits LSB Duty cycle)
TRISC = 0x00;
T2CON = 0b00000100; // TMR2 on, prescale 1:1
PR2 = (128-1); // PWM at period = 128
CCPR2L = 0; // start PWM = 0% by default
CCP2CON = 0b00001100; // PWM module ON, output A on PORTE.F7
//NOTE!! make sure CCP2MX is set to RE7 in the PIC config (edit project)
PORTB = 0;
// TRISB0 = 0; //RB0 as Output PIN
// TRISB1 = 0; //RB1 as Output PIN
// TRISB2 = 0; //RB2 as Output PIN
TRISB = 0x00; //Initialize PortB as output
//-------------------------------------------------------
// main running loop
while(1)
{
for (drow=0;drow<3;drow++) {
for (dcol=0;dcol<3;dcol++) {
switch (drow) {
case 0 : BDA_periodA = Frow0;
case 1 : BDA_periodA = Frow1;
case 2 : BDA_periodA = Frow2;
case 3 : BDA_periodA = Frow3;
}
switch (dcol) {
case 0 : BDA_periodB = Fcol0;
case 1 : BDA_periodB = Fcol1;
case 2 : BDA_periodB = Fcol2;
case 3 : BDA_periodB = Fcol3;
}
make_DTMF_tone();
__delay_ms(1000);
}
}
__delay_ms(6000);
}
}
//-----------------------------------------------------------------------------
void __interrupt() isr(void) {
// INTCONbits.T0IF : flag débordement timer
if (INTCONbits.T0IF) {
if ( u8_NbCycleTimer0 >= 99 ) {
INTCONbits.T0IE = 0; // stop timer
TMR0 = 0;
RB1 = 0;
bitFinTempoDTMF=1;
u8_NbCycleTimer0=0;
}
else {
u8_NbCycleTimer0 ++;
}
INTCONbits.T0IF = 0; // acquittement du flag pour autoriser int suivante
}
}
Generateur DTMF 18F27K42 [Solved]
- paulfjujo
Expert- Messages : 2589
- Âge : 73
- Enregistré en : juillet 2015
- Localisation : 01800
- Contact :
bonjour,
je vois que tu n'as qu'une seule table sinus ?
il en faut 2
ce qui pourrais expliquer que tu n'obtiens qu'une seule frequence
la meme pour Wave_A ou Wave_B
regarde le code 18F27K42
extrait ici
Bonne fete de fin d'année !
je vois que tu n'as qu'une seule table sinus ?
il en faut 2
ce qui pourrais expliquer que tu n'obtiens qu'une seule frequence
la meme pour Wave_A ou Wave_B
regarde le code 18F27K42
extrait ici
Code : Tout sélectionner
// This uses dual sinewaves of 28% different amplitudes, to match the spec for "twist" in
// telephone DTMF to ensure the higher freq has a higher amplitude, to cope with line losses.
uint8_t Sin64L[64]={
// const uint8_t Sin64L[64]={ <-- en mikroC!
39,42,46,50,53,57,60,63,66,68,71,72,74,75,76,77,77,77,76,75,74,72,71,68,66,63,60,57,53,50,46,42,
39,35,31,27,24,20,17,14,11,9,6,5,3,2,1,1,1,1,1,2,3,5,6,9,11,14,17,20,24,27,31,35};
// const uint8_t Sin64H[64] = { <-- en mikroC !
uint8_t Sin64H[64] = {
50,54,59,64,68,73,77,81,85,88,91,93,95,97,98,99,99,99,98,97, 95,93,91,88,85,81,77,73,68,64,59,54,
50,45,40,35,31,26,22,18,14,11,8,6,4,2,1,1,1,1,1,2,4,6,8,11,14,18,22,26,31,35,40,45};
Bonne fete de fin d'année !
Generateur DTMF 18F27K42 [Solved]
Bonjour Paul
Effectivement, le loup était là, merci beaucoup Paul.
Du coup je vois bien qu'il y a bien un mixage de fréquences sur la simulation.
Pour info, J'avais récupéré le source MikroC sur le site de Roman (archive Download SG13_DTMF.zip sur https://www.romanblack.com/SG/SG_tutorial.htm) et il semble que, bien que parlant de DTMF, le programme ne génère qu'un sinus pur.
Et bonnes fêtes de fin d'année à toi également.
Voilà le résultat en simulation (trace bleue = sortie PWM, trace jaune = sortie du filtre 4,7k et 47nF)
Effectivement, le loup était là, merci beaucoup Paul.
Du coup je vois bien qu'il y a bien un mixage de fréquences sur la simulation.
Pour info, J'avais récupéré le source MikroC sur le site de Roman (archive Download SG13_DTMF.zip sur https://www.romanblack.com/SG/SG_tutorial.htm) et il semble que, bien que parlant de DTMF, le programme ne génère qu'un sinus pur.
Et bonnes fêtes de fin d'année à toi également.
Voilà le résultat en simulation (trace bleue = sortie PWM, trace jaune = sortie du filtre 4,7k et 47nF)
Vous n’avez pas les permissions nécessaires pour voir les fichiers joints à ce message.
Qui est en ligne
Utilisateurs parcourant ce forum : Aucun utilisateur enregistré et 44 invités