Det är bara lcd, skift registret, och pulsgivaren (encoder) inkopplad.
EDIT> Programmet skapades för UNO versionen, schemat visar pinne 10 SS, 11 MOSI, 13 SCK
På mega 1280 sitter dom på 51, MOSI , 52 SCK, 53 SS
Det går att ladda upp utan problem men visar som sagt inget på lcd, har väl missat något dumt antar jag.
Här är källkod och bibliotek.
Jag kör i Arduino 00.23.
DOSING_COMPUTER_LIBRARIES.zip
DOSING_COMPUTER_6.zip
bb_img_w_bjt.jpg
Kod: Markera allt
#ifndef DOSE_head_h
#define DOSE_head_h
#include "WProgram.h"
#include "LiquidCrystal_SPI_8Bit.h"
#include "EEPROM.h"
#include "Time.h"
#include "DosingPump.h"
#include "QuickPin.h"
/******** EEPROM ADDRESSES ********/
#define EA_CALIBRATION_FLAGS 16
#define EA_ALK_PUMP 18
#define EA_CA_PUMP 28
#define EA_ALK_SCHEDULE 50
#define EA_CA_SCHEDULE 80
/*********** CONSTANTS ***********/
#define NUMBER_OF_PUMPS 2
#define DEBOUNCE 50
#define DEFAULT_VOLUME 20.0
#define DEFAULT_RATE 20.0
#define MIDNIGHT 1440
#define MAXIMUM_DAILY_VOLUME 120
#define MAXIMUM_CONTAINER_SIZE 5000
#define MAXIMUM_BOOSTER_DOSE 250
#define MAXIMUM_BOOSTER_DAYS 14
/*********** TYPEDEFS ***********/
typedef char* menu_t;
/*********** KNOBS AND BUTTONS *********/
QuickPin button1(7, INPUT, HIGH);
//QuickPin button2(2, INPUT, LOW); // second button unused
QuickPin encoder_Int_Pin(2, INPUT, HIGH);
QuickPin encoder_B_Pin(4, INPUT, HIGH);
char encoder_Counter; //Used to keep count of Rotary Encoder Clicks
/********** DISPLAY **********/
LiquidCrystal_SPI_8Bit LCD(8,10);
/********** PUMPS **********/
DosingPump AlkPump(5);
DosingPump CaPump(6);
/********** TIME **********/
time_t current_time;
/****** REPLACEMENT OPERATORS ******/
/*void* operator new(size_t size)
{
return malloc(size);
}
void operator delete(void* ptr)
{
free(ptr);
}
/********************* ENCODER FUNCTIONS *******************/
void ISR_encoder_handler()
{
(encoder_Int_Pin == encoder_B_Pin)? encoder_Counter++ : encoder_Counter--;
}
void encoderOn()
{
attachInterrupt(0, ISR_encoder_handler, FALLING); // Only using one edge and one interrupt so we get one increment per click
encoder_Counter = 0;
}
void encoderOff()
{
detachInterrupt(0);
encoder_Counter = 0;
}
char checkRotaryEncoder() // Used to get the value of encoder_Counter and reset it
{
char val = encoder_Counter;
encoder_Counter = 0;
return val;
}
template<class T>
void useRotaryEncoder(T& _var)
{
_var += checkRotaryEncoder();
}
template<class T>
void useRotaryEncoder(T& _var, int _mult)
{
_var += (checkRotaryEncoder() * _mult);
}
template<class T>
void useRotaryEncodersingle(T& _var)
{
int _val = checkRotaryEncoder();
if (_val > 0) _var += 1;
if (_val < 0) _var -= 1;
}
/***************** HUMAN INTERFACE INPUT FUNCTIONS ****************/
template<class T>
void printTheNumber(T& _var, int _digits, byte _col, byte _row)
{
// This function handles leading zeros
// In numbers that need them
// So our display stays straight
LCD.setCursor(_col, _row);
if (_var == 0)
{
for (int d_count = 0; d_count < _digits - 1; d_count ++)
{
LCD.print("0");
}
}
if ((_digits > 1) && (_var != 0))
{
int single_digit = (_var / (pow(10, (_digits - 1))));
if (single_digit == 0)
{
LCD.print("0");
printTheNumber(_var, (_digits -1) , _col +1, _row );
}
else
{
LCD.print(_var);
}
}
else
{
LCD.print(_var);
}
return; // when digits is equal to one, or we hit a digit other than 0 we fall through print and return
}
template<class T>
void inputTheNumber (T& _var, int _digits, int _min, int _max, byte _col, byte _row, int _mult)
{
LCD.cursor();
printTheNumber(_var, _digits, _col, _row);
while (button1==LOW); // if the button is still pressed, wait for release.
encoderOn();
do {
useRotaryEncoder(_var, _mult);
if (_var > _max) _var = _min;
if (_var < _min) _var = _max;
printTheNumber(_var, _digits, _col, _row);
LCD.setCursor(_col + (_digits -1), _row);
delay(100);
} while (button1==HIGH); // button press to end loop and lock in entry
while (button1==LOW); // wait for button release
encoderOff();
LCD.noCursor();
}
template<class T>
void inputTheNumber (T& _var, int _digits, int _min, int _max, byte _col, byte _row)
{
inputTheNumber(_var, _digits, _min, _max, _col, _row, 1);
}
template<class T>
void inputTheNumber (T& _var, int _digits, int _min, int _max, byte _col, byte _row, int _mult, char* _disp)
{
// Use whatever numbers you want for col and row, it doesn't matter
// They will be set to 0,1
LCD.clear();
LCD.print(_disp);
inputTheNumber(_var, _digits, _min, _max, 0, 1, _mult);
}
/****************** EEPROM FUNCTIONS *****************/
template<class T>
void writeToEEPROM(int address, T& value)
{
union {
T type;
byte b[sizeof(T)];
} temp;
temp.type = value;
for (int i = 0; i < sizeof(T); i++)
{
EEPROM.write(address + i, temp.b[i]);
}
}
template<class T>
void readFromEEPROM(int address, T& value)
{
union {
T type;
byte b[sizeof(T)];
} temp;
for (int i = 0; i < sizeof(T); i++)
{
temp.b[i] = EEPROM.read(address + i);
}
value = temp.type;
}
/*********************FUNCTION DECLARATIONS NOT IN OTHER HEADERS ***************/
void primePump(DosingPump* _pump);
void calibratePWM(DosingPump* _pump);
void calibrateMinFlow(DosingPump* _pump);
void calibrateMaxFlow(DosingPump* _pump);
void calibratePump(DosingPump* _pump);
void saveCalibration();
void getCalibration();
/**************** GENERAL FUNCTIONS and CALIBRATION *****************/
void primePump(DosingPump* _pump)
{
while(button1==LOW); // If button is pressed, wait until released
boolean quit = false;
encoderOn();
do
{
// turn knob to choose quit or prime
// press button to execute
if (checkRotaryEncoder() != 0) quit = !quit;
LCD.clear();
LCD.setCursor(0,1);
if (quit) LCD.print("QUIT ");
else LCD.print("PRIME");
delay(50); //display delay
if ((button1==LOW) && (quit == false)) // button press chose PRIME
{
encoderOff(); //turn off interrupt
(*_pump).pumpOn();
while (button1 == LOW); // run pump and wait until button release
(*_pump).pumpOff();
encoderOn();
}
}while((!quit) || (button1==HIGH)); // button press to exit only if QUIT
encoderOff();
}
void calibratePWM(DosingPump* _pump)
{
// Turn knob to adjust PWM rate until it you find the lowest setting
// that the pump can run at reliably. This will set your minimum
// flow rate
while(button1==LOW); // If button is pressed, wait for release
int pwm_rate = 128; // Start at 50% Most pumps won't run well below that
LCD.clear();
LCD.print("Adjust PWM");
encoderOn();
do
{
useRotaryEncoder(pwm_rate);
constrain(pwm_rate, 127, 255); // pwm stays between 50% and 100%
LCD.setCursor(0,1);
LCD.print(pwm_rate);
analogWrite((*_pump).pump_pin, pwm_rate);
} while(button1==HIGH); // button press to exit and lock in entry
analogWrite((*_pump).pump_pin, 0);
while(button1==LOW); // wait for button release
encoderOff();
(*_pump).minimum_pwm_rate = pwm_rate; // Set minimum PWM rate
}
void calibrateMinFlow(DosingPump* _pump)
{
// Button press to start. Pump will run for a pre-set time.
// Catch the flow, measure the amount, and input the amount after the pump
// stops running. This calculates the minimum flow rate.
int _volume = 0;
while(button1==LOW); // If button is pressed, wait for release
LCD.clear();
LCD.print("Press Button");
LCD.setCursor(0,1);
LCD.print("When Ready");
while(button1==HIGH); // wait for button press
LCD.clear();
LCD.print("Running...");
delay(1000);
while(button1==LOW); // wait for button release if it's not already.
long start_time = millis();
analogWrite((*_pump).pump_pin, (*_pump).minimum_pwm_rate);
while(millis() < (start_time + 30000)); // Wait for 30 seconds
analogWrite((*_pump).pump_pin, 0);
LCD.clear();
LCD.print("Enter Volume");
inputTheNumber(_volume, 2, 0, 99, 0, 1); // input the volume you got from the pump
(*_pump).minimum_flow_rate = (_volume * 2); // Convert and Record as mL per minute
}
void calibrateMaxFlow(DosingPump* _pump)
{
// Button press to start. Pump will run for a pre-set time.
// Capture the output, and input the amount after the pump
// stops running. This calculates the maximum flow rate.
int _volume = 0;
while(button1==LOW); // If button is pressed, wait for release
LCD.clear();
LCD.print("Press Button");
LCD.setCursor(0,1);
LCD.print("When Ready");
while(button1==HIGH); // Wait for button press
LCD.clear();
LCD.print("Running...");
delay(1000);
while(button1==LOW); // wait for button release if it's not already.
long start_time = millis();
analogWrite((*_pump).pump_pin, (*_pump).maximum_pwm_rate);
while(millis() < (start_time + 30000)); // wait 30 seconds
analogWrite((*_pump).pump_pin, 0);
LCD.clear();
LCD.print("Enter Volume");
inputTheNumber(_volume, 2, 0, 99, 0, 1); // input the volume you got from the pump
(*_pump).maximum_flow_rate = (_volume * 2); // Convert and record as ml / min
}
void calibratePump(DosingPump* _pump)
{
// Runs all the calibration methods
calibratePWM(_pump);
calibrateMinFlow(_pump);
calibrateMaxFlow(_pump);
}
void saveCalibration()
{
writeToEEPROM(EA_ALK_PUMP, AlkPump.minimum_pwm_rate);
writeToEEPROM(EA_ALK_PUMP + 2, AlkPump.minimum_flow_rate);
writeToEEPROM(EA_ALK_PUMP + 6, AlkPump.maximum_flow_rate);
writeToEEPROM(EA_CA_PUMP, CaPump.minimum_pwm_rate);
writeToEEPROM(EA_CA_PUMP + 2, CaPump.minimum_flow_rate);
writeToEEPROM(EA_CA_PUMP + 6, CaPump.maximum_flow_rate);
byte flag = 3;
writeToEEPROM(EA_CALIBRATION_FLAGS, flag);
}
void getCalibration()
{
readFromEEPROM(EA_ALK_PUMP, AlkPump.minimum_pwm_rate);
readFromEEPROM(EA_ALK_PUMP + 2, AlkPump.minimum_flow_rate);
readFromEEPROM(EA_ALK_PUMP + 6, AlkPump.maximum_flow_rate);
readFromEEPROM(EA_CA_PUMP, CaPump.minimum_pwm_rate);
readFromEEPROM(EA_CA_PUMP + 2, CaPump.minimum_flow_rate);
readFromEEPROM(EA_CA_PUMP + 6, CaPump.maximum_flow_rate);
}
/***************************************************
****** THESE HEADERS ARE SPECIFIC TO THIS**********
****** APPLICATION AND MUST REMAIN AT ************
******** THE END OF THIS FILE *************
**************************************************/
#include "DOSE_clock.h"
#include "DOSE_schedule.h"
Dose_S Alk_Schedule;
Dose_S Ca_Schedule;
// Schedule names and pointers to them.
Dose_S* schedules[] = {&Alk_Schedule , &Ca_Schedule};
char* schedule_names[] = {"Alk" , "Cal"};
#include "DOSE_menu.h"
#endif
LiquidCrystal_SPI_8Bit biblioteket i sin helhet.
Kod: Markera allt
#ifndef LiquidCrystal_SPI_8Bit_h
#define LiquidCrystal_SPI_8Bit_h
#include <inttypes.h>
#include "Print.h"
// commands
#define LCD_CLEARDISPLAY 0x01
#define LCD_RETURNHOME 0x02
#define LCD_ENTRYMODESET 0x04
#define LCD_DISPLAYCONTROL 0x08
#define LCD_CURSORSHIFT 0x10
#define LCD_FUNCTIONSET 0x20
#define LCD_SETCGRAMADDR 0x40
#define LCD_SETDDRAMADDR 0x80
// flags for display entry mode
#define LCD_ENTRYRIGHT 0x00
#define LCD_ENTRYLEFT 0x02
#define LCD_ENTRYSHIFTINCREMENT 0x01
#define LCD_ENTRYSHIFTDECREMENT 0x00
// flags for display on/off control
#define LCD_DISPLAYON 0x04
#define LCD_DISPLAYOFF 0x00
#define LCD_CURSORON 0x02
#define LCD_CURSOROFF 0x00
#define LCD_BLINKON 0x01
#define LCD_BLINKOFF 0x00
// flags for display/cursor shift
#define LCD_DISPLAYMOVE 0x08
#define LCD_CURSORMOVE 0x00
#define LCD_MOVERIGHT 0x04
#define LCD_MOVELEFT 0x00
// flags for function set
#define LCD_8BITMODE 0x10
#define LCD_4BITMODE 0x00
#define LCD_2LINE 0x08
#define LCD_1LINE 0x00
#define LCD_5x10DOTS 0x04
#define LCD_5x8DOTS 0x00
class LiquidCrystal_SPI_8Bit : public Print {
public:
LiquidCrystal_SPI_8Bit(uint8_t rs, uint8_t enable);
void init(uint8_t rs, uint8_t rw, uint8_t enable);
void begin(uint8_t cols, uint8_t rows, uint8_t charsize = LCD_5x8DOTS);
void clear();
void home();
void noDisplay();
void display();
void noBlink();
void blink();
void noCursor();
void cursor();
void scrollDisplayLeft();
void scrollDisplayRight();
void leftToRight();
void rightToLeft();
void autoscroll();
void noAutoscroll();
void createChar(uint8_t, uint8_t[]);
void setCursor(uint8_t, uint8_t);
virtual void write(uint8_t);
void command(uint8_t);
private:
void send(uint8_t, uint8_t);
void write4bits(uint8_t);
void write8bits(uint8_t);
void pulseEnable();
uint8_t _rs_pin; // LOW: command. HIGH: character.
uint8_t _rw_pin; // LOW: write to LCD. HIGH: read from LCD.
uint8_t _enable_pin; // activated by a HIGH pulse..
uint8_t _displayfunction;
uint8_t _displaycontrol;
uint8_t _displaymode;
uint8_t _initialized;
uint8_t _numlines,_currline;
};
#endif