PDA

View Full Version : Hserin with Instant Interrupts.



ronjodu
- 13th September 2008, 13:32
My goal is to connect 2 pics together with Zigbee. I bought a Dev. kit from http://www.digi.com/ for $99.00. I'd like to use the Hardware serial port in the pic (18f2525) to communicate with the Zigbees so I'm trying to learn the ins and outs of Hserin, Hserout.

I put together this little collection of snippetts to echo characters back to Hyperterminal. The echo seems to work fine when I send one character or 20. The part that has me stumped is:
1) the Mainloop doesn't run. No Heartbeat.
2) The echo part of the ISR seems to work as expected but the Led2 doesn't toggle as expected. (on with the first byte sent, off with the second on with the third etc....).

I've been thru "TFM" on the Eusart and tried many different register settings many times but the solution hasn't jumped out at me yet.
I've Hserin with and without timeouts.
I've tried a pullup on RC7.
I've tried a pulldown on RC7.

So, as always, I would greatly appreciate a little nudge in the right direction. Not spoon feeding, just a nudge.


'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
'Hserin with Darryl Taylor's Instant Interrupts
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
' Program to echo incoming serial data
' Baudrate : 9600 Baud
' MCSP and MPASM, LabX-2, Microcodeloader, PBP2.50
' Using PIC 18F2525 @ 4MHZ and bootloader
' Using internal USART and MAX232 to interface to Hyperterminal on PC


DEFINE LOADER_USED 1
DEFINE OSC 4
DEFINE HSER_RCSTA 90h ' enable serial port,
define HSER_TXSTA 24h ' enable transmit,
define HSER_SPBRG 25 ' set baudrate to 9600
DEFINE HSER_CLOERR 1 ' automatic clear overrun error

TRISC = %10000000 ' PORTC.7 is the RX input, PORTC.6 is the TX output


' Serial communication definition
' ===============================
'

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

INCLUDE "MODEDEFS.BAS" ' Include Shiftin/out modes
INCLUDE "DT_INTS-18.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ' Include if using PBP interrupts
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
' Variable definition
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::

RCIF VAR PIR1.5 ' Receive interrupt flag (1=full , 0=empty)
TXIF VAR PIR1.4 ' Transmit interrupt flag (1=empty, 0=full)
led var PORTB.0
led1 var PORTB.1
led2 var PORTB.2
holdoff var word
SerialData var byte

clear

'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _Getbytes, PBP, no
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE RX_INT ; enable RX_INT interrupts


'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
' Subroutine to slow loop down some and toggle heartbeat
'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
Mainloop:
for holdoff = 1 to 1000
pause 1
next holdoff
toggle led 'toggle led every loop for heartbeat
goto Mainloop


'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
'ISR for RX_int interrupt
'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))

Getbytes:

While RCIF = 1 ' clear the buffer
HSERIN 100,error,[Serialdata] ' take it
hserout [serialdata] ' send it
Wend
toggle led2 'led to confirm program went to RX ISR

@ INT_RETURN


error:
Toggle led1
@ INT_RETURN
end

skimask
- 13th September 2008, 17:00
For grins, try this instead of TOGGLE...


'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
'Hserin with Darryl Taylor's Instant Interrupts
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
' Program to echo incoming serial data
' Baudrate : 9600 Baud
' MCSP and MPASM, LabX-2, Microcodeloader, PBP2.50
' Using PIC 18F2525 @ 4MHZ and bootloader
' Using internal USART and MAX232 to interface to Hyperterminal on PC


DEFINE LOADER_USED 1
DEFINE OSC 4
DEFINE HSER_RCSTA 90h ' enable serial port,
define HSER_TXSTA 24h ' enable transmit,
define HSER_SPBRG 25 ' set baudrate to 9600
DEFINE HSER_CLOERR 1 ' automatic clear overrun error

TRISC = %10000000 ' PORTC.7 is the RX input, PORTC.6 is the TX output


' Serial communication definition
' ===============================
'

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

INCLUDE "MODEDEFS.BAS" ' Include Shiftin/out modes
INCLUDE "DT_INTS-18.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ' Include if using PBP interrupts
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
' Variable definition
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::

RCIF VAR PIR1.5 ' Receive interrupt flag (1=full , 0=empty)
TXIF VAR PIR1.4 ' Transmit interrupt flag (1=empty, 0=full)
led var PORTB.0
led1count var byte
led2count var byte
led1 var PORTB.1
led2 var PORTB.2
holdoff var word
SerialData var byte

clear

'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _Getbytes, PBP, no
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE RX_INT ; enable RX_INT interrupts


'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
' Subroutine to slow loop down some and toggle heartbeat
'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
Mainloop:
for holdoff = 1 to 1000
pause 1
next holdoff
led1count = led1count + 1
led = led1count.0 'toggle led every loop for heartbeat
goto Mainloop


'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
'ISR for RX_int interrupt
'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))

Getbytes:

While RCIF = 1 ' clear the buffer
HSERIN 100,error,[Serialdata] ' take it
hserout [serialdata] ' send it
Wend
led2count = led2count + 1
led2 = led2count.0 'led to confirm program went to RX ISR

@ INT_RETURN


error:
Toggle led1
@ INT_RETURN
end



Using that method to set the LEDs, you can dispense with the pause loop and select a higher bit in the ledxcount variable to slow down the blinking.

Bruce
- 13th September 2008, 18:39
Nudge: Disable A/D....;o}

skimask
- 13th September 2008, 20:17
Nudge: Disable A/D....;o}

Doh! PortB...A/D...no kidding...

mackrackit
- 13th September 2008, 20:24
Looks like this needs re-named? If PORTS A through Z do not work :D
http://www.picbasic.co.uk/forum/showthread.php?t=561

ronjodu
- 13th September 2008, 23:28
I never thought I'd need to set ADCON1 since I'm not using any of PortA.
Learning something new every day. As always, thanks for the help.

I'm going to try your method of toggling the LED's Skimask, never seen it done like that, Thanks.

New working code with one minor change. (Thanks Bruce.)



'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
'Hserin with Darryl Taylor's Instant Interrupts
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
' Program to echo incoming serial data
' Baudrate : 9600 Baud
' MCSP and MPASM, LabX-2, Microcodeloader, PBP2.50
' Using PIC 18F2525 @ 4MHZ and bootloader
' Using internal USART and MAX232 to interface to Hyperterminal on PC


DEFINE LOADER_USED 1
DEFINE OSC 4
DEFINE HSER_RCSTA 90h ' enable serial port,
define HSER_TXSTA 24h ' enable transmit,
define HSER_SPBRG 25 ' set baudrate to 9600
DEFINE HSER_CLOERR 1 ' automatic clear overrun error

TRISC = %10000000 ' PORTC.7 is the RX input, PORTC.6 is the TX output


' Serial communication definition
' ===============================
'
ADCON1 = %00001111 'Set up ADCON1 register no matter what you're doing!!!!!!
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::

INCLUDE "MODEDEFS.BAS" ' Include Shiftin/out modes
INCLUDE "DT_INTS-18.bas" ' Base Interrupt System
INCLUDE "ReEnterPBP-18.bas" ' Include if using PBP interrupts
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::
' Variable definition
'::::::::::::::::::::::::::::::::::::::::::::::::: :::::::::::::::::::::::::::::

RCIF VAR PIR1.5 ' Receive interrupt flag (1=full , 0=empty)
TXIF VAR PIR1.4 ' Transmit interrupt flag (1=empty, 0=full)
led var PORTB.0
led1 var PORTB.1
led2 var PORTB.2
holdoff var word
SerialData var byte

clear

'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
ASM
INT_LIST macro ; IntSource, Label, Type, ResetFlag?
INT_Handler RX_INT, _Getbytes, PBP, no
endm
INT_CREATE ; Creates the interrupt processor
ENDASM

@ INT_ENABLE RX_INT ; enable RX_INT interrupts


'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
' Subroutine to slow loop down some and toggle heartbeat
'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
Mainloop:
for holdoff = 1 to 1000
pause 1
next holdoff
toggle led 'toggle led every loop for heartbeat
goto Mainloop


