Forum - MCS Electronics

 

FAQFAQ SearchSearch RegisterRegister Log inLog in

Interrupts, Help!

 
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    www.mcselec.com Forum Index -> BASCOM-AVR Archive
View previous topic :: View next topic  
Author Message
DDLP

Bascom Member



Joined: 08 Jun 2011
Posts: 7

PostPosted: Wed Jun 08, 2011 3:45 pm    Post subject: Interrupts, Help! Reply with quote

Hey there, I'm new to these forums and using BASCOM/AVR products and whatnot, so I would really appreciate some help! So this might be kind of a tricky problem but basically I'm using an ATmega324p chip, and I'm trying to run a stepper motor constantly, and use an interrupt triggered by a pushbutton to turn on a LED and then update an LCD display to show which LED is on. My problem is with the pushbutton and therefore the LED/LCD setup, basically I can't get a consistent trigger for whatever reason, it's not very responsive and seems to turn the LED on haphazardly. Here's my code so far, if someone wouldn't mind taking a look and perhaps giving me some ideas/suggestions. Thanks!

Code:

$regfile = "m324pdef.dat"

 Ddrc = &B1111_1100
 Ddrd = &B0111_1011

 Deflcdchar 0 , 238 , 255 , 255 , 255 , 238 , 238 , 238 , 224
 Deflcdchar 1 , 238 , 241 , 241 , 241 , 234 , 234 , 238 , 224

 Config Debounce = 20

'--------Declare-Variables-----------------------------------------------------'

Dim Count As Byte
Dim Count1 As Byte

'--------Declare-Constants-----------------------------------------------------'


'--------Declare-Aliases-------------------------------------------------------'


Switch2 Alias Portc.6
Switch3 Alias Portc.7

Fullstep Alias Portd.5
Resetmotor Alias Portd.4
Outputenable Alias Portd.3
Motordirection Alias Portd.6
Clockmotor Alias Portd.1
Motorphase Alias Portd.0

'--------Declare-Interrupts----------------------------------------------------'

 Enable Interrupts
 Config Int0 = Rising

'--------Declare-Subroutines---------------------------------------------------'

Declare Sub Pulseout1
Declare Sub Light1

'********************************MAIN*PROGRAM**********************************'
'******************************************************************************'

  Disable Int0

  Cursor Off
  Cls
  Lcd "L1:  L2:  L3: "
  Locate 1 , 4
  Lcd Chr(0)
  Locate 1 , 9
  Lcd Chr(0)
  Locate 1 , 14
  Lcd Chr(0)
  Lowerline
  Lcd "L4:  L5:  L6: "
  Locate 2 , 4
  Lcd Chr(0)
  Locate 2 , 9
  Lcd Chr(0)
  Locate 2 , 14
  Lcd Chr(0)


  Outputenable = 1                                          'Motor On
  Motorphase = 1                                            '2 phase
  Fullstep = 0                                              'fullstep mode
  Resetmotor = 1                                            'Run Normally
  Clockmotor = 0

  Enable Int0

Do

   Outputenable = 0

   Clockmotor = 0
   Waitus 200
   Clockmotor = 1
   Waitus 200

Loop

End


'******************************************************************************'
'******************************************************************************'

'--------Interrupt-Handlers----------------------------------------------------'

On Int0 Chooselight

Chooselight:

   Debounce Pind.7 , 1 , Light1 , Sub

   Return

'------------------------------------------------------------------------------'

'--------Subroutines-----------------------------------------------------------'

Sub Light1


   If Count = 0 Then
   Set Switch3
   Locate 1 , 4
   Lcd Chr(1)
   Count = 1

   Elseif Count = 1 Then
   Reset Switch3
   Locate 1 , 4
   Lcd Chr(0)
   Count = 0

   End If

End Sub
Back to top
View user's profile
DDLP

Bascom Member



Joined: 08 Jun 2011
Posts: 7

PostPosted: Wed Jun 08, 2011 5:44 pm    Post subject: Reply with quote

