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.

Stepper motor control with PIC16F84A

Status
Not open for further replies.
try this:

aaaa|dddd
a = address of motor
dddd = signal to motor

Code:
0001|0001 // motor 1 at 1
delay 4
0010|0001 // motor 2 at 1
delay 1
0001|0010 // motor 1 at 2
delay 1
0010|0010 // motor 2 at 2
delay 2
0010|0100 // motor 2 at 3
delay 2
0010|1000 // motor 2 at 4
0001|0100// motor 1 at 3

and go on...

velocity of motor 1 = 1/5
velocity of motor 2 = 1/2

do this loop forever...
 
Here is some code to control N number of motors using one timer interrupt. It only works at relatively low speeds of maybe up to 4000 steps per second. Let me begin with the basics first and maybe later we can refine it to get better performance.

Setup the PIC timer to generate periodic interrupts. The frequency can be between 4000Hz to 20,000Hz depending on the speed of your PIC. I'd choose a 20Mhz PIC16 or, even better, a 40Mhz PIC18 chip and generate periodic interrupts at 2-16 times the desired maximum step rate.

Assign a general purpose file register to hold the status of 8 motors, one bit per motor. If the corresponding bit is "1", the motor is running, "0" if it is stopped. Let's call this register MOTOR_STAT.

Each motor will be assigned a minimum of 3 file registers. One to hold the speed control (SPEED), 2nd a prescale counter (PRE_COUNT), 3rd a postscale counter (POST_COUNT).

Most of the interesting stuff is found in the interrupt serve routine and is coded as follows (MACROS would be quite useful here!):

Code:
         ORG   4

INT_SERVE:
         SAVE_REG
;
         CLEAR_INT_FLAG
;-----------------------------------------------------------
         BTFSS   MOTOR_STAT,0
         GOTO    DO_PULSE_OFF1
;
         MOVF    SPEED1,W
         ADDWF   PRE_COUNT1,F
;
         BTFSC   STATUS,C
         DECFSZ  POST_COUNT1,F
         GOTO    DO_PULSE_OFF1
DO_PULSE_ON1:
         MOVLW   4             ; CAN BE 2-16
         MOVWF   POST_COUNT1
;
         GEN_PULSE_HIGH 1
;
         GOTO    SKIP1
DO_PULSE_OFF1:
         GEN_PULSE_LOW 1
SKIP1:
;-----------------------------------------------------------
         BTFSS   MOTOR_STAT,1
         GOTO    DO_PULSE_OFF2
;
         MOVF    SPEED2,W
         ADDWF   PRE_COUNT2,F
;
         BTFSC   STATUS,C
         DECFSZ  POST_COUNT2,F
         GOTO    DO_PULSE_OFF2
DO_PULSE_ON2:
         MOVLW   4             ; CAN BE 2-16
         MOVWF   POST_COUNT2
;
         GEN_PULSE_HIGH 2
;
         GOTO    SKIP2
DO_PULSE_OFF2:
         GEN_PULSE_LOW 2
SKIP2:
;-----------------------------------------------------------
INT_SERVE_END:
;
         CLEAR_INT_FLAG
;
         LOAD_REG
;
         RETFIE
 
Hi all,

I am sorry to write again but I need some more help.

The idea on this project is to have several running steppers but they will be chosen by the user. So now maybe 1 stepper is running, but the user can activate another 20 minutes or 20 seconds from now. And both steppers running, run at different speeds.

Motion's idea seams great. As far as I could understand we'll do a interrupt every 1ms (for example), and as the steppers are running at very slow (6 RPM or 12 RPM), we will be able to control several motors giving the idea they are working at the same time.

I was using a routine to run the steppers that gives a step every 125 ms or 250 ms, so I must generate these delays independently one from the other. So how can I generate these different delays ? If I am counting till 250 (250 ms delay), and in the middle of this I must start counting to 125, how can I do this at the same time.

Finally, I would like some help choosing a stepper to run at speeds of 6,12,24, ... RPM. Is there any cheap motor capable of give some torque at these speeds ? I need a stepper that doesn't stop even if try to stop it with your fingers.

Thanks to all,

Pedro
 
I was using a routine to run the steppers that gives a step every 125 ms or 250 ms, so I must generate these delays independently one from the other. So how can I generate these different delays ? If I am counting till 250 (250 ms delay), and in the middle of this I must start counting to 125, how can I do this at the same time.

Your problem is much easier than I had thought. You use the following code to service a periodic 1ms interrupt.

Code:
    SAVE_CONTEXT
    CLEAR_INTERRUPT_FLAG
;------------------------------------
    btfsc   motor1_enable
    decfsz  delay1,f
    goto    skip1
;
    movlw   delay1_val
    movwf   delay1