'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))
'ISR for RX_int interrupt
'((((((((((((((((((((((((((((((((((((((()))))))))) )))))))))))))))))))))))))))))

Getbytes:

While RCIF = 1 ' clear the buffer
HSERIN 100,error,[Serialdata] ' take it
hserout [serialdata] ' send it
Wend
toggle led2 'led to confirm program went to RX ISR

@ INT_RETURN


error:
Toggle led1
@ INT_RETURN
end

skimask
- 13th September 2008, 23:49
I'm going to try your method of toggling the LED's Skimask, never seen it done like that, Thanks.
I like that method of using the heartbeat because it allows for an easy change of blink frequency. The LED 'attached' to a timer works also, but it only tells you that the timer is running and an interrupt is working. Generally, I use 2 heartbeats, one for a mainloop, and one for a timer. Mainloop says the program is looping, timer says the PIC is actually running.

Michael
- 22nd September 2008, 15:18
From what I see it's mostly a matter of setting up the defines and running getbytes?

Is this the barebones of what I need to get data in/out of serialdata?

As long as data is at portc.7 it continuously runs in the background as an input, loading serialdata while any other code is executing?

I can then sample serialdata when I need to in my code?


DEFINE LOADER_USED 1
DEFINE OSC 4
DEFINE HSER_RCSTA 90h ' enable serial port,
define HSER_TXSTA 24h ' enable transmit,
define HSER_SPBRG 25 ' set baudrate to 9600
DEFINE HSER_CLOERR 1 ' automatic clear overrun error

TRISC = %10000000 ' PORTC.7 is the RX input, PORTC.6 is the TX output


' Serial communication definition


Getbytes:

While RCIF = 1 ' clear the buffer
HSERIN 100,error,[Serialdata] ' take it
hserout [serialdata] ' send it
Wend

Demon
- 27th December 2014, 14:23
To start,

Set a new flag in interrupt, check that flag in main, do processing there and reset your flag.

Keep isr as small as possible.

Robert

Demon
- 27th December 2014, 14:24
Have you tried DT USART INTERRUPT?

It works great, don't have to play with flags.

Robert

MichelJasmin
- 28th December 2014, 15:31
This is what I do with DT_Interrupts on a serial stream of 115kBps on a PIC18F25k22 @44.2368MHz.

"Buffer" is a circular buffer of 256 bytes. When BufferReady = 1, I use another pointer (ParsePtr) to parse the data.




'----[interrupts Handlers]-------------------------------------------------------
RX_IntHandler:
IF (RCSTA1.2 = 1) THEN
' A framing error occurred.
' Read RCREG to clear the error but don't use the data.
CharBuff = RCREG1

ELSE
' No framing error occurred. Get caracter.
CharBuff = RCREG1

If CharBuff <= 10 Then
Buffer(BuffPtr) = 0
BuffPtr = BuffPtr + 1
BufferReady = 1

Else
If CharBuff >= 32 Then
Buffer(BuffPtr) = CharBuff
BuffPtr = BuffPtr + 1
ENDIF
ENDIF
ENDIF

@ INT_RETURN

HenrikOlsson
- 28th December 2014, 16:35
Hi Andy,

Looking at the original code I think at least one problem is the presense of the PAUSE in main routine.

When using ON INTERRUPT the interrupt flag is checked in between each PBP statement. If characters start to come in while the PIC is exectuing a PAUSE 150 satements you're going to flood the USART buffer since the interrupt isn't serviced untill after the PAUSE 150 finishes.

Same thing with the LCDOUT and PAUSE statements and in the master. They takes some time to execute and the interrupt flag is checked ONLY in between each statement so if the slave starts responding while the master is in the middle of printing to the LCD or executing a PAUSE the slave is going to flood the buffer of the master.

That's the downside of ON INTERRUPT.

/Henrik.

