|
|
View previous topic :: View next topic |
Author |
Message |
erpgc82
Joined: 02 May 2020 Posts: 73
|
PIC16F876a difficulty getting string of characters serial |
Posted: Mon Feb 15, 2021 12:07 pm |
|
|
Hello friends, I am a PIC programming apprentice with CCS.
I've already learned a lot, I'm managing to make several codes with pins, ports, display. This activity that I'm doing now is making me anxious.
"What I thought was easy, take characters that arrive at Serial Hardware (RX) and send them to the computer (tx),
it has become a nightmare, I have been testing dozens of codes for over a week, I already understand the logic, but I can't do it. In other words, I didn't understand. "Laughs
I studied several codes of the CCS forum, saw about the creation of buffer #device buffer_size 8, I thought it was my solution.
Okay, so I decided on serial interruption.
But why is it so hard? I've done so many things with C programming for PIC I was happy, now I am distressed because I can't make it work.
Code: |
// My 1st code, without interruption:
#include <16F876a.h> // directive that defines the pic to be used
#use delay(clock=10000000) // frequency for calculations and delays
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP // fuses for bit setting
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, errors) // directive for serial communication function
#bit SPEN=0x18.7
#bit CREN=0x18.4
#bit FERR=0x18.2
#bit OERR=0x18.1
#bit RCIF=0x0c.5 // 1 the buffer is full, 0 the buffer is empty
#BYTE RCREG=0x1a // monitor the reception recorder
#define buffersize 8
#include "display_8bits16f876.c"
char rec[8];
int i=0;
void main()
{
// enable_interrupts(GLOBAL);
// enable_interrupts(INT_RDA); // start receiving interrupt handling
display_ini();
while(TRUE)
{
printf(write_display,"\fRRG:%d rif:%d ",rcreg,rcif); // displays the contents of RCREG and RCIF, in the first line of the display
printf("%s",rec); // sends the contents of the rec array in string format to the computer.
printf(write_display,"\n%s",rec); // displays the content of the string on the second line of the display
}
} /* took the code that I passed 000102B and played it on the serial monitor I'm using.
Remembering that I pass a barcode reader, a 6 digit card, example 000456, this reader sends the serial code TTL through its RX the code 000456B. So I just wanted to take this code in the RX of the 16F876 and send it to the computer, write the content on the display. The only content I can get on the display, is the value 13 in decimal on the first line of the display, which must be the content of the RCREG, I believe it is 13 in the ASCII table that is equivalent to \ r ie, carriage return. But why is the only code I receive when monitoring RCREG 13? */
|
Code: |
// My 2st code, with interruption:
#include <16F876a.h> // directive that defines the pic to be used
#use delay(clock=10000000) // frequency for calculations and delays
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP // fuses for bit setting
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, errors) // directive for serial communication function
#bit SPEN=0x18.7
#bit CREN=0x18.4
#bit FERR=0x18.2
#bit OERR=0x18.1
#bit RCIF=0x0c.5 // 1 the buffer is full, 0 the buffer is empty
#BYTE RCREG=0x1a // monitor the reception recorder
#define buffersize 8
#include "display_8bits16f876.c"
int i=0;
char code[8];
#int_rda
void usart(void)
{
for(i=0; i<=8; i++)
{
code[i]=""; // oddly enough, assigning an empty character to each increment made something work.
}
gets(code);
if(code[6]=='B')
{
printf("%c%c%c%c%c%c\r\n",code[0],code[1],code[2],code[3],code[4],code[5]);
}
}
void main()
{
while(TRUE);
} /* this 2nd example, even sends the read code to the serial monitor, 001572B but it locks the pic, to the point of having to re-record the pic, I even have to re-record several times and several times the pic, until it works again. */
|
Code: |
// My 3st code, with interruption:
#include <16F876a.h> // directive that defines the pic to be used
#use delay(clock=10000000) // frequency for calculations and delays
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP // fuses for bit setting
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, errors) // directive for serial communication function
#bit SPEN=0x18.7
#bit CREN=0x18.4
#bit FERR=0x18.2
#bit OERR=0x18.1
#bit RCIF=0x0c.5 // 1 the buffer is full, 0 the buffer is empty
#BYTE RCREG=0x1a // monitor the reception recorder
#define buffersize 8
#include "display_8bits16f876.c"
int i=0;
char code[8];
#int_rda
void usart(void)
{
for(i=0; i<=8; i++)
{
code[i]="";
}
for(i=0; i<8; i++)
{
gets(code[i]);
}
if(code[6]=='B')
{
printf("%c%c%c%c%c%c\r\n",code[0],code[1],code[2],code[3],code[4],code[5]);
i=0;
}
}
// this I will post only the while(TRUE)
while(TRUE)
{
printf(write_display,"\f%d",RCREG);
printf(write_display,"\n%d",RCIF);
}
// This 3rd code, reads, writes the 13 on the display, where RCREG is, it does not lock, but the PIC resets at the same time
|
Code: |
// My 4st code, with interruption:
#include <16F876a.h> // directive that defines the pic to be used
#use delay(clock=10000000) // frequency for calculations and delays
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP // fuses for bit setting
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8, errors) // directive for serial communication function
#bit SPEN=0x18.7
#bit CREN=0x18.4
#bit FERR=0x18.2
#bit OERR=0x18.1
#bit RCIF=0x0c.5 // 1 the buffer is full, 0 the buffer is empty
#BYTE RCREG=0x1a // monitor the reception recorder
#define buffer_sz 8
#include "display_8bits16f876.c"
char code[BUFFER_SZ];
int next_in=0;
int temp;
int flag=0;
int i;
#int_rda
void rda_isr(void)
{
{
temp=getc(); // get the character received and thus clear the interrupt flag
code[next_in]=temp; // moves the received character to the appropriate location in the buffer increment input pointer
if(next_in == BUFFER_SZ-2) // if we have 7 characters, go back to 0
{
next_in=0;
}
}
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256);
setup_timer_1(T1_DISABLED);
set_timer0(11); // timer 0 starting at 11, prescaler dividing by 256, to have 25.0880000 milliseconds
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
setup_adc(ADC_OFF);
setup_comparator(NC_NC_NC_NC);
set_tris_a(0b00110110);
set_tris_c(0b00000000);
output_c(0b00000000);
display_ini(); // initializes the display
while(TRUE)
{
////////////////////////////////////////////////////////////////////
////// Standard Display Message //////////////////////////////////
printf(write_display,"\f%d - %d",RCREG,RCIF);
////////////////////////////////////////////////////////////////////
if(flag)
{
printf("%s",code);
printf(write_display,"\n%s",code);
delay_ms(2000);
flag=0;
}
delay_ms(50);
}
} /*This 4th example, when the code arrives at the RX, it only displays the code 13 in the RCREG does not reset and does not lock, but also does not send anything via the serial and does not show anything on the display.*/
|
Please, I don't know what else to do to be able to capture these incoming codes.
They will always be with 7 fixed digits.
123456B
so I created an array of characters
char code [8]
or
#define buffer_sz 8
char code [buffer_sz]
but neither option works.
I've tried to get paid by getc () and by gets ()
but nothing works, help me please
_________________ Gradually you will go far with persistence, will and determination! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Mon Feb 15, 2021 1:18 pm |
|
|
Key thing to understand is that INT_RDA, means _one_ character has
arrived. Just one. Using gets in the interrupt means the code hangs
here waiting for the other characters.
Look at the ex_serial.c, which shoiws how the interrupt has to be handled
by putting the data into a buffer.
Then repeat 50*. Interrupt handlers should be quick. They should handle
the event signified by the interrupt and return immediately. You should
not have slow things like prints in the interrupt.
Your main code needs an equivalent to gets, that reads the input data
into a 'string', until it sees the end of line character. At this point you add
a null terminator to the string, and you then have something that can be
tested and printed. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 479 Location: Montenegro
|
|
Posted: Tue Feb 16, 2021 9:47 am |
|
|
This works for me:
defines
Code: |
#define BUFFER_SIZE 10 //create 10 byte large buffer
char buffer[BUFFER_SIZE];
int8 next_in = 0;
|
interrupt
Code: |
#INT_RDA
void RDA_isr(void) {
tmp = getc();
buffer[next_in]= tmp;
next_in++;
output_toggle(SOME_PIN); // see if you are even getting the characters into the buffer
if(next_in == 7){
buffer[next_in] = '\0'; // terminate string with null
next_in = 0;
Got_Data = 1;
output_high(SOME_PIN); // turn off the LED
}
} // INT_R
|
main
Code: |
// MAIN
while(TRUE){
if(Got_Data){
Got_Data = 0;
printf(write_display,buffer);
delay_ms(200);
}
} // while
|
Regards |
|
|
flyboy71
Joined: 14 Mar 2019 Posts: 8
|
|
Posted: Fri Feb 19, 2021 10:00 am |
|
|
This is similar to the above approach that I had to use in an application where I was getting garbage data coming in over the UART due to a noisy environment. This looks for a start character '$' and a carriage return as the terminator to validate if the data is good. Your example is 7 fixed digits but you show an alphanumeric so if it always ends in B that could be the terminating character. It depends if you can customize what is being received in this case. If not the size is the determinant.
Code: |
#INT_RDA
void RDA_isr(void)
{
ptr++;
if (ptr>6) {ptr=0;} //reset for excess chars
rxchar=getc();
if ( rxchar == '$' ) { //command start flag '$'
memset(rxbuf,0,sizeof(rxbuf)); //clear array
data_ok=0; //clear data_ok flag
ptr=0; //set pointer to zero
rxbuf[ptr] = rxchar;} //store '$' in 0
else if (rxchar == 13) {data_ok=1;} //command end flag CR
else { rxbuf[ptr]=rxchar;} //store everything else
}
|
|
|
|
erpgc82
Joined: 02 May 2020 Posts: 73
|
|
Posted: Sat Feb 20, 2021 8:36 pm |
|
|
Hello friends, as I said before, I am learning to program.
I spent more than a week to understand how the #INT_RDA serial interrupt works and make my code work.
With that I learned that it is not with ready examples from the internet that success will be achieved, but rather by learning what needs to be done. Situations are different from each other.
In the code below, I just need to receive what arrives on the PIC-RX serial hardware and send it to the PC.
The code I receive consists of 6 digits + the B character, totaling 7 characters.
But I found out through a serial monitor, from the T2 ethernet module, that the code comes like this:
When I pass: 000102, it receives 9 characters, but in hexadecimal.
I get: 000102B as being 7 characters.
But the serial monitor receives 9 hexadecimal codes.
Hex: 30 30 30 31 30 32 42 0A 0D
character: 0 0 0 1 0 2 B nl cr
At the RX input of the PIC, I receive these codes from a serial barcode reader.
So the code below worked, but every 10 or 20 records, approximately, the codes pile up. It is complex because I worked so that when the characters arrive at the interruption, it would be increasing the variable J, and when the variable J was greater than 6, take only what matters, which are the numbers and then convert them to (int). Converting numeric characters to (int) was what solved my problem, and the matrix is of type (int).
Can someone help me why I get heaped characters after a certain period? Am I not cleaning the uart correctly? Is the restartRS232 () error clearing function in place?
Code: |
#include <16F876a.h> /* directive that defines the pic used, header file, header file*/
#case /* directive defining the ANSI standard for uppercase and lowercase letters*/
#use delay(clock=10000000) // frequency for calculations and delays
#fuses HS // uses crystal> 4mhz
#fuses NOWDT // disable reset by watch dog
#fuses PUT /* waits 72ms to stabilize the electrical circuit and then turns on the PIC */
#fuses BROWNOUT // reset by voltage <4.5v
#fuses NOLVP // disables low voltage recording
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8, stop=1, errors)
#bit tmr0if = 0x0b.2 /* defines that bit2 of register INTCON / Timer0 name tmr0if
* 1 - timer0 overflowed / burst
* 0 - timer0 did not overflow / burst */
#bit SPEN=0x18.7
#bit CREN=0x18.4
#bit FERR=0x18.2
#bit OERR=0x18.1
#bit SYNC=0x98.4 /* start cleaning, to enable serial, in void main, before while */
#bit RCIF=0x0c.5 //1 the buffer is full, 0 the buffer is empty
#bit PEIE=0x0b.6
#use fast_io (a)
#use standard_io (b)
#use fast_io (c)
#include "display_8bits16f876.c" // display library
#define BEEP PIN_A3
int code[10]; // matrix with 10 variables
int1 f=0; /* flag to inform the main program that there is code in the matrix*/
int j=0; // control variable to wait for the next character
char c; // variable to receive the origin of the characters
// function prototypes
void restartRS232(void);
#INT_RDA
void RDA_isr(void)
{
c = getc(); /* receives the first character and stores it in the variable 'c' type char */
code[j++]= (int)c; /* converts the characters of the variable 'c' type char to int and stores it in the code matrix, and at the same time increments the variable j*/
if(j>6) /* if the control variable has already received 6 characters, then enable the 'f' flag and disable the interrupt, so as not to receive anything else, but it does not advance, as it ends up receiving the character B from the serial reader.*/
{
clear_interrupt(INT_RDA); /* clears the interruption, but nothing good has happened.*/
restartRS232(); /* calls function with code to check for errors, I found it on the internet, but it doesn't help. */
f=1; // assign 1 to variable 'f', enable
disable_interrupts(INT_RDA); /*disables the interruption, so as not to disturb the main code */
}
}
// Main function
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256);
setup_timer_1(T1_DISABLED);
set_timer0(11); /*timer 0 starting at 11, prescaler dividing by 256, to have 25.0880000 milliseconds*/
setup_timer_2(T2_DISABLED,0,1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
setup_adc(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_spi(FALSE);
setup_uart(9600);
setup_uart(UART_DATA);
set_tris_a(0b00110110);
set_tris_c(0b00000000);
output_c(0b00000000);
display_ini(); // initializes the display
while(TRUE)
{
////////////////////////////////////////////////////////////////////
////// Standard Display Message ///////////////////////////////
printf(write_display,"\f %d %d ",f,j);
printf(write_display,"\nCode: ");
/*it is showing the value of the flag and the value of the control variable. And with that I sometimes see that the variable is already worth 1, even after having already read a code.*/
////////////////////////////////////////////////////////////////////
// Cleaning variables ////////////////////////////////////////////
/* Reading the code received on the RX serial, it may be a dirty character. Because the variable 'j' is 1, but when you put this code here, the variable 'j' is always worth 0, after reading it. But even so, it didn't solve the heap problem. */
if((f==0)&&(j==1)) j=0; /* if j is equal to 1, it decreases, correcting, since the 1st time comes with value 0, from the 1st comes value 1
* Correct any failure, if variable j is still valid 1*/
if(f==1)
{
f=0;
j=0;
//c=' ';
/* I tried to make this 'if' code below, in an attempt to verify that it just executes the command, if the contents of code [0] to code [5] were different from the values of B, \ r and \ n. But I was not successful. */
if((!code[0]==0x0d||0x0a||0x23)&&(!code[1]==0x0d||0x0a||0x42)&&(!code[2]==0x0d||0x0a||0x42)&&(!code[3]==0x0d||0x0a||0x42)&&(!code[4]==0x0d||0x0a||0x42)&&(!code[5]==0x0d||0x0a||0x42))
{
/* so I just take the numeric characters and manually put the character B, \ r and \ n. */
printf("%c%c%c%c%c%cB\n\r",code[0],code[1],code[2],code[3],code[4],code[5]);
//printf("%s\n\r",code);
display_pos_xy(11,2);
printf(write_display,"%c%c%c%c%c%c",code[0],code[1],code[2],code[3],code[4],code[5]);
//printf(write_display,"%s",code);
output_high(BEEP);
delay_ms(50);
output_low(BEEP);
delay_ms(100);
output_high(BEEP);
delay_ms(150);
output_low(BEEP);
}
else
{
/* attempt to solve the crowding problem, but to no avail*/
clear_interrupt(INT_RDA);
restartRS232();
}
delay_ms(800);
//clear_interrupt(INT_RDA); // clears the serial interrupt
//enable_interrupts(INT_RDA); /*re-enable serial interruption from here.*/
//restartRS232(); /*clears any possibility of dirt in the communication. But it has not gone ahead, without success.*/
clear_interrupt(INT_RDA); // clears the serial interrupt
delay_ms(10);
enable_interrupts(INT_RDA); /*re-enable serial interruption from here.*/
}
delay_ms(50);
}
}
////////////////////////////////////////////////////////////////////////////////
// Error checking function / routine, call it at the beginning of the
// interrupt function: See the example below.
////////////////////////////////////////////////////////////////////////////////
void restartRS232(void)
{
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;
}
}
|
When the code piles up, see what I get on the PC serial, monitored by the T2 ethernet card software.
30 30 39 30 30 33 42 0A 0D 009003B correct.
30 30 32 33 31 42 42 0A 0D 00231BB incorrect, stacked code.
Please, the hardest I've ever done, but where am I wrong? _________________ Gradually you will go far with persistence, will and determination! |
|
|
erpgc82
Joined: 02 May 2020 Posts: 73
|
|
Posted: Sun Feb 21, 2021 3:43 pm |
|
|
It seems to me that when checking if (j> 6) because it takes more characters than just the 6 numerics that really matter.
I tried to make other changes now, but also without success:
#define buffer_s 10
int code [buffer_s]; // matrix with 10 variables
and check on #int_rda
if (j == buffer_s) j = 0;
As I understand it, when occupying the 10 variables, they would be reset to zero. Got it right or wrong?
But none of the options worked, to correct this flaw or character overlap.
== Editing ==========================
running some tests now, I got this code
ˆ00157B Crying or Very sad
where the ^ is in fact it looked like the letter 'a' in reverse, a strange character. And the correct code to be read and sent to the PC would be 001572B.
Actually this code arrives correctly for me, but it sends heaped or overlaid to the PC, and now my code above, sometimes sends "strange character"
erpgc82 wrote: | Hello friends, as I said before, I am learning to program.
I spent more than a week to understand how the #INT_RDA serial interrupt works and make my code work.
With that I learned that it is not with ready examples from the internet that success will be achieved, but rather by learning what needs to be done. Situations are different from each other.
In the code below, I just need to receive what arrives on the PIC-RX serial hardware and send it to the PC.
The code I receive consists of 6 digits + the B character, totaling 7 characters.
But I found out through a serial monitor, from the T2 ethernet module, that the code comes like this:
When I pass: 000102, it receives 9 characters, but in hexadecimal.
I get: 000102B as being 7 characters.
But the serial monitor receives 9 hexadecimal codes.
Hex: 30 30 30 31 30 32 42 0A 0D
character: 0 0 0 1 0 2 B nl cr
At the RX input of the PIC, I receive these codes from a serial barcode reader.
So the code below worked, but every 10 or 20 records, approximately, the codes pile up. It is complex because I worked so that when the characters arrive at the interruption, it would be increasing the variable J, and when the variable J was greater than 6, take only what matters, which are the numbers and then convert them to (int). Converting numeric characters to (int) was what solved my problem, and the matrix is of type (int).
Can someone help me why I get heaped characters after a certain period? Am I not cleaning the uart correctly? Is the restartRS232 () error clearing function in place?
Code: |
#include <16F876a.h> /* directive that defines the pic used, header file, header file*/
#case /* directive defining the ANSI standard for uppercase and lowercase letters*/
#use delay(clock=10000000) // frequency for calculations and delays
#fuses HS // uses crystal> 4mhz
#fuses NOWDT // disable reset by watch dog
#fuses PUT /* waits 72ms to stabilize the electrical circuit and then turns on the PIC */
#fuses BROWNOUT // reset by voltage <4.5v
#fuses NOLVP // disables low voltage recording
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8, stop=1, errors)
#bit tmr0if = 0x0b.2 /* defines that bit2 of register INTCON / Timer0 name tmr0if
* 1 - timer0 overflowed / burst
* 0 - timer0 did not overflow / burst */
#bit SPEN=0x18.7
#bit CREN=0x18.4
#bit FERR=0x18.2
#bit OERR=0x18.1
#bit SYNC=0x98.4 /* start cleaning, to enable serial, in void main, before while */
#bit RCIF=0x0c.5 //1 the buffer is full, 0 the buffer is empty
#bit PEIE=0x0b.6
#use fast_io (a)
#use standard_io (b)
#use fast_io (c)
#include "display_8bits16f876.c" // display library
#define BEEP PIN_A3
int code[10]; // matrix with 10 variables
int1 f=0; /* flag to inform the main program that there is code in the matrix*/
int j=0; // control variable to wait for the next character
char c; // variable to receive the origin of the characters
// function prototypes
void restartRS232(void);
#INT_RDA
void RDA_isr(void)
{
c = getc(); /* receives the first character and stores it in the variable 'c' type char */
code[j++]= (int)c; /* converts the characters of the variable 'c' type char to int and stores it in the code matrix, and at the same time increments the variable j*/
if(j>6) /* if the control variable has already received 6 characters, then enable the 'f' flag and disable the interrupt, so as not to receive anything else, but it does not advance, as it ends up receiving the character B from the serial reader.*/
{
clear_interrupt(INT_RDA); /* clears the interruption, but nothing good has happened.*/
restartRS232(); /* calls function with code to check for errors, I found it on the internet, but it doesn't help. */
f=1; // assign 1 to variable 'f', enable
disable_interrupts(INT_RDA); /*disables the interruption, so as not to disturb the main code */
}
}
// Main function
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256);
setup_timer_1(T1_DISABLED);
set_timer0(11); /*timer 0 starting at 11, prescaler dividing by 256, to have 25.0880000 milliseconds*/
setup_timer_2(T2_DISABLED,0,1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
setup_adc(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_spi(FALSE);
setup_uart(9600);
setup_uart(UART_DATA);
set_tris_a(0b00110110);
set_tris_c(0b00000000);
output_c(0b00000000);
display_ini(); // initializes the display
while(TRUE)
{
////////////////////////////////////////////////////////////////////
////// Standard Display Message ///////////////////////////////
printf(write_display,"\f %d %d ",f,j);
printf(write_display,"\nCode: ");
/*it is showing the value of the flag and the value of the control variable. And with that I sometimes see that the variable is already worth 1, even after having already read a code.*/
////////////////////////////////////////////////////////////////////
// Cleaning variables ////////////////////////////////////////////
/* Reading the code received on the RX serial, it may be a dirty character. Because the variable 'j' is 1, but when you put this code here, the variable 'j' is always worth 0, after reading it. But even so, it didn't solve the heap problem. */
if((f==0)&&(j==1)) j=0; /* if j is equal to 1, it decreases, correcting, since the 1st time comes with value 0, from the 1st comes value 1
* Correct any failure, if variable j is still valid 1*/
if(f==1)
{
f=0;
j=0;
//c=' ';
/* I tried to make this 'if' code below, in an attempt to verify that it just executes the command, if the contents of code [0] to code [5] were different from the values of B, \ r and \ n. But I was not successful. */
if((!code[0]==0x0d||0x0a||0x23)&&(!code[1]==0x0d||0x0a||0x42)&&(!code[2]==0x0d||0x0a||0x42)&&(!code[3]==0x0d||0x0a||0x42)&&(!code[4]==0x0d||0x0a||0x42)&&(!code[5]==0x0d||0x0a||0x42))
{
/* so I just take the numeric characters and manually put the character B, \ r and \ n. */
printf("%c%c%c%c%c%cB\n\r",code[0],code[1],code[2],code[3],code[4],code[5]);
//printf("%s\n\r",code);
display_pos_xy(11,2);
printf(write_display,"%c%c%c%c%c%c",code[0],code[1],code[2],code[3],code[4],code[5]);
//printf(write_display,"%s",code);
output_high(BEEP);
delay_ms(50);
output_low(BEEP);
delay_ms(100);
output_high(BEEP);
delay_ms(150);
output_low(BEEP);
}
else
{
/* attempt to solve the crowding problem, but to no avail*/
clear_interrupt(INT_RDA);
restartRS232();
}
delay_ms(800);
//clear_interrupt(INT_RDA); // clears the serial interrupt
//enable_interrupts(INT_RDA); /*re-enable serial interruption from here.*/
//restartRS232(); /*clears any possibility of dirt in the communication. But it has not gone ahead, without success.*/
clear_interrupt(INT_RDA); // clears the serial interrupt
delay_ms(10);
enable_interrupts(INT_RDA); /*re-enable serial interruption from here.*/
}
delay_ms(50);
}
}
////////////////////////////////////////////////////////////////////////////////
// Error checking function / routine, call it at the beginning of the
// interrupt function: See the example below.
////////////////////////////////////////////////////////////////////////////////
void restartRS232(void)
{
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;
}
}
|
When the code piles up, see what I get on the PC serial, monitored by the T2 ethernet card software.
30 30 39 30 30 33 42 0A 0D 009003B correct.
30 30 32 33 31 42 42 0A 0D 00231BB incorrect, stacked code.
Please, the hardest I've ever done, but where am I wrong? |
_________________ Gradually you will go far with persistence, will and determination! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 21, 2021 4:18 pm |
|
|
Post the manufacturer and model number of your barcode reader. |
|
|
erpgc82
Joined: 02 May 2020 Posts: 73
|
|
Posted: Sun Feb 21, 2021 6:54 pm |
|
|
PCM programmer wrote: | Post the manufacturer and model number of your barcode reader. |
Hello friend, it is not a commercial reader that you will find information or datasheet out there on the internet. It was an engineer who discovered it about 15 years ago.
At the moment, it doesn't matter how he reads the barcode. But, it reads the code and delivers it ready. For example, it reads the code 001056, and will deliver the 7 character code 001056B. In hex it delivers 9 codes, being 0x30 0x30 0x31 0x30 0x35 0x35 0x36 0x42 0x0a 0x0d.
I've been studying more this weekend, I saw what is wrong. I need to use "circular buffer" logic to handle the matrix data, but I'm still trying to understand it better.
And I still don't understand how to create this circular buffer logic. _________________ Gradually you will go far with persistence, will and determination! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 21, 2021 7:30 pm |
|
|
Look at the CCS example, EX_SISR.C. It shows how to do a circular buffer. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sun Feb 21, 2021 8:01 pm |
|
|
I want to make several comments about your posted program.
Quote: | #use fast_io (a)
#use standard_io (b)
#use fast_io (c)
|
Don't do this (in the 3 lines above). It's not necessary. The compiler
defaults to using standard i/o on all ports. Keep it that way. Don't use
fast i/o. Let the compiler handle setting the TRIS. Delete all the lines above.
Quote: | void restartRS232(void)
{
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;
}
}
|
You don't need the function shown above. The compiler already puts in
code to clear errors when you include the ERRORS parameter in your
#use rs232() statement. Example of ASM code produced by the CCS
compiler when you put ERRORS in #use rs232():
Code: |
.................... #use rs232(UART1, baud=9600, ERRORS)
0004: BTFSS PIR1.RCIF // Wait until a character arrives
0005: GOTO 004
0006: MOVF RCSTA,W // Read the UART receiver status register
0007: MOVWF rs232_errors // Save it
0008: MOVF RCREG,W // Read the received character
0009: MOVWF @78 // Save it
000A: BTFSS rs232_errors.1 // If we got an error, go to 000C
000B: GOTO 00E // If no error, then exit the interrupt code
000C: BCF RCSTA.CREN // Clear CREN bit to clear the error
000D: BSF RCSTA.CREN // Set CREN bit
000E: BCF PCLATH.3
000F: BCF PCLATH.4
0010: GOTO 027 (RETURN)
|
Quote: | setup_timer_0(RTCC_INTERNAL|RTCC_8_BIT|RTCC_DIV_256);
setup_timer_1(T1_DISABLED);
set_timer0(11); /*timer 0 starting at 11, prescaler dividing by 256, to have 25.0880000 milliseconds*/
setup_timer_2(T2_DISABLED,0,1);
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
setup_adc(ADC_OFF);
setup_adc_ports(NO_ANALOGS);
setup_ccp1(CCP_OFF);
setup_ccp2(CCP_OFF);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_spi(FALSE);
setup_uart(9600);
setup_uart(UART_DATA); |
You don't have to disable every module inside the PIC. They are already
disabled by default at power-up. Get rid of most of the code above.
You can keep the two interrupt enable lines.
When you have useless lines in a program, it distracts you from looking
at the real code.
Quote: | set_tris_a(0b00110110);
set_tris_c(0b00000000);
output_c(0b00000000); |
You generally don't need to set the TRIS. Let the compiler set it. You
should set unused pins to a logic low output to greatly reduce
noise inside your PIC. To set an entire unused port to a logic low,
you can do this:
To set individual unused pins to a logic low, you can do this:
Code: | output_low(PIN_B0);
output_low(PIN_B1); |
|
|
|
erpgc82
Joined: 02 May 2020 Posts: 73
|
unnecessary circular buffer |
Posted: Tue Feb 23, 2021 10:07 pm |
|
|
Hello friends, why am I obliged to use circular buffer?
I complex the circular buffer and it seems unnecessary for what I need.
I'm working with a fixed amount of bytes arriving at the serial, #int_rda.
It's only 7 digits + \ n \ r.
For me, this program below is almost perfect.
I can only work perfectly once, then the characters in the matrix get confused.
Code: |
#include <16F876a.h>
#use delay(clock=10000000)
#fuses HS,NOWDT,PUT,BROWNOUT,NOLVP
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8, stop=1, ERRORS)
#include "display_8bits16f876.c"
int code[9];
int next_in=0;
int next_out=0;
int1 f=0;
#INT_RDA
void serial_isr()
{
char char_received;
char_received=getc();
code[next_in] = (int) char_received;
next_in++;
if(char_received=='\r')
{
f=1;
next_out=next_in;
next_in=0;
disable_interrupts(INT_RDA);
}
}
void main()
{
enable_interrupts(GLOBAL);
enable_interrupts(INT_RDA);
display_ini();
while(TRUE)
{
printf(write_display,"\f %d %d ",f,next_out);
printf(write_display,"\nCode: ");
if(f==1)
{
f=0;
output_high(BEEP);
delay_ms(50);
output_low(BEEP);
printf("%s",code);
display_pos_xy(10,2);
printf(write_display,"%c%c%c%c%c%c",code[0],code[1],code[2],code[3],code[4],code[5]);
delay_ms(1000);
next_out=0;
enable_interrupts(INT_RDA);
clear_interrupt(INT_RDA); //required?
}
delay_ms(50);
}
}
|
the first reading that works correctly, displays 1 9 on the LCD display
1 = Flag (code read)
9 = number of characters identified, value of variable next_in
Display shows the code read with 6 digits 001572
on the serial monitor correctly displays 001572B
More precisely 30 30 31 35 37 32 42 0a 0d
the second reading, does not work properly, displays 1 12 on the LCD display
1 = flag (code read)
12 = number of characters identified, variable value next_in
but the characters actually displayed are:
2 invalid (strange characters)
7 normal digits 001572B
More precisely 98 98 30 30 31 35 37 32 42. Add the 0a and 0d.
98 98 are strange characters, but strange characters are always different.
Can someone explain to me why this occurs? _________________ Gradually you will go far with persistence, will and determination! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19513
|
|
Posted: Wed Feb 24, 2021 12:50 am |
|
|
OK.
The key 'point' about the circular buffer is that it can be completely
independant of the processing your code does.
Now the problem with the fixed length buffer, and doing all your
processing when you see the line feed, is "what happens if you can't
complete this processing before the next character arrives"?.
The circular buffer avoids this being a problem.
However, I see a problem in what you are saying. You talk about a string
of seven digits, and \n\r. This is potentially nine characters. You have
been talking about an 8 character buffer. So, you need to actually be very
careful. Make the receive code explicitly not store the '\r' character.
Store the seven digits, and when you see the '\n', store a 0 to terminate the
'string', and set the flag to say 'number complete', and use this to start your
main processing.
In your code, the problem is that you stop processing the received
data when you see the end of your 'packet', and then don't restart for
an absolute age (printf, delays, etc. etc..). When you do restart, you have
no guarantee that you are not 'mid packet' in the data. So you could get
any number of digits, and things will not be where you expect them to be
This is why ideally you separate the jobs. Have a system that receives
and buffers the data. Then whenever this data is complete, process and
store this into the required locations. Then separately at a time interval,
do the display of this stored data. |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9226 Location: Greensville,Ontario
|
|
Posted: Wed Feb 24, 2021 10:34 am |
|
|
The 'buffer' should be at least 2x the size of the known incoming data stream. This allows for some 'overlap' of new incoming data while you're 'processing' the previous contents of the buffer. |
|
|
erpgc82
Joined: 02 May 2020 Posts: 73
|
|
Posted: Thu Feb 25, 2021 10:16 pm |
|
|
Hello friends, can someone really help me?
I've tried all the ways and I can't capture those characters.
1) I understand correctly the Interrupt #int_rda, which captures one character at a time, ok.
2) I don't understand how the circular buffer works. I read the EX_SISR.C example and did not understand how
//////////////////////////////////////////////// /////////////////////////////////////////
I tried only by interrupting int_rda, a control variable next_in reaches a certain value and triggers a flag. I just tried now for switch (next_in) case, and I also couldn't, the maximum was to receive 24 null characters.
Please, can anyone help me It was going so well until I got this reception of serial characters.
I just need to get the main characters which are the codes, the other characters I can dispense, then send by printf to the serial and to the LCD _________________ Gradually you will go far with persistence, will and determination! |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Feb 26, 2021 5:38 am |
|
|
Here is what you want. A way to read bytes from the barcode reader
and display them. I used a PIC with two UARTs to do this. It's the
18F46K22.
First I made a small program to emulate your barcode reader.
It sends the barcode bytes out the serial port on the PIC whenever
a button is pushed on the board. I used the Microchip Low Pin Count
board with a 16F690 for this:
Code: |
#include <16F690.h>
#fuses INTRC_IO
#use delay(clock=8M)
#use rs232(baud=9600, UART1, ERRORS)
//======================
void main(void)
{
port_b_pullups(0x40); // Turn on pullup on pin B6
delay_ms(10);
while(TRUE)
{
while(input(PIN_B6) == 0); // Wait for button to be released
delay_ms(10);
while(input(PIN_B6) == 1); // Wait for button press
printf("001572B\n\r");
}
}
|
Then I connected the Low Pin Count board running the program above, to
the main board running the barcode reader program. I connected ground
to ground on both boards, and Tx on the Low Pin Count board to Rx2 on
the big board.
I programmed the following program into the big board. I don't claim
this is a great program but it does work. It demonstrates how to do it,
in a basic way.
Code: |
#include <18F46K22.h>
#use delay(internal=4M)
#use rs232(baud=9600, UART2, ERRORS, stream=BARCODE_READER)
#use rs232(baud=9600, UART1, ERRORS, stream=PC)
#define BUFFER_SIZE 32
BYTE buffer[BUFFER_SIZE];
BYTE next_in = 0;
BYTE next_out = 0;
// This routine gets the bytes from the barcode reader.
#int_rda2
void serial_isr()
{
int t;
buffer[next_in]=fgetc(BARCODE_READER);
t=next_in;
next_in=(next_in+1) % BUFFER_SIZE;
if(next_in==next_out)
next_in=t; // Buffer full !!
}
#define bkbhit (next_in!=next_out)
BYTE bgetc()
{
BYTE c;
while(!bkbhit);
c=buffer[next_out];
next_out=(next_out+1) % BUFFER_SIZE;
return(c);
}
//======================================
void main()
{
int8 c;
int8 barcode_buffer[10];
enable_interrupts(INT_RDA2);
enable_interrupts(GLOBAL);
while(TRUE)
{
if(bkbhit)
{
c = bgetc();
if(c == '0') // Is this the start of a block of bytes ?
{ // If so, then get them all.
barcode_buffer[0] = c; // 0
barcode_buffer[1] = bgetc(); // 0
barcode_buffer[2] = bgetc(); // 1
barcode_buffer[3] = bgetc(); // 5
barcode_buffer[4] = bgetc(); // 7
barcode_buffer[5] = bgetc(); // 2
barcode_buffer[6] = bgetc(); // B
barcode_buffer[7] = bgetc(); // CR
barcode_buffer[8] = bgetc(); // LF
barcode_buffer[7] = 0; // Make it into a string
fprintf(PC, "Received: %s \n\r", barcode_buffer);
}
}
}
} |
On the big board, UART1 is connected to the PC with a serial cable.
I'm running TeraTerm on the PC. It displays the received barcode
numbers every time I push the button on the little board:
Quote: |
Received: 001572B
Received: 001572B
Received: 001572B
Received: 001572B
Received: 001572B
Received: 001572B
Received: 001572B
Received: 001572B
Received: 001572B
Received: 001572B |
So it's working. |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|