Любопытний текст. Чтение из USART с буфером по прерываниям. ' PicBasic Pro program to demonstrate an interrupt-driven
' input buffer for Hserin using On Interrupt.
' Pin definitions compatible with LAB-X1 and PIC16F877
' Defines for LCD and USART
DEFINE HSER_RCSTA 90h
DEFINE HSER_TXSTA 24h
DEFINE HSER_BAUD 9600
DEFINE LCD_DREG PORTD
DEFINE LCD_DBIT 4
DEFINE LCD_RSREG PORTE
DEFINE LCD_RSBIT 0
DEFINE LCD_EREG PORTE
DEFINE LCD_EBIT 1
ADCON1 = 7 ' Set PortA and E to digital operation
RCIF VAR PIR1.5 ' Alias RCIF (USART Receive Interrupt Flag)
OERR VAR RCSTA.1 ' Alias OERR (USART Overrun Error Flag)
CREN VAR RCSTA.4 ' Alias CREN (USART Continuous Receive Enable)
LED VAR PORTD.0 ' Alias LED to PORTD.0
buffer_size CON 32 ' Sets the size of the ring buffer
buffer VAR BYTE[buffer_size] ' Array variable for holding received characters
index_in VAR BYTE ' Pointer - next empty location in buffer
index_out VAR BYTE ' Pointer - location of oldest character in buffer
bufchar VAR BYTE ' Stores the character retrieved from the buffer
i VAR BYTE ' loop counter
col VAR BYTE ' Stores location on LCD for text wrapping
errflag VAR BYTE ' Holds error flags
' Initialize variables
index_in = 0
index_out = 0
i = 0
col = 1
Low PORTE.2 ' LCD R/W line low (W)
Pause 100 ' Wait for LCD to start
LCDOut $fe,1 ' Clear LCD
INTCON = %11000000 ' Enable interrupts
ON INTERRUPT GoTo serialin ' Declare interrupt handler routine
PIE1.5 = 1 ' Enable interrupt on USART
' Main program starts here - blink an LED at 1Hz
loop: High LED ' Turn on LED connected to PORTD.0
For i = 0 to 250 ' Delay for .5 seconds (250*2mS)
Pause 2 ' Use a short pause within a loop
Next i ' instead of one long pause
Low LED ' Turn off LED connected to PORTD.0
For i = 0 to 250 ' Delay for .5 seconds (250*2mS)
Pause 2 ' Use a short pause within a loop
Next i ' instead of one long pause
display: ' dump the buffer to the LCD
IF errflag Then error ' Handle error if needed
IF index_in = index_out Then loop ' loop if nothing in buffer
GoSub getbuf ' Get a character from buffer
LCDOut bufchar ' Send the character to LCD
col = col + 1 ' Increment LCD location
IF col > 20 Then ' Check for end of line
col = 1 ' Reset LCD location
LCDOut $fe,$c0,REP " "\20 ' Clear line-2 of LCD
LCDOut $FE,2 ' Tell LCD to return home
EndIF
GoTo display ' Check for more characters in buffer
' Subroutines
Disable ' Don't check for interrupts in this section
getbuf: ' move the next character in buffer to bufchar
index_out = (index_out + 1) ' Increment index_out pointer (0 to 63)
IF index_out > (buffer_size-1) Then index_out = 0 ' Reset pointer if outside of buffer
bufchar = buffer[index_out] ' Read buffer location
Return
error: ' Display error message if buffer has overrun
IF errflag.1 Then ' Determine the error
LCDOut $FE,$c0,"Buffer Overrun" ' Display buffer error on line-2
Else
LCDOut $FE,$c0,"USART Overrun" ' Display usart error on line-2
EndIF
LCDOut $fe,2 ' Send the LCD cursor back to line-1 home
For i = 2 to col ' Loop for each column beyond 1
LCDOut $fe,$14 ' Move the cursor right to the right column
Next i
errflag = 0 ' Reset the error flag
CREN = 0 ' Disable continuous receive to clear overrun flag
CREN = 1 ' Enable continuous receive
GoTo display ' Carry on
' Interrupt handler
serialin: ' Buffer the character received
IF OERR Then usart_error ' Check for USART errors
index_in = (index_in + 1) ' Increment index_in pointer (0 to 63)
IF index_in > (buffer_size-1) Then index_in = 0 'Reset pointer if outside of buffer
IF index_in = index_out Then buffer_error ' Check for buffer overrun
HSerin [buffer[index_in]] ' Read USART and store character to next empty location
IF RCIF Then serialin ' Check for another character while we're here
Resume ' Return to program
buffer_error:
errflag.1 = 1 ' Set the error flag for software
' Move pointer back to avoid corrupting the buffer. MIN insures that it ends up within the buffer.
index_in = (index_in - 1) MIN (buffer_size - 1)
HSerin [buffer[index_in]] ' Overwrite the last character stored (resets the interrupt flag)
usart_error:
errflag.0 = 1 ' Set the error flag for hardware
Resume ' Return to program
End