HenrikOlsson
- 29th December 2014, 09:19
Hi Andy,
I don't have the time to rig something up here at the moment but I took a look at your code again and here are a couple of suggestions.
For the master you don't need interrupts at all. Since it's querying the slave for data it already knows when data is supposed to come in. What you may want to do is add a timeout to the HSERIN though in case something goes wrong. The defines for the LCD, at the top of the program, needs to be UPPER CASE or they won't have any effect. So, for the master, remove the interrupt stuff then go directly from HSEROUT to HSERIN, something like this:


Main:
lcdout $fe,1
lcdout $fe,128,"Test RX-Tx"
lcdout $fe,192,"Reading"

pause 1000

lcdout $fe,1
lcdout $fe,128,#m[0],#M[1],#M[2],#M[3]
lcdout $fe,192,"Transmitting!"

High en
high led

hserout ["P",$88]

' Wait for the data to go out before pulling the EN signal to
' the tranceiver - IF that's what the EN-signal is doing.....
While TXSTA.1 = 0 : WEND

low en
low led

Hserin [wait("S0"),m[0], wait("S1"),m[1], wait("S2"),M[2], wait("S3"),m[3]]


toggle led


lcdout $fe,1
lcdout $fe,128,"Received!"
LCDOUT $fe,192,#m[0],"*",#M[1],"*",#M[2],"*",#M[3]
pause 1000
goto main

For the slave, what you can do if you want to keep the ON INTERRUPT and still have your blinking LED in the main is to replace the long PAUSE with loop consisting of many short pauses instead. That way the interrupt flag will be polled after each of those short pauses instead of after the single long one. Much less risk of flooding the buffer. Something like this perhaps:

i VAR WORD
main:
toggle led
low en 'My stuff
For i = 0 to 299
PAUSEUS 500 ' Pause for 150ms
NEXT
goto main

Disable interrupt ' Don't check for interrupts in this section

serialin:

' Read USART and store character to next empty location
Hserin [wait("P"),start]
high en
if start =$88 then
for j=0 to 3 ' Producing ODD numbers (Just for checking of continuous communication)
i=i+1
m[j]=(2*i)+1
if m[j]>100 then
i=0
m[j]=j+1
endif
next j

hserout ["S0",m[0],"S1",m[1],"S2",M[2],"S3",m[3]]

' Wait for the data to go out before pulling the EN signal to
' the tranceiver.
While TXSTA.1 = 0 : WEND

low en
endif

enable interrupt
Resume ' Return to program
goto main

Please note that I have not tested it but it is what I would do given the circumstances. As for DT-INTS what he claimed really is true, once you've used it you'll never want to use ON INTERRUPT again. Yes, it's little bit trickier to use but really not that much. I suggest you look around the forum, there are plenty of examples of how to use it.

/Henrik.

Demon
- 30th December 2014, 03:21
Andy,

Do you have a particular need for USART? Or is this just to start getting familiar with DT Interrupts for whenever you may need them?

Have you been able to get something working?

Robert

Demon
- 30th December 2014, 16:52
Andy,

I've been pulling out my hair since last night trying to get a simple USART communication between 2 PICs (I needed to add it to my current project anyways).

Check this thread I found on Google and who started it:
http://www.picbasic.co.uk/forum/showthread.php?t=17282

I remember things forever, I just have problems recalling the information!

Robert
:D

Archangel
- 30th December 2014, 18:33
Speaking from a position of ignorance, as I have NOT studied the above. This link to serial backpack uses DT_Ints & HSERIN together:
http://www.picbasic.co.uk/forum/content.php?r=171-LCD-serial-backpacks

Demon
- 30th December 2014, 19:36
Andy,

Here's a little something to transmit. I left all the comments in it since I don't know your level of knowledge. I keep these in my programs since I often forget, or leave code on the shelf for year(s).


'--------------------------------------------------------------------'
' Author: Demon '
' Date: Dec 29th, 2014 '
' Project: RESIDENTIAL ALARM SYSTEM '
' Circuit: Master '
' '
' PIC: 18F44K22 @ 64MHz '
' Language: PIC Basic Pro v2.60c '
' Assembler: MPASM v6.49 '
' IDE: MicroCode Studio Plus from Mecanique v2.1.0.7 '
' Programmer: MeLabs USB Programmer v4.32 '
' LCD: CASIL CCM-2040CSL v2.0 (HD44780 parallel interface)'
' '
' All rights reserved. '
' '
' Use of parts of code is permitted as long as credit is given '
' to the author. Code may or may not work, use at your own risk '
' including but not limitted to financial loss, heartbreak and '
' loss of an eye. '
'--------------------------------------------------------------------'

