Menu

Interrupt on serial port

Help
jackjames
2018-01-13
2022-06-20
  • jackjames

    jackjames - 2018-01-13

    I'm writing a program for a programmable thermostat via radio that can interface to my home automation system.
    I use a PIC16F1847 with a 32 MHz internal clock.
    I found problems using the interrupt on the serial port.
    I use both the i2c bus and the serial port and I had to re-program the pins for this function.
    Not using the interrupt the reading and writing do not give any problem.
    Instead, using the interrupt, it seems that the program just crashes on this interrupt routine and no longer goes out.
    I wrote a small piece of code to perform functional tests.
    The LED inserted in the interrupt routine flashes when a character is received, but the control does not return to the main.
    Probably I'm wrong in something ...

    I enclose the test program

    '       $formattagcb
    
    '
    '       Test program for read interrupt on the serial port.
    
            #option explicit
    
            #Chip 16F1847, 32
            #Config OSC = INT, MCLR_OFF ', PLLEN_ON
    
            #Include <DS3231.H>
            ConfigPins
    '
    '       ---------------------------------------------------------------
    '       Preparazione degli interrupts
    '       ---------------------------------------------------------------
    '       ---> Timer1 non più usato NOT USED NOW
    '       On Interrupt Timer1Overflow Call INT_Tmr1Overflowed
    '       -
    '       ---> Arrivo dati sulla porta seriale
            On Interrupt UsartRX1Ready  Call INT_Serial
    '       -
    '       ---> Interrupt on portB.0. One second pulse
    '       INTEDG= Interrupt Edge Select bit
    '       1 = Interrupt on rising edge of INT pin
    '       0 = Interrupt on falling edge of INT pin
            INTEDG = 1
            INTCON.3 = 1  '  IOCE(3) not defined. Abilita Interrupt
    '       Enable portb.0 as the source of the interrupt.
    '       See the datasheet for more information.
            IOCBP.IOCBP0 = 1
    '       On Interrupt PORTBChange Call INT_UnSecondo
    
            #Define USART_BAUD_RATE 2400
            #Define USART_TX_BLOCKING
    '       #Define USART_DELAY 5 ms
    '       #Define USART_BLOCKING
    
    '       Define I2C settings SOFTWARE
    '       #Define I2CMODE Master
    '       #Define I2C_BAUD_RATE 400
    '       #Define I2C_DATA PORTB.1
    '       #Define I2C_CLOCK PORTB.4
    '       #Define I2C_DISABLE_INTERRUPTS On
    
    '       OK values ??for the DS3231.
    '       If missing values, the reading stops responding.
    '       #Define I2C_BIT_DELAY   20 us     ' width of Data Bit On SDA
    '       #Define I2C_CLOCK_DELAY 10 us     ' width of clock pulse On SCL
    '       #Define I2C_END_DELAY   10 us     ' interval between clock pulses
    
    '       Define I2C settings
            #Define HI2C_BAUD_RATE 400
            #Define HI2C_DATA PORTB.1
            #Define HI2C_CLOCK PORTB.4
    '       I2C pins need to be input for SSP module when used on Microchip PIC device
            Dir HI2C_DATA In
            Dir HI2C_CLOCK In
    
    '       MASTER MODE
            HI2CMode Master
    
    '       LCD I2C
            #Define LCD_IO 10                 ' This is required!
            #Define LCD_I2C_ADDRESS_1 0x4e    ' Default = 0x4e
            #Define LCD_SPEED FAST            ' Defaults is FAST
            #Define LCD_BACKLIGHT_ON_STATE  1 ' type 10 LCD
            #Define LCD_BACKLIGHT_OFF_STATE 0 ' type 10 LCD
    
    '       Altri pins
            #Define PIN_TASTIERA  PORTA.0       ' AN0 Tastiera 6 tasti
            #Define P_TEMP_ARIA   AN6 ' PORTB.7       ' AN6 Sensore lettura temperatura Aria
            #Define P_TEMP_ACQUA  AN5 ' PORTB.6       ' AN5 Sensore lettura temperatura Acqua
            #Define P_RELE        LATB.3        ' Relè On/Off fancoil
            #Define LED_TASTIERA  LATA.2        ' Led sulla tastiera
            #Define BUZZER        PORTA.4       ' BUZZER attivo
            #Define SOUNDOUT      BUZZER
    
    '       Relè di utilizzo vario comandati via radio
            #Define RL1           LATA.1        ' Primo relè general purpose
            #Define RL2           LATA.6        ' Secondo relè general purpose
            #Define HC12_SET_PIN  LATA.7    ' Pin per il settaggio dell'HC12
    
            Dim Tmp        As Byte
            Dim Cnt        As Byte
            Dim Ora        As Byte
            Dim Minuti     As Byte
            Dim Secondi    As Byte
            Dim MOra       As Byte
            Dim MMinuti    As Byte
            Dim bLedOn     As Bit
            Dim bSerial    As Bit
            Dim bOneSecond As Bit
    
    '       ===============================================================
    '       Direzione out delle porte relative al led e ai relè.
    '       Non serve ma necessario perchè altrimenti il
    '       compilatora da un errore.
    '       ---------------------------------------------------------------
            Dir PORTA.1 Out ' RL1
            Dir PORTA.2 Out ' LED
            Dir PORTA.4 Out ' BUZZER
            Dir PORTA.6 Out ' RL2
            Dir PORTA.7 Out ' HC_12 Set pin
            Dir PORTA.3 In  ' VRef
    
            Dir PORTB.0 In  ' 1Hz dal DS3231
            Dir PORTB.6 In  ' T. Acqua
            Dir PORTB.7 In  ' T. Aria
    '       ---------------------------------------------------------------
    
    '       Imposta gli ingressi
            Dir PIN_TASTIERA In
            Dir P_TEMP_ARIA  In
            Dir P_TEMP_ACQUA In
    
    '       Pin porta seriale
            Dir PORTB.5 Out
            Dir PORTB.2  In
    
    main:
            IntOn
            Do ForEver
               If bSerial Then
                  bSerial = FALSE
                  HSerSend Tmp
               Else
                  IncCnt
               End If
            Loop
    
    Sub IncCnt
            Cnt ++
            HSerPrint "Cnt="
            HSerPrint Cnt
            HSerSend 13
            HSerSend 10
            Wait 200 ms
    End Sub
    
    Sub INT_Serial
            If PIR1.RCIF Then
               Tmp = HSerReceive
               If LED_TASTIERA Then
                  LED_TASTIERA = FALSE
               Else
                  LED_TASTIERA = TRUE
               End If
               bSerial = TRUE
               PIR1.RCIF = 0
            End If
    End Sub
    
    '       ===============================================================
    '       Serial port and I2C port configuration
    '       Uscite così configurate:
    '       RB1 --> SDA1
    '       RB2 --> RX usart
    '       RB4 --> SCL1
    '       RB5 --> TX usart
    '       ---------------------------------------------------------------
    Sub ConfigPins
            APFCON0.SDO1SEL = 1 ' 0 = SDO1 Function is On RB2 , 1 = SDO1 Function is On RA6
            APFCON0.SS1SEL  = 1 ' 1 = SS1 Function is On RA5
            APFCON0.RXDTSEL = 1 ' 1 = RX/DT Function is On RB2
            APFCON1.TXCKSEL = 1 ' RB5 As TX UART
            BAUDCON.WUE     = 1 ' Wake-up Enable Bit  0 = Receiver is operating normally
            CPSCON0         = 0 ' CAPACTIVE SENSE Module Off
    End Sub
    
     
  • stan cartwright

    stan cartwright - 2018-01-15

    where's On Interrupt PORTBChange Call INT_UnSecondo if that's the prob? I cannot see the interrupt sub.

     
  • mmotte

    mmotte - 2018-01-16

    I am looking why The serial interrupt don't return from the receive sub, but i haven't found it yet.

    One problem is :

     PIR1.RCIF = 0
    

    " The RCIF interrupt flag bit is read-only, it cannot be set or cleared
    by software." off of the Data Sheet. Please remove the "PIR1.RCIF = 0".

    On Interrupt UsartRX1Ready  Call INT_Serial
    

    looks right. "UsartRX1Ready" is defined in the PIC16F1847.dat file and the compiler must set the RCIE to enable it and check the RCIF to trip the interrupt.

    Do you really need the

    If PIR1.RCIF Then
    

    if you already were sent here to get a byte from the RCREG ?
    And actually the HSerReceive does one more checking of the RCIF even though it is disguissed as USARTHasData. So please remove the " If PIR1.RCIF Then... End If"

     If USARTHasData Then
                SerData = RCREG
              End if
    

    Could you try changing
    Tmp = HSerReceive
    to
    Tmp = HSerReceive1
    ?
    Every now and again we have trouble with compiler not remembering the default is Comport =1.

    I don't have a 16F1847 to try this on .

    I'll see if anything else pops into mind.
    BR
    Mike

     
  • jackjames

    jackjames - 2018-01-16

    Thanks for the advices
    Tomorrow, when I return home, I will try to make the changes recommended by you.

    The code I entered is only part of a more complex program that also uses an RTC and a display connected in I2C mode.
    The routinte INT_UnSecondo (here not used) serves to have a clock every second and this impulse is given by the DS3231
    This part of the program inserted in the forum, however, works and the above mentioned problems occur.

    Sub INT_Serial_OK
    Tmp = HSerReceive
    HSerSend Tmp
    End Sub

    This routine works perfectly, but never goes out and the control does not return me to the 'main'.
    The information arriving from the serial port, not cyclically, must be processed in order to decide which operations to perform, therefore, if the control does not return to the 'main', commands received can not be performed.

    Thanks again.
    Giacomo

     
  • jackjames

    jackjames - 2018-01-17

    @mmote:
    No way !
    I made the changes you suggested but practically nothing has changed.
    I'm starting to think it's a problem due to RX redirection from RB1 to RB2 so I can use the I2C hardware module.

    Does anyone have any ideas?

     
  • stan cartwright

    stan cartwright - 2018-01-17

    ok,no idea what the prog does but
    "I wrote a small piece of code to perform functional tests.
    The LED inserted in the interrupt routine flashes when a character is received, but the control does not return to the main.
    Probably I'm wrong in something ..."
    Does not return to the main...where's it go then?

     
  • jackjames

    jackjames - 2018-01-17

    Here is the main:

            IntOn
            Do ForEver
               If bSerial Then
                  bSerial = FALSE
                  HSerSend Tmp
               Else
                  IncCnt
               End If
            Loop
    

    So if the control returns to the main and the 'bSerial' flag is set in the interrupt routine, the 'Tmp' value must be transmitted from the serial to the terminal. This does not happen.

     
  • stan cartwright

    stan cartwright - 2018-01-17

    Do interrupts,seems 2 cause probs?
    Is an interrupt re happening?
    sorry,just a thought. and re mappable 16fxx is new to me

    Sub IncCnt
            Cnt ++
            HSerPrint "Cnt="
            HSerPrint Cnt
            HSerSend 13
            HSerSend 10
            Wait 200 ms
    End Sub
    
     
  • jackjames

    jackjames - 2018-01-18

    The sub 'IncCnt' only serves to have a visual indication that the main loop is running.
    It seems that the interrupt routine takes over even before the interrupt condition occurs.
    I tried to insert an 'HSerPrint "HELLO!"' Statement before the loop and this instruction is not executed.
    Actually I can not understand anything.

     
  • stan cartwright

    stan cartwright - 2018-01-18

    I had probs with 2 interrupts so turned 1 off and then on after something like pulsin. Could be like interrupt at wrong time..dunno. I fake stuff when de bugging ie simulate event.

     
  • jackjames

    jackjames - 2018-01-19

    This weekend I have some free time and I think I'll play a bit.
    I also checked the assembler source but it seems all right.

     
  • jackjames

    jackjames - 2018-02-05

    This is the problem I encountered and I can not answer.
    When the data is received from the serial port, the interrupt routine is called up correctly.
    If I read the data inside the routine it ends correctly, but if I set the flag for a following reading outside of the routine it does not end and remains locked.

     
  • Chris Roper

    Chris Roper - 2018-02-05

    Unless you read the serial port the Interrupt flag is still set, so when you leave the Interrupt Routine it immediately retriggers the interrupt, and the outward appearance is that the program has hung, when it is actually just stuck in a loop.

    Cheers
    Chris

     
  • jackjames

    jackjames - 2018-02-05

    In fact I thought about it too, but PIR1.RCIF is read only, so it is not possible to reset it ...
    I solved by reading only the first character from the interrupt routine and then following the reading elsewhere by checking in a loop PIR1.RCIF and, if set, reading with HSerReceive.

     
  • Jon Nelson

    Jon Nelson - 2022-06-17

    Great Cow Basic PIC16F1847 UART code examples are hard to find but the above thread proved closest. The code below is adapted from that above and echoes characters back to the terminal.
    We did not find RCIF needed checking in the main loop, as suggested immediately above, as the interrupt seems to work as intended. Improvements are most welcome ;-)
    Compiler version used was Great Cow BASIC (0.98.<<>> 2021-<<>>-24 (Linux 64 bit) : Build 1005).
    Use on command line: $ gcbasic /A:GCASM PIC16F1847uartJackJames.gcb
    The PIC was programmed using a PICkit3 and MPLAB IPE v6.00

    '  Test program for read interrupt on the serial port using UART on PIC16F1847.
    'Adapted from https://sourceforge.net/p/gcbasic/discussion/579126/thread/88f6e6de/
    'to include suggestions.
    'Type in a character, it is incremented and echoed back to the terminal. e.g. a returns b etc
    'The LED toggles on every character input. 
    'The LCD is not doing much but kept as in the original, it may be useful if nothing appears on the terminal.
    'DS41453B http://ww1.microchip.com/downloads/en/devicedoc/41453b.pdf PIC16F1847 manual
    '  Note: UART output here is to a MAX483 hence SCKP is set for TX and a transistor inverts received
    'serial from the MAX483. Both inverts likely not needed if a MAX232 was used instead.
    'The MAX483 is connected via twisted pair to a RS-485/USB convertor then into a PC terminal e.g. CuteCom
    
    #option explicit
    #Chip 16F1847, 8 'MHz
    #Config OSC = INT, MCLR_OFF
    
    '#Include <DS3231.H> 'Cannot find /opt/GCBASIC/include//DS3231.H
    '#Include "/opt/GCBASIC/include/ds3231.h" 'This worked but not needed
    ConfigPins
    '       ---------------------------------------------------------------
    '       Preparazione degli interrupts
    '       ---------------------------------------------------------------
    '       ---> Arrivo dati sulla porta seriale
    On Interrupt UsartRX1Ready Call INT_Serial
    
    #Define USART_BAUD_RATE 9600 'was 2400
    #Define USART_TX_BLOCKING
    
    ;LCD I2C
    #Define LCD_IO 10                 ' This is required!
    #Define LCD_I2C_ADDRESS_1 0x4e    ' Default = 0x4e
    #Define LCD_BACKLIGHT_ON_STATE  1 ' type 10 LCD
    #Define LCD_BACKLIGHT_OFF_STATE 0 ' type 10 LCD
    
    ; ----- Define Hardware settings imported
    ' Define I2C settings - CHANGE PORTS
    #define I2C_MODE Master
    #define I2C_DATA PORTB.1 'SDA
    #define I2C_CLOCK PORTB.4 'SCL
    #define I2C_DISABLE_INTERRUPTS ON
    'Optionally, you can reduce the I2C timings.
    #define I2C_BIT_DELAY 0 us
    #define I2C_CLOCK_DELAY 1 us
    #define I2C_END_DELAY 0 us
    
    #Define LED_TASTIERA  LATA.0        ' was LATA.2 Led sulla tastiera, was on PortA.2
    
    'http://ww1.microchip.com/downloads/en/devicedoc/41453b.pdf DS41453B-page 300 
    SCKP = 1 'Asynchronous mode, Transmit inverted data to the TX/CK pin  
    
    Dim Tmp        As Byte
    Dim Cnt        As Byte
    Dim bSerial    As Bit
    
    Dir PORTA.0 Out ' LED LED_TASTIERA was PORTA.2
    'Dir PORTB.5 Out 'TX (not needed here, see SPEN)
    Dir PORTB.2  In 'RX
    
    'DS41453B-page 291 TX and DS41453B-page 296 RX (NB GCB attends to the six below)
    'TXSTA.SYNC = 0 'Async mode
    'RCSTA.SPEN = 1 'Enable the serial port and automatically configures the TX/CK I/O pin as an output
    'TXSTA.TXEN = 1 'Transmit enable
    'PIE1.RCIE = 1 'For RX interrupt
    'INTCON.GIE = 1 'For RX interrupt
    'INTCON.PEIE = 1 'For RX interrupt
    
    ;Below if 1 enables MAX483
    #Define MAX483ENABL PORTb.3
    Dir MAX483ENABL Out
    
    main:
      CLS
      LCDBacklight ON
      Print "Hi LCD"
      MAX483ENABL = 1 ;Enable MAX483 TX
      HSerPrint "Hello PIC16F1847 UART"
      HSerSend 13
      HSerSend 10
      MAX483ENABL = 0 ;Disable MAX483 TX on startup
      bSerial = FALSE ;initialise
    
      IntOn
      Do ForEver
          If RCSTA.OERR = 1 then
            'Receive Overrun Error
            RCSTA.SPEN = 0 'DS41453B-page 295
          End If
          If bSerial Then
            bSerial = FALSE
            MAX483ENABL = 1 ;Enable MAX483 TX
            HSerSend Tmp+1 'Send a from PC get b echoed back etc
            MAX483ENABL = 0 ;Disable MAX483 TX
          End If
          'Wait 200 ms 'slows output down as IncCnt did
      Loop
    
    Sub INT_Serial
      Tmp = HSerReceive1 'mmotte advice
      LED_TASTIERA = !LED_TASTIERA 'Toggle LED state
      bSerial = TRUE 'Tell main a character came in 
    End Sub
    
    '       =============================================
    '       Serial port and I2C port configuration
    '       Uscite così configurate:
    '       RB1 --> SDA1
    '       RB2 --> RX usart
    '       RB4 --> SCL1
    '       RB5 --> TX usart
    '       ----------------------------------------------
    Sub ConfigPins
      APFCON0.RXDTSEL = 1 ' 1 = RX/DT Function is On RB2
      APFCON1.TXCKSEL = 1 ' RB5 As TX UART
      BAUDCON.WUE     = 1 ' Wake-up Enable Bit  0 = Receiver is operating normally see DS41453B-page 300
      CPSCON0         = 0 ' CAPACTIVE SENSE Module Off
    End Sub
    
     

    Last edit: Jon Nelson 2022-06-18
  • Anobium

    Anobium - 2022-06-20

    Nice program - thank you for posting. I will publish as a demo - all credit to you.


    Feedback.

    #CONFIG OSC = INT, MCLR_OFF not needed as the compiler has these as the defaults. See PICINFO for the config defaults for all chips.
    ConfigPins the registers are not required, As Great Cow BASIC uses a unique identifier for every register / register.bit therefore the register suffix is not required.


    See you demo here. https://github.com/GreatCowBASIC/Demonstration_Sources/blob/main/Interrupt_and_Timer_Solutions/Interrupt_Serial_examples/PIC16F1847_UART.gcb You can login into GitHub and edit online if you want to update/change.


    Thank you,

     

    Last edit: Anobium 2022-06-20

Log in to post a comment.

Want the latest updates on software, tech news, and AI?
Get latest updates about software, tech news, and AI from SourceForge directly in your inbox once a month.