PDA

View Full Version : HSERIN & Interupts (aka controlling PIC programs from a remote PC)



HankMcSpank
- 16th June 2009, 14:03
So I started out on this journey with the intention of kludging a little PIC program to simply count encoder pulses from a striped disc attached to a motor then traversing the copper wire feeding onto it viaa stepper motor ...alas, I knew nothing about stepper nor PICs! Well - thanks to a lot of help on here - my PIC program now works....as the main motor turns, the little stepper motor is 'synced' (via the encoder & pic 'counter'), meaning that copper wire is fed onto the coil's core in 'Good King Wenceslas' style (ie deep & crisp & even - geddit?!!). I'll post a video soon.

but wait ...that's not good enough!

Yep - it's bells & whistles time!! [crowd groans]

At the minute, I have some simple push buttons hardwired into my circuit to stop & start the PIC program ..."it's good, but it's not quite right" (UK TV viewers might lock onto that phrase).

I actually would like a few more button options...sure I could crank up the button count...but that's going to get , erhm buttony! Guess what...my PC has lots of buttons (though most people call them keys)

in short I'd like to control my PIC from my PC over serial comms into the h/w USART using interupts....so that when for example I press an 'S' key on my PC, the PIC program stops, or a 'P' key...it pauses etc

Now then, I used interupts with my little PIC program already (for every time there's a black stripe arrives from the encoder wheel, a little interupt is raised...much neater than polling)...but I learnt bo-diddley about interupts. I kludged & 'borrowed' from others' PIC programs...coupled with the help I got on my last thread ...i got there (ie "The worst programmer in the world" thread...which I still am!)

So, I need to try & wrap my head around the mechanism behing DT's interupt routines (he's done a fantastic job, which places him above criticism...but I'd like to say that as a newbie...we could do with couple more examples coupled with more explanation aimed at an amoeba level!)

Ok, so I went to my best friend...a bloke called Google (though Bing crosby might be my new best friend soon...I'm fickle that way). And this thread turns up...

http://www.letbasic.com/forum/showthread.php?p=73546

which had an uber simple example of just the type of code I need to get me started. So in the best tradition of plagiarism, I tried to use it - it didn't work for me.

(Now the author did declare that he hadn't tested it...but I'm figuring if I can get this simple little interupt routine to work with my USART & HSERIN, then I'm laughing....)

Can you help?

my PIC is a 16f690 ...I reckon the switches/fuses are ok, as I've got HSERIN working with another (non interupt based) PIC program.

when the 1 key is pressed, I should see something (either "got it" or "didn't get it" onscreen - I see neither)

@MyConfig = _XT_OSC & _WDT_ON & _MCLRE_ON & _CP_OFF
@MyConfig = MyConfig & _MCLRE_ON & _BOR_OFF
@ __config MyConfig

DEFINE OSC 4
DEFINE HSER_SPBRG 25
DEFINE HSER_TXSTA 24h
DEFINE HSER_CLROERR 1
ANSELH=0
ANSEL=0
CM1CON0 =0
CM2CON0 =0
CM2CON1 =0
adcon1=0
TRISB.6 = 1
TRISB.7 = 0
TRISC=%00000000 ; set all Port C pins as outputs
rcsta.7=1 'SPEN serial port enable bit
low portc.0
low portc.1
low portc.2
low portc.3

mybyte var byte

'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _Get_char, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::

@ INT_ENABLE RX_INT ; enable UART RX interrupt


loop:
if mybyte="1" then
hserout ["got it!"]
mybyte=0
endif
if mybyte<>"1" then
hserout ["didn't get it!"]
mybyte=0
endif
goto loop


'---[USART RX Interrupt handler]----------------------------------------------------
Get_char:
hserin 100,noreceived,[mybyte] 'Get byte
noreceived: 'or if timeout return
@ INT_RETURN



Edit: If I strip all the interupt aspect out from above, and add in a simple

start1:
pause 999
HSEROUT [13,10]
HSEROUT ["Test, 13,10]
goto start1

in place of the original loop...I see the word "Test" on my screen...this proves the config/fuses to do with HSEROUT are correct at least!

Archangel
- 16th June 2009, 17:59
'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
<font color=red>INT_Handler RX_INT, _Get_char, PBP, yes</font color>
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::

<font color=blue>@ INT_ENABLE RX_INT ; enable UART RX interrupt
</font color>
The code in red is the receive interrupt, open DT-INTS and READ the options available, in amongst those are RB and INT choices, add them the way Darrel wrote them, into your interrupt macro, then enable them as done in Blue.
Example:


'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _Get_char, PBP, yes
INT_HANDLER INT_INT, _MyNewLabel, PBP,yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::

@ INT_ENABLE RX_INT ; enable UART RX interrupt
@ INT_ENABLE INT_INT ;enable External Interrupts


Here is your selection snipped from DT-Ints14


#define INT_INT INTCON,INTF ;-- INT External Interrupt
#define RBC_INT INTCON,RBIF ;-- RB Port Change Interrupt
#define TMR0_INT INTCON,T0IF ;-- TMR0 Overflow Interrupt 16F
#define TMR1_INT PIR1,TMR1IF ;-- TMR1 Overflow Interrupt
#define TMR2_INT PIR1,TMR2IF ;-- TMR2 to PR2 Match Interrupt
#define TX_INT PIR1,TXIF ;-- USART Transmit Interrupt
#define RX_INT PIR1,RCIF ;-- USART Receive Interrupt
#define CMP_INT PIR2,CMIF ;-- Comparator Interrupt
#define EE_INT PIR2,EEIF ;-- EEPROM/FLASH Write Operation Interrupt
#define BUS_INT PIR2,BCLIF ;-- Bus Collision Interrupt
#define PSP_INT PIR1,PSPIF ;-- Parallel Slave Port Read/Write Interrupt
#define AD_INT PIR1,ADIF ;-- A/D Converter Interrupt
#define SSP_INT PIR1,SSPIF ;-- Master Synchronous Serial Port Interrupt
#define CCP1_INT PIR1,CCP1IF ;-- CCP1 Interrupt
#define CCP2_INT PIR2,CCP2IF ;-- CCP2 Interrupt

INT_Handler RX_INT, _Get_char, PBP, yes tells the PIC<b> WHICH</b> interrupt to use and <b>WHICH</b> label to jump to.

HankMcSpank
- 17th June 2009, 01:44
Many thanks Joe...that actually helped a lot.

That program I posted above doesn't function this end at all - & I can't for the life of me work out why.

Not sure if it's related to some compile errors I was getting. I managed to get rid of a couple of compile errors by removing the space between the @ & the command, ie....

@ INT_ENABLE RX_INT becomes @INT_ENABLE RX_INT

but I'm still seeing this one during the compile...


Error[122] c:\progra~1\mecani~1\mcs\inter~2.asm 109 :Illegal opcode [RX_INT]

Any ideas?

Ioannis
- 17th June 2009, 06:56
This:



@MyConfig = _XT_OSC & _WDT_ON & _MCLRE_ON & _CP_OFF
@MyConfig = MyConfig & _MCLRE_ON & _BOR_OFF
@ __config MyConfig



should be:




@MyConfig1 = _XT_OSC & _WDT_ON & _MCLRE_ON & _CP_OFF
@MyConfig2 = MyConfig & _MCLRE_ON & _BOR_OFF
@ __config MyConfig1 & MyConfig2



Also where are your include files for the DT-INTS ?

Be sure to select the correct chip before compilation.


Ioannis

HankMcSpank
- 17th June 2009, 10:41
Thanks for taking the time to respond.

Ok, I made that change to the header config. (I already had the correct PIC variant selected)

The include DT bits where in my original program (I cut/pasted a last minute 'just before bed' effort into my post above, where I'd obviously not put that bit in). Actually, now that I have put them back in, I'm getting even more compilation errors - see this screen scrape...

http://img199.imageshack.us/img199/1746/errorkke.th.jpg (http://img199.imageshack.us/i/errorkke.jpg/) (it's a little blurry - but the image can be enlarged a bit more by clicking on the image after opening it the first time)

here's the code (by the way, which option is everyone choosing when they paste iup their code to have it in a box?!)...

@MyConfig1 = _XT_OSC & _WDT_ON & _MCLRE_ON & _CP_OFF
@MyConfig2 = MyConfig & _MCLRE_ON & _BOR_OFF
@ __config MyConfig1 & MyConfig2

INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts

DEFINE OSC 4
DEFINE HSER_SPBRG 25
DEFINE HSER_TXSTA 24h
DEFINE HSER_CLROERR 1
ANSELH=0
ANSEL=0
CM1CON0 =0
CM2CON0 =0
CM2CON1 =0
adcon1=0
TRISB.6 = 1
TRISB.7 = 0
TRISC=%00000000 ; set all Port C pins as outputs
rcsta.7=1 'SPEN serial port enable bit
low portc.0
low portc.1
low portc.2
low portc.3

mybyte var byte

'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _Get_char, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::

@INT_ENABLE RX_INT

loop:
if mybyte="1" then
hserout ["got it!"]
mybyte=0
endif
if mybyte<>"1" then
hserout ["didn't get it!"]
mybyte=0
endif
goto loop


'---[USART RX Interrupt handler]----------------------------------------------------
Get_char:
hserin 100,noreceived,[mybyte] 'Get byte
noreceived: 'or if timeout return
@INT_RETURN

Ioannis
- 17th June 2009, 11:13
sorry I type what you already had as a mistake!

corrected:

@MyConfig1 = _XT_OSC & _WDT_ON & _MCLRE_ON & _CP_OFF
@MyConfig2 = _MCLRE_ON & _BOR_OFF
@ __config MyConfig1 & MyConfig2

or better

@ __config = _XT_OSC & _WDT_ON & _MCLRE_ON & _CP_OFF & _MCLRE_ON & _BOR_OFF

For the boxed code use square brackets [ ] and the tags code and /code for the start and end part.

You do have MPASM selected, right/

Ioannis

HankMcSpank
- 17th June 2009, 11:59
Still no good - errors in spades!


http://img199.imageshack.us/img199/5053/errorse.th.jpg (http://img199.imageshack.us/i/errorse.jpg/)

Darrel Taylor
- 17th June 2009, 12:20
Got a couple problems going on here ...

First the funky Config lines...
I came up with that quite some time ago as a way to shorten the __CONFIG lines in the editor.
It's been passed around a bit, and Hank had it right(almost) in the first post.
With the exception that _MCLRE_ON was duplicated(not a problem) it was perfect.

After time moves on, I tend to do it more like this now ... (16F690)

ASM
cfg= _XT_OSC ; Oscillator Selection
cfg=cfg& _FCMEN_OFF ; Fail-Safe Clock Monitor
cfg=cfg& _IESO_OFF ; Internal External Switchover
cfg=cfg& _BOR_OFF ; Brown-out Reset
cfg=cfg& _CPD_OFF ; Data Code Protection
cfg=cfg& _CP_OFF ; Code Protection
cfg=cfg& _MCLRE_ON ; Master Clear Reset
cfg=cfg& _PWRTE_ON ; Power-up Timer
cfg=cfg& _WDT_OFF ; Watchdog Timer
__CONFIG cfg
ENDASM


The second problem here is Indentation.

The forum tends to scrunch everything up to the left side if you don't use a
block.
Copying snippets from the forum often leads to problems if you forget about the indentation. Especially when it's ASM code.

Take a look at the original examples for DT_INTS (http://darreltaylor.com/DT_INTS-14/hello.html) and you can see the proper indentation for the ASM statements.

Indentation applies to the @ operator too.
Removing the space between the @ and INT_ENABLE etc, does not do what you want it to do. That space must be there.
<br>

HankMcSpank
- 17th June 2009, 12:56
Wow...from the man himself! cool.

I figured it was something to do with formatting (the errors I was seeing alluded to it... hence me experimenting the space after the @ !!)

Anyway, in the light of your info ...it all compiles fine! (*many* thanks!)

My problem now is a simple one, why is my 'if' condition not being met when the 1 key is being pressed on my PC keyboard...



loop:
if mybyte="1" then
hserout ["got it!"]
endif

if mybyte<>"1" then
hserout ["DIDN'T GET IT!",13,10]
hserout [mybyte,13,10] ' (tried to add in this line to see onscreen what the content of mybyte is - nothing output!)
PAUSE 499
mybyte=0
endif
goto loop



(hey, I can do boxes now too! tks Ioannis)

All I see on my ASCII terminal when the program is running is "DIDN'T GET IT!" scrolling down - which suggests that when I press the "1" key, the content of variable mybyte is not 00000001 (but possibly an ASCII interpretation of the number 1 (the ASCII for 1 is 49 tried that but it errored!).

I normally spontaneously combust as I try to work out what I should be 'matching' against, so could someone save the fire brigade a visit here - it makes a terrible mess of the carpet!

Many thanks!

Darrel Taylor
- 17th June 2009, 13:04
Sorry, the only water I have is used Beer. :)
Hope it's a small fire.

So where is mybyte getting read?

I assume there's an HSERIN [mybyte] somewhere? (In the loop?)
<br>

Ioannis
- 17th June 2009, 13:06
And where do you read the serial in port???

Ioannis

HankMcSpank
- 17th June 2009, 13:18
Sorry, I was just stripping out the interupt bits (since they are compiling fine now), but yes, I can see how that's confused you all!

Anyway, to show off my new found "box" skills, here you go...



@MyConfig = _XT_OSC & _WDT_ON & _MCLRE_ON & _CP_OFF
@MyConfig = MyConfig & _BOR_OFF
@ __config MyConfig

INCLUDE "DT_INTS-14.bas" ; Base Interrupt System
INCLUDE "ReEnterPBP.bas" ; Include if using PBP interrupts

DEFINE OSC 4
DEFINE HSER_SPBRG 25
DEFINE HSER_TXSTA 24h
DEFINE HSER_CLROERR 1
ANSELH=0
ANSEL=0
CM1CON0 =0
CM2CON0 =0
CM2CON1 =0
adcon1=0
TRISB.6 = 1
TRISB.7 = 0
TRISC=%00000000 ; set all Port C pins as outputs
rcsta.7=1 'SPEN serial port enable bit
low portc.0
low portc.1
low portc.2
low portc.3

mybyte var byte
'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _Get_char, PBP, yes
endm
INT_CREATE ; Creates the interrupt processor
ENDASM
'::::::::::::::::::::::::::::::::::::::::::::::::: ::::::::::::::::::::::::::
@ INT_ENABLE RX_INT ; enable external (INT) interrupts


loop:
if mybyte="1" then
hserout ["got it!"]
endif

if mybyte=!"1" then
hserout ["DIDN'T GET IT!",13,10]
hserout [mybyte,13,10] ' (tried to add in this line to see onscreen what the content of mybyte is - nothing output!)
PAUSE 499
mybyte=0
endif
goto loop



'---[USART RX - interrupt handler]---------------------------------------------------
Get_char:
hserin 100,noreceived,[mybyte] 'Get byte
noreceived: 'or if timeout return
@ INT_RETURN



My (noob) take here is that, when a key is pressed, the interrupt routine jumps to the Get_char - this keyboard 'keyed' "data" is then stored in the variable mybyte - but what will the actual contents of mbyte be ? For example if I press a "1" key on the keyboard will it be 00000001 (unlikely!), or 00110001 (binary for 49 - the ASCII code for the number "1"). Once I can figure out this bit, then I can make sure my "if" takes account of it. (that'll be my next question!) Also, the line I bolded...I was trying to see onscreen what the content of the variable mybyte was - but nothing was output?

BTW The low portc.0 low portc.1 are in there because I have a Microchip low pin count demo board & my (eventual) target for today is to get some LEDs to light up when certain keys on my PC keyboard are pressed - I'm a simple kind of easy to please chap, who marvels at this kind of thing & insists all around me marvel too! (though it irks my two year old something rotten when I interrupt his Thomas The Tank Engine viewing)

Darrel Taylor
- 17th June 2009, 13:39
My guess is that ... 99.99% of the time is spent in the PAUSE 499 statement.

So if anything does come in via the USART in the interrupt during that time, the byte received will be immediately discarded with the mybyte=0 statement that follows.
<br>

HankMcSpank
- 17th June 2009, 13:52
Ok, so I stripped that bit out - only this bit remains...



loop:
if mybyte="1" then
hserout ["got it!"]
mybyte = 0
endif
goto loop


yet when I press the "1" key on my PC keyboard...nothing happens (ie I don't see "Got it!" on my terminal, which seems very apt as I really don't get it!)

??

Darrel Taylor
- 17th June 2009, 14:17
Which pin are you connected to for RX?

It looks like you are trying to set RB6 as INPUT, as if that were the RX pin.
But RX is on RB5.
<br>

HankMcSpank
- 17th June 2009, 14:29
Which pin are you connected to for RX?

It looks like you are trying to set RB6 as INPUT, as if that were the RX pin.
But RX is on RB5.
<br>

That's a good spot. The config part (setting up ports etc), was a straight lift (cut/paste) from a non-interrupt based HSERIN test program that I have which works fine. You are quite right that on a 16f690 PIC, the RX pin is RB5

Fortunately, I am actually connecting to RB5 for my RX (& like I say, I have a program where the whole HSERIN/HSEROUT kit & kaboodle works with that same config). I guess this is where I 'got lucky' & the PIC has defaulted RB5 to being an input? So alas, I don't think that's my problem :(

I actually think the port setup, registers etc are ok (on account it being a straight cut/paste from an HSERIN/HSEROUT worker) ...what I think this is likely to be is a lack of understanding what I should be matching against? (ie if mybyte="1" then what does a key press "1" get stored in a byte as etc)

HankMcSpank
- 17th June 2009, 14:46
DOH IT WORKS!!!!!

The Solution? :o :o (not sure I should even say, but rather try flam it off as an ahem "a very technical issue")

I'm using a Pickit2 as my pseudo VT terminal ...I've hardwired a switch on the low pin count demo board which allows me to go from programmer mode to VT emulator mode (saves having to buy MAX232 + other components & can also use the USB cable for the PC-PIC serial comms etc - http://www.picbasic.co.uk/forum/showpost.php?p=72981&postcount=21 ) ....sometimes, if I don't flick the switch back from VT terminal mode to programmer mode in time (while PicBasic Pro is compiling), the Pickit2 app then tries to auto update the PIC with the new HEX - but doesn't see it (becuase I never flicked the switch in time) & everything locks up. This necessitates closing the Pickit2 application down & restarting it.

So, I'd become so focused on the code, that I'd overlooked that when I have to restart the Pickit2 app, that I need to tick the 'apply VCC' box to power up the PIC :o

Therefore in summary...this last hurdle was nothing more sinister that my Pic not having any power applied to it from the Pickit2 ....(I reckon my original problems were nailed with the formatting problems)


I'm chuffed to bits - I can't thank you all enough - I'm now off to make some LEDs light up when I press PC keys. My 2yr old son won't be happy as Thomas the Tank Engine has just started & I'll be saying things to him like "hehe... hey son, look at this LED light up - it's all interrupt based you know?". Two year olds of today - they know nothing.