Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Simple AD9833 DDS based signal generator.
- Scott Beasley 2021
- Free for whatever.
- Parts:
- MCU: STC15W404AS SSOP20
- Max 7219 serial LED driver - 8 digit module
- Keyes Rotary encoder module
- Buck regulator set to 5v
- PlatformIO was used as the build system using the intel_mcs51 platform.
- This uses SDCC as the C compiler. The STC chips have a built-in ISP
- and only need a TTL serial connection to program them from the ISP tool
- that PlatformIO uses (stcgal). No other ISP adaptor or programmer needed.
- No extra libraries are needed to compile it.
- */
- #include <stc12.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <string.h>
- #define SET_BIT(p,n) (p |= (1 << n))
- #define CLR_BIT(p,n) (p &= ~(1 << n))
- // GPIO defines
- #define CLK_PIN P1_2
- #define DSPLY_DATA_PIN P1_6
- #define DSPLY_CSEL_PIN P1_5
- #define ENC_CLK_PIN P3_2
- #define ENC_DIR_PIN P3_3
- #define ENC_BUT_PIN P3_4
- #define FRQG_DATA P1_4
- #define FRQG_SYNC_PIN P1_7
- #define LOW 0
- #define HIGH 1
- // Prototype, prototype each and every day!
- void init (void);
- void delay_5us (int __data us);
- void set_7219_reg (int8_t reg, int8_t value);
- void lshift (int8_t val);
- void set_AD9833_reg (uint16_t dat);
- void AD9833_freq_set (long freq, uint16_t type, int running);
- // Max7219 commands
- enum {
- REG_DECODE = 0x09,
- REG_INTENSITY = 0x0A,
- REG_SCANLIMIT = 0x0B,
- REG_SHUTDOWN = 0x0C,
- REG_DISPTEST = 0x0F
- };
- // flag for encoder change int
- volatile uint8_t enc_changed = 0;
- // INT0 handler function
- void exint0 (void) __interrupt 0
- {
- enc_changed = 1;
- }
- // Delay 5us'ish
- void delay_5us (int __data us)
- {
- unsigned char __data i;
- for (; us; us--)
- for (i=13; i; i--)
- __asm__ ("nop");
- }
- void set_7219_reg (int8_t reg, int8_t value)
- {
- DSPLY_CSEL_PIN = 0;
- lshift (reg);
- lshift (value);
- DSPLY_CSEL_PIN = 1;
- }
- // Shift data left for LED display comm
- void lshift (int8_t val)
- {
- int ndx;
- for (ndx = 0; ndx < 8; ndx++) {
- DSPLY_DATA_PIN = val & 0x80;
- CLK_PIN = 1;
- delay_5us (2);
- CLK_PIN = 0;
- delay_5us (2);
- val = val << 1;
- }
- }
- // Shift data left for AD9833 comm
- void set_AD9833_reg (uint16_t val)
- {
- int ndx;
- CLK_PIN = LOW;
- delay_5us (5);
- CLK_PIN = HIGH;
- FRQG_SYNC_PIN = LOW;
- delay_5us (2);
- for (ndx = 0; ndx < 16; ndx++) {
- FRQG_DATA = val & 0x8000;
- CLK_PIN = HIGH;
- delay_5us (5);
- CLK_PIN = LOW;
- delay_5us (5);
- val = val << 1;
- }
- FRQG_DATA = LOW;
- CLK_PIN = HIGH;
- FRQG_SYNC_PIN = HIGH;
- }
- // Set the freq and wave type for the AD9833
- void AD9833_freq_set (long freq, uint16_t type, int running)
- {
- unsigned long int freq_out = (freq * 268435456.0) / 25000000.0;
- // Type is the wave you want. The menu items line up on the DDS
- // val for Sine and Tri, but not on Squre. This is agdusted below
- if (type == 1) type = 40; // Type 1 = Square wave make 40 for DDS
- set_AD9833_reg ((running == 0 ? 0x2000 | type : 0x2100));
- set_AD9833_reg ((uint16_t)((freq_out & 0x3FFF) | 0x4000));
- set_AD9833_reg ((uint16_t)(((freq_out & 0xFFFC000) >> 14) | 0x4000));
- if (running == 1) {
- set_AD9833_reg ((uint16_t)0xC000);
- set_AD9833_reg (type);
- }
- }
- // Setup in the 'Duino world
- void init (void)
- {
- int ndx;
- // Set INT0 up for the encoder
- INT0 = 1;
- IT0 = 1; // Set to "change"
- EX0 = 1; // Enable INT0 interrupt
- EA = 1;
- // Set input pins to quasi-bidirectional
- CLR_BIT (P3M0, 2);
- CLR_BIT (P3M1, 2);
- CLR_BIT (P3M0, 3);
- CLR_BIT (P3M1, 3);
- CLR_BIT (P3M0, 4);
- CLR_BIT (P3M1, 4);
- // Init the display
- set_7219_reg (REG_SHUTDOWN, 0);
- set_7219_reg (REG_INTENSITY, 0x02);
- set_7219_reg (REG_SCANLIMIT, 7);
- set_7219_reg (REG_DECODE, 0b11111100);
- // Populate the display at start
- for (ndx = 1; ndx < 9; ndx++) {
- set_7219_reg (ndx, 0);
- }
- set_7219_reg (2, 0b00000001); // NOP
- set_7219_reg (1, 0b01101101); // Sine wave
- set_7219_reg (REG_SHUTDOWN, 1);
- set_AD9833_reg (0x100); // Reset the AD9833
- }
- int main ( )
- {
- int8_t freq[8];
- uint8_t opt[8];
- int ndx = 0, enc_clk_state = -1, last_clk_state = -1, is_running = 0;
- long int out_freq = 0;
- // Set the freq array to all 0's
- memset (&freq, 0, sizeof (int8_t) * 8);
- // Set the Power option
- freq[6] = 4; // Start at NOP
- // Set the wave type
- freq[7] = 0; // Start at Sine
- init ();
- // Non-numeric chars for digit 7 and 8
- opt[0] = 0b01101101; // Sine wave
- opt[1] = 0b01010011; // Square
- opt[2] = 0b00110001; // Triangle
- opt[3] = 0b01000000; // On
- opt[4] = 0b00000001; // Nop
- opt[5] = 0b00001000; // Off
- opt[6] = 0b10000000; // One extra... Not used.
- DSPLY_CSEL_PIN = 1;
- // Set the first cursor pos for start up.
- set_7219_reg (REG_SHUTDOWN, 0);
- set_7219_reg (8 - ndx, freq[ndx] | 0x80);
- set_7219_reg (REG_SHUTDOWN, 1);
- while (1) {
- if (ENC_BUT_PIN == 0) {
- delay_5us (12500); // Debounce delay
- if (ENC_BUT_PIN == 0) {
- // If on digit 7, look for on/off options
- if (ndx == 6) {
- switch (freq[ndx]) {
- case 3: // Turn on AD9833 (Top seg on)
- out_freq = (freq[0] * 100000);
- out_freq += (freq[1] * 10000);
- out_freq += (freq[2] * 1000);
- out_freq += (freq[3] * 100);
- out_freq += (freq[4] * 10);
- out_freq += freq[5];
- // Outside this compiler, this code is fine
- // If freq[1] > 3 then the out_freq cals is off
- // by 65,530. Silly fix for a silly problem.
- if (freq[1] > 3)
- out_freq += 65530;
- AD9833_freq_set (out_freq, freq[7], is_running);
- is_running = 1;
- continue;
- case 5: // Bottom seg on
- set_AD9833_reg (0x100); // Reset the AD9833
- is_running = 0;
- continue;
- case 4: // NOP (skip to next). Middle seg on
- break;
- default:
- continue;
- }
- }
- set_7219_reg (REG_SHUTDOWN, 0);
- set_7219_reg (8 - ndx, (ndx < 6 ? freq[ndx] : opt[freq[ndx]]));
- set_7219_reg (REG_SHUTDOWN, 1);
- ndx++;
- if (ndx >= 8)
- ndx = 0;
- }
- set_7219_reg (REG_SHUTDOWN, 0);
- set_7219_reg (8 - ndx, (ndx < 6 ? freq[ndx] : opt[freq[ndx]]) | 0x80);
- set_7219_reg (REG_SHUTDOWN, 1);
- continue;
- }
- // Handle any encoder changes
- if (enc_changed == 1) {
- if ((ENC_DIR_PIN == 1 && ENC_CLK_PIN == 0) ||
- (ENC_DIR_PIN == 0 && ENC_CLK_PIN == 1))
- freq[ndx]--;
- if ((ENC_DIR_PIN == 0 && ENC_CLK_PIN == 0) ||
- (ENC_DIR_PIN == 1 && ENC_CLK_PIN == 1))
- freq[ndx]++;
- // Edits for Freq numbers (0-9)
- if (ndx < 6) {
- if (freq[ndx] > 9)
- freq[ndx] = 0;
- if (freq[ndx] < 0)
- freq[ndx] = 9;
- }
- // Edits for ON/OFF options
- if (ndx == 6) {
- if (freq[ndx] == 6) {
- freq[ndx] = 3;
- }
- if (freq[ndx] < 3) {
- freq[ndx] = 5;
- }
- }
- // Edits for Wave type
- if (ndx == 7) {
- if (freq[ndx] == 3) {
- freq[ndx] = 0;
- }
- if (freq[ndx] < 0) {
- freq[ndx] = 2;
- }
- }
- // Send the change to the display with the
- // current digit with the '.' for the cursor
- set_7219_reg (REG_SHUTDOWN, 0);
- set_7219_reg (8 - ndx, (ndx < 6 ? freq[ndx] : opt[freq[ndx]]) | 0x80);
- set_7219_reg (REG_SHUTDOWN, 1);
- delay_5us (14500); // Debounce delay
- enc_changed = 0;
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment