Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

PIC24 PWM Input read

Status
Not open for further replies.

vikash23

Full Member level 2
Joined
Jul 31, 2012
Messages
133
Helped
3
Reputation
6
Reaction score
3
Trophy points
1,298
Activity points
2,676
Hi,

I am using pic24hj128gp502

I am generating a 1KHz signal using a function generator, 5Vpk-pk, 20% duty.

I need to measure the PWM usnig my PIC24 and see it in my UART2 port.

I have executed UART2 port and I can see a message that i send

I saw some guide regarding input capture compare but I didn't understand how to implement it in software

Guide: **broken link removed** ... 70198D.pdf

I have attached my code. Please have a look and let me know how to move further.

Also can I please know when the CPU reads the input of the PWM what it reads as ? as a binary or as a hex value?


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#include "p24hxxxx.h"                  /* generic header for PIC24H family */
 
#include "ccp.h"
#include "../../../Chapter 4 Code Examples/excerise 1 UART/CONU2.h"
 
_FOSCSEL(FNOSC_FRC);                        // set oscillator mode for FRC ~ 8 Mhz
_FOSC(FCKSM_CSDCMD & OSCIOFNC_ON & POSCMD_NONE);   // use OSCIO pin for RA3
_FWDT(FWDTEN_OFF);                           // turn off watchdog
#define PWMin RPINR7bits.IC1R
#define BUF_SIZE 32
#define iend 25   //delay loop is iend times jend instruction cycles
#define jend 1000
char count[] = {'0','0','0','0', '0'};
char s[BUF_SIZE];
int PWM = 0;
static char   rxchar='0';       //received character
unsigned char got_rx =0;      //rx char flag
//delay function
   void delay(void) { // 100 msec
      int i,j;
      for (i=0; i<iend; i++)
         for (j=0;j<jend; j++);    }
 
    void __attribute__((interrupt, no_auto_psv)) _U2RXInterrupt(void)
{
     rxchar =  (char) (U2RXREG & 0x00ff);
   
   
      got_rx =1;
      // Clear the UART RX interrupt flag bit
        IFS1bits.U2RXIF = 0;
               
}
 
    void __attribute__((interrupt, no_auto_psv)) _IC1Interrupt(void)
{
    IFS0bits.IC1IF=0;
}
 
 
int main ( void )
{ 
__builtin_write_OSCCONL(OSCCON & 0xbf) ; //clear bit 6  unlock
 
    PWMin = 6;        //make pin 6 IC1
    
    //programming input perpherial pin selects
    RPINR19bits.U2RXR = 10;   // make pin RP10  U2RX I/O
 
// programming output perpherial pin selects
    RPOR5bits.RP11R =5;  //make RP11 U2TX
 
__builtin_write_OSCCONL(OSCCON | 0x40) ; //set bit 6 lock
    
    T2CONbits.TON = 0; 
    TMR2 = 0;
    PR2 = 25000-1;
    _T2IP = 1;          // Interrupt priority
    T2CONbits.TON = 1;        //0 0 0 0 00 0 0 0 0 1
               
    iniPWMin();
    initU2();
   rxchar =0;
    got_rx= 0;
// interrupt priorities
 
   _U2RXIP=4;
   _IPL =0;
      
//   }   
// Hyperterminal Startup Inro Screen
   clrscr();  //clear hyper terminal screen
    home();
    putsU2("The MicroStick UART2 Experiment");
    putU2(0x0a);  //carriage return /line feed
    putU2(0x0d);
    putsU2("Type a character and watch the return");
    putU2(0x0a);  //carriage return /line feed
    putU2(0x0d);
    
   while (1)    /*  endless loop vary pot and capture reading*/
   {
      
   //   2. delay for min time using timer1 read before next change
        PWM = readPWM();
        //rxchar = getU2();      
        putU2(PWM);
        //Nop();
        
        delay();
        
   }   
 
}




Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/*
** CONU2.h
** console I/O library for Explorer16 board
*/
 
// I/O definitions for the Explorer16
//#define CTS    _RF12   // Cleart To Send, input, HW handshake
//#define RTS     _RF13   // Request To Send, output, HW handshake
#define BACKSPACE 0x8   // ASCII backspace character code            
 
// init the serial port (UART2, 115200@32MHz, 8, N, 1, CTS/RTS )
void initU2( void);
 
// send a character to the serial port
int putU2( int c);
 
// wait for a new character to arrive to the serial port
char getU2( void);
 
// send a null terminated string to the serial port
void putsU2( char *s);
 
// receive a null terminated string in a buffer of len char
char * getsn( char *s, int n);
 
// useful macros
#define clrscr() putsU2( "\x1b[2J") 
#define home()   putsU2( "\x1b[H") 
#define pcr()    putU2( '\r')




Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
/*
** CONIO.C
** Basic CONSOLE I/O for Explorer16 demonstration board
*/
 
#include "p24hxxxx.h"
#include "conU2.h"
 
#define FCY 7370000/2
//#define FCY 8000000/2
#define BAUDRATE 9600
#define BRGVAL ((FCY/BAUDRATE)/4)-1
#define U_ENABLE 0x8000      // enable the UART
#define U_TX    0x0400      // enable transmission
 
// init the serial port (UART2, 1200, 8, N, 1 )
void initU2( void)
{ 
   U2BRG = BRGVAL; // BAUD Rate Setting for 9600
   U2MODE    = U_ENABLE;
   U2STA    = U_TX;
   U2MODEbits.BRGH = 1; // high Speed mode
} // initCon
 
// send a character to the UART2 serial port
int putU2( int c)
{
   while ( U2STAbits.UTXBF);   // wait while Tx buffer full
   U2TXREG = c;
   return c;
} // putU2
 
 
// wait for a new character to arrive to the UART2 serial port -don't use during interrupts
char getU2( void)
{
  
   while ( !U2STAbits.URXDA);   // wait for a new character to arrive
//
   return U2RXREG;      // read the character from the receive buffer
 
 
}// getU2
 
 
// send a null terminated string to the UART2 serial port
void putsU2( char *s)
{
   while( *s)         // loop until *s == '\0' the  end of the string
      putU2( *s++);   // send the character and point to the next one
    putU2( '\r');       // terminate with a cr / line feed
} // putsU2
 
 
char *getsn( char *s, int len)
{
    char *p = s;            // copy the buffer pointer 
    do{
        *s = getU2();       // wait for a new character
        putU2( *s);         // echo character
        
        if (( *s==BACKSPACE)&&( s>p))
        {
            putU2( ' ');     // overwrite the last character
            putU2( BACKSPACE);
            len++;
            s--;            // back the pointer
            continue;
        }
        if ( *s=='\n')      // line feed, ignore it
            continue;
        if ( *s=='\r')      // end of line, end loop
            break;          
        s++;                // increment buffer pointer
        len--;
    } while ( len>1 );      // until buffer full
 
    *s = '\0';              // null terminate the string 
    
    return p;               // return buffer pointer
} // getsn
    
 
#ifndef __CCPDRV_H__
#define __CCPDRV_H__ 
 
void turnoff(void);
void turnon(int setting);
void setPWM(int setting);
int iniPWMin (void);
char readPWM( void);
#endif




Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include "p24hxxxx.h"                  /* generic header for PIC24H family */
 
void turnoff(void) {
   //turn off  RB2, Timer2 and any OC1 configuration on this pin
   T2CON =0;
   OC1CON =0x0000;
   TRISBbits.TRISB2 = 1;
   }
void turnon(int setting) {
      //turn on RB2, Timer2 and the PWM OC1 configuration on this pin
   PR2=0x07ff ;
   OC1R =setting;
   OC1RS =setting;
   OC1CON = 0x0006;  //timer2 and edge aligned PWM
   T2CON =0x8000;
   }
void setPWM(int setting) {
turnoff();
turnon(setting);
}         
 
void iniPWMin (void){
    IC1CONbits.ICM = 0;
    IC1CON = 0x89; //00 0 00000 1 00 0 1 001    rising edge,buffer is empty,No input capture overflow,Interrupt on every second capture, TMR2
    T2CON =0x8000;
}
 
char readPWM( void)
{
  
   while ( !IC1CONbits.ICBNE);   // wait for a new character to arrive
 
   return IC1BUF;      // read the character from the receive buffer
 
}

 

