Op zchool ben ik nog steeds bezig met het maken van een MPPT. hiervoor was dus een microcontroller nodig, en hier had ik eerste ene PIC16F877A voor (omdat die hier aanwezig was) was begonnen met het programmeren in assembler, maar kwam met het probleem te zitten dat er geen hardware multiplier in zat. (en berekeningen dan veel te lang zouden duren )
Een leerar heeft mij toen aangeraden om een PIC18Fxxx microcontroller te gaan gebruiken. ben toen eerst weer met m'n assembler programma verder gegaan, maar dit bleek ook weer erg moeilijk (en onoverzichtelijk!) te zijn.
Gisteren heeft dezelfde leerar mij verteld dat ik maar beter C kan gaan gebruiken. waar ik dus nu 2 dagen mee bezig ben geweest. (had geen ervaring met Microcontrollers voordat ik emt dit project begon. en heb ook weinig ervaring met C. )

anyways, ik heb een programmatje gemaakt welke 2 analoge inputs (van een pic18f2550 op een proefbordje ) leest, deze vermenigvuldigd. en deze waarde dan naar PORTB (8 LEDS) stuurt. Ik weet dat ik 2 bits kwijt raak, gezien de ADC 10-bits en de geheugenplaatsen 8-bit zijn. hier heb ik me verder nog neit in verdiept. (heb justify right gebruikt. dus de lsb, welke voor mij het belangrijkst is, heb ik iig nog)

wat ik nu probeer te doen, is een PWM output linken aan een ADC input. (dus, zodat ik de PWM kan regelen met een potmeter op de ingang. )

hier is mijn code tot nu toe.

#include <adc.h>
#include <pwm.h>
#include <delays.h> 
#include <p18cxxx.h>
#pragma config WDT = OFF

int	ADvalue, ADvalue2, InputPower;
int pwmvdir = 1;
int pwmtmp = 50;
int InputPowerold = 10;

void delay (void)
{
	unsigned int i;	
	for (i = 0; i < 50000 ; i++)
	;
}
void adconvert (void)
{
	//AD input 1
	OpenADC(ADC_FOSC_16 & 
			ADC_RIGHT_JUST & 
			ADC_0_TAD,
			ADC_CH2 & 
			ADC_INT_OFF & 
			ADC_VREFPLUS_VDD & 
			ADC_VREFMINUS_VSS,
			0b1011);
	SetChanADC(ADC_CH2);
	Delay10TCYx( 50 );
	ConvertADC(); 				// Start conversion
	while( BusyADC() ); 		// Wait for ADC conversion
	ADvalue = ReadADC(); 		// Read result and put in temp
	CloseADC(); 				// Disable A/D converter

	//AD input 2
	OpenADC(ADC_FOSC_16 & 
			ADC_RIGHT_JUST & 
			ADC_0_TAD,
			ADC_CH3 & 
			ADC_INT_OFF & 
			ADC_VREFPLUS_VDD & 
			ADC_VREFMINUS_VSS,
			0b1011);
	SetChanADC(ADC_CH3);
	Delay10TCYx( 50 );
	ConvertADC(); 				// Start conversion
	while( BusyADC() ); 		// Wait for ADC conversion
	ADvalue2 = ReadADC(); 		// Read result and put in ADvalue
	CloseADC(); 				// Disable A/D converter
}


void main (void)
{
	TRISB = 0;  				//PORTB = outputs  
	TRISC = 0x00;
	ADCON1 = 0x0f;
	CMCON = 0x07;
	while (1)
	{
		adconvert ();			//Reset the LEDs
		InputPower = ADvalue * ADvalue2;
		PORTB = InputPower;
		
		if(InputPower > InputPowerold)
		{
			// pwmvdir doesnt need changing, since the power increased.
			if(pwmvdir = 1)
			{
				pwmtmp = pwmtmp + 1;
			}
			
			else
			{	
				pwmtmp = pwmtmp - 1;
			}
		}
			
		else
		{
			if(pwmvdir = 1)
			{
				pwmtmp = pwmtmp - 1;
				pwmvdir = pwmvdir + 1;
			}
			
			else
			{
				pwmtmp = pwmtmp + 1;
				pwmvdir = pwmvdir - 1;
			}
		}
		
		InputPowerold = InputPower;

		OpenPWM(0x4E);    //78 in Hex
		SetDCPWM1(pwmtmp);	
		
	}
}

