Displaying laser/light encoded messages on i2c lcd display

Hi guys,

I'm fallowing this instructable: https://www.instructables.com/id/Arduino-Encoded-and-Modulated-Laser-and-Infrared-S/

And I'm trying to get the messages that are received to display on a lcd display on arduino uno.

I've tried things like "lcd.print(pdiode.printbyte());" and trying to add "lcd.print();" to the library so that whenever the messages are printed to serial monitor they also print to the lcd, but so far none are working.

So after some more testing I've added the lcd header files into "HT_light_modulator.h" and added "lcd.print((char)msg_done);" to the printbyte() function (same header file). The result is that not all the information gets transmitted either to serial or the lcd. sending a message like "1234" might only receive a "1" or nothing at all, on serial monitor or lcd. This is the closest I've been to getting it to work.

Any suggestions?

1) make sure you actually receive the messages: print the received data (if any, that is) to the Serial console. 2) make sure your display works: run the example sketches that come with the library you use. When those two work separately, it should be pretty easy to get the received message to show on your lcd. If it still doesn't work, and you need more help, read this and follow the instructions (had you done so already you'd no doubt have known better than to cross post).

  1. The messages are being received, when the timestamp function is turned on in serial monitor the receive side will acknowledge the received data either by printing the timestamp, or in some cases parts of the sent message.

  2. The LCD has been tested and working. Both the receiver and LCD work independently, but once the LCD code has has been added to the receiver code, there seems to be some sort of problem with the receiver not printing the whole message.

Sorry for cross-posting, I did read the instructions, however I did not receive any replies and thought this section would be better suited. I don’t see an option to delete threads, or to move them.

I will attach my code though it’s pretty simple.

Link to instructable github:

Minor changes to add LCD code to github example:

/* Serial laser communicator, receiver

 The circuit:
 * laser VCC pin to pin 6, - pin to ground
 * photodiode signal on pin 7, power pins as normal

 Note:
 * timer 2 used
 * For arduino uno or any board with ATMEL 328/168.. diecimila, duemilanove, lilypad, nano, mini...
 
 Author: Andrew R. from HobbyTransform (http://hobbytransform.com/)
 Written in 2016
*/

#include <HT_hamming_encoder.h>
#include <HT_light_modulator.h>

HT_PhotoReceiver pdiode;

#include <Wire.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


void setup(){

  Serial.begin(9600);
  lcd.init();                      // initialize the lcd 
  // Print a message to the LCD.
  lcd.backlight();
  lcd.setCursor(1,0);
  lcd.print("hello everyone");
  pdiode.set_speed(25000);      // bits/sec, must match laser bit transfer rate
  pdiode.begin();

}//end setup


//timer2 interrupts LIGHT_RECEIVE_PIN at determined speed to receive each half bit
//via the manchester modulated signal.
ISR(TIMER2_COMPA_vect){
  
  //receive message, if any
  pdiode.receive();

  
}


void loop(){
  
  //print and return most recently received byte, if any, only once
  pdiode.printByte();
  
}

Continued…

The header file “HT_light_modulator.h” with changes to the function “printbyte()” at the bottom:

/**   
 ******************************************************************************   
 * @file    HT_light_modulator.h
 * @author  Andrew Ramanjooloo   
 * @date    3-06-2016
 * @brief   photo transceiver peripheral driver
 *
 *		v1.0	-	used timer0
 *		v2.0	-	switched to timer2 as timer0 was intefering with delay()
 *
 ******************************************************************************   
 *     EXTERNAL FUNCTIONS
 ******************************************************************************
 *	
 ******************************************************************************   
 */

#include <Wire.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

#ifndef HT_light_modulator_H
#define HT_light_modulator_H
/* Includes ------------------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
#define	CLOCK_SPEED			16000000
#define LIGHT_SEND_PIN		6
#define LIGHT_RECEIVE_PIN	7

/* Private typedef -----------------------------------------------------------*/
class HT_PhotoTransmitter
{
	unsigned long tx_speed;			// bits/second
	uint8_t tx_buffer[44];
	uint8_t tx_bitnum;			// bit number to be transmitted
	int send_flag;				// light send flag
	
	public:
		void set_speed(unsigned long custom_speed){
			
			tx_speed = custom_speed;
			
		}
		
		unsigned long get_speed(){
			
			return (tx_speed);
			
		}
		
		void begin(){
			tx_bitnum = 0;      // bit number to be transmitted
			send_flag = 0;      // light send flag
			
			cli();//stop interrupts

			//set timer2 interrupt at specified frequency
			TCCR2A = 0;// set entire TCCR2A register to 0
			TCCR2B = 0;// same for TCCR2B
			TCNT2  = 0;//initialize counter value to 0
			// set compare match register for 2khz increments
			OCR2A = (CLOCK_SPEED / (2 * tx_speed * 64)) - 1;// = (16*10^6) / (2000*64) - 1 (must be <256)
			// turn on CTC mode
			TCCR2A |= (1 << WGM21);
			// Set CS22 bit for 64 prescaler
			TCCR2B |= (1 << CS22);   
			// enable timer compare interrupt
			TIMSK2 |= (1 << OCIE2A);

			sei();//allow interrupts
			
			//set light pin as output
			pinMode(LIGHT_SEND_PIN, OUTPUT);
		}
		
