displaying Hexadecimal value in LCD - atmega

I wrote LCD interface program for Atmega328 (Though there are libraries available, I wanted to write from scratch). But have two problems.
1. Sometimes LCD does not display correctly. Only few strips are seen. I end up in resetting once or twice.
2. I am unable to display hexadecimal values usingdisplayOneByteHexValue(). However ASCII coversion was correct and I could see that in Atmel Simulator. Below is the code. I am using Atmel Studio 6.2
/*
* EmbeddedProgram1.c
*
* Created: 16-05-2015 08:19:38
* Author: Mahesha
*/
#ifndef F_CPU
#define F_CPU 8000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Only Change following when changing pin numbers.
// All Data bits have to be assigned sequentially in same the port . RS and EN must be allocated in the same port
#define LCDPORT PORTD
#define LCDDDR DDRD
// used pins on port appropriate ports
#define LCD_DB4 2 // PORTD.2
#define LCD_DB5 3 // PORTD.3
#define LCD_DB6 4 // PORTD.4
#define LCD_DB7 5 // PORTD.5
#define LCD_ENABLE_BIT 6 // PORTD.6 Enable
#define LCD_RS 7 // PORTD.7 Register Select
//#define LCD_RW // R/W is connected to GND permanently
#define LCD_DATA_BITS_MASK 0x3C
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#define SET_EIGHT_BIT_MODE() LCDPORT|=((1<<LCD_DB5)|(1<<LCD_DB4)) // Set DB4 and DB5 as 1 for setting eight bit mode.
#define SET_FOUR_BIT_MODE() LCDPORT|=(1<<LCD_DB5)
#define SET_INSTRUCTION_MODE() LCDPORT&=~(1<<LCD_RS) //Function to select command port on LCD RS pin bit 2
#define SET_DATA_MODE() LCDPORT|=(1<<LCD_RS) //Function to select data port on LCD
#define DISABLE_LCD() LCDPORT&=~(1<<LCD_ENABLE_BIT) //Function to disable LCD P0.18
#define ENABLE_LCD() LCDPORT|=(1<<LCD_ENABLE_BIT) //Function to Enable LCD P0.18
//#define EIGHT_BIT_MODE 0x30 // 0 0 1 1 x x x x DB7 to DB0 0f LCD
#define BUSY_FLAG_WAIT_TIME 20
#define FOUR_BIT_5_BY_10_2LINE 0x28
#define LCD_INIT_DELAY 100 // Give a delay of 200 msec after reset. // Datasheet says 10 msec delay.
//Commands Finalized
#define CLEAR_DISPLAY 0x01
#define CURSOR_HOME 0x02 // return home
#define ENTRY_MODE_LEFT_TO_RIGHT 0x06 // Cursor direction from Left to right , Bit 1 of entry mode in LCD
#define DISPLAY_OFF 0x08 // Blink ON, Cursor ON etc are don't care
#define CURSOR_OFF_BLINK_OFF 0x0C
#define CURSOR_OFF_BLINK_ON 0x0D // blink on Even 0x0D also works. So cursor need not be ON
#define CURSOR_ON_BLINK_OFF 0x0E // blink off
#define CURSOR_ON_BLINK_ON 0x0F
#define SHIFT_ENTIRE_LEFT 0x18
#define SHIFT_CURSOR_LEFT 0x10
#define SHIFT_ENTIRE_RIGHT 0x1C
#define SHIFT_CURSOR_RIGHT 0x14
// Function prototypes
void unpackAndSend(char data);
void waitForBusyFlagToClear(void);
void sendLCDPulse(void);
void displayInRow1(char* data);
void displayInRow2(char* data);
void displayInRow1WithPosition(char* data, uint8_t position);
void displayInRow2WithPosition(char* data, uint8_t position);
void sendTextToLCD(char *data);
void displayOneByteHexValue(unsigned char,unsigned char,char);
void initializeLCD(void);
void CL_delayMS(unsigned int delayMS)
{
while(delayMS--)
{
_delay_ms(1);
}
}
void CL_delayuS(unsigned int delayus)
{
while(delayus--)
{
_delay_us(1);
}
}
// writes a char to the LCD
void writeCharToLCD(unsigned char data)
{
SET_DATA_MODE(); // RS bit has to be 1 for data mode
unpackAndSend(data);
}
// sendLCD pulse will just enable and disable the EN bit of LCD display.
void sendLCDPulse(void)
{
DISABLE_LCD();
CL_delayuS(50);
ENABLE_LCD();
CL_delayMS(1);
DISABLE_LCD();
CL_delayMS(1);
}
// writes an instruction to the LCD
void sendLCDCommand(unsigned char inst)
{
SET_INSTRUCTION_MODE();
unpackAndSend(inst);
waitForBusyFlagToClear();
}
// Unpack and send data will separate two nibbles and send twice.
void unpackAndSend(char inst)
{
char temp=inst;
DISABLE_LCD();
// SET_WRITE_MODE(); // If write is permanently disabled, do not use this.
LCDPORT &= (~LCD_DATA_BITS_MASK); // Clear the data bits
//sendLCDPulse();
inst&=0xF0;
inst=inst>>4; // Get the upper nibble
LCDPORT|=inst<<LCD_DB4; //Replace the bits starting from position of bit LCD_DB4 with this new data
sendLCDPulse();
LCDPORT &= (~LCD_DATA_BITS_MASK); // Clear the data bits again
//sendLCDPulse();
temp &=0x0f; //send low nibble
LCDPORT|=temp<<LCD_DB4;
sendLCDPulse();
}
// waitForBusyFlagToClear functio can wait for the busy bit, But since we are permanently connected R/W pin to ground, we cannot read
// the flag from LCD. In case busy bit has to be read, implementation has to be changed.
void waitForBusyFlagToClear(void)
{
CL_delayMS(BUSY_FLAG_WAIT_TIME);
}
// clear display
void clearDisplay(void)
{
sendLCDCommand (CLEAR_DISPLAY);
}
// return home
void returnCursorHome(void)
{
sendLCDCommand (CURSOR_HOME);
}
// LCD off
void displayOFF(void)
{
sendLCDCommand (DISPLAY_OFF);
}
// LCD on
void displayONCursorOFF(void)
{
sendLCDCommand (CURSOR_OFF_BLINK_OFF);
}
// cursor on
void displayONCursorON(void)
{
sendLCDCommand (CURSOR_ON_BLINK_OFF);
}
// blink on
void cursorOffBlinkOn(void)
{
sendLCDCommand (CURSOR_OFF_BLINK_ON);
}
// blink OFF, but display and cursors are ON
void cursorOnBlinkOff(void)
{
sendLCDCommand (CURSOR_ON_BLINK_OFF);
}
// All are ON
void cursorOnBlinkOn(void)
{
sendLCDCommand (CURSOR_ON_BLINK_ON);
}
//go to first line
void LCDline1 (void)
{
sendLCDCommand (0b10000000);
}
//go to second line
void LCDline2 (void)
{
sendLCDCommand (0b11000000);
}
// goto position x,y
// row1 or row2 are the parameters
// So parameters can be 1 or 2
void setRowAndColumnPositionOnDisplay (unsigned char rowNumber, unsigned char position)
{
unsigned char pos;
if (rowNumber == 1)
{
pos = 0x00 + position;
pos|=0x80; // Command to set 1st Row.
}
else //if (rowNumber == 1) // Either row 1 or two. We cannot have else option.
{
pos = 0x40 + position;
pos|=0xC0; // Command to set second row.
}
sendLCDCommand (pos);
}
void displayInRow1(char* data)
{
sendLCDCommand(0x80); // Set DDRAM Address as 0
sendTextToLCD(data);
}
void displayInRow1WithPosition(char* data, unsigned char position)
{
// The position cannot be more than 15. Display is 16 characters (0-15).
if(position>15)
{
position = 15;
}
sendLCDCommand(0x80|position); // Change the DDRAM address to first line by
// keeping D7 high and setting address to 0 onwards
sendTextToLCD(data);
}
////////////////////////////// diaplayInRow2 /////////////////////////////////////////////
void displayInRow2(char* data)
{
sendLCDCommand(0xC0); // Change the DDRAM address to next line 0x40 to 4F
sendTextToLCD(data);
}
////////////////////// diaplayInRow2WithPosition //////////////////////
void displayInRow2WithPosition(char* data, unsigned char position)
{
// The position cannot be more than 15. Display is 16 characters (0-15).
if(position>15)
{
position = 15;
}
sendLCDCommand(0xC0|position); // Change the DDRAM address to second line by
//keeping Bit D7 high and setting address at 0x40 onwards
sendTextToLCD(data);
}
void scrollLcd(char *row1Data,char *row2Data)
{
while(1)
{
sendLCDCommand(SHIFT_CURSOR_LEFT);
sendLCDCommand(SHIFT_ENTIRE_LEFT);
CL_delayMS(200);
}
}
//write text to the LCD
void sendTextToLCD(char *data)
{
while (*data)
{
writeCharToLCD(*data);
data++;
}
}
// Function to convert lower nibble to ASCII Value
//Only lower nibble of the input is considered and higher nibble is lost
char convertLowerNibbleToASCIIValue(char data)
{
data&=0x0F;
if(data<=9)
{
return(data+0x30);
}
else // There is no chance for getting more than 0x0F in the lowerNibble Parameter)
{
return(data+0x37);
}
}
// Function to convert Higher nibble to ASCII Value
//Only higher nibble of the input is considered and lower nibble is lost
char convertHigherNibbleToASCIIValue(char data)
{
data>>=4;
if(data<=9)
{
return(data+0x30);
}
else // There is no chance for getting more than 0x0F in the lowerNibble Parameter)
{
return(data+0x37);
}
}
void displayOneByteHexValue(unsigned char rowNum, unsigned char pos, char data)
{
char temp;
setRowAndColumnPositionOnDisplay(rowNum,pos);
temp = convertHigherNibbleToASCIIValue(data);
sendTextToLCD(&temp);
temp = convertLowerNibbleToASCIIValue(data);
sendTextToLCD(&temp);
}
// init LCD
void initializeLCD(void)
{
// Set the direction of port pins connected to LCD display as output ports.
// We are permanently connecting R/W pin to ground. So there is no read instruction in this case..
LCDDDR |= (1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7)|(1<<LCD_RS)|(1<<LCD_ENABLE_BIT);
//After reset, data sheet suggests some delay.
CL_delayMS(LCD_INIT_DELAY);
// Note some sites says three times 8 bit mode setting commands need to be sent.
// But it is observed that even without this, LCD works fine. So 1st Command, 2nd Command and 3rd Commands can be deleted below.
//ENABLE_LCD();
// 1st Command
SET_EIGHT_BIT_MODE();
//sendLCDPulse(); // Do not delete this. Need to further analyse. If pulse if sent it is not working
//CL_delayMS(5); // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
_delay_ms(5);
// Second Command
SET_EIGHT_BIT_MODE();
//sendLCDPulse();
_delay_us(100);
//CL_delayuS(100); // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
// third Command
SET_EIGHT_BIT_MODE();
//sendLCDPulse();
//CL_delayuS(100); // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
_delay_us(37);
// Finally Set four bit mode
SET_FOUR_BIT_MODE();
//sendLCDPulse();
CL_delayuS(100);
// First time when 4 bit mode command is sent, only one higher nibble was sent since
// only 4 bits are connected from MPU to LCD. Since D0 to D3 of LCD are not connected,
// their values depend on how the pins are connected in LCD module (May be grounded, may kept open etc)
//So again send function set command to set 2 line display mode mode and 5x7 character mode. But now two write operations to LCD is made
// inside the function sendLCDCommand.
sendLCDCommand (FOUR_BIT_5_BY_10_2LINE);
//turn on display and cursor OFF, Blink OFF (sent two times using below command)
sendLCDCommand (CURSOR_OFF_BLINK_OFF);
//clr display
sendLCDCommand (CLEAR_DISPLAY);
// Set Entry mode left to right
sendLCDCommand (ENTRY_MODE_LEFT_TO_RIGHT);
}
void LCDProgramCallFromMain(char *row1Data, char *row2Data)
{
initializeLCD();
setRowAndColumnPositionOnDisplay (1,0);
sendTextToLCD (row1Data);
displayOneByteHexValue(2,0,0xF4);
//setRowAndColumnPositionOnDisplay (2,5);
//displayInRow1(row1Data);
}
int main(void)
{
LCDProgramCallFromMain("Hello", "Welcome to cloude");
while(1)
{
}
}
Below is the image of the display I am getting. Not able to makeout where the problem is.

