Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

Code For PWM output proportinal to analog input..Almost..Suggestions?

Status
Not open for further replies.

MoRoH

New Member
Hello all,

I have a PIC16f873A microcontroller and my goal is to put an analog signal on RA0 and get a PWM waveform output. I would like 0v = 0%duty and 5v = 100% duty to control a small DC motor.

This is the code i have...right now, on CCP2 i am getting whatever i set CCPPRL1 = X...so if i set it to 50 im getting a constant 50% duty cycle.

Any ideas how to read the analog input?

Code:
unsigned short duty_cycle;
unsigned short adc_val;


void InitMain() {

  ADCON1 = 0xfe;                 // All ADC pin 1 to on
  TRISA = 0x01;                   // PORTA is input

  PORTC = 0;                       // Set PORTC to
  TRISC = 0x00;                       // PORTC is output
  Pwm_Init(5000);                      // Initialize PWM module

                                        // Timer 2
   PR2=100;                          // 4 MHz clock -> 5kHz PWM frequency
   T2CON = (1<<TMR2ON);

                                       // Initialize Control PWM
   CCPR1L  = 50;                        // Initial Duty
   CCP1CON = 0x0f;                      // PWM mode set and 5,4 duty = 0
}

void main() {
  InitMain();
  Pwm_Start();               // Start PWM


while (2)
{
	adc_val = adc_read(0);             //read analog input RA0
	if (adc_val > duty_cycle)               //   if value is higher
		Pwm_Change_Duty(++duty_cycle);   //then increase duty
	else if (adc_val < duty_cycle)            //if value is lower
		Pwm_Change_Duty(--duty_cycle);    //lower duty

	PORTC = duty_cycle;                   //output PWM on C
	Delay_ms(200);                       //slow down process
}



}
 
I would try something like,
Code:
while (2)
{
    adc_val = adc_read(0);              //read analog input RA0
    duty_cycle=adc_value*100;		//convert 0-1023 to 0-100
    duty_cycle/=1024;    
    CCPR1L  = duty_cyle;
    Delay_ms(200);                       //slow down process
}

Mike.
 
Last edited:
Thanks, I've tried what you suggested but i'm just getting 4 oscillations at 50% duty cycle then it goes low and stays there..i'm trying to modify it, ill update you.

any idea why this is happening?


thanks again
 
I notice you don't setup ADCON0. I also notice that you are initializing the ADC in your code but calling a library function to read it. You should change it to use the library to initialize it or write your own routine to read it.

Can you stop the code and see the reading from the ADC?

Mike.
 
Ok, I have it working now...im simulation and getting my Pwm output at C2...but...for Some reason which i cannot explain.

.it starts good from 0-655 then its at bout (75% duty) which is correct one i hit 656 it flatlines and gets messed up or restarts?

Thanks mike ill keep working on it!!
 
I was using this to do ADC, is this what your talking about, im not sure what your saying about calling in a library function
Code:
unsigned short adc_val  ;
void main ( )
{

ADCON1 = 0xfe  ;
TRISA  = 0x01  ;
TRISB  = 0x00  ;
while (1)
{
adc_val = adc_read(0)    ;
portb = adc_val     ;
}

}
 
I'm assuming that adc_read() is defined in a library and in the same library there will be something like adc_init() that you use to set it up. At the moment ADCON0 isn't setup but it appears to be working so this is probably not the problem.

Mike.
 
Well not a direct help to you but I use the following C code to map the 10 bit 0-5vdc analog input to a 8 bit duty cycle PWM digital output on my Arduino board. Mostly just calls to libary functions but the keyto mapping 10bit range to 8 bit range is the divide by 4 step, or could be done by 2 right bit shifts of the 10 bit analog value.

int potPin = 3; // select the input pin for the potentiometer
int ledPin = 13; // select the pin for the LED
int val = 0; // variable to store the value coming from the sensor

