That was my point. He really needs to work on terms. He may understand the concept but he's not conveying it.
In his new graphic for example, point 'C' should be 100% duty cycle and point 'H' should be 0% duty cycle. And without a reference on the X axis one might assume his transitions are occurring at regular intervals which would produce a sawtooth wave instead of a sine wave, that is if you can imply that "pwm increment" is actually "duty cycle".
Shoddy terms followed up with a shoddy graphic which includes more shoddy terms.
while(1)
{
// POSITIVE CYCLE (0° = 0V, 90° = 5V, 180° = 0V)
for(i=0;i<100;i++) // Rising edge in percentage
{
PWM_Output_Positive(i, freq);
}
for(i=100;i>0;i--) // Falling edge in percentage
{
PWM_Output_Positive(i, freq);
}
//****************
//NEGATIVE CYCLE, (180° = 0V, 270° = -5V, 360° = 0V)
for(i=0;i>-100;i--) // Falling edge in percentage
{
PWM_Output_Negative(i, freq); // Negative falling edge of sine wave
}
for(i=-100;i<0;i++) // Rising edge in percentage
{
PWM_Output_Negative(i, freq); // Negative rising edge of sine wave
}
}
; TITLE "CTCSS Encoder"
; Assemble with MPASM
; See below for wiring details
;
LIST P=16C84
__CONFIG 3FF9H ;XTAL OSC @4Mhz,NO WATCHDOG,PWRRST,NO CP.
__IDLOCS 1234
ERRORLEVEL -302
;
CNT1 EQU 0CH ;PRESCALLER COUNTER REG 1
CNT2 EQU 0DH ;PRESCALLER COUNTER REG 2
CNT3 EQU 0EH ;PRESCALLER COUNTER REG 3
TONREG EQU 0FH ;REGISTER FOR TONE NUMBER
PRES1 EQU 10H ;PRESCALLER STORE 1
PRES2 EQU 11H ;PRESCALLER STORE 2
PRES3 EQU 12H ;PRESCALLER STORE 3
PORTA EQU 5
PORTB EQU 6
TRISA EQU 85H
TRISB EQU 86H
OPTREG EQU 81H
PC EQU 2
PULLUP EQU 7
STATUS EQU 3
INTCON EQU 0BH
GIE EQU 7
RBIE EQU 3
RBIF EQU 0
RP0 EQU 5
OUT EQU 2
PTT EQU 7
;
GOTO START
ORG 00C8
START BSF STATUS,RP0 ;SELECT REG BANK 1
BSF TRISB,PTT ;SETUP RB7 AS INPUT FOR PTT
BCF TRISA,OUT ;SETUP RA2 AS OUTPUT FOR TONE
BCF OPTREG,PULLUP ;SET PULLUP RESISTORS ON PORTB
MOVLW 0xFF ; SET PORTB AS I/Ps
MOVWF TRISB ; RB0-RB5 FOR SWITCH INPUTS
;
BCF STATUS,RP0 ;SELECT REG BANK 0
BCF INTCON,GIE ;DISABLE GIE INTERUPTS
BSF INTCON,RBIE ;ENABLE PORT B CHANGE INTERUPT
MOVF TRISB,W ;READ DIP SWITCHES INTO W
MOVWF TONREG ;STORE IN 0F REG
BCF TONREG,6 ; CLEAR BITS 6&7 AS
BCF TONREG,7 ; THEY ARE IRRELAVANTS
MOVF TONREG,W ;RE-STORE INTO W
ADDWF TONREG,F ; MULTIPLY BY 3
ADDWF TONREG,F ; FOR TONE TABLE OFFSET
;
MOVF TONREG,W ;RELOAD TO W FOR OFFSET
CALL TONTBL ;GOTO TONE LOOKUP TABLE
MOVWF PRES1 ;STORE FIRST VALUE FROM TABLE
;
INCF TONREG,F ;INCREMENT FOR NEXT TABLE VALUE
MOVF TONREG,W ;RELOAD W FOR OFFSET
CALL TONTBL ;GOTO TONE LOOKUP TABLE
MOVWF PRES2 ;STORE SECOND VALUE FROM TABLE
;
INCF TONREG,F ;INCREMENT FOR NEXT TABLE VALUE
MOVF TONREG,W ;RELOAD W FOR OFFSET
CALL TONTBL ;GOTO TONE LOOKUP TABLE
MOVWF PRES3 ;STORE THIRD VALUE FROM TABLE
;
;
RELOAD
MOVF PRES1,W ;LOAD W WITH PRESET FOR 1
MOVWF CNT1 ;PRELOAD PRESCALLER 1
MOVF PRES2,W ;LOAD W WITH PRESET FOR 3
MOVWF CNT3 ;PRELOAD PRESCALLER 3
MOVF PRES3,W ;LOAD W WITH PRESET FOR 2 READY
PTTCHK
BTFSC PORTB,PTT ;TEST PTT LINE
GOTO WAIT ;SLEEP TILL LOW
CALL CHORUS ;DO DIVIDER/PRESCALLER ROUTINE
;
OUTPUT
BTFSS PORTA,OUT ;TEST O/P HI OR LO AT PRESENT
GOTO HI ;IF LO GO SET HI
GOTO LO ;IF HI GO SET LO
;
HI
NOP ;BALANCE OUT CYCLE TIME MARK&SPACE
BSF PORTA,OUT ;MAKE O/P HI
GOTO RELOAD ;RETURN TO START OF CYCLE
;
LO
BCF PORTA,OUT ;MAKE O/P LO
GOTO RELOAD ;RETURN TO START OF CYCLE
;
CHORUS
PRE1
DECFSZ CNT1,F ;DECREMENT PRESCALLER 1
GOTO PRE2
GOTO FINE ;CALL FINE ADJUST SUBROUTINE
PRE2 MOVWF CNT2 ;RELOAD PRESCALLER 2
;
PREE DECFSZ CNT2,F ;DECREMENT PRESCALLER 2
GOTO PREE ;GO BACK AND DECREMENT PRE2 TILL 00
;
GOTO PRE1 ;GO BACK AND DECREMENT PRE1 TILL 00
;
FINE DECFSZ CNT3,F ;DECREMENT PRESCALLER 3
GOTO FINE ;GO BACK AND DECREMENT PRE3 TILL 00
RETURN ;RETURN TO CHANGE O/P AND CHECK PTT ETC
;
WAIT
BCF INTCON,RBIF ;CLEAR PORT B CHANGE INT FLAG
SLEEP ;SLEEP AND WAIT FOR PTT
NOP
BCF INTCON,GIE ;DISABLE GLOBAL INTERUPTS AGAIN
GOTO PTTCHK ;CHECK IF PTT PASSES TEST
;
;
;
;TONES TABLE AT 0008H
ORG 0007H
TONTBL
ADDWF PC,F ; W+PC ->PC, JUMP DOWN TABLE
;
;
; 16c84 PIN
; 11 10 9 8 7 6
; TONE FREQ RB5 RB4 RB3 RB2 RB1 RB0
;
DT 02,01,0x9D ; 000 1Khz TEST 0 0 0 0 0 0
DT 86,82,10 ; 001 67.0 0 0 0 0 0 1
DT 81,85,10 ; 002 69.4 * 0 0 0 0 1 0
DT 84,80,0x0F ; 003 71.9 0 0 0 0 1 1
DT 7F,85,0x0F ; 004 74.4 0 0 0 1 0 0
DT 7B,7C,0x0F ; 005 77.0 0 0 0 1 0 1
DT 76,86,0x0F ; 006 79.7 0 0 0 1 1 0
DT 72,82,0x0F ; 007 82.5 0 0 0 1 1 1
DT 74,8F,0x0E ; 008 85.4 0 0 1 0 0 0
DT 63,91,10 ; 009 88.5 0 0 1 0 0 1
DT 5F,9A,10 ; 010 91.5 0 0 1 0 1 0
DT 5B,47,11 ; 011 94.8 0 0 1 0 1 1
DT 55,88,11 ; 012 97.4 0 0 1 1 0 0
DT 56,49,11 ; 013 100.0 0 0 1 1 0 1
DT 09,6E,0xB9 ; 014 103.5 0 0 1 1 1 0
DT 08,81,0xC9 ; 015 107.2 0 0 1 1 1 1
DT 0A,71,98 ; 016 110.9 0 1 0 0 0 0
DT 0B,76,83 ; 017 114.8 0 1 0 0 0 1
DT 0A,0xCA,83 ; 018 118.8 0 1 0 0 1 0
DT 0A,9A,83 ; 019 123.0 0 1 0 0 1 1
DT 09,0xF1,83 ; 020 127.3 0 1 0 1 0 0
DT 08,93,9D ; 021 131.8 0 1 0 1 0 1
DT 07,94,0xB0 ; 022 136.5 0 1 0 1 1 0
DT 07,7C,0xAD ; 023 141.3 0 1 0 1 1 1
DT 07,85,0xA5 ; 024 146.2 0 1 1 0 0 0
DT 08,7B,89 ; 025 151.4 0 1 1 0 0 1
DT 08,80,83 ; 026 156.7 0 1 1 0 1 0
DT 07,0xA2,90 ; 027 159.8 * 0 1 1 0 1 1
DT 08,47,86 ; 028 162.2 0 1 1 1 0 0
DT 07,60,95 ; 029 165.5 * 0 1 1 1 0 1
DT 08,86,78 ; 030 167.9 0 1 1 1 1 0
DT 07,92,87 ; 031 171.3 * 0 1 1 1 1 1
DT 07,90,85 ; 032 173.8 1 0 0 0 0 0
DT 07,7D,85 ; 033 177.3 * 1 0 0 0 0 1
DT 09,5A,66 ; 034 179.9 1 0 0 0 1 0
DT 09,48,66 ; 035 183.5 * 1 0 0 0 1 1
DT 07,9E,78 ; 036 186.2 1 0 0 1 0 0
DT 08,0xBB,60 ; 037 189.9 * 1 0 0 1 0 1
DT 09,4C,60 ; 038 192.8 1 0 0 1 1 0
DT 08,9D,60 ; 039 196.6 * 1 0 0 1 1 1
DT 09,2F,60 ; 040 199.5 * 1 0 1 0 0 0
DT 07,82,70 ; 041 203.5 1 0 1 0 0 1
DT 07,76,70 ; 042 206.5 * 1 0 1 0 1 0
DT 07,66,70 ; 043 210.7 1 0 1 0 1 1
DT 07,6F,6A ; 044 218.1 1 0 1 1 0 0
DT 06,0xA3,70 ; 045 225.7 1 0 1 1 0 1
DT 06,98,70 ; 046 229.1 * 1 0 1 1 1 0
DT 06,8A,70 ; 047 233.6 1 0 1 1 1 1
DT 06,72,70 ; 048 241.8 1 1 0 0 0 0
DT 04,0xC3,99 ; 049 250.3 1 1 0 0 0 1
DT 04,0xB9,99 ; 050 254.1 * 1 1 0 0 1 0
DT 05,1C,99 ; 051 255 * 1 1 0 0 1 1
DT 03,15,20 ; 052 1750 Eu Tone 1 1 0 1 0 0
DT 05,0F,10 ; 053 1800 Eu Tone 1 1 0 1 0 1
DT 01,84,9D ; 054 1200 Packet 1 1 0 1 1 0
DT 02,13,30 ; 055 2200 Packet 1 1 0 1 1 1
DT 03,26,50 ; 056 800 * 1 1 1 0 0 0
DT 03,0F,50 ; 057 900 * 1 1 1 0 0 1
DT 02,3F,50 ; 058 1100 * 1 1 1 0 1 0
DT 03,36,20 ; 059 1300 * 1 1 1 0 1 1
DT 01,68,20 ; 060 1500 * 1 1 1 1 0 0
DT 03,09,20 ; 061 2000 * 1 1 1 1 0 1
DT 02,1A,20 ; 062 2500 * 1 1 1 1 1 0
DT 02,07,20 ; 063 3500 * 1 1 1 1 1 1
;
; * Indicates non EIA standard tone
;
ORG 2100H
END
All CTCSS tones are within EIA standard of .08% .
Use a 4Mhz crystal with 2x18pF capacitors.
PTT line is active LOW. PTT is RB7 Pin 13.
OUTPUT tone is on RA2 Pin1 ,see Low pass filter diag.
Lines RB0-RB5 can be fitted with DIP switches to set
tone frequencies as per table above. A 1 on the table
indicates the RB pin is logic HI . All RB port pins have
been programmed with internal pullup resistors and will
float HI if left open. The binary inputs are read only on
power up and not each time the PTT is keyed.
For CTCSS tones use a Low pass filter as shown here as the
output waveform is square. RO is an padding resistor to
allow for level adjustment typically 20k.
RA2--------2k2----------RO----Output
Pin1 |
|
1uF
|
GND
;
; unsigned int accu = 0; // phase accumulator
; unsigned int tone = 0; // tone phase offset
; unsigned char angle = 0; // sine array index
;
; #define lo(x) (char)((x)&255)
; #define hi(x) (char)((x)/256)
;
; #define r08 const rom unsigned char
;
; r08 sine[] = { 128,140,152,165,176,188,198,208,
; 218,226,234,240,245,250,253,254,
; 255,254,253,250,245,240,234,226,
; 218,208,198,188,176,165,152,140,
; 128,115,103,090,079,067,057,047,
; 037,029,021,015,010,005,002,001,
; 000,001,002,005,010,015,021,029,
; 037,047,057,067,079,090,103,115 };
;
; void interrupt() // 128-usec timer 2 interrupts
; { pir1.TMR2IF = 0; // clear timer 2 interrupt flag
; accu += tone; // bump phase accumulator
; angle = hi(accu)>>2; // upper 6 bits for sine index
; ccpr1l = sine[angle]; // duty cycle for next period
; } //
;
; void main()
; { cmcon0 = 7; // comparator off
; ansel = 0; // analog off, all digital I/O
; trisio = 0b00111011; // GP2 output, all others input
; osccon = 0b01110000; // set INTOSC to 8-MHz
; while(!osccon.HTS); // wait for oscillator stable
; pie1 = 1<<TMR2IE; // enable timer 2 interrupts
; pr2 = 256 - 1; // 128-usec period (7812.5 Hz)
; ccpr1l = 0; // set initial 0% duty cycle
; ccp1con = 0b00001100; // --00---- duty cycle b1..b0
; // ----1100 pwm mode, active hi
; intcon.GIE = 1; // enable global interrupts
; intcon.PEIE = 1; // enable peripheral interrupts
; t2con = 1<<TMR2ON; //
;
; tone = 65536/(78125/915); // phase offset for 91.5 Hz
;
; while(1) //
; { //
; } //
; } //
;
Hi Baxter',
I believe that program is generating a square wave output. Is that what you want?
Mike, I'm just not figuring out how to get a sine wave. I'll take you up on your offer. I haven't chosen a pic yet, so it can be one with PWM. I have not done a lot of pic programming and I am definitely still a novice. I appreciate your help.Hi Baxter',
What PIC device are you using? If it has a PWM module and if you hang in there, I'll post you a C example.
Well, I think I am dense. I am having a lot of trouble figuring this one out. I had hoped to find a simple example out there so that I could look at it and learn. No such luck. There are lots of PWM sine examples, most in ASM and the ones in C are pretty complex. It sounded like it is suppose to be a fairly simple thing.
I have really hesitated asking, but could someone post a simple PWM sine wave generator example in C. Thanks in advance. I think it would be very beneficial to all of us newbie PIC people.
I have not figured out how to do it in C but I do understand the concept, I think.can any1 tell me how does it ACTUALLY work? I mean, pin can only give 1 or 0 and how to achieve
Thanks. I thought that one said it only generated a very low frequency, but I see it was the resolution frequency (I should learn to read). I got it confused so didn't look too hard at it. Sorry. I'll have a look at it and see what I can come up with.The listing in post #25, if you were to turn it into a BoostC program, is pretty much a complete solution that will generate a 91.5-Hz sine wave.
Mike
The listing in post #25, if you were to turn it into a BoostC program, is pretty much a complete solution that will generate a 91.5-Hz sine wave.
I understand that the DDS concept may not be very easy to understand.
Mike
tone = 65536/(78125/2541); // phase offset for 254.1-Hz
/********************************************************************
* *
* Project: CTCSS old *
* Source: CTCSS_old.c *
* Author: Mike McLaren, K8LH *
* Date: 26-Nov-10 *
* Revised: 26-Nov-10 *
* *
* Old 12F683 DDS(PWM) CTCSS Sine Wave Tone Generator Demo' *
* *
* *
* IDE: MPLAB 8.56 (tabs = 4) *
* Lang: SourceBoost BoostC v7.01, Lite/Free version *
* *
********************************************************************/
#include <system.h>
#pragma DATA _CONFIG, _MCLRE_OFF, _WDT_OFF, _INTOSCIO
unsigned int accu = 0; // phase accumulator
unsigned int tone = 0; // tone phase offset
unsigned char angle = 0; // sine array index
#define lo(x) (char)((x)&255)
#define hi(x) (char)((x)/256)
#define r08 const rom unsigned char
r08 sine[] = { 128,140,152,165,176,188,198,208,
218,226,234,240,245,250,253,254,
255,254,253,250,245,240,234,226,
218,208,198,188,176,165,152,140,
128,115,103, 90, 79, 67, 57, 47,
37, 29, 21, 15, 10, 5, 2, 1,
0, 1, 2, 5, 10, 15, 21, 29,
37, 47, 57, 67, 79, 90,103,115 };
void interrupt() // 128-usec timer 2 interrupts
{ pir1.TMR2IF = 0; // clear timer 2 interrupt flag
accu += tone; // bump phase accumulator
angle = hi(accu)>>2; // upper 6 bits for sine index
ccpr1l = sine[angle]; // duty cycle for next period
} //
void main()
{ cmcon0 = 7; // comparator off
ansel = 0; // analog off, all digital I/O
trisio = 0b00111011; // GP2 output, all others input
osccon = 0b01110000; // set INTOSC to 8-MHz
while(!osccon.HTS); // wait for oscillator stable
pie1 = 1<<TMR2IE; // enable timer 2 interrupts
pr2 = 256 - 1; // 128-usec period (7812.5 Hz)
ccpr1l = 0; // set initial 0% duty cycle
ccp1con = 0b00001100; // --00---- duty cycle b1..b0
// ----1100 pwm mode, active hi
intcon.GIE = 1; // enable global interrupts
intcon.PEIE = 1; // enable peripheral interrupts
t2con = 1<<TMR2ON; //
tone = 65536/(78125/915); // phase offset for 91.5 Hz
while(1) //
{ //
} //
}
/********************************************************************
* *
* Project: CTCSS 12F683 *
* Source: CTCSS_12F683.c *
* Author: Mike McLaren, K8LH *
* Date: 26-Nov-10 *
* Revised: 26-Nov-10 *
* *
* High Performance 12F683 DDS(PWM) CTCSS Tone Generator Demo *
* with 24-bit Phase Accumulator (8.388608-MHz crystal) *
* *
* IDE: MPLAB 8.56 (tabs = 4) *
* Lang: SourceBoost BoostC v7.01, Lite/Free version *
* *
********************************************************************/
#include <system.h>
#pragma DATA _CONFIG, _MCLRE_OFF, _WDT_OFF, _HS_OSC
#pragma CLOCK_FREQ 8388608 // using an 8.388608-MHz crystal
//--< function prototypes >------------------------------------------
//--< type definitions >---------------------------------------------
typedef unsigned char u08;
typedef unsigned int u16;
typedef unsigned long u32;
#define r08 rom char*
//--< variables >----------------------------------------------------
u32 accum = 0; // phase accumulator
u32 phase = 0; // phase offset (DDS tuning word)
r08 sinetbl = { 100,102,104,107,109,112,114,117,119,121,
124,126,129,131,133,135,138,140,142,144,
147,149,151,153,155,157,159,161,163,165,
167,168,170,172,174,175,177,178,180,181,
183,184,185,187,188,189,190,191,192,193,
194,194,195,196,197,197,198,198,198,199,
199,199,199,199,200,199,199,199,199,199,
198,198,198,197,197,196,195,194,194,193,
192,191,190,189,188,187,185,184,183,181,
180,178,177,175,174,172,170,168,167,165,
163,161,159,157,155,153,151,149,147,144,
142,140,138,135,133,131,129,126,124,121,
119,117,114,112,109,107,104,102, 99, 97,
95, 92, 90, 87, 85, 82, 80, 78, 75, 73,
70, 68, 66, 64, 61, 59, 57, 55, 52, 50,
48, 46, 44, 42, 40, 38, 36, 34, 32, 31,
29, 27, 25, 24, 22, 21, 19, 18, 16, 15,
14, 12, 11, 10, 9, 8, 7, 6, 5, 5,
4, 3, 2, 2, 1, 1, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 1,
1, 2, 2, 3, 4, 5, 5, 6, 7, 8,
9, 10, 11, 12, 14, 15, 16, 18, 19, 21,
22, 24, 25, 27, 29, 31, 32, 34, 36, 38,
40, 42, 44, 46, 48, 50, 52, 55, 57, 59,
61, 64, 66, 68, 70, 73, 75, 78, 80, 82,
85, 87, 90, 92, 95, 97 };
//--< defines >------------------------------------------------------
//--< isr >----------------------------------------------------------
/*
* 12F/16F1xxx DDS-PWM CTCSS Access Tone Generator Notes
* =====================================================
*
* using an 8.388608 MHz crystal
*
* Tcy = 1 / 8388608 * 4 = 476.837158203125 nsecs
*
* using a 200 cycle PWM period provides a DDS frequency of
*
* Fdds = 1 / (200 Tcy) = 10,485.76 Hz
*
* frequency resolution using a 24 bit phase accumulator is
*
* Fres = Fdds / 2^24
* Fres = 10485.76 / 16777216 = 0.000625 Hz
*
* dds tuning word (phase offset) can be calculated a couple
* different ways. since the dds frequency resolution (Fres)
* is basically 0.01-Hz divided by 16, you can calculate the
* phase offset by mulitplying desired Fout output frequency
* by 1600. the phase offset for an Fout of 254.1-Hz is;
*
* phase = (Fout * 100) * 16
* = (254.1 * 100) * 16 = 406560
*
* phase = 25410 << 4 = 406560
*
* or you can also calculate phase offset like this (yuch!);
*
* phase = Fout / Fres
* = 254.1 / 0.000625 = 406560
*
* phase = Fout * 2^24 / Fdds
* = 254.1 * 16777216 / 10485.76 = 406560
*
* the highest CTCSS frequency (254.1 Hz) will produce the
* smallest number of sine wave D/A output points per cycle;
*
* INT(10485.76 / 254.1) = 41 output points per cycle
*
*/
void interrupt() // 200-cycles (10485.76-Hz)
{ pir1.TMR2IF = 0; // clear TMR2 interrupt flag
accum += phase; // add phase offset to accum
ccpr1l = sinetbl[accum>>16]; // sine duty cycle value for
} // next PWM period
//--< main >---------------------------------------------------------
void main()
{
cmcon0 = 7; // comparator off, digital I/O
ansel = 0; // a2d module off, digital I/O
trisio = 0b00111011; // GP2 output, all others input
/*
* setup PWM module for 200 cycle interrupts (10485.76-Hz with
* an 8.388608-MHz clock)
*
*/
ccp1con = 0b00001100; // 00001100
// --00---- DC1B<1:0>, duty cycle b1:b0
// ----1100 CCP1M<3:0>, pwm mode
t2con = 0b00000000; // 00000000
// -0000--- TOUTPS<3:0>, postscale 1
// -----0-- TMR2ON, timer off
// ------00 T2CKPS<1:0>, prescale 1
// for 476.837158203125 nsec 'ticks'
pr2 = 200-1; // for 95.367431640625 usec interrupts
ccpr1l = 0; // 0% duty cycle
pie1 = 1<<TMR2IE; // enable Timer 2 interrupts
pir1 = 0; // clear all peripheral interrupt flags
intcon.PEIE = 1; // enable peripheral interrupts
intcon.GIE = 1; // enable global interrupts
t2con.TMR2ON = 1; // turn TMR2 on
phase = 25410<<4; // phase offset for 254.1-Hz tone
while(1); // loop forever
}
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?