"Interrupt Flags can also be cleared by writing a logic one to the flag bit position(s) to be cleared." So a better question might be how do I write a logic one to the flag bit position, or what's the syntax really. Thanks.
Back to top
View user's profile
DDLP

Bascom Member



Joined: 08 Jun 2011
Posts: 7

PostPosted: Wed Jun 08, 2011 7:55 pm    Post subject: Reply with quote

So just in case any other newbs are having similar troubles... To solve this issue I changed the INT0 trigger to falling, and used a bitwait low so stop any bouncing after the button was pushed, and then cleared the external interrupt flag register to stop any bouncing that may have occurred when the interrupt was triggered....or I just got lucky, anyways here's the changed bit of code.

Code:
On Int0 Chooselight

Chooselight:

   Disable Int0

   Bitwait Pind.7 , Reset

   Gosub Light1

   Waitus 1000


   Eifr.intf0 = 1

   Enable Int0

   Return
   Return
 
Back to top
View user's profile
mattcro

Bascom Member



Joined: 03 Oct 2007
Posts: 327
Location: Scotland

uk.gif
PostPosted: Wed Jun 08, 2011 8:02 pm    Post subject: Reply with quote

To clear the interrupt flag (best to do it just before returning from the interrupt handler), just use something like:
Code:
Set EIFR.INTF0


It might be better to use a timer interrupt to clock the stepper motor. That way you can set up a constant step rate, and the main loop can handle the button and LCD updates. It's also bad practice to have delays and things like bitwait inside an interrupt handler. It doesn't matter so much for the program so far, but if you add other interrupts, serial comms etc you will have problems because the interrupt handler delays will stop anything else happening.

EDIT: just saw you update post. You don't need to disable and enable the interrupt inside the handler, because interrupts are automatically disabled when you enter an interrupt handler, and enabled when you exit.

_________________
If all else fails, read the manual. Even better: read the manual before something fails. If you can't find it in the manual, search the forum.
BascomAVR 2.0.8.5
Back to top
View user's profile
AdrianJ

Bascom Expert



Joined: 16 Jan 2006
Posts: 2483
Location: Queensland

australia.gif
PostPosted: Wed Jun 08, 2011 11:56 pm    Post subject: Reply with quote

There is already a Bascom solution for reading switches. Look up DEBOUNCE in the Bascom Help.

Mattcro is right, you should not use wait statements inside interrupt routines.

IMHO, you should not use an interrupt at all to read a mechanical switch. IRQs are for reading fast things, down in the order of microseconds, where the processor cannot easily access the line that fast. Mechanical switches pushed by humans are at most 5 times a second. There you can use a poll in the main loop, or even better use a timer ISR to poll the switch at a fixed rate. 100 times a second is plenty fast enough.

_________________
Adrian Jansen
Computer language is a framework for creativity
Back to top
View user's profile Visit poster's website
ivangel

Bascom Member



Joined: 20 Sep 2010
Posts: 41
Location: Poland

poland.gif
PostPosted: Thu Jun 09, 2011 11:25 am    Post subject: Reply with quote

You are right but the interrupt is one great advantage: it generates an interrupt, and interrupts the main program which is sometimes necessary ...
Back to top
View user's profile Visit poster's website
DDLP

Bascom Member



Joined: 08 Jun 2011
Posts: 7

PostPosted: Thu Jun 09, 2011 2:45 pm    Post subject: Reply with quote

Hey thanks for the suggestion guys. @mattcro I'll have to try that timer interrupt for the motor. I definitely only disabled and enabled the interrupt as a precaution but I gather bascom is unique in that you don't have to, so I'll get rid of that. I only used the bitwait so that if on pushing the button, it bounced into the interrupt, it would have to wait for the button to be released to switch on the led, but that's definitely "kludgy". I have read that the external interrupts are commonly used for pushbuttons, and in this case I used it because I actually need the motor to turn back and forth like an oscillating fan, so I don't think I could really poll the main loop for satisfied IF statements, I'll try the timer ISR though that sounds great. @ AdrianJ I have used the debounce in other programs(and I tried in this one if you look at the first bit of code), but I had no success with it in this program although I don't think I was clearing the interrupt flag when trying it. It was very finicky in any case, perhaps it's just an even worse idea within an interrupt.

