Surface Mount ATMega328p-AU sensor board.



  • I have been working on a project that will integrate a wide range of sensors into a nice surface mount package for the ATMega328p-au (Arduino chip). I am currently waiting on these boards from OSH Park so they are untested at the moment. I will post an update once it has been tested.

    Board layout:

    • 3-Pin Headers: Each of the 3 pin headers are attached to VCC and Ground with I/O pin in the middle. RELAY = D6, FLOW = D5, A_TEMP = D4, W_TEMP = D3, PRESSURE = A0

    • 4-Pin Headers: Most of the 4 pin headers are for I2C devices and go VCC - SCL - SDA - GND. The exception is TTL which is VCC - RX - TX - GND.

    • Programer header: Top to bottom >> GND - NC - VCC - TX - RX - DTR

    • L1-L3 are WS2812B addressable RGB LED's.

    The board was designed in eagleCAD if anyone was interested in the sch or brd files.

    Link to OSH Park: https://oshpark.com/shared_projects/IVovQwgz

    ![Alt text][1]
    [1]: https://644db4de3505c40a0444-327723bce298e3ff5813fb42baeefbaa.ssl.cf1.rackcdn.com/uploads/project/top_image/IVovQwgz/i.png "SMD Sensor Board"


  • Hero Member

    I like it, looking forward to seeing how your testing goes.



  • I am glad to report that my first attempt at designing a board went well overall. The project/boards linked in my above post works as is, but I would make a few modifications on future boards. Some of the modifications I will hopefully implement soon are:

    • Addition of holes so the board can be mounted to a project enclosure.
    • Combine the Water/Air Temp sensors onto a single pin to the ATMega328p along with adding a resistor between the data and VCC. Unfortunately, I did not realize that DS18B20's could be chained together to save on pins, or that it needs to have a pull-up resistor.
    • Drop the number of I2C pin connections to one or two. In addition to this I will probably also make a simple breakout board for expanding the number of connections as needed.
    • Include I2C pull up resistors. It has been functioning without any issues without them, but I should have put them on the board.

    The Sketch I have created and have running includes the following sensors so far:

    • Atlas Scientific pH sensor and probe
    • Atlas Scientific ORP sensor and probe
    • (2)Dallas DS18B20 for water and air temp.
    • Relay for pool pump
    • MPX5500DP pressure sensor to monitor water at the filter pressure
    • A 4 line 20 character LCD display currently showing temps/ORP/pH

    The sketch is sending the data to my MIOS as expected. However, when I turn the relay on I have noticed the message is broadcast quite a few times. When debugging is active it seemed that the incoming message would display around a hundred times (I never actually counted the number of times). Is such a large number of attempts to send the message normal? Any feedback or recommendations are welcome.

    Note: I do not have the arduino bootloader running on my boards. I am using the Visual Micro addin for AtmelStudio and an MKII ISP to program the boards.

    #include <SPI.h>
    #include <MySensor.h>
    #include <Wire.h>
    #include <DallasTemperature.h>
    #include <OneWire.h>
    #include <LiquidCrystal_I2C.h>
    
    /*#### MySensor Node definitions  ####*/
    #define NODE_ID 2
    #define PRES_CHILD 0		
    #define WTEMP_CHILD 1
    #define ATEMP_CHILD 2
    #define RELAY_CHILD_ID 3
    #define PH_CHILD_ID 4
    #define ORP_CHILD_ID 5
    
    /*####  Arduino Pin definitions  #####*/
    #define MPX5500DP_PIN	0 // A0 - MPX5500DP pin
    #define WTEMP_PIN		3 // D3 - Dallas one wire temp sensor
    #define ATEMP_PIN		4 // D4 - Dallas one wire temp sensor
    #define PUMP_RELAY		6 // D6 - Relay Pin
    
    /*####    Program definitions     #####*/
    #define PH_I2C 99   			//default I2C ID number for EZO pH Circuit.
    #define ORP_I2C 98  			//default I2C ID number for EZO ORP Circuit.
    #define NUMBER_OF_RELAYS 1 		// Total number of attached relays
    #define RELAY_ON 1  			// GPIO value to write to turn on attached relay
    #define RELAY_OFF 0 			// GPIO value to write to turn off attached relay
    #define MAX_ATTACHED_DS18B20 16	// Define the max number of DS18B20 per pin
    #define LCD_I2C 0x3F 			// I2C address of the LCD screen
    
    /*####   Program variables   #####*/
    unsigned long SLEEP_TIME = 5000; // Sleep time between reads (in mili-seconds)
    int delay_count = 0;
    int periodUpdate = 0;
    LiquidCrystal_I2C lcd(LCD_I2C, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
    
    //temperature variables
    OneWire waterOneWire(WTEMP_PIN);
    DallasTemperature wSensors(&waterOneWire);
    OneWire airOneWire(ATEMP_PIN);
    DallasTemperature aSensors(&airOneWire);
    float atemperature = 0;
    float wtemperature = 0;
    float lastPressure = -1;
    float lastWTemp = -1;
    float lastATemp = -1;
    
    // &&&& pH and ORP &&&&
    byte code=0;                    //used to hold the I2C response code.
    char I2C_data[10];              //we make a 20 byte character array to hold incoming data from the circuit.
    byte in_char=0;                 //used as a 1 byte buffer to store in bound bytes from the pH Circuit.
    byte i=0;                       //counter used for ph_data array.
    float ph_float = 0;             //float var used to hold the float value of the pH.
    float ORP_float = 0;            //float var used to hold the float value of the ORP.
    float last_ph_float = 1;		//float var used to hold the float value of the last pH.
    float last_ORP_float = 1;		//float var used to hold the float value of the last ORP.
    
    
    /*####   My Sensors   #####*/ 
    boolean metric;
    MySensor gw;
    //Message definitions
    MyMessage pHMsg(PH_CHILD_ID, V_VAR1);
    MyMessage orpMsg(ORP_CHILD_ID, V_VAR1);
    MyMessage wTempMsg(WTEMP_CHILD, V_TEMP);
    MyMessage aTempMsg(ATEMP_CHILD, V_TEMP);
    MyMessage pressureMsg(PRES_CHILD, V_PRESSURE);
    
    /*####  Program #####*/
    void setup() {
    	wSensors.begin();
    	aSensors.begin();
    	gw.begin(incomingMessage, NODE_ID, true);
    
    	// Send the sketch version information to the gateway and Controller
    	gw.sendSketchInfo("Sensor Node AlphaMax", "0.1"); // Update Node name for each node -- Update version number for each update.
    
    	// Register sensors to gw (they will be created as child devices)
    	gw.present(PRES_CHILD, S_BARO);
    	gw.present(WTEMP_CHILD, S_TEMP);
    	gw.present(ATEMP_CHILD, S_TEMP);
    	gw.present(PH_CHILD_ID, S_CUSTOM);
    	gw.present(ORP_CHILD_ID, S_CUSTOM);
    	gw.present(RELAY_CHILD_ID, S_LIGHT);
    
    	metric =  gw.getConfig().isMetric;											// getConfig() returns true for metric, false for imperial
    	pinMode(PUMP_RELAY, OUTPUT);												// Then set relay pins in output mode
    	digitalWrite(PUMP_RELAY, gw.loadState(RELAY_CHILD_ID)?RELAY_ON:RELAY_OFF);	// Set relay to last known state (using eeprom storage)
    	lcd.begin(20,4);															// Initialize the lcd for 20 chars 4 lines
    	lcd.clear();																// Clear LCD screen before use
    }
    
    void loop() {
    	gw.process();
    
    	//Get temperature
    	aSensors.requestTemperatures();
    	atemperature = static_cast<float>(static_cast<int>((gw.getConfig().isMetric?aSensors.getTempCByIndex(0):aSensors.getTempFByIndex(0)) * 100.)) / 100.;
    	wSensors.requestTemperatures();
    	wtemperature = static_cast<float>(static_cast<int>((gw.getConfig().isMetric?wSensors.getTempCByIndex(0):wSensors.getTempFByIndex(0)) * 100.)) / 100.;
    	//Get pressure
    	float pressure = analogRead(MPX5500DP_PIN); //MPX5500DP Pressure sensor	
    	//Get ph and ORP
    	atlas(PH_I2C);
    	atlas(ORP_I2C);
    	//Update LCD Screen
    	printscreen();
    
    	//Update VERA when needed.
    	if (ph_float != last_ph_float)
    	{
    		gw.send(pHMsg.set(ph_float,2));
    		last_ph_float = ph_float;
    	}
    	if (ORP_float != last_ORP_float)
    	{
    		gw.send(orpMsg.set(ORP_float,1));
    		last_ORP_float = ORP_float;
    	}
    	//Periodic updates were used when LCD display was on another node
    	//since they do not appear to be hurting anything I left them in.
    	if (wtemperature != lastWTemp | periodUpdate == 250000) {	
    		gw.send(wTempMsg.setDestination(0).set(wtemperature,1));
    		lastWTemp = wtemperature;
    	}
    	if (atemperature != lastATemp | periodUpdate == 500000) {
    		gw.send(aTempMsg.setDestination(0).set(atemperature,1));
    		lastATemp = atemperature;
    	}
    	if (pressure != lastPressure | periodUpdate == 750000) {
    		gw.send(pressureMsg.set(pressure, 0));
    		lastPressure = pressure;
    	}
    	if(periodUpdate >= 750000)
    	{
    		periodUpdate = 0;
    	}
    	periodUpdate++;
    }
    
    //This function is used to handle data to and from the ORP and pH sensors
    void atlas(int address){	
    	
    	Wire.beginTransmission(address); //call the circuit by its ID number.
    	Wire.write('R');				 //transmit the command that was sent through the serial port.
    	Wire.endTransmission();          //end the I2C data transmission.
    	
    	for(int k=0;k<=140;k++)			// Need to delay 1.4 seconds between sending read command
    	{								// and requesting data. This for loop keeps delays between
    		gw.process();				// processing incoming messages short.
    		delay(10);
    	}
    	
    	Wire.requestFrom(address,20,1); //call the circuit and request 20 bytes (this may be more then we need).
    	code=Wire.read();               //the first byte is the response code, we read this separately.
    	switch (code){                  //switch case based on what the response code is.
    		case 1:                     //decimal 1.
    		Serial.println("Success");  //means the command was successful.
    		break;                      //exits the switch case.
    		
    		case 2:                     //decimal 2.
    		Serial.println("Failed");   //means the command has failed.
    		break;                      //exits the switch case.
    		
    		case 254:                   //decimal 254.
    		Serial.println("Pending");  //means the command has not yet been finished calculating.
    		break;                      //exits the switch case.
    		
    		case 255:                   //decimal 255.
    		Serial.println("No Data");  //means there is no further data to send.
    		break;                      //exits the switch case.
    	}
    	while(Wire.available()){        //are there bytes to receive.
    		in_char = Wire.read();      //receive a byte.
    		I2C_data[i]= in_char;       //load this byte into our array.
    		i+=1;                       //incur the counter for the array element.
    		if(in_char==0){             //if we see that we have been sent a null command.
    			i=0;                    //reset the counter i to 0.
    			Wire.endTransmission(); //end the I2C data transmission.
    			break;                  //exit the while loop.
    		}
    	}
    	Serial.println(I2C_data);       //print the data.
    	
    	if(address == PH_I2C)
    	{
    		ph_float = atof(I2C_data);
    	}
    	else if(address == ORP_I2C)
    	{
    		ORP_float = atof(I2C_data);		
    	}
    	else
    	Serial.print("No address match!!!!");
    }
    
    void incomingMessage(const MyMessage &message) 
    {
    	// We only expect one type of message from controller. But we better check anyway.
    	if (message.type==V_LIGHT) 
    	{
    		// Change relay state
    		digitalWrite(PUMP_RELAY, message.getBool()?RELAY_ON:RELAY_OFF);
    		// Store state in eeprom
    		gw.saveState(RELAY_CHILD_ID, message.getBool());
    		// Write some debug info
    		Serial.print("Incoming change for sensor:");
    		Serial.print(message.sensor);
    		Serial.print(", New status: ");
    		Serial.println(message.getBool());
    	}
    }
    
    void printscreen()
    {
    	lcd.clear();
    	
    	lcd.setCursor(0,0);
    	lcd.print("Water Temp ");
    	lcd.setCursor(11,0);
    	lcd.print(wtemperature);
    	
    	lcd.setCursor(0,1);
    	lcd.print("Air Temp");
    	lcd.setCursor(11,1);
    	lcd.print(atemperature);
    	
    	lcd.setCursor(0,2);
    	lcd.print("pH");
    	lcd.setCursor(11,2);
    	lcd.print(ph_float);
    	
    	lcd.setCursor(0,3);
    	lcd.print("ORP");
    	lcd.setCursor(11,3);
    	lcd.print(ORP_float);
    }
    

  • Hero Member

    The relay switch causes "noise" into the power lines, which drives the radio (mostly) and arduino (sometimes) crazy.

    How are you powering your arduino / radio?



  • I have been using an old(cheap) wall-to-USB power supply. I'll give it a try with a beefier supply and let you know the results I get.


 

313
Online

7.5k
Users

8.4k
Topics

90.3k
Posts