Yes, it worked after I changed the function as below. Thanks for the help.
void displayOneByteHexValue(unsigned char rowNum, unsigned char pos, char data)
{
char temp;
setRowAndColumnPositionOnDisplay(rowNum,pos);
temp = convertHigherNibbleToASCIIValue(data);
writeCharToLCD(temp);
temp = convertLowerNibbleToASCIIValue(data);
writeCharToLCD(temp);
}
I further optimized the code and below is the complete working code with small demo function called from main.
#ifndef F_CPU
#define F_CPU 16000000UL
#endif
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <avr/sfr_defs.h>
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//Only Change following when changing pin numbers.
// All Data bits have to be assigned sequentially in same the port . RS and EN must be allocated in the same port
#define LCDPORT PORTD
#define LCDDDR DDRD
// used pins on port appropriate ports
#define LCD_DB4 2 // PORTD.2
#define LCD_DB5 3 // PORTD.3
#define LCD_DB6 4 // PORTD.4
#define LCD_DB7 5 // PORTD.5
#define LCD_ENABLE_BIT 6 // PORTD.6 Enable
#define LCD_RS 7 // PORTD.7 Register Select
//#define LCD_RW // R/W is connected to GND permanently
#define LCD_DATA_BITS_MASK ((1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7))
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/*
#define SET_EIGHT_BIT_MODE() LCDPORT|=((1<<LCD_DB5)|(1<<LCD_DB4)) // Set DB4 and DB5 as 1 for setting eight bit mode.
#define SET_FOUR_BIT_MODE() LCDPORT|=(1<<LCD_DB5)
*/
#define SET_INSTRUCTION_MODE() LCDPORT&=~(1<<LCD_RS) //Function to select command port on LCD RS pin bit 2
#define SET_DATA_MODE() LCDPORT|=(1<<LCD_RS) //Function to select data port on LCD
#define DISABLE_LCD() LCDPORT&=~(1<<LCD_ENABLE_BIT) //Function to disable LCD P0.18
#define ENABLE_LCD() LCDPORT|=(1<<LCD_ENABLE_BIT) //Function to Enable LCD P0.18
#define BUSY_FLAG_WAIT_TIME 20
#define FOUR_BIT_5_BY_10_2LINE 0x28
#define LCD_INIT_DELAY 100 // Give a delay of 100 msec after reset. // Datasheet says 10 msec delay.
// Function prototypes for external use (to be kept in Header file)
void sendLCDCommand(unsigned char cmd);
void displayInRow1(unsigned char* data);
void displayInRow2(unsigned char* data);
void displayInRow1WithPosition(unsigned char* data, uint8_t position);
void displayInRow2WithPosition(unsigned char* data, uint8_t position);
void sendTextToLCD(unsigned char *data);
void initializeLCD(void);
// Function prototypes for file use (only internal)
void unpackAndSend(char data);
void waitForBusyFlagToClear(void);
void sendLCDPulse(void);
void displayOneByteHexValue(unsigned char,unsigned char,char); // This function is no longer needed. Only for demo purpose.
// #define commands are replaced by enums to demonstrate the feature of enumerated data types
enum DISPLAY_PROPERTY
{
CLEAR_DISPLAY=0x01,
CURSOR_HOME = 0x02, // return home
ENTRY_MODE_LEFT_TO_RIGHT= 0x06, // Cursor direction from Left to right , Bit 1 of entry mode in LCD
DISPLAY_OFF= 0x08, // Blink ON, Cursor ON etc are don't care
CURSOR_OFF_BLINK_OFF= 0x0C,
CURSOR_OFF_BLINK_ON= 0x0D, // blink on Even 0x0D also works. So cursor need not be ON
CURSOR_ON_BLINK_OFF=0x0E, // blink off
CURSOR_ON_BLINK_ON=0x0F,
SHIFT_ENTIRE_LEFT= 0x18,
SHIFT_CURSOR_LEFT= 0x10,
SHIFT_ENTIRE_RIGHT= 0x1C,
SHIFT_CURSOR_RIGHT= 0x14,
};
void SET_EIGHT_BIT_MODE(void)
{
LCDPORT=(LCDPORT&(~LCD_DATA_BITS_MASK))|((0<<LCD_DB7)|(0<<LCD_DB6)|(1<<LCD_DB5)|(1<<LCD_DB4)); // Set DB4 and DB5 as 1 for setting eight bit mode.
}
void SET_FOUR_BIT_MODE(void)
{
LCDPORT= (LCDPORT&(~LCD_DATA_BITS_MASK)) | ((0<<LCD_DB7)|(0<<LCD_DB6)|(1<<LCD_DB5)|(0<<LCD_DB4));
}
void CL_delayMS(unsigned int delayMS)
{
while(delayMS--)
{
_delay_ms(1);
}
}
void CL_delayuS(unsigned int delayus)
{
while(delayus--)
{
_delay_us(1);
}
}
// writes a char to the LCD
void writeCharToLCD(unsigned char data)
{
SET_DATA_MODE(); // RS bit has to be 1 for data mode
unpackAndSend(data);
}
// sendLCD pulse will just enable and disable the EN bit of LCD display.
void sendLCDPulse(void)
{
//DISABLE_LCD();
//CL_delayuS(50);
ENABLE_LCD();
CL_delayMS(1);
DISABLE_LCD();
CL_delayMS(1);
}
// writes an instruction to the LCD
void sendLCDCommand(unsigned char cmd)
{
SET_INSTRUCTION_MODE();
unpackAndSend(cmd);
waitForBusyFlagToClear();
}
// Unpack and send data will separate two nibbles and send twice.
void unpackAndSend(char inst)
{
char temp=inst;
DISABLE_LCD();
// SET_WRITE_MODE(); // If write is permanently disabled, do not use this.
LCDPORT &= (~LCD_DATA_BITS_MASK); // Clear the data bits
//sendLCDPulse();
inst&=0xF0;
inst=inst>>4; // Get the upper nibble
LCDPORT|=inst<<LCD_DB4; //Replace the bits starting from position of bit LCD_DB4 with this new data
sendLCDPulse();
LCDPORT &= (~LCD_DATA_BITS_MASK); // Clear the data bits again
//sendLCDPulse();
temp &=0x0f; //send low nibble
LCDPORT|=temp<<LCD_DB4;
sendLCDPulse();
}
// waitForBusyFlagToClear function can wait for the busy bit, But since we are permanently connected R/W pin to ground, we cannot read
// the flag from LCD. In case busy bit has to be read, implementation has to be changed.
void waitForBusyFlagToClear(void)
{
CL_delayMS(BUSY_FLAG_WAIT_TIME);
}
// goto position x,y
// row1 or row2 are the parameters
// So parameters can be 0 or 1
void setRowAndColumnPositionOnDisplay (unsigned char rowNumber, unsigned char position)
{
unsigned char pos;
if (rowNumber==0) // If Row is 0, display in 1st row
{
pos = 0x00 + position;
pos|=0x80; // Command to set 1st Row.
}
else //if (rowNumber == 1) // Either row 1 or two etc
{
pos = 0x40 + position;
pos|=0xC0; // Command to set second row.
}
sendLCDCommand (pos);
}
void displayInRow1(unsigned char* data)
{
sendLCDCommand(0x80); // Set DDRAM Address as 0
sendTextToLCD(data);
}
void displayInRow1WithPosition(unsigned char* data, unsigned char position)
{
sendLCDCommand(0x80|position); // Change the DDRAM address to first line by
// keeping D7 high and setting address to 0 onwards
sendTextToLCD(data);
}
////////////////////////////// diaplayInRow2 /////////////////////////////////////////////
void displayInRow2(unsigned char* data)
{
sendLCDCommand(0xC0); // Change the DDRAM address to next line 0x40 to 4F
sendTextToLCD(data);
}
////////////////////// diaplayInRow2WithPosition //////////////////////
void displayInRow2WithPosition(unsigned char* data, unsigned char position)
{
sendLCDCommand(0xC0|position); // Change the DDRAM address to second line by
//keeping Bit D7 high and setting address at 0x40 onwards
sendTextToLCD(data);
}
//write text to the LCD
void sendTextToLCD(unsigned char *data)
{
while (*data)
{
writeCharToLCD(*data);
data++;
}
}
// initialize LCD
void initializeLCD(void)
{
// Set the direction of port pins connected to LCD display as output ports
// We are permanently connecting R/W pin to ground. So there is no read instruction in this case
LCDDDR |= (1<<LCD_DB4)|(1<<LCD_DB5)|(1<<LCD_DB6)|(1<<LCD_DB7)|(1<<LCD_RS)|(1<<LCD_ENABLE_BIT);
//After reset, data sheet suggests some delay.
CL_delayMS(LCD_INIT_DELAY);
// Note some sites says three times 8 bit mode setting commands need to be sent.
// But it is observed that even without this, LCD works fine. So 1st Command, 2nd Command and 3rd Commands can be deleted below.
//ENABLE_LCD();
// 1st Command
SET_EIGHT_BIT_MODE();
sendLCDPulse(); // Do not delete this. Need to further analyze. If pulse if sent it is not working
//CL_delayMS(5); // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
_delay_ms(5);
// Second Command
SET_EIGHT_BIT_MODE();
sendLCDPulse();
_delay_us(100);
//CL_delayuS(100); // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
// third Command
SET_EIGHT_BIT_MODE();
sendLCDPulse();
//CL_delayuS(100); // Do not use this delay since delay is not acurate, Either use _delay_ms or use timers
_delay_us(37);
// Finally Set four bit mode
SET_FOUR_BIT_MODE();
sendLCDPulse();
CL_delayuS(100);
// First time when 4 bit mode command is sent, only one higher nibble was sent since
// only 4 bits are connected from MPU to LCD. Since D0 to D3 of LCD are not connected,
// their values depend on how the pins are connected in LCD module (May be grounded, may kept open etc)
//So again send function set command to set 2 line display mode mode and 5x7 character mode. But now two write operations to LCD is made
// inside the function sendLCDCommand.
sendLCDCommand (FOUR_BIT_5_BY_10_2LINE);
//turn on display and cursor OFF, Blink OFF (sent two times using below command)
sendLCDCommand (CURSOR_OFF_BLINK_OFF);
//clr display
sendLCDCommand (CLEAR_DISPLAY);
// Set Entry mode left to right
sendLCDCommand (ENTRY_MODE_LEFT_TO_RIGHT);
}
void displayNumberTest(int range)
{
float fNum = -0.332;
unsigned char lcdBuffer[50];
sendLCDCommand(CLEAR_DISPLAY);
//setRowAndColumnPositionOnDisplay (0,0);
//sendTextToLCD("Decimal = ");
for (int count=0;count<range;count++)
{
itoa(count,lcdBuffer,2);
setRowAndColumnPositionOnDisplay (1,0);
sendTextToLCD(lcdBuffer);
itoa(count,lcdBuffer,16);
setRowAndColumnPositionOnDisplay (1,13);
sendTextToLCD(lcdBuffer);
itoa(count,lcdBuffer,10);
setRowAndColumnPositionOnDisplay (0,0); // 1st Row, 0th position
sendTextToLCD(lcdBuffer);
// Now display some floating value number.
// use the function dtostrf(). It take 4 parameters
// Parameter1: The value to be converted
// 2: Width
//3. Precision
// 4. String to hold ASCII
// It is also possible to use sprintf function. But it takes more memory.
fNum=(fNum*(-1)*(count+1)/101.12)+0.012;
dtostrf(fNum,5,3,lcdBuffer);
setRowAndColumnPositionOnDisplay (0,7);
sendTextToLCD(lcdBuffer);
CL_delayMS(300);
}
}
// Scroll the display
// This program need to be modified further to display only whatever characters are there in DDRAM.
// Right now 4 columns will be shifted just to demonstrate.
void scrollingDisplayTest(unsigned char *row1Text, unsigned char* row2Text, unsigned int scrollDelay)
{
unsigned char count=40;
sendLCDCommand(CLEAR_DISPLAY);
displayInRow1(row1Text);
displayInRow2(row2Text);
CL_delayMS(2000);
while(count--)
{
sendLCDCommand(SHIFT_ENTIRE_LEFT);
CL_delayMS(scrollDelay);
}
}
void LCDDemoProgram(unsigned char *row1Data, unsigned char *row2Data)
{
initializeLCD();
sendTextToLCD (row1Data);
setRowAndColumnPositionOnDisplay (1,0);
sendTextToLCD (row2Data);
CL_delayMS(3000);
sendLCDCommand(CLEAR_DISPLAY);
// Just to demostrate how Hex values can be displayed without using itoa library function
displayOneByteHexValue(0,0,CLKPR);
setRowAndColumnPositionOnDisplay (1,0);
displayOneByteHexValue(1,12,0xE2);
CL_delayMS(3000);
sendLCDCommand(CLEAR_DISPLAY);
//Wait for 3 seconds
scrollingDisplayTest("Display will be cleared for 3 sec after displaying DONE ", "Please Wait.... Please Wait.....",1000);
CL_delayMS(2000);
sendLCDCommand(CLEAR_DISPLAY);
displayInRow1("DONE");
CL_delayMS(3000);
displayInRow1("Cur OFF Bl OFF");
sendLCDCommand(CURSOR_OFF_BLINK_OFF);
CL_delayMS(3000);
sendLCDCommand(CLEAR_DISPLAY);
displayInRow1("Cur OFF Bl ON");
sendLCDCommand(CURSOR_OFF_BLINK_ON);
CL_delayMS(3000);
sendLCDCommand(CLEAR_DISPLAY);
displayInRow1("Cur ON Bl OFF");
sendLCDCommand(CURSOR_ON_BLINK_OFF);
CL_delayMS(3000);
sendLCDCommand(CLEAR_DISPLAY);
displayInRow1("Cur ON Bl ON");
sendLCDCommand(CURSOR_ON_BLINK_ON);
CL_delayMS(3000);
displayNumberTest(100);
}
//////////////////////////////////////////////// Do No Use Below code. This is Only for demo purpose//////////////////////////////////////////
// Function to convert lower nibble to ASCII Value
//Only lower nibble of the input is considered and higher nibble is lost
// This function is written for understanding purpose only.
// itoa () library function can be used instead of this with base of 16.
unsigned char convertLowerNibbleToASCIIValue(unsigned char data)
{
data&=0x0F;
if(data<=9)
{
return(data+0x30);
}
else // There is no chance for getting more than 0x0F in the lowerNibble Parameter)
{
return(data+0x37);
}
}
// Function to convert Higher nibble to ASCII Value
//Only higher nibble of the input is considered and lower nibble is lost
unsigned char convertHigherNibbleToASCIIValue(unsigned char data)
{
data>>=4;
if(data<=9)
{
return(data+0x30);
}
else // There is no chance for getting more than 0x0F in the lowerNibble Parameter)
{
return(data+0x37);
}
}
void displayOneByteHexValue(unsigned char rowNum, unsigned char pos, char data)
{
char temp;
setRowAndColumnPositionOnDisplay(rowNum,pos);
temp = convertHigherNibbleToASCIIValue(data);
writeCharToLCD(temp);
temp = convertLowerNibbleToASCIIValue(data);
writeCharToLCD(temp);
}
// Displays 8 bit Register values in LCD display unit.
// name is the name of the register to be displayed. You can give any name.
// port is the register name.
void displayRegisterValues(unsigned char *displayName, volatile uint8_t *registerName)
{
char temp2;
displayInRow1(displayName);
//temp2=registerName;
temp2 = (convertLowerNibbleToASCIIValue(*registerName));
displayInRow1(&temp2);
// Get the higher Nibble
temp2 = (convertLowerNibbleToASCIIValue((*registerName)>>4));
displayInRow2(&temp2);
}
int main(void)
{
LCDDemoProgram("Hello", "World is Great");
while(1)
{
//TODO:: Please write your application code
}
return(0);
}

