basic code what am I missing? IF ADC is => increase PWM

Electronics Computer Programming Q&A
hp
Posts: 245
Joined: Sat Aug 09, 2003 1:01 am
Location: Friendswood, TX
Contact:

Post by hp »

Alot of compilers have demo versions that are limited by lines of code or by compiled code size.

HITech C has a good ANSI C compiler limited by chip type and hex code size.

Proton Basic has an excellent, easy to use, IDE + demo that is limited to 31 lines of code and certain processes. I would definately use Proton Basic to do something like this saying it can probably be done in less than 31 lines of code.

Microchip has a free student edition of their C18 compiler for the PIC18 series.

There are alot of other free compilers, but those are most of the popular ones. Search on google and you should be able to get download links for them quite easily.
cwaugs
Posts: 28
Joined: Thu Sep 01, 2005 1:01 am
Contact:

Post by cwaugs »

Will do Thanks again gotta get this thing running!
cwaugs
Posts: 28
Joined: Thu Sep 01, 2005 1:01 am
Contact:

Post by cwaugs »

Hard to believe what I was asking of you guys/gals. Two months later and 4-500 lines of code in a 16f877 and I have the program running. I had no idea it would be this involved and admire each and every one of you'all who even VENTURE into someone elses coding project knowing what's involved in completing the program. I thank you all for not telling me that I'm dreaming if I think I can program this thing! I have two ADC's, three opto isolated relays, and an LCD telling me what's happening and the ability to serial program it all for under $50 for all of the hardware. Thank you all again for your support and humility. I owe you all a debt of gratitude. Emmett
Sambuchi
Posts: 366
Joined: Tue Jan 18, 2005 1:01 am
Location: Orlando FL
Contact:

Post by Sambuchi »

cwaugs

great to hear that you got it working... :D


getting your first , or any!... firmware project running is an acplishment. Sounds like you have a good sence of the hardware and software to build from.

Cant wait to hear about your next firmware project.

congrats!!! :D :D
cwaugs
Posts: 28
Joined: Thu Sep 01, 2005 1:01 am
Contact:

PicBasicPro to Codevision "C"

Post by cwaugs »

Well I'm back with a little less hair and on the verge of a cardiac arrest, no just kidding. The PIC code works well and I am happy with it but need to move everything over to Atmel. :( Codevision has a utility to set up the three timers but I have no clue how to code in "c". How would I begin to set up the three timers and one adc channel on this Mega48 to
1. read the adc
2. pause 30 seconds or so (I might be able to figure this part out)
3. Read the ADC again and if it is lower than the first reading then raise the frequency of all three timers 10 Hz, and if it is higher than the first reading then lower the frequency 10 Hz.
That's the basics of the program but when it comes to all of the
>><<{{}} in "C" I obviously don't know beans about it. I have bought a C programming book that don't help me much! Anyhow after all the hours invested programming the 16F877 PIC I know what I am asking and I don't expect you all to drop everything and figure this out but if there is any code samples or ? that might point me in the right direction I would so much appreciate it. Thank you'all so much! Emmett

This is the basic pic code to do what I need (without the defines and stuff).

BEGIN:
For PWMFREQ = 150 To 300 Step 10
TIMER0,DUTY,PWMFREQ
ADCIN 0, CNTRL
PAUSE 60
ADCIN 0, TST
IF TST < CNTRL THEN PWMFREQ=PWMFREQ +10
PAUSE 60
ADCIN 0, TST
if TST >= CNTRL THEN PWMFREQ=PWMFREQ -10
NEXT PWMFREQ
goto BEGIN:
end

This is the setup generated by Codevision for the three timers to put out both non-inverted and inverted outputs

Project : three pwm's six outputs

Chip type : ATmega48
Clock frequency : 4.000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega48.h>

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{
// Place your code here

}

// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{
// Place your code here

}

// Timer 2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{
// Place your code here

}

#define ADC_VREF_TYPE 0x00

// Read the AD conversion result
unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input|ADC_VREF_TYPE;
// Start the AD conversion
ADCSRA|=0x40;
// Wait for the AD conversion to complete
while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}

// Declare your global variables here

