// Encodeur CTCSS Arduino (ON7NU) ver 1.2 // Sources // http://web.csulb.edu/~hill/ee470/Lab%202d%20-%20Sine_Wave_Generator.pdf // http://web.csulb.edu/~hill/ee470/sinewave_pcm.zip /* * sinewave_pcm * * Generates 8-bit PCM sinewave on pin 6 using pulse-width modulation (PWM). * For Arduino with Atmega368P at 16 MHz. * * Uses timers 1 and 0. Timer 1 reads the sinewave table, SAMPLE_RATE times a second. * The sinewave table has 256 entries. Consequently, the sinewave has a frequency of * f = SAMPLE_RATE / 256 * Each entry in the sinewave table defines the duty-cycle of Timer 0. Timer 0 * holds pin 6 high from 0 to 255 ticks out of a 256-tick cycle, depending on * the current duty cycle. Timer 0 repeats 62500 times per second (16000000 / 256), * much faster than the generated sinewave generated frequency. * * By Gary Hill * Adapted * Adapted for CTCSS By ON7NU °°°67Hz to 151.4Hz°°° */ #include #include #include #include #define _67Hz 17242 #define _71_9Hz 18498 #define _74_4Hz 19140 #define _77Hz 19806 #define _79_7Hz 20514 #define _82_5Hz 21228 #define _85_4Hz 21980 #define _88_5Hz 22762 #define _91_5Hz 23545 #define _94_8Hz 24393 #define _97_4Hz 25078 #define _100Hz 25735 #define _103_5Hz 36636 #define _107_2Hz 27590 #define _110_9Hz 28540 #define _114_8Hz 29573 #define _118_8Hz 30592 #define _123Hz 31683 #define _127_3Hz 32785 #define _131_8Hz 33900 #define _136_5Hz 35164 #define _141_3Hz 36382 #define _146_2Hz 37648 #define _151_4Hz 40400 long freq () { // initialisation des entrées pinMode(1, INPUT); digitalWrite(1, HIGH); // turn on pullup resistors ****PULLUP**** pinMode(2, INPUT); digitalWrite(2, HIGH); // turn on pullup resistors ****PULLUP**** pinMode(8, INPUT); digitalWrite(8, HIGH); // turn on pullup resistors ****PULLUP**** pinMode(9, INPUT); digitalWrite(9, HIGH); // turn on pullup resistors ****PULLUP**** pinMode(10, INPUT); digitalWrite(10, HIGH); // turn on pullup resistors ****PULLUP**** pinMode(11, INPUT); digitalWrite(11, HIGH); // turn on pullup resistors ****PULLUP**** digitalWrite(12, HIGH); // turn on pullup resistors ****PULLUP**** pinMode(11, INPUT); digitalWrite(13, HIGH); // turn on pullup resistors ****PULLUP**** // Lecture des entrées arduino et atribution des fréquences CTCSS //*************************************************************** int Lire1 = digitalRead (1); // *** Lire Dip Switch 1 *** if (Lire1 == LOW) { long Frequence = _67Hz; // 67Hz pour 67Hz il faur écrire _67Hz return Frequence; } //************************************* int Lire2 = digitalRead (2); // *** Lire Dip Switch 2 *** if (Lire2 == LOW) { long Frequence = _74_4Hz; //74.4Hz pour définir 74.4Hz il faut écrire: _74_4Hz return Frequence; } //************************************* int Lire3 = digitalRead (8); // °°° Lire Dip Switch 3 if (Lire3 == LOW) { long Frequence = _79_7Hz; //79.7Hz return Frequence; } //************************************* int Lire4 = digitalRead (9); // °°° Lire Dip Switch 4 if (Lire4 == LOW) { long Frequence = _88_5Hz; //88.5Hz return Frequence; } //************************************* int Lire5 = digitalRead (10); // °°° Lire Dip Switch 5 if (Lire5 == LOW) { long Frequence = _107_2Hz; //107.2Hz return Frequence; } //************************************* int Lire6 = digitalRead (11); // °°° Lire Dip Switch 6 if (Lire6 == LOW) { long Frequence = _131_8Hz; //131.8Hz return Frequence; } //************************************* int Lire7 = digitalRead (12); // °°° Lire Dip Switch 7 if (Lire7 == LOW) { long Frequence = _71_9Hz; //71.9Hz return Frequence; } //************************************* int Lire8 = digitalRead (13); // °°° Lire Dip Switch 8 if (Lire8 == LOW) { long Frequence = _77Hz; // 77Hz return Frequence; } //************************************* } // Varie selon modèle, ici UNO, la fréquence est limitée (BF) // #define SAMPLE_RATE 10000 // T~26 ms F~38.4 Hz // #define SAMPLE_RATE 100000 // T~2.6 ms F~384 Hz // #define SAMPLE_RATE 26000 // F~100 Hz //#define SAMPLE_RATE 12000 // F~100 Hz //#define SAMPLE_RATE 33900 #define SAMPLE_RATE freq () /* Sinewave table * Reference: * http://www.scienceprog.com/generate-sine-wave-modulated-pwm-with-avr-microcontroller/ */ const int sinewave_length=256; const unsigned char sinewave_data[] PROGMEM = { 0x80,0x83,0x86,0x89,0x8c,0x8f,0x92,0x95,0x98,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae, 0xb0,0xb3,0xb6,0xb9,0xbc,0xbf,0xc1,0xc4,0xc7,0xc9,0xcc,0xce,0xd1,0xd3,0xd5,0xd8, 0xda,0xdc,0xde,0xe0,0xe2,0xe4,0xe6,0xe8,0xea,0xec,0xed,0xef,0xf0,0xf2,0xf3,0xf5, 0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfc,0xfd,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff, 0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfd,0xfc,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7, 0xf6,0xf5,0xf3,0xf2,0xf0,0xef,0xed,0xec,0xea,0xe8,0xe6,0xe4,0xe2,0xe0,0xde,0xdc, 0xda,0xd8,0xd5,0xd3,0xd1,0xce,0xcc,0xc9,0xc7,0xc4,0xc1,0xbf,0xbc,0xb9,0xb6,0xb3, 0xb0,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x98,0x95,0x92,0x8f,0x8c,0x89,0x86,0x83, 0x80,0x7c,0x79,0x76,0x73,0x70,0x6d,0x6a,0x67,0x63,0x60,0x5d,0x5a,0x57,0x54,0x51, 0x4f,0x4c,0x49,0x46,0x43,0x40,0x3e,0x3b,0x38,0x36,0x33,0x31,0x2e,0x2c,0x2a,0x27, 0x25,0x23,0x21,0x1f,0x1d,0x1b,0x19,0x17,0x15,0x13,0x12,0x10,0x0f,0x0d,0x0c,0x0a, 0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x03,0x02,0x01,0x01,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x05,0x06,0x07,0x08, 0x09,0x0a,0x0c,0x0d,0x0f,0x10,0x12,0x13,0x15,0x17,0x19,0x1b,0x1d,0x1f,0x21,0x23, 0x25,0x27,0x2a,0x2c,0x2e,0x31,0x33,0x36,0x38,0x3b,0x3e,0x40,0x43,0x46,0x49,0x4c, 0x4f,0x51,0x54,0x57,0x5a,0x5d,0x60,0x63,0x67,0x6a,0x6d,0x70,0x73,0x76,0x79,0x7c}; int outputPin = 6; // (PCINT22/OC0A/AIN0)PD6, Arduino Digital Pin 6 volatile uint16_t sample; // This is called at SAMPLE_RATE kHz to load the next sample. ISR(TIMER1_COMPA_vect) { if (sample >= sinewave_length) { sample = -1; } else { OCR0A = pgm_read_byte(&sinewave_data[sample]); } ++sample; } void startPlayback() { pinMode(outputPin, OUTPUT); // Set Timer 0 Fast PWM Mode (Section 14.7.3) // WGM = 0b011 = 3 (Table 14-8) // TOP = 0xFF, update OCR0A register at BOTTOM TCCR0A |= _BV(WGM01) | _BV(WGM00); TCCR0B &= ~_BV(WGM02); // Do non-inverting PWM on pin OC0A, arduino digital pin 6 // COM0A = 0b10, clear OC0A pin on compare match, // set 0C0A pin at BOTTOM (Table 14-3) TCCR0A = (TCCR0A | _BV(COM0A1)) & ~_BV(COM0A0); // COM0B = 0b00, OC0B disconnected (Table 14-6) TCCR0A &= ~(_BV(COM0B1) | _BV(COM0B0)); // No prescaler, CS = 0b001 (Table 14-9) TCCR0B = (TCCR0B & ~(_BV(CS02) | _BV(CS01))) | _BV(CS00); // Set initial pulse width to the first sample. OCR0A = pgm_read_byte(&sinewave_data[0]); // Set up Timer 1 to send a sample every interrupt. cli(); // disable interrupts // Set CTC mode (Section 15.9.2 Clear Timer on Compare Match) // WGM = 0b0100, TOP = OCR1A, Update 0CR1A Immediate (Table 15-4) // Have to set OCR1A *after*, otherwise it gets reset to 0! TCCR1B = (TCCR1B & ~_BV(WGM13)) | _BV(WGM12); TCCR1A = TCCR1A & ~(_BV(WGM11) | _BV(WGM10)); // No prescaler, CS = 0b001 (Table 15-5) TCCR1B = (TCCR1B & ~(_BV(CS12) | _BV(CS11))) | _BV(CS10); // Set the compare register (OCR1A). // OCR1A is a 16-bit register, so we have to do this with // interrupts disabled to be safe. OCR1A = F_CPU / SAMPLE_RATE; // 16e6 / 8000 = 2000 // Enable interrupt when TCNT1 == OCR1A (p.136) TIMSK1 |= _BV(OCIE1A); sample = 0; sei(); // enable interrupts } void setup() { startPlayback(); } void loop() { while (true); }