Related

Receiving data from SIM808

I am trying to use SIM808 module but I have no response even after sending only "AT". I am using 5V/2.5A AC/DC adapter. The board (ecb-v3.2) is rather connected well because two diodes are on all the time and one is blinking every three seconds. I tried my UART code by sending and receiving data from uC to PC and it worked. I also tried to display some data in different parts of my code to find a line with a bug. I think that problem is in the while loop in which I am waiting for receiving a single char from SIM808 module. I marked this line in the code (in function UART_RxChar()). I am using two UARTs in my code, one for sending data between uC and PC (channel 0 in the code) and second for sending data between uC and SIM808 (channel 1), but I checked both versions on my computer. This is my code:
#define F_OSC 7372800UL
#define BAUD 115200
#define ubrr ((F_OSC/16/BAUD)-1)
#include <avr/io.h>
#include <util/delay.h>
#include "lcd.h"
void UART_TxString(char *string_ptr, uint8_t channel);
void UART_Init( uint8_t channel )
{
if ( channel == 0)
{
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR0B = (1<<TXEN0) | (1<<RXEN0);
/* Set frame format: 8data, 1stop bit */
UCSR0C = (1<<UCSZ00) | (1<<UCSZ01);
}
else
{
/*Set baud rate */
UBRR1H = (unsigned char)(ubrr>>8);
UBRR1L = (unsigned char)ubrr;
/*Enable receiver and transmitter */
UCSR1B = (1<<TXEN1) | (1<<RXEN1);
/* Set frame format: 8data, 1stop bit */
UCSR1C = (1<<UCSZ10)|(1<<UCSZ11);
}
}
char UART_RxChar( uint8_t channel )
{
if ( channel == 0 )
{
while((UCSR0A & (1<<RXC0))==0); // Wait till the data is received
return(UDR0); // return the received char
}
else
{
//Here is the problem. The condition in the loop is always true.
while((UCSR1A & (1<<RXC1))==0); // Wait till the data is received
return(UDR1); // return the received char
}
}
void UART_TxChar(char ch, uint8_t channel)
{
if ( channel == 0)
{
while((UCSR0A & (1<<UDRE0))==0); // Wait till Transmitter(UDR) register becomes Empty
UDR0 =ch; // Load the data to be transmitted
}
else
{
while((UCSR1A & (1<<UDRE1))==0); // Wait till Transmitter(UDR) register becomes Empty
UDR1 =ch; // Load the data to be transmitted
UART_TxChar(ch,0);
}
}
void UART_TxString(char *string_ptr, uint8_t channel)
{
while(*string_ptr)
UART_TxChar(*string_ptr++, channel);
}
void UART_RxString(char *string_ptr, uint8_t channel)
{
char ch;
while(1)
{
ch=UART_RxChar(channel); //Reaceive a char
UART_TxChar(ch, channel); //Echo back the received char
if((ch=='\r') || (ch=='\n')) //read till enter key is pressed
{ //once enter key is pressed
*string_ptr=0; //null terminate the string
break; //and break the loop
}
*string_ptr=ch; //copy the char into string.
string_ptr++; //and increment the pointer
}
}
int main(void)
{
UART_Init(0);
UART_Init(1);
initLCD();
UART_TxString("\r\nstart", 0);
while(1)
{
char ans[15] = "";
DDRE = 0xff;
UART_TxString("AT\r\n",1);
DDRE = 0x00;
UART_RxString(ans,1);
_delay_ms(2000);
}
}
I also checked all possibilities sending: AT\r", "AT\n", "AT\r\n", "AT\n\r.
Thank you in advance for any help.
The problem is you are echoing the received character back to SIM808 module on line
UART_TxChar(ch, channel); //Echo back the received char
this may confuse SIM808 and put it in inconsistent state.
Try connecting SIM808 module to PC and use CoolTerm to analyze response after firing AT command.

