PDA

View Full Version : Serial UART and Interupts on a 16F87X



scasale
- 29th August 2011, 21:29
I have been trying to get interupts to work for a few days now. I kind of understand them but seem to have a sticking point somewhere. Maybe the "OPTION" register. Not sure. Been all over the net reading. This seems to be quite common. Anyway can someone help. I have been using PB PRO for a while but not for bidirectional RS-232.

I am simply trying to engage 6 relays based on commands. Then while not doing that continuosly send data back down to a PC. When serial command arrives, act on it. Below is my code.

Thanks. Scott.C.

'************************************************* ***************
'* Name : Antenna_ROTOR.BAS *
'* Date : 5/23/2011 *
'* Version : 1.0 *
'* Notes : PIC 16F873A *
'* : *
'************************************************* ***************
'* Notes : Pin Outs are as follows
'* ******
'* MCLR ******1 28*****
'* Position Sense ******2 27*****
'* ******3 26***** CTS (FUTURE)
'* ******4 25***** RTS (FUTURE)
'* ******5 24***** ANT 4
'* ******6 23***** ANT 3
'* ******7 22***** ANT 2
'* GND ******8 21***** ANT 1
'* CLK ******9 20***** +5VDC
'* *****10 19***** GND
'* *****11 18***** RS-232 RX
'* *****12 17***** RS-232 TX
'* *****13 16***** C-CW RELAY
'* *****14 15***** CW RELAY
'* ******
'* Notes : Interface between Alliance HD-73 rotor and PC Serial Port
'* : 2400 8, N, 1
'* : Provides constant rotor position, status feedback
'* : Responds to serial commands to move rotor CW or CCW via 2 relays
'*
'************************************************* ************************

DEFINE OSC 4 ' 4 MHz clock
DEFINE ADC_BITS 10 ' Set number of bits in result
DEFINE ADC_CLOCK 3 ' Set clock source (3=rc)
DEFINE ADC_SAMPLEUS 20 ' Set sampling time in uS

DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 20h ' Enable transmit, BRGH = 0
DEFINE HSER_SPBRG 25 ' 2400 Baud @ 4MHz, 0.17%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically

TRISA = %000001 ' Set PORTA
TRISB = %01100000 ' Set PORTB
TRISC = %10000000 ' Set PORTC
INTCON = %10010000
PIE1 = %00100000
'**************** DEFINE VARIABLES ***************************************

relay VAR BYTE 'relay number storage variable
stat VAR BYTE 'relay status ON/OFF variable
POTADC VAR WORD 'ADC Result
RXBYTE var byte

'**************** PORT B Setup *******************************************

ANT4 VAR PORTB.3 'ANT4 Relay
ANT3 VAR PORTB.2 'ANT3 Relay
ANT2 VAR PORTB.1 'ANT2 Relay
ANT1 VAR PORTB.0 'ANT1 Relay

'**************** PORT C Setup *******************************************

CCW VAR PORTC.5 'CCW Relay
CW VAR PORTC.4 'CW Relay

'****************** PORT SETUP *******************************************

CW=0 ' CW Relay Off
CCW=0 ' CCw Relay Off
ANT1=0
ANT2=0
ANT3=0
ANT4=0
ADCON0=0 ' Set up ADCON1

'***************** Main Program ******************************************
on interrupt goto RECEIVE

LOOP:

TRANSMIT:
ADCIN 0, POTADC 'convert ADC value to a byte value:
HSEROUT [DEC POTADC,32] 'TX DATA on PORTC.6
PAUSE 50

GOTO loop

DISABLE
RECEIVE:
IF (RCSTA.2=1) THEN
HSERIN [RXBYTE]
else
HSERIN 500,TRANSMIT,[WAIT(254),relay,stat] 'serial data in on Portc.7
endif