Thanks again all,

DDLP

EDIT: I was just thinking I probably could use if statements if I used a simple counter to count the number of times the motor pulse has been sent, and then at a certain value switch directions...oh well, my goal was to learn about interrupts, and I guess I've achieved that at least haha.
Back to top
View user's profile
AdrianJ

Bascom Expert



Joined: 16 Jan 2006
Posts: 2483
Location: Queensland

australia.gif
PostPosted: Thu Jun 09, 2011 11:46 pm    Post subject: Reply with quote

You definitely should not use DEBOUNCE inside an interrupt. For a start, it looks for both edges of a switch closure, whereas the IRQ looks only for one edge ( usually ). So it will never work properly.

If you construct your main loop so it normally executes in a few msec, then polling a switch, or using DEBOUNCE, will work perfectly. That is not to say that you cant run much longer routines in a main loop. but you can usually organize it to run those only when some condition is met, so not on every main loop cycle.

Refreshing an LCD is typical. You cant read an LCD faster than about 2 per second, so why refresh it any faster ? So you can run a fast loop, and only refresh the LCD every nth loop, n being a counter set so that the refresh time is about 500 msec. Many other processes can be handled the same way.

_________________
Adrian Jansen
Computer language is a framework for creativity
Back to top
View user's profile Visit poster's website
DDLP

Bascom Member



Joined: 08 Jun 2011
Posts: 7

PostPosted: Tue Jun 14, 2011 4:32 pm    Post subject: Reply with quote

Hey, so just as a follow up to this thread, I did end up using TIMER0 to run the motor, as it runs it very smoothly, as opposed to running it from a main loop and subroutine which sends the pulses out much slower, resulting in choppy movement. I also opted to use a dip switch for the LED's, and given that I used the timer interrupt for the motor, it is seemingly necessary to use interrupts(both external and pc) to trigger the LED's, in any case it runs very smoothly using all interrupts. Here's the latest iteration of the code, but please note it's not a final pristine product. Also please note that the LCD is configured using the built-in LCD options.(Options->Compiler->LCD)

Code:


'-----------------------------------------------------------------------------------------
'name                     : motor.timer.test4.bas
'author                    : DDLP
'purpose                  : stepper motor + LEDs + LCD
'-----------------------------------------------------------------------------------------

$regfile = "m324pdef.dat"

 Ddrc = &B1111_1100
 Ddrd = &B0111_0011
 Config Porta.7 = Input

 Deflcdchar 0 , 238 , 255 , 255 , 255 , 238 , 238 , 238 , 224
 Deflcdchar 1 , 238 , 241 , 241 , 241 , 234 , 234 , 238 , 224

'--------Declare-Variables-----------------------------------------------------'

Dim Count As Byte
Dim Count1 As Word

'--------Declare-Constants-----------------------------------------------------'


'--------Declare-Aliases-------------------------------------------------------'

Switch1 Alias Portc.5
Switch2 Alias Portc.6
Switch3 Alias Portc.7
Switch4 Alias Portc.4

Fullstep Alias Portd.5
Resetmotor Alias Portd.4
Outputenable Alias Portc.2
Motordirection Alias Portd.6
Clockmotor Alias Portd.1
Motorphase Alias Portd.0

'--------Declare-Interrupts----------------------------------------------------'

 Enable Interrupts
 Enable Timer0
 Config Timer0 = Timer , Prescale = 1
 On Timer0 Pulseout1
 Enable Int0
 Enable Int1
 Enable Pcint2
 Enable Pcint0
 Config Int0 = Change
 Config Int1 = Change
 On Int0 Light2
 On Int1 Light1
 On Pcint2 Light3
 Pcmsk2 = &B00000010
 On Pcint0 Light4
 Pcmsk0 = &B10000000
