Browse Source

Solved inaccuracy problem with adc. Started with a nice overview for the raw samples

software_develop
Elmar van Rijnswou 7 years ago
parent
commit
6b49cbebb3
  1. 19
      software/app/adc.h
  2. 30
      software/app/ads101x.cpp
  3. 5
      software/app/ads101x.h
  4. 148
      software/app/web_interface.cpp
  5. 109
      software/app/web_interface.h
  6. 18
      software/files/index.html
  7. 5
      software/files/index.js

19
software/app/adc.h

@ -12,13 +12,30 @@
namespace rijnfel { namespace rijnfel {
/**
* Abstract interface for Analog to Digital converters.
* Template holds sample type and voltage type
*/
template<typename Sample, typename Voltage> template<typename Sample, typename Voltage>
class cADC: public cSensor<Sample> { class cADC: public cSensor<Sample> {
public: public:
/**
* Default constructor
*/
cADC() { cADC() {
} }
virtual Voltage ConvertSample(Sample & sample) = 0;
/**
* This virtual function should be implemented to convert a sample to a voltage
* @param i_sample the raw sample that should be converted
* @return a voltage in mili-volt
*/
virtual Voltage ConvertSample(Sample & i_sample) = 0;
/**
* Default destructor
*/
virtual ~cADC() { virtual ~cADC() {
} }

30
software/app/ads101x.cpp

@ -74,27 +74,34 @@ bool cADS101x::IsReady(void) {
} }
uint16_t cADS101x::CreateSettings(uint8_t start) { uint16_t cADS101x::CreateSettings(uint8_t start) {
return OS_BIT(start) | MUX_BIT(m_mux) | PGA_BIT(m_gain) return OS_BIT(start) | MUX_BIT(m_mux) | PGA_BIT(m_gain) | MODE_BIT(m_oneShot) | DR_BIT(m_sampleSpeed);
| MODE_BIT(m_oneShot) | DR_BIT(m_sampleSpeed);
} }
void cADS101x::WriteSettings(uint16_t i_settings) { void cADS101x::WriteSettings(uint16_t i_settings) {
#ifdef DUMMY_ADC
return;
#else
Wire.beginTransmission(m_address); Wire.beginTransmission(m_address);
Wire.write((uint8_t) REGISTER_CONFIG); Wire.write((uint8_t) REGISTER_CONFIG);
Wire.write((uint8_t) (i_settings >> 8)); Wire.write((uint8_t) (i_settings >> 8));
Wire.write((uint8_t) (i_settings & 0xFF)); Wire.write((uint8_t) (i_settings & 0xFF));
int8_t ret = Wire.endTransmission(); int8_t ret = Wire.endTransmission();
if (ret) { if (ret) {
Serial.printf("Err writing settings ret: %d\n\r", ret); //Serial.printf("Err writing settings ret: %d\n\r", ret);
} }
#endif
} }
uint16_t cADS101x::ReadRegister(uint8_t i_register) { uint16_t cADS101x::ReadRegister(uint8_t i_register) {
#ifdef DUMMY_ADC
return 1;
#else
Wire.beginTransmission(m_address); Wire.beginTransmission(m_address);
Wire.write(i_register); Wire.write(i_register);
Wire.endTransmission(); Wire.endTransmission();
Wire.requestFrom(m_address, static_cast<uint8_t>(2)); Wire.requestFrom(m_address, static_cast<uint8_t>(2));
return ((Wire.read() << 8) | (Wire.read())); return ((Wire.read() << 8) | (Wire.read()));
#endif
} }
void cADS101x::OneShot(void) { void cADS101x::OneShot(void) {
@ -105,7 +112,11 @@ void cADS101x::OneShot(void) {
} }
uint16_t cADS101x::GetSettings(void) { uint16_t cADS101x::GetSettings(void) {
return ReadRegister(REGISTER_CONFIG);; #ifdef DUMMY_ADC
return CreateSettings(0);
#else
return ReadRegister(REGISTER_CONFIG);
#endif
} }
ads_voltage_t cADS101x::ConvertSample(ads_sample_t & sample) { ads_voltage_t cADS101x::ConvertSample(ads_sample_t & sample) {
//Raw sample is in (parts of) millivolts, go to micro to remove fractions //Raw sample is in (parts of) millivolts, go to micro to remove fractions
@ -140,12 +151,20 @@ ads_voltage_t cADS101x::ConvertSample(ads_sample_t & sample) {
} }
ads_sample_t cADS101x::RawSample(void) { ads_sample_t cADS101x::RawSample(void) {
#ifdef DUMMY_ADC
ads_sample_t sample;
sample.gain = m_gain;
sample.mux = m_mux;
sample.rawSample = m_counter++;
return sample;
#else
OneShot(); OneShot();
ads_sample_t sample; ads_sample_t sample;
sample.rawSample = ReadRegister(REGISTER_CONVERSION); sample.rawSample = ReadRegister(REGISTER_CONVERSION);
sample.gain = m_gain; sample.gain = m_gain;
sample.mux = m_mux; sample.mux = m_mux;
m_latestSample = sample; m_latestSample = sample;
#endif
return sample; return sample;
} }
@ -154,6 +173,9 @@ void cADS101x::SetDefaults(void) {
m_gain = eGainAmplifier::FSR_2_048; m_gain = eGainAmplifier::FSR_2_048;
m_sampleSpeed = eSampleSpeed::SPS_1600; m_sampleSpeed = eSampleSpeed::SPS_1600;
m_oneShot = true; m_oneShot = true;
#ifdef DUMMY_ADC
m_counter = 0;
#endif
} }
} }

5
software/app/ads101x.h

@ -9,6 +9,7 @@
#define APP_ADS101X_H_ #define APP_ADS101X_H_
#include <stdint.h> #include <stdint.h>
#include "hardware.h"
#include "adc.h" #include "adc.h"
namespace rijnfel { namespace rijnfel {
@ -65,6 +66,10 @@ private:
enum eInputMux m_mux; enum eInputMux m_mux;
enum eGainAmplifier m_gain; enum eGainAmplifier m_gain;
enum eSampleSpeed m_sampleSpeed; enum eSampleSpeed m_sampleSpeed;
private:
#ifdef DUMMY_ADC
uint16_t m_counter;
#endif
}; };
} }
} }