Als ik dit zo compile, krijg ik 1 error message:
" Error - could not find definition of symbol 'OpenPWM' in file 'C:\MPPT Project\test rubbish\PIC18F2550test.o'. "

Ik heb in datasheets en de Microchip C18 guide gekeken, maar kan niet vinden wat ik hier nu verkeerd doe.
Ik programmeer dus met MPLab 8.0 en heb de C18 compiler van microchip geinstalleerd.

Ik heb de microcontoller op 20MHz lopen. en het is de bedoelling dat de PWM op 150kHz gaat werken.

het is verder ook de bedoelling dat ik dit programma in een PIC18F4550 plaats als ik dit programma op de 18F2550 aan de praat heb. (heb tot nu toe alleen nog maar algemene libaries hoeven te gebruiken, dus volgens mij moet dat gewoon kunnen )

Gr.
Tim

Voor zover ik kan afleiden moet je de Timer2 module ingesteld hebben. Ik citeer vanuit de microchip pdf :

In addition to opening the PWM, Timer2 must also be opened with an
OpenTimer2(...) statement before the PWM will operate.

Uit uw code stel ik vast dat Timer2 niet ingesteld is en dat ook het commando OpenTimer2() niet gebruikt is. Met het commando OpenTimer2(hex waarde) doe je een configuratie van de Timer2 module.

Kijk desnoods ook eens in die pdf van microchip, het noemt MPLAB C18 Compiler libraries. :)

Worden de ingelezen waardes van de ADC nu opgeslagen als 10-bit of als 8-bit waarden?
ik weet dat de ADC10-bits is, en de geheugenplaatsen 8-bits zijn, maar hoe kan ik 2 geheugenplaatsen adresseren om dit getal in het geheel op te slaan? (als dit niet al gebeurd. )

ps: Ik denk dat ik de PWM ( <- edited, had er ADC staan, sorry! ) aan de praat heb. (heb nog niet gemeten) nu moet ik alleen nog kijken dat ik de goede frequenties instel.

Gr.
Tim

Ge springt van het ene probleem naar het andere zonder hier eigenlijk te zeggen wat je nu precies wilt van ons.

Eerst krijg je een PWM error en ik geef je uitleg over wat er precies fout is maar daar geef je geen reactie op en nu begin je over de ADC ?

Werkt die PWM nu of niet ?

Excuses, in de PS: bedoelde ik de PWM. ja, deze werk (in ieder geval in de simulatie. ) Ik heb het nog neit in een microcontroller kunnen programmeren. maar zoals het er nu naar uit ziet is dat probleem de wereld uit. :) bedankt voor het geven van het OpenTimer2() commando.

Nu de PWM werkt, zou ik er graag een 10-bit waarde naar toe krijgen. (ipv een 8-bit). dat is dut mijn probleem nu.

Gr.
Tim

Voor zover ik weet is dat zelfs niet mogelijk. Je zal moeten een keuze maken welke bits er voor u het belangrijkste zijn.

Ofwel neem je 8 bits uit de ADC beginnend van de MSB ofwel neem je de 8 bits beginnend vanuit de LSB.

het is dus niet mogelijk om de 10-bit ADC waarde op te slaan, en berekeningen mee te doen? (als 10-bit waarde)

Dat gaat natuurlijk wel maar je kan slechts 8 bits naar de PWM module sturen.

Of je moet via een interrupt lus je eigen PWM signaal maken. Deze kan je zoveel bits geven als nodig is.

lees ik de datasheet verkeerd?

"In Pulse-Width Modulation (PWM) mode, the CCPx pin
produces up to a 10-bit resolution PWM output. Since
the CCP2 pin is multiplexed with a PORTB or PORTC
data latch, the appropriate TRIS bit must be cleared to
make the CCP2 pin an output."

(Ik probeer alleen even te snappen wat ik nu verkeerd lees :) )

maar, het is mogelijk om de ADC als 10 bit waarde in te lezen, en de berekeningen mee te maken? als U mij zou kunnen vertellen hoe ik dit zou moeten doen, dan heb ik het volgens mij ook al voor elkaar. (een 8-bit PWM is genoeg, gezien de pwm niet direct met een ADC waarde gevoerd word)