'--------Declare-Subroutines---------------------------------------------------'

Declare Sub Pulseout1
Declare Sub Light1
Declare Sub Light2
Declare Sub Light3
Declare Sub Light4

'********************************MAIN*PROGRAM**********************************'
'******************************************************************************'

  Disable Interrupts

  Cursor Off
  Cls
  Lcd "L1:  L2:  L3: "
  Locate 1 , 4
  Lcd Chr(0)
  Locate 1 , 9
  Lcd Chr(0)
  Locate 1 , 14
  Lcd Chr(0)
  Lowerline
  Lcd "L4:  L5:  L6: "
  Locate 2 , 4
  Lcd Chr(0)
  Locate 2 , 9
  Lcd Chr(0)
  Locate 2 , 14
  Lcd Chr(0)

  Motorphase = 1                                            '2 phase
  Fullstep = 0                                              'fullstep mode
  Resetmotor = 1                                            'Run Normally
  Clockmotor = 0

  Enable Interrupts

Do




Loop




'******************************************************************************'
'******************************************************************************'

'--------Interrupt-Handlers----------------------------------------------------'



'--------Subroutines-----------------------------------------------------------'


Pulseout1:

   If Count1 <= 250 Then

   Outputenable = 0
   Motordirection = 0
   Clockmotor = 0
   Waitus 400
   Clockmotor = 1
   Waitus 400
   Count1 = Count1 + 1

   Elseif Count1 < 500 Then

   Outputenable = 0
   Motordirection = 1
   Clockmotor = 0
   Waitus 400
   Clockmotor = 1
   Waitus 400
   Count1 = Count1 + 1

   Elseif Count1 >= 500 Then

   Count1 = 0


   End If

Return


Light1:

   If Pind.7 = 1 Then

      Set Switch3
      Locate 1 , 4
      Lcd Chr(1)


   Elseif Pind.7 = 0 Then

      Reset Switch3
      Locate 1 , 4
      Lcd Chr(0)

   End If

Return


Light2:

   If Pinc.0 = 1 Then

      Set Switch2
      Locate 1 , 9
      Lcd Chr(1)

   Elseif Pinc.0 = 0 Then

      Reset Switch2
      Locate 1 , 9
      Lcd Chr(0)


   End If

Return


Light3:

   If Pinc.1 = 1 Then

      Set Switch1
      Locate 1 , 14
      Lcd Chr(1)

   Elseif Pinc.1 = 0 Then

      Reset Switch1
      Locate 1 , 14
      Lcd Chr(0)


   End If

Return


Light4:

   If Pina.7 = 1 Then

      Set Switch4
      Locate 2 , 4
      Lcd Chr(1)

   Elseif Pina.7 = 0 Then

      Reset Switch4
      Locate 2 , 4
      Lcd Chr(0)


   End If

Return

 


Cheers,

DDLP
Back to top
View user's profile
AdrianJ

Bascom Expert



Joined: 16 Jan 2006
Posts: 2483
Location: Queensland

australia.gif
PostPosted: Wed Jun 15, 2011 12:23 am    Post subject: Reply with quote

Good that your code works, and you are happy with it.
I would have done it more like this:
Code:

'-----------------------------------------------------------------------------------------
'name                     : motor.timer.test4.bas
'author                    : DDLP, modified by AJ
'purpose                  : stepper motor + LEDs + LCD
'-----------------------------------------------------------------------------------------

$regfile = "m324pdef.dat"

 Ddrc = &B1111_1100
 Ddrd = &B0111_0011
 Config Porta.7 = Input

 Deflcdchar 0 , 238 , 255 , 255 , 255 , 238 , 238 , 238 , 224
 Deflcdchar 1 , 238 , 241 , 241 , 241 , 234 , 234 , 238 , 224

