PIC 16F1503 to Arduino nano UART communication - Page 1
Forum section: electronics / general

author: sumithcmohan
author_rank: Newbie
timestamp: December 04, 2018, 12:21:44 pm
content: I am not able to Send the Charactor '1' from PIC 16F1503 to Arduino nano receiver module. Its works fine between Arduino nano transmitter and receiver modules. But PIC to Arduino having problem. Please find below the transmitter PIC16F1503 code for your reference. Please put some light on my long way worry.************TRANSMITTER (PIC 16F1503) CODE************************Code:#include <xc.h>#include <pic.h>// by default frequency is 500KHz#define Baudrate 1200 //bps#define OneBitDelay (125000/Baudrate)#define DataBitCount 8 // no parity, no flow control#define UART_RX LATAbits.LATA1 //PORTAbits.RA1 // UART RX pin#define UART_TX LATAbits.LATA0 //PORTAbits.RA0 // UART TX pin#define UART_RX_DIR TRISA1 // UART RX pin direction register#define UART_TX_DIR TRISA0 // UART TX pin direction register//Function Declarationsvoid InitSoftUART(void);void UART_Transmit(unsigned char);// CONFIG1#pragma config FOSC = INTOSC // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)#pragma config WDTE = OFF // Watchdog Timer Enable (WDT disabled)#pragma config PWRTE = OFF // Power-up Timer Enable (PWRT disabled)#pragma config MCLRE = ON // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)#pragma config CP = OFF // Flash Program Memory Code Protection (Program memory code protection is disabled)#pragma config BOREN = OFF // Brown-out Reset Enable (Brown-out Reset disabled)#pragma config CLKOUTEN = OFF // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)// CONFIG2#pragma config WRT = OFF // Flash Memory Self-Write Protection (Write protection off)#pragma config STVREN = ON // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)#pragma config BORV = LO // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)#pragma config LPBOR = OFF // Low-Power Brown Out Reset (Low-Power BOR is disabled)#pragma config LVP = OFF // Low-Voltage Programming Enable (High-voltage on MCLR/VPP must be used for programming)void main(){ANSELA = 0x00; // Set ports as digital I/O, not analog inputPORTA = 0x00;TRISA = 0x00; // Make all pins 0InitSoftUART(); // Intialize Soft UARTwhile(1){UART_Transmit('1'); //}}void InitSoftUART(void) // Initialize UART pins to proper values{UART_TX = 1; // TX pin is high in idle stateUART_TX_DIR = 0; // Output}void UART_Transmit(unsigned char DataValue){/* Basic LogicTX pin is usually high. A high to low bit is the starting bit anda low to high bit is the ending bit. No parity bit. No flow control.BitCount is the number of bits to transmit. Data is transmitted LSB first.*/// Send Start BitUART_TX = 0;__delay_us(OneBitDelay);UART_TX = 1;__delay_us(OneBitDelay*2);UART_TX = 0;__delay_us(OneBitDelay);for ( unsigned char i = 1; i /* 8bits*/; i <<= 1 ){//Set Data pin according to the DataValueif(DataValue & i) //if Bit is high{UART_TX = 1;}else //if Bit is low{UART_TX = 0;}__delay_us(OneBitDelay);}//Send Stop BitUART_TX = 1;__delay_us(OneBitDelay*10);}**************************************ARDUINO_NANO_RECEIVER**************************Code:#include <VirtualWire.h>#include <LiquidCrystal_I2C.h>LiquidCrystal_I2C lcd(0x27,16,2); // set the LCD address to 0x27 for a 16 chars and 2 line display//LiquidCrystal lcd(7,6, 5, 4, 3, 2); //lcd (rs, enable, d4, d5, d6, d7)#define ledPin 10#define relay 9char buf;int pos = 0;void setup(){lcd.begin();Serial.begin(9600);pinMode(ledPin, OUTPUT);pinMode(relay, OUTPUT);digitalWrite(ledPin, LOW);digitalWrite(relay, LOW);vw_set_ptt_inverted(true);// Required for DR3100vw_set_rx_pin(11);vw_setup(1200); // Bits per secvw_rx_start(); // Start the receiver PLL running}void loop(){Serial.print(Serial.read());uint8_t buf;uint8_t buflen = VW_MAX_MESSAGE_LEN;if (vw_get_message(buf, &buflen))// Non-blocking{if(buf == '1'){digitalWrite(ledPin, HIGH);digitalWrite(relay, HIGH);lcd.setCursor(0,1);lcd.clear(); // clear displaylcd.print("WATER LOW");delay(1000);lcd.clear(); // clear displaylcd.setCursor(0,1);lcd.print("PUMP ON");}if(buf == '0'){digitalWrite(ledPin, LOW);digitalWrite(relay, LOW);lcd.setCursor(0,1);lcd.clear(); // clear displaylcd.print("WATER ENOUGH");}if(buf == 'x'){digitalWrite(ledPin, LOW);digitalWrite(relay, LOW);lcd.setCursor(0,1);lcd.clear(); // clear displaylcd.print("Float Error");}if(buf == 'S'){digitalWrite(ledPin, LOW);lcd.setCursor(0,1);lcd.clear(); // clear displaylcd.print("TX Sleeping");}}}

