' QBASIC program to generate PIC code for 1-bit sine wave ' generation. ' ' Notes added 10/7/2009 ' ' This program does these things ... ' Calculates the frequency for a certain musical note based ' on the number of half-tones above A. This part isn't really ' essential to the 1-bit sine thing, but I just wanted to make ' a muscial note while I'm at it ... ' ' Then it creates an array of bits (1s and 0s) to fill the period ' of the desired sine wave with each bit assumed to be one ' microsecond wide. It does this by keeping a running total ' (integral) of a cosine function while stepping its argument ' through 0 to 360 degrees in steps dictated by the the 1 microsec ' width of each bit ... and ... keeping a separate running total of ' the array of bits created thus far. The next bit value depends ' on a comparison of the integral of the array with the integral ' of the cosine function. If the array's total is larger, the ' next bit is zero, otherwise, it's one. In this way the sum of ' the array's bits tracks the value of the cosine wave. ' ' The program next prints the bit array out to a text file of ' ones and zeroes, 50 per line. This is just for the user's ' amusement. It also prints some info on the parameters used to ' create the array. The text file's name is "1bit.txt". NOTE: ' The current version has this part "commented out". If you want ' to see the ones and zeroes, remove the " ' " characters from the ' front of the PRINT #1 "1" and PRINT #1 "0" statements. ' ' Finally, the program examines the array and prints to the same ' file the source code to be used in the PIC program to produce the ' bit array with the PIC. A little trick is used because there ' is not enough memory in the PIC I used to have one statement ' for every bit. There are long stretches of ones and similar ' stretches of zeroes in a row where a single repetitive command ' can be used and reused. If the current bit is different from ' the last, the program generates a SETHIGH or SETLOW statement ' as appropriate to change the output of the PIC. If the current ' bit is the same as the last, the program increments a counter. ' When the bit finally changes, the count reached is used to ' generate a subroutine call to "waste" that number of cycles. ' Note that the SETHIGH and SETLOW macros and the time wasting ' subroutines are all defined within the PIC program and not ' written by this one. Source text produced by this program is ' copied and then pasted into the source code for the PIC. The ' name of that source code file is "PIC-SINE.ASM". ' NRK 10/7/2009 outfile$ = "1bit.txt" ' for use as file name OPEN outfile$ FOR OUTPUT AS #1 degree = 5 ' degree is half tones above A (440 Hz) btone = 440 * 2 ^ (degree / 12) ' 5th tone is D note period = CINT(1 / btone * 1000000!) ' CINT rounds to nearest INT ' in microseconds PI = 3.14159265# ' QBASIC defaults to radians for trig incr = 2 * PI / period PRINT "period in us ", period PRINT #1, "; This code created by QBASIC program 1BITSINE.BAS" PRINT #1, "; period in u-sec = "; period PRINT #1, "; semi-tones above 440: "; degree PRINT #1, "; frequency = "; btone PRINT #1, "" ' Note that in creating the array, the bits have values of ' 1 and 0. But in comparing the integrated value of the array ' to the integrated value of the cosine function, the bits must ' have values of +1 and -1 since that is the range of the cosine ' function. DIM bitarray(period) AS INTEGER digint = 0 ' running integral of bits cosint = 0 ' running integral of cosine function angle = 0 ' bitnow = -1 ' current value of output bit column = 0 ' for print formatting in printing the array FOR i = 0 TO period angle = angle + incr cosint = cosint + COS(angle) * incr digint = digint + bitnow * incr IF cosint > digint THEN ' PRINT #1, "1"; bitnow = 1 bitarray(i) = 1 ELSE ' PRINT #1, "0"; bitnow = -1 bitarray(i) = 0 END IF column = column + 1 IF column = 50 THEN column = 0 ' PRINT #1, CHR$(13) END IF NEXT i ' start my PIC code with setting the output pin high using the ' SETHIGH macro PRINT #1, " SETHIGH" ' Next I want to examine the data in bitarray() and have the program ' write code to match the bit pattern samecount = 0 lastbit = 1 FOR i = 1 TO period IF bitarray(i) = lastbit THEN samecount = samecount + 1 IF samecount = 13 THEN GOSUB WRITECODE samecount = 0 END IF ELSE IF samecount <> 0 THEN GOSUB WRITECODE ' create repeats before changing line END IF samecount = 0 IF bitarray(i) = 1 THEN PRINT #1, " SETHIGH" ELSE PRINT #1, " SETLOW" END IF END IF lastbit = bitarray(i) NEXT i ' Now use up any counts not yet printed to program ' I added this part after I realized my code was using 1692 clocks Vs ' the expected 1703 ... IF samecount <> 0 THEN GOSUB WRITECODE END IF CLOSE #1 END WRITECODE: SELECT CASE samecount CASE 1 PRINT #1, " nop" CASE 2 PRINT #1, " nop" PRINT #1, " nop" CASE 3 PRINT #1, " nop" PRINT #1, " nop" PRINT #1, " nop" CASE 4 PRINT #1, " CALL delay4" CASE 5 PRINT #1, " CALL delay5" CASE 6 PRINT #1, " CALL delay6" CASE 7 PRINT #1, " CALL delay7" CASE 8 PRINT #1, " CALL delay8" CASE 9 PRINT #1, " CALL delay9" CASE 10 PRINT #1, " CALL delay10" CASE 11 PRINT #1, " CALL delay11" CASE 12 PRINT #1, " CALL delay12" CASE 13 PRINT #1, " CALL delay13" END SELECT RETURN