[PIC] Serial interrupt RX-C7 crashes after sending TX-C6 char PC, in CCS

Status
Not open for further replies.

erpgc82

Junior Member level 1
Joined
Mar 21, 2021
Messages
17
Helped
0
Reputation
0
Reaction score
1
Trophy points
3
Activity points
228
Hello mr's, I'm having a problem here and I'm not able to solve it, I don't know what happens, if it is some bit of some transmission register that I must clear, if it is the serial interrupt that I need to clear clear_interrupts (INT_RDA) ;.
I put delay_ms (1) as a test, after sending the character.
I've done clear_interrupts (INT_RDA); after re-enabling the serial interrupt.
Anyway, I've done everything and nothing works.

Here is just a piece of the code.

Today I can get the string that arrives at the RX (hardware) I do what I have to do with it and send it to the PC via TX (hardware) and it works perfectly.

The response variable, if it is 1 (TRUE) when the PIC reads sensors / input pins, it must send a certain character to the PC, only when doing this the serial interrupt #INT_RDA stops working.

If the response variable is 0 (FALSE), that is, never send characters to the PC, the serial interrupt works perfectly. Note¹: it always stops when a certain number of characters arrives, and then right after a certain function that takes about 5 seconds to occur, the serial interruption is reactivated and this works PERFECTLY.

I'm not getting to know why it hangs / stops after sending a character to the PC. Note¹: Whenever I send a character to the computer, the serial interrupt is activated (at least it was supposed to be) because until then the PIC had not read anything from it and so it was not deactivated.

tanks();


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#include <16F876a.h>
#case                     
#use delay(clock=10000000) 
 
#fuses HS,NOWDT, PUT, BROWNOUT, NOLVP
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, stop=1, ERRORS)
 
int1 returns=1;
char X='X';
char Y='Y';
 
#INT_RDA
void serial_isr()
{
    restartRS232();  // It's unnecessarily here
    int t; 
   
    buffer[next_in]=getc();
    t=next_in;
    next_in=(next_in+1)%BUFFER_SIZE; 
    if(next_in==next_out) next_in=t;   
}
 
BYTE bgetc()
{
    BYTE c;
    while(!bkbhit);
    c=buffer[next_out];
    next_out=(next_out+1)%BUFFER_SIZE;
    return(c);
}
 
void main()
{
    enable_interrupts(GLOBAL);
    enable_interrupts(INT_RDA);
     
     while(TRUE)
    {
            if(bkbhit)
           {
            c=bgetc();
            if(c=='0')
            {
                key_card=TRUE;
                clean_keyboard();
                output_high(BEEP);
                delay_ms(40);
                output_low(BEEP);
                barcode_buffer[0]=c;       
                barcode_buffer[1]=bgetc(); 
                barcode_buffer[2]=bgetc(); 
                barcode_buffer[3]=bgetc(); 
                barcode_buffer[2]=0;       
                printf("%c%c%c%c%c%cC\n\r",barcode_buffer[0],barcode_buffer[1],barcode_buffer[2],barcode_buffer[3]);
                d_int_rda=FALSE;
                disable_interrupts(INT_RDA);
                read_code();
            }
             /*******************************************************************************************/
             if((returns)&&(!input(SENSOR_OUT))) printf("%c\r\n",X);
             if((returns)&&(!input(SENSOR_IN)))    printf("%c\r\n",Y);             
        }
    }
}

 

I think we need to know more about the variables you are using. For example what type is 'int1', 'bkbhit', 'bgetc' and 'returns'?
Should barcode_buffer[2] really have zero in it? It would work as a string terminator.
Should you 'disable_interrupts(INT_RDA), whatever that is , without re-enabling it again somewhere?

There seems to be a lot of code missing.

Brian.
 

    eagle1109

    Points: 2
    Helpful Answer Positive Rating
Hi,

Your not documented code makes it difficult for us to understand what the instructions do.

Klaus
 


Hi Brian;
int1 is a 1 bit variable, short int, in CCS
bkbhit is a function that takes the characters from the INT_RDA serial interrupt and sends to the while, the bkbhit function along with what occurs while is a buffer (variables in a circle).
returns is a name I put, it returns (actually sends) YES or NO characters to the software on a PC.