'--------Declare-Variables-----------------------------------------------------'

Dim Count As Byte
Dim Count1 As Word

dim bIRQFlag as byte

'--------Declare-Constants-----------------------------------------------------'


'--------Declare-Aliases-------------------------------------------------------'

Switch1 Alias Portc.5
Switch2 Alias Portc.6
Switch3 Alias Portc.7
Switch4 Alias Portc.4

Fullstep Alias Portd.5
Resetmotor Alias Portd.4
Outputenable Alias Portc.2
Motordirection Alias Portd.6
Clockmotor Alias Portd.1
Motorphase Alias Portd.0

'--------Declare-Interrupts----------------------------------------------------'

' Enable Interrupts dont enable IRQs here !
'this may cause IRQs to be serviced while setting them up
 Enable Timer0
 Config Timer0 = Timer , Prescale = 1
 On Timer0 Pulseout1
 Enable Int0
 Enable Int1
 Enable Pcint2
 Enable Pcint0
 Config Int0 = Change
 Config Int1 = Change
 On Int0 Light2
 On Int1 Light1
 On Pcint2 Light3
 Pcmsk2 = &B00000010
 On Pcint0 Light4
 Pcmsk0 = &B10000000
'--------Declare-Subroutines---------------------------------------------------'
'you do not have to DECLARE subroutines when they are actually ISRs
'in fact doing so might cause the compiler to insert RET opcodes
'rather than RETI opcodes, which will cause serious problems.

Declare Sub Pulseout1
Declare Sub Light1
Declare Sub Light2
Declare Sub Light3
Declare Sub Light4

'********************************MAIN*PROGRAM**********************************'
'******************************************************************************'

'  Disable Interrupts not necessary if not enabled above

  Cursor Off
  Cls
  Lcd "L1:  L2:  L3: "
  Locate 1 , 4
  Lcd Chr(0)
  Locate 1 , 9
  Lcd Chr(0)
  Locate 1 , 14
  Lcd Chr(0)
  Lowerline
  Lcd "L4:  L5:  L6: "
  Locate 2 , 4
  Lcd Chr(0)
  Locate 2 , 9
  Lcd Chr(0)
  Locate 2 , 14
  Lcd Chr(0)

  Motorphase = 1                                            '2 phase
  Fullstep = 0                                              'fullstep mode
  Resetmotor = 1                                            'Run Normally
  Clockmotor = 0

  Enable Interrupts

Do

if bIRQFlag.0 = 1 then       'handle flag set by timer
reset bIRQFlag.0
   If Count1 <= 250 Then

   Outputenable = 0
   Motordirection = 0
   Clockmotor = 0
   Waitus 400
   Clockmotor = 1
   Waitus 400
   Count1 = Count1 + 1

   Elseif Count1 < 500 Then

   Outputenable = 0
   Motordirection = 1
   Clockmotor = 0
   Waitus 400
   Clockmotor = 1
   Waitus 400
   Count1 = Count1 + 1

   Elseif Count1 >= 500 Then

   Count1 = 0


   End If
end if

if bIRQFlag.1 = 1 then        'handle flags set by switches
 reset bIRQFlag.1
   If Pind.7 = 1 Then

      Set Switch3
      Locate 1 , 4
      Lcd Chr(1)


   Elseif Pind.7 = 0 Then

      Reset Switch3
      Locate 1 , 4
      Lcd Chr(0)

   End If
end if

if bIRQFlag.2 = 1 then
   reset bIRQFlag.2

   If Pinc.0 = 1 Then

      Set Switch2
      Locate 1 , 9
      Lcd Chr(1)

   Elseif Pinc.0 = 0 Then

      Reset Switch2
      Locate 1 , 9
      Lcd Chr(0)


   End If
end if

if bIRQFlag.3 = 1 then
reset bIRQFlag.3
   If Pinc.1 = 1 Then

      Set Switch1
      Locate 1 , 14
      Lcd Chr(1)

   Elseif Pinc.1 = 0 Then

      Reset Switch1
      Locate 1 , 14
      Lcd Chr(0)


   End If
