MAX038 Function Generator Design

Thread Starter

adam555

Joined Aug 17, 2013
858
Thank you for all the help, especially to you two.

I'm not sure if it was the change from electrolytic to ceramic what solved the problem, or if it was separating both supplies with the resistor and adding individual caps to each. I suspect it was the later, because I believe I tried the ceramics instead of electrolytics at the very beginning without solving the problem.

I've been running a whole battery of tests, and it works far better than I have never expected; not a single glitch or issue, unlike the other function generator I did last year, which is practically useless due to all the problems it has.

But -and it's not my intention to re-open this discussion- in one of the tests I noticed that even with the dual bench power supply, under a load from 1kΩ the resulting wave begins to experience a drop in amplitude (an issue that we discussed before). I wasn't expecting this to happen, since the power supply is good for 7.5A in the +5V rail and 300 mA in the -5V rail; which is well within the maximum power limits I calculated through the datasheets. But even then, the amplitude begins to drop with a 1kΩ load, is down to 80% with a 700Ω load, and to 60% with a 100Ω load.

I decided to do the same tests with a new recalculated shunt regulator with the zeners; I built another test circuit, and power it up with it. I got the exact same results as with the dual bench power supply! The exact same drops in amplitude with the exact same loads.

So I was thinking: if I'm going to get the exact same results whether I use the bench supply, the switching supply, or the zeners supply, what am I going to gain by ordering the components and rebuilding it again; especially when this PCB is already traced for the zeners?

I understand the reasons you gave for a power supply that could supply the maximum power needed, and why the zeners would never achieve this -especially when I'm measuring the power consumption with a multimeter, which is giving me the wrong reading- and I totally agree with you, but at this point I don't see the practical benefits, or any improvements I would get by changing the power supply to the switching one... unless I'm missing something here.

Anyway, this is the picture I promised of what the final project looks like:

Handheld_Function_Generator.jpg
 

atferrari

Joined Jan 6, 2004
4,771
Good to see you are coming to an end. aplausos bis.gif

Please credit Richard only, for his help. He really knows what is all this about.

Could you post the final circuit in white background, por favor? And, could you also add the final specs of it?

Just a comment that you could leave unanswered (no problem if you do): as long as it is not symptom of anything abnormal in other functions, a simple irregularity (dip) in the high level of the square signal, I think is of no real concern.

Real life digital signals are much more irregular than that and things work OK. If not, what are the high and low level margins for? Methinks.

Muy bueno, realmente.
 

RichardO

Joined May 4, 2013
2,270
Thank you for all the help, especially to you two.
But -and it's not my intention to re-open this discussion- in one of the tests I noticed that even with the dual bench power supply, under a load from 1kΩ the resulting wave begins to experience a drop in amplitude (an issue that we discussed before). I wasn't expecting this to happen, since the power supply is good for 7.5A in the +5V rail and 300 mA in the -5V rail; which is well within the maximum power limits I calculated through the datasheets. But even then, the amplitude begins to drop with a 1kΩ load, is down to 80% with a 700Ω load, and to 60% with a 100Ω load.
Can you give us more details. I suspect that you are trying to get 5 volts out. This will not happen even with a rail-rail amplifier except at a minimal load. Note that with the 50 ohm resistor between the output amp and the BNC the amplitude will drop in half with a 50 ohm load. (Ohms law). This is expected and what you want in an impedance matched system such as when driving a 50 ohm coax.
 

Thread Starter

adam555

Joined Aug 17, 2013
858
Can you give us more details. I suspect that you are trying to get 5 volts out. This will not happen even with a rail-rail amplifier except at a minimal load. Note that with the 50 ohm resistor between the output amp and the BNC the amplitude will drop in half with a 50 ohm load. (Ohms law). This is expected and what you want in an impedance matched system such as when driving a 50 ohm coax.
Hi Richard,

I tested the output with the oscilloscope while trying different size resistors in the output; basically the same test as described in post #84 but without the amperimeter. You are right, I did the test at the maximum amplitude (10Vpp).

I just tested it at 5Vpp and 2Vpp and the amplitude drop is far less: just around 25% drop on both cases with a 100Ω load. And this was with the zener shunt regulator.

My main doubt about this issue is: if I'm going to get the same drop, whether I use the bench dual power supply, the new switching power supply, or the zener shunt regulator supply, virtually making the result in practice identical, then I don't see the advantage of buying the new components and building the whole device again. Could you confirm that this is the case?