Gr.
Tim

Zou het genoeg zijn als ik van de int , long int maak?

Unsigned int is prima voor de adc, icm right justify, daarin komt dan een waarde van 0 t/m 1023.

Je moet trouwens werken met OpenPWM1 en OpenPWM2 (toch niet goed gelezen?).

In een project heb ik zelf dit:


OpenADC(ADC_FOSC_64 & ADC_RIGHT_JUST & ADC_20_TAD, ADC_CH0 & ADC_INT_OFF & ADC_VREFPLUS_EXT & ADC_VREFMINUS_VSS, 0b1110);


OpenTimer2(TIMER_INT_OFF & T2_PS_1_4 & T2_POST_1_16);

OpenPWM1(128);
SetOutputPWM1(SINGLE_OUT, PWM_MODE_1);
SetDCPWM1(0);

En ergens anders in een loop:


static unsigned int adcresult, dutycycle;

if (!BusyADC())
{
	adcresult = ReadADC();
	ConvertADC();

	[allemaal berekenigen]

	SetDCPWM1(dutycycle);
}

Hier staat ook een vrij handig document, alle libraries staan daar in beschreven.

[Bericht gewijzigd door bobo1on1 op (11%)]

dit is het programma zoals het nu is. volgens mij moet het zo kloppen. als iemand toch nog een (stomme?) fout ziet, zou fijn zijn als het even gemeld zou kunnen worden. :)

#include <adc.h>
#include <pwm.h>
#include <delays.h> 
#include <timers.h>
#include <p18cxxx.h>
#pragma config WDT = OFF
//#pragma config FOSC = HS

int	Iinput, Vinput, Voutput, InputPower, outputvoltage;
int 		pwmvdir = 1;
int 		pwmtmp = 50;
int 		InputPowerold = 10;

void delay (void)
{
	unsigned int i;	
	for (i = 0; i < 50000 ; i++)
	;
}
void adconvert (void)
{
	//AD input 1
	OpenADC(ADC_FOSC_16 & 
			ADC_RIGHT_JUST & 
			ADC_0_TAD,
			ADC_CH1 & 
			ADC_INT_OFF & 
			ADC_VREFPLUS_VDD & 
			ADC_VREFMINUS_VSS,
			0b1011);
	SetChanADC(ADC_CH1);
	Delay10TCYx( 50 );
	ConvertADC(); 				// Start conversion
	while( BusyADC() ); 		// Wait for ADC conversion
	Iinput = ReadADC(); 		// Read result and put in temp
	CloseADC(); 				// Disable A/D converter

	//AD input 2
	OpenADC(ADC_FOSC_16 & 
			ADC_RIGHT_JUST & 
			ADC_0_TAD,
			ADC_CH2 & 
			ADC_INT_OFF & 
			ADC_VREFPLUS_VDD & 
			ADC_VREFMINUS_VSS,
			0b1011);
	SetChanADC(ADC_CH2);
	Delay10TCYx( 50 );
	ConvertADC(); 				// Start conversion
	while( BusyADC() ); 		// Wait for ADC conversion
	Vinput = ReadADC(); 		// Read result and put in ADvalue
	CloseADC(); 				// Disable A/D converter

	//AD input 3
	OpenADC(ADC_FOSC_16 & 
			ADC_RIGHT_JUST & 
			ADC_0_TAD,
			ADC_CH3 & 
			ADC_INT_OFF & 
			ADC_VREFPLUS_VDD & 
			ADC_VREFMINUS_VSS,
			0b1011);
	SetChanADC(ADC_CH3);
	Delay10TCYx( 50 );
	ConvertADC(); 				// Start conversion
	while( BusyADC() ); 		// Wait for ADC conversion
	Voutput = ReadADC(); 		// Read result and put in temp
	CloseADC(); 				// Disable A/D converter
}