'DEFINE LOADER_USED 1
clear

' ---------------------------- Configuration Fuses -----------------------------
asm
__CONFIG _CONFIG1H, _FOSC_INTIO67_1H & _PLLCFG_ON_1H & _PRICLKEN_OFF_1H & _FCMEN_ON_1H & _IESO_OFF_1H
__CONFIG _CONFIG2L, _PWRTEN_ON_2L & _BOREN_SBORDIS_2L & _BORV_285_2L
__CONFIG _CONFIG2H, _WDTEN_OFF_2H
__CONFIG _CONFIG3H, _CCP2MX_PORTC1_3H & _PBADEN_OFF_3H & _CCP3MX_PORTE0_3H & _HFOFST_OFF_3H & _T3CMX_PORTB5_3H & _P2BMX_PORTC0_3H & _MCLRE_EXTMCLR_3H
__CONFIG _CONFIG4L, _STVREN_OFF_4L & _LVP_OFF_4L & _XINST_OFF_4L & _DEBUG_OFF_4L
endasm

' -------------------------------- Oscillator ----------------------------------
DEFINE OSC 64

' --------------------------------- Includes -----------------------------------
'INCLUDE "DT_INTS-18.bas"
'INCLUDE "ReEnterPBP-18.bas"
'INCLUDE "ReEnterPBP-18LP.bas" ; PBP Re-entry for low priority external interrupt
'INCLUDE "Elapsed_INT-18_64MHz.bas"

' -------------------------------- Interrupts ----------------------------------

'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
' RX must be done manually on Master x
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
;ASM
;----[High Priority Interrupts] ------------------------------------------------
;INT_LIST macro ; IntSource, Label, Type, ResetFlag?
; INT_Handler TMR1_INT, _ClockCount, PBP, yes
; endm
; INT_CREATE ; Creates the High Priority interrupt processor

;----[Low Priority Interrupts] -------------------------------------------------
;INT_LIST_L macro ; IntSource, Label, Type, ResetFlag?

; INT_Handler TMR3_INT, _T3handler, PBP, yes
; endm
; INT_CREATE_L ; Creates the Low Priority interrupt processor
;ENDASM

;DEFINE USE_LOWPRIORITY 1 ' Low priority interrupts

' ------------------------------------ USB -------------------------------------

' --------------------------------- Registers ----------------------------------
OSCCON = %01110000 ' OSCILLATOR CONTROL REGISTER
' bit 7 IDLEN: Idle Enable bit
' R/W 1 = Device enters Idle mode on SLEEP instruction
' 0 = Device enters Sleep mode on SLEEP instruction
' bit 6-4 IRCF<2:0>: Internal RC Oscillator Frequency Select bits(2)
' R/W 111 = HFINTOSC – (16 MHz)
' 110 = HFINTOSC/2 – (8 MHz)
' 101 = HFINTOSC/4 – (4 MHz)
' 100 = HFINTOSC/8 – (2 MHz)
' 011 = HFINTOSC/16 – (1 MHz)(3)
' If INTSRC = 0 and MFIOSEL = 0:
' 010 = HFINTOSC/32 – (500 kHz)
' 001 = HFINTOSC/64 – (250 kHz)
' 000 = LFINTOSC – (31.25 kHz)
' If INTSRC = 1 and MFIOSEL = 0:
' 010 = HFINTOSC/32 – (500 kHz)
' 001 = HFINTOSC/64 – (250 kHz)
' 000 = HFINTOSC/512 – (31.25 kHz)
' If INTSRC = 0 and MFIOSEL = 1:
' 010 = MFINTOSC – (500 kHz)
' 001 = MFINTOSC/2 – (250 kHz)
' 000 = LFINTOSC – (31.25 kHz)
' If INTSRC = 1 and MFIOSEL = 1:
' 010 = MFINTOSC – (500 kHz)
' 001 = MFINTOSC/2 – (250 kHz)
' 000 = MFINTOSC/16 – (31.25 kHz)
' bit 3 OSTS: Oscillator Start-up Time-out Status bit
' R 1 = Device is running from the clock DEFINEd by FOSC<3:0> of the CONFIG1H register
' 0 = Device is running from the internal oscillator (HFINTOSC, MFINTOSC or LFINTOSC)
' bit 2 HFIOFS: HFINTOSC Frequency Stable bit
' R 1 = HFINTOSC frequency is stable
' 0 = HFINTOSC frequency is not stable
' bit 1-0 SCS<1:0>: System Clock Select bit
' R/W 1x = Internal oscillator block
' 01 = Secondary (SOSC) oscillator
' 00 = Primary clock (determined by FOSC<3:0> in CONFIG1H).