Good to see you are coming to an end. View attachment 77649

Please credit Richard only, for his help. He really knows what is all this about.

Could you post the final circuit in white background, por favor? And, could you also add the final specs of it?

Just a comment that you could leave unanswered (no problem if you do): as long as it is not symptom of anything abnormal in other functions, a simple irregularity (dip) in the high level of the square signal, I think is of no real concern.

Real life digital signals are much more irregular than that and things work OK. If not, what are the high and low level margins for? Methinks.

Muy bueno, realmente.
The range switching circuit was your idea; so you also deserve some credit. :)

The specs are (hope this is what you are asking for):
- 5 different frequency ranges from: 50Hz to 500Hz, 500Hz to 5KHz, 5KHz to 50KHz, 50KHz to 500KHz, and 500KHz to 5MHz (you can change the range up to 10MHz without much problems).
- Frequency and fine frequency adjust.
- 3 different waveforms: square, triangular and sinewave.
- Duty cycle adjust from 0 to 100%
- Amplitude adjust from 0 to 10Vpp
- Supply with any 12V DC 0.5 Amps adapter.
- Display with Frequency, period time, waveform and range.
- In-circuit programming through ICSP and reset button.
- BNC output.

I'm attaching the schematic you asked for and the PCB layout. These are for an updated version -not the one I built- but still using the zener shunt regulator. If you want the switching power supply version, please ask.

Ok more pics please if you can ..


Thanks and Awesome Work
Jay Sr
Thanks for the interest... but there's really not much else to show. Anyway, please let me know if you want specific pictures of any part.

With this pictures and the specs above I almost have the brochure ready. :)

- Top left is the ICSP connection
- Under it the range button, waveform button and PIC reset button
- Then the 12V DC plug.
- to the right is the display brightness pot
- the BNC output
- then the amplitude, frequency, and duty cycle pots
- and at the end the frequency fine tune.

WP_20141227_001.jpg
WP_20141227_002.jpg
WP_20141227_006.jpg
 

Attachments

RichardO

Joined May 4, 2013
2,270
The specs are (hope this is what you are asking for):
- 5 different frequency ranges from: 50Hz to 500Hz, 500Hz to 5KHz, 5KHz to 50KHz, 50KHz to 500KHz, and 500KHz to 5MHz (you can change the range up to 10MHz without much problems).
-
The frequency ranges should overlap by a fair amount otherwise the could be missing frequencies between ranges. For instance the ranges 50Hz to 500Hz and 500Hz to 5KHz could leave a gap at 500 Hz. Instead, a range from 50 Hz to 5 KHz makes sure that you can get 500 Hz.

I would add one more frequency range at the low frequency end to generate low frequency audio (20 Hz, bass). You only have to put the traces on the PCB. You don't have to populate the added circuit, although I would. If you have enough overlap between frequency ranges then you might get 20 Hz on what is now the 50 Hz to 500 Hz range.

With the timing capacitor values given in your schematic, I doubt that you really get the frequency ranges you state.

- Amplitude adjust from 0 to 10Vpp
The output can not be better than the THS4222. You need to check the THS4222 spec's. You should specify the 50-ohm terminated output swing.

- Supply with any 12V DC 0.5 Amps adapter.
Does this have to be a regulated adapter? If so, then say so...


Take a look at a function generator specification such as for the Wavetek 148. Obviously you do not need this much detail in your spec but it will give you a feel for what is desirable in your spec.
http://www.seas.gwu.edu/~ecelabs/appnotes/PDF/equipment/wv148a.pdf
 

RichardO

Joined May 4, 2013
2,270
My main doubt about this issue is: if I'm going to get the same drop, whether I use the bench dual power supply, the new switching power supply, or the zener shunt regulator supply, virtually making the result in practice identical, then I don't see the advantage of buying the new components and building the whole device again. Could you confirm that this is the case?
You still have not tested to the full possible load. At minimum you have to be able to drive a 50 ohm load. In practice my function generators can drive a a shorted load.

If you insist on building a simple and cheap circuit that does not work then use the shunt regulator. :eek:
 

Thread Starter

adam555

Joined Aug 17, 2013
858
The frequency ranges should overlap by a fair amount otherwise the could be missing frequencies between ranges. For instance the ranges 50Hz to 500Hz and 500Hz to 5KHz could leave a gap at 500 Hz. Instead, a range from 50 Hz to 5 KHz makes sure that you can get 500 Hz.
You are right, even though there is a small marging (e.g. in the second range it goes from 4.5KHz to 55KHz) in some ranges like the first one is so tight that I need to use the frequency fine tune, which is not meant to be used in normal usage.