author: Buriedcode
author_rank: Super Contributor
timestamp: December 04, 2018, 12:58:24 pm
content: Well.. a few things.Firstly, please use code tags to post code. Its the # symbol just below "font size" when posting. Alternatively, put your code between the html tags [ code] and [ /code] (without the sapce between [ and c.Secondly, please say what compiler you're using. Many will assume XC8 with MPLAB X but the "InitSoftUART" looks like MikroC to me. Which is it?Your void UART_Transmit routine looks odd. You send 0110 (a start bit, then 1 for two bit periods, then a 0) before sending your byte, and a stop bit. Why? This makes no sense. It jsut needs to be a start bit (a bit 0). The for loop, whilst I understand you're shifting a 1 through a byte, doesn't look like it actually ends. I'm unsure why you are making life so difficult for yourself when all you have to do is:Code:UART_TX = 0;__delay_us(OneBitDelay);for(i=0;i<8;i++) {if(DataValue & 0x80) // if MSBit is high{UART_TX = 1;}else //if Bit is low{UART_TX = 0;}DataValue <<= 1;__delay_us(OneBitDelay);}UART_TX = 1;__delay_us(OneBitDelay);You may need to tweak the OneBitDelay value, although at such a low baud it shouldn't matter.

author: sumithcmohan
author_rank: Newbie
timestamp: December 05, 2018, 04:55:31 am
content: Thanks @Buriedcode for your suggestions.Quote from: Buriedcode on December 04, 2018, 12:58:24 pmThanks for this informationQuoteI am using the compiler XC8 with MPLAB X.QuoteI tried this. Still my serial print at receiver module is like this, while tried to send '1' from PIC transmitterCode:Its blank. What is wrong here.I have placed the Serial.print() function here.Code:if (vw_get_message(buf, &buflen))// Non-blocking{Serial.println(buf);if(buf == '1'){

author: Buriedcode
author_rank: Super Contributor
timestamp: December 05, 2018, 02:37:01 pm
content: Ok, now that I can read the code better with the tags, I think I see the problem.You're using the virtualwire library to receive, but you're sending plain old serial (with a start and stop bit?). Please tell us whatexactlyyou are trying to achieve here, are you planning on sending the data wirelessly and just trying to send it over wire as a test? is this for IR communication? I believe the protocol (channel coding) of the virtualwire library is very different from standard UART.When you said it works with Arduino transmitting, I assumed you had used the exact same code for the Arduino to transmit during the test.So either you must use the virtual wire library from your PIC, which I don't think is possible since the library is written for Arduino, and written in C++ (XC8 is plain 'ol C). Or... you need to write your own library for XC8 to send the data in the same format as virtualwire. The latter shouldn't be too hard, especially if you're just planning on sending a few bytes.This is the danger of using libraries without knowing exactly what the library is doing

author: sumithcmohan
author_rank: Newbie
timestamp: December 06, 2018, 10:18:44 am
content: QuoteI am planning to send data wirelessly through a 433MHz RF transmitter.Quoteyes, same code used in that case.QuoteI tried other way.

author: Buriedcode
author_rank: Super Contributor
timestamp: December 06, 2018, 11:22:41 am
content: Ok, to transmit data over a 433MHz link, as you have found out you must use something other than standard UART formatting. I believe "virtual wire" uses some other form of channel coding, possibly manchester coding, or sending specific symbols per bit. This is so there are equal numbers of 0's and 1's, because any wireless link cannot transmit a DC component, so the data must be balanced. It also provides plenty of transitions (no longer strings of 0's or 1's) so that the receiver can synchronize to the data - this is why manchester encoding is used, as it is "self clocking", there is a transition in the middle of every data bit, allowing the receiver to easily distinguish between bits.You said you used the same code for both the Arduino transmitter, and the PIC transmitter. In that case I don't see how the code you posted can work, as it just sends "0110" then 8 bits of data. Where-as according to the virtual wire documentation, it requires a long preamble, and sends each "bit" as a 4 or 6-bit symbol. Perhaps the "0110" is one of these symbols?Apologies if I'm missing something, but it seems like the virtual wire library is more complicated than you realize. Sending data over RF isn't easy, and whilst prebuilt libraries can help a lot, it is often best to know what that library is doing. I'm sure it can be ported to a PIC micro, but it doesn't just send data via a UART, it appears to be much more involved. This guy apparently ported it to a PIC32:http://webedh.free.fr/?page_id=36If you wish to use 433Mhz modules and PIC's, but don't want to use virtual wire, then Roman Black has an excellent write-up:https://www.romanblack.com/RF/cheapRFmodules.htmAlthough I tend to hate "instructables" as they often leave out vital information:https://www.instructables.com/id/Wireless-Communication-Using-Cheap-433MHz-RF-Modul-1/