OSCCON2 = %00000100 ' OSCILLATOR CONTROL REGISTER 2
' bit 7 PLLRDY: PLL Run Status bit
' R 1 = System clock comes from 4xPLL
' 0 = System clock comes from an oscillator, other than 4xPLL
' bit 6 SOSCRUN: SOSC Run Status bit
' R 1 = System clock comes from secondary SOSC
' 0 = System clock comes from an oscillator, other than SOSC
' bit 5 Unimplemented: Read as ‘0’.
' bit 4 MFIOSEL: MFINTOSC Select bit
' R/W=0 1 = MFINTOSC is used in place of HFINTOSC frequencies of 500 kHz, 250 kHz and 31.25 kHz
' 0 = MFINTOSC is not used
' bit 3 SOSCGO(1): Secondary Oscillator Start Control bit
' R/W=0 1 = Secondary oscillator is enabled.
' 0 = Secondary oscillator is shut off if no other sources are requesting it.
' bit 2 PRISD: Primary Oscillator Drive Circuit Shutdown bit
' R/W=1 1 = Oscillator drive circuit on
' 0 = Oscillator drive circuit off (zero power)
' bit 1 MFIOFS: MFINTOSC Frequency Stable bit
' R 1 = MFINTOSC is stable
' 0 = MFINTOSC is not stable
' bit 0 LFIOFS: LFINTOSC Frequency Stable bit
' R 1 = LFINTOSC is stable
' 0 = LFINTOSC is not stable

OSCTUNE = %11000000 ' OSCILLATOR TUNING REGISTER
' bit 7 INTSRC: Internal Oscillator Low-Frequency Source Select bit
' R/W 1 = 31.25 kHz device clock derived from the MFINTOSC or HFINTOSC source
' 0 = 31.25 kHz device clock derived directly from LFINTOSC internal oscillator
' bit 6 PLLEN: Frequency Multiplier 4xPLL for HFINTOSC Enable bit(1)
' R/W 1 = PLL enabled
' 0 = PLL disabled
' bit 5-0 TUN<5:0>: Frequency Tuning bits – use to adjust MFINTOSC and HFINTOSC frequencies
' R/W 011111 = Maximum frequency
' 011110 =
' • • •
' 000001 =
' 000000 = Oscillator module (HFINTOSC and MFINTOSC) are running at the factory calibrated frequency.
' 111111 =
' • • •
' 100000 = Minimum frequency

PMD0 = %10111111 ' PERIPHERAL MODULE DISABLE REGISTER 0
' bit 7 UART2MD: UART2 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 6 UART1MD: UART1 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 5 TMR6MD: Timer6 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 4 TMR5MD: Timer5 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 3 TMR4MD: Timer4 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 2 TMR3MD: Timer3 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 1 TMR2MD: Timer2 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 0 TMR1MD: Timer1 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power

PMD1 = %11011111 ' PERIPHERAL MODULE DISABLE REGISTER 1
' bit 7 MSSP2MD: MSSP2 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 6 MSSP1MD: MSSP1 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 5 Unimplemented: Read as ‘0’
' bit 4 CCP5MD: CCP5 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 3 CCP4MD: CCP4 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 2 CCP3MD: CCP3 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 1 CCP2MD: CCP2 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 0 CCP1MD: CCP1 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power