This is why I preferred to use a 200K pot for the frequency change, as it gave quite a safe margin; but had to settle for the 100K because I couldn't find a matching pot of the same brand.

I would add one more frequency range at the low frequency end to generate low frequency audio (20 Hz, bass). You only have to put the traces on the PCB. You don't have to populate the added circuit, although I would. If you have enough overlap between frequency ranges then you might get 20 Hz on what is now the 50 Hz to 500 Hz range.
I also considered that possibility: using 6 ranges from 10Hz to 10Mhz. But I don't know what you mean by putting the traces on the PCB and not populating the the added circuit. One of the ranges is already working without a transistor (there's 4 transistors for 5 ranges); which works when no other is selected.

With the timing capacitor values given in your schematic, I doubt that you really get the frequency ranges you state.
You have a pretty good eye for this things. :)

The caps on that schematic should read: 470nF, 47nF, 4.7nF, 470pF, and I think I used a 20 or 30 pF for the last one (to which the transistors' output capacitance are added).

The output can not be better than the THS4222. You need to check the THS4222 spec's. You should specify the 50-ohm terminated output swing.
Since the zeners I'm using are 5.1V, the output voltage is fairly close to 10Vpp -just measured it at around 9.8Vpp without load, and 9.4Vpp with a load >2KΩ-.

Does this have to be a regulated adapter? If so, then say so...
To be honest, I didn't try it with an unregulated source; but I don't think it would work, as the zeners and limiting resistors of the current power supply are calculated exactly for 12V DC.

Take a look at a function generator specification such as for the Wavetek 148. Obviously you do not need this much detail in your spec but it will give you a feel for what is desirable in your spec.
http://www.seas.gwu.edu/~ecelabs/appnotes/PDF/equipment/wv148a.pdf
I just had a look and there are a lot of things from those specs that I don't understand; far too much to ask on this thread. I'll go through it with time to see if I can apply any of those things to a future version.

You still have not tested to the full possible load. At minimum you have to be able to drive a 50 ohm load. In practice my function generators can drive a a shorted load.
I just tested it with a shorted and a 50Ω load:
- at 10Vpp I get a flat line with a shorted load; which also restarts the PIC. And with a 50Ω load the amplitude is down to around 45%.
- at 5Vpp I get the amplitude down to 10% with a shorted load, and 50% with a 50Ω load.
- and at 2Vpp the amplitude drops to 20% with a shorted load, and again to 50% with a 50Ω load.

If you insist on building a simple and cheap circuit that does not work then use the shunt regulator. :eek:
:) I was fearing you would say something like that.

But that's exactly what I'm asking: what is the benefit that I would get by building the switching power supply instead of the this cheap and simple solution? I'm not arguing this point, I truly don't have a clue what would be the difference in practice. So far, I haven't seen any difference between the zener shunt regulator and the bench dual power supply; but it's also true I completely forgot to do the minimum tests above.

I only noticed one tiny difference between the two sources: when I did the test 100Ω load test with the shunt regulator; if instead of doing with a square wave, I do it with a triangular wave, I can see the tips of the triangles cropped a little bit; which I guess is the op-amp not getting enough power due to the zener shunt regulator limitations. That's the only difference; which I guess it would get far worse with a 50Ω load and a shorted load.
 
Last edited:

RichardO

Joined May 4, 2013
2,270
I just tested it with a shorted and a 50Ω load:
- at 10Vpp I get a flat line with a shorted load; which also restarts the PIC. And with a 50Ω load the amplitude is down to around 45%.
. . . . . . .
That's the only difference; which I guess it would get far worse with a 50Ω load and a shorted load.
The PIC restarting isn't a big difference???? :eek:
 

Thread Starter

adam555

Joined Aug 17, 2013
858
The PIC restarting isn't a big difference???? :eek:
But that's going to happen with a shorted load whether I use zeners, the bench, or the switching power supply. I mean, I can't test it now with the bench supply -unless I remove the zeners again- but since the results under load are so similar with both I don't have any reason to doubt the result will be any different... or not?
 

RichardO

