-
Has anyone used this javascript PID controller code? Everything looks good but I can't figure out how to call it. Can someone point me in the right direction?
I'm still trying to wrap my head around this 'prototype' concept in javascript. Yet to reach that ah ha moment!
-
-
Thanks Gordon that's a huge help.
I did manage to get to a reasonable point by logging temperatures to an array. That was until the array got too large and crashed the Espruino! So now when I get to the max array size I 'unshift' the first value off the array.
Mode appears to work better than median. I will investigate further using your post above.
The noise may be down to the thermistor I am using. I'm using a 10K thermistor with a 10K resistor as the divider all on a small board next to the Espruino.
To test the readings I was using a 10K resistor in place of the thermistor so in theory I should be reading bang on 25°C but it was fluctuating around too much.
The response doesn't need to be super fast so I think some sort of array and average should work okay.
-
I have a thermistor connected to one of the ADC's but I am having quite a bit of trouble with noise.
As a test I have setup the circuit with another resistor in replacement of the thermistor bead but I cannot seem to get the readings to a stable state. I have in addition tried using a 100nF capacitor across the input which helps to some degree but not enough.
Ideally I would like to stabilise the temp to at least one decimal place.
I would assume some sort of software filter, any suggestions? -
-
-
-
-
Thanks for all your help Gordon!
If anyone has been following this the code has been merged into the main branch and is now available as a module.
http://www.espruino.com/DS3231 -
-
How does this look?
exports = {}; var dstStatus = true; function DS3231(_i2c) { this.i2c = _i2c; } //private var C = { i2c_address: 0x68, dateReg : 0x04, monthReg : 0x05, yearReg : 0x06, secsReg : 0x00, minsReg : 0x01, hourReg : 0x02, dowReg : 0x03 }; //private functions // Convert Decimal value to BCD function dec2bcd(val) { return parseInt(val, 16); } // Convert BCD value to decimal function bcd2dec(val) { return ((val >> 4)*10+(val & 0x0F)); } // Formatting function format(val) { return ("0"+val).substr(-2); } //DST function isDST(day,month,dow) { if ((month === 3) && (dow === 7) && (day > 23)) { return true; } if ((month === 10) && (dow === 7) && (day > 23)) { return false; } if ((month > 3) && (month < 11)) { return true; } else { return false; } } //public //public functions /* Put most of my comments outside the functions... */ DS3231.prototype.setDow = function(day) { var days = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]; var idx = days.indexOf(day); if (idx<0) { print("Not a valid day"); } else { this.i2c.writeTo(C.i2c_address,[C.dowReg, (dec2bcd(1+idx))]); } }; DS3231.prototype.setDate = function(date,month,year) { this.i2c.writeTo(C.i2c_address,[C.dateReg, (dec2bcd(date))]); this.i2c.writeTo(C.i2c_address,[C.monthReg, (dec2bcd(month))]); this.i2c.writeTo(C.i2c_address,[C.yearReg, (dec2bcd(year))]); dstStatus = isDST(date,month,year); }; DS3231.prototype.setTime = function(hour,minute) { this.i2c.writeTo(C.i2c_address,[C.secsReg, 0]); this.i2c.writeTo(C.i2c_address,[C.minsReg, (dec2bcd(minute))]); this.i2c.writeTo(C.i2c_address,[C.hourReg, (dec2bcd(hour))]); }; DS3231.prototype.readDateTime = function () { this.i2c.writeTo(C.i2c_address, C.secsReg/* address*/); var data = this.i2c.readFrom(C.i2c_address, 7/* bytes */); //read number of bytes from address var seconds = bcd2dec(data[0]); var minutes = bcd2dec(data[1]); var hours = bcd2dec(data[2]); var dow = bcd2dec(data[3]); var date = bcd2dec(data[4]); var month = bcd2dec(data[5]); var year = bcd2dec(data[6]); //print(hours+" "+minutes+" "+seconds+" "+(isDST(date,month,dow))+" "+dstStatus); if (hours === 1 && minutes === 0 && seconds === 0 && isDST(date,month,dow) === true && dstStatus === false) { // clocks go forward this.i2c.writeTo(C.i2c_address,[C.hourReg, (dec2bcd(2))]); hours = 2; dstStatus = true; } if (hours === 2 && minutes === 0 && seconds === 0 && isDST(date,month,dow) === false && dstStatus === true) { // clocks go back this.i2c.writeTo(C.i2c_address,[C.hourReg, (dec2bcd(1))]); hours = 1; dstStatus = false; } var rtcDate = format(date)+"/"+format(month)+"/"+format(year); var rtcTime = format(hours)+":"+format(minutes)+":"+format(seconds); var rtcDateTime = rtcDate+" "+rtcTime; return rtcDateTime; }; exports.connect = function(i2c) { return new DS3231(i2c); }; I2C1.setup({scl:B6,sda:B7}); var rtc = exports.connect(I2C1);
-
-
-
Yes that works, got some errors to work though now but its at least calling it okay.
It appears some of my old function code doesn't work. I have tried reflashing the board but still errors.
Stepping all the way back to the code I posted in #19, I get the following error.ERROR: Got '}' expected EOF at line 1 col 286 {I2C1.writeTo(104,0);var data=I2C1.readFrom(104,3);var seconds=("0"+data[0].toString(16)).substr(-2);var minutes=("0"+data[1].toString(16)).substr(-2);var hours=("0"+data[2].toString(16)).substr(-2);var rtcTime=hours+":"+minutes+":"+seconds;print(text,data);print(text,rtcTime);return} ^ at line 1 col 285 {I2C1.writeTo(104,0);var data=I2C1.readFrom(104,3);var seconds=("0"+data[0].toString(16)).substr(-2);var minutes=("0"+data[1].toString(16)).substr(-2);var hours=("0"+data[2].toString(16)).substr(-2);var rtcTime=hours+":"+minutes+":"+seconds;print(text,data);print(text,rtcTime);return} ^ in function called from system ERROR: Error processing interval - removing it. Execution Interrupted during event processing.
-
Thanks Gordon, I think I have made the appropriate changes correctly.
There are no errors at least when I drop the code into the Espruino.
When I type
rtc
into the console it returns
={"i2c":I2C1 }
What is the syntax to call one of the public functions now? i.e.
DS3231.prototype.readDateTime = function ()
-
I'm not sure I have got the grasp of these modules.
How does something like this look?
/* Copyright (c) 2014 Your Name. See the file LICENSE for copying permission. */ /* Quick description of my module... */ //private var C = { dstStatus : , // description rtcDate: , // description rtcTime: , // description }; //private functions // Convert Decimal value to BCD function dec2bcd(val) { return parseInt(val, 16); } // Convert BCD value to decimal function bcd2dec(val) { return ("0"+val.toString(16)).substr(-2); } //DST function isDST(date,month,dow) { //January, february, and december are out. if (month < 3 || month > 11) { return false; } //April to October are in if (month > 3 && month < 11) { return true; } var previousSunday = day - dow; //In march, we are DST if our previous sunday was on or after the 8th. if (month == 3) { return previousSunday >= 8; } //In november we must be before the first sunday to be dst. //That means the previous sunday must be before the 1st. return previousSunday <= 0; } //public DS3231.prototype.C = { i2c_address = 0x68, rtcTime : , // description rtcDate : , // description rtcDay : , // description dstShift : }; //public functions /* Put most of my comments outside the functions... */ DS3231.prototype.setDate = function(date,month,year) { I2C1.writeTo(i2c_address,[0x04, (dec2bcd(date))]); I2C1.writeTo(i2c_address,[0x05, (dec2bcd(month))]); I2C1.writeTo(i2c_address,[0x06, (dec2bcd(year))]); } DS3231.prototype.setTime = function(hour,minute) { I2C1.writeTo(i2c_address,[0x00, 0]); I2C1.writeTo(i2c_address,[0x01, (dec2bcd(minute))]); if (dstStatus === true) { I2C1.writeTo(i2c_address,[0x02, (dec2bcd(hour-1))]); } else I2C1.writeTo(i2c_address,[0x02, (dec2bcd(hour))]); } DS3231.prototype.setDay = function (val) { var days = ["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"]; var idx = days.indexOf(val); if (idx<0) { print("Not a valid day"); } else { I2C1.writeTo(i2c_address,[0x03, (dec2bcd(1+idx))]); } } DS3231.prototype.setDstShift = function (hours) { dstShift = hours; } DS3231.prototype.readDateTime = function () { I2C1.writeTo(i2c_address, 0x00/* address*/); var data = I2C1.readFrom(i2c_address, 7/* bytes */); //read number of bytes from address var seconds = bcd2dec(data[0]); var minutes = (bcd2dec(data[1])); var hours = (data[2]); var dow = (bcd2dec(data[3])); var date = (bcd2dec(data[4])); var month = (bcd2dec(data[5])); var year = (bcd2dec(data[6])); if ((isDST(date,month,dow)) === true) { hours = bcd2dec((hours)+(dstShift)); dstStatus = true; } else { hours = bcd2dec(hours); dstStatus = false; } rtcDate = date+"/"+month+"/"+year; rtcTime = hours+":"+minutes+":"+seconds; rtcDateTime = rtcDate+" "+rtcTime; rtcDay = dow; return rtcDateTime; };
-
-
Starting to get to grips with this now.
It's probably not very elegant but the following seems to be working from what I can see. Any comments greatly appreciated good or bad.I2C1.setup({scl:B6,sda:B7}); var rtcTime = ''; var rtcDate = ''; var rtcDateTime = ''; var dstStatus = ''; var dstShift = 1; i2c_address = 0x68; function readDateTime() { I2C1.writeTo(i2c_address, 0x00/* address*/); var data = I2C1.readFrom(i2c_address, 7/* bytes */); //read number of bytes from address var seconds = bcd2dec(data[0]); var minutes = (bcd2dec(data[1])); var hours = (data[2]); var dow = (bcd2dec(data[3])); var date = (bcd2dec(data[4])); var month = (bcd2dec(data[5])); var year = (bcd2dec(data[6])); if ((isDST(date,month,dow)) === true) { hours = bcd2dec((hours)+(dstShift)); dstStatus = true; } else { hours = bcd2dec(hours); dstStatus = false; } rtcDate = date+"/"+month+"/"+year; rtcTime = hours+":"+minutes+":"+seconds; rtcDateTime = rtcDate+" "+rtcTime; return; } function setDate(date,month,year) { I2C1.writeTo(i2c_address,[0x04, (dec2bcd(date))]); I2C1.writeTo(i2c_address,[0x05, (dec2bcd(month))]); I2C1.writeTo(i2c_address,[0x06, (dec2bcd(year))]); } function setTime(hour,minute) { I2C1.writeTo(i2c_address,[0x00, 0]); I2C1.writeTo(i2c_address,[0x01, (dec2bcd(minute))]); if (dstStatus === true) { I2C1.writeTo(i2c_address,[0x02, (dec2bcd(hour-1))]); } else I2C1.writeTo(i2c_address,[0x02, (dec2bcd(hour))]); } function setDay(val) { switch (val.toString) { case "Monday": I2C1.writeTo(i2c_address,[0x03, (dec2bcd(1))]); break; case "Tuesday": I2C1.writeTo(i2c_address,[0x03, (dec2bcd(2))]); break; case "Wednesday": I2C1.writeTo(i2c_address,[0x03, (dec2bcd(3))]); break; case "Thursday": I2C1.writeTo(i2c_address,[0x03, (dec2bcd(4))]); break; case "Friday": I2C1.writeTo(i2c_address,[0x03, (dec2bcd(5))]); break; case "Saturday": I2C1.writeTo(i2c_address,[0x03, (dec2bcd(6))]); break; case "Sunday": I2C1.writeTo(i2c_address,[0x03, (dec2bcd(7))]); break; default: print(text,"Not a valid day"); return; } } //DST function isDST(date,month,dow) { //January, february, and december are out. if (month < 3 || month > 11) { return false; } //April to October are in if (month > 3 && month < 11) { return true; } var previousSunday = day - dow; //In march, we are DST if our previous sunday was on or after the 8th. if (month == 3) { return previousSunday >= 8; } //In november we must be before the first sunday to be dst. //That means the previous sunday must be before the 1st. return previousSunday <= 0; } // Convert Decimal value to BCD function dec2bcd(val) { return parseInt(val, 16); } // Convert BCD value to decimal function bcd2dec(val) { return ("0"+val.toString(16)).substr(-2); } setInterval(readDateTime, 500);
-
Thats better!
I2C1.setup({scl:B6,sda:B7}); var rtcTime = ''; function time() { I2C1.writeTo(0x68/* I2C slave address*/, 0/* register addr*/); var data = I2C1.readFrom(0x68, 3/* bytes */); var seconds = ("0"+data[0].toString(16)).substr(-2); var minutes = ("0"+data[1].toString(16)).substr(-2); var hours = ("0"+data[2].toString(16)).substr(-2); rtcTime = (hours+":"+minutes+":"+seconds); print(text,data); print(text,rtcTime); return; } setInterval(time, 10000);
-
-
Well I think I may have it working!
Only reading the time off it at the moment. Need to figure out how to set the date and the time.The following code appears to be reading the time okay.
I2C1.setup({scl:B6,sda:B7}); var rtcTime = ''; function time() { I2C1.writeTo(0x68/* I2C slave address*/, 0/* register addr*/); var data = I2C1.readFrom(0x68, 3/* bytes */); var seconds = (data[0] >> 1).toString(); var minutes = (data[1] >> 1).toString(); var hours = (data[2] >> 1).toString(); if (hours < 10) { hours = ("0" + hours); } if (minutes < 10) { minutes = ("0" + minutes); } if (seconds < 10) { seconds = ("0" + seconds); } rtcTime = (hours+":"+minutes+":"+seconds); return; } setInterval(time,500);
I just need to leave it running a while to see if its keeping the right time.
-
@mgg1010 - for some applications there is no internet however if there is then I agree that the other method with the crystal would be better.
Okay back to this little module:
The data I get back if I ask for 2 bytes starting at address 0 seems to come back okay to give me the seconds and minutes into an array, however for some reason it appears that minutes are counted in 90 seconds intervals rather than 60.
i.e. the seconds count up to 89 then the minute is incremented by one and the seconds restart from 0.
Why is this?
-
-
Yes have pullup resistors on the I2C lines.
I think its my understanding thats lacking here. Let me see if what I am assuming is correct.
So the wiki for the RTC module indicates that the DS3231 default I2C address is 0x68. There is no reason this should be different and I have no other devices on the bus.
The DS3231 registers run from BIT0 to BIT7.
So if I want to read 'seconds' for instance am I right in understanding that I need to calculate the exact location by adding the I2C address (0x68) + the register address (00h) and then read 4 Bits?
I assume this then returns those 4 bits that then need to be converted into an integer.
@JumJum - I did find that one first, but I figured if we are going to have a module for the Espruino it had better have all the bells and whistles.
This version from Rhys Williams is ported from Brett Beauregard's Arduino version which was pretty well documented on his blog a few years ago.
@Gordon - No never really done any object oriented stuff, just simple bits and pieces. I seem to learn best by hacking away at other examples to understand whats going on. But I will definitely refer to your example.
I had pretty much figured it out what you had with the PID code.
The only issue may be when the value that is returned from getTime() rolls over.
It appears to be working using a few simple tests (finger on thermistor) watch demand decrease, finger off thermistor watch demand increase.