PMD2 = %00001111 ' PERIPHERAL MODULE DISABLE REGISTER 2
' bit 7-4 Unimplemented: Read as ‘0’
' bit 3 CTMUMD: CTMU Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 2 CMP2MD: Comparator C2 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 1 CMP1MD: Comparator C1 Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power
' bit 0 ADCMD: ADC Peripheral Module Disable Control bit
' 1 = Module is disabled, Clock Source is disconnected, module does not draw digital power
' 0 = Module is enabled, Clock Source is connected, module draws digital power

ANSELA = %00000000 ' Set ports to digital
ANSELB = %00000000
ANSELC = %00000000
ANSELD = %00000000
ANSELE = %00000000

ADCON0 = %00000000 ' Disable ADC

' ---------------------------------- EUSART ------------------------------------
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
' For MULTIPLE Slaves x
' x
' Do not use USART TX pin for HSEROUT on Slave x
' Use SEROUT at 115200 baud open collector x
' x
' - or - x
' x
' Enable USART TX pin for HSEROUT on Slave x
' Transmit to Master x
' Disable TX pin x
' (my preferred method) x
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

'DEFINE CHAR_PACING 1000
DEFINE HSER_RCSTA 90h ' Enable serial port & continuous receive
DEFINE HSER_TXSTA 24h ' Enable transmit, BRGH = 1
DEFINE HSER_CLROERR 1 ' Clear overflow automatically
DEFINE HSER_SPBRG 138 ' 115200 Baud @ 64MHz, -0,08%

RCSTA = $90 ' Enable serial port & continuous receive
TXSTA = $24 ' Enable transmit, BRGH = 1
SPBRG = 138 ' 115200 Baud @ 64MHz, -0.08%
SPBRGH = 0 ' Baud Rate Generator high byte
BAUDCON.3 = 1 ' Enable 16 bit Baud Rate Generator

' Override switches
'RCSTA1.4 = 0 ' Disable USART RX1 function
'RCSTA2.4 = 0 ' Disable USART RX2 function
'TXSTA1.5 = 0 ' Disable USART TX1 function
'TXSTA2.5 = 0 ' Disable USART TX2 function

' ------------------------------------ LCD -------------------------------------
DEFINE LCD_DREG PORTA
DEFINE LCD_DBIT 0
DEFINE LCD_RSREG PORTE ' Register Select
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTE ' Enable
DEFINE LCD_EBIT 1
DEFINE LCD_BITS 4
DEFINE LCD_LINES 4
'DEFINE LCD_COMMANDUS 1500 ' Set command delay time in microseconds
'DEFINE LCD_DATAUS 50 ' Set data delay time in microseconds

' ------------------------------ Port directions -------------------------------
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
' - From Microchip PIC datasheet in EUSART section - x
' For all modes of EUSART operation, the TRIS control bits corresponding to x
' the RXx/DTx and TXx/CKx pins should be set to ‘1’. The EUSART control will x
' automatically reconfigure the pin from input to output, as needed. x
'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
TRISA = %00000000 ' 0 = output
TRISB = %00000000 ' 1 = input
TRISC = %11000000
TRISD = %00000000
TRISE = %00000000

' ----------------------------------- Ports ------------------------------------
PORTA = %00000000 ' 0 = low (GND)
PORTB = %00000000 ' 1 = high (5V)
PORTC = %00000000
PORTD = %00000000
PORTE = %00000000

' --------------------------------- Constants ----------------------------------
conSlave1 CON 1 ' Slave address
conSlave2 CON 2
conEcho con 69 ' Slave Echo command (Dec 69 = ASCII "E")

' --------------------------------- Variables ----------------------------------
pinTX var PortC.4 ' This pin is used for debugging only

bytLoop var byte ' Loop control
bytAddress var byte ' Slave address
bytCommand var byte ' Slave command

wrdCS var word ' CheckSum

bytBuffer1 var byte[8] ' Data buffers sent to Slave
bytBuffer2 var byte[8]