Joined May 4, 2013
2,270
But that's going to happen with a shorted load whether I use zeners, the bench, or the switching power supply. I mean, I can't test it now with the bench supply -unless I remove the zeners again- but since the results under load are so similar with both I don't have any reason to doubt the result will be any different... or not?
The PIC restarting is a huge problem. It should never happen. Period. Not ever. No normal operating condition should cause a restart. And, before you ask, a short on the output is a common happening and must not ever cause a restart.

You need to track down the reason. If you need to remove the Zener diodes then so be it.

My first guess as to the cause is that the power supply is not staying at 5 volts under heavy load. Maybe you leads from the bench supply are too high a resistance. Some of the connections could also be high resistance.

If the PIC MCLR input is floating it could cause a reset from noise caused by the short. This noise could be in the ground circuit. The ICSP connection could also pic up noise. A ground loop could be caused by the power line safety ground connection hyour bench supply and your computer. Does the restart happen with the ICSP cable disconnected?
 

Thread Starter

adam555

Joined Aug 17, 2013
858
The PIC restarting is a huge problem. It should never happen. Period. Not ever. No normal operating condition should cause a restart. And, before you ask, a short on the output is a common happening and must not ever cause a restart.

You need to track down the reason. If you need to remove the Zener diodes then so be it.

My first guess as to the cause is that the power supply is not staying at 5 volts under heavy load. Maybe you leads from the bench supply are too high a resistance. Some of the connections could also be high resistance.

If the PIC MCLR input is floating it could cause a reset from noise caused by the short. This noise could be in the ground circuit. The ICSP connection could also pic up noise. A ground loop could be caused by the power line safety ground connection hyour bench supply and your computer. Does the restart happen with the ICSP cable disconnected?
Thanks Richard,

The MCLR has a 10k pull up resistor; so I doubt noise is the problem.

The PIC is supplied 4.4V when operating normally. This is because I'm using a diode between the PIC's power supply input and the rest of components, so when I connect the ICSP the PICKIT only powers the PIC, and not the whole device.

I just measured the drop in voltage with a shorted load -which is 4.2V in the positive rail- and it also shouldn't be enough to restart the PIC; as according to the PIC16F88's datasheet it should work with only 2V.

I looked in the source code, and noticed the BOREN (Brown-out Reset) was enabled. I disabled it, and now it doesn't restart with the shorted load at maximum output amplitude. It doesn't completely solve the problem, as I guess there's still a considerable drop of voltage, but at least it doesn't reset.

However, while doing this test I noticed something that doesn't look right. In this picture of the positive rail, you can see how it's not stable at 4.4V; it varies depending on which part of the cycle the output is. Now that I fixed the reset problem, I think there are no more performance issues left, but I would like to know what you make of it.

WP_20141230_001.jpg
 
Last edited:

RichardO

Joined May 4, 2013
2,270
I looked in the source code, and noticed the BOREN (Brown-out Reset) was enabled. I disabled it, and now it doesn't restart with the shorted load at maximum output amplitude. It doesn't completely solve the problem, as I guess there's still a considerable drop of voltage, but at least it doesn't reset.

However, while doing this test I noticed something that doesn't look right. In this picture of the positive rail, you can see how it's not stable at 4.4V; it varies depending on which part of the cycle the output is. Now that I fixed the reset problem, I think there are no more performance issues left, but I would like to know what you make of it.
As you have said, the brownout detect is just a symptom. You still need to find out the source of the voltage drop.

About for your waveform... No answer is possible without more information such as frequency, amplitude and measuring methods.
 

Thread Starter

adam555

Joined Aug 17, 2013
858
As you have said, the brownout detect is just a symptom. You still need to find out the source of the voltage drop.

About for your waveform... No answer is possible without more information such as frequency, amplitude and measuring methods.
Sorry, I completely forgot to add that in the picture above the output square wave is at 2V per division (the maximum possible output amplitude) and centered in the middle of the screen. The PIC supply line is centered on the bottom line of the graticule and it's at 1V per division. The frequency is 1KHz.

The oscillation in the supply seems quite small, but I was wondering if it could affect the performance in any way that I have been unable to notice so far.

By the way... Happy New Year!
 

Thread Starter

adam555

Joined Aug 17, 2013
858
adam555 I was wondering if you could post the code for the pic , it seems to be the only thing missing
Sorry for the delay; I've been busy with other stuff... hope you're still around.

I use 4 files: 2 headers, and 2 c.