IF relay = 1 THEN outr1 ' if relay#1 then goto relay#1 routine
IF relay = 2 THEN outr2 ' if relay#2 then goto relay#2 routine
IF relay = 3 THEN outr3 ' if relay#3 then goto relay#3 routine
IF relay = 4 THEN outr4 ' if relay#4 then goto relay#4 routine
IF relay = 5 THEN outr5 ' if relay#5 then goto relay#5 routine
IF relay = 6 THEN outr6 ' if relay#6 then goto relay#6 routine

RESUME
ENABLE

'***************** DRIVE RELAYS ******************************************
outr1:
IF stat = 1 THEN high1
LOW CW: GOTO LOOP
high1:
HIGH CW: GOTO loop ' Turn on CW Relay

outr2:
IF stat = 1 THEN high2
LOW CCW: GOTO loop
high2:
HIGH CCW: GOTO loop ' Turn on CCW Relay

outr3:
IF stat = 1 THEN
HIGH ANT1: LOW ANT2: LOW ANT3: LOW ANT4
GOTO loop ' Turn On Relay for Antenna 1
endif

outr4:
IF stat = 1 THEN
HIGH ANT2: LOW ANT1: LOW ANT3: LOW ANT4
GOTO loop ' Turn On Relay for Antenna 2
endif

outr5:
IF stat = 1 THEN
HIGH ANT3: LOW ANT1: LOW ANT2: LOW ANT4
GOTO loop ' Turn On Relay for Antenna 3
endif

outr6:
IF stat = 1 THEN
HIGH ANT4: LOW ANT1: LOW ANT2: LOW ANT3
GOTO loop ' Turn On Relay for Antenna 4
endif

END

cncmachineguy
- 30th August 2011, 00:26
In your isr you check for relay =1..6. Then you GOTO a routine to turn the proper relay on. Then from there you GOTO back to loop.

Isr is never re-enabled. Plus you goto out of your isr sub routine so there is no way to get back and properly return.

That's my thoughts.

Archangel
- 30th August 2011, 03:44
Ok probably I am wrong again:
DISABLE
RECEIVE:
I think Disable should go inside this sub directory
like
RECEIVE:
DISABLE
Cause if you goto receive then do not you sail past the disable?
Also you have if then loops for condition 1:6,
where does it go if NOT 1:6?

WW6PAC

scasale
- 30th August 2011, 04:46
If it is not 1 thru 6 then it loops back to the start. I will look at this again in the AM as I start work early.
I put an ENABLE after the RESUME. Does that in itself not restart the checking for an interupt? But maybe I need a GOTO loop just after that. I noticed I missed a goto loop just after the ENABLE. Looks like it has no where to go! Maybe that is what I missed.
DO I need to set the option reg for a rising edge for the incomming serial?

Thanks,

Scott

scasale
- 30th August 2011, 04:49
I also agree that the disable goes inside, but all the code I see eaxamples of always put it just before the subroutine, so that is what I did.

cncmachineguy
- 30th August 2011, 05:31
Ok maybe a better way for me to explain is this:

Think about the ISR as a subroutine. As such it MUST be returned from. In the case of ON INTERRUPT, this is the RESUME statement. But in your case you jump past the resume with the GOTO's in the ISR. I don't know if the interrupt get re-enabled, but I don't think so because of this. You have 2 choices IMHO.

1. make all the goto's gosub's in the IF's, then change the GOTO loop in each RELAY action to return.
2 This is my favorite:


Loop:
HSEROUT stuff
IF Relay > 0 then
If relay = 1 then outr1
If relay = 2 then outr2
If ....
Endif


Then in each outr routine, set relay = 0 before you goto loop.

Last thing, Don't use loop for a label. It is reserved in later releases of PBP.

HenrikOlsson
- 30th August 2011, 06:23
Hi,
I never use ON INTERRUPT so I don't know if you have to clear the interrupt flag before resuming (the USART flag clears itself when reading the RXREG but the interruptflag). Apart from that I think Bert is on it. You get to the interrupt, then you GOTO one of the Outx routines and then you END....

ENABLE/DISABLE are not normal "PBP commands" that executes at runtime. They are directives to the compiler to tell it where to start/stop inserting commands to poll the interrupt flag. In this case it doesn't matter if you put ENABLE before or after the Receive: label since ENABLE is not a command that executes at runtime.