;
    call    step_motor1
skip1:
;------------------------------------
    btfsc   motor2_enable
    decfsz  delay2,f
    goto    skip2
;
    movlw   delay2_val
    movwf   delay2
;
    call    step_motor2
skip2:
;------------------------------------
    RESTORE_CONTEXT
    retfie

Use motor1_enable & motor2_enable flags to run/stop the motors. You may also add as many motors as needed. A separate 20 minute timer can be used to govern their operation.

The step delay is controlled by the values delay1_val & delay2_val. They can be constants or values stored in memory to adjust the speed as required. A value of 125 produces a 125ms delay between steps.

Interrupts here aren't mandatory. The event is slow enough you can poll a timer flag and enter this routine when it is set.
 
Finally, I would like some help choosing a stepper to run at speeds of 6,12,24, ... RPM. Is there any cheap motor capable of give some torque at these speeds ? I need a stepper that doesn't stop even if try to stop it with your fingers.

Try looking for those motors used for slot machine reels. They're cheap and designed to run at around these speeds. They should be reliable :wink: .
 
Hi,

I am in a trouble to connect a 2x16 LCD. First I tried the schematics of the following webpage:

http://www.rentron.com/PicBasic-LCD.htm

But, as you can see, the drawing can fool you because the pins are on reverse order. At least fooled me, and I only discovered that something was very wrong because the LCD + PIC were consuming 450 mA !!! Outch !!

Now with all the wiring correct, I can't send any data to the LCD. The LCD powers on correctly but it displays nothing.

I am using the following configuration (LCD connected to PIC16F84A):

- R/W - Ground
- E - DB3
- RS - DB2
- Data - DB4..DB7

Is there a very simple code to test the LCD ?

The PIC is ok. The problem must be the LCD or the code. But I have strange feelings about this LCD, and I think I should buy another one.

Thank you very much to all,

Pedro Cardoso
 
Hi to all,

I tried with a new LCD and it worked. Now I am trying to do a chronometer with a pic. To do this I connected the LCD to the pic and I wrote some code to count seconds, minutes, hours and days. But I can't get a precise chronometer, because LCD takes a bit to display.

So can you give me an idea how to do this with a very small error ?

Regards,

Pedro
 
netbug said:
Hi to all,

I tried with a new LCD and it worked. Now I am trying to do a chronometer with a pic. To do this I connected the LCD to the pic and I wrote some code to count seconds, minutes, hours and days. But I can't get a precise chronometer, because LCD takes a bit to display.

So can you give me an idea how to do this with a very small error ?