16F88.h
Code:
// CONFIG1
#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTRC oscillator; port I/O function on both RA6/OSC2/CLKO pin and RA7/OSC1/CLKI pin)
#pragma config WDTE = OFF        // Watchdog Timer Enable bit (WDT enabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = ON       // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is MCLR)
#pragma config BOREN = OFF       // Brown-out Reset Enable bit (BOR enabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Code protection off)
#pragma config WRT = OFF        // Flash Program Memory Write Enable bits (Write protection off)
#pragma config CCPMX = RB3      // CCP1 Pin Selection bit (CCP1 function on RB3)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

// CONFIG2
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal External Switchover bit (Internal External Switchover mode disabled)

// Set the oscillator frequency (default = 31.25 KHz)
#define _XTAL_FREQ 8000000
LCD.h
Code:
*
*  RS on pin RB7
*      H = display data
*      L = instruction data
*
* E on pin RA4
*      H = enable data
*      L = disable data
*
* RA0 = 11
* RA1 = 12
* RA2 = 13
* RA3 = 14
*
*/

#include <stdint.h>

//LCD Data pins
#define lcddatatris TRISA
#define lcddataport PORTA

#define rs PORTBbits.RB4
#define en PORTBbits.RB5

void lcdcmd(uint8_t);
void lcddata(uint8_t);

void LCD_Init(void);
void LCD_Clear(void);
void LCD_SetCursor(uint8_t, uint8_t);
void LCD_Write(uint8_t *);
void LCD_WriteInt(uint32_t);
LCD.c
Code:
#include "16F88.h"
#include "LCD.h"
#include <xc.h>
#include <stdio.h>
#include <stdint.h>

void lcdnbl(unsigned char nblout)
{
    lcddataport = (lcddataport & 0xF0) | (nblout & 0xF);
}

void lcdcmd(unsigned char cmdout)
{
    lcdnbl(cmdout>>4);
    rs=0;
    en=1;
    __delay_us(1);
    en=0;

    lcdnbl(cmdout);
    rs=0;
    en=1;
    __delay_us(1);
    en=0;
}

void lcddata(unsigned char dataout)
{
    lcdnbl(dataout>>4);
    rs=1;
    en=1;
    __delay_us(1);
    en=0;

    lcdnbl(dataout);
    en=1;
    __delay_us(1);
    en=0;
}

void LCD_Init()
{
    __delay_ms(100);

    en=0;
    rs=0;
    __delay_us(1);
    lcdcmd(0x28);           // No.6 - Set 2 lines 5x8 font
    lcdcmd(0x0C);           // No.4 - Display ON cursor OFF
    lcdcmd(0x06);           // No.3 - Increment cursor
    lcdcmd(0x01);           // No.1 - Clear display
    lcdcmd(0xC0);           // No.8 - Set cursor home
    __delay_ms(10);
}

void LCD_Clear()
{
    rs=0;
    en=0;
    __delay_us(1);
    lcdcmd(0x01);           // Clear display
    lcdcmd(0xC0);           // No.8 - Set cursor home
    __delay_ms(10);
}

void LCD_Write(unsigned char *data)
{
    unsigned int i = 0;

    while(data[i]!='\0')
    {
        lcddata(data[i]);   // Call lcddata function to send characters
                            // one by one from ?data? array
        i++;
    }
}

void LCD_WriteInt(uint32_t data)
{
    uint8_t i = 0;
    unsigned char cdata[16];

    sprintf(cdata, "%lu\0", data);
  
    while(cdata[i]!='\0')
    {
        lcddata(cdata[i]);   // Call lcddata function to send characters
                            // one by one from ?data? array
        i++;
    }
}

void LCD_SetCursor(unsigned char row, unsigned char col)
{
    if(row > 1)
        row = 1;

    rs=0;
    en=0;
    __delay_us(1);
    lcdcmd(0x80 + (0x40 * row) + col);           // No.8 - Set Cursor (DDRAM address)
    __delay_ms(10);
}
main.c
Code:
#include "16F88.h"
#include "LCD.h"
#include <xc.h>
#include <stdint.h>

#define BUT1 PORTAbits.RA6
#define BUT2 PORTAbits.RA7

unsigned char message[17] = "Initializing...";
unsigned char n_freq[7]="Freq:";
unsigned char n_mode[3][8]= {   "Square ",
                                "Triang.",
                                "Sine   "};
unsigned char n_range[5][9] = { "  x50 Hz",
                                " x500 Hz",
                                "  x5 KHz",
                                " x50 KHz",
                                "x500 KHz"};