end if

if bIRQFlag.4 = 1 then
reset bIRQFlag.4
   If Pina.7 = 1 Then

      Set Switch4
      Locate 2 , 4
      Lcd Chr(1)

   Elseif Pina.7 = 0 Then

      Reset Switch4
      Locate 2 , 4
      Lcd Chr(0)


   End If
end if

Loop




'******************************************************************************'
'******************************************************************************'

'--------Interrupt-Handlers----------------------------------------------------'



'--------Subroutines-----------------------------------------------------------'


Pulseout1:

set bIRQFlag.0

Return


Light1:

set bIRQFlag.1


Return


Light2:

set bIRQFlag.2



Return


Light3:
set bIRQFlag.3


Return


Light4:
set bIRQFlag.4

Return
 

_________________
Adrian Jansen
Computer language is a framework for creativity
Back to top
View user's profile Visit poster's website
DDLP

Bascom Member



Joined: 08 Jun 2011
Posts: 7

PostPosted: Wed Jun 15, 2011 1:36 am    Post subject: Reply with quote

Great, thanks for taking the time to put that together, I'll have to try it out tomorrow.
Back to top
View user's profile
DDLP

Bascom Member



Joined: 08 Jun 2011
Posts: 7

PostPosted: Thu Jun 16, 2011 2:27 pm    Post subject: Reply with quote

Hey so I tried out you're program Adrian, but it doesn't seem to work at all. For whatever reason the motor wouldn't spin, and the lights wouldn't trigger. I believe it might be because if the timer interrupt is executing so quickly, or even before the pulseout is finished and then just piling up, then the main loop is never going to run, and it would essentially just keep pointlessly setting birqflag.0 without doing anything else.
Back to top
View user's profile
AdrianJ

Bascom Expert



Joined: 16 Jan 2006
Posts: 2483
Location: Queensland

australia.gif
PostPosted: Thu Jun 16, 2011 11:23 pm    Post subject: Reply with quote

Hmm. Yes I suppose its possible. Timer0 is an 8 bit timer, so max count 256. And since you use prescale=1, that is 256 processor clock cycles. It might take nearly that to enter and exit the timer IRQ. You dont give the processor clock frequency, so I suppose its the default 1 MHz. You should really tell the compiler what frequency you run the processor at with the $crystal directive near the start of your code, else the value is taken from the compiler defaults, which may not be what you actually use in the processor.

Do you need the IRQ that often ? If you have those waitus 400 statements in your IRQ, then in fact the timer IRQ is not being executed every 256 usec either, its just that you dont notice it when you run that way. Typical steppers I have seen use pulses around every 1 msec or so at max, which is roughly what you have when you put the waits in the timer IRQ. You would get the same effect by setting a timer0 prescale of say 8 or even 64.

If you want finer control over the motor pulse timing, consider using Timer1, which has a 16 bit range. Then you reload the timer value inside the IRQ with a value to set the pulse width to whatever you need, in the range 0 - 65535. In reality the bottom limit is about 200, not 0. And remember the timer counts from the value you set up to 65535, then the IRQ happens as it rolls over to 0 again.

Of course, you could simply revert to your code, which works. The problem with that is that it is not really working how you think it is, so changing anything in it is likely to result in unexpected behaviour, and tracing exactly what is wrong in an even more complex program can be a hard task.

_________________
Adrian Jansen
Computer language is a framework for creativity
Back to top
View user's profile Visit poster's website
Display posts from previous:   
This forum is locked: you cannot post, reply to, or edit topics.   This topic is locked: you cannot edit posts or make replies.    www.mcselec.com Forum Index -> BASCOM-AVR Archive All times are GMT + 1 Hour
Page 1 of 1

 
Jump to:  
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
You cannot attach files in this forum
You cannot download files in this forum