What compiler are you using? It is generally not a good idea to use the 'generic' headers as there can be significant variations within the device families. I would suggest that you use the latest XC16 compiler (which is free) whch means all you need to add in is the 'xc.h. include at the start and the MPLABx IDE will do they rest for you.
The Input Capture module effectively measures the time interval between two input transition events. Therefore you really need to understand what you want to measure.
With a PWM signal, the thing that varies (typically) is the width of the pulse (hence the name 'pulse *width* modulation) - the frequency of the pulses is always the same.
Therefore you can set the IC module to capture the counter on the leading and trailing edges of the wave form. That means you need to read 2 values from the FIFO and subtract the first from the 2nd - that will give you the number of clock ticks between the two events.
You also need to set the timer/counter to a suitable frequency. For that you need to know the resolution you want to measure the pulse width to. If the PWM signal has a base frequency of 1kHz and there can be 100 steps between the narrowest and the widest pulse with, then you will need a clock that is ticking at least once every 10uSec (possibly much faster - say 10x faster - so the counter will always have incremented between the two edge triggers). Of course you will need to do your own calculations - I'm just making these requirements up as I go and selecting numbers that make the calculations easier.
Now that you know how fast the timer/counter is incrementing and you know the counts at the start and end of the pulse (specifically their difference) then you can work out the time the difference represents.
Section 12.5.1 of the FRM section that you reference shows this as well.
As for the format of the numbers of the IC module FIFO, they are always 16-bit unsigned integers - the same as the timer/counter values. How you interpret them is up to you. If you want to treat them as hex values then take the bits 4 at a time.
When you come to sending the values through the UART, you need to think about that as well - specifically what is going to receive the values and how it will interpret the values. You could send each 16-bit binary value as 2 8-bit values, or you could convert the value to ASCII characters and send those (especially if the receiving end is a terminal emulator - don't forget to add in the line terminators in this case). It really is up to you as the designer to determine these things.
Susan
 

Thanks for the detailed info.

I use XC 16 compiler and I can understand all your procedures. All I am trying to do is how to implement it in terms of as code.

Also I came to know that it is hard to use a input capture compare and it's better to use RC filter and use analog input to find the duty cycle. Is it true?

If yes then I will implement that method as I have used the ADC before.

- - - Updated - - -

Also I am using dspic33EV eval kit and I am trying to generate PWM. Our software engineers have developed HAL function to generate PWM and it works find.

my application is DC motor control using full bridge and I would like to know how I can disable the low side of the PWM using IOCONx ?

or do I needs to use a complementary PWM and give 0% duty cycle for the low side ?
 

Hi,

Also I came to know that it is hard to use a input capture compare and it's better to use RC filter and use analog input to find the duty cycle. Is it true?
Why do you think it is hard?
The "capture value" is a timestamp.
You need three timestamps to calculate duty cycle very previsely:
T1) first rising edge
T2) falling edge
T3) second rising edge

T2-T1 = HIGH time
T3 - T1 = period time
Duty cycle = high time / period time = (T2 - T1) / (T3 - T1)

You may also use the "analog filter and ADC" method, but it is more hardware effort with less accuracy.

Klaus
 

Hi,

many thanks for your response and let me try the method that you have mentioned.

on the other side I am trying to use the UART

Basically I bought a book "Beginner's Guide to Programming the PIC24/dsPIC33: Using the Microstick and Microchip C Compiler for PIC24 and dsPIC33 " and learnt how to use PWM, ADC, UART , Setting up clock.

The PIC24 used is PIC24HJ128GP502 have similar function to dsPIC33EV256GM106 of the UART function and have same register settings .

I just copied the code that was written to PIC24HJ128GP502 to use it on the dsPIC33EV256GM106 and set the UART TX and RX PPS functions

I can able to see the message transmitted from the chip to serial port (tera term)

But i cant see any letter on the tera term that was typed on the keyboard.

Basicall what the code does is what ever I type on the keyboard it will be displayed on the tera term and I check the code the PIC24H eval board and it;s fine.

Can you please see what I am missing here ? Please see my code attached

Code:
/**********************************************************************
* © 2010 Microchip Technology Inc.
*
* FileName:        main_led.c
* Dependencies:    p24HJ64GP502.h
* Processor:       PIC24H
* Compiler:        MPLAB® C30 v2.01 or higher
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* ADDITIONAL NOTES:  
*
* Simple demo program showing a flashing LED 
*modified by THK for chapter2 execerises 1/18/10
*modified by THK for chapter 6 timer execerises with interrupts
*modified by THK for chapter7 UART excerises
*********************************************************************/
//#include "p24hxxxx.h"									/* generic header for PIC24H family */
#include "xc.h"
#include "CONU2.h"
_FOSCSEL(FNOSC_FRC);								// set oscillator mode for FRC ~ 8 Mhz
_FOSC(FCKSM_CSDCMD & OSCIOFNC_ON & POSCMD_NONE);	// use OSCIO pin for RA3
_FWDT(FWDTEN_OFF);									// turn off watchdog
#define led LATCbits.LATC4
//***************************************************/
// Define Constants Variables
//***************************************************/

#define BUF_SIZE 32

//***************************************************

static char	rxchar='0'; 		//received character
char s[BUF_SIZE];
unsigned char got_rx =0;		//rx char flag
//RX U2 interrupt ---no used in data logger
void __attribute__((interrupt, no_auto_psv)) _U2RXInterrupt(void)
{
	
 

		rxchar =  (char) (U2RXREG & 0x00ff);
	
	
		got_rx =1;
		// Clear the UART RX interrupt flag bit
        IFS1bits.U2RXIF = 0;
      			
}
/********************************* 
	main entry point
*********************************/
int main ( void )
{	/* 	Initialize ports */
	 									//set all pins that share analog and make them digital

//programming input perpherial pin selects
RPINR19bits.U2RXR = 35;	// make pin RB3 U2RX I/O

// programming output perpherial pin selects
RPOR3bits.RP40R1 =1;  //make RB8 U2TX  
RPOR3bits.RP40R0 =1;

initU2();

rxchar =0;
got_rx= 0;
// interrupt priorities

	_U2RXIP=0;
	_IPL =0;
	
//	while(1) {
//	putU2('0');	
		
//	}	
// Hyperterminal Startup Inro Screen
	clrscr();  //clear hyper terminal screen
    home();
    putsU2("The MicroStick UART2 Experiment");
    putU2(0x0a);  //carriage return /line feed
    putU2(0x0d);
    putsU2("Type a character and watch the return");
    putU2(0x0a);  //carriage return /line feed
    putU2(0x0d);
    
	
	/*  endless loop*/
	while (1)
	{
	
    rxchar = getU2();		
	putU2(rxchar);
        Nop();
	}
	
}

Code:
/*
** CONIO.C
** Basic CONSOLE I/O for Explorer16 demonstration board
*/


//#include "p24hxxxx.h"
#include "xc.h"
#include "conU2.h"


#define FCY 7370000/2
//#define FCY 8000000/2
#define BAUDRATE 9600
#define BRGVAL ((FCY/BAUDRATE)/4)-1
#define U_ENABLE 0x8000		// enable the UART
#define U_TX	 0x0400		// enable transmission

// init the serial port (UART2, 1200, 8, N, 1 )
void initU2( void)
{ 
	U2BRG = BRGVAL; // BAUD Rate Setting for 9600
	U2MODE 	= U_ENABLE;
	U2STA 	= U_TX;
	U2MODEbits.BRGH = 1; // high Speed mode
} // initCon

// send a character to the UART2 serial port
int putU2( int c)
{

	while ( U2STAbits.UTXBF);   // wait while Tx buffer full
	U2TXREG = c;
	return c;
} // putU2


// wait for a new character to arrive to the UART2 serial port -don't use during interrupts
char getU2( void)
{
  
	while ( !U2STAbits.URXDA);	// wait for a new character to arrive
//
	return U2RXREG;		// read the character from the receive buffer


}// getU2


// send a null terminated string to the UART2 serial port
void putsU2( char *s)
{
	while( *s)			// loop until *s == '\0' the  end of the string
		putU2( *s++);	// send the character and point to the next one
    putU2( '\r');       // terminate with a cr / line feed
} // putsU2