void main (void)
{
	TRISB = 0;  				//PORTB = outputs  
	TRISC = 0x00;
	ADCON1 = 0x0f;
	CMCON = 0x07;
	while (1)
	{
		adconvert ();			//Reset the LEDs
		InputPower = Iinput * Vinput;
		outputvoltage = Voutput;
		
		if(outputvoltage > 0xB9 )   //55.2V (4x 13,8V) is the cutoff value, reference is 5 volt.  te value is 3,61V.   
									// so,   3,61/5 = 185             185 in hex is B9
		{
			pwmtmp = 0;
		}	

		else
		{
			if(InputPower > InputPowerold)
			{
				// pwmvdir doesnt need changing, since the power increased.
				if(pwmvdir = 1)
				{
					pwmtmp = pwmtmp + 1;
				}
			
				else
				{	
					pwmtmp = pwmtmp - 1;
				}
			}
			
			else
			{
				if(pwmvdir = 1)
				{
					pwmtmp = pwmtmp - 1;
					pwmvdir = pwmvdir + 1;
				}
			
				else
				{
					pwmtmp = pwmtmp + 1;
					pwmvdir = pwmvdir - 1;
				}
			}
		}
		InputPowerold = InputPower;

//Setup PWM output

		//Open Timer 2 - Timer 1 & 2sources all CCPs 
  		OpenTimer2( TIMER_INT_OFF & T2_PS_1_16 & T2_POST_1_1 );   //timer 2 settings

		//Configure PWM 
  		OpenPWM1(0x1F);      // 150kHz @ 20MHz  ( 156.25 kHz )

		//Set PWM Duty Cycle 
  		SetDCPWM1(pwmtmp);  
		
	}
}

De adc hoef je maar 1x te openen, dit doe je nu bij elke conversie, hetzelfde doe je met de pwm en met timer2.

Je roept voor elke conversie ConvertADC aan en dan wacht je tot de conversie klaar is.
Wat je beter kunt doen is ConvertADC aanroepen direct na de conversie, dat werkt het snelst aangezien de controller nog het een en ander kan doen tijdens de conversie.


if(pwmvdir = 1)

Daar moet je = in == veranderen, je assigned nu namelijk 1 aan pvmdir en de if bekijkt of 1 niet gelijk is aan 0.
Deze code doet hetzelfde:


pwmvdir = 1;
if(1)

Het lijkt me niet dat je dat wil.

Bedankt! die dubbel = had ik inderdaad neit gezien! :)