void main(void)
{
// Declare your local variables here

// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

// Input/Output Ports initialization
// Port B initialization
// Func7=In Func6=In Func5=In Func4=In Func3=Out Func2=Out Func1=Out Func0=In
// State7=T State6=T State5=T State4=T State3=0 State2=0 State1=0 State0=T
PORTB=0x00;
DDRB=0x0E;

// Port C initialization
// Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In
// State6=T State5=T State4=T State3=T State2=T State1=T State0=T
PORTC=0x00;
DDRC=0x00;

// Port D initialization
// Func7=In Func6=In Func5=In Func4=In Func3=Out Func2=In Func1=In Func0=In
// State7=T State6=T State5=T State4=T State3=0 State2=T State1=T State0=T
PORTD=0x00;
DDRD=0x08;

// Timer/Counter 0 initialization
// Clock source: System Clock
// Clock value: 62.500 kHz
// Mode: Fast PWM top=FFh
// OC0A output: Non-Inverted PWM
// OC0B output: Inverted PWM
TCCR0A=0xB3;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

// Timer/Counter 1 initialization
// Clock source: System Clock
// Clock value: 15.625 kHz
// Mode: Fast PWM top=01FFh
// OC1A output: Non-Inv.
// OC1B output: Inverted
// Noise Canceler: Off
// Input Capture on Falling Edge
// Timer 1 Overflow Interrupt: On
// Input Capture Interrupt: Off
// Compare A Match Interrupt: Off
// Compare B Match Interrupt: Off
TCCR1A=0xB2;
TCCR1B=0x0C;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

// Timer/Counter 2 initialization
// Clock source: System Clock
// Clock value: 15.625 kHz
// Mode: Fast PWM top=OCR0A
// OC2A output: Non-Inverted PWM
// OC2B output: Inverted PWM
ASSR=0x00;
TCCR2A=0xB3;
TCCR2B=0x0E;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

// External Interrupt(s) initialization
// INT0: Off
// INT1: Off
// Interrupt on any change on pins PCINT0-7: Off
// Interrupt on any change on pins PCINT8-14: Off
// Interrupt on any change on pins PCINT16-23: Off
EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

// Timer/Counter 0 Interrupt(s) initialization
TIMSK0=0x01;
// Timer/Counter 1 Interrupt(s) initialization
TIMSK1=0x01;
// Timer/Counter 2 Interrupt(s) initialization
TIMSK2=0x01;

// Analog Comparator initialization
// Analog Comparator: Off
// Analog Comparator Input Capture by Timer/Counter 1: Off
ACSR=0x80;
ADCSRB=0x00;

// ADC initialization
// ADC Clock frequency: 1000.000 kHz
// ADC Voltage Reference: AREF pin
// ADC Auto Trigger Source: None
// Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On
// ADC4: On, ADC5: On
DIDR0=0x00;
ADMUX=ADC_VREF_TYPE;
ADCSRA=0x82;

// Global enable interrupts
#asm("sei")

while (1)
{
// Place your code here

};
User avatar
philba
Posts: 2050
Joined: Tue Nov 30, 2004 1:01 am
Location: Seattle
Contact:

Post by philba »

<holds his nose> there is a basic for the AVR. the demo version of bascom can build up to 4K of code. I think you are probably safe...
cwaugs
Posts: 28
Joined: Thu Sep 01, 2005 1:01 am
Contact:

Post by cwaugs »

Tried it, but not user freindly enough for a dumb butt like myself.
O.K. I'm thinkin' start small. In "C" what would the code be for these
three lines?

ADCIN 0, any variable name1
pause 60 seconds
ADCIN 0, any variable name2

I'm just at a loss as to all of the punctuation marks.
Thanks again Emmett
bodgy
Posts: 1044
Joined: Tue Dec 04, 2001 1:01 am
Location: Australia
Contact:

Post by bodgy »

cwaugs wrote: ADCIN 0, any variable name1
pause 60 seconds
ADCIN 0, any variable name2
To be really useful, you'll need to check your 'C' compilers library of inbuilt functions that may well do all that you want in a fashion that you're used to.

One of the problems with autocode dooflunkies is that they can be difficult to decipher.

The first thing I'd suggest is to delete most things that appear between /* */ these are comments or commented out sections of code. Delete also // these are single line comments.

In 'C' so that the compiler knows when an end to a code line is reached you have to bung in a semicolon.

Sections of code are demarcated by the { } brackets.

Your For statement will become For (PWMFREQ = 150;PWMFREQ <= 300; PWMFREQ = PWMFREQ + 10)
{
code here will depend upon how your internal libraries work
}


You might need to do some experiments here, for example my 'C' compiler for Pics gives better ASM if I have a For statment as For (PWMFREQ = 300;PWMFREQ; PWMFREQ = PWMFREQ - 10), though in this case that might not be helpful.

I've just realised that much of what you want is already in the code you posted - I'll play about with it to make it more readable and see if that helps.

Colin
On a clear disk you can seek forever.
bodgy
Posts: 1044
Joined: Tue Dec 04, 2001 1:01 am
Location: Australia
Contact:

Post by bodgy »

OK here is a slightly tidied up version.

With 'C' if you want to be able to follow it in the same way that basic starts at the top and works down to the bottom, you'll need to put function prototypes under the DOT H file, then you can put all your functions in any order underneath the MAIN one.

Colin

Project : three pwm's six outputs

Chip type : ATmega48
Clock frequency : 4.000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega48.h>
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif


#define ADC_VREF_TYPE 0x00

// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{

}

// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{

}

// Timer 2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{

}



// Read the AD conversion result

unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input|ADC_VREF_TYPE; // Start the AD conversion

ADCSRA|=0x40; // Wait for the AD conversion to complete

while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;
}

/* Setup initialises all ports and hardware such as ADC, PWM etc */
void setup(void)
{
/* Input/Output Ports initialization **
** Port B initialization. To make pin an input clear the bit, to make output set the bit
**
** Pins 7 6 5 4 3 2 1 0
** 0 0 0 0 1 1 1 0
********************************************************************/

PORTB=0x00;
DDRB=0x0E;

/* Port C initialization */

PORTC=0x00;
DDRC=0x00;

/* Port D initialization */

PORTD=0x00;
DDRD=0x08;

/* Timer/Counter 0 initialization **
**
** Clock source: System Clock
** Clock value: 62.500 kHz
** Mode: Fast PWM top=FFh
** OC0A output: Non-Inverted PWM
** OC0B output: Inverted PWM
******************************************************************/

TCCR0A=0xB3;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

/* Timer/Counter 1 initialization **
**
** Clock source: System Clock
** Clock value: 15.625 kHz
** Mode: Fast PWM top=01FFh
** OC1A output: Non-Inv. OC1B output: Inverted
** Noise Canceler: Off
** Input Capture on Falling Edge, Input Capture Interrupt: Off
** Timer 1 Overflow Interrupt: On
** Compare A Match Interrupt: Off , Compare B Match Interrupt: Off
***************************************************************/

TCCR1A=0xB2;
TCCR1B=0x0C;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

/* Timer/Counter 2 initialization **
**
** Clock source: System Clock
** Clock value: 15.625 kHz
** Mode: Fast PWM top=OCR0A
** OC2A output: Non-Inverted PWM , OC2B output: Inverted PWM
****************************************************************/

ASSR=0x00;
TCCR2A=0xB3;
TCCR2B=0x0E;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

/* External Interrupt(s) initialization **
**
** INT0: Off , INT1: Off
** Interrupt on any change on pins PCINT0-7: Off
** Interrupt on any change on pins PCINT8-14: Off
** Interrupt on any change on pins PCINT16-23: Off
**************************************************************/

EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

TIMSK0=0x01; // Timer/Counter 0 Interrupt(s) initialization

TIMSK1=0x01; // Timer/Counter 1 Interrupt(s) initialization

TIMSK2=0x01; // Timer/Counter 2 Interrupt(s) initialization


/* Analog Comparator initialization **
**
** Analog Comparator: Off
** Analog Comparator Input Capture by Timer/Counter 1: Off
************************************************************/

ACSR=0x80;
ADCSRB=0x00;

** ADC initialization **
**
** ADC Clock frequency: 1000.000 kHz
** ADC Voltage Reference: AREF pin
** ADC Auto Trigger Source: None
** Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On ADC4: On, ADC5: On
***********************************************************/

DIDR0=0x00;

ADMUX=ADC_VREF_TYPE;
ADCSRA=0x82;

// Global enable interrupts

#asm("sei")
}