author: sumithcmohan
author_rank: Newbie
timestamp: December 07, 2018, 12:58:15 pm
content: Thanks for the Romanblack code. I am trying on it. Will update the status tomorrow.

author: sumithcmohan
author_rank: Newbie
timestamp: December 08, 2018, 05:35:58 pm
content: Finally with your great support I have made a good communication between Pic 16F1503 and Arduino nano using the marvelous romanblack code. The final code will update here on Monday.I am very thankful to buried code for getting a unconditional support on my coding issues. Today I am very happy and get rid off the long one week coding meditation 🧘‍♂️. Now confidence leveled up.

author: Buriedcode
author_rank: Super Contributor
timestamp: December 08, 2018, 06:26:46 pm
content: No problem, thats what the forum is for!Also note that, there are many ways to communicate with these modules. Some good search terms would be "channel coding", "line coding", etc.. Also, there are many standards that are well documented, reading up on these shows the different kinds of synchronization, error detection/correction, and modulation used. Stuff like Keeloq, used for remotes have at least two different standards..

author: sumithcmohan
author_rank: Newbie
timestamp: December 13, 2018, 06:42:18 am
content: I have successfully made wireless communication between PIC and Arduino. See the codes below.PIC16F1503 Code for Transmission to arduino nanoCode:void send_rf_byte(unsigned char txdat){//-------------------------------------------------------// This is a pulse period encoded system to send a byte to RF module.// Bits are sent MSB first. Each byte sends 9 pulses (makes 8 periods).// Timing;// HI pulse width; always 80uS// 0 bit, LO width; 20uS (total 0 bit pulse period 100uS)// 1 bit, LO width; 70uS (total 1 bit pulse period 150uS)// space between bytes, LO width; 170uS (total space period 250uS)// (timings tested with 20MHz xtal PIC 18F, no pll)//-------------------------------------------------------unsigned char tbit;// make 250uS start bit first__delay_us(PAUSE_LO); // 170uS LOUART_TX= 1;__delay_us(PAUSE_HI); // 80uS HIUART_TX = 0;for(tbit=0; tbit<8; tbit++){__delay_us(DEFULT_LO); // default 0 bit LO period is 20uSif(txdat&(1<<7))__delay_us(INCREASE_LO); // increase the LO period if is a 1 bit!UART_TX = 1;__delay_us(HI_PULSE); // 80uS HI pulseUART_TX = 0;txdat <<= 1; // roll data byte left to get next bit}__delay_ms(150);SLEEP();}Arduino nano Receiver codeCode:void loop(){//-------------------------------------------------------// This function receives an RF packet of bytes in my pulse period// encoded format. The packet must have 10 valid contiguous bytes// or the function will not exit. There is no timeout feature, but could be added.// global variable; unsigned char rxdat holds the 10 byte result.// Note! TMR0 is running at 500kHz, so 200uS = 100 TMR0 ticks//-------------------------------------------------------unsigned char rrp_data;//unsigned char rrp_period;float rrp_period;unsigned char rrp_period2;unsigned char rrp_bits;unsigned char rrp_bytes;signa = digitalRead(receiver);rrp_bytes = 0;while(rrp_bytes < 5) // loop until it has received 10 contiguous RF bytes{//-----------------------------------------// wait for a start pulse >200uSwhile(1){rrp_period = pulseIn(receiver,LOW)/multipier; // grab the pulse period!//rrp_period2 = pulseIn(receiver,HIGH); // grab the pulse period!//rrp_period = rrp_period1 + rrp_period2;//Serial.println(rrp_period);// and ready to record next periodif(rrp_period < 250) rrp_bytes = 0; // clear bytecount if still receiving noiseelse break; // exit if pulse was >200uS}//-----------------------------------------// now we had a start pulse, record 8 bitsrrp_bits = 8;while(rrp_bits){rrp_period = pulseIn(receiver,LOW)/multipier; // grab the pulse period!//Serial.println(rrp_period);if(rrp_period >= 250) break; // if >=200uS, is unexpected start pulse!if(rrp_period < 80) bitWrite(rrp_data, 0, 0); // 61 = 122uSelse bitWrite(rrp_data,0,1);//Serial.println(rrp_data);if (rrp_bits!=1) rrp_data = (rrp_data << 1); // save the good bit into rrp_datarrp_bits--; // and record 1 more good bit done}//Serial.println(rrp_data);//-----------------------------------------// gets to here after 8 good bits OR after an error (unexpected start pulse)if(rrp_bits) // if error{rrp_bytes = 0; // reset bytes, must run from start of a new packet again!}else // else 8 good bits were received{rxdat = rrp_data; // so save the received byte into arrayrrp_bytes++; // record another good byte was saved//Serial.print("LOW float instruction = ");//Serial.println(rxdat);//Serial.print("HIGH float instruction = ");//Serial.println(rxdat);}Serial.print("instruction = ");Serial.println(rxdat);task(rxdat);}}