I'll edit the code and put more information, I understood that only a piece would help those who could help me!
--- Updated ---


Code C - [expand]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
[TABLE]
[TR]
[TD]#include <16F876a.h>
#case
#use delay(clock=10000000)
 
#fuses HS,NOWDT, PUT, BROWNOUT, NOLVP
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, stop=1, ERRORS)
 
#include "display_8bits16f876.c"
 
#define BEEP        PIN_A2
#define SENSOR_IN   PIN_A3
#define SENSOR_OUT  PIN_A4
#define bkbhit      (next_in!=next_out)
BYTE  next_in                 = 0;
BYTE  next_out                = 0;
BYTE  buffer                    [BUFFER_SIZE];
int8  barcode_buffer            [10];
 
int1  returns     = 1; // short int returns=TRUE; // Checks whether to send characters to the PC software
int1  time_Td     = 0; // Checks whether to enter the time count
int1  d_int_rda   = 0; // checks if the serial interrupt is disabled
int1  msg_default = 0; // checks whether to display the standard message on the LCD 
int8  code        = 0;
char X='X';
char Y='Y';
 
void restartRS232();
void msg_Default();
 
#INT_RDA
void serial_isr()
{
   restartRS232(); // It's unnecessarily here
   int t;
 
   buffer[next_in]=getc();
   t=next_in;
   next_in=(next_in+1)%BUFFER_SIZE;
   if(next_in==next_out) next_in=t;
}
 
BYTE bgetc()
{
   BYTE c;
   while(!bkbhit);
   c=buffer[next_out];
   next_out=(next_out+1)%BUFFER_SIZE;
   return(c);
}
 
void main()
{
   enable_interrupts(GLOBAL);
   enable_interrupts(INT_RDA);
   setup_timer_0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256);
   setup_timer_1(T1_DISABLED);
   set_timer0(11);   
   display_ini();
 
   while(TRUE)
   {
        if(d_int_rda)   // check if it is to re-enable the interruption and if it is true, re-enable
        {
            enable_interrupts(INT_RDA); /* Without considering, that the function enable_interrupts (INT_RDA);
                                         * already starts in main (), but if it is disabled, then re-enable*/                                         
            delay_ms(1);
            d_int_rda=FALSE;
        }
        
        if(!msg_default) msg_Default(); // if you are not displaying the default message, then display
       
        if(time_Td)  
        {
            if(tmr0if) 
            {
                tmr0if=0;      
                set_timer0(11); // initializes timer0
                code++;      // increments the variable that will define the time that the code will be displayed on the LCD
            }
        }        
        if(code>=200) 
        {
            tmr0if=0;                      
            code=0;
            msg_Default();  // After a XX time displaying the characters on the LCD, it then returns to the standard message        
        }                   /**************************************************
                             * It turns out that, if the situations have not occurred:
                             * if ((returns) && (! input (SENSOR_IN))) printf ("% c \ r \ n", Y);
                             * or
                             * if ((returns) && (! input (SENSOR_OUT))) printf ("% c \ r \ n", X);
                             * the serial interrupt works again, and the characters are received.
                             * 
                             * But if you receive an electric pulse on the corresponding pin and the
                             * interruption is disabled, when the "d_int_rda" flag returns to re-enable
                             * the serial interruption, calling the enable_interrupts (INT_RDA)
                             * function, nothing happens, it does not receive any more characters.
                             * Then, making only the flag returns to 0 or FALSE, so as not to receive
                             * any more electrical pulse, then the interruption will work again, being
                             * disabled and re-enabled normally.*/
           
       if(bkbhit)     /* Next to INT_RDA and bgetc () it takes the characters it stores in 
                      * a character array. Circular buffer.*/
       {
         c=bgetc();
         if(c=='0')       
         {  
            output_high(BEEP);
            delay_ms(40);
            output_low(BEEP);
            barcode_buffer[0]=c;
            barcode_buffer[1]=bgetc();
            barcode_buffer[2]=bgetc();
            barcode_buffer[3]=bgetc();
            barcode_buffer[2]=0;
            printf("%c%c%c%c%c%cC\n\r",barcode_buffer[0],barcode_buffer[1],barcode_buffer[2],barcode_buffer[3]);
            d_int_rda=FALSE;       /* Disables the standard message, and displays the numbers read on the LCD. 
                                    * I did not put the function of displaying the codes read on the LCD here,
                                    * as I thought it was unnecessary not to get too long the code*/
            disable_interrupts(INT_RDA); /* I disable the serial interrupt, so that I don't receive 
                                          * another character while doing certain situations or commands.*/
            read_code();            // This function displays the received code on the LCD display, it is 4 characters.          
         }
/*******************************************************************************************/
         if((returns)&&(!input(SENSOR_OUT))) printf("%c\r\n",X);  /* if returns are true, and receive an electrical pulse
                                                                   * on the SENSOR_OUT pin, send an X character to the PC software*/
         if((returns)&&(!input(SENSOR_IN))) printf("%c\r\n",Y);   /* if returns are true, and receive an electrical pulse 
                                                                    * on the SENSOR_IN pin, send a Y character to the PC software*/
      }  
   }
}
 