Trying to send a float value over SPI between 2 Arduinos

I am currently trying to send a float value across two Arduinos via SPI. Currently I am working to send a static value of 2.25 across and then read it via the Serial.println() command. I would then want to pass a float value from a linear displacement sensor. My end goal is to be able to have the master ask for information, the slave gathers the appropriate data and packages it and then master receives said data and does what it needs with it.
Currently I am getting an error "call of overloaded 'println(byte [7])' is ambiguous" and I am not to sure why I am getting this error. I am currently a mechanical engineering student and I am crash-coursing myself through C/C++. I am not entirely positive about what I am doing. I know that a float is 4 bytes and I am attempting to create a buffer of 7 bytes to store the float and the '\n' char with room to spare. My current code is below.
Master:
#include <SPI.h>
void setup() {
pinMode(SS,OUTPUT);
digitalWrite(SS,HIGH);
SPI.begin();
SPI.setClockDivider(SPI_CLOCK_DIV4);
}
void loop() {
digitalWrite(SS,LOW);
float a = 2.25;
SPI.transfer(a);
SPI.transfer('\n');
digitalWrite(SS,HIGH);
}
My slave code is as follows:
#include <SPI.h>
byte buf[7];
volatile byte pos = 0;
volatile boolean process_it = false;
void setup() {
Serial.begin(9600);
pinMode(MISO,OUTPUT);
digitalWrite(MISO,LOW);
SPCR |= _BV(SPE); // SPI Enable, sets this Arduino to Slave
SPCR |= _BV(SPIE); // SPI interrupt enabled
}
ISR(SPI_STC_vect) {
// Interrupt Service Routine(SPI_(SPI Transfer Complete)_vector)
byte c = SPDR;
// SPDR = SPI Data Register, so you are saving the byte of information in that register to byte c
if (pos < sizeof buf) {
buf[pos++] = c;
if (c == '\n') {
process_it = true;
}
}
}
void loop() {
if (process_it = true) {
Serial.println(buf);
pos = 0;
process_it = false;
}
}
I figured out what I needed to do and I wanted to post my finished code. I also added an ability to transfer more than one float value.
Master:
#include <SPI.h>
float a = 3.14;
float b = 2.25;
uint8_t storage [12];
float buff[2] = {a, b};
void setup()
{
digitalWrite(SS, HIGH);
SPI.begin();
Serial.begin(9600);
SPI.setClockDivider(SPI_CLOCK_DIV8);
}
void loop()
{
digitalWrite(SS, LOW);
memcpy(storage, &buff, 8);
Serial.print("storage[0] = "); Serial.println(storage[0]); // the
following serial prints were to check i was getting the right decimal
numbers for the floats.
Serial.print("storage[1] = "); Serial.println(storage[1]);
Serial.print("storage[2] = "); Serial.println(storage[2]);
Serial.print("storage[3] = "); Serial.println(storage[3]);
Serial.print("storage[4] = "); Serial.println(storage[4]);
Serial.print("storage[5] = "); Serial.println(storage[5]);
Serial.print("storage[6] = "); Serial.println(storage[6]);
Serial.print("storage[7] = "); Serial.println(storage[7]);
SPI.transfer(storage, sizeof storage ); //SPI library allows a user to
transfer a whole array of bytes and you need to include the size of the
array.
digitalWrite(SS, HIGH);
delay(1000);
}
For my Slave code:
#include <SPI.h>
byte storage [8];
volatile byte pos;
volatile boolean process;
float buff[2];
void setup()
{
pinMode(MISO,OUTPUT);
SPCR |= _BV(SPE);
SPCR |= _BV(SPIE);
pos = 0;
process = false;
Serial.begin(9600);
}
ISR(SPI_STC_vect)
{
byte gathered = SPDR;
if( pos < sizeof storage)
{
storage[pos++] = gathered;
}
else
process = true;
}
void loop()
{
if( process )
{
Serial.print("storage[0] = "); Serial.println(storage[0]);
Serial.print("storage[1] = "); Serial.println(storage[1]);
Serial.print("storage[2] = "); Serial.println(storage[2]);
Serial.print("storage[3] = "); Serial.println(storage[3]);
Serial.print("storage[4] = "); Serial.println(storage[4]);
Serial.print("storage[5] = "); Serial.println(storage[5]);
Serial.print("storage[6] = "); Serial.println(storage[6]);
Serial.print("storage[7] = "); Serial.println(storage[7]);
memcpy(buff,&storage,8);
Serial.print("This is buff[0]");Serial.println(buff[0]);
Serial.print("This is buff[1]");Serial.println(buff[1]);
storage[pos] = 0;
pos = 0;
process = false;
}
}
The immediate problem is that Serial.print doesn't know what to do with a byte array. Either declare it as a char array or cast it in the print statement:
char buf[7];
OR
Serial.print((char*) buf);
Either way, though, it's not going to show up as a float like you want.
An easier way to do all this is to use memcpy or a union to go back and forth between float and bytes. On the master end:
uint8_t buf[4];
memcpy(buf, &a, 4);
Then use SPI to send 4 bytes. Reverse it on the peripheral end.
Note that sending '\n' as the termination byte is a bad idea because it can lead to weird behavior, since one of the bytes in the float could easily be 0x0a, the hexadecimal equivalent of '\n'.

