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.

DC Motor Driver(ADC doesn't work)

Status
Not open for further replies.

Cantafford

Member
Hello,

I'm trying to make a DC motor driver that consists of a PIC18F2580, L93D h bridge, some buttons to choose a rotation direction for the motor, a rotary encoder and an LCD display to display the value that the ADC reads. Here's the schematic from proteus:

**broken link removed**

And here is the code:
Code:
/*
* File:   main.c
* Author: Paul
*
* Created on November 1, 2015, 11:24 AM
*/

#include <stdio.h>
#include <stdlib.h>
#include "header.h"
#include <plib/adc.h>
#include <plib/xlcd.h>
#include <plib/delays.h>


void Initialize_ADC(void); // Initialize the ADC
void Initialize_LCD(void); // Initialize the LCD
void DelayFor18TCY(void); //  Delay for 18 cycles
void DelayPORXLCD(void);  //  Delay for 15ms
void DelayXLCD(void);     //  Delay for 5ms
void DoTheConversion(void);

unsigned int ADCResult = 0;
float voltage;
unsigned char ResultString[20];

void main()
{
    OSCCON = 0x76; // set internal oscillator to 8Mhz
    TRISC = 0b11100111; // RC0-2: buttons, RC3,4-outputs to drive the H bridge
    LATCbits.LATC3 = 0; LATCbits.LATC4 = 0; // motor is stopped
    Initialize_ADC();
    Initialize_LCD();
    while(1)
    {
     if(PORTCbits.RC0 == 0 && PORTCbits.RC1 == 1 && PORTCbits.RC2 == 1) // clockwise
     {
         LATCbits.LATC3 = 1;
         LATCbits.LATC4 = 0;
         DoTheConversion();
     }


     if(PORTCbits.RC0 == 1 && PORTCbits.RC1 == 0 && PORTCbits.RC2 == 1) // clockwise
     {  LATCbits.LATC3 = 0;
        LATCbits.LATC4 = 1;
        DoTheConversion();
     }

     if(PORTCbits.RC2 == 0) // motor stops
     {  LATCbits.LATC3 = 1;
        LATCbits.LATC4 = 1;
        DoTheConversion();
     }
    }
}


void Initialize_ADC(void)
{
    OpenADC(ADC_FOSC_2 & ADC_RIGHT_JUST & ADC_2_TAD, ADC_CH0 & ADC_INT_ON &ADC_REF_VDD_VSS, ADC_1ANA);
}

void Initialize_LCD(void)
{
    OpenXLCD(FOUR_BIT&LINES_5X7);
    while(BusyXLCD());
    WriteCmdXLCD(0x06); // move cursor right and don't shift display
    WriteCmdXLCD(0x0C); // turn on the display without blinking cursor
    putrsXLCD("DC motor driver"); // Display
    SetDDRamAddr(0x40); // Shift cursor to beginning of second line
    for(int x = 0; x<=20; x++) __delay_ms(50); // 1 second delay
    for(int x = 0; x<=20; x++) __delay_ms(50); // 1 second delay
    for(int x = 0; x<=20; x++) __delay_ms(50); // 1 second delay
    WriteCmdXLCD(0x01); // Clear screen
}

void DelayFor18TCY(void)
{
    Delay10TCYx(20);
}

void DelayPORXLCD(void)
{
    Delay1KTCYx(30);
}

void DelayXLCD(void)
{
    Delay1KTCYx(10);
}

void DoTheConversion(void)
{
         while(BusyADC()); // Wait untill the conversion is done(wait here)
         ADCResult = ReadADC(); // Read the converted value
         voltage = (ADCResult*5.0)/10.24;
         putrsXLCD("Speed is: "); // Display
         sprintf(ResultString, "%.3g", voltage); // Convert ADCResult to a string
         putsXLCD(ResultString); // Display voltage on the screen
         putrsXLCD("  "); // Clear extra digits
         WriteCmdXLCD(0x02); // Home position on LCD
}

Here is the header.h:
Code:
/*
* File:   header.h
* Author: Paul
*
* Created on November 1, 2015, 11:23 AM
*/

// PIC18F2580 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1H
#pragma config OSC = IRCIO67    // Oscillator Selection bits (Internal oscillator block, port function on RA6 and RA7)
#pragma config FCMEN = OFF      // Fail-Safe Clock Monitor Enable bit (Fail-Safe Clock Monitor disabled)
#pragma config IESO = OFF       // Internal/External Oscillator Switchover bit (Oscillator Switchover mode disabled)

// CONFIG2L
#pragma config PWRT = OFF       // Power-up Timer Enable bit (PWRT disabled)
#pragma config BOREN = BOHW     // Brown-out Reset Enable bits (Brown-out Reset enabled in hardware only (SBOREN is disabled))
#pragma config BORV = 3         // Brown-out Reset Voltage bits (VBOR set to 2.1V)

// CONFIG2H
#pragma config WDT = ON         // Watchdog Timer Enable bit (WDT enabled)
#pragma config WDTPS = 32768    // Watchdog Timer Postscale Select bits (1:32768)

// CONFIG3H
#pragma config PBADEN = ON      // PORTB A/D Enable bit (PORTB<4:0> pins are configured as analog input channels on Reset)
#pragma config LPT1OSC = OFF    // Low-Power Timer 1 Oscillator Enable bit (Timer1 configured for higher power operation)
#pragma config MCLRE = OFF      // MCLR Pin Enable bit (RE3 input pin enabled; MCLR disabled)

// CONFIG4L
#pragma config STVREN = ON      // Stack Full/Underflow Reset Enable bit (Stack full/underflow will cause Reset)
#pragma config LVP = OFF        // Single-Supply ICSP Enable bit (Single-Supply ICSP disabled)
#pragma config BBSIZ = 1024     // Boot Block Size Select bit (1K words (2K bytes) boot block)
#pragma config XINST = OFF      // Extended Instruction Set Enable bit (Instruction set extension and Indexed Addressing mode disabled (Legacy mode))

// CONFIG5L
#pragma config CP0 = OFF        // Code Protection bit (Block 0 (000800-001FFFh) not code-protected)
#pragma config CP1 = OFF        // Code Protection bit (Block 1 (002000-003FFFh) not code-protected)
#pragma config CP2 = OFF        // Code Protection bit (Block 2 (004000-005FFFh) not code-protected)
#pragma config CP3 = OFF        // Code Protection bit (Block 3 (006000-007FFFh) not code-protected)

// CONFIG5H
#pragma config CPB = OFF        // Boot Block Code Protection bit (Boot block (000000-0007FFh) not code-protected)
#pragma config CPD = OFF        // Data EEPROM Code Protection bit (Data EEPROM not code-protected)

// CONFIG6L
#pragma config WRT0 = OFF       // Write Protection bit (Block 0 (000800-001FFFh) not write-protected)
#pragma config WRT1 = OFF       // Write Protection bit (Block 1 (002000-003FFFh) not write-protected)
#pragma config WRT2 = OFF       // Write Protection bit (Block 2 (004000-005FFFh) not write-protected)
#pragma config WRT3 = OFF       // Write Protection bit (Block 3 (006000-007FFFh) not write-protected)

// CONFIG6H
#pragma config WRTC = OFF       // Configuration Register Write Protection bit (Configuration registers (300000-3000FFh) not write-protected)
#pragma config WRTB = OFF       // Boot Block Write Protection bit (Boot block (000000-0007FFh) not write-protected)
#pragma config WRTD = OFF       // Data EEPROM Write Protection bit (Data EEPROM not write-protected)

// CONFIG7L
#pragma config EBTR0 = OFF      // Table Read Protection bit (Block 0 (000800-001FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR1 = OFF      // Table Read Protection bit (Block 1 (002000-003FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR2 = OFF      // Table Read Protection bit (Block 2 (004000-005FFFh) not protected from table reads executed in other blocks)
#pragma config EBTR3 = OFF      // Table Read Protection bit (Block 3 (006000-007FFFh) not protected from table reads executed in other blocks)

// CONFIG7H
#pragma config EBTRB = OFF      // Boot Block Table Read Protection bit (Boot block (000000-0007FFh) not protected from table reads executed in other blocks)

#define _XTAL_FREQ 8000000

As I'm sure it's obvious from the code the program is supposed to start, "DC Motor driver" will be displayed on the LCD then as I push a button to choose a rotational direction the converted value of the RPM should be displayed on the LCD. But a weird thing happens(as you can see from the photo of the schematic that I've provided). The value displayed on the LCD is too high and it's also not changing(not even when the motor is stopped and it should be 0). I'm guessing it's a code issue but can't figure it out. Please help me correct it. Thank you!
 
As I explained in your other post!!! That isn't how the encoder motor is connected!! There are two motor models with 3 wire outputs.... One is a servo control and the other is an encoding output!! The encoder has to be interfaced to a quadrature encoder... The servo motor model accepts a pulse width.. it doesn't produce one..
 
I'm no programmer, but it looks to me that port B is enabled for analog input, but a motor tacho is connected to A0. Is that right?
 
As I explained in your other post!!! That isn't how the encoder motor is connected!! There are two motor models with 3 wire outputs.... One is a servo control and the other is an encoding output!! The encoder has to be interfaced to a quadrature encoder... The servo motor model accepts a pulse width.. it doesn't produce one..
Hello. Can you please explain how am I supposed to connect it in my schematic. I don't quite understand how am I supposed to connect it. I'm no expert as I said. I'm going to do some research on encoders now.
 
Correct me if I'm wrong but doesn't a rotary encoder present a digital output rather than an analog one?
 
Correct me if I'm wrong but doesn't a rotary encoder present a digital output rather than an analog one?
Yes I suppose it's digital since it should give a value for speed. So in that case I just have to get it from it's output and display it on the LCD somehow. But I'm not sure if it's digital or continous.
 
There are encoders that do what you want but that encoder is a raw signal
To use quad encoding study the signal..
upload_2015-11-3_19-41-26.png


However!!! You only need a single pulse... So hook the Index pin or the Q1 pin up to the "INT0" pin and count the input for 1 second That way you can determine speed..


Get the interrupt to fire every 250mS and work out the pulses... say you count 1 pulse then the motor is at 4 hz on the index pin or divide the PPR into it if you use the Q1 pin..
 
Okay Ignore my last post!!!

Hook Q1 to RA4..
Set Timer0 to read from RA4..
T0CON = 0x10;​
Then clear TMR0...
TMR0 = 0;​
Then delay 250mS..
__delay_ms(50);
__delay_ms(50);
__delay_ms(50);
__delay_ms(50);
__delay_ms(50);​

Read TMR0.... tada!!! 24PPR from the model ( you can change this )
 
For just rpm you can also use the index, 1 pulse/rev, I have used this, unless you are going to very low RPM detection.
For direction you would use the A & B quadrature (90° apart pulses), the basic pulse count/rev can be used, or 2 rising edges for x2 or 2 rising and 2 falling edges for x4 the count to increase the resolution.
Max.
 
To the OP - what I was getting at was that the output of the encoder is digital, hence you don't need to use the ADC. Follow Ian's guidance above.

If you were using a potentiometer, then you would use the ADC. But not with an encoder.
 
Ok guys thank you all very much for the advices. I will try them when I get home tomorrow evening and then let you know. Thanks again!
 
One side note: I haven't tried modifying the code yet will try when I get home. But one quick question:
I want to implement this in hardware. Will this motor+encoder be good for my project? **broken link removed**

I'm asking this because I've never done a hardware project before. Thanks!
 
Appears to be a single pulse slot sensor for tachometer purposes, if so it is not an encoder but a Tach.
I see a +5v supply but no 5v common?
What is 'Send'?
Max.
 
Last edited:
Looks to me like 'send' would energise a LED and 'receive' would provide a signal from a photo-transistor, to sense the rotor slots. The tab on the motor body presumably would be ground for both functions. The 'receive' pulses would need to be passed to a frequency-to-voltage converter.
 
I am using a similar product, not Chinese, that uses the slot sensor pulses to input to CCP capture input and the period is measure by T1.
The ebay lister should be contacted for elaboration to the hook-up.
Just because they label it that way, does not mean it is an encoder, in the recognized sense.
Max.
 
Okay Ignore my last post!!!

Hook Q1 to RA4..
Set Timer0 to read from RA4..
T0CON = 0x10;​
Then clear TMR0...
TMR0 = 0;​
Then delay 250mS..
__delay_ms(50);
__delay_ms(50);
__delay_ms(50);
__delay_ms(50);
__delay_ms(50);​

Read TMR0.... tada!!! 24PPR from the model ( you can change this )

Hello again, thanks for the answer.
Here's what I added to the code:

Code:
         PSA = 0; // to set preescaler to Timer0 module
         T0CS = 1; // to select counter mode
         T0SE = 0; // to select rising edge as incrementing edge
         __delay_ms(50);
         __delay_ms(50);
         __delay_ms(50);
         __delay_ms(50);
         __delay_ms(50);
Now I suppose I have to read the TMRo to get the value but I don't know how to do that. Specifically what bit of the TMR0 I have to read and how do I do that. I just create a variable, store the value of the TMRo in it then convert it to a string so I can display it on the LCD? Is that the way?
Excuse my questions which may seem dumb to you but I'm no expert like you guys :). Thanks.
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top