void restartRS232()           /* Error checking routine, call it at the beginning of the interrupt function: See example below.
                               * But it hasn't solved anything*/
{
   if (OERR || FERR) // RS232 Error Handling  
   {                 // Reset / Clear errors in reception usart
      SPEN = 1;
      CREN = 0;
      delay_us (1);
      CREN = 1;
      delay_us (1); 
      return;
   }
}
 
void msg_Default() 
{                   
    if(!msg_default)      msg_default = TRUE;   // checks if the default message is disabled and then enables
    if (!d_int_rda)       d_int_rda = TRUE;     // checks if the serial interrupt is disabled and re-enables
     
    // write these messages and go back to the while 
    printf(write_display,"\f>>>>  Test  <<<<");
    printf(write_display,"\n>>    Ready   <<");
    return;
}
 
[/TD]
 
[TD]
[/TD]
[/TR]
[/TABLE]


--- Updated ---

Observation. the time_td variable is reported as true (1) within the read_code () function as this function only displays the code on the LCD display and returns to the while, then makes contact and then returns to the standard message, and automatically enabling the enable_interrupts function (INT_RDA);

I also tried before rehabilitating using the function
clear_interrupts (INT_RDA); but it's no use, the problem is sending a simple character "printf (" X ");" and the interruption doesn't work again.
--- Updated ---

would the transmit register be locking the receive register?

I'm new to programming, sorry for the ignorance.
--- Updated ---

Hi,

Your not documented code makes it difficult for us to understand what the instructions do.

Klaus


hello Klaus, I just put a piece of code so it doesn't get too long, I'm a programming apprentice, but I've already made a code that works perfectly on a pic16f876, and I'm using 66% of this pic.
With the exception of this situation, it does not reactivate INT_RDA (serial interruption). See that I edited the code, and improved it, but still there are the main commands.
 
Last edited:

hello,


in void restartRS232()
you must also read the UART RX register (=> empty buffer) to clear the error
Frame error or Overrun error are blocking status if not cleared.
 

In addition to showing the faulty code, you should say what it is supposed to do.
There are many instructions spread inline which surely could be enclosed into specific functions.
 

I just tested here, and the problem is not even the interruption, now I have NEVER set the serial interruption to be disabled, and even so, when sending any character eg: printf ("x") to the pc / software the interruption stops to work, I really don’t know what’s going on, I’ll put that aside and then come back, because I need to send characters to the pc / software.
 

Friends, I managed to find where the error was, after 1 week suffering from it.

This is very good to learn

I was doing the directives
#use fast_io (c)

then in main ()
{
set_tris_c (0b00000000); // all pins as output
output_c (0b00000000); // all pins at 0V
}

and just now I thought, the TX and RX pins are from the portC and if that is the problem?

but the use of rom increased considerably in percentage%.

so i commented the lines and the problem disappeared, now i can send characters to the pc (serial monitor) normally, which does not lock the serial interrupt.
 

If the code is for you and you have developed it yourself, then there should be some bugs.

A good strategy, is to download a good well coded library and test it, if the project runs well, then you should search for the bugs in your code.

I think the microchip code configurator can produce a good documented code for what you want.
 

Status
Not open for further replies.

Similar threads

Cookies are required to use this site. You must accept them to continue using the site. Learn more…