|
|
View previous topic :: View next topic |
Author |
Message |
cuopbienquin
Joined: 17 Aug 2007 Posts: 4
|
A problem with interrupt _external |
Posted: Wed Sep 19, 2007 7:08 am |
|
|
Hi everyone.These followed codes are control stepper motor program.
include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
#byte portb=0x06
#byte intcon=0x000B
#bit RB4=portb.4
#bit RB5=portb.5
#bit RB6=portb.6
#bit RB7=portb.7
#bit RBIF=intcon.0 //
#bit RBIE=intcon.3 //
void left()
{
portb=0b00000101;
delay_ms(50);
portb=0b00000110;
delay_ms(50);
portb=0b00001010;
delay_ms(50);
portb=0b00001001;
delay_ms(50);
}
void right()
{
portb=0b00000101;
delay_ms(50);
portb=0b00001001;
delay_ms(50);
portb=0b00001010;
delay_ms(50);
portb=0b00000110;
delay_ms(50);
}
void stop()
{
portb=0;
}
// Interrupt
#int_RB
void ngat_RB()
{
if((RBIF)&&(RBIE))
{
//Test sw1
{
if(RB4==0)
{
while ( RB5==1 && RB6 ==1)
{
left();
}
}
}
//Test sw2
{
if(RB5==0)
{
while( RB4==1 && RB6==1)
{
right();
}
}
}
//Test sw3
{
if(RB6==0)
{
while ( RB5==1 && RB4 ==1 )
{
stop();
}
}
}
}
RBIF=0; //
}
// Main program
main()
{
set_tris_b(0b11110000);
portb=0b00001111;
enable_interrupts(global);
enable_interrupts(int_RB);
ext_int_edge(H_to_L);
while(true)
{
}
}
When press sw1 ,motor turn left
sw2 ,.................right
sw3,..................stop
But when motor is mode 1(left),I press once other mode ,it also mode 1.I press twice ,motor is other mode?I dont know so why ?I hope your helping.Good luck _________________ Let shared to be shared. |
|
|
rnielsen
Joined: 23 Sep 2003 Posts: 852 Location: Utah
|
|
Posted: Wed Sep 19, 2007 8:49 am |
|
|
First of all, this is not the proper way to use an interrupt. Interrupts are meant to react, quickly, to an internal/external event, do some kind of action (relatively short) and then exit the interrupt. You have functions being called from inside the interrupt and at least 200ms worth of delays for each function being called.
Instead of using an interrupt, I would suggest you simply monitor separate input pins, from inside of main(), and call the apropriate functions from there. There are several posts on reading inputs, with switches, in the forums.
Ronald |
|
|
Ttelmah Guest
|
|
Posted: Wed Sep 19, 2007 9:21 am |
|
|
First, use the 'code' buttons when posting. It makes code easier to read....
Then, you do not need to test the interrupt flag, or the interrupt enable. The interrupt handler, will only be called if these are both set.
Then at the end of the routine, you do not need to clear the interrupt. This is already done for you by the compiler.
Now, as it stands, once the interrupt is triggered by a 'left', the code stays for 200mSec, in the 'left' handler. The buttons are only tested each time round the loop, and if RB5 goes low, while RB4 is also low, the code will drop out ofthe 'left' loop (since RB5 is no longer '1'), but not then execute the right loop (since RB4 is still 0). Only on a second press, retriggering the interrupt, will the motor go the other way...
The code, sits permanently inside the interrupt handler, handling the stepping, which makes using an interrupt, rather 'pointless'.
Realistically, the whole thing is slightly the wrong approach.
Have something like:
Code: |
include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
int1 motor_on=FALSE;
int1 direction;
int8 phases[4] = {0b00000101,0b00000110,0b00001010,0b00001001};
#define RIGHT (0)
#define LEFT (1)
#define BUTTON_LEFT (16)
#define BUTTON_RIGHT (32)
#define BUTTON_STOP (64)
#INT_RB
void b_changed(void) {
int8 temp;
temp=input_b() ^ 0xFF;
if (temp & BUTTON_STOP) motor_on=FALSE;
else {
//This way, 'stop' overrides other buttons
if (temp & BUTTON_RIGHT) {
direction=RIGHT;
motor_on=TRUE;
}
if (temp &BUTTON_LEFT) {
direction=LEFT;
motor_on=TRUE;
}
}
}
#INT_TIMER2
void tick(void) {
static int8 state=0;
if (motor_on) {
if (direction==LEFT) {
state=++state & 3;
}
else {
state=--state & 3;
}
portb=phases[state];
}
else portb=0;
}
// Main program
void main(void) {
int8 temp;
set_tris_b(0b11110000);
portb=0b00001111;
setup_timer_2(T2_DIV_BY_16,207,15);
//Gives approximately a 50mSec timer 'tick'
temp=input_b();
//you should read the port, and clear the interrupt, or a spurious
//trigger will occur when the interrupt is enabled.
clear_interrupts(int_RB);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RB);
enable_interrupts(INT_TIMER2)
//ext_int_edge(H_to_L);
//The _RB_ interrupt, occurs on both edges. The edge control function
//Only works with the external 'INT' interrupt.
while(true) {
//Now the code here will carry on executing. When a button
//is pushed, the control bits 'direction', and 'motor_on' get set
//or cleared. In the timer interrupt, according to the state of
//these, patterns are fed out to the motor, to drive it.
}
}
|
No guarantees, this is just 'freehand' typed in, so errors may well exist. However it shows how to continue code execution, while the motor is driven, and how to make the 'stop' have priority over the other buttons.
Best Wishes |
|
|
cuopbienquin
Joined: 17 Aug 2007 Posts: 4
|
|
Posted: Thu Sep 20, 2007 5:39 am |
|
|
Thank for comment.And I use ur codes to simulink stpeper motor circuit by Proteuss and it oprerate as I desire.But actually, I cant understand fully this code (sorry u ) .I wish u can find the error in my code and correct it .Good luck. _________________ Let shared to be shared. |
|
|
Ttelmah Guest
|
|
Posted: Thu Sep 20, 2007 4:03 pm |
|
|
The main error, is described in what I have already typed.
You are sticking inside the interrupt, handling the stepper.
I'll try to document what is happening in my code better.
Code: |
include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT
#use delay(clock=4000000)
#use fast_io(b)
int1 motor_on=FALSE;
int1 direction;
int8 phases[4] = {0b00000101,0b00000110,0b00001010,0b00001001};
//These are the four bit pattern wanted to drive the motor. To turn it
//left, we need to output these patterns in order, 'right to left'. To turn
//the motor right, we need to go through these the other way.
#define RIGHT (0)
#define LEFT (1)
#define BUTTON_LEFT (16)
#define BUTTON_RIGHT (32)
#define BUTTON_STOP (64)
#INT_RB
void b_changed(void) {
int8 temp;
temp=input_b() ^ 0xFF;
//Read the input port, and 'invert' all the bits. Bits are now '1', where
//a switch is pressed.
if (temp & BUTTON_STOP) motor_on=FALSE;
//If the 'stop' button is pressed, turn off the motor
else {
//This way, 'stop' overrides other buttons
if (temp & BUTTON_RIGHT) {
//If the 'right' button is pressed, turn on the motor, and set the
//direction to 'right'
direction=RIGHT;
motor_on=TRUE;
}
if (temp &BUTTON_LEFT) {
//if the left button is pressed, set the direction to left, and motor 'on'
direction=LEFT;
motor_on=TRUE;
}
}
}
//Now this handler does nothing, except as the buttons are pressed, sets
//the motor_on and direction bits to the required patterns.
#INT_TIMER2
void tick(void) {
//The actual movement is done here.
//This routine will be called about every 50mSec
//(actually 4000000/(4*16*208*15) times per second
//20.03* per second, or 49.92mSec
static int8 state=0;
//Because this variable is 'static', it retains it's value beween calls
if (motor_on) {
//Here only if motor is 'on
if (direction==LEFT) {
//Move _forward_ through the array for 'left'
state=++state & 3;
}
else {
//Otherwise backwards for right
state=--state & 3;
}
//Because of the '&3', the value of'state', can only be 0,1,2,3
//Hence it gives 0,1,2,3,0,1,2,3, on subsequent calls when 'left'
//is selected, and 3,2,1,0,3,2,1,0 when 'right' is selected
portb=phases[state];
//Output the required bit pattern
}
else portb=0;
//If motor is not on, turn off the output drive.
}
// Main program
void main(void) {
int8 temp;
set_tris_b(0b11110000);
portb=0b00001111;
setup_timer_2(T2_DIV_BY_16,207,15);
//Gives approximately a 50mSec timer 'tick'
temp=input_b();
//you should read the port, and clear the interrupt, or a spurious
//trigger will occur when the interrupt is enabled.
clear_interrupts(int_RB);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RB);
enable_interrupts(INT_TIMER2)
//ext_int_edge(H_to_L);
//The _RB_ interrupt, occurs on both edges. The edge control function
//Only works with the external 'INT' interrupt.
while(true) {
//Now the code here will carry on executing. When a button
//is pushed, the control bits 'direction', and 'motor_on' get set
//or cleared. In the timer interrupt, according to the state of
//these, patterns are fed out to the motor, to drive it.
//The key 'neat' thing is that you can do other jobs here
//and the motor will keep moving.
}
}
|
Best Wishes |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Sep 20, 2007 4:16 pm |
|
|
Don't forget to add the NOLVP fuse.
Quote: | #include <16F877A.h>
#fuses NOWDT,PUT,XT,NOPROTECT, NOLVP
#use delay(clock=4000000)
void main(void) {
set_tris_b(0b11110000);
portb=0b00001111;
|
|
|
|
cuopbienquin
Joined: 17 Aug 2007 Posts: 4
|
|
Posted: Thu Sep 20, 2007 9:49 pm |
|
|
@Ttlemah.Okay I see what you expalin in ur code.Genarally, I tend to expand urs to switch program using Timer2_interrupt. For example:
button 1: portb=0b0001111;
delay 50 ms
portb =0b1111111;
delay 100ms;
portb=0b0001101;
delay 200ms;
button 1: portb=0b0001111;
delay 50 ms
portb =0b1111111;
delay 100ms;
portb=0b0001101;
delay 200ms;
portb=0b0000111;
delay 50 ms
portb =0b1111001;
delay 100ms;
portb=0b1110000;
delay 200ms;
button3 : portb=0;
I think in ur code , a number of the phase left mode is equivalent one's right mode is 4.So what's the happiness if they are diffirent ??I hope u can correct ur code to more general.The best wish u?
@PCM programmer.Thank you for comment,MR PCM . I hope u canlead me the link of switch program in forum,cant u?.Good luck to u. _________________ Let shared to be shared. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|