Ik zal morgen het programma aanpassen. (en even kijken wat ik weg kan laten met de ADC's openen etc )

Gr.
Tim

Hbe het programma aangepast, werkt nog steeds niet (helaas)

Ik heb alleen geen idee waarom niet. dus dacht ik, laat ik even een programma maken waaring ik alleen een constante PMW output genereer.

#include <pwm.h>
#include <timers.h>
#include <p18cxxx.h>



void main(void)
{
        while
        {
	       OpenTimer2( TIMER_INT_OFF & T2_PS_1_16 );  
	       OpenPWM1(0x1F);		// Configure PWM channel 1.
	       SetDCPWM1(0xB3);	       // Write a duty cycle value of 70% PWM channel 1.

        }
}

dit is het resultaat. echter, als ik dit programma er in zet, en de Microcontroller aan zet, krijg ik een DC spanning van iets over 1volt op de PWM1 pin. ( CCP1, pin-17 )
wat doe ik hiermee verkeerd? want volgens mij zou dit zo toch moeten werken.

of moet ik de PWM output na elke cycle closen? de datasheets en guides word ik op het moment ook niet wijs uit. veel te veel info, en ik heb zo onderhand geen idee meer wat nu wel of niet van toepassing is voor mij.

Je blijft nu constant je PWM instellen, dat kan rare effecten hebben.

Probeer eens:


void main(void)
{
 	       OpenTimer2( TIMER_INT_OFF & T2_PS_1_16 );  
	       OpenPWM1(0x1F);		// Configure PWM channel 1.
	       SetDCPWM1(0xB3);	       // Write a duty cycle value of 70% PWM channel 1.
       while
        {

        }
}

Overigens, geen idee of het werkt. Vergeet overigens niet je poorten als uitgangen in te stellen, via configuratie bits kun je ze namelijk standaard als analoog ingang zetten.

/Edit: Hoe meet je overigens? Ik hoop dat je met een scope meet die snel genoeg is. Met een multimeter zul je weinig resultaat zien, tenzij het een true rms ding is.

[Bericht gewijzigd door RoelA op (14%)]

helaas werkt het niet.

Ik meet met een Philips PM3050 Scope. gaat tot 60MHz.

Moet ik een kristal (welke verbonden is met de 2 OSC pinnen nog in de software instellen? zodat de chip deze 20MHz kristal gebruikt ipv een interne klok generator of zo? (Ik snap niet waarom dit nu neit werkt.. Alle gegevens staan er zo toch goed in? )

edit: heb de clock (in dat configuration bits scherm, op SH: USB-HS staan. als ik dat vergelijk emt de datasheet zou deze toch inderdaar de 20MHz van de xtal moeten gebruiken? (voor 20MHz staat in de datasheet dat ik HS moet hebben, er zijn 2 HS, deze en HS + PLL, en dat lijkt me niet juist. )

[Bericht gewijzigd door Klamath op (31%)]

Als je een 20 mhz kristal hebt kun je dit wel als config gebruiken:


        #pragma config PLLDIV   = 5         // (20 MHz crystal)
        #pragma config CPUDIV   = OSC1_PLL2
        #pragma config USBDIV   = 2         // Clock source from 96MHz PLL/2
        #pragma config FOSC     = HSPLL_HS
        #pragma config PWRT     = ON
        #pragma config WDT      = OFF

Ben nu al een tijdje weer aan het proberen/meten. de compiler geeft geen errors. (hoewel ik neit weet hoe ik de PWM output zou moeten kunnen simuleren op de pc)
maar als ik het programma in de Microcontroller zet, blijft de PWM poort op 0 Volt.


#include <p18cxxx.h>
#include <pwm.h>
#include <timers.h>
#include <adc.h>

//configuring the clock to use the 20MHz crystal
#pragma config PLLDIV   = 5         // (20 MHz crystal)
#pragma config CPUDIV   = OSC1_PLL2
#pragma config USBDIV   = 2         // Clock source from 96MHz PLL/2
#pragma config FOSC     = HSPLL_HS
#pragma config PWRT     = ON
#pragma config WDT      = OFF



void main(void)
{
 	TRISC = 0;			//Set PORTC as output.	       
	OpenTimer2( T2_PS_1_16 );   
	OpenPWM1(0x1F);		// Configure PWM channel 1.
	SetDCPWM1(0xB3);	// Write a duty cycle value of 70% PWM channel 1.
       while(1)
        {
		;	//loop to keep the program running
        }
}

Ik meet de PWM uitgang op pin 12 (CCP1) en pin 8 (Vdd)
er hangt een 20MHz kristal aan pin 9 en 10 (OSC1 en OSC2) met uiteraard de 2 C's.

Voor zover ik weet (info uit de datasheets en guides kan halen) zou dit programma zo moeten werken.
Ik wil gewoon een 150kHz PWM signaal (met een dutycycle van 70%) op de CCP1 pin hebben.

Ik snap niet waarom dit nu niet werkt.

heb het programma herschreven. (ipv PWM.h te gebruiken, de waardes zelf invoeren etc)

#include <p18F2550.h>
#include <pwm.h>
#include <timers.h>
#include <adc.h>

//configuring the clock to use the 20MHz crystal
#pragma config PLLDIV   = 5         // (20 MHz crystal)
#pragma config CPUDIV   = OSC1_PLL2
#pragma config USBDIV   = 2         // Clock source from 96MHz PLL/2
#pragma config FOSC     = HSPLL_HS
#pragma config PWRT     = OFF
#pragma config WDT      = OFF


void main(void)
{
	
	PR2 = 0x3F;				//Set PWM Frequentcy to ~150kHz
	CCPR1L = 0xB3;			//set PWM Dutycycle.  70% here
	CCP1CON	= 0b00011111;	//Set CCP1 to PWM mode and set the 2 LSB's of the PWM DTs
	TRISC = 0;				//set PORTB as outputs
	T2CON = 0b00000100; 	//set timer 2.   prescaler =0, timer2 = on, Postscaler = 1:16

	while(1)
	{
		;
	}
}

het probleem, exact hetzelfde resultaat als m'n andere programma. Ik meet tussen de CCP1 pin, en een Vss pin helemaal niets (0 Volt DC )

iemand enig idee waardoor dit kan komen?

Werkt de pic wel? Misschien iets van

Led = 1
delayms 500
led = 0
delayms 500

in je while toevoegen?

Hoe meet je het? Een 150KHz pwm is best snel, misschien kan je multimeter het niet aan. Heb je geen scoop. Anders zou je er een ledje aan kunnen hangen en het programma zo schrijven dat de pwm freq steeds iets stijgt.

Je houdt niet precies de volgorde van de datasheet aan, misschien dat het werkt als je dat wel doet.

Ik meet met een scope (welke tot 60MHz aan kan) en krijg alleen maar een DC spanning er uit. (als ik de gnd know druk, veranderd er niets)
Ik trigger de scope op een 150kHz blokgolf van een functie generator, zodat ik het beeld in ieder geval ongeveer goed heb staan.
Ik zal morgen eens kijken of ik een andere PIC kan gebruiken. maar, zowel de PIC18F2550 als onze PIC18F4550 geven geen PWM signaal emt dit programma.

PS: Ik heb me juist letterlijk aan de datasheet volgorde gehouden. (voor zover ik kan lezen)

15.4.4 SETUP FOR PWM OPERATION
The following steps should be taken when configuring
the CCP module for PWM operation:
1. Set the PWM period by writing to the PR2
register.
2. Set the PWM duty cycle by writing to the
CCPRxL register and CCPxCON<5:4> bits.
3. Make the CCPx pin an output by clearing the
appropriate TRIS bit.
4. Set the TMR2 prescale value, then enable
Timer2 by writing to T2CON.
5. Configure the CCPx module for PWM operation.

[Bericht gewijzigd door Klamath op (40%)]

Je gaat niet in op de waardevolle blink-a-led tip van bassie-. Ik ga nu niet de datasheets voor je uitpluizen, of die PWM-library bekijken, maar je wilt toch op z'n minst weten of die uC wel draait, niet?

De uC draait wel. (heb er andere programma's in geprobeerd, welke wel werken. )

anyways, heb de PWM nu ook aan eht draaien.

#include <p18F4550.h>
#include <pwm.h>
#include <timers.h>
#include <adc.h>

//configuring the clock to use the 20MHz crystal
#pragma config PLLDIV   = 5         // (20 MHz crystal)
#pragma config CPUDIV   = OSC1_PLL2
#pragma config USBDIV   = 2         // Clock source from 96MHz PLL/2
#pragma config FOSC     = HSPLL_HS
#pragma config PWRT     = OFF
#pragma config WDT      = OFF


void main(void)
{
	PR2 = 0x43;				//(0x43 for the test pcb) Set PWM Frequentcy to ~150kHz
	CCPR1L = 0x2A;			//set PWM Dutycycle.  70% here
	CCP1CON	= 0b00011111;	//Set CCP1 to PWM mode and set the 2 LSB's of the PWM DTs
	TRISC = 0;				//set PORTB as outputs
	T2CON = 0b00000000; 	//set timer 2.   postscalercaler =0, timer2 = on, Prescaler = 1:16
	T2CONbits.TMR2ON = 1; 	//enable Timer 2

	while(1)
	{
		;
	}
}

Ik had Timer 2 ge-enabled in dezelfde commando als deze geconfigureerd werd. dat mag blijkbaar niet.
Ook had ik de CCPR1L te hoog staan. (want de PWM was constand '1' toen deze werkte. mag blijkbaar niet hoger zijn dan 0x3F (de waarde van PR2 op dat moment.)

maar het enablen van de Timer2 in een commando na het configureren, en niet in het configuratieprogramma was dus het probleem. (in de PIC18F2550 op de test print werkt het, in de 4550 nog niet. maar daar meot wel achter te komen zijn lijkt me)

Je gaat niet in op de waardevolle blink-a-led tip van bassie-. Ik ga nu niet de datasheets voor je uitpluizen, of die PWM-library bekijken, maar je wilt toch op z'n minst weten of die uC wel draait, niet?

Ik heb gisteren laat ind e middag m'n laatste post hier gemaakt.. en het is nu de morgen erna en ik begin er net weer mee.. tuurlijk ben ik er nog neit op in gegaan.