unsigned char n_period[3][6] = {    "ms  ",
                                    "us  ",
                                    "ns  "};

// Function Generator set variables
uint8_t mode = 0;
uint8_t range = 0;

// Frequency counter variables
uint32_t pulses = 0;
uint32_t count = 0;
uint8_t divider = 0;
uint8_t signal = 0;
uint8_t signal_prev = 0;

uint16_t power(uint16_t num, uint16_t exp)
{
    uint16_t result = num;

    for(int t=1; t<exp; t++)
    {
        result = result * num;
    }

    return result;
}

void display(void)
{
    uint16_t period;
    uint32_t frequency;

    LCD_SetCursor(0,0);

    if(pulses==0)
        LCD_Write("-- No Signal -- ");
    else
    {
        frequency = pulses * ((range==4) ? 512 : (power(2,((range*2)+2))));
        LCD_WriteInt(frequency);
        LCD_Write("Hz ");

//        LCD_SetCursor(0,10);
        if(frequency > 100000)
        {
            if(frequency < 1000000)
                LCD_Write(" ");
            LCD_WriteInt(1*1000000000/frequency);
            LCD_Write(n_period[2]);
        }
        if(frequency > 100)
        {
            if(frequency > 10000)
                LCD_Write("  ");
            else if(frequency > 1000)
                LCD_Write("   ");
            else
                LCD_Write("    ");
            LCD_WriteInt(1*1000000/frequency);
            LCD_Write(n_period[1]);
        }
        else
        {
            if(frequency > 100)
                LCD_Write("     ");
            else
                LCD_Write("      ");
            LCD_WriteInt(1*1000/frequency);
            LCD_Write(n_period[0]);
        }
    }
  
    LCD_SetCursor(1,0);
    LCD_Write(n_mode[mode]);

    LCD_SetCursor(1,8);
    LCD_Write(n_range[range]);
}

void interrupt myISR()
{
    if(TMR0IF)      // Timer 0 interrupt: as counter for input signal
    {
        count++;
        TMR0IF = 0;
    }

    if(TMR1IF)      // Timer 1 interrupt: as timer
    {
        pulses=(count*0xFF)+TMR0;
        count=TMR0=TMR1IF=0;
    }
}

void main(void)
{
    // Input button variables
    unsigned char buttonpressed1 = 0;
    unsigned char buttonpressed2 = 0;

    // General setup
    TRISA = 0b11110000;
    TRISB = 0b00000000;
    ANSEL = 0;

    OSCCONbits.IRCF = 0b110;    // Set oscillator to 4Mhz

    // LCD Setup
    LCD_Init();             // LCD initialization
    LCD_Write(message);
    __delay_ms(500);
    LCD_Clear();

    // Timer 1 config
    PIE1bits.TMR1IE = 1;        // enable timer1
    T1CONbits.T1CKPS = 0b11;    // prescaler 1:8
    T1CONbits.TMR1CS = 0;       // Timer1 source
    T1CONbits.TMR1ON = 1;       // Timer1 On

    // Timer 0 config
    INTCONbits.TMR0IE = 1;      // Timer0 overflow interrupt enabled
    OPTION_REGbits.PSA = 0;     // Assign prescaler to Timer0
    OPTION_REGbits.PS = 0;      // Prescaler 1:2 (initial value)

    // General interrupt config
    INTCONbits.PEIE = 1;        // Peripheral interrupt enable
    INTCONbits.GIE = 1;         // Global interrupt enable

    while(1)
    {
        if(BUT1 == 0) {
            if(buttonpressed1 == 0) {
                if(mode < 2) mode++;
                else mode=0;
                buttonpressed1=1;
            } }
        else buttonpressed1=0;

        if(BUT2 == 0) {
            if(buttonpressed2 == 0) {
                if(range < 4) range++;
                else range=0;
                buttonpressed2=1;
                OPTION_REGbits.PS = (range==4) ? 0b111 : (range*2);      // Change prescaler
            } }
        else buttonpressed2=0;

        // Write to output ports
        PORTB = (PORTB & 0x3F) | ((mode << 6) & 0xC0);  // Write mode to RB<5:4>
        PORTB = (PORTB & 0xF0) | ((1 << range) & 0x0F); // Write range to RB<3:0>

        display();
    }
}
It can be improved... a lot; but it should work as it is on a PIC16F88 or equivalent.
 
Top