void main(void)
{

setup(); // call the initialisation function

while (1)
{
// Place your code here

};
On a clear disk you can seek forever.
bodgy
Posts: 1044
Joined: Tue Dec 04, 2001 1:01 am
Location: Australia
Contact:

Post by bodgy »

To make the above program into a basic type flow - do the following. I've added in the call to the ADC as well in this version. For long delays you would probably use one of the Timer interrupts to delay a second and then call the ADC.

The adc stuff could either be in the interrupt after checking for the interrupt flag, or, if the rest of your program is time sensitive, you'd set a flag variable in the interrupt and check this in MAIN which would then call the adc.


Chip type : ATmega48
Clock frequency : 4.000000 MHz
Memory model : Small
External SRAM size : 0
Data Stack size : 128
*****************************************************/

#include <mega48.h>
// Crystal Oscillator division factor: 1
#pragma optsize-
CLKPR=0x80;
CLKPR=0x00;
#ifdef _OPTIMIZE_SIZE_
#pragma optsize+
#endif

unsigned int read_adc(unsigned char adc_input);
void setup();


#define ADC_VREF_TYPE 0x00


void main(void)
{
unsigned char ADC_var;

setup(); // call the initialisation function

while (1)
{

adc_var =read_adc(0);

delay(60seconds); //Note your compiler will have a library file for delays.

adc_var = read_adc(0);

};


// Timer 0 overflow interrupt service routine
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
{

}

// Timer 1 overflow interrupt service routine
interrupt [TIM1_OVF] void timer1_ovf_isr(void)
{

}

// Timer 2 overflow interrupt service routine
interrupt [TIM2_OVF] void timer2_ovf_isr(void)
{

}


/* Setup initialises all ports and hardware such as ADC, PWM etc */
void setup(void)
{
/* Input/Output Ports initialization **
** Port B initialization. To make pin an input clear the bit, to make output set the bit
**
** Pins 7 6 5 4 3 2 1 0
** 0 0 0 0 1 1 1 0
********************************************************************/

PORTB=0x00;
DDRB=0x0E;

/* Port C initialization */

PORTC=0x00;
DDRC=0x00;

/* Port D initialization */

PORTD=0x00;
DDRD=0x08;

/* Timer/Counter 0 initialization **
**
** Clock source: System Clock
** Clock value: 62.500 kHz
** Mode: Fast PWM top=FFh
** OC0A output: Non-Inverted PWM
** OC0B output: Inverted PWM
******************************************************************/

TCCR0A=0xB3;
TCCR0B=0x03;
TCNT0=0x00;
OCR0A=0x00;
OCR0B=0x00;

/* Timer/Counter 1 initialization **
**
** Clock source: System Clock
** Clock value: 15.625 kHz
** Mode: Fast PWM top=01FFh
** OC1A output: Non-Inv. OC1B output: Inverted
** Noise Canceler: Off
** Input Capture on Falling Edge, Input Capture Interrupt: Off
** Timer 1 Overflow Interrupt: On
** Compare A Match Interrupt: Off , Compare B Match Interrupt: Off
***************************************************************/

TCCR1A=0xB2;
TCCR1B=0x0C;
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0x00;
OCR1BH=0x00;
OCR1BL=0x00;

/* Timer/Counter 2 initialization **
**
** Clock source: System Clock
** Clock value: 15.625 kHz
** Mode: Fast PWM top=OCR0A
** OC2A output: Non-Inverted PWM , OC2B output: Inverted PWM
****************************************************************/

ASSR=0x00;
TCCR2A=0xB3;
TCCR2B=0x0E;
TCNT2=0x00;
OCR2A=0x00;
OCR2B=0x00;

/* External Interrupt(s) initialization **
**
** INT0: Off , INT1: Off
** Interrupt on any change on pins PCINT0-7: Off
** Interrupt on any change on pins PCINT8-14: Off
** Interrupt on any change on pins PCINT16-23: Off
**************************************************************/

EICRA=0x00;
EIMSK=0x00;
PCICR=0x00;

TIMSK0=0x01; // Timer/Counter 0 Interrupt(s) initialization

TIMSK1=0x01; // Timer/Counter 1 Interrupt(s) initialization

TIMSK2=0x01; // Timer/Counter 2 Interrupt(s) initialization


/* Analog Comparator initialization **
**
** Analog Comparator: Off
** Analog Comparator Input Capture by Timer/Counter 1: Off
************************************************************/

ACSR=0x80;
ADCSRB=0x00;

** ADC initialization **
**
** ADC Clock frequency: 1000.000 kHz
** ADC Voltage Reference: AREF pin
** ADC Auto Trigger Source: None
** Digital input buffers on ADC0: On, ADC1: On, ADC2: On, ADC3: On ADC4: On, ADC5: On
***********************************************************/

DIDR0=0x00;

ADMUX=ADC_VREF_TYPE;
ADCSRA=0x82;

// Global enable interrupts

#asm("sei")
}


// Read the AD conversion result

unsigned int read_adc(unsigned char adc_input)
{
ADMUX=adc_input|ADC_VREF_TYPE; // Start the AD conversion

ADCSRA|=0x40; // Wait for the AD conversion to complete

while ((ADCSRA & 0x10)==0);
ADCSRA|=0x10;
return ADCW;

}
On a clear disk you can seek forever.
bodgy
Posts: 1044
Joined: Tue Dec 04, 2001 1:01 am
Location: Australia
Contact:

Post by bodgy »

A flag is a variable that you declare and then make some of its bits 1 or 0 as you choose.

So make the variable global (declare it outside the MAIN function)

unsigned char my_system_flag;

Then in whichever timer you can use for long delays.

while(!Timer_bit_flag)
{

Timer_bit_flag = 0; //The name of this will be in the hardware register file of your compiler
my_system_flag |= my_system _flag |=(1<<bit2); // set bit 2 of flag byte

}

In MAIN

void main()
{

setup;

while(1)
{

while(my_system_flag)
{
my_system_flag = my_system_flag &~(1<<bit2); //clear bit 2 of flag
adc_var = read_adc(0);
}

}

Hope that helps

Colin
On a clear disk you can seek forever.
User avatar
philba
Posts: 2050
Joined: Tue Nov 30, 2004 1:01 am
Location: Seattle
Contact:

Post by philba »

cwaugs wrote:Tried it, but not user freindly enough for a dumb butt like myself.
O.K. I'm thinkin' start small. In "C" what would the code be for these
three lines?

ADCIN 0, any variable name1
pause 60 seconds
ADCIN 0, any variable name2

I'm just at a loss as to all of the punctuation marks.
Thanks again Emmett
I would do this differently in C.

First off, I'd use a timer interrupt to create a "clock". typically, I set up a 50 uS timer interrupt rate. inside the timer ISR, I have something like this:

Code: Select all

void timer_ISR(void) {
    if( tcnt1mS-- ) {
        tcnt1mS = 20;           // for a 50 uS clock
        // put 1 mS events here
       if( tcnt10mS--) {        // 10 mS section
            tcnt10mS = 10;     // reload 10 mS counter
            // put 10 mS events here (like switch debounce stuff)
            if(tcnt1S--) {        // 1 Second section
                tcnt1S = 100;   // reload seconds counter
                // read ADC value, start next sample going
                }
            }
        }
    }
The idea is you read the current conversion value and then start the next sample going. thus, the ISR just runs on it's own and the ADC values just show up in the vars. You can adjust the count values to make for any ADC sampling rate you want.

Now, you'll need to figure out how to select var 1 or var 2 though i would do is a little differently (move the old value to var 2 and read new value in var 1).
bodgy
Posts: 1044
Joined: Tue Dec 04, 2001 1:01 am
Location: Australia
Contact:

Post by bodgy »

Ahaa, so that's how you keep the correct spacing, on BB's. I'll remember that for the future.


Colin
On a clear disk you can seek forever.
cwaugs
Posts: 28
Joined: Thu Sep 01, 2005 1:01 am
Contact:

Post by cwaugs »

Trying to absorb all of this, I'll be back. Thanks much!
cwaugs
Posts: 28
Joined: Thu Sep 01, 2005 1:01 am
Contact:

Post by cwaugs »

What is the difference between a goto or gosub statement, and an interrupt?
Post Reply

Who is online

Users browsing this forum: No registered users and 7 guests