spi 74hc595 Cascading atmega64

I have a problem with displaying 40 values displayed on the 7 segment (40 components 74hc595 cascade link.
enter image description here
I implement my program on arduino and it works well
Here is my code:
static const byte Pattern[] = {
B00010100, // 0
B00111111, // 1
B10011000, // 2
B00011010, // 3
B00110011, // 4
B01010010, // 5
B01010000, // 6
B00011111, // 7
B00010000, // 8
B00010010, // 9
B00010000}; // BLANK
byte HC595_DS_POS = 2; //Data pin (DS) pin location
byte HC595_SH_CP_POS = 3; //Shift Clock (SH_CP) pin location
byte HC595_ST_CP_POS = 4; //Store Clock (ST_CP) pin location
void IE74595_Out(uint8_t *p, unsigned char n)
{
unsigned char i, j;
uint8_t b;
digitalWrite(HC595_ST_CP_POS,0);
digitalWrite(HC595_SH_CP_POS,0);
for(j=0;j<n;j++)
{
b = Pattern[*(p+n-j-1)]; // Lay byte cao nhat truoc
for(i=0;i<8;i++)
{
digitalWrite(HC595_SH_CP_POS,0);
if(b & 0b00000001)
{
digitalWrite(HC595_DS_POS,1);
}
else
{
digitalWrite(HC595_DS_POS,0);
}
digitalWrite(HC595_SH_CP_POS,1);
b=b>>1; //Now bring next bit at MSB position
}
}
digitalWrite(HC595_ST_CP_POS,1);
}
void setup()
{
// put your setup code here, to run once:
pinMode(HC595_ST_CP_POS, OUTPUT);
pinMode(HC595_SH_CP_POS, OUTPUT);
pinMode(HC595_DS_POS, OUTPUT);
}
void loop() {
uint8_t Data[40]={2,5,1,3,2,1,3,6,1,9,4,8,1,7,0,5,1,2,5,6,5,4,1,4,1,8,1,3,1,9,5,6,4,5,6,2,6,1,0,2};
IE74595_Out(Data,40);
}
And then I remade another program on atmel studio and I load it via extrem burner and Usbasp in my card
Here is my code :
#define F_CPU 8000000UL
#include <avr/io.h>
#include <util/delay.h>
static const uint8_t Pattern[] = {
0b00010100, // 0
0b00111111, // 1
0b10011000, // 2
0b00011010, // 3
0b00110011, // 4
0b01010010, // 5
0b01010000, // 6
0b00011111, // 7
0b00010000, // 8
0b00010010, // 9
0b00010000}; // BLANK
#define output_low(port,pin) port &= ~(1<<pin)
#define output_high(port,pin) port |= (1<<pin)
#define set_input(portdir,pin) portdir &= ~(1<<pin)
#define set_output(portdir,pin) portdir |= (1<<pin)
#define HC595_DS_POS PC4 //Data pin (DS) pin location
#define HC595_SH_CP_POS PC5 //Shift Clock (SH_CP) pin location
#define HC595_ST_CP_POS PC6 //Store Clock (ST_CP) pin location
#define HC595_PORT PORTC
#define HC595_DDR DDRC
void IE74595_Out(uint8_t *p, unsigned char n)
{
unsigned char i, j;
uint8_t b;
output_low(HC595_PORT,HC595_ST_CP_POS);
output_low(HC595_PORT,HC595_SH_CP_POS);
for(j=0;j<n;j++)
{
b = Pattern[*(p+n-j-1)];// Lay byte cao nhat truoc
for(i=0;i<8;i++)
{
output_low(HC595_PORT,HC595_SH_CP_POS);
if(b & 0b00000001)
{
output_high(HC595_PORT,HC595_DS_POS);
}
else
{
output_low(HC595_PORT,HC595_DS_POS);
}
output_high(HC595_PORT,HC595_SH_CP_POS);
b=b>>1;
}
}
output_high(HC595_PORT,HC595_ST_CP_POS);
}
int main(void)
{
set_output(DDRC,HC595_DS_POS);
set_output(DDRC,HC595_SH_CP_POS);
set_output(DDRC,HC595_ST_CP_POS);
uint8_t Data[40]={5,9,1,6,1,1,0,9,1,7,1,5,4,2,6,2,8,7,0,7,1,2,3,5,1,5,4,2,1,7,5,9,1,9,4,8,1,5,2,9};
while (1)
{
IE74595_Out(Data,40);
return 1;
}
}
Here is my card
enter image description here
The display is not like that of the arduino
I only have the last value displayed
I have developed my electronic card in china.
Is the problem of the material ???
The only difference between the two programs is:
DigitalWrite () on arduino
And Output_High () or output_Low on atmel
Is the implementation of DigitalWrite == Output_high() or output_Low() ????
Must i Write the last instruction Return 1; after the while ????
Thank's
The 10K pull-down resistor on the SS (Slave Select) is designed to keep the registers from clocking in bits while the main processor is booting, and the SS line might be "floating" and in an indeterminate state.
Here is the date sheet of 74hc595
The call to SPI.transfer() sends a byte to the register (a bit at a time) and then bringing the LATCH (otherwise known as SS or ST) line high causes the data to be transferred from the register's internal memory to the output pins.
Pin connections
Pin connections for Uno and similar:

Global variable arduino

I'm using I2C to communicate a Master Arduino to 4 Slaves Arduinos, and an Shield (OULIMEX Shield LCD 16x2) on every Arduino slave.
I send Data from the master to slaves using I2C. So I use this code in the master :
#include <Wire.h>
#include <math.h>
#include <floatToString.h>
double incomingData;
void setup()
{
Wire.begin();
Serial.begin(9600);
incomingData = Serial.parseFloat(); //read incoming data
}
void loop()
{
delay (1000);
if (Serial.available())
{
incomingData = Serial.parseFloat(); //read incoming data
Wire.beginTransmission(8); // transmit to device #8
if ((M==0) || (M==1) || (M==2))
Wire.beginTransmission(8); // transmit to device #8 *****************************************************************
else
Wire.beginTransmission(7); // transmit to device #7 *****************************************************************
M++;
if (M==5)
M=0;
String a = "";
a = floatToString(test,incomingData,3,5,true);
for(i=0; a[i]!='\0'; ++i); // length of the string
Wire.write(i);
Wire.write(floatToString(test,incomingData,3,5,true)); // sends one byte
Wire.endTransmission(); // stop transmitting
}
}
I wanted the Data to be printed on the Shield, but I'm connecting all slaves with the same way with the master. For that I have two problems :
1- The global data I'm using to print value is always printed as 0, and not giving the real value;
2- All Shields print the same thing : For exemple, I print "hello" in the first Shield, and I print "hi" in the second Shield, but bouth are printing the same thing (hello or hi).
The code using for the first slave is :
#include <LCD16x2.h>
#include <Wire.h>
LCD16x2 lcd;
int buttons;
int sensorPin = A0; // select the input pin for the potentiometer
int sensorValue = 0; // variable to store the value coming from the sensor
float numOut;
int comp=1 ;
String wordd = "";
int M =0;
void setup()
{
Wire.begin(8); // join i2c bus with address #8
Wire.onReceive(receiveEvent); // register event
Serial.begin(9600); // start serial for output
}
void loop()
{
delay(500);
}
// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany) {
wordd = "";
int x = Wire.read();
for (int i=0; i<=x; i++)
{
char c = Wire.read();
wordd += c;
}
numOut = wordd.toFloat();
Serial.println(numOut,3); // print the integer
}
Thank you in advance !!
I think it's due to a poor program structure in master shield.
This block selects the slave but on the first line you already select #8
I think this is confusing for the slaves.
Wire.beginTransmission(8); // transmit to device #8
if ((M==0) || (M==1) || (M==2))
Wire.beginTransmission(8); // transmit to device #8
else
Wire.beginTransmission(7); // transmit to device #7
This block should be at the end of the function
M++;
if (M==5)
M=0;
Then you parse the value in a string.
But leave out the first char because you write ++i instead of i++
Moreover you close the loop with ; so it does nothing
String a = "";
a = floatToString(test,incomingData,3,5,true);
for(i=0; a[i]!='\0'; ++i); // length of the string
Finally you write the ordinal number of the byte
And then again the Whole string
So you should get "0" (or "1" because of ++i)
followed by your number if Wire.write() supports it
Wire.write(i);
Wire.write(floatToString(test,incomingData,3,5,true)); // sends one byte
Wire.endTransmission(); // stop transmitting
}
Your sketch should be:
if (Serial.available())
{
incomingData = Serial.parseFloat(); //read incoming data
String a = "";
a = floatToString(test,incomingData,3,5,true);
if ((M==0) || (M==1) || (M==2))
Wire.beginTransmission(8); // transmit to device #8
else
Wire.beginTransmission(7); // transmit to device #7
for(i=0; a[i]!='\0'; ++i) // length of the string
Wire.write(a[i]); // write one byte
Wire.endTransmission(); // stop transmitting
M++;
if (M==5) M=0;
}
Let me know if this works.
I already ask this question but I think I have the answer of it. A global variable have to be diclared befor the void setup, and the void loop too, like that :
type YourGlobalVariable;
void setup()
{
}
void loop()
{
}
So, it is exactly how I did already. The reason it didn't work for me, it was cause of I used this function :
void receiveEvent(int howMany) {}
I don't really know what are the properties of it that let it not work for a global variables, but It works like I sayd already.
Thank you all