/Henrik.

scasale
- 30th August 2011, 15:01
Ok, I made the following changes and it is not responding to any data now. It does continue to send data, just won't receive.
Also the code from the PC sets the corosponding relay back to 0 at the end of the command.
Example TX 2,1 then TX 2,0 meaning relay 2 HIGH then relay 2 LOW. Relays 3 thru 6 are latching and are unlatched when a differint relay is selected. Only relays 1 and 2 are momentary.

Intersting thing is I had this working great when connecting to a PC directly using COM Port with OUT interupts. I was using RTS/CTS but now that I am going thru a LAN to serial adapter it does not behave the same. I just recently added a RS-232 level converter that has a MAX232 of some flavor on board, so maybe I'll give the RTS/CTS deal a try again. I would love to get a handle on this interupt thing though so I can grow my PIC projects!

I also took out the wait statement, because I understand the UART can only grab 2 bytes at a time. Changed loop to MAIN.

Thanks for the info on ENABLE/DISABLE. It is for the compiler! I'll keep grinding away here.


on interrupt goto RECEIVE

MAIN:

TRANSMIT:
ADCIN 0, POTADC 'convert ADC value to a byte value:
HSEROUT [DEC POTADC,32] 'TX DATA on PORTC.6
PAUSE 300

GOTO MAIN

DISABLE
RECEIVE:
IF (RCSTA.2=1) THEN
HSERIN [RXBYTE]
else
HSERIN 500,TRANSMIT,[relay,stat] 'Serial data in on PortC.7
endif

IF relay = 1 THEN GOSUB outr1 ' Process relay#1 routine
IF relay = 2 THEN GOSUB outr2 ' Process relay#2 routine
IF relay = 3 THEN GOSUB outr3 ' Process relay#3 routine
IF relay = 4 THEN GOSUB outr4 ' Process relay#4 routine
IF relay = 5 THEN GOSUB outr5 ' Process relay#5 routine
IF relay = 6 THEN GOSUB outr6 ' Process relay#6 routine

RESUME
ENABLE
GOTO MAIN

'***************** DRIVE RELAYS ******************************************
outr1:
IF stat = 1 THEN high1
LOW CW: RETURN
high1:
HIGH CW: RETURN ' Turn on CW Relay

outr2:
IF stat = 1 THEN high2
LOW CCW: RETURN
high2:
HIGH CCW: RETURN ' Turn on CCW Relay

outr3:
IF stat = 1 THEN
HIGH ANT1: LOW ANT2: LOW ANT3: LOW ANT4
RETURN ' Turn On Relay for Antenna 1
endif

outr4:
IF stat = 1 THEN
HIGH ANT2: LOW ANT1: LOW ANT3: LOW ANT4
RETURN ' Turn On Relay for Antenna 2
endif

outr5:
IF stat = 1 THEN
HIGH ANT3: LOW ANT1: LOW ANT2: LOW ANT4
RETURN ' Turn On Relay for Antenna 3
endif

outr6:
IF stat = 1 THEN
HIGH ANT4: LOW ANT1: LOW ANT2: LOW ANT3
RETURN ' Turn On Relay for Antenna 4
endif

END

Bruce
- 31st August 2011, 11:40
Here's a untested/simplfied version that should work. Compare it to your original to see the changes.


DEFINE OSC 4 ' 4 MHz clock
DEFINE ADC_BITS 10 ' Set number of bits in result
DEFINE ADC_CLOCK 3 ' Set clock source (3=rc)
DEFINE ADC_SAMPLEUS 20 ' Set sampling time in uS
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 20h ' Enable transmit, BRGH = 0
DEFINE HSER_SPBRG 25 ' 2400 Baud @ 4MHz, 0.17%
DEFINE HSER_CLROERR 1 ' Clear overflow automatically

TRISA = %000001 ' Set PORTA
TRISB = %01100000 ' Set PORTB
TRISC = %10000000 ' Set PORTC
ADCON1 = %10001110 ' RA0 A/D input. +Vref=Vdd, -Vref=Vss. Right justified for 10-bit
INTCON = %11000000 ' Global & peripheral ints enabled. Not RB0/INT
PIE1 = %00100000

