|
|
View previous topic :: View next topic |
Author |
Message |
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Wed Mar 29, 2023 4:58 am |
|
|
Use interrupt on a receiving side. Sooo much easier. Hook your Pickit. Check the received data with it. Or at least use a blinking LED to see if you even arrive to the interrupt. |
|
|
gaugeguy
Joined: 05 Apr 2011 Posts: 303
|
|
Posted: Wed Mar 29, 2023 6:21 am |
|
|
These modules can work well when used as intended. The receiver does hear the first few pulses sent. The preamble might be 16 pulses at 50% duty cycle and the receiver may only pass the last 14 or so through depending on background noise. After the preamble is a slight delay before data is sent. The data is most commonly on off keyed PWM or manchester. You want a lot of high low transitions to keep the data link synchronized. Too long of a pause or too many 0's in a row and the link will have to resynchronize and some bits are lost. If the bit rate is too high the data will not go through. If the bit rate is too low then the module will loose sync and drop out. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Wed Mar 29, 2023 7:06 am |
|
|
I use HC-12 modules. Works OK, range is good. |
|
|
Khansokhua
Joined: 06 Nov 2021 Posts: 92
|
|
Posted: Wed Mar 29, 2023 7:45 am |
|
|
Code: | while(TRUE)
{
distance=HCSR04_get_distance();
send_preamble();
putc(distance); //To take the data into the send_preamble() function will be more efficient?
} |
It really works. Not rach yet, I guess it can be more impressive. Thank you Mr. temtronic for your unrequited knowledge sharing and thank you to other individuals.
Code: | void send_preamble()
{
int i;
for(i=0;i<5;i++)
{
putc(0x55);
}
int l; // What can I try differently?
for(l=0;l<5;l++)
{
putc(0x00);
}
int k;
for(k=0;k<5;k++)
{
putc(0xFF);
}
} |
Is my baud rate OK? or must take a try for different values?
Code: | #use rs232(baud=4800,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=SPIC,errors) |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9241 Location: Greensville,Ontario
|
|
Posted: Wed Mar 29, 2023 8:30 am |
|
|
Maybe use the preamble in the 2nd link ??
It worked for him.. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Wed Mar 29, 2023 11:03 am |
|
|
This function would send your data with a preamble and markers. Of course you need a matching function to extract that data on the other side. The point of preamble is to somehow wake up the receiver. Those bytes can be lost, so you can't count how many bytes you've received so far and after that presume that next one is your data. One possible way is to use a known character or a sequence of them to indicate when something useful will come in and when it has ended. That way you can to some degree be sure that what you have is what was sent. Character U is used as a preamble because it alternates between 0 and 1, to prevent any saturation of the receiver.
Code: |
void SendData(int8 Payload){
int i;
for(i=0;i<8;i++){
fputc('U', SPIC); // preamble. U (ASCII) is used because in binary it is 01010101
}
fputc('#', SPIC); // start marker #
fputc(Payload, SPIC); // actual data
fputs("&\n\r", SPIC); // end marker &
}
|
You call this with: SendData(distance); |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Wed Mar 29, 2023 5:21 pm |
|
|
And a matching code to decipher that on the receiving end:
Code: |
// declare some variables at the start for this to work
char Tmp; // serial data is recorded here
int8 ReceivedData; // received data will be found here
int1 TransmissionOK = 0; // flag for main(), initialized to 0
int8 PARSE = 0; // switch variable, initialized to 0
// all global to enable easier debugging vith Pickit3
// *********************************************************
// *********************************************************
#INT_RDA
void RDA_isr(void)
{
Tmp = getc();
switch (PARSE){
// You stay in case 0 until # comes along. Everything else is
// ignored at this point. Preamble too, of course.
// ----------- waiting for # or start marker ---------------
// ignore everything else, just sit tight and wait for #
case 0:{
if(Tmp == '#'){ // we have "#"
PARSE = 1; // expecting distance data in the next byte
delay_cycles(1);
}
else{
PARSE = 0; // else statement is not needed, but it is easier to read
}
break;
}
// -------------- waiting for distance data ----------------
case 1:{ // # was received, save distance info
ReceivedData = Tmp; // expecting end marker in next byte
PARSE = 2;
delay_cycles(1);
break;
}
// --- waiting for & or end marker in other words ---------
case 2:{
if(Tmp == '&'){ // we got "&", parsing is complete, data is good. Inform main via TransmissionOK flag.
TransmissionOK = 1; // Valid data is stored in ReceivedData variable. Clear the flag it in main().
delay_cycles(1);
}
else{
TransmissionOK = 0; // & didn't arrive. Abort. This else statement is not needed, it is here to explain the logic
}
PARSE = 0; // Good or bad data, go waiting for the next '#'
break;
}
// ---------------------------------------------------------
} // switch
} // end interrupt RDA_isr
// *********************************************************
// *********************************************************
void main(void)
{
while(true)
{
if(TransmissionOK == 1) // RDA_isr informed us we have new data in ReceivedData variable
{
delay_cycles(1);
TransmissionOK = 0; // clear flag
// do whatever you want with your data now
}
}
}
|
Those delay_cycles(1) are there if you decide to use a debugger to see what is going on :-) |
|
|
Khansokhua
Joined: 06 Nov 2021 Posts: 92
|
|
Posted: Thu Mar 30, 2023 8:30 am |
|
|
Greetings
As my teacher said ignore the problems doesn't solve them.Anyway
I use 2xPIC16F877A, tx-rx rx-tx wired.
I use 8 bit ADC and control 8 different LED with a potentiometer.
When it comes to accomplish it using RS-232.Only at max value(255=LED8) a single LED is high.In the case of read adc value, except value 255, all 8 LEDs blinks simulteneaously.How can I overcome this situation ?I want this be the same like first.
RX header file
Code: | #include <16F877A.h>
#device ADC=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOPUT //No Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NOPROTECT //Code not protected from reading
#device ICD=TRUE
#use delay(crystal=20000000)
#use rs232(baud=4800,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=SPIC,errors)
#use STANDARD_IO( B )
#use FIXED_IO( B_outputs=PIN_B7,PIN_B6,PIN_B4,PIN_B3,PIN_B2,PIN_B1,PIN_B0 )
#define LED1 PIN_B0
#define LED2 PIN_B1
#define LED3 PIN_B2
#define LED4 PIN_B3
#define LED5 PIN_B4
#define LED6 PIN_C0
#define LED7 PIN_B6
#define LED8 PIN_B7
|
RX Code: | #include <ADC_8LED.h>
int8 led_value;
void main()
{
/* setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_32);
set_adc_channel(0);
delay_us(20);*/
while(TRUE)
{
// led_value=read_adc();
led_value=getc();
if(led_value>=0 && led_value<=32){
output_high(LED1);
output_low(LED2);
output_low(LED3);
output_low(LED4);
output_low(LED5);
output_low(LED6);
output_low(LED7);
output_low(LED8); }
if(led_value>=33 && led_value<=65){
output_low(LED1);
output_high(LED2);
output_low(LED3);
output_low(LED4);
output_low(LED5);
output_low(LED6);
output_low(LED7);
output_low(LED8); }
if(led_value>=66 && led_value<=98){
output_low(LED1);
output_low(LED2);
output_high(LED3);
output_low(LED4);
output_low(LED5);
output_low(LED6);
output_low(LED7);
output_low(LED8); }
if(led_value>=99 && led_value<=131){
output_low(LED1);
output_low(LED2);
output_low(LED3);
output_high(LED4);
output_low(LED5);
output_low(LED6);
output_low(LED7);
output_low(LED8); }
if(led_value>=132 && led_value<=164){
output_low(LED1);
output_low(LED2);
output_low(LED3);
output_low(LED4);
output_high(LED5);
output_low(LED6);
output_low(LED7);
output_low(LED8); }
if(led_value>=165 && led_value<=197){
output_low(LED1);
output_low(LED2);
output_low(LED3);
output_low(LED4);
output_low(LED5);
output_high(LED6);
output_low(LED7);
output_low(LED8); }
if(led_value>=198 && led_value<=229){
output_low(LED1);
output_low(LED2);
output_low(LED3);
output_low(LED4);
output_low(LED5);
output_low(LED6);
output_high(LED7);
output_low(LED8); }
if(led_value>=230 && led_value<=255){
output_low(LED1);
output_low(LED2);
output_low(LED3);
output_low(LED4);
output_low(LED5);
output_low(LED6);
output_low(LED7);
output_high(LED8); }
}
}
|
TX header file Code: | #include <16F877A.h>
#device ADC=8
#FUSES NOWDT //No Watch Dog Timer
#FUSES NOPUT //No Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES NOLVP //No low voltage prgming, B3(PIC16) or B5(PIC18) used for I/O
#FUSES NOCPD //No EE protection
#FUSES NOWRT //Program memory not write protected
#FUSES NOPROTECT //Code not protected from reading
#device ICD=TRUE
|
TX Code: | #include <adc_send_LED.h>
#use delay(crystal=20000000)
#use rs232(baud=4800,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8,stream=SPIC,errors)
int8 adc_led=0;
void main()
{
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_DIV_32);
set_adc_channel(0);
delay_us(20);
while(TRUE)
{
adc_led=read_adc();
putc(adc_led);
}
} |
|
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9241 Location: Greensville,Ontario
|
|
Posted: Thu Mar 30, 2023 9:20 am |
|
|
at the very minimum, you need to add code for the following
1) connect the TXD of the RX PIC to a TTL<>USB module and send the received data to a PC terminal program.
you NEED this to VERIFY that the incoming data is true
2) have the TX PIC send KNOWN data at a1 Hz rate, to VERIFY the correct data IS being sent and received
3) delete the #USE_FIXED_IO(). let the compiler handle the DDRs as needed ! In 25+ years I've only needed fixed_io for 2 project, both had very,very tight timing requirements, you don't !! |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Thu Mar 30, 2023 10:15 am |
|
|
You sure don't like interrupts :-). Your style of coding, I guess, but you are only making it harder for yourself. Two things, the first is to shorten the code. If you have all of LEDs on the same port, use output_x(pattern) instead of writing 8 statements for 8 LEDs. The second one concerns ICD. If you can, move those diodes to PortD to be able to use output_x(). The reason for this is that it is best to leave ICD lines free. If you won't use output_x, move just two diodes away from PIN_B6 and PIN_B7. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Thu Mar 30, 2023 10:34 am |
|
|
Also, Mr. Temtronic is right. Maybe I missed that post, but so far I haven't seen that you confirmed your receiving routines work. Concentrate on that, all your assignments depend on that (very short, very easy) piece of code. I posted two or three examples in this thread that WORK. I was in your place a while ago, then with some searching and help came to a solution which I use all the time since then. No thinking when a new project comes along. Copy, paste, forget. Once you get that going, everything else you do is basically the same. Get a value over serial, do something based on that value. But if you don't know if you even received correct value or for that matter any value, nothing can work as expected. |
|
|
Khansokhua
Joined: 06 Nov 2021 Posts: 92
|
|
Posted: Thu Mar 30, 2023 11:22 am |
|
|
PrinceNai wrote: | You sure don't like interrupts :-). Your style of coding, I guess, but you are only making it harder for yourself. Two things, the first is to shorten the code. If you have all of LEDs on the same port, use output_x(pattern) instead of writing 8 statements for 8 LEDs. The second one concerns ICD. If you can, move those diodes to PortD to be able to use output_x(). The reason for this is that it is best to leave ICD lines free. If you won't use output_x, move just two diodes away from PIN_B6 and PIN_B7. |
Code: | if(led_value>=0 && led_value<=32){
output_d(0b10000000); }
if(led_value>=33 && led_value<=65){
output_d(0b01000000);
}
if(led_value>=66 && led_value<=98){
output_d(0b00100000); }
if(led_value>=99 && led_value<=131){
output_d(0b00010000); }
if(led_value>=132 && led_value<=164){
output_d(0b00001000); }
if(led_value>=165 && led_value<=197){
output_d(0b00000100); }
if(led_value>=198 && led_value<=229){
output_d(0b00000010); }
if(led_value>=230 && led_value<=255){
output_d(0b00000001); } |
Far much better thank you |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Thu Mar 30, 2023 12:03 pm |
|
|
Cool. It is shorter. Now just make it nicer and easier to read. 80% of that IDE can do for you. Use tabs, 3 spaces sound ok. Use indents. That way you can see the structure and levels of your code and makes it way easier for you and others to read. Like this:
Code: |
if(led_value>=0 && led_value<=32){
output_d(0b10000000);
}
if(led_value>=33 && led_value<=65){
output_d(0b01000000);
}
|
or, if you like your braces to match on the same column, like this:
Code: |
if(led_value>=0 && led_value<=32)
{
output_d(0b10000000);
}
if(led_value>=33 && led_value<=65)
{
output_d(0b01000000);
}
|
This also helps, and I mean helps, when you forget the closing brace and try to figure out just where you forgot to write it. I for one ALWAYS write both braces first and then the code between them. |
|
|
Khansokhua
Joined: 06 Nov 2021 Posts: 92
|
|
Posted: Thu Mar 30, 2023 1:47 pm |
|
|
Using pickit3 debugger, I can observe from watch window: At max value of adc is constant 0xFF.
At min value 0x01 0x08 0xfd changes.
I can eliminate the values those cause problem,
so I can obtain what I want I think...
It seems ridiculous why adc value keep changing that way |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9241 Location: Greensville,Ontario
|
|
Posted: Thu Mar 30, 2023 3:12 pm |
|
|
re: ADC values not correct
What is the source of the analog voltage you're reading ?
What hardware filtering have you on the signal ?
What is the Vref for the ADC ?
If it's VDD, THAT can be a huge problem !
Is the received adc value the SAME as the transmitted value ?
Have you proper VDD filtering(bypass caps ) on the TX PIC ?
What values do you see compared to what you know they should be ?
Are you reading the sensor (pot ??) once only ? Should use Olympic averaging or similar.
What is the 'sensor' ?
If it's a pot, it HAS to be filtered as all pots are 'scratchy' aka wiper noise
Max = 255 = 0xff
Min should be zero
TX needs to
loop:
read adc
delay_ms(100); only 1/10th second delay, I'd prefer 1 second
send adc
loop |
|
|
|
|
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
|