Arduino to arduino i2c code

I have an OPT101 connected to a slave arduino to measure light intensity. I want to send the data received from the OPT101 circuit to a master arduino that will print the data on the serial monitor. When I test my code, nothing shows up on the screen. (I know it's not my i2c connection cause I tested it by sending "hello"). I am using an arduino leonardo as the slave and the arduino uno as the master.
The code for the OPT101 circuit is:
#define inPin0 0
void setup() {
Serial.begin(9600);
Serial.println();
}
void loop() {
int pinRead0 = analogRead(inPin0);
double pVolt0 = pinRead0 / 1024.00 * 5.0;
Serial.print(pVolt0, 4 );
Serial.println();
delay(100);
}
I tired to combine the slave code and my OPT101 code to get this:
#include
#define inPin0 0
void setup() {
Wire.begin(2);
}
void loop() {
Wire.beginTransmission(2);
Wire.onRequest(requestEvent);
Wire.endTransmission();
}
void requestEvent()
{
int pinRead0 = analogRead(inPin0);
int pVolt0 = pinRead0 / 1024.0 * 5.0;
Wire.write((byte)pVolt0);
}
And this is my master code:
#include <Wire.h>
void setup()
{
Wire.begin();
Serial.begin(14400);
Wire.requestFrom(2, 8);
while(Wire.available())
{
char c = Wire.read();
Serial.print(c);
}
}
void loop()
{
}
You must follow steps described below to communicate between master and slave I2C devices:
Only master can initiate read or write request.
Read or write requests must be synchronous. It means, slave can only return data after master requests for them and vice versa for write.
Do not use slave address from 0 - 7. They are reserved. Use slave address that ranges between 8 to 127.
On Arduino I2C, you can only send and receive a byte. To send or receive integer, double that have multiple bytes, you need to split them first and on other side, you have to combine them into its equivalent datatype. (Correct me, if I'm wrong.)
Your code should be like this:
Master Sketch:
#include <Wire.h>
#define SLAVE_ADDRESS 0x40
// This macro reads two byte from I2C slave and converts into equivalent int
#define I2C_ReadInteger(buf,dataInteger) \
buf[0] = Wire.read(); \
buf[1] = Wire.read(); \
dataInteger = *((int *)buf);
// Returns light intensity measured by 'SLAVE_ADDRESS' device
int GetLightIntensity()
{
byte Temp[2];
int Result;
// To get integer value from slave, two are required
int NumberOfBytes = 2;
// Request 'NumberOfBytes' from 'SLAVE_ADDRESS'
Wire.requestFrom(SLAVE_ADDRESS, NumberOfBytes);
// Call macro to read and convert bytes (Temp) to int (Result)
I2C_ReadInteger(Temp, Result);
return Result;
}
void setup()
{
// Initiate I2C Master
Wire.begin();
// Initiate Serial communication # 9600 baud or of your choice
Serial.begin(9600);
}
void loop()
{
// Print light intensity at defined interval
Serial.print("Light Intensity = ");
Serial.println(GetLightIntensity());
delay(1000);
}
Slave Sketch:
#include <Wire.h>
#define SLAVE_ADDRESS 0x40
#define inPin0 0
// Preapres 2-bytes equivalent to its int
#define IntegerToByte(buf,intData) \
*((int *)buf) = intData;
// Sends int to Master
void I2C_SendInteger(int Data)
{
byte Temp[2];
// I2C can only send a byte at a time.
// Int is of 2bytes and we need to split them into bytes
// in order to send it to Master.
// On Master side, it receives 2bytes and parses into
// equvivalent int.
IntegerToByte(Temp, Data);
// Write 2bytes to Master
Wire.write(Temp, 2);
}
void setup()
{
// Initiate I2C Slave # 'SLAVE_ADDRESS'
Wire.begin(SLAVE_ADDRESS);
// Register callback on request by Master
Wire.onRequest(requestEvent);
}
void loop()
{
}
//
void requestEvent()
{
// Read sensor
int pinRead0 = analogRead(inPin0);
int pVolt0 = pinRead0 / 1024.0 * 5.0;
// Send int to Master
I2C_SendInteger(pVolt0);
}
This code is tested on Arduino Version: 1.6.7.
For more information regarding I2C communication, refer Arduino
Example: Master Reader
Why are you putting the while loop in the setup() function instead of using the loop() function ?
But more confusing is this line int pVolt0 = pinRead0 / 1024.0 * 5.0;. In the initial code the variable is not int but double. I suggest you try to recode using the original line:
double pVolt0 = pinRead0 / 1024.00 * 5.0;
And only then reduce to int.
In Arduino I2C, you can only send and receive one byte, and it is necessary to combine them in their equivalent data type.

Resources