		void manchester_modulate(uint16_t light_msg){
			int i;
			uint8_t tmp;
			
			// first start bit
			for(i = 0; i < 4; i++){
				tx_buffer[i] = i%2;
			}
			
			for(i = 15; i >= 8; i--){
				tmp = !!(light_msg & (1 << i));         // i-th bit value of tx_buffer
				tx_buffer[2*(15-i) + 4] = (tmp ^ 1);
				tx_buffer[2*(15-i) + 5] = (tmp ^ 0);
			}
			
			// first stop bit
			tx_buffer[20] = 1;
			tx_buffer[21] = 0;
			
			// second start bit
			for(i = 22; i < 26; i++){
				tx_buffer[i] = i%2;
			}
			
			for(i = 7; i >= 0; i--){
				tmp = !!(light_msg & (1 << i));         // i-th bit value of tx_buffer
				tx_buffer[2*(7-i) + 26] = (tmp ^ 1);
				tx_buffer[2*(7-i) + 27] = (tmp ^ 0);
			}
			
			// second stop bit
			tx_buffer[42] = 1;
			tx_buffer[43] = 0;
			
			send_flag = 1;
		}
		
		void transmit(){
			//generates pulse wave of frequency 2kHz/2 = 1kHz (takes two cycles for full wave- toggle high then toggle low)

			// Generate wave based on manchester input
			if(send_flag){
				digitalWrite(LIGHT_SEND_PIN,tx_buffer[tx_bitnum]);

				// shift to next bit in the send buffer
				if(tx_bitnum < 43){
					tx_bitnum++;    // next bit
				} else {
					tx_bitnum = 0;    // reset to beginning of buffer
					send_flag = 0;    // done sending
				}
			}

		}
};


class HT_PhotoReceiver
{
	unsigned long rx_speed;			// bits/second
	uint8_t rx_buffer[44];
	uint8_t rx_bitnum;			// number of bits received
	int recv_flag;				// light receive flag
	uint16_t msg_raw;
	uint8_t msg_done;
	uint8_t can_print;

	public:
		void set_speed(unsigned long custom_speed){
			
			rx_speed = custom_speed;
			
		}
		
		unsigned long get_speed(){
			
			return (rx_speed);
			
		}
		
		void begin(){
			rx_bitnum = 0;      // bit number to be transmitted
			recv_flag = 0;      // light send flag
			can_print = 0;
			
			cli();//stop interrupts

			//set timer2 interrupt at specified frequency
			TCCR2A = 0;// set entire TCCR2A register to 0
			TCCR2B = 0;// same for TCCR2B
			TCNT2  = 0;//initialize counter value to 0
			// set compare match register for 2khz increments
			OCR2A = (CLOCK_SPEED / (2 * rx_speed * 64)) - 1;// = (16*10^6) / (2000*64) - 1 (must be <256)
			// turn on CTC mode
			TCCR2A |= (1 << WGM21);
			// Set CS22 bit for 64 prescaler
			TCCR2B |= (1 << CS22);   
			// enable timer compare interrupt
			TIMSK2 |= (1 << OCIE2A);

			sei();//allow interrupts
			
			//set photodiode pin as input
			pinMode(LIGHT_RECEIVE_PIN, INPUT);
		}
		
		uint16_t manchester_demodulate(){
			uint8_t i, check1, check2;
			uint16_t out = 0;
			
			/* first frame */
			for(i = 4; i < 20; i+=2){
				check1 = rx_buffer[i];
				check2 = rx_buffer[i+1];
				if(!check1 && check2) out |= (1 << (15-((i-4)/2)));
			}
			
			/* second frame */
			for(i = 26; i < 42; i+=2){
				check1 = rx_buffer[i];
				check2 = rx_buffer[i+1];
				if(!check1 && check2) out |= (1 << (7-((i-26)/2)));
			}
			return (out);
		}
		
		void receive(){
			int tmp;
			
			if(!recv_flag){
				tmp = !!(PIND & (1 << LIGHT_RECEIVE_PIN));		// direct pin access is better (quicker) than digitalRead at high frequencies
				switch(rx_bitnum){
					case 0:
						if(tmp == 1) rx_bitnum = 1;
						break;
					case 1:
						if(tmp == 0) rx_bitnum = 2;
						else rx_bitnum = 0;
						break;
					case 2:
						if(tmp == 1) rx_bitnum = 3;
						else rx_bitnum = 0;
						break;
					case 3:
						recv_flag = 1;
						for(rx_bitnum = 0; rx_bitnum < 4; rx_bitnum++){
							rx_buffer[rx_bitnum] = rx_bitnum % 2;
						}
						rx_bitnum = 4;
						rx_buffer[rx_bitnum] = tmp;
						rx_bitnum++;
						break;
				}
			} else if(rx_bitnum < 44){
				rx_buffer[rx_bitnum] = !!(PIND & (1 << LIGHT_RECEIVE_PIN));
				rx_bitnum++;
			} else {
				rx_bitnum = 0;
				recv_flag = 0;
				
				// Read data from the photodiode
				msg_raw = manchester_demodulate();
				msg_done = hamming_byte_decoder((msg_raw >> 8), (0xFF & msg_raw));
				
				can_print = 1;
				
			}
		}
		
		uint8_t printByte(){
			if(can_print){
				Serial.print((char)msg_done);
                                lcd.print((char)msg_done);
				can_print = 0;
			}
			return (msg_done);
		}
};

/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* External function prototypes -----------------------------------------------*/
#endif

No changes to “HT_hamming_encoder.h” or “HT_hamming_encoder.cpp” in the library.

Then wiring is pretty simple, transmitter (ky-oo8 laser module) S to pin 6, - to ground, receiver “laser sensor module, non-modulated” signal on pin 7, power pins as normal, i2c LCD display connected ground/vcc to power and ground, SDA/SCL to SDA and SCL pins on arduino uno.