148
software/app/web_interface.cpp

@ -7,20 +7,18 @@
#include "web_interface.h" #include "web_interface.h"
#include <SmingCore/SmingCore.h> #include <SmingCore/SmingCore.h>
#include <SmingCore/Network/WebConstants.h>
//TODO remove this
#include "ads101x.h"
namespace rijnfel { namespace rijnfel {
cWebInterface *cWebInterface::s_instance = 0; cWebInterface *cWebInterface::s_instance = 0;
static void onIndex(HttpRequest &request, HttpResponse &response) { static void onIndex(HttpRequest & i_request, HttpResponse & i_response) {
cWebInterface::GetInstance()->OnIndex(request, response); cWebInterface::GetInstance()->OnIndex(i_request, i_response);
} }
static void onRefresh(HttpRequest &request, HttpResponse &response) { static void onRefresh(HttpRequest & i_request, HttpResponse & i_response) {
cWebInterface::GetInstance()->OnRefresh(request, response); cWebInterface::GetInstance()->OnRefresh(i_request, i_response);
} }
static void onConfiguration(HttpRequest &request, HttpResponse &response) { static void onConfiguration(HttpRequest &request, HttpResponse &response) {
@ -34,116 +32,134 @@ static void onConfiguration_json(HttpRequest &request, HttpResponse &response) {
cWebInterface::cWebInterface() : cWebInterface::cWebInterface() :
m_serverStarted(false) { m_serverStarted(false) {
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
m_adc_value[i] = 0; m_adc_value_average[i] = 0;
}
// Integer requires 8 digits, and one for the comma
m_jsonBuffer = new char[RAW_SAMPLES * 8 + RAW_SAMPLES * 2];
if (m_jsonBuffer == NULL) {
Serial.print("Not enough ram");
} }
// TODO Auto-generated constructor stub // TODO Auto-generated constructor stub
} }
void onFile(HttpRequest &request, HttpResponse &response) { void onFile(HttpRequest & i_request, HttpResponse & i_response) {
String file = request.getPath(); String file = i_request.getPath();
if (file[0] == '/') if (file[0] == '/')
file = file.substring(1); file = file.substring(1);
if (file[0] == '.') if (file[0] == '.')
response.forbidden(); i_response.forbidden();
else { else {
response.setCache(86400, true); // It's important to use cache for better performance. i_response.setCache(86400, true); // It's important to use cache for better performance.
response.sendFile(file); i_response.sendFile(file);
} }
} }
void cWebInterface::Start() { void cWebInterface::StartServer() {
if (m_serverStarted) if (m_serverStarted)
return; return;
server.addPath("/", onIndex); m_server.addPath("/", onIndex);
server.addPath("/state", onRefresh); m_server.addPath("/state", onRefresh);
server.addPath("/config", onConfiguration); m_server.addPath("/config", onConfiguration);
server.addPath("/config.json", onConfiguration_json); m_server.addPath("/config.json", onConfiguration_json);
server.setDefaultHandler(onFile); m_server.setDefaultHandler(onFile);
server.listen(80); m_server.listen(80);
} }
void cWebInterface::Stop() { void cWebInterface::StopServer() {
if (!m_serverStarted) if (!m_serverStarted)
return; return;
m_serverStarted = false; m_serverStarted = false;
} }
void cWebInterface::OnIndex(HttpRequest &request, HttpResponse &response) { void cWebInterface::OnIndex(HttpRequest &i_request, HttpResponse & i_response) {
response.setCache(86400, true); // It's important to use cache for better performance. i_response.setCache(86400, true); // It's important to use cache for better performance.
response.sendFile("index.html"); i_response.sendFile("index.html");
} }
void cWebInterface::OnRefresh(HttpRequest &request, HttpResponse &response) { void cWebInterface::OnRefresh(HttpRequest & i_request, HttpResponse & i_response) {
JsonObjectStream* stream = new JsonObjectStream(); JsonObjectStream* stream = new JsonObjectStream();
JsonObject& json = stream->getRoot(); JsonObject& json = stream->getRoot();
json["adc_1"] = m_adc_value[0]; json["adc_1"] = m_adc_value_average[0];
json["adc_2"] = m_adc_value[1]; json["adc_2"] = m_adc_value_average[1];
#ifdef REV_1 #ifdef REV_1
json["adc_3"] = m_adc_value[3]; json["adc_3"] = m_adc_value_average[3];
json["adc_4"] = m_adc_value[2]; json["adc_4"] = m_adc_value_average[2];
#else #else
json["adc_3"] = m_adc_value[2]; json["adc_3"] = m_adc_value_average[2];
json["adc_4"] = m_adc_value[3]; json["adc_4"] = m_adc_value_average[3];
#endif #endif
response.sendJsonObject(stream); char * writePos = m_jsonBuffer;
for (int sample = 0; sample < m_adc_values_raw_cnt[RAW_CHANNEL]; sample++) {
const int pos = sprintf(writePos, "%d,", m_adc_values_raw[RAW_CHANNEL][sample]);
writePos = &m_jsonBuffer[pos];
}/*
json["raw_adc"] = m_jsonBuffer; //ss.str();
*/
i_response.sendJsonObject(stream);
m_adc_values_raw_cnt[RAW_CHANNEL] = 0;
}
void cWebInterface::OnRawUpdate(HttpRequest& i_request, HttpResponse& i_response) {
} }
void cWebInterface::UpdateAdc(cADC<ads::ads_sample_t, int32_t> & adc, void cWebInterface::UpdateAdc(cADC<ads::ads_sample_t, int32_t> & i_adc, cDoubleBuffer<ads::ads_sample_t>& i_adcBuffer) {
cDoubleBuffer<ads::ads_sample_t>& adcBuffer) { ads::ads_sample_t * buf = &i_adcBuffer.GetReadyBuffer()[0];
ads::ads_sample_t * buf = &adcBuffer.GetReadyBuffer()[0];
if (buf != NULL) { if (buf != NULL) {
ads::ads_sample_t averageSample; int pos = buf->mux - ads::eInputMux::AIN_0;
averageSample.gain = buf->gain;
averageSample.mux = buf->mux;
int64_t average = 0; int64_t average = 0;
//Serial.printf("Channel: %d\n\r", buf->mux - ads::eInputMux::AIN_0); int size = i_adcBuffer.GetSize();
int size = adcBuffer.GetSize();
for (int i = 0; i < size; i++) { for (int i = 0; i < size; i++) {
average += buf[i].rawSample; average += i_adc.ConvertSample(buf[i]);
//Serial.printf("%d ", buf[i].rawSample);
if (pos == RAW_CHANNEL) {
int idx = m_adc_values_raw_cnt[RAW_CHANNEL];
if (idx < RAW_SAMPLES) {
m_adc_values_raw[RAW_CHANNEL][idx] = i_adc.ConvertSample(buf[i]);
m_adc_values_raw_cnt[RAW_CHANNEL]++;
}
}
} }
//Serial.printf("\n\r before: %d", average);
if (size != 0) { if (size != 0) {
average /= size; average /= size;
} }
//Serial.printf("after: %d [%d]\n\r", average, size);
averageSample.rawSample = static_cast<int16_t>(average); m_adc_value_average[pos] = static_cast<int32_t>(average);
int pos = averageSample.mux - ads::eInputMux::AIN_0;
m_adc_value[pos] = adc.ConvertSample(averageSample);
} }
} }
void cWebInterface::PrintValues() { void cWebInterface::PrintValues() {
Serial.printf("c[0]: %d c[1]: %d c[2]: %d c[3]: %d\n\r", m_adc_value[0], Serial.printf("c[0]: %d c[1]: %d c[2]: %d c[3]: %d\n\r", m_adc_value_average[0], m_adc_value_average[1],
m_adc_value[1], m_adc_value[2], m_adc_value[3]); m_adc_value_average[2], m_adc_value_average[3]);
} }
void cWebInterface::UpdateTemp(cDoubleBuffer<uint32_t>& adcBuffer) { void cWebInterface::UpdateTemp(cDoubleBuffer<uint32_t>& i_tempBuffer) {
} }
cWebInterface::~cWebInterface() { cWebInterface::~cWebInterface() {
// TODO Auto-generated destructor stub // TODO Auto-generated destructor stub
} }
void cWebInterface::OnConfiguration(HttpRequest &request, HttpResponse &response) void cWebInterface::ResetRawValues() {
{ for (int channel = 0; channel < 4; channel++) {
for (int sample = 0; sample < 1000; sample++) {
m_adc_values_raw[channel][sample] = 0;
}
}
}
if (request.method == HTTP_POST) void cWebInterface::OnConfiguration(HttpRequest &request, HttpResponse &response) {
{
debugf("Update config"); if (strcmp(request.getRequestMethod().c_str(), RequestMethod::POST) == 0) {
//debugf("Update config");
// Update config // Update config
if (request.getBody() == NULL) if (request.getBody() == NULL) {
{
Serial.println(request.getPostParameter("StaSSID")); Serial.println(request.getPostParameter("StaSSID"));
debugf("NULL bodyBuf"); //debugf("NULL bodyBuf");
return; return;
} } else {
else
{
StaticJsonBuffer<200> jsonBuffer; StaticJsonBuffer<200> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(request.getBody()); JsonObject& root = jsonBuffer.parseObject(request.getBody());
//root.prettyPrintTo(Serial); //Uncomment it for debuging //root.prettyPrintTo(Serial); //Uncomment it for debuging
@ -177,16 +193,13 @@ void cWebInterface::OnConfiguration(HttpRequest &request, HttpResponse &response
}*/ }*/
} }
//saveConfig(ActiveConfig); //saveConfig(ActiveConfig);
} } else {
else
{
response.setCache(86400, true); // It's important to use cache for better performance. response.setCache(86400, true); // It's important to use cache for better performance.
response.sendFile("config.html"); response.sendFile("config.html");
} }
} }
void cWebInterface::OnConfiguration_json(HttpRequest &request, HttpResponse &response) void cWebInterface::OnConfiguration_json(HttpRequest &request, HttpResponse &response) {
{
JsonObjectStream* stream = new JsonObjectStream(); JsonObjectStream* stream = new JsonObjectStream();
JsonObject& json = stream->getRoot(); JsonObject& json = stream->getRoot();
@ -194,9 +207,8 @@ void cWebInterface::OnConfiguration_json(HttpRequest &request, HttpResponse &res
json["StaPassword"] = 23; json["StaPassword"] = 23;
json["StaEnable"] = 24; json["StaEnable"] = 24;
response.sendDataStream(stream, MIME_JSON); response.sendDataStream(stream, ContentType::JSON);
} }
} /* namespace rijnfel */ } /* namespace rijnfel */

109
software/app/web_interface.h

@ -9,44 +9,119 @@
#define APP_WEB_INTERFACE_H_ #define APP_WEB_INTERFACE_H_
#include "adc.h" #include "adc.h"
//TODO remove this
#include "ads101x.h" #include "ads101x.h"
#include "dummy_adc.h"
#include "double_buffer.h" #include "double_buffer.h"
#include <SmingCore/SmingCore.h> #include <SmingCore/SmingCore.h>
namespace rijnfel { namespace rijnfel {
#define RAW_CHANNEL 1
#define RAW_SAMPLES 1000
class cWebInterface { class cWebInterface {
public: public:
static cWebInterface *s_instance; /**
* Returns the global cWebInterface instance.
* Only one webserver should ever be running
* @return global cWebInterface instance
*/
static cWebInterface *GetInstance() { static cWebInterface *GetInstance() {
if (cWebInterface::s_instance == NULL) if (cWebInterface::s_instance == NULL)
cWebInterface::s_instance = new cWebInterface(); cWebInterface::s_instance = new cWebInterface();
return cWebInterface::s_instance; return cWebInterface::s_instance;
} }
/// Singleton instance
static cWebInterface *s_instance;
public: public:
cWebInterface(); /**
cWebInterface(cWebInterface const&) { * Should not be used because it's a singleton
m_serverStarted = false; * @param delete
} */
cWebInterface& operator=(cWebInterface const&) { cWebInterface(cWebInterface const&) = delete;
}
void Start(); /**
void Stop(); * Should not be used because it's a singleton
void UpdateAdc(cADC<ads::ads_sample_t, int32_t> & adc, * @param delete
cDoubleBuffer<ads::ads_sample_t> & adcBuffer); * @return delete
void UpdateTemp(cDoubleBuffer<uint32_t> & adcBuffer); */
cWebInterface& operator=(cWebInterface const&) = delete;
/**
* Registers the paths and starts the server
*/
void StartServer();
/**
* Stops the server
*/
void StopServer();
/**
* Updates the adc on the website. Averages it
* @param i_adc Instance of the adc sensor
* @param i_adcBuffer Buffer containing the raw adc values
*/
void UpdateAdc(cADC<ads::ads_sample_t, int32_t> & i_adc, cDoubleBuffer<ads::ads_sample_t> & i_adcBuffer);
/**
* Updates the temperature on the website
* @param i_tempBuffer buffer containing temperature values
*/
void UpdateTemp(cDoubleBuffer<uint32_t> & i_tempBuffer);
/**
* This is a debug function that prints out the average values
* @todo remove this
*/
void PrintValues(); void PrintValues();
/**
* Destructor
*/
virtual ~cWebInterface(); virtual ~cWebInterface();
public: public:
void OnIndex(HttpRequest &request, HttpResponse &response); /**
void OnRefresh(HttpRequest &request, HttpResponse &response); *
* @param i_request
* @param i_response Response to the client, index.html
*/
void OnIndex(HttpRequest & i_request, HttpResponse & i_response);
/**
* Function gets called from the mobile to refresh the average values
* @param i_request Request from the client
* @param i_response Response to the client, contains JSON with averages
*/
void OnRefresh(HttpRequest & i_request, HttpResponse & i_response);
/**
*
* @param i_request
* @param i_response
*/
void OnRawUpdate(HttpRequest& i_request, HttpResponse& i_response);
void OnConfiguration_json(HttpRequest &request, HttpResponse &response); void OnConfiguration_json(HttpRequest &request, HttpResponse &response);
void OnConfiguration(HttpRequest &request, HttpResponse &response); void OnConfiguration(HttpRequest &request, HttpResponse &response);
protected:
/**
* Initializes the variables
*/
cWebInterface();
private: private:
void ResetRawValues();
/// Whether the server has started or not
bool m_serverStarted; bool m_serverStarted;
int32_t m_adc_value[4]; /// Holds the average for all the channels
HttpServer server; int32_t m_adc_value_average[4];
/// Server instance
HttpServer m_server;
char * m_jsonBuffer;
int32_t m_adc_values_raw[4][RAW_SAMPLES];
int m_adc_values_raw_cnt[4];
}; };
} /* namespace rijnfel */ } /* namespace rijnfel */

18
software/files/index.html

@ -31,6 +31,24 @@
<div class="row"> <div class="row">
<h2>&nbsp;</h2> <h2>&nbsp;</h2>
<div class="col-xs-offset-2">
<div class="col-xs-10">
<div class="panel panel-default">
<div class="panel-heading">
<h3 class="panel-title">Raw samples</h3>
</div>
<div class="panel-body">
<textarea id="raw_samples" rows="4" cols="50" style="width:100%;">
</textarea>
</div>
</div>
</div>
</div> <!-- /col -->
</div> <!-- /row -->
<div class="row">
<div class="col-xs-offset-2"> <div class="col-xs-offset-2">
<div class="col-xs-10 col-md-5"> <div class="col-xs-10 col-md-5">
<div class="panel panel-default"> <div class="panel panel-default">

5
software/files/index.js

@ -7,7 +7,10 @@ $( document ).ready(function() {
document.getElementById('adc_3').textContent = data.adc_3; document.getElementById('adc_3').textContent = data.adc_3;
document.getElementById('adc_4').textContent = data.adc_4; document.getElementById('adc_4').textContent = data.adc_4;
setTimeout(worker, 1000); //var text = document.getElementById('raw_adc');
//text.value += data.raw_adc;
setTimeout(worker, 500);
}); });
})(); })();
}); });

Loading…
Cancel
Save