'**************** DEFINE VARIABLES ***************************************
relay VAR BYTE 'relay number storage variable
stat VAR BYTE 'relay status ON/OFF variable
POTADC VAR WORD 'ADC Result
RXBYTE var byte

'**************** PORT B Setup *******************************************
ANT4 VAR PORTB.3 'ANT4 Relay
ANT3 VAR PORTB.2 'ANT3 Relay
ANT2 VAR PORTB.1 'ANT2 Relay
ANT1 VAR PORTB.0 'ANT1 Relay

'**************** PORT C Setup *******************************************
CCW VAR PORTC.5 'CCW Relay
CW VAR PORTC.4 'CW Relay

'****************** PORT SETUP *******************************************
CW=0 ' CW Relay Off
CCW=0 ' CCw Relay Off
ANT1=0
ANT2=0
ANT3=0
ANT4=0
ADCON0=0 ' Set up ADCON1
ON INTERRUPT GOTO RECEIVE

MAIN:
ADCIN 0, POTADC 'convert ADC value to a byte value:
HSEROUT [DEC POTADC,32] 'TX DATA on PORTC.6
PAUSE 300
GOTO MAIN

DISABLE ' <-- doesn't matter if DISABLE is before or after the label
' just as long as it's before any CODE.
RECEIVE:
IF RCSTA.2=1 THEN
HSERIN [RXBYTE]
ELSE
HSERIN 500,IntExit,[relay,stat] 'Serial data in on PortC.7
ENDIF

' Simplified version without gosubs, gotos, etc.
IF relay = 1 THEN CW = Stat.0 ' Process relay#1
IF relay = 2 THEN CCW = Stat.0 ' Process relay#2
IF relay = 3 THEN PORTB = %00000001 ' Process relay#3
IF relay = 4 THEN PORTB = %00000010 ' Process relay#4
IF relay = 5 THEN PORTB = %00000100 ' Process relay#5
IF relay = 6 THEN PORTB = %00001000 ' Process relay#6

IntExit:
RESUME
ENABLE ' <-- You only need ENABLE if you place more code below
' it and you want interrupt checking code there.
END

scasale
- 1st September 2011, 22:45
I will try that out Thanks! I did some searching and found this tutorial. Explains it fairly well! I need to look at again while coding the above post by Bruce. Check it out when you have time.

http://www.microcontrollerboard.com/pic_interrupt.html

scasale
- 27th September 2011, 14:32
Ok, I got off on a different project for a while. Now to pick this up again! Lets see if I can get my head around this and remember where I was at.

scasale
- 29th September 2011, 23:35
Yes, this seems to work! I need to check one other thing before I sign this off. But I left some of my notes at work. So I will check the last thing tomorrow morning.

Can someone answer what the .0 is for or how it behaves in the line:
IF relay = 1 THEN CW = Stat.0 ' Process relay#1
IF relay = 2 THEN CCW = Stat.0 ' Process relay#2

I understand the "stat" part, but not seeing what .0 function is.

Thank you
Scott

mackrackit
- 30th September 2011, 03:18
Stat VAR BYTE 'relay status ON/OFF variable
8 bits in a byte -- 0 to 7

IF relay = 1 THEN CW = Stat.0 ' Process relay#1
Stat.0 is the first bit of byte Stat

From the PBP manual


4.4. Aliases
VAR can also be used to create an alias (another name) for a variable. This is most useful for accessing the innards of a variable.

fido var dog ' fido is another name for dog
b0 var w0.byte0 ' b0 is the first byte of word w0
b1 var w0.byte1 ' b1 is the second byte of word w0
flea var dog.0 ' flea is bit0 of dog

scasale
- 4th October 2011, 13:29
Ok! It is all good. Thanks to all that helped me get a handle on this. Makes sense, and I see why it did not work early on, and understand what I did wrong.

Thanks,

Scott