void setup() {
pinMode(ledPin, OUTPUT); // declare the ledPin as an OUTPUT
}

void loop() {
val = analogRead(potPin); // read the value from the sensor
analogWrite(ledPin, val / 4);
}

Lefty
 
Last edited:
He needs the 0-1023 to be mapped to 0-100 (probably 99) and so the simple way to do it is *100/1023. By doing the multiply by 100 first then simple integer maths will suffice. This is why I put the multiply and divide on two separate lines.

Making it 8 bit and dividing by 4 like your example would make it much simpler.

Mike.
 
OK! i got it working.

But i also want to output the digital number on LEDS..sooo

1)I can get the lower 8 bits displayed on port B and the PWM comming of CC2...is there a way to also set RC6 and RC7 to display the 2 MSB while still having PWM on RC2?

2) I'm kinda confused in regards to the clock and osc and thing...I need an external oscillator correct? should it be the same speed as my clk? is it the same thing?

Thanks
 
Hello all, i got my PWM and 10 bit output working using this code...and it was reseting around 3.56 so i changed some timer and multiplier numbers??? (Trial and error) to get it fully on at 5v and off at 0v. Here is my code.

Code:
unsigned int duty_cycle;
unsigned int adc_val;


void InitMain() {

  ADCON1 = 0xfe;                 // All ADC pin 1 to on
  TRISA = 0x01;                   // PORTA is input

  TRISB  = 0x00  ;


  TRISC  = 0x3F;  // Pins RC7, RC6 are outputs


  PORTC = 0;                       // Set PORTC to

  Pwm_Init(8000);                      // Initialize PWM module

                                        // Timer 2
   PR2=62;                          // CALBIRATED THIS BY CHANGIN IT TO 62?TAE
   T2CON = (1<<TMR2ON);

                                       // Initialize Control PWM
   CCPR1L  = 50;                        // Initial Duty
   CCP1CON = 0x0f;                      // PWM mode set and 5,4 duty = 0
}

void main() {
  InitMain();
  Pwm_Start();               // Start PWM

while (2)
{

    adc_val = adc_read(0)    ;
    portb = adc_val     ;
    portc = adc_val >> 2;  // Send 2 most significant bits to Rc7, Rc6


 adc_val = adc_read(0);              //read analog input RA0
    duty_cycle=adc_val*64;		// CALIBRATED IT BY CHANGIN 100 TO 64
    duty_cycle/=1024;
    CCPR1L  = duty_cycle;
}
}


do i need an external oscialltor? what Freq should it be?

Heres my understanding of what i have...my PWM freq is set to 8000khz. is that my clock?

Thanks
 
Can I use this with a flex sensor instead of a pot as the analog input and use the PWM to run a servo ? The flex sensor when not bent as a resistance of 10,000 ohms. As the flex sensor is bent, the resistance increases to 30-40 kohms at 90 degrees ?
 
sure, i don't see why not, as your sensor is bent more, more Vin will be more and yull get a greater duty cycle on your PWM.

you might want to ask someone elses opinion but as long as you get a analog voltage inn the microcontroller dosent care where it comes from. I'm acually taking the vout of a infrared detector for mine.

I used microC compiler for my programming so if you try it in MPLab or something i dont think it will work.
 
Ok but I need a little help with the PWM since the Servo needs to be updated every 20ms and to adjust the servo there needs to be a time on how long theres a high on the output based on this chart approx how would I modify it ? And I only need the one output pin since the servo will be powered seperatly of course

The standard time vs. angle is represented in this chart:
**broken link removed**
 
Last edited:
Hmm, i'm not sure, i'm still all new to microcontrollers, start a new thread. the guys here are good and you should get help pretty soon. I had no idea what i was doing a week ago and now i have it working so try that. sorry im not much help aha
 
I have but all try thanks and np im still new too hence why I have no idea what to use for the code I could do it with a 555 easly enough but its too finiky and its better to do it with a PIC
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top