' ------------------------------- Program start --------------------------------
for bytLoop = 0 to 7 ' Initialize arrays with "fake data"
bytBuffer1[bytLoop] = bytLoop
bytBuffer2[bytLoop] = bytLoop
next bytLoop

pause 500

'@ INT_ENABLE TMR1_INT

goto MainProgram

' -------------------------------- Subroutines ---------------------------------
'T1handler:
' T1CON.0 = 0 ' Stop timer
'@ INT_RETURN

' -------------------------------- Main Program --------------------------------
MainProgram:

Lcdout $fe, 1, "USART sample program"

bytAddress = conSlave1 ' Slave system address
bytCommand = conEcho ' Slave echo command
wrdCS = bytAddress + bytCommand ' Checksum = Address + Command
for bytLoop = 0 to 7 ' Checksum = Checksum + Buffer1 + Buffer2
wrdCS = wrdCS + bytBuffer1[bytLoop]
wrdCS = wrdCS + bytBuffer2[bytLoop]
next bytLoop

pinTX = 1 ' Signal the start of Transmit to Slave PIC
hserout [dec3 bytAddress, dec2 bytCommand, _
str bytBuffer1\8, str bytBuffer2\8, _
dec5 wrdCS.byte1, dec5 wrdCS.byte0]
pinTX = 0 ' Signal the end

Lcdout $fe, $c0, "Addr:", dec3 bytAddress, " Cmd:", dec2 bytCommand
Lcdout $fe, $94, "Buf:", dec1 bytBuffer1[0], dec1 bytBuffer1[1], dec1 bytBuffer1[2], _
dec1 bytBuffer1[3], dec1 bytBuffer1[4], dec1 bytBuffer1[5], _
dec1 bytBuffer1[6], dec1 bytBuffer1[7], _
dec1 bytBuffer2[0], dec1 bytBuffer2[1], dec1 bytBuffer2[2], _
dec1 bytBuffer2[3], dec1 bytBuffer2[4], dec1 bytBuffer2[5], _
dec1 bytBuffer2[6], dec1 bytBuffer2[7]
Lcdout $fe, $D4, "Checksum:", dec5 wrdCS.byte1, dec5 wrdCS.byte0

' goto MainProgram
end

You can comment out the LCD stuff if you don't need it. I use a Saleae probe to see the data on the TX pin. The normal method is to connect to a PC using MAX232 chip (search forum for circuit).

The interrupt is commented out because it is just a placeholder. It is not in working order, it's just there so I remember where I put stuff in my program. I adjust it to my needs when I need it. In this case, we don't need one in the Master.

This shows how the data is sent across the TX line (display is too narrow on laptop).
7619
7620

Robert

Demon
- 30th December 2014, 20:17
The checksum method above is just a basic one, there are many formulas, this was good enough for me.

The code above is a basic structured approach. I try to keep all my "stuff" in the same order, makes it easier for me to find stuff (to copy&paste into new programs). Nothing is forcing you to organize your code, but there are some exceptions (DT_INT must be the first of DT includes). There is also paging issues, but that's advanced stuff. Generally; config fuses at top, then defines, registers, ports, variables, code and then data (it can be anywhere, it's just easier when it's at the bottom of the scroll range - especially when you have LOTS of data statements).

Comments are your friend and take no space.

I don't know how complex your PIC network will be, but the code above gives you a basic design. The Address can be for a single PIC, or a Call-All-PICs address (999 or whatever you want). The Command gives you flexibility in telling the slave what code to execute. The Buffers can be whatever you want (within PBP/PIC limits), mine will be at least 55 bytes. Same with the address and command; they can be whatever format you want.

There are many ways to handle the actual message size. Some send one byte at a time, some send the longest record and let the slave figure out what it needs. Another way is to send a command first, the slave determines which size wil be sent, signals the master to send the data and then waits for it. You transfer less bytes but you do more data transfers; if my buffer lengths vary little, I send it all, if there's a HUGE difference in size, it's worth telling the slave what to wait for.

There's no limit to how complex you can handle communications. I suggest you stick with whatever makes you happy.

(have to get back to my PC, wife doesn't like having parts in the kitchen)

Robert