char *getsn( char *s, int len)
{
    char *p = s;            // copy the buffer pointer 
    do{
        *s = getU2();       // wait for a new character
        putU2( *s);         // echo character
        
        if (( *s==BACKSPACE)&&( s>p))
        {
            putU2( ' ');     // overwrite the last character
            putU2( BACKSPACE);
            len++;
            s--;            // back the pointer
            continue;
        }
        if ( *s=='\n')      // line feed, ignore it
            continue;
        if ( *s=='\r')      // end of line, end loop
            break;          
        s++;                // increment buffer pointer
        len--;
    } while ( len>1 );      // until buffer full
 
    *s = '\0';              // null terminate the string 
    
    return p;               // return buffer pointer
} // getsn

Code:
/*
** CONU2.h
** console I/O library for Explorer16 board
*/

// I/O definitions for the Explorer16
//#define CTS 	_RF12   // Cleart To Send, input, HW handshake
//#define RTS     _RF13   // Request To Send, output, HW handshake
#define BACKSPACE 0x8   // ASCII backspace character code            

// init the serial port (UART2, 115200@32MHz, 8, N, 1, CTS/RTS )
void initU2( void);

// send a character to the serial port
int putU2( int c);

// wait for a new character to arrive to the serial port
char getU2( void);

// send a null terminated string to the serial port
void putsU2( char *s);

// receive a null terminated string in a buffer of len char
char * getsn( char *s, int n);

// useful macros
#define clrscr() putsU2( "\x1b[2J") 
#define home()   putsU2( "\x1b[H") 
#define pcr()    putU2( '\r')
 

If you can see the characters/strings that are generated by the code then you know that the 'putU2()' function is working and that the BAUD rate etc is allowing characters to be exchanged.
What you need to do is to confirm that the characters are being received and read by the 'getU2()' function. Probably the easiest way to do that is to do a debug build and set a breakpoint in the 'getU2' function. There you can check that the UART is correctly receiving something - or not!
If nothing is being received then try connecting the Tx and Rx lines from the PC to make sure that it is actually sending something. Also check that the pin you are using to receive is set to 'digital' mode (if the pin can have an analog input then it will be defaulted to 'analog' mode).
Let us know how you get on with that and we can help you further depending on what you find.
Susan
 

Hi,

Many many many thanks for your help...

It did work.

It's the pin that is set to analog by default.

On the PIC24 chip example UART it says AD1PCFGL where by default all pin is set to analog.

for dspic33ev ANSELx register sets all pin by default as analog. I set the port a and c to digital and it works now.

My next task is ADC.

For some reason the debug is not working and says "Programming/Verify complete
The target device is not ready for debugging. Please check your configuration bit settings and program the device before proceeding. The most common causes for this failure are oscillator and/or PGC/PGD settings."

There is some thing I need to do with config bits. I will try and let you know the results

Please guide me if I am struck with some thing.

Thanks again.
 