Use a timer to generate a regular interrupt, the interrupt routine increments a counter and generates seconds, minutes, hours (and whatever you want) from it. If you have the interrupt routine set a flag everytime the seconds change you can just check the flag in your main program, and only update the display when the flag is set (reseting it once you've done so).

I posted some sample code I've been playing with a few weeks ago, based on the 16F628 - which has an improved extra timer from the obselete 16F84.
 
Hi,


I am sorry to put so dummy question, but suppose I am generating an interrupt every 250 ms. If after every interrupt I display the result on an LCD, and it takes t ms to be displayed, the second interrupt will happen 250ms after the first or 250 + t ms after the first ?


Thanks,

Pedro
 
netbug said:
I am sorry to put so dummy question, but suppose I am generating an interrupt every 250 ms. If after every interrupt I display the result on an LCD, and it takes t ms to be displayed, the second interrupt will happen 250ms after the first or 250 + t ms after the first ?

You don't usually display the result after every interrupt, particularly if they are fairly short - as they are likely to be in practice, I don't think you can get a timer interrupt as long as 250mS?.

It's usual to do the display routine as part of the main program, and keep the interrupt routine as short as possible.

One of the first things the interrupt routine should do is re-enable the timer interrupt, so it starts counting again - this way the interrupts are exactly the same time apart, if you wait until you exit the interrupt routine the time taken can vary, depending on which counters need updating. Obviously, it's VERY important that the interrupt routine finishes before the next timer interrupt comes along - this shouldn't be a problem if you are just incrementing counters.
 
Hi,

Well I want this timer to count seconds and display them on LCD. But because the LCD takes some time to display data, the counting is afected by this dead time LCD introduces in my code.

So I would like to know how to display every second and keep this clock acurate.

Regards,

Pedro
 
netbug said:
Hi,

Well I want this timer to count seconds and display them on LCD. But because the LCD takes some time to display data, the counting is afected by this dead time LCD introduces in my code.

So I would like to know how to display every second and keep this clock acurate.

Regards,

Pedro

Use interrupts for your clock signal, using one of the PIC timers - or you could use a seperate clock chip (battery backed) to do the actual clock functions, using the PIC to read it and display the data. There's an example in my I2C tutorials using a Philips clock chip, Dallas make a popular one as well.
 
Hi again,

My project is working better every day thanks to all fo you :D .

Once again I have 3 more questions:

How can I connect , for example, 4 switches to an input line of a PIC, and treat them separatly ? This is, I would like each switch to be recognised although being connect to same pic input.

I also would like to measure the voltage of the batteries and display this on lcd, just like mobile phones do. So I would like to plot a figure on LCD with the battery level.

Can I use a shift register to communicate between devices, in order to free pic data lines ? Can you tell me how to code this ?

Best regards,

Pedro Cardoso
 
netbug said:
Hi again,

My project is working better every day thanks to all fo you :D .

Once again I have 3 more questions:

How can I connect , for example, 4 switches to an input line of a PIC, and treat them separatly ? This is, I would like each switch to be recognised although being connect to same pic input.

You can use the switches to select different value resistors, and use either an A2D (or a capacitor charging method) to determine which resistor is selected. It's a common technique, often used in commercial equipment.

I also would like to measure the voltage of the batteries and display this on lcd, just like mobile phones do. So I would like to plot a figure on LCD with the battery level.

You really need a PIC with an A2D, which one are you using?.

Can I use a shift register to communicate between devices, in order to free pic data lines ? Can you tell me how to code this ?

You can use shift registers to convert both ways, giving multiple inputs or outputs off two pins - they are commonly known as 'port expanders'.

But a lot depends what you are trying to do, and how you are trying to do it - there may be simpler ways? - one obvious one is to use a larger PIC.
 
Thanks for that. I'll try to use the switches connected to different resistors. I think it's a very good idea. It's like connecting a potenciometer to the PIC.

I have one PIC with ADC but I can't remember exactly which one. I know it's from 16 series.

Can you sugest me a pic simulator ? I am trying PIC simulator IDE. It has some devices, but it is too slow. Also if you try to use the basic compiler is very limited in instructions. So, is there another pic simulator with commom devices (lcd, bcd, ...) better than this one ?

Best regards,

Pedro Cardoso
 
netbug said:
Thanks for that. I'll try to use the switches connected to different resistors. I think it's a very good idea. It's like connecting a potenciometer to the PIC.

I have one PIC with ADC but I can't remember exactly which one. I know it's from 16 series.

The 16F819 is an 18 pin one, the 16F876 is 28 pin, and the 16F877 is 40 pin - amongst various others!.

Can you sugest me a pic simulator ? I am trying PIC simulator IDE. It has some devices, but it is too slow. Also if you try to use the basic compiler is very limited in instructions. So, is there another pic simulator with commom devices (lcd, bcd, ...) better than this one ?

I never use one, but MPLAB includes a simulator.
 
Hi,

I need some more help.

I am using 4 separate pic to control a stepper motor each one. Each pic should interface with a fifth pic that is connected to an LCD. The 4 pics that control the motors, receive orders from the user like: start/stop and the speed that the user wants to that specific motor. Every time one of these pics want to communicate with the user, tey should send a message to the 5th pic to be displayed on LCD.

I would like some help doing this interface between the 4 pics and the pic that controls the LCD.

Best regards,

Pedro Cardoso
 
Hi just onde more thing, is it possible to force a pic do a reset by software (using pic basic)?

Regards,

Pedro Cardoso
 
There is no software command on a pic to make it reset itself but...

You can force a hardware reset by using an output pin to pull MCLR low
check https://www.electro-tech-online.com...if-anyone-knows-what-this-component-is.12145/

Or, if you write your code well, and initialize all variables and perephials before you use them (make no assumptions about POR state of things) you could just jump to the reset vector (0x000) and pretend you've reset. i've done this several times and there were no problems. You shouldn't even mind the stack as it 'rolls over' anyway.
 
Hi all,

Thank you for that help Exo.

I would like your opinion about my project, and how do you think it should be done.

I need to control 4 steppers, that accept commands from the user on an independent way. Each stepper starts when user wants to, as well as speed of rotation. The time of each stepper must appear on a lcd. There is only one lcd, so the user should select which stepper he wants to see displayed.

I am doing this with 5 pics's, 4 controlling each stepper, and the fifth controlling the LCD. This last pic is responsible for time counting for each stepper, so it must count time four the 4 steppers seperatly.

The problem with all of this is that the 4 pics must communicate with the fifth pic to tell it what to display, and I don't know how to do this.

Please just give some ideas about this, and if you feel that I am using the right approach to the problem or not. If not please suggest what would you do in this case.

Best regards,

Pedro Cardoso
 
Status
Not open for further replies.

Latest threads

New Articles From Microcontroller Tips

Back
Top