/* * File: main.c * Author: jrich & mwainwright * * Created on Jan 21, 2019, 12:42 PM * fixed on Jan 15 2020 * Updated to 64 programs version */ //Pin IO //1 = +5 //2 = RA5/CCP1 (PWM) - DDS output //3 = RA4/AN3 (Phaseshift) - readADC (2) - version 1 jumper to pin 7 (RA0) //4 = MCLR/VPP //5 = RA2 using external interrupt flag - tactile pre-set //6 = RA1/AN1/ICSPCLK - readADC (1) //7 = RA0/ICSPDAT //8 = GND // CONFIG1 #pragma config FOSC = INTOSC // Oscillator Selection->INTOSC oscillator: I/O function on CLKIN pin #pragma config WDTE = OFF // Watchdog Timer Enable->WDT disabled #pragma config PWRTE = OFF // Power-up Timer Enable->PWRT disabled #pragma config MCLRE = ON // MCLR Pin Function Select->MCLR/VPP pin function is MCLR #pragma config CP = OFF // Flash Program Memory Code Protection->Program memory code protection is disabled #pragma config CPD = OFF // Data Memory Code Protection->Data memory code protection is disabled #pragma config BOREN = ON // Brown-out Reset Enable->Brown-out Reset enabled #pragma config CLKOUTEN = OFF // Clock Out Enable->CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin #pragma config IESO = ON // Internal/External Switchover->Internal/External Switchover mode is enabled #pragma config FCMEN = ON // Fail-Safe Clock Monitor Enable->Fail-Safe Clock Monitor is enabled // CONFIG2 #pragma config WRT = OFF // Flash Memory Self-Write Protection->Write protection off #pragma config PLLEN = ON // PLL Enable->4x PLL enabled #pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable->Stack Overflow or Underflow will cause a Reset #pragma config BORV = LO // Brown-out Reset Voltage Selection->Brown-out Reset Voltage (Vbor), low trip point selected. #pragma config LVP = ON // Low-Voltage Programming Enable->Low-voltage programming enabled //////////////////////////// #include #include #include #define LED PORTAbits.RA0 // RA0 (pin 7) #define _XTAL_FREQ 32000000 #define ADCStart ADCON0bits.GO_nDONE = 1 //set this bit to begin ADC conversion ////////////////////////////////////////////////////////////////////////////// unsigned char ctr = 1; // counter for presets, initial pseudorandom unsigned char ctr2 = 1; // counter2 for other presets,initial pseudorandom char bootflag = 0; //counter step variables unsigned char step; unsigned char step1; unsigned char step2; unsigned char step3; const unsigned char sine[256] = {// sine wave 8 bit resolution scaled to 94% max val 120, 123, 126, 129, 132, 134, 137, 140, 143, 146, 149, 152, 155, 157, 160, 163, 165, 168, 171, 174, 177, 179, 181, 184, 186, 189, 191, 194, 196, 198, 200, 202, 205, 207, 209, 211, 212, 214, 216, 218, 220, 221, 223, 224, 226, 227, 228, 229, 230, 231, 233, 234, 235, 235, 236, 237, 238, 238, 239, 239, 239, 240, 240, 240, 240, 240, 240, 240, 239, 239, 239, 238, 238, 237, 236, 235, 235, 234, 233, 231, 230, 229, 228, 227, 226, 224, 223, 221, 220, 218, 216, 214, 212, 211, 209, 207, 205, 202, 200, 198, 196, 194, 191, 189, 186, 184, 181, 179, 177, 174, 171, 168, 165, 163, 160, 157, 155, 152, 149, 146, 143, 140, 137, 134, 132, 129, 126, 123, 120, 117, 114, 111, 108, 105, 102, 100, 97, 94, 91, 87, 85, 83, 80, 77, 74, 71, 69, 66, 63, 61, 58, 55, 54, 51, 49, 46, 44, 41, 39, 38, 35, 33, 31, 29, 27, 25, 24, 22, 20, 19, 17, 16, 14, 13, 11, 10, 9, 8, 7, 6, 5, 5, 4, 3, 2, 2, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 3, 4, 5, 5, 6, 7, 8, 9, 10, 11, 13, 14, 16, 17, 19, 20, 22, 24, 25, 27, 29, 31, 33, 35, 38, 39, 41, 44, 46, 49, 51, 54, 55, 58, 61, 63, 66, 69, 71, 74, 77, 80, 83, 85, 87, 91, 94, 97, 100, 102, 105, 108, 111, 114, 117 }; const unsigned char triangle[256] = {// triangle wave 8 bit resolution scaled to 94% max val 120, 121, 123, 125, 127, 129, 131, 133, 134, 136, 138, 140, 142, 144, 146, 148, 149, 151, 153, 155, 157, 159, 161, 163, 165, 166, 168, 170, 172, 174, 176, 178, 180, 181, 183, 185, 187, 189, 191, 193, 195, 196, 198, 200, 202, 204, 206, 208, 210, 212, 213, 215, 217, 219, 221, 223, 225, 227, 228, 230, 232, 234, 236, 238, 240, 238, 236, 234, 232, 230, 228, 227, 225, 223, 221, 219, 217, 215, 213, 212, 210, 208, 206, 204, 202, 200, 198, 196, 195, 193, 191, 189, 187, 185, 183, 181, 180, 178, 176, 174, 172, 170, 168, 166, 165, 163, 161, 159, 157, 155, 153, 151, 149, 148, 146, 144, 142, 140, 138, 136, 134, 133, 131, 129, 127, 125, 123, 121, 120, 118, 117, 115, 113, 111, 109, 107, 105, 103, 102, 100, 98, 96, 94, 92, 90, 88, 86, 85, 83, 81, 79, 77, 75, 73, 71, 70, 68, 66, 64, 62, 60, 58, 56, 55, 53, 51, 49, 47, 45, 43, 41, 39, 38, 36, 34, 32, 30, 28, 26, 24, 23, 21, 19, 17, 15, 13, 11, 9, 8, 6, 4, 2, 0, 2, 4, 6, 8, 9, 11, 13, 15, 17, 19, 21, 23, 24, 26, 28, 30, 32, 34, 36, 38, 39, 41, 43, 45, 47, 49, 51, 53, 55, 56, 58, 60, 62, 64, 66, 68, 70, 71, 73, 75, 77, 79, 81, 83, 85, 86, 88, 90, 92, 94, 96, 98, 100, 102, 103, 105, 107, 109, 111, 113, 115, 117, 118 }; const unsigned char saw[256] = {// saw wave 8 bit resolution scaled to 94% max val 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, 162, 163, 164, 165, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, 180, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240, 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 118, 119 }; const unsigned char triangle3[256] = {// triangle3 wave 8 bit resolution scaled to 94% max val 120, 122, 124, 127, 129, 131, 133, 135, 137, 139, 141, 143, 146, 148, 149, 151, 153, 155, 156, 158, 160, 162, 164, 165, 167, 169, 171, 173, 175, 177, 179, 180, 182, 184, 186, 189, 191, 193, 196, 197, 200, 202, 205, 207, 210, 212, 214, 216, 219, 221, 223, 226, 227, 229, 231, 232, 234, 235, 236, 238, 238, 239, 240, 240, 240, 240, 240, 239, 238, 238, 236, 235, 234, 232, 231, 229, 227, 226, 223, 221, 219, 216, 214, 212, 210, 207, 205, 202, 200, 197, 196, 193, 191, 189, 186, 184, 182, 180, 179, 177, 175, 173, 171, 169, 167, 165, 164, 162, 160, 158, 156, 155, 153, 151, 149, 148, 146, 143, 141, 139, 137, 135, 133, 131, 129, 127, 124, 122, 120, 118, 116, 113, 111, 109, 107, 104, 102, 101, 99, 97, 94, 92, 90, 88, 86, 85, 84, 82, 80, 78, 76, 74, 72, 71, 69, 67, 65, 63, 61, 59, 57, 55, 54, 51, 49, 47, 44, 42, 39, 38, 35, 33, 30, 28, 25, 24, 21, 19, 17, 14, 12, 10, 8, 8, 6, 5, 4, 2, 2, 1, 0, 0, 0, 0, 0, 1, 2, 2, 4, 5, 6, 8, 8, 10, 12, 14, 17, 19, 21, 24, 25, 28, 30, 33, 35, 38, 39, 42, 44, 47, 49, 51, 54, 55, 57, 59, 61, 63, 65, 67, 69, 71, 72, 74, 76, 78, 80, 82, 84, 85, 86, 88, 90, 92, 94, 97, 99, 101, 102, 104, 107, 109, 111, 113, 116, 118 }; const unsigned char saw7[256] = {// saw7 wave 8 bit resolution scaled to 94% max val 120, 121, 123, 125, 127, 128, 130, 131, 132, 133, 133, 134, 134, 134, 134, 135, 135, 135, 135, 135, 135, 135, 135, 136, 136, 137, 138, 139, 140, 142, 143, 145, 147, 149, 150, 152, 154, 156, 157, 159, 161, 162, 163, 164, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 165, 166, 167, 168, 169, 171, 172, 174, 177, 179, 180, 182, 185, 187, 189, 191, 193, 195, 196, 196, 197, 197, 197, 197, 197, 196, 196, 196, 195, 194, 193, 192, 191, 191, 191, 192, 192, 194, 195, 196, 199, 202, 205, 209, 212, 216, 220, 224, 227, 230, 234, 236, 238, 240, 240, 240, 238, 235, 232, 227, 222, 215, 208, 199, 190, 180, 168, 157, 145, 133, 120, 107, 95, 83, 71, 60, 50, 40, 32, 24, 18, 12, 8, 5, 2, 0, 0, 0, 2, 4, 6, 9, 12, 16, 20, 24, 27, 31, 35, 38, 40, 43, 45, 46, 48, 48, 49, 49, 49, 48, 47, 46, 45, 44, 44, 43, 42, 42, 42, 42, 42, 43, 44, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 66, 68, 69, 71, 71, 72, 73, 74, 75, 75, 75, 75, 75, 74, 74, 74, 74, 74, 74, 74, 75, 75, 76, 77, 78, 79, 81, 83, 84, 86, 87, 89, 91, 93, 95, 97, 98, 100, 101, 102, 102, 103, 103, 104, 104, 104, 104, 104, 104, 104, 104, 105, 105, 105, 105, 106, 107, 108, 109, 110, 112, 113, 115, 117, 118 }; const unsigned char myarray[256] = {// myarray 8 bit resolution. //Microcomputer music is always in-flux, noisy and may be overwritten. Adjusted ASCII to decimal conversion 217, 211, 217, 214, 208, 202, 252, 249, 252, 234, 240, 243, 234, 243, 234, 226, 223, 211, 199, 205, 197, 194, 211, 220, 211, 199, 194, 194, 199, 205, 211, 223, 223, 255, 249, 243, 243, 249, 246, 243, 243, 234, 214, 197, 199, 214, 197, 208, 197, 191, 199, 191, 156, 104, 168, 217, 205, 199, 208, 220, 211, 205, 197, 199, 208, 202, 182, 121, 60, 0, 17, 37, 104, 168, 217, 208, 194, 199, 211, 223, 252, 249, 252, 249, 249, 243, 249, 249, 252, 234, 234, 240, 243, 234, 228, 240, 240, 234, 231, 223, 252, 249, 249, 252, 252, 249, 243, 240, 237, 231, 228, 240, 243, 249, 243, 249, 252, 249, 246, 240, 234, 223, 226, 223, 226, 226, 214, 197, 194, 199, 208, 194, 211, 220, 226, 228, 231, 220, 231, 226, 223, 217, 205, 211, 228, 246, 246, 246, 246, 237, 231, 243, 234, 214, 223, 234, 231, 234, 214, 223, 255, 249, 246, 246, 249, 246, 237, 240, 240, 231, 243, 249, 252, 249, 249, 243, 240, 240, 246, 243, 249, 249, 249, 252, 249, 246, 249, 252, 252, 234, 243, 249, 249, 252, 249, 243, 249, 249, 249, 246, 237, 226, 223, 234, 240, 246, 240, 237, 231, 226, 228, 226, 234, 243, 249, 243, 234, 214, 223, 165, 104, 168, 231, 237, 226, 182, 136, 78, 20, 37, 104, 168, 231, 237, 226, 214, 208, 194, 199, 202, 208, 217, 217, 199, 202, 182, 121, 60, 0, 17, 37, 104, 168, 234, 234, 228 }; ////////////////////////////////Global variable here////////////////////////////////////////////// long PhaseAccum; //phase accumulator generates the cycle rate for lookup table //loading thereby changing frequency. The MSbyte is used to provide the byte address //of the look up table value to be used. long PhaseShift; //value added to PhaseAccum every PWM cycle. This makes the waveform //lookup faster or slower which changes frequency. //////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////PIC Config routine here//////////////////////////////////// //map function // eg map(readADC(1), 0, 1023, 0, 255); //long map(long x, long in_min, long in_max, long out_min, long out_max) { // return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; //} void Init_Main() { //PIC12F1840 specific config OPTION_REG = 0b11000000; // disable internal pull ups OSCCON = 0b11110000; // 8MHz clk //32Mhz pll TRISA = 0b00011111; // configure IO/A2D(GPIO0) and MCLR set as inputs // direction in/out T2CON = 0b00000100; // TMR2 ON, postscale 1:1, prescale 1:1 PR2 = (0x50); // sets PWM rate to approx 98.5KHz with 32Mhz internal oscillator CCP1CON = 0b00001111; // CCP1 ON, and set to simple PWM mode (pin 2) APFCONbits.CCP1SEL = 1; // RA2 = 0 RA5 = 1 //alternative pin function //tactile select PhaseShift = 0x00FFFFFF; // frequency values loaded into //0x00FFFFFF = 16777215 (24 bit)) ANSELA = 0b00010010; // select RA4 (pin 3) and RA1 (pin 6) as A2D inputs // ANSELA select as analogue or digital // PhaseShift and Touch //orig ADCON0 = 0b00001101; // configure ADC ADCON1 = 0b00100000; // configure ADC // 1 = right justification (bit 7) // 0 = left just. Seems to produce a 16-bit value! INTCON = 0b10010000; // config interrupt - GIE and INTE } // interrupt service routine - pre-set select tactile switch random! void __interrupt() ISR(void) { if (INTCONbits.INTF == 1) { //using external interrupt flag @ RA2 // __delay_ms(1); // debounce // if (INTCONbits.INTF == 1){ // if still pressed ctr = (rand () % 7); // randomise the counter 0-8 ctr2 = (rand () % 7); // randomise the counter2 0-8 INTCONbits.INTF = 0; //clear flag // } // //number of presets here! // if (ctr == (9 + 1)) // if counter reaches n, + 1 more than presets, // ctr = 1; // reset counter (min no.) // if (ctr2 == (5 + 1)) // if counter reaches n, + 1 more than presets, // ctr2 = 1; // reset counter (min no.) } } unsigned int readADC(unsigned char channel) { unsigned int AN_Val; // Select desired channel for ADC operation switch (channel) { case 1: // AN1 (pin 6) touch ADCON0bits.CHS = 1; break; case 2: // AN3 (pin 3) PhaseShift ADCON0bits.CHS = 3; break; default: // Any other value will default to: ADCON0bits.CHS = 0; // } // Channel selected proceed with ADC conversion __delay_us(5); // sampling time // can be c. 5 us - acquisition time // start a conversion ADCON0bits.GO = 1; //This sets the go/!done bit that starts conversion. Bit will be cleared when ADC is complete while (ADCON0bits.GO == 1) // __delay_us(10); // longer delay here influences the ISR and timers // can afford to leave this out AN_Val = ((ADRESH << 8) + ADRESL); // returns 10-bit // NOTE justification ADCON1! //AN_Val = ADRESH; //returns 8-bit return AN_Val; // int ADC(unsigned char channel) } ////////////////////////////main program loop here///////////////////////////////// void main() { Init_Main(); //config part unsigned int AN_Val; while (1) { //always do this //__delay_us(5); //testing the sample time for readADC function. Lower pitch and more aliasing. // written in nested loop below less aliasing // ////ADC channel 1 - LED test////// // // if (readADC(1) >= 32000) // NOTE justification ADCON1 needs to be right just for 10-bit? // left just @ 16-bit (65535)? // LED = 1; // else // LED = 0; // // ///////////// while (!PIR1bits.TMR2IF); // wait for TMR2 cycle to restart // nested loop? // Resolution of PWM. Standard up to 10 bits. Here set at 8 bit? (6 bits in MSbits - CCPRIL/2 bits in CCP1CON) // CCP1 RA5 = pin 2 (output) // What happens when bitwise operator is altered = PWM resolution? >> 4 quieter and lower freq. No bitwise? Distorted. Changes waveshape ramp-like // Moved to the left get PWM lower res and a kind of bit crushing << 4 // &PhaseAccum)[3] 3? // (char *) is a pointer to character at an address // (char *) & = a cast? convert type int - char? //some step variables step ^= ADRESL; //step1 not used step2 += 1; step3 += 3; ////// 8 different waveform generators 'cores' /////// if (ctr2 == 0) { //nosy CCPR1L = (sine[((char *) &PhaseAccum)[3]]) + step + 1; // * 2; // load MSbits 7-2 duty cycle value into CCPRIL CCP1CON ^= ((sine[step]) & 0x03) << 4; // load in bits 1-0 into 5 and 4 of CCP1CON } if (ctr2 == 1) { //sawww CCPR1L = ((char *) &PhaseAccum)[3] >> 2; CCP1CON ^= ((char *) &PhaseAccum)[3] & 0x03 << 4; } if (ctr2 == 2) { //vinegar CCPR1L = (sine[ ((char *) &PhaseAccum) [3] & readADC(1)]) >> 2; CCP1CON ^= ((sine[((char *) &PhaseAccum)[3]]) & 0x03) << 4; } if (ctr2 == 3) { //myarray CCPR1L = (myarray[((char *) &PhaseAccum)[3]]) >> 2; CCP1CON ^= ((myarray[((char *) &PhaseAccum)[3]]) & 0x03) << 4; } // 2nd edition if (ctr2 == 4) { //stanbard dog CCPR1L = (saw7[((char *) &PhaseAccum)[3]]) >> readADC(1) % 3; CCP1CON ^= ((triangle[((char *) &PhaseAccum)[step2]]) & 0x03) << 4; } if (ctr2 == 5) { //swine CCPR1L = (saw[((char *) &PhaseAccum)[3]]) >> 2; CCP1CON ^= ((sine[((char *) &PhaseAccum)[3]]) & 0x03); } if (ctr2 == 6) { //an-yooouuuu CCPR1L = (triangle[((char *) &PhaseAccum)[3] % PhaseAccum]) >> 2; CCP1CON ^= ((triangle3[((char *) &PhaseAccum)[3]]) & 3); } if (ctr2 == 7) { //1 wing CCPR1L = (triangle[((char *) &PhaseAccum)[3] & step3]) >> 1; CCP1CON ^= 0; } ////duty cycle value byte is now loaded for next cycle coming////// if (PIR1bits.ADIF == 0) ADCStart; //start ADC here to get value into PhaseShift to change Freq //will have to go around the loop one time before ready flag is high if (PIR1bits.ADIF) //if ADC read complete load values and clear flag // readADC(2) here seems to change the channel, also loads ADC value into ADRESL and ADRESH. // although is this then duplicated or overwritten below - ((char *) &PhaseShift)[1] = ADRESL etc.? readADC(2); ((char *) &PhaseShift)[1] = ADRESL; //load ADRESL into PhaseShift ((char *) &PhaseShift)[2] = ADRESH; //load ADRESH into PhaseShift PIR1bits.ADIF = 0; //clear flag so next time ADC can?run PIR1bits.TMR2IF = 0; // clear TMR2 int flag ////// 9 algorithms ////// //random initialisation, only once while (bootflag == 0) { __delay_us(10); //might help ctr = readADC(1) * readADC(0) % 7; __delay_us(10); //might help ctr2 = readADC(1) * readADC(0) % 7; bootflag = 1; } //stuff if (ctr == 0){ PhaseAccum = PhaseAccum + ((PhaseShift * sine[readADC(1)]) + 1); } //whistle FM if (ctr == 1){ PhaseAccum = PhaseAccum + (((PhaseShift << readADC(1)) * sine[step2]) + 1); //step2 += 1; //see variables } //brocken if (ctr == 2){ PhaseAccum = ((PhaseShift * sine[ADRESL]) + PhaseShift + readADC(1)); } //starling if (ctr == 3){ PhaseAccum = PhaseAccum % (PhaseAccum + step3) + (((PhaseShift * sine[step3 >> readADC(1)]))); //step3 += 3; } //sine if (ctr == 4){// brackets added! PhaseAccum = PhaseAccum + ((PhaseShift << 6) + 1); } //brownouts if (ctr == 5){ PhaseAccum = ((PhaseShift * sine[ADRESL]) + PhaseShift)*2232; } //speed-dial if (ctr == 6){ PhaseAccum = PhaseAccum + (PhaseShift << (myarray[readADC(1)] >> 5)); PhaseShift ^= readADC(1); } //strange memory effect if (ctr == 7){ ADRESL = readADC(1)*PhaseShift; PhaseAccum = PhaseAccum + ((PhaseShift * (sine[readADC(1)*6] ))); } } }