If you can program the MCU then the PGC/PGD lines are probably OK.
I would check that you are actually doing a 'debug' build with the correct programming pin pair specified and programming that into the MCU. (Note: *DON'T set the DEBUG config setting yourself - the IDE will do that for you depending on the type of buld you have selected.)
By the way, I've just looked back to your original code. If you are using XC16 then you should NOT include any processor or family specific header file. Rather, you just include "<xc.h>" and it uses the information passed from the IDE about the chip you are using to select the correct processor specific header file for you.
[Aside: When you do a 'release' build in the IDE, the compiler/linker will use exactly the code you have written and program that into the MCU. In this case, when the MCU comes out of reset, then your code will start immediately. On the other hand, when you do a 'debug' build, the linker will add in a block of code called the 'debug kernel' and this is the code that will be executed first on coming out of reset. What this code does is to use the CONFIG settings to know which programming/debug pair of lines to use and it will then try to communicate with the IDE over these lines. On the IDE side of things, when you complete a debug programming cycle, the IDE will try to communicate with the 'debug kernel' and the error message you are seeing is what results when it cannot communicate.
With devices such as yours that have more than one pair of programming pins, you can use any pair to program the MCU but you must specify the correct pair (in the CONFIG settings) where the debugger is connected so that it can communicate back to the IDE. Hence the reference in the error message to check the CONFIG settings.]
Susan
 

Hi Susan,

many thanks for your detailed explanation about the debug and programming.

Just to make you clear I am using two EVAL board.

First I bought the book "Beginner's Guide to Programming the PIC24/dsPIC33: Using the Microstick and Microchip C Compiler for PIC24 and dsPIC33 " and the eval kit that is related to that book.

Second one is the "dsPIC33EV 5V CAN-LIN Starter Kit ( DM330018 )" which I am going to use for my actual project.

I am trying to use the code that came with the PIC24 kit to my dsPIC33EV. Most peripherals are similar and PIC24H uses a different pin for debug.

Yesterday, I included the line "_FICD(ICS_PGD2);" to my dsPIC33EV code and it worked perfectly fine (As you mentioned to use correct pair for debugging)

Now I have got UART working and debug port working too.

Will try ADC today and let you know the results.

thanks

-Vikash
 

Have a look at the XC16 User Guide for the newer format for specifying the CONFIG setting using the #pragma directive. While what you are using is not wrong, I think the #pragma format is a little easier to read.
Susan
 

I didt use pragma because the clock and watch dog timer uses the follwoing format

Code:
_FOSCSEL(FNOSC_FRC);								// set oscillator mode for FRC ~ 8 Mhz
_FOSC(FCKSM_CSDCMD & OSCIOFNC_ON & POSCMD_NONE);	// use OSCIO pin for RA3
_FWDT(FWDTEN_OFF);

so I used the same format to make it look like same

Ok, Now like i mentioned I did the code for the ADC and using UART I can able to see the ADC values,.

Basically the ADC raw value is in hex format and I use binary to ASCII to print it in the serial port

Again this code is also part of PIC24H dev kit and what I dont understand is the ADC value is Hex format and why the function is written as Binary to ascii when I see it needs to say Hex to ascii.

New I need to scale my hex value.

0 as 0volt and 4096 as 5 v. (using 12 bit configuration)

if i need to get voltage the formula is dec value * 0.00122 (dev val = 4096 0.12222 = 5V/4096 resolution for 12 bit)

How do I do it ?

how can I divide hex value by decimal or another hex value ?

if I divide two hex value what happens to the reminder and how will I use it ?

Also I am using same function binary_to_ASCIIconvert(); for both temperature and pot meter ADC conversion . is it correct ?

because when I tune the potentiometer I see the temperature ADC value also changes.

Code:
#ifndef __ADCDRV_H__
#define __ADCDRV_H__ 

extern char bcd10000;
extern char bcd1000;
extern char bcd100;
extern char bcdtens;
extern char bcdunits; 

//Define ADC pin
#define AN19 19
#define AN18 18

int readADC( int ANpin);   //parameter I/O expansion pin number this function does conversion
void initADC( int ANpin);	//initialize ADC operation ofr this I/O pin
int mask_translate(int IOpin);
void binary_to_ASCIIconvert( int n);
int averagevalue (int ANpin);

#endif

Code:
/*
** CONU2.h
** console I/O library for Explorer16 board
*/

// I/O definitions for the Explorer16
//#define CTS 	_RF12   // Cleart To Send, input, HW handshake
//#define RTS     _RF13   // Request To Send, output, HW handshake
#define BACKSPACE 0x8   // ASCII backspace character code            

// init the serial port (UART2, 115200@32MHz, 8, N, 1, CTS/RTS )
void initU2( void);

// send a character to the serial port
int putU2( int c);

// wait for a new character to arrive to the serial port
char getU2( void);

// send a null terminated string to the serial port
void putsU2( char *s);

// receive a null terminated string in a buffer of len char
char * getsn( char *s, int n);

// useful macros
#define clrscr() putsU2( "\x1b[2J") 
#define home()   putsU2( "\x1b[H") 
#define pcr()    putU2( '\r')

Code:
/*
** CONIO.C
** Basic CONSOLE I/O for Explorer16 demonstration board
*/


#include "xc.h"
#include "conU2.h"


#define FCY 7370000/2
//#define FCY 8000000/2
#define BAUDRATE 9600
#define BRGVAL ((FCY/BAUDRATE)/4)-1
#define U_ENABLE 0x8000		// enable the UART
#define U_TX	 0x0400		// enable transmission

// init the serial port (UART2, 1200, 8, N, 1 )
void initU2( void)
{ 
	U1BRG = BRGVAL; // BAUD Rate Setting for 9600
	U1MODE 	= U_ENABLE;
	U1STA 	= U_TX;
	U1MODEbits.BRGH = 1; // high Speed mode
} // initCon

// send a character to the UART2 serial port
int putU2( int c)
{

	while ( U1STAbits.UTXBF);   // wait while Tx buffer full
	U1TXREG = c;
	return c;
} // putU2


// wait for a new character to arrive to the UART2 serial port -don't use during interrupts
char getU2( void)
{
  
	while ( !U1STAbits.URXDA);	// wait for a new character to arrive
//
	return U1RXREG;		// read the character from the receive buffer


}// getU2


// send a null terminated string to the UART2 serial port
void putsU2( char *s)
{
	while( *s)			// loop until *s == '\0' the  end of the string
		putU2( *s++);	// send the character and point to the next one
    putU2( '\r');       // terminate with a cr / line feed
} // putsU2


char *getsn( char *s, int len)
{
    char *p = s;            // copy the buffer pointer 
    do{
        *s = getU2();       // wait for a new character
        putU2( *s);         // echo character
        
        if (( *s==BACKSPACE)&&( s>p))
        {
            putU2( ' ');     // overwrite the last character
            putU2( BACKSPACE);
            len++;
            s--;            // back the pointer
            continue;
        }
        if ( *s=='\n')      // line feed, ignore it
            continue;
        if ( *s=='\r')      // end of line, end loop
            break;          
        s++;                // increment buffer pointer
        len--;
    } while ( len>1 );      // until buffer full
 
    *s = '\0';              // null terminate the string 
    
    return p;               // return buffer pointer
} // getsn

Code:
#include "C:\Program Files (x86)\Microchip\xc16\v1.36\support\generic\h\xc.h"
#include "adc.h"
#define FCY 7370000/2
#include "C:\Program Files (x86)\Microchip\xc16\v1.36\support\generic\h\libpic30.h"
char bcd10000 =0;
char bcd1000 =0;
char bcd100 =0 ;
char bcdtens =0 ;
char bcdunits =0;
int average =0;


int readADC( int ANpin)
{
	
    AD1CHS0bits.CH0SA  = ANpin;               // select analog input channel based upon I/o epxansion pin
     ANSELGbits.ANSG6 = 1;    
     ANSELGbits.ANSG7 = 1;
    //_AD1IF = 0;
    AD1CON1bits.SAMP = 0;       // start sampling, automatic conversion will follow
    while (!AD1CON1bits.DONE);   // wait to complete the conversion
    return ADC1BUF0;            // read the conversion result
} // readADC

void initADC( int ANpin) 
{  //recheck bit settings for 12 bits
    AD1CON1 = 0;            // POR: 10-bit @4ch mode, ADC disabled, manual sample
    AD1CON2 = 0;            // POR: AVdd/Avss for Vref, do not scan, IRQ every sample
    AD1CON3 = 0;            // POR: Use system clock, TAD = 1Tcyc, SAMC = 0TAD
    AD1CON4 = 0; 
    AD1CHS123 = 0;          // not used in 12bit mode, as only 1 S/H available
    
    AD1CON1bits.FORM = 0;   // integer data format (unsigned)
    AD1CON1bits.ASAM = 1;   // continuous automatic sampling enabled

    AD1CON3bits.ADCS = 8;   // 9 Tcy = 1TAD (so TAD = 9*25ns = 225ns = 4.44MHz)
    AD1CON3bits.SAMC = 8;   // set auto sample time as 8TAD = 1.8us


    AD1CON1bits.AD12B = 1;  // 12-bit conversion, 14TAD convert time

    AD1CON1bits.ADON = 1;   // enable converter
    __delay_ms(100);
    AD1CON1bits.SAMP = 1;
    
    /*AD1CON1 = 0x00E0;   // auto convert after end of sampling
  	 AD1CON1bits.AD12B =1;			//set to 12 bits 
    AD1CSSL = 0;        // no scanning required 
    AD1CSSH = 0;        // no scanning required 
    AD1CON3 = 0x1F02;   // system clock,max sample time = 31Tad, Tad = 2 x Tcy = 125ns >75ns
    AD1CON2 = 0;        // use MUXA, AVss and AVdd are used as Vref+/-
    AD1CON1bits.ADON = 1; // turn on the ADC*/
    
} //initADC


int mask_translate(int ANpin) {
	//recheck pin setting for Microstick
	int tempmask =0xfffe;   //default to pin 2 AN0
	if (ANpin==0) tempmask= 0xfffe;
	if (ANpin==1) tempmask= 0xfffd;
	if (ANpin==4) tempmask= 0xffef;
	if (ANpin==5) tempmask= 0xff8f;
	if (ANpin==9) tempmask= 0xfdff;
	if (ANpin==10) tempmask= 0xfbff;
	if (ANpin==11) tempmask= 0xf7ff;
	if (ANpin==12) tempmask= 0xefff;
	return tempmask;
	
}
void binary_to_ASCIIconvert( int n) {
bcd10000 =0x00;
bcd1000=0x00;
bcd100 =0x00;
bcdtens =0x00;
bcdunits =0x00;
while (n>=10000) {
n = n-10000;
bcd10000 =bcd10000+1;
}
while (n>=1000) {
n = n-1000;
bcd1000 =bcd1000+1;
}
while (n>=100) {
n = n-100;
bcd100 =bcd100+1;
}
while (n>=10) {
n = n-10;
bcdtens =bcdtens+1;
}

 bcdunits =n;
bcd10000 =bcd10000+0x30;
bcd1000 =bcd1000+0x30;
bcd100 =bcd100+0x30;
bcdtens =bcdtens+0x30;
bcdunits =bcdunits+0x30;
}
//performs running average
int averagevalue (int ANpin) {
	int pin = ANpin;
	average =0;
	average = readADC(pin);
	average = average +readADC(pin);
	average = average +readADC(pin);
	average = average +readADC(pin);
	average = average/4;
	return average;
}

/*int Hex_to_Binay(char hex[17],char bin[65]){
    for(int i=0; hex[i]!='\0'; i++)
    {
        switch(hex[i])
        {
            case '0':
                strcat(bin, "0000");
                break;
            case '1':
                strcat(bin, "0001");
                break;
            case '2':
                strcat(bin, "0010");
                break;
            case '3':
                strcat(bin, "0011");
                break;
            case '4':
                strcat(bin, "0100");
                break;
            case '5':
                strcat(bin, "0101");
                break;
            case '6':
                strcat(bin, "0110");
                break;
            case '7':
                strcat(bin, "0111");
                break;
            case '8':
                strcat(bin, "1000");
                break;
            case '9':
                strcat(bin, "1001");
                break;
            case 'a':
            case 'A':
                strcat(bin, "1010");
                break;
            case 'b':
            case 'B':
                strcat(bin, "1011");
                break;
            case 'c':
            case 'C':
                strcat(bin, "1100");
                break;
            case 'd':
            case 'D':
                strcat(bin, "1101");
                break;
            case 'e':
            case 'E':
                strcat(bin, "1110");
                break;
            case 'f':
            case 'F':
                strcat(bin, "1111");
                break;
            default:
                printf("Invalid hexadecimal input.");
        }
    }

    return bin;
}
		*/

Code:
/**********************************************************************
 * © 2010 Microchip Technology Inc.
 *
 * FileName:        main_led.c
 * Dependencies:    p24HJ64GP502.h
 * Processor:       PIC24H
 * Compiler:        MPLAB® C30 v2.01 or higher
 **~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 *
 * ADDITIONAL NOTES:  
 *
 * Simple demo program showing a flashing LED 
 *modified by THK for chapter2 execerises 1/18/10
 *modified by THK for chapter 6 timer execerises with interrupts
 *modified by THK for chapter7 UART excerises
 *********************************************************************/
#include "C:\Program Files (x86)\Microchip\xc16\v1.36\support\generic\h\xc.h"	/* generic header for PIC24H family */
#include "CONU2.h"                              //UART header
#include "adc.h"                                //ADC header  
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FCY 7370000/2
#include <libpic30.h>
#include <p33EV256GM106.h>                           //delay header
_FOSCSEL(FNOSC_FRC); // set oscillator mode for FRC ~ 8 Mhz
_FOSC(FCKSM_CSDCMD & OSCIOFNC_ON & POSCMD_NONE); // use OSCIO pin for RA3
_FWDT(FWDTEN_OFF); // turn off watchdog
_FICD(ICS_PGD2);

#define led LATBbits.LATB5
//***************************************************/
// Define Constants Variables
//***************************************************/

#define BUF_SIZE 32

//***************************************************

static char rxchar = '0'; //received character
char s[BUF_SIZE];
unsigned char got_rx = 0; //rx char flag
char count[] = {'0','0','0','0','0','\0'};
int PotVal = 0;
int PotADC = 0;
int TempVal = 0;
int TempADC = 0;
/*unsigned int ADCVoltage = 0; 
unsigned int DecUnits = 0;
unsigned int DecTens = 0;
unsigned int Dec100 = 0;
unsigned int Dec1000 = 0;
unsigned int Dec10000 = 0;
unsigned int DecTot = 0;*/

        //RX U1 interrupt ---no used in data logger
        /*void __attribute__((interrupt, no_auto_psv)) _U1RXInterrupt(void)
        {
	
                rxchar =  (char) (U1RXREG & 0x00ff);
                got_rx =1;
                // Clear the UART RX interrupt flag bit
                IFS0bits.U1RXIF = 0;
      			
        }*/


        /********************************* 
            main entry point
         *********************************/
int main(void){/* 	Initialize  */
    initU2();
    initADC(AN19);      //AN19 for Potentiometer input 
    rxchar = 0;
    got_rx = 0;

    //set all pins that share analog and make them digital
    ANSELAbits.ANSA0 = 0;
    ANSELCbits.ANSC0 = 0;
    ANSELGbits.ANSG8 = 0;
    TRISGbits.TRISG8 = 0;
    LATGbits.LATG8 = 1;
    ANSELGbits.ANSG6 = 1;
    
    __builtin_write_OSCCONL(OSCCON & 0xbf); //clear bit 6 -unlock PPS
    //programming input perpherial pin selects
    RPINR18bits.U1RXR = 16; // make pin RA0  U1RX I/O

    // programming output perpherial pin selects
    RPOR5bits.RP48R = 1; //make RC0 U1TX  

    __builtin_write_OSCCONL(OSCCON | 0x40); //set bit 6 - lock PPS
  
    // interrupt priorities
    _U1RXIP = 4;
    _IPL = 0;


    // Hyperterminal Startup Inro Screen
    clrscr(); //clear hyper terminal screen
    home();
    putsU2("The MicroStick UART2 Experiment");
    putU2(0x0a); //carriage return /line feed
    putU2(0x0d);
    putsU2("Type a character and watch the return");
    putU2(0x0a); //carriage return /line feed
    putU2(0x0d);


    /*  endless loop*/
    while (1) {
        
        //rxchar = getU2(); 
        PotVal = readADC(AN19);     //Read potentiometer value
        TempVal = readADC(AN18);
        //PotVal = PotVal >> 2;
        binary_to_ASCIIconvert(PotVal);
        count[0]= bcd10000; //store ASCII result in array
		count[1] =bcd1000;
		count[2] =bcd100;
		count[3] =bcdtens;
		count[4]= bcdunits;
        /*putU2(count[0]);
        putU2(count[1]);
        putU2(count[2]);
        putU2(count[3]);
        putU2(count[4]);*/
        //printf("%c%c%c%c%c", count[0],count[1],count[2],count[3],count[4]);
        printf("%s", count);
        putU2(0x0a);
        putU2(0x0d);
        __delay_ms(1000);
        
        binary_to_ASCIIconvert(TempVal);
        count[5]= bcd10000; //store ASCII result in array
		count[6] =bcd1000;
		count[7] =bcd100;
		count[8] =bcdtens;
		count[9]= bcdunits;
        putU2(count[5]);
        putU2(count[6]);
        putU2(count[7]);
        putU2(count[8]);
        putU2(count[9]);
        putU2(0x0a);
        putU2(0x0d);
        
        //ASCII to decimal converter
       /* DecUnits = count[4] * 1;
        DecTens = count[3] * 16;
        Dec100 = count[2] * 256;
        Dec1000 = count[1] * 4096;
        Dec10000 = count[0] * 65536;
        DecTot = DecUnits + DecTens + Dec100 + Dec1000 + Dec10000;
        ADCVoltage = DecTot * 0.00122;
        putU2(ADCVoltage);
        //putU2(0x0a);
        putU2(0x0d);*/
        __delay_ms(1000);
        Nop();
    }

}
 

Hi,
Finally i used the following code to scale my value 0 to 4096 to 0volt to 5 volt which is 0 to 4998

Code:
        PotADC = PotVal * 1.22;
        printf("%d", PotADC);
        putU2(0x0a);
        putU2(0x0d);

where potval is the scaling value 0 to 4096

But the minimum value it goes to is 20 in terms of voltage (scale of 0 to 4998)

Is it because of sampling ?
 

Hi Susan,

I am doing PWM control and as mentioned earlier its for brushed DC motor control and I am using full bridge.

As you know the control logic for the brushed DC motor , I would like to know how I can disable only one one module like PWM 1 (dsPIC33EV have 3 PWM - PWM 1, PWM 2 , PWM 3)

There is a register PTEN where setting it will disable all the 3 module.

But I need to disable only one ?

How do I do it ?
 

Hi,

What do you mean with "disable"
* setting the output LOW
* setting the output HIGH
* setting the output HIGH IMPEDANCE
* setting the output to KEEP CURRENT STATE
* or anything else?

Klaus
 

Hi KlausST,

Disable means setting the output of PWM1H or PWM1L or both to low.

I can do by making the duty cycle zero.

But would like to know if there is any register like "PTEN: PWMx Module Enable bit " to disable onlt those PWM1 signal
 

The dsPIC33EV256GM106 has a single Fast PWM module and the PTEN bit you refer to turns the whole module on or off.
The module has 3 PWM generators within it that can be individually controlled - you need to look in the data sheet for register names that end in "x" (e.g.IOCONx) which tells you that the register/bits will reference one of the 3 PWM generators individually (as opposed to the whole module).
If you want to disable PWM1H and PWM1L, then look at the PENH and PENL bits of the appropriate IOCONx register (e.g. IOCON1bits.PENH for the PWM1H signal) - when this bit is set to '0' then the pin acts as a normal GPIO and you can set it to how you like using the appropriate LAT register.
I suggest that you also read the "High Speed PWM" FRM section for that MCU, in particular Section 14.12 (and 14.12.6).
Susan
 

The dsPIC33EV256GM106 has a single Fast PWM module and the PTEN bit you refer to turns the whole module on or off.
The module has 3 PWM generators within it that can be individually controlled - you need to look in the data sheet for register names that end in "x" (e.g.IOCONx) which tells you that the register/bits will reference one of the 3 PWM generators individually (as opposed to the whole module).
If you want to disable PWM1H and PWM1L, then look at the PENH and PENL bits of the appropriate IOCONx register (e.g. IOCON1bits.PENH for the PWM1H signal) - when this bit is set to '0' then the pin acts as a normal GPIO and you can set it to how you like using the appropriate LAT register.
I suggest that you also read the "High Speed PWM" FRM section for that MCU, in particular Section 14.12 (and 14.12.6).
Susan

I already looked at that section and implemented the code but still I dont see the PWM1H or PWM1L output goes low. Still the signal is ON on both PWMxH and PWMxL. For my application its not a big deal as I can left this pin floating but I wonder why I can't implement it in software.

Also reference to the section 14.12 (and 14.12.6), It says "halted by the Debugger". Is it during debug mode, where I use break point to check each line of the code ? If that is the case I am not after that , I would like to disable the PWMxH and PWMxL during run time.

I have attached the section of the code that I used to implement PEM1H and PWM1L disable


Below code implemented under main.C
Code:
        TRISBbits.TRISB12 = 0;
        TRISBbits.TRISB13 = 0;
        TRISBbits.TRISB14 = 0;
        TRISBbits.TRISB15 = 0;
        
        LATBbits.LATB12 = 0;
        LATBbits.LATB13 = 0;
        LATBbits.LATB14 = 0;
        LATBbits.LATB15 = 0;

Below code implemented under PWM.C

Code:
/* Set Primary Time Base, Edge-Aligned Mode and Independent Duty Cycles */
PWMCON1 = 0x0000;

/* Set Primary Time Base, Edge-Aligned Mode and Independent Duty Cycles */
PWMCON2 = 0x0000
 

Hi Susan,



I have attached the code below



Code:
/*
** CONU2.h
** console I/O library for Explorer16 board
*/

// I/O definitions for the Explorer16
//#define CTS _RF12 // Cleart To Send, input, HW handshake
//#define RTS _RF13 // Request To Send, output, HW handshake
#define BACKSPACE 0x8 // ASCII backspace character code

// init the serial port (UART2, 115200@32MHz, 8, N, 1, CTS/RTS )
void initU2( void);

// send a character to the serial port
int putU2( int c);

// wait for a new character to arrive to the serial port
char getU2( void);

// send a null terminated string to the serial port
void putsU2( char *s);

// receive a null terminated string in a buffer of len char
char * getsn( char *s, int n);

// useful macros
#define clrscr() putsU2( "\x1b[2J") 
#define home() putsU2( "\x1b[H") 
#define pcr() putU2( '\r')




Code:
/**********************************************************************
* © 2010 Microchip Technology Inc.
*
* FileName: main_led.c
* Dependencies: p24HJ64GP502.h
* Processor: PIC24H
* Compiler: MPLAB® C30 v2.01 or higher
**~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*
* ADDITIONAL NOTES: 
*
* Simple demo program showing a flashing LED 
*modified by THK for chapter2 execerises 1/18/10
*modified by THK for chapter 6 timer execerises with interrupts
*modified by THK for chapter7 UART excerises
* 
* 
* Pins used on dsPIC33EV256GM106
* Potentiometer - AN19/RG6
* Temperature - AN18/RG7
* Sensor - AN3/RB1
* UART_RX - RA0
* UART_TX - RC0
* Digital Output for Potentiometer - AN17/RG8
* PWM1H2 - RB12
* PWM1L2 - RB13
* PWM1H1 - RB14
* PWM1L1 - RB15
* 
* 
*********************************************************************/
#include "C:\Program Files (x86)\Microchip\xc16\v1.36\support\generic\h\xc.h" /* generic header for PIC24H family */
#include "CONU2.h" //UART header
#include "adc.h" //ADC header 
#include "PWM.h" //PWM Header
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define FCY 7370000/2
#include <libpic30.h> //delay header
_FOSCSEL(FNOSC_FRC); // set oscillator mode for FRC ~ 8 Mhz
_FOSC(FCKSM_CSDCMD & OSCIOFNC_ON & POSCMD_NONE); // use OSCIO pin for RA3
_FWDT(FWDTEN_OFF); // turn off watchdog
_FICD(ICS_PGD2);

#define led LATBbits.LATB5
//***************************************************/
// Define Constants Variables
//***************************************************/

#define BUF_SIZE 32

//***************************************************

static char rxchar = '0'; //received character
char s[BUF_SIZE];
unsigned char got_rx = 0; //rx char flag
char Pot[] = {'0','0','0','0','0','\0'};
char Temp[] = {'0','0','0','0','0','\0'};
int ADCValue[3] = {0,0,0};
int PotVal = 0;
double PotADC = 0;
int PotValtoPWM = 0;
int TempVal = 0;
int SensorVal = 0;
double TempADC = 0;
double Temperature = 0;
double SensorADC = 0;
int SensorAngle = 0 ;
int SensorAvgVal = 0 ;
char Motor_Direction = '0';

/********************************* 
main entry point
*********************************/
int main(void){/* Initialize */
initU2();
initADC(); //AN19 for Potentiometer input 
//initPWM1(); //Initialise PWM 1
//initPWM2(); //Initialise PWM 2
//initPWM();
rxchar = 0;
got_rx = 0;

//set all pins that share analog and make them digital
//ANSELA = 0;
//ANSELB = 0;

//Set UART1
ANSELAbits.ANSA0 = 0; //Set UART RA0 to digital
ANSELCbits.ANSC0 = 0; //Set UART RC0 to digital
RPINR18bits.U1RXR = 16; // make pin RA0 U1RX I/O
RPOR5bits.RP48R = 1; //make RC0 U1TX 

//Set GPIO for Forward, Reverse and Stop condition (High side )
//ANSELBbits.ANSB0 = 0; //Digital o/p PRI32 
//ANSELBbits.ANSB1 = 0; //Digital o/p PRI33 

// interrupt priorities
_U1RXIP = 4;
_IPL = 0;


// Hyperterminal Startup Inro Screen
clrscr(); //clear hyper terminal screen
home();
putsU2("The MicroStick UART2 Experiment");
putU2(0x0a); //carriage return /line feed
putU2(0x0d);
putsU2("Type a character and watch the return");
putU2(0x0a); //carriage return /line feed
putU2(0x0d);


/* endless loop*/
while (1) {

//rxchar = getU2();
//putU2(rxchar);



/*ADCValue[0] = ADC1BUF0; //Read AN19 Potentiometer Value
ADCValue[1] = ADC1BUF1; //Read AN18 Temperature Value
ADCValue[2] = ADC1BUF2; //Read third Pot Value - Future use*/

PotVal = readPotADC(); //Read onboard potentiometer value
TempVal = readTempADC(); //Read onboard Temp value
SensorVal = readSensorADC(); //Read external potentiometer value
SensorAvgVal = averagevalue(SensorVal);
//PotVal = PotVal >> 2;
PotADC = (PotVal * 4.8875) / 1000; //10-bit to voltage
PotValtoPWM = PotADC * 200 ;
printf("Potentiometer Value = %.2f", PotADC);
putU2(0x0a);
putU2(0x0d);
__delay_ms(1000);

//Onboard temperature measurement (MCP9701A)
TempADC = (TempVal * 4.8875)/1000; //10-bit to voltage
Temperature = (TempADC - 0.4)/0.0195; //to calculate the temperature
printf("Onboard Temperature Value = %.2f", Temperature);
putU2(0x0a);
putU2(0x0d);

/*
//External Component Temperature Measurement (LMT87-Q1))
TempADC = (TempVal * 4.8875)/1000; //10-bit to voltage
Temperature = (TempADC - 2.637)/0.0136; //to calculate the temperature
printf("Onboard Temperature Value = %.2f", Temperature);
putU2(0x0a);
putU2(0x0d); */

__delay_ms(1000);
SensorADC = (SensorAvgVal * 4.8875) / 1000;
SensorAngle = SensorADC * 72;
printf("Sensor Value = %d", SensorAngle);
putU2(0x0a);
putU2(0x0d);
__delay_ms(1000);
Nop();

initPWM2(PotValtoPWM); //Vary PWM duty using external Pot
initPWM1(PotValtoPWM); //Vary PWM duty using external Pot

/*if (PotADC >= 3){
printf("Greater");
putU2(0x0a);
putU2(0x0d);
//initPWM2();
}

else if(PotADC <= 2){ 
printf("Lesser");
putU2(0x0a);
putU2(0x0d);
//denitPWM();
}

else { 
printf("Equal");
putU2(0x0a);
putU2(0x0d);
//denitPWM();
}*/
/*

switch(Motor_Direction){

case 'F':
printf("Motor Direction if Forward");
continue;
case 'R':
printf("Motor Direction Reverse");
continue;
case 'B':
printf("Motor Direction Break");
continue;
default:
printf("Motor Direction invalid");
break;;

}
//printf("Motor Direction = %d", Motor_Direction);

}*/
}
}



Code:
#include "C:\Program Files (x86)\Microchip\xc16\v1.36\support\generic\h\xc.h"
#include "adc.h"
#define FCY 7370000/2
#include "C:\Program Files (x86)\Microchip\xc16\v1.36\support\generic\h\libpic30.h"
char bcd10000 =0;
char bcd1000 =0;
char bcd100 =0 ;
char bcdtens =0 ;
char bcdunits =0;
int average =0;

int readPotADC(void){
AD1CHS0bits.CH0SA = 19; // Onboard Potentiometer input for Channel 0 A - AN19/RG6
AD1CHS0bits.CH0NA = 0;
AD1CON1bits.SAMP = 1; // start sampling, automatic conversion will follow
while (!AD1CON1bits.DONE); // wait to complete the conversion
return ADC1BUF0;
}


int readTempADC(void){
AD1CHS0bits.CH0SB = 18; // Onboard/Offboard Temperature input for Channel 0 B - AN18/RG7
AD1CHS0bits.CH0NB = 0;
AD1CON1bits.SAMP = 1; // start sampling, automatic conversion will follow
while (!AD1CON1bits.DONE); // wait to complete the conversion
return ADC1BUF2;
}

int readSensorADC(void){

AD1CHS123bits.CH123SB0 = 1; // Offboard Sensor input for Channel 0 A - AN03/RB1
AD1CHS123bits.CH123NB = 0;
AD1CON1bits.SAMP = 1; // start sampling, automatic conversion will follow
while (!AD1CON1bits.DONE); // wait to complete the conversion
return ADC1BUF3;
}

void initADC(void) 
{ 

/*//recheck bit settings for 12 bits
AD1CON1 = 0; // POR: 10-bit @4ch mode, ADC disabled, manual sample
AD1CON2 = 0; // POR: AVdd/Avss for Vref, do not scan, IRQ every sample
AD1CON3 = 0; // POR: Use system clock, TAD = 1Tcyc, SAMC = 0TAD
AD1CON4 = 0; 
AD1CHS123 = 0; // not used in 12bit mode, as only 1 S/H available

AD1CON1bits.FORM = 1; // Signed integer data format (unsigned)
AD1CON1bits.ASAM = 1; // continuous automatic sampling enabled

AD1CON3bits.ADCS = 8; // 9 Tcy = 1TAD (so TAD = 9*25ns = 225ns = 4.44MHz)
AD1CON3bits.SAMC = 8; // set auto sample time as 8TAD = 1.8us


AD1CON1bits.AD12B = 1; // 12-bit conversion, 14TAD convert time

AD1CON1bits.ADON = 1; // enable converter
__delay_ms(100);
AD1CON1bits.SAMP = 1;

AD1CON1 = 0x00E0; // auto convert after end of sampling
AD1CON1bits.AD12B =1; //set to 12 bits 
AD1CSSL = 0; // no scanning required 
AD1CSSH = 0; // no scanning required 
AD1CON3 = 0x1F02; // system clock,max sample time = 31Tad, Tad = 2 x Tcy = 125ns >75ns
AD1CON2 = 0; // use MUXA, AVss and AVdd are used as Vref+/-
AD1CON1bits.ADON = 1; // turn on the ADC*/

/* Set port configuration */ 
ANSELAbits.ANSA0 = 0; //Set as digital for UART
ANSELCbits.ANSC0 = 0; //Set as digital for UART
ANSELGbits.ANSG8 = 0; //Set as digital for Pot 
TRISGbits.TRISG8 = 0; //Output
LATGbits.LATG8 = 1; //High
ANSELGbits.ANSG6 = 1; //AN19 Potentiometer pin
ANSELGbits.ANSG7 = 1; //AN18 Temperature pin 
ANSELBbits.ANSB1 = 1; //AN3 Sensor pin



/* Initialize ADC module */
AD1CON1 = 0x00E4; // Enable sequential sampling, auto-sample and auto-conversion
AD1CON2 = 0x010D; // Sample 2 channels, with alternate sampling enabled
AD1CON3 = 0x0F0F; // Sample for 15*Tad before triggering conversion
AD1CON4 = 0x0000;
AD1CSSH = 0x0000;
AD1CSSL = 0x0000;

/* Enable ADC module */
AD1CON1bits.ADON = 1;
__delay_ms(1);
} //initADC

void binary_to_ASCIIconvert( int n) {
bcd10000 =0x00;
bcd1000=0x00;
bcd100 =0x00;
bcdtens =0x00;
bcdunits =0x00;
while (n>=10000) {
n = n-10000;
bcd10000 =bcd10000+1;
}
while (n>=1000) {
n = n-1000;
bcd1000 =bcd1000+1;
}
while (n>=100) {
n = n-100;
bcd100 =bcd100+1;
}
while (n>=10) {
n = n-10;
bcdtens =bcdtens+1;
}

bcdunits =n;
bcd10000 =bcd10000+0x30;
bcd1000 =bcd1000+0x30;
bcd100 =bcd100+0x30;
bcdtens =bcdtens+0x30;
bcdunits =bcdunits+0x30;
}

int averagevalue (int ANpin) {

average =0;
average = readSensorADC();
average = average +readSensorADC();
average = average +readSensorADC();
average = average +readSensorADC();
average = average/4;
return average;


}





Code:
#ifndef __ADCDRV_H__
#define __ADCDRV_H__

extern char bcd10000;
extern char bcd1000;
extern char bcd100;
extern char bcdtens;
extern char bcdunits;

//Define ADC pin
#define AN19 19
#define AN18 18

//int readADC( int ANpin); //parameter I/O expansion pin number this function does conversion
int readPotADC(void);
int readTempADC(void);
int readSensorADC(void);
void initADC(void); //initialize ADC operation ofr this I/O pin
int mask_translate(int IOpin);
void binary_to_ASCIIconvert( int n);
int averagevalue (int ANpin);

#endif







Code:
/*
** CONIO.C
** Basic CONSOLE I/O for Explorer16 demonstration board
*/


#include "xc.h"
#include "conU2.h"


#define FCY 7370000/2
//#define FCY 8000000/2
#define BAUDRATE 9600
#define BRGVAL ((FCY/BAUDRATE)/4)-1
#define U_ENABLE 0x8000 // enable the UART
#define U_TX 0x0400 // enable transmission

// init the serial port (UART2, 1200, 8, N, 1 )
void initU2( void)
{ 
U1BRG = BRGVAL; // BAUD Rate Setting for 9600
U1MODE = U_ENABLE;
U1STA = U_TX;
U1MODEbits.BRGH = 1; // high Speed mode
} // initCon

// send a character to the UART2 serial port
int putU2( int c)
{

while ( U1STAbits.UTXBF); // wait while Tx buffer full
U1TXREG = c;
return c;
} // putU2


// wait for a new character to arrive to the UART2 serial port -don't use during interrupts
char getU2( void)
{

while ( !U1STAbits.URXDA); // wait for a new character to arrive
//
return U1RXREG; // read the character from the receive buffer


}// getU2


// send a null terminated string to the UART2 serial port
void putsU2( char *s)
{
while( *s) // loop until *s == '\0' the end of the string
putU2( *s++); // send the character and point to the next one
putU2( '\r'); // terminate with a cr / line feed
} // putsU2


char *getsn( char *s, int len)
{
char *p = s; // copy the buffer pointer 
do{
*s = getU2(); // wait for a new character
putU2( *s); // echo character

if (( *s==BACKSPACE)&&( s>p))
{
putU2( ' '); // overwrite the last character
putU2( BACKSPACE);
len++;
s--; // back the pointer
continue;
}
if ( *s=='\n') // line feed, ignore it
continue;
if ( *s=='\r') // end of line, end loop
break; 
s++; // increment buffer pointer
len--;
} while ( len>1 ); // until buffer full

*s = '\0'; // null terminate the string 

return p; // return buffer pointer
} // getsn





Code:
void initPWM(void);
void initPWM1(int duty);
void initPWM2(int duty);
void denitPWM(void);
int averagevalue (int ANpin);



Code:
/*
* File: PWM.c
* Author: Vikash.Kumar
*
* Created on 15 May 2019, 15:47
*/


#include "C:\Program Files (x86)\Microchip\xc16\v1.36\support\generic\h\xc.h"
#include "PWM.h"
#define FCY 7370000/2 //FCY = Fosc / 2
#include "C:\Program Files (x86)\Microchip\xc16\v1.36\support\generic\h\libpic30.h"


//Complementary PWM Mode ? Independent Duty Cycle and Phase, Fixed Primary Period, Edge-Aligned

void denitPWM(void){
PTCON = 0x0000;
PTCON2 = 0x0000;
PTPER = 0x0000;
SEVTCMP = 0x0000;
MDC = 0x0000;
CHOP = 0x0000;
PWMKEY = 0x0000;
}

void initPWM(void){



}

void initPWM1(int duty) {

/* Set PWM Period on Primary Time Base */
PTPER = 1000; // PTPER = Fosc / Fpwm * PWM Input clock prescaler

/* Set Phase Shift */
PHASE1 = 0;

/* Set Duty Cycles */
PDC1 = duty;

/* Set Dead Time Values */
DTR1 = 25;
ALTDTR1 = 25;

/* Set PWM Mode to Complementary */
//IOCON1 = 0x0000;
IOCON1bits.OVRDAT0 = 1;
IOCON1bits.OVRDAT1 = 1;
IOCON1bits.OVRENH = 1;
IOCON1bits.OVRENL = 1;
IOCON1bits.PENH = 0;
IOCON1bits.PENL = 0;
LATBbits.LATB14 = 0;
LATBbits.LATB15 = 0;
TRISBbits.TRISB14 = 1;
TRISBbits.TRISB15 = 1;
FCLCON1bits.FLTMOD0 = 1;
FCLCON1bits.FLTMOD1 = 1;

/* Set Primary Time Base, Edge-Aligned Mode and Independent Duty Cycles */
PWMCON1 = 0x0000;

/* Configure Faults */
FCLCON1 = 0x0003;

/* 1:1 Prescaler */
PTCON2 = 0x0000;

/* Enable PWM Module */
PTCON = 0x8000;
}

void initPWM2(int duty) {

/* Set PWM Period on Primary Time Base */
PTPER = 1000; // PTPER = Fosc / Fpwm * PWM Input clock prescaler

/* Set Phase Shift */
PHASE2 = 100;

/* Set Duty Cycles */
PDC2 = duty;

/* Set Dead Time Values */
DTR2 = 25;
ALTDTR2 = 25;

/* Set PWM Mode to Complementary */
//IOCON2 = 0x0000;
IOCON2bits.OVRDAT0 = 1;
IOCON2bits.OVRDAT1 = 1;
IOCON2bits.OVRENH = 1;
IOCON2bits.OVRENL = 1;
IOCON2bits.PENH = 0;
IOCON2bits.PENL = 0;
LATBbits.LATB13 = 0;
LATBbits.LATB12 = 0;
TRISBbits.TRISB13 = 1;
TRISBbits.TRISB12 = 1;
FCLCON2bits.FLTMOD0 = 1;
FCLCON2bits.FLTMOD1 = 1;

/* Set Primary Time Base, Edge-Aligned Mode and Independent Duty Cycles */
PWMCON2 = 0x0000;

/* Configure Faults */
FCLCON2 = 0x0003;

/* 1:1 Prescaler */
PTCON2 = 0x0000;

/* Enable PWM Module */
PTCON = 0x8000;
}
 

In post #17, you say that you set the TRISB bits (12, 13, 14 and 15) to '0' (actually I can't see that in the code you post in #18) but the code in the last code block in post #18, you have them set to '1'. When you set the TRIS register to '1', you make the corresponding pin an Input (I use the memory aid of '1nput' and '0utput' - those are the number s 1 and 0 at the start of each word). When a pin is an input it will float - it may go high and it may go low or anywhere in between, depending on if it is being driven by something else or picking up parasitic currents from somewhere.
Also why are you completely reinitialising the Fast PWM modules each time you want to just change the duty cycle - initialise once and update the duty cycle when it needs to change.
I would be very cautious about mixing the full path to an include file with the system-defined path to the same file - especially if the fully defined path includes the compiler version number. It is all too easy to get a mix of header files that way with unpredictable results.
The include file for delay functions is <delay.h> not <libpic30.h>. In fact I would be very cautious about using the libpic30 as I suspect that this is targeted for the dsPIC30 family of devices and not necessarily the dsPIC33EV family you are now using. (I may be wrong here but in all the time I've used the dsPIC33 devices, I've never used that library.)
Finally, I don't understand what you are actually trying to do here. It seems to me that you are initialising the PWM Generator 1 and Generator 2 components of the Fast PWM module and then turning off the outputs of those generators!
Looking at your code, it is a mixture of references to a PIC24HJ and a dsPIC33EV; there is a lot of commented out code that can obscure the actual operation of the app; and I suspect code snippets from all over the place. It may be time to get rid of most of that code and just concentrate on getting the Fast PWM module to work the way you want it to with (if necessary) some constant duty cycle values. Once that is working then add back in the ADC and UART functions. (I assume the rest is working correctly.)
Susan
 

In post #17, you say that you set the TRISB bits (12, 13, 14 and 15) to '0' (actually I can't see that in the code you post in #18) but the code in the last code block in post #18, you have them set to '1'. When you set the TRIS register to '1', you make the corresponding pin an Input (I use the memory aid of '1nput' and '0utput' - those are the number s 1 and 0 at the start of each word). When a pin is an input it will float - it may go high and it may go low or anywhere in between, depending on if it is being driven by something else or picking up parasitic currents from somewhere.

I initially set TRISB bits (12, 13, 14 and 15) to '0' and it didnt work so I removed it completely. Later when I got your response about looking at the section 14.12 then again I want to try it. as you mentioned 0 is output and 1 is input. TRIS is used to set output. LAT is to set high or low. I set LAT as 0 which is low. So I didnt bother about setting TRIS as input or output as any how the pin is low.

Also why are you completely reinitialising the Fast PWM modules each time you want to just change the duty cycle - initialise once and update the duty cycle when it needs to change.

If you see my code I started with the following initialisation

Code:
void initPWM(void){
    
}

I have just started learning software and that's the reason I am not sure which one to initialise and which one to put under while loop. I will update my code to reflect your suggestions about initialising.

I would be very cautious about mixing the full path to an include file with the system-defined path to the same file - especially if the fully defined path includes the compiler version number. It is all too easy to get a mix of header files that way with unpredictable results.

Initially I started with "xc.h" and it throwed an error while compiling saying it cant find the path. hence I added the complete path.

The include file for delay functions is <delay.h> not <libpic30.h>. In fact I would be very cautious about using the libpic30 as I suspect that this is targeted for the dsPIC30 family of devices and not necessarily the dsPIC33EV family you are now using. (I may be wrong here but in all the time I've used the dsPIC33 devices, I've never used that library.)

I got the header file explanation from this file. I will replace it to <delay.h> and try my code.
https://ww1.microchip.com/downloads/en//softwarelibrary/fixed point math library/50001456j.pdf

Finally, I don't understand what you are actually trying to do here. It seems to me that you are initialising the PWM Generator 1 and Generator 2 components of the Fast PWM module and then turning off the outputs of those generators!

All I am trying to do here is to disable any one signal of the complementary PWM . wither high or low. But yes I am trying to turn off all outputs because just to see if I can do it. Sorry I am totally vexed of trying this again and again.

Looking at your code, it is a mixture of references to a PIC24HJ and a dsPIC33EV; there is a lot of commented out code that can obscure the actual operation of the app; and I suspect code snippets from all over the place. It may be time to get rid of most of that code and just concentrate on getting the Fast PWM module to work the way you want it to with (if necessary) some constant duty cycle values. Once that is working then add back in the ADC and UART functions. (I assume the rest is working correctly.)

Initially I started with learning PIC24HJ and I find dspic33 is bit difficult and advanced in terms of learning ADC and PWM. So I used PIC24F as a base and developing from it.

Yes my code is not clean but I am trying to make individual component work first (UART, ADC, PWM) when all works ok I will tidy up.

Now I have 3 ADC's working, UART working, PWM working and when I vary the potentiometer I can see my PWM duty cycle varies.

Its brushed DC motor two half bridge control using PWM.

Now when I see my serial port I get ADC values

The MicroStick UART2 Experiment
Type a character and watch the return
Potentiometer Value = 0.00
Onboard Temperature Value = -20.51
Sensor Value = 0
Potentiometer Value = 0.35
Onboard Temperature Value = 21.85
Sensor Value = 4
Potentiometer Value = 0.35
Onboard Temperature Value = 21.85
Sensor Value = 4
Potentiometer Value = 0.35
Onboard Temperature Value = 21.85
Sensor Value = 4

the following first three line is always like the below.

"Potentiometer Value = 0.00
Onboard Temperature Value = -20.51
Sensor Value = 0"

when do I get -20.5 when my actual,onbaord temp is 21.85 ?

am I doing anything wrong with initialising ADC ?
 

Status
Not open for further replies.

Similar threads

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top