mirror of
https://github.com/RobTillaart/Arduino.git
synced 2024-10-03 18:09:02 -04:00
2021-01-29
This commit is contained in:
parent
72861821fc
commit
7661eee8b4
@ -1,7 +1,7 @@
|
||||
|
||||
# MIT License
|
||||
|
||||
Copyright (c) 2010-2020 Rob Tillaart
|
||||
Copyright (c) 2010-2021 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
41
README.md
41
README.md
@ -1,39 +1,52 @@
|
||||
# Arduino libraries
|
||||
|
||||
**NOTE** these libraries will all get their own repo, so this repository
|
||||
does not have the latest version of all libs anymore. That said I will update
|
||||
this bulk repo on request or if time permit.
|
||||
**NOTE** these libraries all have their own repo under https://github.com/RobTillaart?tab=repositories
|
||||
|
||||
So this repository does not have the latest version of all libs anymore.
|
||||
That said I will update this bulk repo on request or if time permit.
|
||||
|
||||
|
||||
### Introduction
|
||||
|
||||
This repository contains several Arduino libraries I have written to be used in applications.
|
||||
Most of them include example code how the libraries can be used.
|
||||
Furthermore this repository contains a few stand alone applications.
|
||||
|
||||
|
||||
### Questions
|
||||
|
||||
For questions about the usage of the libraries, please post a question on the Arduino
|
||||
forum at http://forum.arduino.cc/
|
||||
|
||||
|
||||
### Bugs and issues
|
||||
|
||||
**Please check if the library has its own repo first and fill an issue there**
|
||||
|
||||
For bugs in the libraries, please fill in an issue in Github as that makes it
|
||||
far easier to track them. If possible provide a minimal code snippet that exposes
|
||||
the bug. Also proposals for solutions are welcome.
|
||||
For bugs in the libraries, please fill in an issue in Github as that makes it far easier to track them.
|
||||
If possible provide a minimal code snippet that exposes the bug.
|
||||
Add information about platform used and version etc.
|
||||
Also proposals for solutions are welcome.
|
||||
|
||||
Other issues are not directly bugs but still problematic.
|
||||
E.g. if a library is too slow for your application that is an serious issue, not a bug.
|
||||
Please fill in an issue and provide as much details about your requirements.
|
||||
Maybe I can help to fix it.
|
||||
|
||||
Issues are not bugs but still possible problematic. E.g. if a library is too slow
|
||||
for your application that is an issue, not a bug. Please fill in an issue and provide
|
||||
as much details about your requirements.
|
||||
|
||||
### Improvements and changes
|
||||
For improvements and changes, please provide a pull request. I will try to follow up on them
|
||||
asap but it can take quite some time. Please try to be generic in your improvements and try to
|
||||
see "over the needs of your own application".
|
||||
|
||||
For improvements and changes, please provide a pull request.
|
||||
I will try to follow up on them asap but it can take quite some time.
|
||||
Please try to be generic in your improvements and try to see "over the needs of your own application".
|
||||
|
||||
There is no guarantee that pull requests will be honored.
|
||||
In such case feel free to start your own modified library from a fork.
|
||||
|
||||
|
||||
### License and Warranty
|
||||
I appreciate if you give credits when appropriate, and if you want to donate, please
|
||||
donate to charity like "doctors without borders".
|
||||
|
||||
I appreciate if you give credits when appropriate.
|
||||
|
||||
Please check the file LICENSE.md for the details.
|
||||
|
||||
|
7
libraries/ACS712/.arduino-ci.yml
Normal file
7
libraries/ACS712/.arduino-ci.yml
Normal file
@ -0,0 +1,7 @@
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
- uno
|
||||
- leonardo
|
||||
- due
|
||||
- zero
|
13
libraries/ACS712/.github/workflows/arduino_test_runner.yml
vendored
Normal file
13
libraries/ACS712/.github/workflows/arduino_test_runner.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: Arduino CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
arduino_ci:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Arduino-CI/action@master
|
||||
# Arduino-CI/action@v0.1.1
|
@ -1,66 +1,68 @@
|
||||
//
|
||||
// FILE: ACS712.cpp
|
||||
// AUTHOR: Rob Tillaart, Pete Thompson
|
||||
// VERSION: 0.2.0
|
||||
// VERSION: 0.2.1
|
||||
// DATE: 2020-08-02
|
||||
// PURPOSE: ACS712 library - current measurement
|
||||
//
|
||||
// HISTORY:
|
||||
// 0.1.0 2020-03-17 initial version
|
||||
// 0.1.1 2020-03-18 first release version
|
||||
// 0.1.2 2020-03-21 automatic formfactor test
|
||||
// 0.1.2 2020-03-21 automatic formfactor test
|
||||
// 0.1.3 2020-05-27 fix library.json
|
||||
// 0.1.4 2020-08-02 Allow for faster processors
|
||||
// 0.2.0 2020-08-02 Add autoMidPoint
|
||||
// 0.2.1 2020-12-06 Add arduino-CI + readme + unittest + refactor
|
||||
|
||||
#include "ACS712.h"
|
||||
|
||||
ACS712::ACS712(uint8_t analogPin, float volts, uint16_t maxADC, uint8_t mVperA)
|
||||
{
|
||||
_pin = analogPin;
|
||||
// 1x 1000 for V -> mV
|
||||
_mVpstep = 1000.0 * volts / maxADC;
|
||||
_mVperAmpere = mVperA;
|
||||
_formFactor = 0.70710678119; // 0.5 * sqrt(2); TODO: should be smaller in practice 0.5 ?
|
||||
_midPoint = maxADC / 2;
|
||||
_noisemV = 21; // Noise is 21mV according to datasheet
|
||||
_pin = analogPin;
|
||||
_mVpstep = 1000.0 * volts / maxADC; // 1x 1000 for V -> mV
|
||||
_mVperAmpere = mVperA;
|
||||
_formFactor = 0.70710678119; // 0.5 * sqrt(2); TODO: should be smaller in practice 0.5 ?
|
||||
_midPoint = maxADC / 2;
|
||||
_noisemV = 21; // Noise is 21mV according to datasheet
|
||||
}
|
||||
|
||||
int ACS712::mA_AC(uint8_t freq)
|
||||
{
|
||||
uint32_t start = micros();
|
||||
uint16_t period = ((freq == 60) ? 16670 : 20000);
|
||||
uint16_t samples = 0;
|
||||
uint16_t zeros = 0;
|
||||
int _min, _max;
|
||||
_min = _max = analogRead(_pin);
|
||||
while (micros() - start < period) // UNO ~180 samples...
|
||||
{
|
||||
samples++;
|
||||
int val = analogRead(_pin);
|
||||
if (val < _min) _min = val;
|
||||
if (val > _max) _max = val;
|
||||
if (abs(val - _midPoint) <= (_noisemV/_mVpstep)) zeros++;
|
||||
}
|
||||
int p2p = (_max - _min);
|
||||
uint32_t start = micros();
|
||||
uint16_t period = ((freq == 60) ? 16670 : 20000);
|
||||
uint16_t samples = 0;
|
||||
uint16_t zeros = 0;
|
||||
|
||||
// automatic determine _formFactor / crest factor
|
||||
float D = 0;
|
||||
float FF = 0;
|
||||
if (zeros > samples * 0.025)
|
||||
{
|
||||
D = 1.0 - (1.0 * zeros) / samples; // % SAMPLES NONE ZERO
|
||||
FF = sqrt(D) * 0.5 * sqrt(2); // ASSUME NON ZERO PART ~ SINUS
|
||||
}
|
||||
else // # zeros is small => D --> 1 --> sqrt(D) --> 1
|
||||
{
|
||||
FF = 0.5 * sqrt(2);
|
||||
}
|
||||
_formFactor = FF;
|
||||
int _min, _max;
|
||||
_min = _max = analogRead(_pin);
|
||||
|
||||
// math could be partially precalculated: C = 1000.0 * 0.5 * _mVpstep / _mVperAmpere;
|
||||
// rounding?
|
||||
return 1000.0 * 0.5 * p2p * _mVpstep * _formFactor / _mVperAmpere;
|
||||
while (micros() - start < period) // UNO ~180 samples...
|
||||
{
|
||||
samples++;
|
||||
int val = analogRead(_pin);
|
||||
if (val < _min) _min = val;
|
||||
if (val > _max) _max = val;
|
||||
if (abs(val - _midPoint) <= (_noisemV/_mVpstep)) zeros++;
|
||||
}
|
||||
int point2point = (_max - _min);
|
||||
|
||||
// automatic determine _formFactor / crest factor
|
||||
float D = 0;
|
||||
float FF = 0;
|
||||
if (zeros > samples * 0.025)
|
||||
{
|
||||
D = 1.0 - (1.0 * zeros) / samples; // % SAMPLES NONE ZERO
|
||||
FF = sqrt(D) * 0.5 * sqrt(2); // ASSUME NON ZERO PART ~ SINUS
|
||||
}
|
||||
else // # zeros is small => D --> 1 --> sqrt(D) --> 1
|
||||
{
|
||||
FF = 0.5 * sqrt(2);
|
||||
}
|
||||
_formFactor = FF;
|
||||
|
||||
// math could be partially precalculated: C = 1000.0 * 0.5 * _mVpstep / _mVperAmpere;
|
||||
// rounding?
|
||||
return 1000.0 * 0.5 * point2point * _mVpstep * _formFactor / _mVperAmpere;
|
||||
}
|
||||
|
||||
int ACS712::mA_DC()
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// FILE: ACS712.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.0
|
||||
// VERSION: 0.2.1
|
||||
// DATE: 2020-08-02
|
||||
// PURPOSE: ACS712 library - current measurement
|
||||
//
|
||||
@ -11,7 +11,7 @@
|
||||
|
||||
#include "Arduino.h"
|
||||
|
||||
#define ACS712_LIB_VERSION "0.1.3"
|
||||
#define ACS712_LIB_VERSION "0.2.1"
|
||||
|
||||
|
||||
class ACS712
|
||||
@ -37,7 +37,7 @@ class ACS712
|
||||
int mA_DC();
|
||||
|
||||
// midpoint ADC for DC only
|
||||
inline void setMidPoint(uint16_t mp) { _midPoint = mp; };
|
||||
inline void setMidPoint(uint16_t mp) { _midPoint = mp; };
|
||||
inline uint16_t getMidPoint() { return _midPoint; };
|
||||
inline void incMidPoint() { _midPoint++; };
|
||||
inline void decMidPoint() { _midPoint--; };
|
||||
@ -58,8 +58,8 @@ class ACS712
|
||||
|
||||
private:
|
||||
uint8_t _pin;
|
||||
float _mVpstep; // millivolt per step
|
||||
float _formFactor; // P2P -> RMS
|
||||
float _mVpstep; // millivolt per step
|
||||
float _formFactor; // point2point -> RMS
|
||||
uint8_t _mVperAmpere;
|
||||
uint16_t _midPoint;
|
||||
uint8_t _noisemV;
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020 Rob Tillaart
|
||||
Copyright (c) 2020-2021 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
23
libraries/ACS712/keywords.txt
Normal file
23
libraries/ACS712/keywords.txt
Normal file
@ -0,0 +1,23 @@
|
||||
# Syntax Coloring Map For ACS712
|
||||
|
||||
# Datatypes (KEYWORD1)
|
||||
ACS712 KEYWORD1
|
||||
|
||||
# Methods and Functions (KEYWORD2)
|
||||
mA_AC KEYWORD2
|
||||
mA_DC KEYWORD2
|
||||
setMidPoint KEYWORD2
|
||||
getMidPoint KEYWORD2
|
||||
incMidPoint KEYWORD2
|
||||
decMidPoint KEYWORD2
|
||||
setFormFactor KEYWORD2
|
||||
getFormFactor KEYWORD2
|
||||
setNoisemV KEYWORD2
|
||||
getNoisemV KEYWORD2
|
||||
setmVperAmp KEYWORD2
|
||||
getmVperAmp KEYWORD2
|
||||
|
||||
|
||||
# Constants (LITERAL1)
|
||||
ACS712_LIB_VERSION LITERAL1
|
||||
|
@ -21,7 +21,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/ACS712"
|
||||
},
|
||||
"version":"0.2.0",
|
||||
"version":"0.2.1",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*"
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=ACS712
|
||||
version=0.2.0
|
||||
version=0.2.1
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>, Pete Thompson <pete.thompson@yahoo.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=ACS712 library for Arduino.
|
||||
|
@ -1,6 +1,12 @@
|
||||
|
||||
[![Arduino CI](https://github.com/RobTillaart/ACS712/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
||||
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/ACS712/blob/master/LICENSE)
|
||||
[![GitHub release](https://img.shields.io/github/release/RobTillaart/ACS712.svg?maxAge=3600)](https://github.com/RobTillaart/ACS712/releases)
|
||||
|
||||
# ACS712
|
||||
|
||||
Current Sensor - 5A, 20A, 30A
|
||||
Library for the ACS712 Current Sensor - 5A, 20A, 30A
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
@ -9,8 +15,8 @@ analog output that provides a voltage that is lineair with the current.
|
||||
The ACS712 library supports only a built in ADC by means of analogRead().
|
||||
There are 2 core functions:
|
||||
|
||||
* **int mA_DC()**
|
||||
* **int mA_AC()**
|
||||
- **int mA_DC()**
|
||||
- **int mA_AC()**
|
||||
|
||||
To measure DC current a single analogRead() with some conversion math is sufficient to get
|
||||
a value. To stabilize the signal analogRead() is called twice.
|
||||
@ -20,10 +26,50 @@ peak to peak value which is converted to the RMS value. To convert the peak2peak
|
||||
value to RMS one need the so called crest or form factor. This factor depends heavily
|
||||
on the signal form. For a perfect sinus the value is sqrt(2)/2.
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
#### Base
|
||||
|
||||
- **ACS712(analogPin, volts = 5.0, maxADC = 1023, mVperA = 100)** constructor
|
||||
- **mA_AC(freq = 50)** blocks ~21 ms to sample a whole 50 or 60 Hz period.
|
||||
- **mA_DC()**
|
||||
|
||||
#### Midpoint
|
||||
|
||||
- **setMidPoint(mp)** sets midpoint ADC for DC only
|
||||
- **autoMidPoint(uint8_t freq = 50)** Auto midPoint, assuming zero DC current or any AC current
|
||||
- **getMidPoint()** read back setting
|
||||
- **incMidPoint()** manual increase midpoint (manually)
|
||||
- **decMidPoint()** manual decrease midpoint (manually)
|
||||
|
||||
|
||||
#### Formfactor
|
||||
|
||||
Also known as crest factor; affects AC only.
|
||||
Default = 0.5 \* sqrt(2) = ~0.70710678...
|
||||
|
||||
- **setFormFactor(ff)** manually sets formfactor 0.0 .. 1.0
|
||||
- **getFormFactor()** returns current formFactor
|
||||
|
||||
#### Noise
|
||||
|
||||
Default = 21 mV.
|
||||
- **setNoisemV(noisemV)** set noise level
|
||||
- **getNoisemV()** returns set value
|
||||
|
||||
#### mV per Ampere
|
||||
|
||||
Both for AC and DC
|
||||
- **setmVperAmp(mva)** sets the milliVolt per Ampere measured.
|
||||
- **getmVperAmp()** returns set value.
|
||||
|
||||
|
||||
## Test
|
||||
|
||||
The library is tested with the RobotDyn ACS712 20A breakout and an Arduino UNO.
|
||||
|
||||
|
||||
## Operation
|
||||
|
||||
With the constructor the parameters **volts** and **maxADC (steps)** of the ADC are set
|
||||
@ -41,3 +87,9 @@ To callibrate the noise level (used for AC measurements), 2 functions are availa
|
||||
get and set the noise in mV.
|
||||
|
||||
The examples show the basic working of the functions.
|
||||
|
||||
## Future
|
||||
|
||||
- mA_AC blocks 20 ms so might affect taskscheduling on a ESP32.
|
||||
This needs to be investigated.
|
||||
- int point2point(uint8_t freq) function for AC. Is part of mA_AC() allready.
|
||||
|
141
libraries/ACS712/test/unit_test_001.cpp
Normal file
141
libraries/ACS712/test/unit_test_001.cpp
Normal file
@ -0,0 +1,141 @@
|
||||
//
|
||||
// FILE: unit_test_001.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// DATE: 2020-12-06
|
||||
// PURPOSE: unit tests for the SHT31 temperature and humidity sensor
|
||||
// https://github.com/RobTillaart/SHT31
|
||||
// https://www.adafruit.com/product/2857
|
||||
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
|
||||
//
|
||||
|
||||
// supported assertions
|
||||
// ----------------------------
|
||||
// assertEqual(expected, actual)
|
||||
// assertNotEqual(expected, actual)
|
||||
// assertLess(expected, actual)
|
||||
// assertMore(expected, actual)
|
||||
// assertLessOrEqual(expected, actual)
|
||||
// assertMoreOrEqual(expected, actual)
|
||||
// assertTrue(actual)
|
||||
// assertFalse(actual)
|
||||
// assertNull(actual)
|
||||
|
||||
#include <ArduinoUnitTests.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "ACS712.h"
|
||||
|
||||
#define A0 0
|
||||
|
||||
unittest_setup()
|
||||
{
|
||||
}
|
||||
|
||||
unittest_teardown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unittest(test_mA_DC)
|
||||
{
|
||||
GodmodeState* state = GODMODE();
|
||||
state->reset();
|
||||
|
||||
// 0 == A0
|
||||
ACS712 ACS(0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
|
||||
|
||||
// assertEqual(0, ACS.mA_AC(50));
|
||||
// assertEqual(0, ACS.mA_AC(60));
|
||||
int future[12] = {0, 0, 100, 100, 200, 200, 511, 511, 900, 900, 1023, 1023};
|
||||
state->analogPin[0].fromArray(future, 12);
|
||||
|
||||
assertEqual(-24975, ACS.mA_DC());
|
||||
assertEqual(-20087, ACS.mA_DC());
|
||||
assertEqual(-15200, ACS.mA_DC());
|
||||
assertEqual(0, ACS.mA_DC());
|
||||
assertEqual(19012, ACS.mA_DC());
|
||||
assertEqual(25024, ACS.mA_DC());
|
||||
}
|
||||
|
||||
|
||||
unittest(test_mA_AC)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
|
||||
|
||||
// loop with micros and a lot of analogReads - not possible
|
||||
// assertEqual(0, ACS.mA_AC(50));
|
||||
// assertEqual(0, ACS.mA_AC(60));
|
||||
assertEqual(1, 1);
|
||||
}
|
||||
|
||||
unittest(test_midPoint)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100); // analogPin, volts, maxADC, mVperA
|
||||
|
||||
// loop with micros and a lot of analogReads - not possible
|
||||
// ACS.autoMidPoint(50);
|
||||
// float amp50 = ACS.getMidPoint();
|
||||
// assertEqual(0, amp50);
|
||||
//
|
||||
// ACS.autoMidPoint(60);
|
||||
// float amp60 = ACS.getMidPoint();
|
||||
// assertEqual(0, amp60);
|
||||
|
||||
ACS.setMidPoint(1000);
|
||||
float amp = ACS.getMidPoint();
|
||||
assertEqual(1000, amp);
|
||||
|
||||
ACS.incMidPoint();
|
||||
amp = ACS.getMidPoint();
|
||||
assertEqual(1001, amp);
|
||||
|
||||
ACS.decMidPoint();
|
||||
amp = ACS.getMidPoint();
|
||||
assertEqual(1000, amp);
|
||||
}
|
||||
|
||||
unittest(test_formFactor)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
|
||||
// default 0.5 * sqrt(2)
|
||||
float ff = ACS.getFormFactor();
|
||||
float eff = 0.5 * sqrt(2);
|
||||
float delta = abs(eff - ff);
|
||||
assertMoreOrEqual(0.0001, delta);
|
||||
|
||||
ACS.setFormFactor(0.8);
|
||||
ff = ACS.getFormFactor();
|
||||
eff = 0.8;
|
||||
delta = abs(eff - ff);
|
||||
assertMoreOrEqual(0.0001, delta);
|
||||
}
|
||||
|
||||
unittest(test_Noise)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
|
||||
int nmv = ACS.getNoisemV();
|
||||
assertEqual(21, nmv); // default value..
|
||||
|
||||
ACS.setNoisemV(100);
|
||||
nmv = ACS.getNoisemV();
|
||||
assertEqual(100, nmv);
|
||||
}
|
||||
|
||||
unittest(test_mVperAmp)
|
||||
{
|
||||
ACS712 ACS(A0, 5.0, 1023, 100);
|
||||
|
||||
int mpa = ACS.getmVperAmp();
|
||||
assertEqual(100, mpa); // default value..
|
||||
|
||||
ACS.setmVperAmp(50);
|
||||
mpa = ACS.getmVperAmp();
|
||||
assertEqual(50, mpa);
|
||||
}
|
||||
|
||||
unittest_main()
|
||||
|
||||
// --------
|
7
libraries/AD520X/.arduino-ci.yml
Normal file
7
libraries/AD520X/.arduino-ci.yml
Normal file
@ -0,0 +1,7 @@
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
- uno
|
||||
- leonardo
|
||||
- due
|
||||
- zero
|
13
libraries/AD520X/.github/workflows/arduino_test_runner.yml
vendored
Normal file
13
libraries/AD520X/.github/workflows/arduino_test_runner.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: Arduino CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
arduino_ci:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Arduino-CI/action@master
|
||||
# Arduino-CI/action@v0.1.1
|
148
libraries/AD520X/AD520X.cpp
Normal file
148
libraries/AD520X/AD520X.cpp
Normal file
@ -0,0 +1,148 @@
|
||||
//
|
||||
// FILE: AD520X.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2020-07-24
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: Arduino library for AD5204 and AD5206 digital potentiometers (+ older AD8400, AD8402, AD8403)
|
||||
// URL: https://github.com/RobTillaart/AD520X
|
||||
//
|
||||
// HISTORY:
|
||||
// 0.0.1 2020-07-24 initial version
|
||||
// 0.0.2 2020-07-25 support for AD8400 series in documentation.
|
||||
// 0.1.0 2020-07-26 refactor, fix #2 select pin for HW SPI; add shutdown.
|
||||
// 0.1.1 2020-12-08 Arduino-CI + unit test + isPowerOn()
|
||||
|
||||
|
||||
#include "AD520X.h"
|
||||
|
||||
|
||||
AD520X::AD520X(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut, uint8_t clock)
|
||||
{
|
||||
_pmCount = 6;
|
||||
_select = select;
|
||||
_data = dataOut;
|
||||
_clock = clock;
|
||||
_reset = reset;
|
||||
_shutdown = shutdown;
|
||||
_hwSPI = (dataOut == 255) && (clock == 255);
|
||||
}
|
||||
|
||||
// initializes the pins and starts SPI in case of hardware SPI
|
||||
void AD520X::begin(uint8_t value)
|
||||
{
|
||||
pinMode(_select, OUTPUT);
|
||||
digitalWrite(_select, HIGH);
|
||||
pinMode(_reset, OUTPUT);
|
||||
digitalWrite(_reset, LOW);
|
||||
pinMode(_shutdown, OUTPUT);
|
||||
digitalWrite(_shutdown, LOW);
|
||||
|
||||
if(_hwSPI)
|
||||
{
|
||||
SPI.begin();
|
||||
delay(1);
|
||||
}
|
||||
else
|
||||
{
|
||||
pinMode(_data, OUTPUT);
|
||||
pinMode(_clock, OUTPUT);
|
||||
digitalWrite(_data, LOW);
|
||||
digitalWrite(_clock, LOW);
|
||||
}
|
||||
|
||||
setAll(value);
|
||||
}
|
||||
|
||||
void AD520X::setValue(uint8_t pm, uint8_t value)
|
||||
{
|
||||
if (pm >= _pmCount) return;
|
||||
_value[pm] = value;
|
||||
updateDevice(pm);
|
||||
}
|
||||
|
||||
void AD520X::setAll(uint8_t value)
|
||||
{
|
||||
for (uint8_t pm = 0; pm < _pmCount; pm++)
|
||||
{
|
||||
setValue(pm, value);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t AD520X::getValue(uint8_t pm)
|
||||
{
|
||||
if (pm >= _pmCount) return 0;
|
||||
return _value[pm];
|
||||
}
|
||||
|
||||
void AD520X::reset(uint8_t value)
|
||||
{
|
||||
digitalWrite(_reset, HIGH);
|
||||
digitalWrite(_reset, LOW);
|
||||
setAll(value);
|
||||
}
|
||||
|
||||
void AD520X::updateDevice(uint8_t pm)
|
||||
{
|
||||
if (_hwSPI)
|
||||
{
|
||||
SPI.beginTransaction(SPISettings(16000000, MSBFIRST, SPI_MODE1));
|
||||
digitalWrite(_select, LOW);
|
||||
SPI.transfer(pm);
|
||||
SPI.transfer(_value[pm]);
|
||||
digitalWrite(_select, HIGH);
|
||||
SPI.endTransaction();
|
||||
}
|
||||
else // Software SPI
|
||||
{
|
||||
digitalWrite(_select, LOW);
|
||||
swSPI_transfer(pm);
|
||||
swSPI_transfer(_value[pm]);
|
||||
digitalWrite(_select, HIGH);
|
||||
}
|
||||
}
|
||||
|
||||
// simple one mode version
|
||||
void AD520X::swSPI_transfer(uint8_t value)
|
||||
{
|
||||
for (uint8_t mask = 0x80; mask; mask >>= 1)
|
||||
{
|
||||
digitalWrite(_data,(value & mask) != 0);
|
||||
digitalWrite(_clock, HIGH);
|
||||
digitalWrite(_clock, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
AD5206::AD5206(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut, uint8_t clock)
|
||||
: AD520X(select, reset, shutdown, dataOut, clock)
|
||||
{
|
||||
_pmCount = 6;
|
||||
}
|
||||
|
||||
AD5204::AD5204(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut, uint8_t clock)
|
||||
: AD520X(select, reset, shutdown, dataOut, clock)
|
||||
{
|
||||
_pmCount = 4;
|
||||
}
|
||||
|
||||
AD8403::AD8403(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut, uint8_t clock)
|
||||
: AD520X(select, reset, shutdown, dataOut, clock)
|
||||
{
|
||||
_pmCount = 4;
|
||||
}
|
||||
|
||||
AD8402::AD8402(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut, uint8_t clock)
|
||||
: AD520X(select, reset, shutdown, dataOut, clock)
|
||||
{
|
||||
_pmCount = 2;
|
||||
}
|
||||
|
||||
AD8400::AD8400(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut, uint8_t clock)
|
||||
: AD520X(select, reset, shutdown, dataOut, clock)
|
||||
{
|
||||
_pmCount = 1;
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
85
libraries/AD520X/AD520X.h
Normal file
85
libraries/AD520X/AD520X.h
Normal file
@ -0,0 +1,85 @@
|
||||
#pragma once
|
||||
//
|
||||
// FILE: AD520X.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2020-07-24
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: Arduino library for AD5204 and AD5206 digital potentiometers (+ older AD8400, AD8402, AD8403)
|
||||
// URL: https://github.com/RobTillaart/AD520X
|
||||
//
|
||||
// HISTORY:
|
||||
// see AD520X.cpp file
|
||||
//
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SPI.h"
|
||||
|
||||
#define AD520X_LIB_VERSION "0.1.1"
|
||||
|
||||
class AD520X
|
||||
{
|
||||
public:
|
||||
AD520X(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut, uint8_t clock);
|
||||
|
||||
void begin(uint8_t value = 128);
|
||||
void setValue(uint8_t pm, uint8_t value);
|
||||
void setAll(uint8_t value);
|
||||
uint8_t getValue(uint8_t pm);
|
||||
|
||||
void reset(uint8_t value = 128);
|
||||
int pmCount() { return _pmCount; };
|
||||
|
||||
void powerOn() { digitalWrite(_shutdown, LOW); };
|
||||
void powerOff() { digitalWrite(_shutdown, HIGH); };
|
||||
void powerDown() { powerOff(); }; // will become obsolete
|
||||
bool isPowerOn() { return digitalRead(_shutdown) == LOW; };
|
||||
|
||||
|
||||
protected:
|
||||
uint8_t _data;
|
||||
uint8_t _clock;
|
||||
uint8_t _select;
|
||||
uint8_t _reset;
|
||||
uint8_t _shutdown;
|
||||
bool _hwSPI = 3;
|
||||
uint8_t _value[6];
|
||||
uint8_t _pmCount = 6;
|
||||
|
||||
void updateDevice(uint8_t pm);
|
||||
void swSPI_transfer(uint8_t value);
|
||||
};
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class AD5206 : public AD520X
|
||||
{
|
||||
public:
|
||||
AD5206(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut = 255, uint8_t clock = 255);
|
||||
};
|
||||
|
||||
class AD5204 : public AD520X
|
||||
{
|
||||
public:
|
||||
AD5204(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut = 255, uint8_t clock = 255);
|
||||
};
|
||||
|
||||
class AD8400 : public AD520X
|
||||
{
|
||||
public:
|
||||
AD8400(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut = 255, uint8_t clock = 255);
|
||||
};
|
||||
|
||||
class AD8402 : public AD520X
|
||||
{
|
||||
public:
|
||||
AD8402(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut = 255, uint8_t clock = 255);
|
||||
};
|
||||
|
||||
class AD8403 : public AD520X
|
||||
{
|
||||
public:
|
||||
AD8403(uint8_t select, uint8_t reset, uint8_t shutdown, uint8_t dataOut = 255, uint8_t clock = 255);
|
||||
};
|
||||
|
||||
// -- END OF FILE --
|
21
libraries/AD520X/LICENSE
Normal file
21
libraries/AD520X/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2020-2021 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
74
libraries/AD520X/README.md
Normal file
74
libraries/AD520X/README.md
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
[![Arduino CI](https://github.com/RobTillaart/AD520X/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
||||
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/AD520X/blob/master/LICENSE)
|
||||
[![GitHub release](https://img.shields.io/github/release/RobTillaart/AD520X.svg?maxAge=3600)](https://github.com/RobTillaart/AD520X/releases)
|
||||
|
||||
# AD520X
|
||||
|
||||
Arduino library for SPI AD5204 and AD5206 digital potentiometers
|
||||
|
||||
## Description
|
||||
|
||||
The library is still experimental as not all functionality is tested (enough).
|
||||
|
||||
The **AD5204** (4 pm) and **AD5206** (6 pm) are SPI based digital potentiometers.
|
||||
This library consists of a base class **AD520X** that does the work.
|
||||
|
||||
The interface is straightforward, one can set a value per pm between 0..255.
|
||||
|
||||
_Although not tested this library should work for the older **AD8400** (1 pm),
|
||||
the **AD8402** (2 pm) and **AD8403** (4 pm) as the interface is very similar
|
||||
(datasheet comparison). If you can confirm it works, please let me know._
|
||||
|
||||
## Interface
|
||||
|
||||
|
||||
### Constructors
|
||||
|
||||
- **AD520X(select, reset, shutdown, dataOut = 255, clock = 255)** constructor
|
||||
Base class, not to be used directly.
|
||||
If dataOut and clock are set to 255 (default) it uses hardware SPI.
|
||||
If dataOut and clock are set to another (valid) value) it uses software SPI.
|
||||
reset and shutdown may be set to 255 too, which effectively disables them.
|
||||
Note: hardware SPI is 10+ times faster on an UNO.
|
||||
- **AD5204(select, reset, shutdown, dataOut = 255, clock = 255)** uses 4 pm.
|
||||
- **AD5206(select, reset, shutdown, dataOut = 255, clock = 255)** uses 6 pm.
|
||||
- **AD8400(select, reset, shutdown, dataOut = 255, clock = 255)** uses 1 pm.
|
||||
- **AD8402(select, reset, shutdown, dataOut = 255, clock = 255)** uses 2 pm.
|
||||
- **AD8403(select, reset, shutdown, dataOut = 255, clock = 255)** uses 4 pm.
|
||||
|
||||
### Base
|
||||
- **begin(value = 128)** value is the initial value of all potentiometer.
|
||||
- **setValue(pm, value)** set a potentiometer to a value
|
||||
- **setAll(value)** set all potentiometers to the same value e.g. 0 or max or mid
|
||||
- **getValue(pm)** returns the last set value of a specific potmeter
|
||||
- **reset(value = 128)** resets all potentiometers to value, default 128.
|
||||
|
||||
### Misc
|
||||
- **pmCount()** returns the number of internal potmeters.
|
||||
- **powerOn()** switches the module on
|
||||
- **powerOff()** switches the module off
|
||||
- **powerDown()** use powerOFf() instead
|
||||
- **isPowerOn()** returns true if on (default) or
|
||||
|
||||
## Future
|
||||
|
||||
- **setInvert(pm)** invert flag per potmeter
|
||||
- 0..255 -> 255..0
|
||||
- 1 uint8_t can hold 8 flags
|
||||
- **getInvert(pm)**
|
||||
|
||||
- **follow(pm_B, pm_A, percentage = 100)**
|
||||
- makes pm_B follow pm_A unless pm_B is addressed explicitly
|
||||
- array cascade = 0xFF or pm_A.
|
||||
- It will follow pm_A for certain percentage default 100.
|
||||
|
||||
- **setPercentage(pm, float value)** 0..100%
|
||||
- **getPercentage(pm)**
|
||||
- logarithmic effect? setGamma(pm, value);
|
||||
easier with setPercentage()
|
||||
|
||||
|
||||
## Operations
|
||||
|
||||
See examples.
|
114
libraries/AD520X/examples/AD5204_demo/AD5204_demo.ino
Normal file
114
libraries/AD520X/examples/AD5204_demo/AD5204_demo.ino
Normal file
@ -0,0 +1,114 @@
|
||||
//
|
||||
// FILE: AD5204_demo.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: demo
|
||||
// DATE: 2020-07-24
|
||||
// URL: https://github.com/RobTillaart/AD520X
|
||||
|
||||
#include "AD520X.h"
|
||||
|
||||
uint32_t start, stop;
|
||||
|
||||
#define TWOPI (3.14159265 * 2)
|
||||
|
||||
// select, reset, shutdown, data, clock
|
||||
// AD5204 pot(10, 255, 255, 8, 9); // SW SPI
|
||||
AD5204 pot = AD5204(10, 12, 13); // HW SPI
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
|
||||
pot.begin(4);
|
||||
|
||||
test_sinus();
|
||||
test_sawtooth();
|
||||
test_timing();
|
||||
|
||||
Serial.println("\nDone...");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
// connect all A GND and B 5V
|
||||
// every W will have a different signal (same freq).
|
||||
void test_sinus()
|
||||
{
|
||||
Serial.println(__FUNCTION__);
|
||||
delay(10);
|
||||
|
||||
start = millis();
|
||||
uint32_t i = 0;
|
||||
while (millis() - start < 10000)
|
||||
{
|
||||
uint8_t value = 127 * sin(i * TWOPI / 100);
|
||||
pot.setValue(0, 128 + value);
|
||||
pot.setValue(1, 128 + value / 2);
|
||||
pot.setValue(2, 64 + value / 2);
|
||||
pot.setValue(3, 192 + value / 2);
|
||||
pot.setValue(4, 224 + value / 4);
|
||||
pot.setValue(5, 128 - value);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
// straightforward sawtooth.
|
||||
void test_sawtooth()
|
||||
{
|
||||
Serial.println(__FUNCTION__);
|
||||
delay(10);
|
||||
|
||||
start = millis();
|
||||
uint8_t i = 0;
|
||||
while (millis() - start < 10000)
|
||||
{
|
||||
pot.setValue(0, i++); // autowrap is fast...
|
||||
}
|
||||
}
|
||||
|
||||
void test_timing()
|
||||
{
|
||||
Serial.println(__FUNCTION__);
|
||||
delay(10);
|
||||
|
||||
start = micros();
|
||||
for (int i = 0; i < 10000; i++)
|
||||
{
|
||||
pot.setValue(0, i++); // autowrap is fast...
|
||||
}
|
||||
stop = micros();
|
||||
Serial.print("10000 x setValue():\t");
|
||||
Serial.println(stop - start);
|
||||
delay(10);
|
||||
|
||||
start = micros();
|
||||
for (int i = 0; i < 1000; i++)
|
||||
{
|
||||
pot.setAll(i++);
|
||||
}
|
||||
stop = micros();
|
||||
Serial.print("1000 x setAll():\t");
|
||||
Serial.println(stop - start);
|
||||
delay(10);
|
||||
|
||||
volatile int x = 0;
|
||||
start = micros();
|
||||
for (int i = 0; i < 250; i++)
|
||||
{
|
||||
x += pot.getValue(0);
|
||||
x += pot.getValue(1);
|
||||
x += pot.getValue(2);
|
||||
x += pot.getValue(3);
|
||||
}
|
||||
stop = micros();
|
||||
Serial.print("1000 x getValue():\t");
|
||||
Serial.println(stop - start);
|
||||
delay(10);
|
||||
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
24
libraries/AD520X/keywords.txt
Normal file
24
libraries/AD520X/keywords.txt
Normal file
@ -0,0 +1,24 @@
|
||||
# Syntax Coloring Map For AD520X
|
||||
|
||||
# Datatypes (KEYWORD1)
|
||||
AD520X KEYWORD1
|
||||
AD5204 KEYWORD1
|
||||
AD5206 KEYWORD1
|
||||
AD8400 KEYWORD1
|
||||
AD8402 KEYWORD1
|
||||
AD8403 KEYWORD1
|
||||
|
||||
# Methods and Functions (KEYWORD2)
|
||||
begin KEYWORD2
|
||||
setValue KEYWORD2
|
||||
setAll KEYWORD2
|
||||
getValue KEYWORD2
|
||||
reset KEYWORD2
|
||||
powerOn KEYWORD2
|
||||
powerOff KEYWORD2
|
||||
powerDown KEYWORD2
|
||||
isPowerOn KEYWORD2
|
||||
pmCount KEYWORD2
|
||||
|
||||
# Constants (LITERAL1)
|
||||
AD520X_LIB_VERSION LITERAL1
|
21
libraries/AD520X/library.json
Normal file
21
libraries/AD520X/library.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "AD520X",
|
||||
"keywords": "AD520X, SPI, AD5204, AD5206, AD8400, AD8402, AD8403, potentiometers",
|
||||
"description": "Arduino library for SPI AD5204 and AD5206 digital potentiometers",
|
||||
"authors":
|
||||
[
|
||||
{
|
||||
"name": "Rob Tillaart",
|
||||
"email": "Rob.Tillaart@gmail.com",
|
||||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/AD520X.git"
|
||||
},
|
||||
"version":"0.1.1",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*"
|
||||
}
|
11
libraries/AD520X/library.properties
Normal file
11
libraries/AD520X/library.properties
Normal file
@ -0,0 +1,11 @@
|
||||
name=AD520X
|
||||
version=0.1.1
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino library for SPI AD5204 and AD5206 digital potentiometers
|
||||
paragraph=Not tested but should work for AD8400, AD8402 and AD8403.
|
||||
category=Sensors
|
||||
url=https://github.com/RobTillaart/AD520X
|
||||
architectures=*
|
||||
includes=AD520X.h
|
||||
depends=
|
126
libraries/AD520X/test/unit_test_001.cpp
Normal file
126
libraries/AD520X/test/unit_test_001.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
//
|
||||
// FILE: unit_test_001.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// DATE: 2020-12-08
|
||||
// PURPOSE: unit tests for the AD520X digital potentiometers
|
||||
// https://github.com/RobTillaart/AD520X
|
||||
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
|
||||
//
|
||||
|
||||
// supported assertions
|
||||
// ----------------------------
|
||||
// assertEqual(expected, actual)
|
||||
// assertNotEqual(expected, actual)
|
||||
// assertLess(expected, actual)
|
||||
// assertMore(expected, actual)
|
||||
// assertLessOrEqual(expected, actual)
|
||||
// assertMoreOrEqual(expected, actual)
|
||||
// assertTrue(actual)
|
||||
// assertFalse(actual)
|
||||
// assertNull(actual)
|
||||
|
||||
#include <ArduinoUnitTests.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "AD520X.h"
|
||||
|
||||
|
||||
unittest_setup()
|
||||
{
|
||||
}
|
||||
|
||||
unittest_teardown()
|
||||
{
|
||||
}
|
||||
|
||||
unittest(test_begin)
|
||||
{
|
||||
AD5204 pot = AD5204(10, 12, 13); // HW SPI
|
||||
pot.begin();
|
||||
assertEqual(128, pot.getValue(0));
|
||||
|
||||
pot.begin(42);
|
||||
assertEqual(42, pot.getValue(0));
|
||||
}
|
||||
|
||||
unittest(test_setValue)
|
||||
{
|
||||
AD5206 pot = AD5206(10, 12, 13); // HW SPI
|
||||
pot.begin();
|
||||
assertEqual(128, pot.getValue(0));
|
||||
|
||||
for (int i = 0; i < pot.pmCount(); i++)
|
||||
{
|
||||
pot.setValue(i, 35);
|
||||
assertEqual(35, pot.getValue(i));
|
||||
}
|
||||
|
||||
pot.setAll(42);
|
||||
for (int i = 0; i < pot.pmCount(); i++)
|
||||
{
|
||||
assertEqual(42, pot.getValue(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest(test_reset)
|
||||
{
|
||||
AD5204 pot = AD5204(10, 12, 13); // HW SPI
|
||||
pot.begin();
|
||||
assertEqual(128, pot.getValue(0));
|
||||
|
||||
pot.reset(35);
|
||||
assertEqual(35, pot.getValue(0));
|
||||
}
|
||||
|
||||
|
||||
unittest(test_power)
|
||||
{
|
||||
AD5204 pot = AD5204(10, 12, 13); // HW SPI
|
||||
pot.begin(213);
|
||||
assertEqual(213, pot.getValue(0));
|
||||
assertTrue(pot.isPowerOn());
|
||||
|
||||
pot.powerOff();
|
||||
assertFalse(pot.isPowerOn());
|
||||
delay(100);
|
||||
|
||||
pot.powerOn();
|
||||
assertTrue(pot.isPowerOn());
|
||||
delay(100);
|
||||
|
||||
for (int i = 0; i < pot.pmCount(); i++)
|
||||
{
|
||||
assertEqual(213, pot.getValue(i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest(test_pm_count)
|
||||
{
|
||||
AD5204 pot1 = AD5204(10, 12, 13); // HW SPI
|
||||
pot1.begin();
|
||||
assertEqual(4, pot1.pmCount());
|
||||
|
||||
AD5206 pot2 = AD5206(10, 12, 13); // HW SPI
|
||||
pot2.begin();
|
||||
assertEqual(6, pot2.pmCount());
|
||||
|
||||
AD8403 pot3 = AD8403(10, 12, 13); // HW SPI
|
||||
pot3.begin();
|
||||
assertEqual(4, pot3.pmCount());
|
||||
|
||||
AD8402 pot4 = AD8402(10, 12, 13); // HW SPI
|
||||
pot4.begin();
|
||||
assertEqual(2, pot4.pmCount());
|
||||
|
||||
AD8400 pot5 = AD8400(10, 12, 13); // HW SPI
|
||||
pot5.begin();
|
||||
assertEqual(1, pot5.pmCount());
|
||||
}
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
// --------
|
7
libraries/AD524X/.arduino-ci.yml
Normal file
7
libraries/AD524X/.arduino-ci.yml
Normal file
@ -0,0 +1,7 @@
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
- uno
|
||||
- leonardo
|
||||
- due
|
||||
- zero
|
13
libraries/AD524X/.github/workflows/arduino_test_runner.yml
vendored
Normal file
13
libraries/AD524X/.github/workflows/arduino_test_runner.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: Arduino CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
arduino_ci:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Arduino-CI/action@master
|
||||
# Arduino-CI/action@v0.1.1
|
@ -1,7 +1,7 @@
|
||||
//
|
||||
// FILE: AD524X.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.1
|
||||
// VERSION: 0.3.1
|
||||
// PURPOSE: I2C digital potentiometer AD5241 AD5242
|
||||
// DATE: 2013-10-12
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
@ -16,98 +16,143 @@
|
||||
#define AS524X_O1_HIGH 0x10
|
||||
#define AS524X_O2_HIGH 0x08
|
||||
|
||||
AD524X::AD524X(const uint8_t address)
|
||||
|
||||
AD524X::AD524X(const uint8_t address, TwoWire *wire)
|
||||
{
|
||||
// address: 0x01011xx = 0x2C - 0x2F
|
||||
_address = address;
|
||||
_lastValue[0] = _lastValue[1] = 127; // power on reset => mid position
|
||||
_O1 = _O2 = 0;
|
||||
// address: 0x01011xx = 0x2C - 0x2F
|
||||
_address = address;
|
||||
_wire = wire;
|
||||
_lastValue[0] = _lastValue[1] = 127; // power on reset => mid position
|
||||
_O1 = _O2 = 0;
|
||||
_pmCount = 2;
|
||||
}
|
||||
|
||||
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
bool AD524X::begin(uint8_t dataPin, uint8_t clockPin)
|
||||
{
|
||||
_wire = &Wire;
|
||||
if ((dataPin < 255) && (clockPin < 255))
|
||||
{
|
||||
_wire->begin(dataPin, clockPin);
|
||||
} else {
|
||||
_wire->begin();
|
||||
}
|
||||
if (! isConnected()) return false;
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
bool AD524X::begin()
|
||||
{
|
||||
_wire->begin();
|
||||
if (! isConnected()) return false;
|
||||
reset();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool AD524X::isConnected()
|
||||
{
|
||||
_wire->beginTransmission(_address);
|
||||
return ( _wire->endTransmission() == 0);
|
||||
}
|
||||
|
||||
|
||||
uint8_t AD524X::reset()
|
||||
{
|
||||
write(0, 127, LOW, LOW);
|
||||
return write(1, 127);
|
||||
}
|
||||
|
||||
|
||||
uint8_t AD524X::zeroAll()
|
||||
{
|
||||
write(0, 0, LOW, LOW);
|
||||
return write(1, 0);
|
||||
write(0, 0, LOW, LOW);
|
||||
return write(1, 0);
|
||||
}
|
||||
|
||||
uint8_t AD524X::write(const uint8_t rdac, const uint8_t value)
|
||||
{
|
||||
if (rdac > 1) return AS524X_ERROR;
|
||||
if (rdac >= _pmCount) return AS524X_ERROR;
|
||||
|
||||
uint8_t cmd = (rdac == 0) ? AS524X_RDAC0 : AS524X_RDAC1;
|
||||
// apply the output lines
|
||||
cmd = cmd | _O1 | _O2;
|
||||
_lastValue[rdac] = value;
|
||||
return send(cmd, value);
|
||||
uint8_t cmd = (rdac == 0) ? AS524X_RDAC0 : AS524X_RDAC1;
|
||||
// apply the output lines
|
||||
cmd = cmd | _O1 | _O2;
|
||||
_lastValue[rdac] = value;
|
||||
return send(cmd, value);
|
||||
}
|
||||
|
||||
uint8_t AD524X::write(const uint8_t rdac, const uint8_t value, const uint8_t O1, const uint8_t O2)
|
||||
{
|
||||
if (rdac > 1) return AS524X_ERROR;
|
||||
if (rdac >= _pmCount) return AS524X_ERROR;
|
||||
|
||||
uint8_t cmd = (rdac == 0) ? AS524X_RDAC0 : AS524X_RDAC1;
|
||||
_O1 = (O1 == LOW) ? 0 : AS524X_O1_HIGH;
|
||||
_O2 = (O2 == LOW) ? 0 : AS524X_O2_HIGH;
|
||||
// apply the output lines
|
||||
cmd = cmd | _O1 | _O2;
|
||||
_lastValue[rdac] = value;
|
||||
return send(cmd, value);
|
||||
uint8_t cmd = (rdac == 0) ? AS524X_RDAC0 : AS524X_RDAC1;
|
||||
_O1 = (O1 == LOW) ? 0 : AS524X_O1_HIGH;
|
||||
_O2 = (O2 == LOW) ? 0 : AS524X_O2_HIGH;
|
||||
// apply the output lines
|
||||
cmd = cmd | _O1 | _O2;
|
||||
_lastValue[rdac] = value;
|
||||
return send(cmd, value);
|
||||
}
|
||||
|
||||
uint8_t AD524X::setO1(const uint8_t value)
|
||||
{
|
||||
_O1 = (value == LOW) ? 0 : AS524X_O1_HIGH;
|
||||
uint8_t cmd = AS524X_RDAC0 | _O1 | _O2;
|
||||
return send(cmd, _lastValue[0]);
|
||||
_O1 = (value == LOW) ? 0 : AS524X_O1_HIGH;
|
||||
uint8_t cmd = AS524X_RDAC0 | _O1 | _O2;
|
||||
return send(cmd, _lastValue[0]);
|
||||
}
|
||||
|
||||
uint8_t AD524X::setO2(const uint8_t value)
|
||||
{
|
||||
_O2 = (value == LOW) ? 0: AS524X_O2_HIGH;
|
||||
uint8_t cmd = AS524X_RDAC0 | _O1 | _O2;
|
||||
return send(cmd, _lastValue[0]);
|
||||
_O2 = (value == LOW) ? 0: AS524X_O2_HIGH;
|
||||
uint8_t cmd = AS524X_RDAC0 | _O1 | _O2;
|
||||
return send(cmd, _lastValue[0]);
|
||||
}
|
||||
|
||||
uint8_t AD524X::getO1()
|
||||
{
|
||||
return (_O1 > 0);
|
||||
return (_O1 > 0);
|
||||
}
|
||||
|
||||
uint8_t AD524X::getO2()
|
||||
{
|
||||
return (_O2 > 0);
|
||||
return (_O2 > 0);
|
||||
}
|
||||
|
||||
uint8_t AD524X::read(const uint8_t rdac)
|
||||
{
|
||||
return _lastValue[rdac];
|
||||
return _lastValue[rdac];
|
||||
}
|
||||
|
||||
uint8_t AD524X::readBackRegister()
|
||||
{
|
||||
Wire.beginTransmission(_address);
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom(_address, (uint8_t)1);
|
||||
return Wire.read();
|
||||
Wire.beginTransmission(_address);
|
||||
Wire.endTransmission();
|
||||
Wire.requestFrom(_address, (uint8_t)1);
|
||||
return Wire.read();
|
||||
}
|
||||
|
||||
uint8_t AD524X::midScaleReset(const uint8_t rdac)
|
||||
{
|
||||
if (rdac > 1) return AS524X_ERROR;
|
||||
if (rdac >= _pmCount) return AS524X_ERROR;
|
||||
|
||||
uint8_t cmd = AS524X_RESET;
|
||||
if (rdac == 1) cmd |= AS524X_RDAC1;
|
||||
cmd = cmd | _O1 | _O2;
|
||||
_lastValue[rdac] = 127;
|
||||
return send(cmd, _lastValue[rdac]);
|
||||
uint8_t cmd = AS524X_RESET;
|
||||
if (rdac == 1) cmd |= AS524X_RDAC1;
|
||||
cmd = cmd | _O1 | _O2;
|
||||
_lastValue[rdac] = 127;
|
||||
return send(cmd, _lastValue[rdac]);
|
||||
}
|
||||
|
||||
// read datasheet P.15
|
||||
uint8_t AD524X::shutDown()
|
||||
{
|
||||
uint8_t cmd = AS524X_SHUTDOWN; // TODO TEST & VERIFY
|
||||
return send(cmd, 0);
|
||||
}
|
||||
|
||||
// TODO read datasheet
|
||||
// uint8_t AD524X::shutDown()
|
||||
// {
|
||||
// uint8_t cmd = AS524X_SHUTDOWN;
|
||||
// sendCommand(cmd, 0)
|
||||
// }
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
//
|
||||
@ -115,10 +160,23 @@ uint8_t AD524X::midScaleReset(const uint8_t rdac)
|
||||
//
|
||||
uint8_t AD524X::send(const uint8_t cmd, const uint8_t value)
|
||||
{
|
||||
Wire.beginTransmission(_address);
|
||||
Wire.write(cmd);
|
||||
Wire.write(value);
|
||||
return Wire.endTransmission();
|
||||
Wire.beginTransmission(_address);
|
||||
Wire.write(cmd);
|
||||
Wire.write(value);
|
||||
return Wire.endTransmission();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
AD5241::AD5241(const uint8_t address, TwoWire *wire) : AD524X(address, wire)
|
||||
{
|
||||
_pmCount = 1;
|
||||
};
|
||||
|
||||
AD5242::AD5242(const uint8_t address, TwoWire *wire) : AD524X(address, wire)
|
||||
{
|
||||
_pmCount = 2;
|
||||
};
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// FILE: AD524X.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.1
|
||||
// VERSION: 0.3.1
|
||||
// PURPOSE: I2C digital PotentioMeter AD5241 AD5242
|
||||
// DATE: 2013-10-12
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
@ -11,45 +11,73 @@
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
|
||||
#define AD524X_VERSION "0.2.1"
|
||||
|
||||
#define AS524X_OK 0
|
||||
#define AS524X_ERROR 100
|
||||
#define AD524X_VERSION (F("0.3.1"))
|
||||
|
||||
|
||||
#define AS524X_OK 0
|
||||
#define AS524X_ERROR 100
|
||||
|
||||
|
||||
class AD524X
|
||||
{
|
||||
public:
|
||||
// address
|
||||
explicit AD524X(const uint8_t);
|
||||
explicit AD524X(const uint8_t address, TwoWire *wire = &Wire);
|
||||
|
||||
uint8_t zeroAll();
|
||||
// rdac
|
||||
uint8_t read(const uint8_t);
|
||||
// for debugging
|
||||
uint8_t readBackRegister(); // returns the last value written in register.
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
bool begin(uint8_t sda, uint8_t scl);
|
||||
#endif
|
||||
bool begin();
|
||||
bool isConnected();
|
||||
|
||||
uint8_t reset(); // reset both channels to 127 and O1/O2 to LOW
|
||||
uint8_t zeroAll(); // set both channels to 0 and O1/O2 to LOW
|
||||
|
||||
// rdac value
|
||||
uint8_t write(const uint8_t, const uint8_t);
|
||||
// rdac value O1 O2
|
||||
uint8_t write(const uint8_t, const uint8_t, const uint8_t, const uint8_t);
|
||||
uint8_t read(const uint8_t rdac);
|
||||
uint8_t write(const uint8_t rdac, const uint8_t value);
|
||||
uint8_t write(const uint8_t rdac, const uint8_t value, const uint8_t O1, const uint8_t O2);
|
||||
|
||||
uint8_t setO1(const uint8_t); // HIGH / LOW
|
||||
uint8_t setO2(const uint8_t); // HIGH / LOW
|
||||
uint8_t getO1();
|
||||
uint8_t getO2();
|
||||
uint8_t setO1(const uint8_t value = HIGH); // HIGH (default) / LOW
|
||||
uint8_t setO2(const uint8_t value = HIGH); // HIGH (default) / LOW
|
||||
uint8_t getO1();
|
||||
uint8_t getO2();
|
||||
|
||||
// rdac
|
||||
uint8_t midScaleReset(const uint8_t);
|
||||
//
|
||||
// uint8_t shutDown();
|
||||
uint8_t midScaleReset(const uint8_t rdac);
|
||||
uint8_t pmCount() { return _pmCount; };
|
||||
|
||||
// debugging
|
||||
uint8_t readBackRegister(); // returns the last value written in register.
|
||||
|
||||
// experimental - to be tested - use at own risk
|
||||
uint8_t shutDown(); // datasheet P15
|
||||
|
||||
protected:
|
||||
uint8_t _pmCount = 0;
|
||||
|
||||
private:
|
||||
uint8_t send(const uint8_t, const uint8_t); // cmd value
|
||||
uint8_t send(const uint8_t, const uint8_t); // cmd value
|
||||
|
||||
uint8_t _address;
|
||||
uint8_t _lastValue[2];
|
||||
uint8_t _O1;
|
||||
uint8_t _O2;
|
||||
uint8_t _address;
|
||||
uint8_t _lastValue[2];
|
||||
uint8_t _O1;
|
||||
uint8_t _O2;
|
||||
|
||||
TwoWire* _wire;
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
class AD5241 : public AD524X
|
||||
{
|
||||
public:
|
||||
AD5241(const uint8_t address, TwoWire *wire = &Wire);
|
||||
};
|
||||
|
||||
class AD5242 : public AD524X
|
||||
{
|
||||
public:
|
||||
AD5242(const uint8_t address, TwoWire *wire = &Wire);
|
||||
};
|
||||
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013 - 2020 Rob Tillaart
|
||||
Copyright (c) 2013 - 2021 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,6 +1,12 @@
|
||||
|
||||
[![Arduino CI](https://github.com/RobTillaart/AD524X/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
||||
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/AD524X/blob/master/LICENSE)
|
||||
[![GitHub release](https://img.shields.io/github/release/RobTillaart/AD524X.svg?maxAge=3600)](https://github.com/RobTillaart/AD524X/releases)
|
||||
|
||||
|
||||
# AD524X
|
||||
|
||||
I2C digital potentiometer AD5241 AD5242
|
||||
Arduino class for I2C digital potentiometer AD5241 AD5242
|
||||
|
||||
## Description
|
||||
|
||||
@ -14,30 +20,66 @@ and can be set in 256 steps.
|
||||
An important property of the devices is that they defaults
|
||||
to their mid position at startup.
|
||||
|
||||
|
||||
## I2C address
|
||||
The AD524X has two address lines to configure the I2C address.
|
||||
|
||||
The range is: 0x01011**YX** = 0x2C - 0x2F
|
||||
The AD524X has two address lines to configure the I2C address.0x2C - 0x2F
|
||||
|
||||
| Addr(dec)| Addr(Hex) | AD0 | AD1 |
|
||||
|:----:|:------:|:----:|:----:|
|
||||
| 44 | 0x2C | GND | GND |
|
||||
| 45 | 0x2D | GND | +5V |
|
||||
| 46 | 0x2E | +5V | GND |
|
||||
| 47 | 0x2F | +5V | +5V |
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
The library has a number of functions which are all quite straightforward.
|
||||
One can get / set the value of (both) the potentiometer(s), and the O1 and O2 lines.
|
||||
|
||||
|
||||
### Constructors
|
||||
|
||||
- **AD524X(uint8_t address, TwoWire \*wire = &Wire)** base class,
|
||||
creates an instance with 2 potentiometer.
|
||||
This class does not distinguish between AD5241 and AD5242.
|
||||
The developer is responsible for handling this correctly.
|
||||
- **AD5241(uint8_t address, TwoWire \*wire = &Wire)** create an instance with 1 potentiometer
|
||||
- **AD5242(uint8_t address, TwoWire \*wire = &Wire)** create an instance with 2 potentiometer
|
||||
|
||||
|
||||
### Wire initialization
|
||||
|
||||
- **bool begin(uint8_t sda, uint8_t scl)** ESP32 a.o initializing of Wire
|
||||
- **bool begin()** for UNO
|
||||
- **bool isConnected()** See if address set in constructor is on the bus.
|
||||
|
||||
|
||||
### Basic IO
|
||||
|
||||
- **uint8_t write(rdac, value)** set channel rdac 0/1 to value 0..255
|
||||
- **uint8_t write(rdac, value, O1, O2)** idem + set output lines O1 and O2 too
|
||||
- **uint8_t read(rdac)** read back set value
|
||||
- **uint8_t setO1(value = HIGH)** value = HIGH (default) or LOW
|
||||
- **uint8_t setO2(value = HIGH)** value = HIGH (default) or LOW
|
||||
- **uint8_t getO1()** read back O1 line
|
||||
- **uint8_t getO2()** read back O2 line
|
||||
|
||||
|
||||
### Misc
|
||||
|
||||
- **uint8_t zeroAll()** sets pm's and I/O to 0 or LOW.
|
||||
- **uint8_t reset()** sets pm's to midpoint = 127 and I/O to LOW. (startup)
|
||||
- **uint8_t midScaleReset(rdac)** resets one to midpoint = 127.
|
||||
- **uint8_t readBackRegister()** read register back, for debugging.
|
||||
|
||||
|
||||
### Experimental
|
||||
|
||||
- **uint8_t shutDown()** check datasheet, not tested yet, use at own risk.
|
||||
|
||||
Where **AD0 = X** and **AD1 = Y**
|
||||
|
||||
## Operation
|
||||
|
||||
The library has a number of functions which are all quite straightforward.
|
||||
One can set the value of (both) the potentiometer(s), and the O1 and O2 lines.
|
||||
|
||||
* **uint8_t write(rdac, value);** value 0..255
|
||||
* **uint8_t write(rdac, value, O1, O2);**
|
||||
* **uint8_t setO1(value);** value = HIGH or LOW
|
||||
* **uint8_t setO2(value);**
|
||||
|
||||
Also one can read the current values
|
||||
|
||||
* **uint8_t read(rdac);**
|
||||
* **uint8_t getO1();**
|
||||
* **uint8_t getO2();**
|
||||
|
||||
Note: the class does not distinguish between AD5241 and AD5242.
|
||||
The developer is responsible for handling this correctly.
|
||||
|
||||
The examples show the basic working of the functions.
|
||||
|
@ -1,28 +1,24 @@
|
||||
//
|
||||
// FILE: AD524X_followA0.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.01
|
||||
// VERSION: 0.1.2
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2013-10-12
|
||||
// URL:
|
||||
//
|
||||
// Released to the public domain
|
||||
//
|
||||
|
||||
#include "AD524X.h"
|
||||
#include "Wire.h"
|
||||
|
||||
AD524X AD01(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print("\nStart AD524X_followA0 : ");
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
Serial.println("Follow Analog A0");
|
||||
|
||||
Wire.begin();
|
||||
TWBR = 72; // 100 KHz
|
||||
Wire.setClock(400000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
@ -41,4 +37,6 @@ void loop()
|
||||
Serial.println(rv);
|
||||
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -0,0 +1,37 @@
|
||||
//
|
||||
// FILE: AD524X_isConnected.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2021-01-27
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
//
|
||||
|
||||
|
||||
#include "AD524X.h"
|
||||
|
||||
AD524X AD01(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000);
|
||||
|
||||
bool b = AD01.begin();
|
||||
Serial.println(b?"true":"false");
|
||||
Serial.println(AD01.isConnected());
|
||||
|
||||
Serial.println("\nDone...");
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -1,27 +1,24 @@
|
||||
//
|
||||
// FILE: AD524X_midScaleReset.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.01
|
||||
// VERSION: 0.1.2
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2013-10-12
|
||||
// URL:
|
||||
//
|
||||
// Released to the public domain
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
//
|
||||
|
||||
#include "AD524X.h"
|
||||
#include "Wire.h"
|
||||
|
||||
AD524X AD01(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print("\nStart AD524X_midScaleReset : ");
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
TWBR = 12; // 400 KHz
|
||||
Wire.setClock(400000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
@ -41,4 +38,6 @@ void loop()
|
||||
Serial.println("reset");
|
||||
AD01.midScaleReset(1);
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -1,27 +1,24 @@
|
||||
//
|
||||
// FILE: AD524X_read.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.01
|
||||
// VERSION: 0.1.2
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2013-10-12
|
||||
// URL:
|
||||
//
|
||||
// Released to the public domain
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
//
|
||||
|
||||
#include "AD524X.h"
|
||||
#include "Wire.h"
|
||||
|
||||
AD524X AD01(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print("\nStart AD524X_read : ");
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
TWBR = 12; // 400 KHz
|
||||
Wire.setClock(400000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
@ -37,4 +34,6 @@ void loop()
|
||||
delay(100);
|
||||
}
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -1,27 +1,24 @@
|
||||
//
|
||||
// FILE: AD524X_readBackRegister.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.00
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2016-04-10
|
||||
// URL:
|
||||
//
|
||||
// Released to the public domain
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
//
|
||||
|
||||
#include "AD524X.h"
|
||||
#include "Wire.h"
|
||||
|
||||
AD524X AD01(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print("\nStart AD524X_readBackRegister : ");
|
||||
Serial.println(AD524X_VERSION);
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
TWBR = 12; // 400 KHz
|
||||
Wire.begin();
|
||||
Wire.setClock(400000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
@ -48,4 +45,6 @@ void test(uint8_t rdac, uint8_t val)
|
||||
Serial.print('\t');
|
||||
Serial.println(y);
|
||||
delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -1,27 +1,24 @@
|
||||
//
|
||||
// FILE: AD524X_sawtooth.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.01
|
||||
// VERSION: 0.1.2
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2013-10-12
|
||||
// URL:
|
||||
//
|
||||
// Released to the public domain
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
//
|
||||
|
||||
#include "AD524X.h"
|
||||
#include "Wire.h"
|
||||
|
||||
AD524X AD01(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print("\nStart AD524X_sawtooth : ");
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
TWBR = 72; // 100KHz
|
||||
Wire.setClock(400000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
@ -32,4 +29,6 @@ void loop()
|
||||
Serial.println(val);
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -1,27 +1,24 @@
|
||||
//
|
||||
// FILE: AD524X_setO.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.01
|
||||
// VERSION: 0.1.2
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2013-10-12
|
||||
// URL:
|
||||
//
|
||||
// Released to the public domain
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
//
|
||||
|
||||
#include "AD524X.h"
|
||||
#include "Wire.h"
|
||||
|
||||
AD524X AD01(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print("\nStart AD524X_setO : ");
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
TWBR = 72; // 100 KHz
|
||||
Wire.setClock(400000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
@ -41,4 +38,6 @@ void loop()
|
||||
Serial.print('\t');
|
||||
Serial.println(AD01.getO2());
|
||||
delay(x);
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -1,28 +1,24 @@
|
||||
//
|
||||
// FILE: AD524X_write.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.01
|
||||
// VERSION: 0.1.2
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2013-10-12
|
||||
// URL:
|
||||
//
|
||||
// Released to the public domain
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
//
|
||||
|
||||
#include "AD524X.h"
|
||||
#include "Wire.h"
|
||||
|
||||
AD524X AD01(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.print("\nStart AD524X_write : ");
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
TWBR = 12; // 400 KHz
|
||||
|
||||
Wire.setClock(400000);
|
||||
}
|
||||
|
||||
void loop()
|
||||
@ -41,4 +37,6 @@ void loop()
|
||||
Serial.println(val);
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -0,0 +1,44 @@
|
||||
//
|
||||
// FILE: AD524X_write_AD5241ino.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2020-12-08
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
//
|
||||
|
||||
#include "AD524X.h"
|
||||
|
||||
AD5241 AD(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000);
|
||||
|
||||
Serial.println(AD.pmCount());
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
for (int val = 0; val < 255; val++)
|
||||
{
|
||||
AD.write(0, val);
|
||||
if (val == 200)
|
||||
{
|
||||
AD.write(1, val, HIGH, LOW);
|
||||
}
|
||||
if (val == 0)
|
||||
{
|
||||
AD.write(0, val, LOW, LOW);
|
||||
}
|
||||
Serial.println(val);
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,44 @@
|
||||
//
|
||||
// FILE: AD524X_write_AD5242.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: AD524X demo program
|
||||
// DATE: 2020-12-08
|
||||
// URL: https://github.com/RobTillaart/AD524X
|
||||
//
|
||||
|
||||
#include "AD524X.h"
|
||||
|
||||
AD5242 AD(0x2C); // AD0 & AD1 == GND
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.println(AD524X_VERSION);
|
||||
|
||||
Wire.begin();
|
||||
Wire.setClock(400000);
|
||||
|
||||
Serial.println(AD.pmCount());
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
for (int val = 0; val < 255; val++)
|
||||
{
|
||||
AD.write(1, val);
|
||||
if (val == 200)
|
||||
{
|
||||
AD.write(1, val, HIGH, LOW);
|
||||
}
|
||||
if (val == 0)
|
||||
{
|
||||
AD.write(1, val, LOW, LOW);
|
||||
}
|
||||
Serial.println(val);
|
||||
delay(20);
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
28
libraries/AD524X/keywords.txt
Normal file
28
libraries/AD524X/keywords.txt
Normal file
@ -0,0 +1,28 @@
|
||||
# Syntax Coloring Map For AD524X
|
||||
|
||||
# Datatypes (KEYWORD1)
|
||||
AD524X KEYWORD1
|
||||
AD5241 KEYWORD1
|
||||
AD5242 KEYWORD1
|
||||
|
||||
# Methods and Functions (KEYWORD2)
|
||||
begin KEYWORD2
|
||||
reset KEYWORD2
|
||||
zeroAll KEYWORD2
|
||||
|
||||
read KEYWORD2
|
||||
write KEYWORD2
|
||||
|
||||
setO1 KEYWORD2
|
||||
setO2 KEYWORD2
|
||||
getO1 KEYWORD2
|
||||
getO2 KEYWORD2
|
||||
|
||||
midScaleReset KEYWORD2
|
||||
pmCount KEYWORD2
|
||||
shutDown KEYWORD2
|
||||
|
||||
# Constants (LITERAL1)
|
||||
AD524X_VERSION LITERAL1
|
||||
AS524X_OK LITERAL1
|
||||
AS524X_ERROR LITERAL1
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "AD524X",
|
||||
"keywords": "I2C,digital,PotentioMeter,AD5241,AD5242",
|
||||
"keywords": "I2C,digital,PotentioMeter, AD5241, AD5242",
|
||||
"description": "Library to control digital potentiometer AD5241 AD5242",
|
||||
"authors":
|
||||
[
|
||||
@ -15,7 +15,7 @@
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/AD524X"
|
||||
},
|
||||
"version":"0.2.1",
|
||||
"version":"0.3.1",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*"
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
name=AD524X
|
||||
version=0.2.1
|
||||
version=0.3.1
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino Library for AD524X
|
||||
|
133
libraries/AD524X/test/unit_test_001.cpp
Normal file
133
libraries/AD524X/test/unit_test_001.cpp
Normal file
@ -0,0 +1,133 @@
|
||||
//
|
||||
// FILE: unit_test_001.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.3.0
|
||||
// DATE: 2020-12-03
|
||||
// PURPOSE: unit tests for I2C digital PotentioMeter AD5241 AD5242
|
||||
// https://github.com/RobTillaart/AD524X
|
||||
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
|
||||
//
|
||||
|
||||
// supported assertions
|
||||
// ----------------------------
|
||||
// assertEqual(expected, actual)
|
||||
// assertNotEqual(expected, actual)
|
||||
// assertLess(expected, actual)
|
||||
// assertMore(expected, actual)
|
||||
// assertLessOrEqual(expected, actual)
|
||||
// assertMoreOrEqual(expected, actual)
|
||||
// assertTrue(actual)
|
||||
// assertFalse(actual)
|
||||
// assertNull(actual)
|
||||
|
||||
#include <ArduinoUnitTests.h>
|
||||
|
||||
#include "AD524X.h"
|
||||
|
||||
|
||||
unittest_setup()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unittest_teardown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unittest(test_constructors)
|
||||
{
|
||||
Wire.begin();
|
||||
|
||||
AD524X ADx(0x2C); // AD0 & AD1 == GND
|
||||
assertEqual(127, ADx.read(0));
|
||||
assertEqual(127, ADx.read(1));
|
||||
|
||||
AD5241 AD1(0x2C);
|
||||
assertEqual(127, AD1.read(0));
|
||||
assertEqual(127, AD1.read(1));
|
||||
|
||||
AD5242 AD2(0x2C);
|
||||
assertEqual(127, AD2.read(0));
|
||||
assertEqual(127, AD2.read(1));
|
||||
}
|
||||
|
||||
|
||||
unittest(test_reset)
|
||||
{
|
||||
AD524X AD(0x2C); // AD0 & AD1 == GND
|
||||
Wire.begin();
|
||||
|
||||
assertEqual(127, AD.read(0));
|
||||
assertEqual(127, AD.read(1));
|
||||
|
||||
AD.zeroAll();
|
||||
assertEqual(0, AD.read(0));
|
||||
assertEqual(0, AD.read(1));
|
||||
|
||||
AD.reset();
|
||||
assertEqual(127, AD.read(0));
|
||||
assertEqual(127, AD.read(1));
|
||||
|
||||
AD.zeroAll();
|
||||
assertEqual(0, AD.read(0));
|
||||
assertEqual(0, AD.read(1));
|
||||
|
||||
AD.midScaleReset(0);
|
||||
assertEqual(127, AD.read(0));
|
||||
AD.midScaleReset(1);
|
||||
assertEqual(127, AD.read(1));
|
||||
}
|
||||
|
||||
|
||||
unittest(test_write_read)
|
||||
{
|
||||
AD524X AD(0x2C); // AD0 & AD1 == GND
|
||||
Wire.begin();
|
||||
|
||||
assertEqual(127, AD.read(0));
|
||||
assertEqual(127, AD.read(1));
|
||||
|
||||
AD.write(0, 42);
|
||||
assertEqual(42, AD.read(0));
|
||||
assertEqual(127, AD.read(1));
|
||||
|
||||
AD.write(1, 42);
|
||||
assertEqual(42, AD.read(0));
|
||||
assertEqual(42, AD.read(1));
|
||||
}
|
||||
|
||||
|
||||
unittest(test_O1_O2)
|
||||
{
|
||||
AD524X AD(0x2C); // AD0 & AD1 == GND
|
||||
Wire.begin();
|
||||
|
||||
assertEqual(0, AD.getO1());
|
||||
assertEqual(0, AD.getO2());
|
||||
|
||||
AD.setO1();
|
||||
assertEqual(1, AD.getO1());
|
||||
assertEqual(0, AD.getO2());
|
||||
|
||||
AD.setO2();
|
||||
assertEqual(1, AD.getO1());
|
||||
assertEqual(1, AD.getO2());
|
||||
|
||||
AD.setO1(0);
|
||||
assertEqual(0, AD.getO1());
|
||||
assertEqual(1, AD.getO2());
|
||||
|
||||
AD.setO2(0);
|
||||
assertEqual(0, AD.getO1());
|
||||
assertEqual(0, AD.getO2());
|
||||
|
||||
AD.write(0, 0, 1, 1);
|
||||
assertEqual(1, AD.getO1());
|
||||
assertEqual(1, AD.getO2());
|
||||
}
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
// --------
|
7
libraries/AD985X/.arduino-ci.yml
Normal file
7
libraries/AD985X/.arduino-ci.yml
Normal file
@ -0,0 +1,7 @@
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
- uno
|
||||
- leonardo
|
||||
- due
|
||||
- zero
|
13
libraries/AD985X/.github/workflows/arduino_test_runner.yml
vendored
Normal file
13
libraries/AD985X/.github/workflows/arduino_test_runner.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: Arduino CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
arduino_ci:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Arduino-CI/action@master
|
||||
# Arduino-CI/action@v0.1.1
|
315
libraries/AD985X/AD985X.cpp
Normal file
315
libraries/AD985X/AD985X.cpp
Normal file
@ -0,0 +1,315 @@
|
||||
//
|
||||
// FILE: AD985X.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.2
|
||||
// DATE: 2019-02-08
|
||||
// PURPOSE: Class for AD9850 and AD9851 function generator
|
||||
//
|
||||
// HISTORY:
|
||||
// 0.1.0 2019-03-19 initial version
|
||||
// 0.1.1 2020-12-09 add arduino-ci
|
||||
// 0.1.2 2020-12-27 add setAutoMode() + offset
|
||||
// 0.2.0 2020-12-28 major refactor class hierarchy + float frequency
|
||||
// 0.2.1 2021-01-10 add get- and setARCCutOffFreq()
|
||||
// 0.2.2 2021-01-24 add manual updating frequency
|
||||
// get- setManualFQ_UD(), update()
|
||||
// inverted SELECT line as preparation for multidevice.
|
||||
|
||||
|
||||
#include "AD985X.h"
|
||||
|
||||
|
||||
// UNO HARDWARE SPI PINS
|
||||
#define SPI_CLOCK 13
|
||||
#define SPI_MISO 12
|
||||
#define SPI_MOSI 11
|
||||
|
||||
|
||||
#define AD985X_POWERDOWN 0x04
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// AD9850
|
||||
//
|
||||
|
||||
AD9850::AD9850()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void AD9850::begin(int select, int resetPin, int FQUDPin, int dataOut , int clock)
|
||||
{
|
||||
_select = select;
|
||||
_reset = resetPin;
|
||||
_fqud = FQUDPin;
|
||||
pinMode(_select, OUTPUT);
|
||||
pinMode(_reset, OUTPUT);
|
||||
pinMode(_fqud, OUTPUT);
|
||||
digitalWrite(_select, LOW); // device select = HIGH See - https://github.com/RobTillaart/AD985X/issues/13
|
||||
digitalWrite(_reset, LOW);
|
||||
digitalWrite(_fqud, LOW);
|
||||
_useHW = true;
|
||||
|
||||
// SW SPI
|
||||
if ((dataOut != 0) && (clock != 0))
|
||||
{
|
||||
_dataOut = dataOut;
|
||||
_clock = clock;
|
||||
pinMode(_dataOut, OUTPUT);
|
||||
pinMode(_clock, OUTPUT);
|
||||
digitalWrite(_dataOut, LOW);
|
||||
digitalWrite(_clock, LOW);
|
||||
_useHW = false;
|
||||
}
|
||||
|
||||
if (_useHW)
|
||||
{
|
||||
SPI.begin(); // set MOSI & MISO pin right.
|
||||
}
|
||||
|
||||
reset();
|
||||
}
|
||||
|
||||
|
||||
void AD9850::reset()
|
||||
{
|
||||
pulsePin(_reset);
|
||||
if (_useHW) pulsePin(SPI_CLOCK);
|
||||
else pulsePin(_clock);
|
||||
|
||||
_config = 0; // 0 phase no powerdown
|
||||
_freq = 0;
|
||||
_factor = 0;
|
||||
_offset = 0;
|
||||
_autoUpdate = true;
|
||||
writeData();
|
||||
}
|
||||
|
||||
|
||||
void AD9850::powerDown()
|
||||
{
|
||||
_config |= AD985X_POWERDOWN; // keep phase and REFCLK as is.
|
||||
writeData();
|
||||
}
|
||||
|
||||
|
||||
void AD9850::powerUp()
|
||||
{
|
||||
_config &= ~AD985X_POWERDOWN;
|
||||
writeData();
|
||||
}
|
||||
|
||||
|
||||
void AD9850::setPhase(uint8_t phase)
|
||||
{
|
||||
if (phase > 31) return;
|
||||
_config &= 0x07;
|
||||
_config |= (phase << 3);
|
||||
writeData();
|
||||
}
|
||||
|
||||
|
||||
void AD9850::pulsePin(uint8_t pin)
|
||||
{
|
||||
digitalWrite(pin, HIGH);
|
||||
digitalWrite(pin, LOW);
|
||||
}
|
||||
|
||||
|
||||
void AD9850::writeData()
|
||||
{
|
||||
// Serial.println(_factor, HEX);
|
||||
// Serial.println(_config, HEX);
|
||||
uint32_t data = _factor;
|
||||
|
||||
// used for multidevice config only - https://github.com/RobTillaart/AD985X/issues/13
|
||||
digitalWrite(_select, HIGH);
|
||||
if (_useHW)
|
||||
{
|
||||
SPI.beginTransaction(SPISettings(2000000, LSBFIRST, SPI_MODE0));
|
||||
SPI.transfer(data & 0xFF);
|
||||
data >>= 8;
|
||||
SPI.transfer(data & 0xFF);
|
||||
data >>= 8;
|
||||
SPI.transfer(data & 0xFF);
|
||||
SPI.transfer(data >> 8);
|
||||
SPI.transfer(_config & 0xFD); // mask factory test bit
|
||||
SPI.endTransaction();
|
||||
}
|
||||
else
|
||||
{
|
||||
swSPI_transfer(data & 0xFF);
|
||||
data >>= 8;
|
||||
swSPI_transfer(data & 0xFF);
|
||||
data >>= 8;
|
||||
swSPI_transfer(data & 0xFF);
|
||||
swSPI_transfer(data >> 8);
|
||||
swSPI_transfer(_config & 0xFD); // mask factory test bit
|
||||
}
|
||||
digitalWrite(_select, LOW);
|
||||
|
||||
// update frequency + phase + control bits.
|
||||
// should at least be 4 ns delay - P14 datasheet
|
||||
if (_autoUpdate) update();
|
||||
}
|
||||
|
||||
|
||||
// simple one mode version
|
||||
void AD9850::swSPI_transfer(uint8_t value)
|
||||
{
|
||||
// for (uint8_t mask = 0x80; mask; mask >>= 1) // MSBFIRST
|
||||
for (uint8_t mask = 0x01; mask; mask <<= 1) // LSBFIRST
|
||||
{
|
||||
digitalWrite(_dataOut,(value & mask) != 0);
|
||||
digitalWrite(_clock, HIGH);
|
||||
digitalWrite(_clock, LOW);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void AD9850::setFrequency(uint32_t freq)
|
||||
{
|
||||
// freq OUT = (Δ Phase × CLKIN)/2^32
|
||||
// 64 bit math to keep precision to the max
|
||||
if (freq > AD9850_MAX_FREQ) freq = AD9850_MAX_FREQ;
|
||||
// _factor = round(freq * 34.359738368); // 4294967296 / 125000000
|
||||
_factor = (147573952589ULL * freq) >> 32;
|
||||
_freq = freq;
|
||||
_factor += _offset;
|
||||
writeData();
|
||||
}
|
||||
|
||||
|
||||
// especially for lower frequencies (with decimals)
|
||||
void AD9850::setFrequencyF(float freq)
|
||||
{
|
||||
// freq OUT = (Δ Phase × CLKIN)/2^32
|
||||
// 64 bit math to keep precision to the max
|
||||
if (freq > AD9850_MAX_FREQ) freq = AD9850_MAX_FREQ;
|
||||
_factor = round(freq * 34.359738368); // 4294967296 / 125000000
|
||||
_freq = freq;
|
||||
_factor += _offset;
|
||||
writeData();
|
||||
}
|
||||
|
||||
|
||||
void AD9850::update()
|
||||
{
|
||||
digitalWrite(_select, HIGH);
|
||||
pulsePin(_fqud);
|
||||
digitalWrite(_select, LOW);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// AD9851
|
||||
//
|
||||
|
||||
#define AD9851_REFCLK 0x01 // bit is a 6x multiplier bit P.14 datasheet
|
||||
|
||||
void AD9851::setFrequency(uint32_t freq)
|
||||
{
|
||||
// PREVENT OVERFLOW
|
||||
if (freq > AD9851_MAX_FREQ) freq = AD9851_MAX_FREQ;
|
||||
|
||||
// AUTO SWITCH REFERENCE FREQUENCY
|
||||
if (_autoRefClock)
|
||||
{
|
||||
if (freq > _ARCCutOffFreq)
|
||||
{
|
||||
_config |= AD9851_REFCLK;
|
||||
}
|
||||
else
|
||||
{
|
||||
_config &= ~AD9851_REFCLK;
|
||||
}
|
||||
}
|
||||
|
||||
if (_config & AD9851_REFCLK) // 6x 30 = 180 MHz
|
||||
{
|
||||
_factor = (102481911520ULL * freq) >> 32; // (1 << 64) / 180000000
|
||||
}
|
||||
else // 1x 30 = 30 MHz
|
||||
{
|
||||
_factor = (614891469123ULL * freq) >> 32; // (1 << 64) / 30000000
|
||||
}
|
||||
_freq = freq;
|
||||
_factor += _offset;
|
||||
writeData();
|
||||
}
|
||||
|
||||
|
||||
// especially for lower frequencies (with decimals)
|
||||
void AD9851::setFrequencyF(float freq)
|
||||
{
|
||||
// PREVENT OVERFLOW
|
||||
if (freq > AD9851_MAX_FREQ) freq = AD9851_MAX_FREQ;
|
||||
|
||||
// AUTO SWITCH REFERENCE FREQUENCY
|
||||
if (_autoRefClock)
|
||||
{
|
||||
if (freq > _ARCCutOffFreq)
|
||||
{
|
||||
_config |= AD9851_REFCLK;
|
||||
}
|
||||
else
|
||||
{
|
||||
_config &= ~AD9851_REFCLK;
|
||||
}
|
||||
}
|
||||
|
||||
if (_config & AD9851_REFCLK) // 6x 30 = 180 MHz
|
||||
{
|
||||
_factor = uint64_t(102481911520ULL * freq) >> 32; // (1 << 64) / 180000000
|
||||
}
|
||||
else // 1x 30 = 30 MHz
|
||||
{
|
||||
_factor = (6148914691ULL * uint64_t (100 * freq)) >> 32;
|
||||
}
|
||||
|
||||
_freq = freq;
|
||||
_factor += _offset;
|
||||
writeData();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////
|
||||
//
|
||||
// AD9851 - AUTO REFERENCE CLOCK
|
||||
//
|
||||
void AD9851::setAutoRefClock(bool arc)
|
||||
{
|
||||
_autoRefClock = arc;
|
||||
setFrequency(_freq);
|
||||
};
|
||||
|
||||
|
||||
void AD9851::setRefClockHigh()
|
||||
{
|
||||
_config |= AD9851_REFCLK;
|
||||
setFrequency(_freq);
|
||||
}
|
||||
|
||||
|
||||
void AD9851::setRefClockLow()
|
||||
{
|
||||
_config &= ~AD9851_REFCLK;
|
||||
setFrequency(_freq);
|
||||
}
|
||||
|
||||
|
||||
uint8_t AD9851::getRefClock()
|
||||
{
|
||||
return (_config & AD9851_REFCLK) ? 180 : 30;
|
||||
}
|
||||
|
||||
void AD9851::setARCCutOffFreq(uint32_t Hz)
|
||||
{
|
||||
if (Hz > 30000000UL) Hz = 30000000;
|
||||
_ARCCutOffFreq = Hz;
|
||||
};
|
||||
|
||||
|
||||
// -- END OF FILE --
|
101
libraries/AD985X/AD985X.h
Normal file
101
libraries/AD985X/AD985X.h
Normal file
@ -0,0 +1,101 @@
|
||||
#pragma once
|
||||
//
|
||||
// FILE: AD985X.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.2
|
||||
// DATE: 2019-02-08
|
||||
// PURPOSE: Class for AD9850 and AD9851 function generator
|
||||
//
|
||||
// URL: https://github.com/RobTillaart/AD985X
|
||||
//
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "SPI.h"
|
||||
|
||||
|
||||
#define AD985X_LIB_VERSION (F("0.2.2"))
|
||||
|
||||
|
||||
#define AD9850_MAX_FREQ (40UL * 1000UL * 1000UL)
|
||||
#define AD9851_MAX_FREQ (70UL * 1000UL * 1000UL)
|
||||
|
||||
|
||||
class AD9850
|
||||
{
|
||||
public:
|
||||
AD9850();
|
||||
|
||||
// for HW SPI only use lower 3 parameters.
|
||||
void begin(int select, int resetPin, int FQUDPin, int dataOut = 0, int clock = 0);
|
||||
void reset();
|
||||
void powerDown();
|
||||
void powerUp();
|
||||
|
||||
void setFrequency(uint32_t freq); // 0..AD9850_MAX_FREQ
|
||||
void setFrequencyF(float freq); // works best for lower frequencies.
|
||||
float getFrequency() { return _freq; };
|
||||
uint32_t getMaxFrequency() { return AD9850_MAX_FREQ; };
|
||||
|
||||
// 0 .. 31 steps of 11.25 degrees
|
||||
void setPhase(uint8_t phase = 0);
|
||||
uint8_t getPhase() { return (_config >> 3); };
|
||||
|
||||
// offset to calibrate the frequency (internal counter)
|
||||
// offset must be stored by the user.
|
||||
void setCalibration(int32_t offset = 0) { _offset = offset; };
|
||||
int32_t getCalibration() { return _offset; };
|
||||
// internal chip factor used for frequency. (debugging only)
|
||||
uint32_t getFactor() { return _factor; };
|
||||
|
||||
// autoUpdate is default true;
|
||||
void setAutoUpdate(bool update) { _autoUpdate = update; };
|
||||
bool getAutoUpdate() { return _autoUpdate; };
|
||||
void update();
|
||||
|
||||
|
||||
protected:
|
||||
void pulsePin(uint8_t pin);
|
||||
void writeData();
|
||||
void swSPI_transfer(uint8_t value);
|
||||
|
||||
bool _useHW = true;
|
||||
uint8_t _dataOut = 0;
|
||||
uint8_t _clock = 0;
|
||||
uint8_t _select = 0;
|
||||
|
||||
float _freq = 1;
|
||||
uint32_t _factor = 0;
|
||||
uint8_t _config = 0;
|
||||
uint8_t _reset = 0;
|
||||
uint8_t _fqud = 0;
|
||||
int32_t _offset = 0;
|
||||
bool _autoUpdate = true;
|
||||
};
|
||||
|
||||
|
||||
class AD9851 : public AD9850
|
||||
{
|
||||
public:
|
||||
void setFrequency(uint32_t freq); // 0..AD9851_MAX_FREQ
|
||||
void setFrequencyF(float freq);
|
||||
uint32_t getMaxFrequency() { return AD9851_MAX_FREQ; };
|
||||
|
||||
void setRefClockHigh(); // 180 MHz
|
||||
void setRefClockLow(); // 30 MHz
|
||||
uint8_t getRefClock();
|
||||
|
||||
void setAutoRefClock(bool arc);
|
||||
bool getAutoRefClock() { return _autoRefClock; };
|
||||
|
||||
// 10 MHz is default, set in Hz.
|
||||
// will be kept <= 30 MHz as that is the freq of LOW mode.
|
||||
void setARCCutOffFreq(uint32_t Hz = 10000000UL );
|
||||
uint32_t getARCCutOffFreq() { return _ARCCutOffFreq; };
|
||||
|
||||
protected:
|
||||
bool _autoRefClock = false;
|
||||
uint32_t _ARCCutOffFreq = 10000000UL;
|
||||
|
||||
};
|
||||
|
||||
// -- END OF FILE --
|
21
libraries/AD985X/LICENSE
Normal file
21
libraries/AD985X/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 - 2021 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
217
libraries/AD985X/README.md
Normal file
217
libraries/AD985X/README.md
Normal file
@ -0,0 +1,217 @@
|
||||
|
||||
[![Arduino CI](https://github.com/RobTillaart/AD985X/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
||||
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/AD985X/blob/master/LICENSE)
|
||||
[![GitHub release](https://img.shields.io/github/release/RobTillaart/AD985X.svg?maxAge=3600)](https://github.com/RobTillaart/AD985X/releases)
|
||||
|
||||
# AD985X
|
||||
|
||||
Arduino library for AD9850 and AD9851 function generators.
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
Library for the AD9850 and AD9851 function generators.
|
||||
The library has a AD9850 base class that implements the commonalities.
|
||||
The AD9851 is derived and has its own **setFrequency()** methods.
|
||||
Furthermore the AD9851 also has function to select the reference clock,
|
||||
a feature the AD9850 does not have.
|
||||
|
||||
**Warning**
|
||||
The library is not suitable for AD9852 as that is a function generator with
|
||||
way more functionality.
|
||||
|
||||
|
||||
## Connection
|
||||
|
||||
|
||||
```
|
||||
TOP VIEW
|
||||
+-----------+
|
||||
| X-TAL |
|
||||
| L |
|
||||
VCC | o o | VCC
|
||||
CLK | o o | D0
|
||||
PUFD | o o | D1
|
||||
DATA | o o | D2
|
||||
RESET | o o | D3
|
||||
GND | o CCC o | D4
|
||||
QOUT1 | o CCC o | D5
|
||||
QOUT2 | o o | D6
|
||||
ZOUT1 | o o | D7 ----- SELECT SERIAL LOW
|
||||
ZOUT2 | o PP o | GND
|
||||
| PP |
|
||||
+-----------+
|
||||
|
||||
XTAL = crystal
|
||||
L = LED
|
||||
C = chip
|
||||
P = potmeter => for duty cycle square wave
|
||||
|
||||
```
|
||||
|
||||
### Multidevice
|
||||
|
||||
**Warning**: this setup needs to be confirmed as it is not actually tested by me yet.
|
||||
|
||||
Discussed in detail here - https://github.com/RobTillaart/AD985X/issues/13
|
||||
|
||||
The AD985X board can be connected with a SPI bus like interface.
|
||||
However there is **no Chip Select pin (CS)** so one must take other measures to control multiple AD985X devices.
|
||||
|
||||
|
||||
#### Trivial solution
|
||||
|
||||
The trivial implementation is to give each device a set of unique pins.
|
||||
If you have pins to spare this is the perfect solution.
|
||||
|
||||
|
||||
#### Shared line solution
|
||||
|
||||
A more common SPI solution is to share the data and clock lines.
|
||||
However that would typical set all AD985X devices simultaneously.
|
||||
So extra hardware is needed to prevent this.
|
||||
|
||||
A possible solution is to put all needed lines behind an AND port that allows only
|
||||
communication when the **SELECT** is HIGH.
|
||||
|
||||
|
||||
The **DATA** line of the device is connected to the output of an **AND** port.
|
||||
The inputs if the **AND** port are (a) the SPI bus **DATA** line and (b) the **SELECT** pin.
|
||||
Strictly for the **DATA** this is not needed as data will only clock in if there is a **CLOCK**.
|
||||
|
||||
The **CLOCK** pin of the device is connected to the output of an **AND** port.
|
||||
The inputs if the **AND** port are (a) the SPI bus **CLOCK** line and (b) the **SELECT** pin.
|
||||
|
||||
The **FQ_UD** pin of the device is connected to the output of an **AND** port.
|
||||
The inputs if the **AND** port are (a) the MCU **FQ_UD** line and (b) the **SELECT** pin.
|
||||
See FQ_UD note below.
|
||||
|
||||
The **RESET** pin of the device is connected to the output of an **AND** port.
|
||||
The inputs if the **AND** port are (a) the MCU **RESET** line and (b) the **SELECT** pin.
|
||||
|
||||
A typical IC to use is the **74HC08** which has 4 AND ports in it.
|
||||
|
||||
|
||||
In short this setup makes the lines 'switchable' pass through, with the **SELECT** line.
|
||||
It allows to have multiple AD985X devices, and even to share the SPI bus **DATA** and **CLOCK**
|
||||
lines with other SPI devices.
|
||||
|
||||
|
||||
TODO - picture.
|
||||
|
||||
**Note** Other multiplexing solutions are possible of course.
|
||||
|
||||
|
||||
### FQ_UD note
|
||||
|
||||
It might be possible to connect a single FQ_UD line to multiple AD985X devices directly.
|
||||
The FQ_UD pulse would update the frequency and as this register is not changed, the FQ_UD
|
||||
pulse might just have no changing effect. To be investigated to confirm this.
|
||||
|
||||
If confirmed this would change the above Shared line solution a bit.
|
||||
|
||||
If the FQ_UD line can be shared directly it offers a way to start / change multiple
|
||||
devices at the same time.
|
||||
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
### Constructors
|
||||
|
||||
- **AD9850()** 40 MHz signal generator
|
||||
- **AD9851()** 70 MHz signal generator, derived from AD9850 with some extra options.
|
||||
|
||||
|
||||
### Common interface
|
||||
|
||||
- **begin(selectPin, resetPin, FQUDPin, dataOut = 0, clock = 0)**
|
||||
For hardware SPI only use the first three parameters,
|
||||
for SW SPI you need to define the data and clock pin too.
|
||||
- selectPin = chip select. The library uses HIGH as active and LOW as not selected.
|
||||
- resetPin = reset
|
||||
- FQUD = Frequency UpDate Pin
|
||||
- **reset()** resets the function generator.
|
||||
- **powerDown()** idem
|
||||
- **powerUp()** idem
|
||||
- **setFrequency(uint32_t freq)** SetFrequency sets the frequency and is limited by the
|
||||
MaxFrequency of the class used. For the AD9850 => 40 MHz, for the AD9851 => 70 MHz.
|
||||
- Note that the quality of the signal gets less at higher frequencies.
|
||||
- Note setFrequency is affected by the autoUpdateFlag.
|
||||
- **setFrequencyF(float freq)** SetFrequencyF sets the frequency with a float with a maximum of **two** decimals.
|
||||
- Note that a float only has a mantisse of 6-7 digits so above ~1.000.000 decimals are lost.
|
||||
- Note setFrequencyF is affected by the autoUpdateFlag.
|
||||
- **getMaxFrequency()** returns the maximum frequency setable. For the AD9850 this is 20 MHz.
|
||||
For the AD9851 this is 70 MHz.
|
||||
- **getFrequency()** returns the frequency set. As it returns a float it might loose some accuracy at higher frequencies.
|
||||
- **setPhase(uint8_t phase = 0)** set the phase in units of 11.25° 0..31 allowed.
|
||||
Default it sets the phase to 0.
|
||||
- **getPhase()** returns the phase set, 0 by default.
|
||||
|
||||
|
||||
### Calibration
|
||||
|
||||
**Warning:** use with care.
|
||||
|
||||
- **void setCalibrationOffset(int32_t offset = 0)** sets an offset to calibrate the frequency.
|
||||
- **uint32_t getCalibrationOffset()** reads back the offset set.
|
||||
- **uint32_t getFactor()** internal factor, for debugging
|
||||
|
||||
Note: reset() resets the offset to 0..
|
||||
Note: setting the offset reduces the range of frequencies (at the ends of scale).
|
||||
|
||||
|
||||
### Auto update / manual update
|
||||
|
||||
(new since 0.2.2)
|
||||
|
||||
**Warning:** use with care.
|
||||
|
||||
- **void setAutoUpdate(bool update)** sets the autoUpdate flag, default it is true.
|
||||
- **bool getAutoUpdate()** reads the autoUpdate flag.
|
||||
- **void update()** manually toggle the FQ_UD flag to update the frequency.
|
||||
|
||||
Manual updating allows one to prepare the frequency, and actually apply
|
||||
it at a later moment.
|
||||
|
||||
The default of the flag is true, and will be reset to true by the **reset()** call.
|
||||
|
||||
|
||||
|
||||
### AD9850 specific
|
||||
|
||||
The AD9850 has no specific functions.
|
||||
|
||||
### AD9851 specific
|
||||
|
||||
- **setRefClockHigh()** set reference clock to 180 Mhz.
|
||||
- **setRefClockLow()** set reference clock to 30 Mhz.
|
||||
- **getRefClock()** returns 30 or 180.
|
||||
- **setAutoRefClock(bool arc)** sets a flag so the library switches automatically
|
||||
to the reference clock of 180 MHz when the frequency is set above 10 MHz and
|
||||
to 30 MHz when the frequency is set to 10 MHz or lower.
|
||||
The initial value is **false** == OFF for backwards compatibility.
|
||||
- **getAutoRefClock()** returns true is automode is set.
|
||||
- **void setARCCutOffFreq(uint32_t Hz = 10000000UL )** set cut off frequency
|
||||
for the auto reference clock. max value is 30 MHz, typical 10MHz
|
||||
- **uint32_t getARCCutOffFreq()** returns cut off frequency set.
|
||||
|
||||
|
||||
- Note: the autoRefClock mode does **NOT** automatically adjust the calibration offset.
|
||||
- Note: **reset()** does **NOT** reset the autoRefClock flag.
|
||||
|
||||
|
||||
## Operation
|
||||
|
||||
See examples
|
||||
|
||||
|
||||
### Operational notes
|
||||
|
||||
- The quality of the signal becomes less at higher frequencies.
|
||||
Switch the refclock to find your optimal quality.
|
||||
- If the calibration offset is not 0, it needs to be set by the user after every startup,
|
||||
and after switching the reference clock.
|
||||
The user is also responsible to store it e.g. in EEPROM to make it persistent.
|
||||
- Experimental parts may change or removed in the future.
|
||||
|
93
libraries/AD985X/examples/AD9850_demo/AD9850_demo.ino
Normal file
93
libraries/AD985X/examples/AD9850_demo/AD9850_demo.ino
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// FILE: AD9850_demo.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: demo
|
||||
|
||||
|
||||
#include "AD985X.h"
|
||||
|
||||
AD9850 freqGen;
|
||||
|
||||
uint32_t freq = 0;
|
||||
uint32_t prev = 0;
|
||||
uint32_t maxFreq;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AD985X_LIB_VERSION: \t");
|
||||
Serial.println(AD985X_LIB_VERSION);
|
||||
|
||||
help();
|
||||
|
||||
freqGen.begin(10, 9, 8, 7, 6);
|
||||
freqGen.powerUp();
|
||||
maxFreq = freqGen.getMaxFrequency();
|
||||
Serial.println(maxFreq);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
int c = Serial.read();
|
||||
switch (c)
|
||||
{
|
||||
case '?' :
|
||||
help();
|
||||
break;
|
||||
case 'R' :
|
||||
freqGen.reset();
|
||||
freq = freqGen.getFrequency();
|
||||
break;
|
||||
case 'P' :
|
||||
freqGen.powerDown();
|
||||
break;
|
||||
case 'U' :
|
||||
freqGen.powerUp();
|
||||
break;
|
||||
case '+' :
|
||||
freq += 1;
|
||||
break;
|
||||
case '-' :
|
||||
freq -= 1;
|
||||
break;
|
||||
case '*' :
|
||||
freq *= 10;
|
||||
break;
|
||||
case '/' :
|
||||
freq /= 10;
|
||||
break;
|
||||
}
|
||||
if (freq > maxFreq) freq = maxFreq;
|
||||
}
|
||||
|
||||
// UPDATE AD985X IF NEW VALUE
|
||||
if (prev != freq)
|
||||
{
|
||||
prev = freq;
|
||||
freqGen.setFrequency(freq);
|
||||
Serial.println(freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void help()
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println("+ : f = f + 1");
|
||||
Serial.println("- : f = f - 1");
|
||||
Serial.println("* : f = f * 10");
|
||||
Serial.println("/ : f = f / 10");
|
||||
Serial.println("? : help");
|
||||
Serial.println("R : AD9850 reset");
|
||||
Serial.println("P : AD9850 power down");
|
||||
Serial.println("U : AD9850 power up");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,94 @@
|
||||
//
|
||||
// FILE: AD9850_demo_float.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: demo
|
||||
|
||||
|
||||
#include "AD985X.h"
|
||||
|
||||
|
||||
AD9850 freqGen;
|
||||
|
||||
uint32_t freq = 0;
|
||||
uint32_t prev = 0;
|
||||
uint32_t maxFreq;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AD985X_LIB_VERSION: \t");
|
||||
Serial.println(AD985X_LIB_VERSION);
|
||||
|
||||
help();
|
||||
|
||||
freqGen.begin(10, 9, 8, 7, 6);
|
||||
freqGen.powerUp();
|
||||
maxFreq = freqGen.getMaxFrequency();
|
||||
Serial.println(maxFreq);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
int c = Serial.read();
|
||||
switch (c)
|
||||
{
|
||||
case '?' :
|
||||
help();
|
||||
break;
|
||||
case 'R' :
|
||||
freqGen.reset();
|
||||
freq = freqGen.getFrequency();
|
||||
break;
|
||||
case 'P' :
|
||||
freqGen.powerDown();
|
||||
break;
|
||||
case 'U' :
|
||||
freqGen.powerUp();
|
||||
break;
|
||||
case '+' :
|
||||
freq += 1;
|
||||
break;
|
||||
case '-' :
|
||||
freq -= 1;
|
||||
break;
|
||||
case '*' :
|
||||
freq *= 10;
|
||||
break;
|
||||
case '/' :
|
||||
freq /= 10;
|
||||
break;
|
||||
}
|
||||
if (freq > maxFreq) freq = maxFreq;
|
||||
}
|
||||
|
||||
// UPDATE AD985X IF NEW VALUE
|
||||
if (prev != freq)
|
||||
{
|
||||
prev = freq;
|
||||
freqGen.setFrequencyF(freq * 0.01);
|
||||
Serial.println(freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void help()
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println("+ : f = f + 0.01");
|
||||
Serial.println("- : f = f - 0.01");
|
||||
Serial.println("* : f = f * 10");
|
||||
Serial.println("/ : f = f / 10");
|
||||
Serial.println("? : help");
|
||||
Serial.println("R : AD9850 reset");
|
||||
Serial.println("P : AD9850 power down");
|
||||
Serial.println("U : AD9850 power up");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
93
libraries/AD985X/examples/AD9851_demo/AD9851_demo.ino
Normal file
93
libraries/AD985X/examples/AD9851_demo/AD9851_demo.ino
Normal file
@ -0,0 +1,93 @@
|
||||
//
|
||||
// FILE: AD9851_demo.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: demo
|
||||
|
||||
|
||||
#include "AD985X.h"
|
||||
|
||||
AD9851 freqGen;
|
||||
|
||||
uint32_t freq = 0;
|
||||
uint32_t prev = 0;
|
||||
uint32_t maxFreq;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AD985X_LIB_VERSION: \t");
|
||||
Serial.println(AD985X_LIB_VERSION);
|
||||
|
||||
help();
|
||||
|
||||
freqGen.begin(10, 9, 8, 7, 6);
|
||||
freqGen.powerUp();
|
||||
maxFreq = freqGen.getMaxFrequency();
|
||||
Serial.println(maxFreq);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
int c = Serial.read();
|
||||
switch(c)
|
||||
{
|
||||
case '?' :
|
||||
help();
|
||||
break;
|
||||
case 'R' :
|
||||
freqGen.reset();
|
||||
freq = freqGen.getFrequency();
|
||||
break;
|
||||
case 'P' :
|
||||
freqGen.powerDown();
|
||||
break;
|
||||
case 'U' :
|
||||
freqGen.powerUp();
|
||||
break;
|
||||
case '+' :
|
||||
freq += 1;
|
||||
break;
|
||||
case '-' :
|
||||
freq -= 1;
|
||||
break;
|
||||
case '*' :
|
||||
freq *= 10;
|
||||
break;
|
||||
case '/' :
|
||||
freq /= 10;
|
||||
break;
|
||||
}
|
||||
if (freq > maxFreq) freq = maxFreq;
|
||||
}
|
||||
|
||||
// UPDATE AD985X IF NEW VALUE
|
||||
if (prev != freq)
|
||||
{
|
||||
prev = freq;
|
||||
freqGen.setFrequency(freq);
|
||||
Serial.println(freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void help()
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println("+ : f = f + 1");
|
||||
Serial.println("- : f = f - 1");
|
||||
Serial.println("* : f = f * 10");
|
||||
Serial.println("/ : f = f / 10");
|
||||
Serial.println("? : help");
|
||||
Serial.println("R : AD9851 reset");
|
||||
Serial.println("P : AD9851 power down");
|
||||
Serial.println("U : AD9851 power up");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
152
libraries/AD985X/examples/AD9851_demo_2/AD9851_demo_2.ino
Normal file
152
libraries/AD985X/examples/AD9851_demo_2/AD9851_demo_2.ino
Normal file
@ -0,0 +1,152 @@
|
||||
//
|
||||
// FILE: AD9851_demo_2.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: demo
|
||||
|
||||
|
||||
#include "AD985X.h"
|
||||
|
||||
|
||||
AD9851 freqGen;
|
||||
|
||||
uint32_t freq = 0;
|
||||
uint32_t prev = 0;
|
||||
uint32_t maxFreq;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AD985X_LIB_VERSION: \t");
|
||||
Serial.println(AD985X_LIB_VERSION);
|
||||
|
||||
help();
|
||||
|
||||
freqGen.begin(10, 9, 8, 7, 6);
|
||||
freqGen.powerUp();
|
||||
maxFreq = freqGen.getMaxFrequency();
|
||||
Serial.print(" MAX_FREQ: ");
|
||||
Serial.println(maxFreq);
|
||||
Serial.print("REF_CLOCK: ");
|
||||
Serial.println(freqGen.getRefClock());
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
int c = Serial.read();
|
||||
switch (c)
|
||||
{
|
||||
case '0'...'9' :
|
||||
freq *= 10;
|
||||
freq += c - '0';
|
||||
break;
|
||||
case '?' :
|
||||
help();
|
||||
break;
|
||||
case 'R' :
|
||||
freqGen.reset();
|
||||
freq = freqGen.getFrequency();
|
||||
break;
|
||||
case 'P' :
|
||||
freqGen.powerDown();
|
||||
break;
|
||||
case 'U' :
|
||||
freqGen.powerUp();
|
||||
break;
|
||||
case 'A' :
|
||||
freqGen.setAutoRefClock(true);
|
||||
Serial.println("REF_CLOCK: AUTO ON");
|
||||
break;
|
||||
case 'C' :
|
||||
freqGen.setAutoRefClock(false);
|
||||
Serial.println("REF_CLOCK: AUTO OFF");
|
||||
break;
|
||||
case 'G' :
|
||||
Serial.print("REF_CLOCK: ");
|
||||
Serial.println(freqGen.getRefClock());
|
||||
break;
|
||||
case 'H' :
|
||||
freqGen.setRefClockHigh();
|
||||
Serial.print("REF_CLOCK: ");
|
||||
Serial.println(freqGen.getRefClock());
|
||||
break;
|
||||
case 'L' :
|
||||
freqGen.setRefClockLow();
|
||||
Serial.print("REF_CLOCK: ");
|
||||
Serial.println(freqGen.getRefClock());
|
||||
break;
|
||||
case '+' :
|
||||
freq += 1;
|
||||
break;
|
||||
case '-' :
|
||||
freq -= 1;
|
||||
break;
|
||||
case '*' :
|
||||
freq *= 10;
|
||||
break;
|
||||
case '/' :
|
||||
freq /= 10;
|
||||
break;
|
||||
}
|
||||
if (freq > maxFreq) freq = maxFreq;
|
||||
}
|
||||
|
||||
// UPDATE AD985X IF NEW VALUE
|
||||
if (prev != freq)
|
||||
{
|
||||
prev = freq;
|
||||
|
||||
freqGen.setFrequency(freq);
|
||||
freq = freqGen.getFrequency();
|
||||
Serial.println(freq);
|
||||
// printFreq(freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void help()
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println(" HELP AD985X");
|
||||
Serial.println("+ : freq = freq + 1");
|
||||
Serial.println("- : freq = freq - 1");
|
||||
Serial.println("* : freq = freq * 10");
|
||||
Serial.println("/ : freq = freq / 10");
|
||||
Serial.println("? : help");
|
||||
Serial.println("R : AD9851 reset");
|
||||
Serial.println("P : AD9851 power down");
|
||||
Serial.println("U : AD9851 power up");
|
||||
Serial.println("A : AD9851 set reference clock AUTO ON");
|
||||
Serial.println("C : AD9851 set reference clock AUTO OFF");
|
||||
Serial.println("G : AD9851 print reference clock");
|
||||
Serial.println("H : AD9851 set reference clock HIGH");
|
||||
Serial.println("L : AD9851 set reference clock LOW");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
|
||||
void printFreq(float freq)
|
||||
{
|
||||
if (freq > 1000000)
|
||||
{
|
||||
Serial.print(freq / 1e6, 2);
|
||||
Serial.println(" MHz");
|
||||
return;
|
||||
}
|
||||
|
||||
if (freq > 1000)
|
||||
{
|
||||
Serial.print(freq / 1e3, 2);
|
||||
Serial.println(" KHz");
|
||||
return;
|
||||
}
|
||||
Serial.print(freq, 2);
|
||||
Serial.println(" Hz");
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,90 @@
|
||||
//
|
||||
// FILE: AD9851_demo_float.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: demo
|
||||
|
||||
|
||||
#include "AD985X.h"
|
||||
|
||||
|
||||
AD9851 freqGen;
|
||||
|
||||
uint32_t freq = 0;
|
||||
uint32_t prev = 0;
|
||||
uint32_t maxFreq;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AD985X_LIB_VERSION: \t");
|
||||
Serial.println(AD985X_LIB_VERSION);
|
||||
|
||||
help();
|
||||
|
||||
freqGen.begin(10, 9, 8, 7, 6);
|
||||
freqGen.powerUp();
|
||||
maxFreq = freqGen.getMaxFrequency();
|
||||
Serial.println(maxFreq);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (Serial.available() > 0)
|
||||
{
|
||||
int c = Serial.read();
|
||||
switch(c)
|
||||
{
|
||||
case '?' :
|
||||
help();
|
||||
break;
|
||||
case 'R' :
|
||||
freqGen.reset();
|
||||
freq = freqGen.getFrequency();
|
||||
break;
|
||||
case 'P' :
|
||||
freqGen.powerDown();
|
||||
break;
|
||||
case '+' :
|
||||
freq += 1;
|
||||
break;
|
||||
case '-' :
|
||||
freq -= 1;
|
||||
break;
|
||||
case '*' :
|
||||
freq *= 10;
|
||||
break;
|
||||
case '/' :
|
||||
freq /= 10;
|
||||
break;
|
||||
}
|
||||
if (freq > maxFreq) freq = maxFreq;
|
||||
}
|
||||
|
||||
// UPDATE AD985X IF NEW VALUE
|
||||
if (prev != freq)
|
||||
{
|
||||
prev = freq;
|
||||
freqGen.setFrequency(freq * 0.01);
|
||||
Serial.println(freq);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void help()
|
||||
{
|
||||
Serial.println();
|
||||
Serial.println("+ : f = f + 0.01");
|
||||
Serial.println("- : f = f - 0.01");
|
||||
Serial.println("* : f = f * 10");
|
||||
Serial.println("/ : f = f / 10");
|
||||
Serial.println("? : help");
|
||||
Serial.println("R : reset AD985X");
|
||||
Serial.println("P : power down AD985X");
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
// END OF FILE
|
@ -0,0 +1,70 @@
|
||||
//
|
||||
// FILE: AD9851_manual update.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: demo
|
||||
|
||||
|
||||
#include "AD985X.h"
|
||||
|
||||
|
||||
AD9851 freqGen;
|
||||
|
||||
uint32_t freq = 0;
|
||||
uint32_t maxFreq = 2000000UL;
|
||||
|
||||
bool up = true;
|
||||
|
||||
uint32_t lastUpdate = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AD985X_LIB_VERSION: \t");
|
||||
Serial.println(AD985X_LIB_VERSION);
|
||||
|
||||
freqGen.begin(10, 9, 8, 7, 6);
|
||||
freqGen.powerUp();
|
||||
freqGen.setAutoRefClock(true);
|
||||
|
||||
freq = 100;
|
||||
|
||||
Serial.print("AutoUpdate: ");
|
||||
Serial.println(freqGen.getAutoUpdate());
|
||||
freqGen.setAutoUpdate(false);
|
||||
Serial.print("AutoUpdate: ");
|
||||
Serial.println(freqGen.getAutoUpdate());
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (up == true) freq *= 1.01;
|
||||
else freq /= 1.01;
|
||||
|
||||
if (freq > maxFreq)
|
||||
{
|
||||
freq = maxFreq;
|
||||
up = false;
|
||||
}
|
||||
if (freq < 100)
|
||||
{
|
||||
freq = 100;
|
||||
up = true;
|
||||
}
|
||||
freqGen.setFrequency(freq);
|
||||
|
||||
// only update once per second
|
||||
// effectively have a random frequency
|
||||
if (millis() - lastUpdate >= 1000)
|
||||
{
|
||||
lastUpdate = millis();
|
||||
freqGen.update();
|
||||
Serial.print(millis());
|
||||
Serial.print('\t');
|
||||
Serial.println(freq);
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,49 @@
|
||||
//
|
||||
// FILE: AD9851_six_potmeter.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: demo
|
||||
|
||||
|
||||
#include "AD985X.h"
|
||||
|
||||
|
||||
AD9851 freqGen;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AD985X_LIB_VERSION: \t");
|
||||
Serial.println(AD985X_LIB_VERSION);
|
||||
|
||||
freqGen.begin(10, 9, 8, 7, 6);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
float freq = readFreq(true);
|
||||
|
||||
freqGen.setFrequencyF(freq);
|
||||
Serial.println(freq);
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
float readFreq(bool KHZ)
|
||||
{
|
||||
float freq = 0;
|
||||
freq += (analogRead(A0) / 103) * 1000;
|
||||
freq += (analogRead(A1) / 103) * 100;
|
||||
freq += (analogRead(A2) / 103) * 10;
|
||||
freq += (analogRead(A3) / 103) * 1;
|
||||
freq += (analogRead(A4) / 103) * 0.1;
|
||||
freq += (analogRead(A5) / 103) * 0.01;
|
||||
|
||||
if (KHZ) freq *= 1000;
|
||||
return freq;
|
||||
}
|
||||
|
||||
// END OF FILE
|
56
libraries/AD985X/examples/AD9851_sweeper/AD9851_sweeper.ino
Normal file
56
libraries/AD985X/examples/AD9851_sweeper/AD9851_sweeper.ino
Normal file
@ -0,0 +1,56 @@
|
||||
//
|
||||
// FILE: AD9851_sweeper.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.0
|
||||
// PURPOSE: demo
|
||||
|
||||
|
||||
#include "AD985X.h"
|
||||
|
||||
|
||||
AD9851 freqGen;
|
||||
|
||||
uint32_t freq = 0;
|
||||
uint32_t maxFreq = 2000000UL;
|
||||
|
||||
bool up = true;
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("AD985X_LIB_VERSION: \t");
|
||||
Serial.println(AD985X_LIB_VERSION);
|
||||
|
||||
freqGen.begin(10, 9, 8, 7, 6);
|
||||
freqGen.powerUp();
|
||||
freqGen.setAutoRefClock(true);
|
||||
|
||||
freq = 100;
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (up == true) freq *= 1.01;
|
||||
else freq /= 1.01;
|
||||
|
||||
if (freq > maxFreq)
|
||||
{
|
||||
freq = maxFreq;
|
||||
up = false;
|
||||
}
|
||||
if (freq < 100)
|
||||
{
|
||||
freq = 100;
|
||||
up = true;
|
||||
}
|
||||
freqGen.setFrequency(freq);
|
||||
Serial.print(millis());
|
||||
Serial.print('\t');
|
||||
Serial.println(freq);
|
||||
delay(50);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
38
libraries/AD985X/keywords.txt
Normal file
38
libraries/AD985X/keywords.txt
Normal file
@ -0,0 +1,38 @@
|
||||
# Syntax Coloring Map For AD985X
|
||||
|
||||
# Datatypes (KEYWORD1)
|
||||
AD9850 KEYWORD1
|
||||
AD9851 KEYWORD1
|
||||
|
||||
|
||||
# Methods and Functions (KEYWORD2)
|
||||
begin KEYWORD2
|
||||
reset KEYWORD2
|
||||
powerDown KEYWORD2
|
||||
powerUp KEYWORD2
|
||||
|
||||
setFrequencyF KEYWORD2
|
||||
setFrequency KEYWORD2
|
||||
getFrequency KEYWORD2
|
||||
setPhase KEYWORD2
|
||||
getPhase KEYWORD2
|
||||
|
||||
setRefClockHigh KEYWORD2
|
||||
setRefClockLow KEYWORD2
|
||||
getRefClock KEYWORD2
|
||||
setAutoRefClock KEYWORD2
|
||||
getAutoRefClock KEYWORD2
|
||||
setARCCutOffFreq KEYWORD2
|
||||
getARCCutOffFreq KEYWORD2
|
||||
|
||||
setCalibration KEYWORD2
|
||||
getCalibration KEYWORD2
|
||||
getFactor KEYWORD2
|
||||
setAutoUpdate KEYWORD2
|
||||
getAutoUpdate KEYWORD2
|
||||
update KEYWORD2
|
||||
|
||||
|
||||
# Constants (LITERAL1)
|
||||
AD9850_MAX_FREQ LITERAL1
|
||||
AD9851_MAX_FREQ LITERAL1
|
21
libraries/AD985X/library.json
Normal file
21
libraries/AD985X/library.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "AD985X",
|
||||
"keywords": "AD9850 AD9851",
|
||||
"description": "Arduino library for AD9850 and AD9851 function generators.",
|
||||
"authors":
|
||||
[
|
||||
{
|
||||
"name": "Rob Tillaart",
|
||||
"email": "Rob.Tillaart@gmail.com",
|
||||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/AD985X.git"
|
||||
},
|
||||
"version":"0.2.2",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*"
|
||||
}
|
11
libraries/AD985X/library.properties
Normal file
11
libraries/AD985X/library.properties
Normal file
@ -0,0 +1,11 @@
|
||||
name=AD985X
|
||||
version=0.2.2
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino library for AD9850 and AD9851 function generators. Supports both hardware SPI as software SPI.
|
||||
paragraph=Will not work for the AD9852.
|
||||
category=Signal Input/Output
|
||||
url=https://github.com/RobTillaart/AD985X
|
||||
architectures=*
|
||||
includes=AD985X.h
|
||||
depends=
|
210
libraries/AD985X/test/unit_test_001.cpp
Normal file
210
libraries/AD985X/test/unit_test_001.cpp
Normal file
@ -0,0 +1,210 @@
|
||||
//
|
||||
// FILE: unit_test_001.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2020-12-03
|
||||
// PURPOSE: unit tests for the AD9850 and AD9851 function generator
|
||||
// https://github.com/RobTillaart/AD985X
|
||||
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
|
||||
//
|
||||
|
||||
// supported assertions
|
||||
// ----------------------------
|
||||
// assertEqual(expected, actual)
|
||||
// assertNotEqual(expected, actual)
|
||||
// assertLess(expected, actual)
|
||||
// assertMore(expected, actual)
|
||||
// assertLessOrEqual(expected, actual)
|
||||
// assertMoreOrEqual(expected, actual)
|
||||
// assertTrue(actual)
|
||||
// assertFalse(actual)
|
||||
// assertNull(actual)
|
||||
|
||||
#include <ArduinoUnitTests.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "AD985X.h"
|
||||
|
||||
|
||||
unittest_setup()
|
||||
{
|
||||
}
|
||||
|
||||
unittest_teardown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unittest(test_constructor)
|
||||
{
|
||||
fprintf(stderr, "VERSION: %s\n", AD985X_LIB_VERSION);
|
||||
AD9850 funcgen0;
|
||||
AD9851 funcgen1;
|
||||
|
||||
assertEqual(AD9850_MAX_FREQ, funcgen0.getMaxFrequency());
|
||||
assertEqual(AD9851_MAX_FREQ, funcgen1.getMaxFrequency());
|
||||
}
|
||||
|
||||
|
||||
unittest(test_auto_update)
|
||||
{
|
||||
fprintf(stderr, "VERSION: %s\n", AD985X_LIB_VERSION);
|
||||
AD9850 funcgen0;
|
||||
AD9851 funcgen1;
|
||||
funcgen0.begin(4, 5, 6);
|
||||
funcgen1.begin(10, 11, 16);
|
||||
|
||||
|
||||
assertTrue(funcgen0.getAutoUpdate());
|
||||
assertTrue(funcgen1.getAutoUpdate());
|
||||
funcgen0.setAutoUpdate(false);
|
||||
funcgen1.setAutoUpdate(false);
|
||||
assertFalse(funcgen0.getAutoUpdate());
|
||||
assertFalse(funcgen1.getAutoUpdate());
|
||||
funcgen0.setAutoUpdate(true);
|
||||
funcgen1.setAutoUpdate(true);
|
||||
assertTrue(funcgen0.getAutoUpdate());
|
||||
assertTrue(funcgen1.getAutoUpdate());
|
||||
}
|
||||
|
||||
|
||||
unittest(test_ad9850)
|
||||
{
|
||||
AD9850 funcgen;
|
||||
funcgen.begin(4, 5, 6);
|
||||
|
||||
funcgen.setFrequency(1000);
|
||||
long freq = funcgen.getFrequency();
|
||||
assertEqual(1000, freq);
|
||||
|
||||
for (int ph = 0; ph < 32; ph += 4)
|
||||
{
|
||||
funcgen.setPhase(ph);
|
||||
int phase = funcgen.getPhase();
|
||||
assertEqual(ph, phase);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest(test_ad9851)
|
||||
{
|
||||
AD9851 funcgen;
|
||||
funcgen.begin(4, 5, 6);
|
||||
|
||||
funcgen.setFrequency(1000);
|
||||
long freq = funcgen.getFrequency();
|
||||
assertEqual(1000, freq);
|
||||
|
||||
for (int ph = 0; ph < 32; ph += 4)
|
||||
{
|
||||
funcgen.setPhase(ph);
|
||||
int phase = funcgen.getPhase();
|
||||
assertEqual(ph, phase);
|
||||
}
|
||||
|
||||
funcgen.setRefClockHigh();
|
||||
assertEqual(180, funcgen.getRefClock());
|
||||
funcgen.setRefClockLow();
|
||||
assertEqual(30, funcgen.getRefClock());
|
||||
}
|
||||
|
||||
|
||||
unittest(test_ad9851_reset)
|
||||
{
|
||||
AD9851 funcgen;
|
||||
funcgen.begin(4, 5, 6);
|
||||
|
||||
funcgen.setFrequency(1000);
|
||||
assertEqual(1000, funcgen.getFrequency());
|
||||
funcgen.setPhase(14);
|
||||
assertEqual(14, funcgen.getPhase());
|
||||
funcgen.setRefClockHigh();
|
||||
assertEqual(180, funcgen.getRefClock());
|
||||
|
||||
funcgen.reset();
|
||||
|
||||
assertEqual(0, funcgen.getFrequency());
|
||||
assertEqual(0, funcgen.getPhase());
|
||||
assertEqual(30, funcgen.getRefClock());
|
||||
}
|
||||
|
||||
|
||||
unittest(test_ad9851_autoRefClock)
|
||||
{
|
||||
AD9851 funcgen;
|
||||
funcgen.begin(4, 5, 6);
|
||||
|
||||
assertFalse(funcgen.getAutoRefClock());
|
||||
for (uint32_t freq = 70; freq <= 70000000; freq *= 10)
|
||||
{
|
||||
funcgen.setFrequency(freq);
|
||||
fprintf(stderr, "freq %ld\t", freq);
|
||||
assertEqual(30, funcgen.getRefClock());
|
||||
}
|
||||
|
||||
funcgen.setAutoRefClock(true);
|
||||
assertTrue(funcgen.getAutoRefClock());
|
||||
for (uint32_t freq = 70; freq <= 1000000; freq *= 10)
|
||||
{
|
||||
funcgen.setFrequency(freq);
|
||||
fprintf(stderr, "freq %ld\t", freq);
|
||||
assertEqual(30, funcgen.getRefClock());
|
||||
}
|
||||
|
||||
funcgen.setFrequency(10000000);
|
||||
fprintf(stderr, "freq 10000000\t");
|
||||
assertEqual(30, funcgen.getRefClock());
|
||||
funcgen.setFrequency(100000001);
|
||||
fprintf(stderr, "freq 100000001\t");
|
||||
assertEqual(180, funcgen.getRefClock());
|
||||
funcgen.setFrequency(70000000);
|
||||
fprintf(stderr, "freq 70000000\t");
|
||||
assertEqual(180, funcgen.getRefClock());
|
||||
|
||||
fprintf(stderr, "get- setARCCutOffFreq\t");
|
||||
funcgen.setARCCutOffFreq(5000);
|
||||
assertEqual(5000, funcgen.getARCCutOffFreq());
|
||||
funcgen.setARCCutOffFreq(5000000);
|
||||
assertEqual(5000000, funcgen.getARCCutOffFreq());
|
||||
funcgen.setARCCutOffFreq(50000000);
|
||||
assertEqual(30000000, funcgen.getARCCutOffFreq());
|
||||
|
||||
}
|
||||
|
||||
|
||||
unittest(test_ad9851_offset)
|
||||
{
|
||||
AD9851 funcgen;
|
||||
funcgen.begin(4, 5, 6);
|
||||
|
||||
assertEqual(0, funcgen.getCalibration());
|
||||
funcgen.setFrequency(1000000);
|
||||
assertEqual(1000000, funcgen.getFrequency());
|
||||
for (int32_t offset = -1000; offset <= 1000; offset += 100)
|
||||
{
|
||||
funcgen.setCalibration(offset);
|
||||
fprintf(stderr, "offset %d\t", offset);
|
||||
assertEqual(offset, funcgen.getCalibration());
|
||||
}
|
||||
assertEqual(1000000, funcgen.getFrequency());
|
||||
|
||||
funcgen.setCalibration();
|
||||
assertEqual(0, funcgen.getCalibration());
|
||||
}
|
||||
|
||||
unittest(test_ad9851_float_freq)
|
||||
{
|
||||
AD9851 funcgen;
|
||||
funcgen.begin(4, 5, 6);
|
||||
|
||||
for (float f = 100.0; f < 110.0; f += 0.1)
|
||||
{
|
||||
funcgen.setFrequencyF(f);
|
||||
fprintf(stderr, "%ld\t", funcgen.getFactor());
|
||||
assertEqualFloat(f, funcgen.getFrequency(), 1.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
// --------
|
7
libraries/ADS1x15/.arduino-ci.yml
Normal file
7
libraries/ADS1x15/.arduino-ci.yml
Normal file
@ -0,0 +1,7 @@
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
- uno
|
||||
- leonardo
|
||||
- due
|
||||
- zero
|
13
libraries/ADS1x15/.github/workflows/arduino_test_runner.yml
vendored
Normal file
13
libraries/ADS1x15/.github/workflows/arduino_test_runner.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: Arduino CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
arduino_ci:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Arduino-CI/action@master
|
||||
# Arduino-CI/action@v0.1.1
|
555
libraries/ADS1x15/ADS1X15.cpp
Normal file
555
libraries/ADS1x15/ADS1X15.cpp
Normal file
@ -0,0 +1,555 @@
|
||||
//
|
||||
// FILE: ADS1X15.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.7
|
||||
// DATE: 2013-03-24
|
||||
// PUPROSE: Arduino library for ADS1015 and ADS1115
|
||||
// URL: https://github.com/RobTillaart/ADS1X15
|
||||
//
|
||||
// HISTORY:
|
||||
// 0.0.0 2013-03-24 initial version
|
||||
// 0.0.1 2013-03-24 first working version
|
||||
// 0.1.0 2017-07-31 removed pre 1.0 support; added getVoltage
|
||||
// 0.2.0 2020-04-08 initial release; refactor ad fundum;
|
||||
// 0.2.1 2020-08-15 fix issue 2 gain; refactor
|
||||
// 0.2.2 2020-08-18 add begin(sda, scl) for ESP32
|
||||
// 0.2.3 2020-08-20 add comparator code + async mode
|
||||
// 0.2.4 2020-08-26 check readme.md and minor fixes
|
||||
// 0.2.5 2020-08-26 add missing readADC_Differential_X_X()
|
||||
// 0.2.6 2020-09-01 fix #12 - fix getMaxVoltage + minor refactor
|
||||
// 0.2.7 2020-09-27 redo readRegister() + getValue() + getError()
|
||||
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
#define ADS1015_CONVERSION_DELAY 1
|
||||
#define ADS1115_CONVERSION_DELAY 8
|
||||
|
||||
|
||||
// Kept #defines a bit in line with Adafruits library.
|
||||
|
||||
// REGISTERS
|
||||
#define ADS1X15_REG_CONVERT 0x00
|
||||
#define ADS1X15_REG_CONFIG 0x01
|
||||
#define ADS1X15_REG_LOW_THRESHOLD 0x02
|
||||
#define ADS1X15_REG_HIGH_THRESHOLD 0x03
|
||||
|
||||
|
||||
// CONFIG REGISTER
|
||||
|
||||
// BIT 15 Operational Status // 1 << 15
|
||||
#define ADS1X15_OS_BUSY 0x0000
|
||||
#define ADS1X15_OS_NOT_BUSY 0x8000
|
||||
#define ADS1X15_OS_START_SINGLE 0x8000
|
||||
|
||||
// BIT 12-14 read differential
|
||||
#define ADS1X15_MUX_DIFF_0_1 0x0000
|
||||
#define ADS1X15_MUX_DIFF_0_3 0x1000
|
||||
#define ADS1X15_MUX_DIFF_1_3 0x2000
|
||||
#define ADS1X15_MUX_DIFF_2_3 0x3000
|
||||
// read single
|
||||
#define ADS1X15_READ_0 0x4000 // pin << 12
|
||||
#define ADS1X15_READ_1 0x5000 // pin = 0..3
|
||||
#define ADS1X15_READ_2 0x6000
|
||||
#define ADS1X15_READ_3 0x7000
|
||||
|
||||
|
||||
// BIT 9-11 gain // (0..5) << 9
|
||||
#define ADS1X15_PGA_6_144V 0x0000 // voltage
|
||||
#define ADS1X15_PGA_4_096V 0x0200 //
|
||||
#define ADS1X15_PGA_2_048V 0x0400 // default
|
||||
#define ADS1X15_PGA_1_024V 0x0600
|
||||
#define ADS1X15_PGA_0_512V 0x0800
|
||||
#define ADS1X15_PGA_0_256V 0x0A00
|
||||
|
||||
// BIT 8 mode // 1 << 8
|
||||
#define ADS1X15_MODE_CONTINUE 0x0000
|
||||
#define ADS1X15_MODE_SINGLE 0x0100
|
||||
|
||||
// BIT 5-7 datarate sample per second // (0..7) << 5
|
||||
/*
|
||||
differs for different devices, check datasheet or readme.md
|
||||
| datarate | ADS101x | ADS 111x |
|
||||
|:----:|----:|----:|
|
||||
| 0 | 128 | 8 |
|
||||
| 1 | 250 | 16 |
|
||||
| 2 | 490 | 32 |
|
||||
| 3 | 920 | 64 |
|
||||
| 4 | 1600 | 128 |
|
||||
| 5 | 2400 | 250 |
|
||||
| 6 | 3300 | 475 |
|
||||
| 7 | 3300 | 860 |
|
||||
*/
|
||||
|
||||
// BIT 4 comparator modi // 1 << 4
|
||||
#define ADS1X15_COMP_MODE_TRADITIONAL 0x0000
|
||||
#define ADS1X15_COMP_MODE_WINDOW 0x0010
|
||||
|
||||
// BIT 3 ALERT active value // 1 << 3
|
||||
#define ADS1X15_COMP_POL_ACTIV_LOW 0x0000
|
||||
#define ADS1X15_COMP_POL_ACTIV_HIGH 0x0008
|
||||
|
||||
// BIT 2 ALERT latching // 1 << 2
|
||||
#define ADS1X15_COMP_NON_LATCH 0x0000
|
||||
#define ADS1X15_COMP_LATCH 0x0004
|
||||
|
||||
// BIT 0-1 ALERT mode // (0..3)
|
||||
#define ADS1X15_COMP_QUE_1_CONV 0x0000 // trigger alert after 1 convert
|
||||
#define ADS1X15_COMP_QUE_2_CONV 0x0001 // trigger alert after 2 converts
|
||||
#define ADS1X15_COMP_QUE_4_CONV 0x0002 // trigger alert after 4 converts
|
||||
#define ADS1X15_COMP_QUE_NONE 0x0003 // dosable comparator
|
||||
|
||||
// _CONFIG masks
|
||||
//
|
||||
// | bit | description |
|
||||
// |:----:|:----|
|
||||
// | 0 | # channels |
|
||||
// | 1 | - |
|
||||
// | 2 | resolution |
|
||||
// | 3 | - |
|
||||
// | 4 | GAIN supported |
|
||||
// | 5 | COMPARATOR supported |
|
||||
// | 6 | - |
|
||||
// | 7 | - |
|
||||
#define ADS_CONF_CHAN_1 0x00
|
||||
#define ADS_CONF_CHAN_4 0x01
|
||||
#define ADS_CONF_RES_12 0x00
|
||||
#define ADS_CONF_RES_16 0x04
|
||||
#define ADS_CONF_NOGAIN 0x00
|
||||
#define ADS_CONF_GAIN 0x10
|
||||
#define ADS_CONF_NOCOMP 0x00
|
||||
#define ADS_CONF_COMP 0x20
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// STATIC MEMBERS
|
||||
//
|
||||
static bool writeRegister(uint8_t address, uint8_t reg, uint16_t value)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write((uint8_t)reg);
|
||||
Wire.write((uint8_t)(value >> 8));
|
||||
Wire.write((uint8_t)(value & 0xFF));
|
||||
return (Wire.endTransmission() == 0);
|
||||
}
|
||||
|
||||
static uint16_t readRegister(uint8_t address, uint8_t reg)
|
||||
{
|
||||
Wire.beginTransmission(address);
|
||||
Wire.write(reg);
|
||||
Wire.endTransmission();
|
||||
|
||||
int rv = Wire.requestFrom(address, (uint8_t) 2);
|
||||
if (rv == 2)
|
||||
{
|
||||
uint16_t value = Wire.read() << 8;
|
||||
value += Wire.read();
|
||||
return value;
|
||||
}
|
||||
return 0x0000;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
//
|
||||
// BASE CONSTRUCTOR
|
||||
//
|
||||
ADS1X15::ADS1X15()
|
||||
{
|
||||
setGain(0); // _gain = ADS1X15_PGA_6_144V;
|
||||
setMode(1); // _mode = ADS1X15_MODE_SINGLE;
|
||||
setDataRate(4); // middle speed, depends on device.
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
bool ADS1X15::begin(uint8_t sda, uint8_t scl)
|
||||
{
|
||||
Wire.begin(sda, scl);
|
||||
if ((_address < 0x48) || (_address > 0x4B)) return false;
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
bool ADS1X15::begin()
|
||||
{
|
||||
Wire.begin();
|
||||
if ((_address < 0x48) || (_address > 0x4B)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADS1X15::isBusy()
|
||||
{
|
||||
uint16_t val = readRegister(_address, ADS1X15_REG_CONFIG);
|
||||
if ((val & ADS1X15_OS_NOT_BUSY) != 0) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADS1X15::isConnected()
|
||||
{
|
||||
Wire.beginTransmission(_address);
|
||||
return (Wire.endTransmission() == 0);
|
||||
}
|
||||
|
||||
void ADS1X15::setGain(uint8_t gain)
|
||||
{
|
||||
if (!(_config & ADS_CONF_GAIN)) gain = 0;
|
||||
switch (gain)
|
||||
{
|
||||
default: // catch invalid values and go for the safest gain.
|
||||
case 0: _gain = ADS1X15_PGA_6_144V; break;
|
||||
case 1: _gain = ADS1X15_PGA_4_096V; break;
|
||||
case 2: _gain = ADS1X15_PGA_2_048V; break;
|
||||
case 4: _gain = ADS1X15_PGA_1_024V; break;
|
||||
case 8: _gain = ADS1X15_PGA_0_512V; break;
|
||||
case 16: _gain = ADS1X15_PGA_0_256V; break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ADS1X15::getGain()
|
||||
{
|
||||
if (!(_config & ADS_CONF_GAIN)) return 0;
|
||||
switch (_gain)
|
||||
{
|
||||
case ADS1X15_PGA_6_144V: return 0;
|
||||
case ADS1X15_PGA_4_096V: return 1;
|
||||
case ADS1X15_PGA_2_048V: return 2;
|
||||
case ADS1X15_PGA_1_024V: return 4;
|
||||
case ADS1X15_PGA_0_512V: return 8;
|
||||
case ADS1X15_PGA_0_256V: return 16;
|
||||
}
|
||||
_err = ADS1X15_INVALID_GAIN;
|
||||
return _err;
|
||||
}
|
||||
|
||||
float ADS1X15::toVoltage(int16_t val)
|
||||
{
|
||||
if (val == 0) return 0;
|
||||
|
||||
float volts = getMaxVoltage();
|
||||
if (volts < 0) return volts;
|
||||
|
||||
volts *= val;
|
||||
if (_config & ADS_CONF_RES_16)
|
||||
{
|
||||
volts /= 32767; // val = 16 bits - sign bit = 15 bits mantissa
|
||||
}
|
||||
else
|
||||
{
|
||||
volts /= 2047; // val = 12 bits - sign bit = 11 bit mantissa
|
||||
}
|
||||
return volts;
|
||||
}
|
||||
|
||||
float ADS1X15::getMaxVoltage()
|
||||
{
|
||||
switch (_gain)
|
||||
{
|
||||
case ADS1X15_PGA_6_144V: return 6.144;
|
||||
case ADS1X15_PGA_4_096V: return 4.096;
|
||||
case ADS1X15_PGA_2_048V: return 2.048;
|
||||
case ADS1X15_PGA_1_024V: return 1.024;
|
||||
case ADS1X15_PGA_0_512V: return 0.512;
|
||||
case ADS1X15_PGA_0_256V: return 0.256;
|
||||
}
|
||||
_err = ADS1X15_INVALID_VOLTAGE;
|
||||
return _err;
|
||||
}
|
||||
|
||||
void ADS1X15::setMode(uint8_t mode)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 0: _mode = ADS1X15_MODE_CONTINUE; break;
|
||||
default:
|
||||
case 1: _mode = ADS1X15_MODE_SINGLE; break;
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ADS1X15::getMode(void)
|
||||
{
|
||||
switch (_mode)
|
||||
{
|
||||
case ADS1X15_MODE_CONTINUE: return 0;
|
||||
case ADS1X15_MODE_SINGLE: return 1;
|
||||
}
|
||||
_err = ADS1X15_INVALID_MODE;
|
||||
return _err;
|
||||
}
|
||||
|
||||
void ADS1X15::setDataRate(uint8_t dataRate)
|
||||
{
|
||||
_datarate = dataRate;
|
||||
if (_datarate > 7) _datarate = 4; // default
|
||||
_datarate <<= 5; // convert 0..7 to mask needed.
|
||||
}
|
||||
|
||||
uint8_t ADS1X15::getDataRate(void)
|
||||
{
|
||||
return (_datarate >> 5); // convert mask back to 0..7
|
||||
}
|
||||
|
||||
int16_t ADS1X15::readADC(uint8_t pin)
|
||||
{
|
||||
if (pin >= _maxPorts) return 0;
|
||||
uint16_t mode = ((4 + pin) << 12); // pin to mask
|
||||
return _readADC(mode);
|
||||
}
|
||||
|
||||
void ADS1X15::requestADC_Differential_0_1()
|
||||
{
|
||||
_requestADC(ADS1X15_MUX_DIFF_0_1);
|
||||
}
|
||||
|
||||
int16_t ADS1X15::readADC_Differential_0_1()
|
||||
{
|
||||
return _readADC(ADS1X15_MUX_DIFF_0_1);
|
||||
}
|
||||
|
||||
void ADS1X15::requestADC(uint8_t pin)
|
||||
{
|
||||
if (pin >= _maxPorts) return;
|
||||
uint16_t mode = ((4 + pin) << 12); // pin to mask
|
||||
_requestADC(mode);
|
||||
}
|
||||
|
||||
int16_t ADS1X15::getValue()
|
||||
{
|
||||
int16_t raw = readRegister(_address, ADS1X15_REG_CONVERT);
|
||||
if (_bitShift) raw >>= _bitShift; // Shift 12-bit results
|
||||
return raw;
|
||||
}
|
||||
|
||||
void ADS1X15::setComparatorThresholdLow(int16_t lo)
|
||||
{
|
||||
writeRegister(_address, ADS1X15_REG_LOW_THRESHOLD, lo);
|
||||
};
|
||||
|
||||
int16_t ADS1X15::getComparatorThresholdLow()
|
||||
{
|
||||
return readRegister(_address, ADS1X15_REG_LOW_THRESHOLD);
|
||||
};
|
||||
|
||||
void ADS1X15::setComparatorThresholdHigh(int16_t hi)
|
||||
{
|
||||
writeRegister(_address, ADS1X15_REG_HIGH_THRESHOLD, hi);
|
||||
};
|
||||
|
||||
int16_t ADS1X15::getComparatorThresholdHigh()
|
||||
{
|
||||
return readRegister(_address, ADS1X15_REG_HIGH_THRESHOLD);
|
||||
};
|
||||
|
||||
int8_t ADS1X15::getError()
|
||||
{
|
||||
int8_t rv = _err;
|
||||
_err = ADS1X15_OK;
|
||||
return rv;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE
|
||||
//
|
||||
int16_t ADS1X15::_readADC(uint16_t readmode)
|
||||
{
|
||||
_requestADC(readmode);
|
||||
if (_mode == ADS1X15_MODE_SINGLE)
|
||||
{
|
||||
while ( isBusy() ) yield(); // wait for conversion; yield for ESP.
|
||||
}
|
||||
else
|
||||
{
|
||||
delay(_conversionDelay); // TODO needed in continuous mode?
|
||||
}
|
||||
return getValue();
|
||||
}
|
||||
|
||||
void ADS1X15::_requestADC(uint16_t readmode)
|
||||
{
|
||||
// write to register is needed in continuous mode as other flags can be changed
|
||||
uint16_t config = ADS1X15_OS_START_SINGLE; // bit 15 force wake up if needed
|
||||
config |= readmode; // bit 12-14
|
||||
config |= _gain; // bit 9-11
|
||||
config |= _mode; // bit 8
|
||||
config |= _datarate; // bit 5-7
|
||||
if (_compMode) config |= ADS1X15_COMP_MODE_WINDOW; // bit 4 comparator modi
|
||||
else config |= ADS1X15_COMP_MODE_TRADITIONAL;
|
||||
if (_compPol) config |= ADS1X15_COMP_POL_ACTIV_HIGH; // bit 3 ALERT active value
|
||||
else config |= ADS1X15_COMP_POL_ACTIV_LOW;
|
||||
if (_compLatch) config |= ADS1X15_COMP_LATCH;
|
||||
else config |= ADS1X15_COMP_NON_LATCH; // bit 2 ALERT latching
|
||||
config |= _compQueConvert; // bit 0..1 ALERT mode
|
||||
writeRegister(_address, ADS1X15_REG_CONFIG, config);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ADS1013
|
||||
//
|
||||
ADS1013::ADS1013(uint8_t address)
|
||||
{
|
||||
_address = address;
|
||||
_config = ADS_CONF_NOCOMP | ADS_CONF_NOGAIN | ADS_CONF_RES_12 | ADS_CONF_CHAN_1;
|
||||
_conversionDelay = ADS1015_CONVERSION_DELAY;
|
||||
_bitShift = 4;
|
||||
_maxPorts = 1;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ADS1014
|
||||
//
|
||||
ADS1014::ADS1014(uint8_t address)
|
||||
{
|
||||
_address = address;
|
||||
_config = ADS_CONF_COMP | ADS_CONF_GAIN | ADS_CONF_RES_12 | ADS_CONF_CHAN_1;
|
||||
_conversionDelay = ADS1015_CONVERSION_DELAY;
|
||||
_bitShift = 4;
|
||||
_maxPorts = 1;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ADS1015
|
||||
//
|
||||
ADS1015::ADS1015(uint8_t address)
|
||||
{
|
||||
_address = address;
|
||||
_config = ADS_CONF_COMP | ADS_CONF_GAIN | ADS_CONF_RES_12 | ADS_CONF_CHAN_4;
|
||||
_conversionDelay = ADS1015_CONVERSION_DELAY;
|
||||
_bitShift = 4;
|
||||
_maxPorts = 4;
|
||||
}
|
||||
|
||||
int16_t ADS1015::readADC_Differential_0_3()
|
||||
{
|
||||
return _readADC(ADS1X15_MUX_DIFF_0_3);
|
||||
}
|
||||
|
||||
int16_t ADS1015::readADC_Differential_1_3()
|
||||
{
|
||||
return _readADC(ADS1X15_MUX_DIFF_1_3);
|
||||
}
|
||||
|
||||
int16_t ADS1015::readADC_Differential_2_3()
|
||||
{
|
||||
return _readADC(ADS1X15_MUX_DIFF_2_3);
|
||||
}
|
||||
|
||||
int16_t ADS1015::readADC_Differential_0_2()
|
||||
{
|
||||
return readADC(2) - readADC(0);
|
||||
}
|
||||
|
||||
int16_t ADS1015::readADC_Differential_1_2()
|
||||
{
|
||||
return readADC(2) - readADC(1);;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void ADS1015::requestADC_Differential_0_3()
|
||||
{
|
||||
_requestADC(ADS1X15_MUX_DIFF_0_3);
|
||||
}
|
||||
|
||||
void ADS1015::requestADC_Differential_1_3()
|
||||
{
|
||||
_requestADC(ADS1X15_MUX_DIFF_1_3);
|
||||
}
|
||||
|
||||
void ADS1015::requestADC_Differential_2_3()
|
||||
{
|
||||
_requestADC(ADS1X15_MUX_DIFF_2_3);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ADS1113
|
||||
//
|
||||
ADS1113::ADS1113(uint8_t address)
|
||||
{
|
||||
_address = address;
|
||||
_config = ADS_CONF_NOCOMP | ADS_CONF_NOGAIN | ADS_CONF_RES_16 | ADS_CONF_CHAN_1;
|
||||
_conversionDelay = ADS1115_CONVERSION_DELAY;
|
||||
_bitShift = 0;
|
||||
_maxPorts = 1;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ADS1114
|
||||
//
|
||||
ADS1114::ADS1114(uint8_t address)
|
||||
{
|
||||
_address = address;
|
||||
_config = ADS_CONF_COMP | ADS_CONF_GAIN | ADS_CONF_RES_16 | ADS_CONF_CHAN_1;
|
||||
_conversionDelay = ADS1115_CONVERSION_DELAY;
|
||||
_bitShift = 0;
|
||||
_maxPorts = 1;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// ADS1115
|
||||
//
|
||||
ADS1115::ADS1115(uint8_t address)
|
||||
{
|
||||
_address = address;
|
||||
_config = ADS_CONF_COMP | ADS_CONF_GAIN | ADS_CONF_RES_16 | ADS_CONF_CHAN_4;
|
||||
_conversionDelay = ADS1115_CONVERSION_DELAY;
|
||||
_bitShift = 0;
|
||||
_maxPorts = 4;
|
||||
}
|
||||
|
||||
int16_t ADS1115::readADC_Differential_0_3()
|
||||
{
|
||||
return _readADC(ADS1X15_MUX_DIFF_0_3);
|
||||
}
|
||||
|
||||
int16_t ADS1115::readADC_Differential_1_3()
|
||||
{
|
||||
return _readADC(ADS1X15_MUX_DIFF_1_3);
|
||||
}
|
||||
|
||||
int16_t ADS1115::readADC_Differential_2_3()
|
||||
{
|
||||
return _readADC(ADS1X15_MUX_DIFF_2_3);
|
||||
}
|
||||
|
||||
int16_t ADS1115::readADC_Differential_0_2()
|
||||
{
|
||||
return readADC(2) - readADC(0);
|
||||
}
|
||||
|
||||
int16_t ADS1115::readADC_Differential_1_2()
|
||||
{
|
||||
return readADC(2) - readADC(1);;
|
||||
}
|
||||
|
||||
void ADS1115::requestADC_Differential_0_3()
|
||||
{
|
||||
_requestADC(ADS1X15_MUX_DIFF_0_3);
|
||||
}
|
||||
|
||||
void ADS1115::requestADC_Differential_1_3()
|
||||
{
|
||||
_requestADC(ADS1X15_MUX_DIFF_1_3);
|
||||
}
|
||||
|
||||
void ADS1115::requestADC_Differential_2_3()
|
||||
{
|
||||
_requestADC(ADS1X15_MUX_DIFF_2_3);
|
||||
}
|
||||
|
||||
// --- END OF FILE
|
209
libraries/ADS1x15/ADS1X15.h
Normal file
209
libraries/ADS1x15/ADS1X15.h
Normal file
@ -0,0 +1,209 @@
|
||||
#pragma once
|
||||
//
|
||||
// FILE: ADS1X15.H
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.7
|
||||
// DATE: 2013-03-24
|
||||
// PUPROSE: Arduino library for ADS1015 and ADS1115
|
||||
// URL: https://github.com/RobTillaart/ADS1X15
|
||||
//
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
|
||||
#define ADS1X15_LIB_VERSION "0.2.7"
|
||||
|
||||
// allow compile time default address
|
||||
// address in { 0x48, 0x49, 0x4A, 0x4B }, no test...
|
||||
#ifndef ADS1015_ADDRESS
|
||||
#define ADS1015_ADDRESS 0x48
|
||||
#endif
|
||||
|
||||
#ifndef ADS1115_ADDRESS
|
||||
#define ADS1115_ADDRESS 0x48
|
||||
#endif
|
||||
|
||||
|
||||
#define ADS1X15_OK 0
|
||||
#define ADS1X15_INVALID_VOLTAGE -100
|
||||
#define ADS1X15_INVALID_GAIN 0xFF
|
||||
#define ADS1X15_INVALID_MODE 0xFE
|
||||
|
||||
|
||||
class ADS1X15
|
||||
{
|
||||
public:
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
bool begin(uint8_t sda, uint8_t scl);
|
||||
#endif
|
||||
bool begin();
|
||||
bool isConnected();
|
||||
|
||||
// GAIN
|
||||
// 0 = ±6.144V default
|
||||
// 1 = ±4.096V
|
||||
// 2 = ±2.048V
|
||||
// 4 = ±1.024V
|
||||
// 8 = ±0.512V
|
||||
// 16 = ±0.256V
|
||||
void setGain(uint8_t gain = 0); // invalid values are mapped to 0 (default).
|
||||
uint8_t getGain(); // 0xFF == invalid gain error.
|
||||
|
||||
// both may return ADS1X15_INVALID_VOLTAGE if the gain is invalid.
|
||||
float toVoltage(int16_t val = 1); // converts raw to voltage
|
||||
float getMaxVoltage(); // -100 == invalid voltage error
|
||||
|
||||
// 0 = CONTINUOUS
|
||||
// 1 = SINGLE default
|
||||
void setMode(uint8_t mode = 1); // invalid values are mapped to 1 (default)
|
||||
uint8_t getMode(); // 0xFE == invalid mode error.
|
||||
|
||||
// 0 = slowest
|
||||
// 7 = fastest
|
||||
// 4 = default
|
||||
void setDataRate(uint8_t dataRate);// invalid values are mapped on 4 (default)
|
||||
uint8_t getDataRate(); // actual speed depends on device
|
||||
|
||||
int16_t readADC(uint8_t pin);
|
||||
int16_t readADC_Differential_0_1();
|
||||
|
||||
// used by continuous mode and async mode.
|
||||
int16_t getLastValue() { return getValue(); }; // will be obsolete in future
|
||||
int16_t getValue();
|
||||
|
||||
// ASYNC INTERFACE
|
||||
// requestADC(pin) -> isBusy() or isReady() -> getValue();
|
||||
// see examples
|
||||
void requestADC(uint8_t pin);
|
||||
void requestADC_Differential_0_1();
|
||||
bool isBusy();
|
||||
bool isReady() { return isBusy() == false; };
|
||||
|
||||
|
||||
// COMPARATOR
|
||||
// 0 = TRADITIONAL > high => on < low => off
|
||||
// else = WINDOW > high or < low => on between => off
|
||||
void setComparatorMode(uint8_t mode) { _compMode = mode == 0 ? 0 : 1; };
|
||||
uint8_t getComparatorMode() { return _compMode; };
|
||||
|
||||
// 0 = LOW (default)
|
||||
// else = HIGH
|
||||
void setComparatorPolarity(uint8_t pol) { _compPol = pol ? 0 : 1; };
|
||||
uint8_t getComparatorPolarity() { return _compPol; };
|
||||
|
||||
// 0 = NON LATCH
|
||||
// else = LATCH
|
||||
void setComparatorLatch(uint8_t latch) { _compLatch = latch ? 0 : 1; };
|
||||
uint8_t getComparatorLatch() { return _compLatch; };
|
||||
|
||||
// 0 = trigger alert after 1 conversion
|
||||
// 1 = trigger alert after 2 conversions
|
||||
// 2 = trigegr alert after 4 conversions
|
||||
// 3 = Disable comparator = default, also for all other values.
|
||||
void setComparatorQueConvert(uint8_t mode) { _compQueConvert = (mode < 3) ? mode : 3; };
|
||||
uint8_t getComparatorQueConvert() { return _compQueConvert; };
|
||||
|
||||
void setComparatorThresholdLow(int16_t lo);
|
||||
int16_t getComparatorThresholdLow();
|
||||
void setComparatorThresholdHigh(int16_t hi);
|
||||
int16_t getComparatorThresholdHigh();
|
||||
|
||||
int8_t getError();
|
||||
|
||||
protected:
|
||||
ADS1X15();
|
||||
|
||||
// CONFIGURATION
|
||||
// BIT DESCRIPTION
|
||||
// 0 # channels 0 == 1 1 == 4;
|
||||
// 1 0
|
||||
// 2 # resolution 0 == 12 1 == 16
|
||||
// 3 0
|
||||
// 4 has gain 0 = NO 1 = YES
|
||||
// 5 has comparator 0 = NO 1 = YES
|
||||
// 6 0
|
||||
// 7 0
|
||||
uint8_t _config;
|
||||
uint8_t _maxPorts;
|
||||
uint8_t _address;
|
||||
uint8_t _conversionDelay;
|
||||
uint8_t _bitShift;
|
||||
uint16_t _gain;
|
||||
uint16_t _mode;
|
||||
uint16_t _datarate;
|
||||
|
||||
// COMPARATOR vars
|
||||
// TODO merge these into one COMPARATOR MASK?
|
||||
// would speed up code in _requestADC() and save 3 bytes RAM.
|
||||
uint8_t _compMode = 0;
|
||||
uint8_t _compPol = 1;
|
||||
uint8_t _compLatch = 0;
|
||||
uint8_t _compQueConvert = 3;
|
||||
|
||||
int16_t _readADC(uint16_t readmode);
|
||||
void _requestADC(uint16_t readmode);
|
||||
|
||||
int8_t _err = ADS1X15_OK;
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Derived classes from ADS1X15
|
||||
//
|
||||
class ADS1013 : public ADS1X15
|
||||
{
|
||||
public:
|
||||
ADS1013(uint8_t Address = ADS1015_ADDRESS);
|
||||
};
|
||||
|
||||
class ADS1014 : public ADS1X15
|
||||
{
|
||||
public:
|
||||
ADS1014(uint8_t Address = ADS1015_ADDRESS);
|
||||
};
|
||||
|
||||
class ADS1015 : public ADS1X15
|
||||
{
|
||||
public:
|
||||
ADS1015(uint8_t Address = ADS1015_ADDRESS);
|
||||
int16_t readADC_Differential_0_3();
|
||||
int16_t readADC_Differential_1_3();
|
||||
int16_t readADC_Differential_2_3();
|
||||
int16_t readADC_Differential_0_2(); // not possible in async
|
||||
int16_t readADC_Differential_1_2(); // not possible in async
|
||||
void requestADC_Differential_0_3();
|
||||
void requestADC_Differential_1_3();
|
||||
void requestADC_Differential_2_3();
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Derived classes from ADS1X15
|
||||
//
|
||||
class ADS1113 : public ADS1X15
|
||||
{
|
||||
public:
|
||||
ADS1113(uint8_t address = ADS1115_ADDRESS);
|
||||
};
|
||||
|
||||
class ADS1114 : public ADS1X15
|
||||
{
|
||||
public:
|
||||
ADS1114(uint8_t address = ADS1115_ADDRESS);
|
||||
};
|
||||
|
||||
class ADS1115 : public ADS1X15
|
||||
{
|
||||
public:
|
||||
ADS1115(uint8_t address = ADS1115_ADDRESS);
|
||||
int16_t readADC_Differential_0_3();
|
||||
int16_t readADC_Differential_1_3();
|
||||
int16_t readADC_Differential_2_3();
|
||||
int16_t readADC_Differential_0_2(); // not possible in async
|
||||
int16_t readADC_Differential_1_2(); // not possible in async
|
||||
void requestADC_Differential_0_3();
|
||||
void requestADC_Differential_1_3();
|
||||
void requestADC_Differential_2_3();
|
||||
};
|
||||
|
||||
// --- END OF FILE ---
|
21
libraries/ADS1x15/LICENSE
Normal file
21
libraries/ADS1x15/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2013-2021 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
265
libraries/ADS1x15/README.md
Normal file
265
libraries/ADS1x15/README.md
Normal file
@ -0,0 +1,265 @@
|
||||
|
||||
[![Arduino CI](https://github.com/RobTillaart/ADS1X15/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
||||
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/ADS1X15/blob/master/LICENSE)
|
||||
[![GitHub release](https://img.shields.io/github/release/RobTillaart/ADS1X15.svg?maxAge=3600)](https://github.com/RobTillaart/ADS1X15/releases)
|
||||
|
||||
# ADS1X15
|
||||
|
||||
Arduino library for I2C ADC ADS1015, ADS1115,
|
||||
|
||||
## Description
|
||||
|
||||
This library should work for the devices mentioned below,
|
||||
although not all sensors support all functionality.
|
||||
|
||||
| Device | Channels | Resolution | Max sps | Comparator | ProgGainAMP | Notes |
|
||||
|:----:|:----:|:----:|:----:|:----:|:----:|:----|
|
||||
| ADS1013 | 1 | 12 | 3300 | N | N | |
|
||||
| ADS1014 | 1 | 12 | 3300 | Y | Y | |
|
||||
| ADS1015 | 4 | 12 | 3300 | Y | Y | |
|
||||
| ADS1113 | 1 | 16 | 860 | N | N | |
|
||||
| ADS1114 | 1 | 16 | 860 | Y | Y | |
|
||||
| ADS1115 | 4 | 16 | 860 | Y | Y | Tested |
|
||||
|
||||
As the 1015 and the 1115 are both 4 channels these are the most
|
||||
interesting from functionality point of view as these can also do
|
||||
differential measurement.
|
||||
|
||||
#### Note
|
||||
|
||||
This readme file is work in progress.
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
The address of the ADS1113/4/5 is determined by to which pin the ADDR
|
||||
is connected to:
|
||||
|
||||
| ADDR pin connected to | Address | Note |
|
||||
|:----:|:----:|:----:|
|
||||
| GND | 0x48 | default |
|
||||
| VDD | 0x49 | |
|
||||
| SDA | 0x4A | |
|
||||
| SCL | 0x4B | |
|
||||
|
||||
- **ADS1x15()** constructor, should not be used.
|
||||
- **ADS1013(address)** constructor
|
||||
- **ADS1014(address)** constructor
|
||||
- **ADS1015(address)** constructor
|
||||
- **ADS1113(address)** constructor
|
||||
- **ADS1114(address)** constructor
|
||||
- **ADS1115(address)** constructor
|
||||
|
||||
After construction the **ADS.begin()** need to be called. This will return false
|
||||
if an invalid address is used.
|
||||
The function **isConnected()** can be used to verify the reading of the ADS.
|
||||
|
||||
|
||||
#### Programmable Gain
|
||||
|
||||
- **setGain(gain)** set the gain value, indicating the maxVoltage that can be measured
|
||||
Adjusting the gain allows one to make more precise measurements.
|
||||
See table below.
|
||||
- **getGain()** returns the gain value (index).
|
||||
|
||||
| PGA value | Max Voltage | note |
|
||||
|:----:|:----:|:----:|
|
||||
| 0 | ±6.144V | default |
|
||||
| 1 | ±4.096V | |
|
||||
| 2 | ±2.048V | |
|
||||
| 4 | ±1.024V | |
|
||||
| 8 | ±0.512V | |
|
||||
| 16 | ±0.256V | |
|
||||
|
||||
- **getMaxVoltage()** returns the max voltage with the current gain.
|
||||
- **toVoltage(raw = 1)** converts a raw measurement to a voltage.
|
||||
Can be used for normal and differential measurements.
|
||||
The default value of 1 returns the conversion factor for any raw number.
|
||||
|
||||
The voltage factor can also be used to set HIGH and LOW threshold registers
|
||||
with a voltage in the comparator mode.
|
||||
Check the examples.
|
||||
|
||||
```cpp
|
||||
float f = ADS.toVoltage();
|
||||
ADS.setComparatorThresholdLow( 3.0 / f );
|
||||
ADS.setComparatorThresholdLow( 4.3 / f );
|
||||
```
|
||||
|
||||
#### Operational mode
|
||||
|
||||
The ADS sensor can operate in single shot or continuous mode.
|
||||
Depending on how often one needs a conversion one can tune the mode.
|
||||
- **setMode(mode)** 0 = CONTINUOUS, 1 = SINGLE (default)
|
||||
- **getMode()** returns current mode 0 or 1, or ADS1X15_INVALID_MODE = 0xFE.
|
||||
|
||||
|
||||
#### Datarate
|
||||
|
||||
- **setDataRate(dataRate)** Datarate depends on type of device.
|
||||
For all devices the index 0..7 can be used, see table below.
|
||||
Values above 7 ==> will be set to the default 4.
|
||||
- **getDataRate()** returns the current datarate (index).
|
||||
|
||||
The library has no means to convert this index to the actual numbers
|
||||
as that would take 32 bytes.
|
||||
|
||||
Datarate in samples per second, based on datasheet numbers.
|
||||
|
||||
| datarate | ADS101x | ADS 111x | Notes & remarks |
|
||||
|:----:|----:|----:|:----:|
|
||||
| 0 | 128 | 8 | slowest |
|
||||
| 1 | 250 | 16 | |
|
||||
| 2 | 490 | 32 | |
|
||||
| 3 | 920 | 64 | |
|
||||
| 4 | 1600 | 128 | default |
|
||||
| 5 | 2400 | 250 | |
|
||||
| 6 | 3300 | 475 | |
|
||||
| 7 | 3300 | 860 | fastest |
|
||||
|
||||
|
||||
#### ReadADC Single mode
|
||||
|
||||
Reading the ADC is very straightforward, the **readADC()** function handles
|
||||
all in one call. Under the hood it uses the asynchronuous calls.
|
||||
- **int16_t readADC(pin)** normal ADC functionality, pin = 0..3.
|
||||
If the pinnumber is out of range, this function will return 0.
|
||||
|
||||
To read the ADC in an asynchronuous way (e.g. to minimize blocking) one has to use three calls:
|
||||
- **requestADC(pin)** Start the conversion. pin = 0..3.
|
||||
- **isBusy()** Is the conversion not ready?
|
||||
- **isReady()** Is the conversion ready? (= wrapper around **isBusy()** )
|
||||
- **getValue()** Read the result of the conversion.
|
||||
|
||||
|
||||
in terms of code
|
||||
```cpp
|
||||
|
||||
void setup()
|
||||
{
|
||||
// other setup things here
|
||||
ADS.requestADC(pin);
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (ADS.isReady())
|
||||
{
|
||||
val = ADS.getValue();
|
||||
ADS.requestADC(pin); // request new conversion
|
||||
}
|
||||
// do other things here
|
||||
}
|
||||
|
||||
```
|
||||
See examples
|
||||
|
||||
## ReadADC Differential
|
||||
|
||||
For reading the ADC in a differential way there are 4 calls possible.
|
||||
- **readADC_Differential_0_1()** returns the difference between 2 ADC pins.
|
||||
- **readADC_Differential_0_3()** ADS1x15 only
|
||||
- **readADC_Differential_1_3()** ADS1x15 only
|
||||
- **readADC_Differential_2_3()** ADS1x15 only
|
||||
- **readADC_Differential_0_2()** ADS1x15 only - in software (no async equivalent)
|
||||
- **readADC_Differential_1_2()** ADS1x15 only - in software (no async equivalent)
|
||||
|
||||
The differential reading of the ADC can also be done with asynchronuous calls.
|
||||
- **requestADC_Differential_0_1()** starts conversion for differential reading
|
||||
- **requestADC_Differential_0_3()** ADS1x15 only
|
||||
- **requestADC_Differential_1_3()** ADS1x15 only
|
||||
- **requestADC_Differential_2_3()** ADS1x15 only
|
||||
|
||||
After one of these calls one need to call
|
||||
- **isBusy()** Is the conversion ready?
|
||||
- **getValue()** Read the result of the conversion.
|
||||
|
||||
|
||||
#### ReadADC continuous mode
|
||||
|
||||
To use the continuous mode one need three calls
|
||||
- **setMode(0)** 0 = CONTINUOUS, 1 = SINGLE (default)
|
||||
- **readADC()** or **requestADC()** to get the continuous mode started.
|
||||
- **getValue()** to return the last value read by the device.
|
||||
Calling this over and over again can give the same value multiple times.
|
||||
|
||||
By using **isBusy()** or **isReady()** one can wait until new data is available.
|
||||
Or one can use the **ALERT/RDY** pin to trigger via hardware the readyness of the conversion.
|
||||
|
||||
See examples.
|
||||
|
||||
#### Threshold registers ==> mode RDY pin
|
||||
|
||||
If the thresholdHigh is set to 0x0100 and the thresholdLow to 0x0000
|
||||
the **ALERT/RDY** pin is triggered when a conversion is ready.
|
||||
- **setComparatorThresholdLow(0x0000)**
|
||||
- **setComparatorThresholdHigh(0x0100)**
|
||||
|
||||
See examples.
|
||||
|
||||
## Comparator
|
||||
|
||||
Please read Page 15 of the datasheet as the behavior of the
|
||||
comparator is not trivial.
|
||||
|
||||
#### Comparator Mode
|
||||
|
||||
When configured as a **TRADITIONAL** comparator, the **ALERT/RDY** pin asserts
|
||||
(active low by default) when conversion data exceed the limit set in the
|
||||
high threshold register. The comparator then deasserts when the input
|
||||
signal falls below the low threshold register value.
|
||||
|
||||
If the comparator **LATCH** is set, the **ALERT/RDY** pin asserts and it will be
|
||||
reset after reading the sensor (conversion register) again.
|
||||
*An SMB alert command (00011001) on the I2C bus will also reset the alert state.*
|
||||
*Not implemented in the library (yet)*
|
||||
|
||||
In **WINDOW** comparator mode, the **ALERT/RDY** pin asserts if conversion data exceeds
|
||||
the high threshold register or falls below the low threshold register.
|
||||
In this mode the alert is held if the **LATCH** is set. This is similar as above.
|
||||
|
||||
#### Polarity
|
||||
|
||||
Default state of the **ALERT/RDY** pin is **LOW**, can be to set **HIGH**.
|
||||
|
||||
#### Latch
|
||||
|
||||
Holds the **ALERT/RDY** to **HIGH** (or **LOW** depending on polarity) after triggered
|
||||
even if actual value has been 'restored to normal' value.
|
||||
|
||||
#### QueConvert
|
||||
|
||||
Set the number of conversions before trigger activates.
|
||||
The **setComparatorQueConvert(uint8_t mode)** is used to set the number of
|
||||
conversions that exceed the threshold before the **ALERT/RDY** pin is set **HIGH**.
|
||||
A value of 3 (or above) effectively disables the comparator. See table below.
|
||||
|
||||
| value | meaning | notes |
|
||||
|:----:|:----|:----|
|
||||
| 0 | trigger alert after 1 conversion | |
|
||||
| 1 | trigger alert after 2 conversions | |
|
||||
| 2 | trigegr alert after 4 conversions | |
|
||||
| 3 | Disable comparator | default |
|
||||
|
||||
#### Threshold registers comparator mode
|
||||
|
||||
Depending on the comparator mode **TRADITIONAL** or **WINDOW** the thresholds registers
|
||||
mean something different see - Comparator Mode above or datasheet.
|
||||
- **setComparatorThresholdLow(lo)** set the low threshold; take care the hi >= lo
|
||||
- **setComparatorThresholdHigh(hi)** set the high threshold; take care the hi >= lo
|
||||
- **getComparatorThresholdLow()** returns set value
|
||||
- **getComparatorThresholdHigh()** returns set value
|
||||
|
||||
|
||||
## Future ideas & improvements
|
||||
|
||||
- Improve documentation
|
||||
- more examples?
|
||||
- SMB alert command (00011001) on I2C bus?
|
||||
- implement missing Differential reads in software.
|
||||
- testing....
|
||||
|
||||
## Operation
|
||||
|
||||
See examples
|
47
libraries/ADS1x15/examples/ADS_continuous/ADS_continuous.ino
Normal file
47
libraries/ADS1x15/examples/ADS_continuous/ADS_continuous.ino
Normal file
@ -0,0 +1,47 @@
|
||||
//
|
||||
// FILE: ADS_continuous.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: read analog input
|
||||
//
|
||||
|
||||
// test
|
||||
// connect 1 potmeter
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x (connect to AIN0).
|
||||
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
// choose you sensor
|
||||
// ADS1013 ADS(0x48);
|
||||
// ADS1014 ADS(0x48);
|
||||
// ADS1015 ADS(0x48);
|
||||
// ADS1113 ADS(0x48);
|
||||
// ADS1114 ADS(0x48);
|
||||
ADS1115 ADS(0x48);
|
||||
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
ADS.begin();
|
||||
ADS.setGain(0); // 6.144 volt
|
||||
ADS.setDataRate(7); // fast
|
||||
ADS.setMode(0); // continuous mode
|
||||
ADS.readADC(0); // first read to trigger
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
Serial.println(ADS.getValue());
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,94 @@
|
||||
//
|
||||
// FILE: ADS_continuous_4_channel.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.2
|
||||
// PURPOSE: read multiple analog inputs continuously
|
||||
// interrupt driven to catch all conversions.
|
||||
//
|
||||
|
||||
// test
|
||||
// connect multiple potmeters
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x - connect to AIN0..4.
|
||||
//
|
||||
// for the test it is good to have AIN3 connected to 5V and AIN4 to GND
|
||||
// so one can see these as references in the output.
|
||||
//
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
// choose you sensor
|
||||
// ADS1013 ADS(0x48);
|
||||
// ADS1014 ADS(0x48);
|
||||
// ADS1015 ADS(0x48);
|
||||
// ADS1113 ADS(0x48);
|
||||
// ADS1114 ADS(0x48);
|
||||
ADS1115 ADS(0x48);
|
||||
|
||||
volatile bool RDY = false;
|
||||
uint8_t channel = 0;
|
||||
int16_t val[4] = { 0, 0, 0, 0 };
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
pinMode(2, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(2), adsReady, RISING);
|
||||
|
||||
ADS.begin();
|
||||
ADS.setGain(0); // 6.144 volt
|
||||
ADS.setDataRate(7); // slow
|
||||
|
||||
// SET ALERT RDY PIN
|
||||
ADS.setComparatorThresholdHigh(0x8000);
|
||||
ADS.setComparatorThresholdLow(0x0000);
|
||||
ADS.setComparatorQueConvert(0);
|
||||
|
||||
// SET INTERRUPT HANDLER TO CATCH CONVERSION READY
|
||||
pinMode(2, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(2), adsReady, RISING);
|
||||
|
||||
ADS.setMode(0); // continuous mode
|
||||
ADS.readADC(channel); // trigger first read
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
handleConversion();
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
Serial.print(val[i]);
|
||||
Serial.print('\t');
|
||||
handleConversion();
|
||||
}
|
||||
Serial.println();
|
||||
delay(100);
|
||||
}
|
||||
|
||||
void adsReady()
|
||||
{
|
||||
RDY = true;
|
||||
}
|
||||
|
||||
void handleConversion()
|
||||
{
|
||||
if (RDY)
|
||||
{
|
||||
// save the value
|
||||
val[channel] = ADS.getValue();
|
||||
// request next channel
|
||||
channel++;
|
||||
if (channel >= 4) channel = 0;
|
||||
ADS.readADC(channel);
|
||||
RDY = false;
|
||||
}
|
||||
}
|
||||
// -- END OF FILE --
|
@ -0,0 +1,126 @@
|
||||
//
|
||||
// FILE: ADS_continuous_8_channel.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: read multiple analog inputs continuously
|
||||
// interrupt driven to catch all conversions.
|
||||
//
|
||||
|
||||
// test
|
||||
// connect multiple potmeters to 2 ADS1115
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x - connect to AIN0..4.
|
||||
//
|
||||
// for the test it is good to have AIN3 connected to 5V and AIN4 to GND
|
||||
// so one can see these as references in the output.
|
||||
//
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
// adjust addresses if needed
|
||||
ADS1115 ADS_1(0x49);
|
||||
ADS1115 ADS_2(0x48);
|
||||
|
||||
volatile bool RDY_1 = false;
|
||||
volatile bool RDY_2 = false;
|
||||
uint8_t channel_1 = 0;
|
||||
uint8_t channel_2 = 0;
|
||||
int16_t val[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
// SETUP FIRST ADS1115
|
||||
ADS_1.begin();
|
||||
ADS_1.setGain(0); // 6.144 volt
|
||||
ADS_1.setDataRate(7);
|
||||
|
||||
// SET ALERT RDY PIN
|
||||
ADS_1.setComparatorThresholdHigh(0x8000);
|
||||
ADS_1.setComparatorThresholdLow(0x0000);
|
||||
ADS_1.setComparatorQueConvert(0);
|
||||
|
||||
// SET INTERRUPT HANDLER TO CATCH CONVERSION READY
|
||||
pinMode(2, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(2), adsReady_1, RISING);
|
||||
|
||||
ADS_1.setMode(0); // continuous mode
|
||||
ADS_1.readADC(channel_1); // trigger first read
|
||||
|
||||
|
||||
// SETUP SECOND ADS1115
|
||||
ADS_2.begin();
|
||||
ADS_2.setGain(0); // 6.144 volt
|
||||
ADS_2.setDataRate(7);
|
||||
|
||||
// SET ALERT RDY PIN
|
||||
ADS_2.setComparatorThresholdHigh(0x8000);
|
||||
ADS_2.setComparatorThresholdLow(0x0000);
|
||||
ADS_2.setComparatorQueConvert(0);
|
||||
|
||||
// SET INTERRUPT HANDLER TO CATCH CONVERSION READY
|
||||
pinMode(3, INPUT_PULLUP);
|
||||
attachInterrupt(digitalPinToInterrupt(3), adsReady_2, RISING);
|
||||
|
||||
ADS_2.setMode(0); // continuous mode
|
||||
ADS_2.readADC(channel_2); // trigger first read
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
handleConversion();
|
||||
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
Serial.print(val[i]);
|
||||
Serial.print('\t');
|
||||
handleConversion();
|
||||
}
|
||||
Serial.println();
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// catch interrupt and set flag
|
||||
void adsReady_1()
|
||||
{
|
||||
RDY_1 = true;
|
||||
}
|
||||
|
||||
void adsReady_2()
|
||||
{
|
||||
RDY_2 = true;
|
||||
}
|
||||
|
||||
// handle conversions that are ready
|
||||
void handleConversion()
|
||||
{
|
||||
if (RDY_1)
|
||||
{
|
||||
// save the last value
|
||||
val[channel_1] = ADS_1.getValue();
|
||||
// request next channel
|
||||
channel_1++;
|
||||
if (channel_1 >= 4) channel_1 = 0;
|
||||
ADS_1.readADC(channel_1);
|
||||
RDY_1 = false;
|
||||
}
|
||||
if (RDY_2)
|
||||
{
|
||||
// save the last value
|
||||
val[4 + channel_2] = ADS_2.getValue();
|
||||
// request next channel
|
||||
channel_2++;
|
||||
if (channel_2 >= 4) channel_2 = 0;
|
||||
ADS_2.readADC(channel_2);
|
||||
RDY_2 = false;
|
||||
}
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,64 @@
|
||||
//
|
||||
// FILE: ADS_differential.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: read differential
|
||||
//
|
||||
|
||||
// test 1
|
||||
// connect 2 potmeters in series
|
||||
//
|
||||
// GND ---[ x ]------[ y ]---- 5V
|
||||
// | |
|
||||
//
|
||||
// measure at x and y (connect to AIN0 and AIN1).
|
||||
// x should be lower or equal to y
|
||||
|
||||
// test 2
|
||||
// connect 2 potmeters parallel
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// GND ---[ y ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x and y (connect to AIN0 and AIN1).
|
||||
// range from -VDD .. +VDD are possible
|
||||
|
||||
#include <ADS1X15.h>
|
||||
|
||||
ADS1115 ADS(0x48);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
ADS.begin();
|
||||
ADS.setGain(0);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
int16_t val_01 = ADS.readADC_Differential_0_1();
|
||||
int16_t val_03 = ADS.readADC_Differential_0_3();
|
||||
int16_t val_13 = ADS.readADC_Differential_1_3();
|
||||
int16_t val_23 = ADS.readADC_Differential_2_3();
|
||||
float volts_01 = ADS.toVoltage(val_01);
|
||||
float volts_03 = ADS.toVoltage(val_03);
|
||||
float volts_13 = ADS.toVoltage(val_13);
|
||||
float volts_23 = ADS.toVoltage(val_23);
|
||||
|
||||
Serial.print("\tval_01: "); Serial.print(val_01); Serial.print("\t"); Serial.println(volts_01, 3);
|
||||
Serial.print("\tval_03: "); Serial.print(val_03); Serial.print("\t"); Serial.println(volts_03, 3);
|
||||
Serial.print("\tval_13: "); Serial.print(val_13); Serial.print("\t"); Serial.println(volts_13, 3);
|
||||
Serial.print("\tval_23: "); Serial.print(val_23); Serial.print("\t"); Serial.println(volts_23, 3);
|
||||
Serial.println();
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
46
libraries/ADS1x15/examples/ADS_minimum/ADS_minimum.ino
Normal file
46
libraries/ADS1x15/examples/ADS_minimum/ADS_minimum.ino
Normal file
@ -0,0 +1,46 @@
|
||||
//
|
||||
// FILE: ADS_minimum.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: read analog input
|
||||
//
|
||||
|
||||
// test
|
||||
// connect 1 potmeter
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x (connect to AIN0).
|
||||
|
||||
// view with Serial Plotter
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
// choose you sensor
|
||||
// ADS1013 ADS(0x48);
|
||||
// ADS1014 ADS(0x48);
|
||||
// ADS1015 ADS(0x48);
|
||||
// ADS1113 ADS(0x48);
|
||||
// ADS1114 ADS(0x48);
|
||||
ADS1115 ADS(0x48);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
ADS.begin();
|
||||
ADS.setGain(0); // 6.144 volt
|
||||
Serial.println("Voltage");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
int16_t raw = ADS.readADC(0);
|
||||
Serial.println(ADS.toVoltage(raw), 3);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,92 @@
|
||||
//
|
||||
// FILE: ADS_performance.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: read analog input
|
||||
//
|
||||
|
||||
// test
|
||||
// connect 1 potmeter
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x (connect to AIN0).
|
||||
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
// choose you sensor
|
||||
// ADS1013 ADS(0x48);
|
||||
// ADS1014 ADS(0x48);
|
||||
// ADS1015 ADS(0x48);
|
||||
// ADS1113 ADS(0x48);
|
||||
// ADS1114 ADS(0x48);
|
||||
ADS1115 ADS(0x48);
|
||||
|
||||
uint32_t start, d1, d2;
|
||||
int x;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
ADS.begin();
|
||||
ADS.setGain(0); // 6.144 volt
|
||||
|
||||
for (int dr = 0; dr < 8; dr++)
|
||||
{
|
||||
ADS.setDataRate(dr);
|
||||
Serial.print("DR:\t");
|
||||
Serial.println(dr);
|
||||
|
||||
test_single_shot();
|
||||
test_continuous();
|
||||
|
||||
Serial.print("\t\tFACTOR:\t");
|
||||
Serial.println(1.0 * d1 / d2);
|
||||
}
|
||||
|
||||
Serial.println("\nDone...");
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
void test_single_shot()
|
||||
{
|
||||
Serial.print(__FUNCTION__);
|
||||
|
||||
ADS.setMode(1);
|
||||
start = micros();
|
||||
x = ADS.readADC(0);
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
x = ADS.readADC(0);
|
||||
}
|
||||
d1 = micros() - start;
|
||||
Serial.print("\t");
|
||||
Serial.println(d1);
|
||||
}
|
||||
|
||||
void test_continuous()
|
||||
{
|
||||
Serial.print(__FUNCTION__);
|
||||
|
||||
ADS.setMode(0);
|
||||
start = micros();
|
||||
x = ADS.readADC(0);
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
x = ADS.getValue();
|
||||
}
|
||||
d2 = micros() - start;
|
||||
Serial.print("\t\t");
|
||||
Serial.println(d2);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
51
libraries/ADS1x15/examples/ADS_read/ADS_read.ino
Normal file
51
libraries/ADS1x15/examples/ADS_read/ADS_read.ino
Normal file
@ -0,0 +1,51 @@
|
||||
//
|
||||
// FILE: ADS_read.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.2.1
|
||||
// PURPOSE: read analog inputs - straightforward.
|
||||
//
|
||||
|
||||
// test
|
||||
// connect 1 potmeter per port.
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x (connect to AIN0).
|
||||
//
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
ADS1115 ADS(0x48);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
ADS.begin();
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
ADS.setGain(0);
|
||||
|
||||
int16_t val_0 = ADS.readADC(0);
|
||||
int16_t val_1 = ADS.readADC(1);
|
||||
int16_t val_2 = ADS.readADC(2);
|
||||
int16_t val_3 = ADS.readADC(3);
|
||||
|
||||
float f = ADS.toVoltage(1); // voltage factor
|
||||
|
||||
Serial.print("\tAnalog0: "); Serial.print(val_0); Serial.print('\t'); Serial.println(val_0 * f, 3);
|
||||
Serial.print("\tAnalog1: "); Serial.print(val_1); Serial.print('\t'); Serial.println(val_1 * f, 3);
|
||||
Serial.print("\tAnalog2: "); Serial.print(val_2); Serial.print('\t'); Serial.println(val_2 * f, 3);
|
||||
Serial.print("\tAnalog3: "); Serial.print(val_3); Serial.print('\t'); Serial.println(val_3 * f, 3);
|
||||
Serial.println();
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
62
libraries/ADS1x15/examples/ADS_read_RDY/ADS_read_RDY.ino
Normal file
62
libraries/ADS1x15/examples/ADS_read_RDY/ADS_read_RDY.ino
Normal file
@ -0,0 +1,62 @@
|
||||
//
|
||||
// FILE: ADS_read_RDY.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: read analog inputs - straightforward.
|
||||
//
|
||||
|
||||
// test
|
||||
// connect 1 potmeter per port.
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x (connect to AIN0).
|
||||
//
|
||||
|
||||
// EXPERIMENTAL
|
||||
//
|
||||
// The RDY pin (or ALERT Pin) is triggered when conversion is ready
|
||||
//
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
ADS1115 ADS(0x48);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
ADS.begin();
|
||||
ADS.setGain(0); // 6.144 volt
|
||||
ADS.setDataRate(7); // fast
|
||||
ADS.setMode(1); // continuous mode
|
||||
ADS.readADC(0); // first read to trigger
|
||||
|
||||
// set the thresholds to Trigger RDY pin
|
||||
ADS.setComparatorThresholdLow(0x0000);
|
||||
ADS.setComparatorThresholdHigh(0x0200);
|
||||
ADS.setComparatorQueConvert(0); // enable RDY pin !!
|
||||
ADS.setComparatorLatch(0);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
ADS.setGain(0);
|
||||
|
||||
int16_t val_0 = ADS.readADC(0);
|
||||
|
||||
float f = ADS.toVoltage(1); // voltage factor
|
||||
|
||||
Serial.print("\tAnalog0: ");
|
||||
Serial.print(val_0);
|
||||
Serial.print('\t');
|
||||
Serial.println(val_0 * f, 3);
|
||||
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
50
libraries/ADS1x15/examples/ADS_read_async/ADS_read_async.ino
Normal file
50
libraries/ADS1x15/examples/ADS_read_async/ADS_read_async.ino
Normal file
@ -0,0 +1,50 @@
|
||||
//
|
||||
// FILE: ADS_read_async.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: read analog inputs - asynchronous
|
||||
//
|
||||
|
||||
// test
|
||||
// connect 1 potmeter per port.
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x (connect to AIN0).
|
||||
//
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
ADS1115 ADS(0x48);
|
||||
float f = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
ADS.begin();
|
||||
ADS.setGain(0);
|
||||
f = ADS.toVoltage(); // voltage factor
|
||||
ADS.requestADC(0);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (ADS.isBusy() == false)
|
||||
{
|
||||
int16_t val_0 = ADS.getValue();
|
||||
ADS.requestADC(0); // request a new one
|
||||
Serial.print("\tAnalog0: ");
|
||||
Serial.print(val_0);
|
||||
Serial.print('\t');
|
||||
Serial.println(val_0 * f, 3);
|
||||
}
|
||||
// simulate other tasks...
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,62 @@
|
||||
//
|
||||
// FILE: ADS_read_async_rdy.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: read analog inputs - straightforward.
|
||||
//
|
||||
|
||||
// test
|
||||
// connect 1 potmeter per port.
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x (connect to AIN0).
|
||||
//
|
||||
|
||||
// EXPERIMENTAL
|
||||
//
|
||||
// The RDY pin (or ALERT Pin) is triggered when conversion is ready
|
||||
//
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
ADS1115 ADS(0x48);
|
||||
float f = 0;
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
ADS.begin();
|
||||
ADS.setGain(0); // 6.144 volt
|
||||
ADS.setDataRate(0); // slow so the led blinks visible for the eye.
|
||||
f = ADS.toVoltage(); // voltage factor
|
||||
ADS.requestADC(0);
|
||||
|
||||
// set the thresholds to Trigger RDY pin
|
||||
ADS.setComparatorThresholdLow(0x0000);
|
||||
ADS.setComparatorThresholdHigh(0x0200);
|
||||
ADS.setComparatorQueConvert(0); // enable RDY pin !!
|
||||
ADS.setComparatorLatch(0);
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
if (ADS.isReady())
|
||||
{
|
||||
int16_t val_0 = ADS.getValue();
|
||||
ADS.requestADC(0); // request a new one
|
||||
Serial.print("\tAnalog0: ");
|
||||
Serial.print(val_0);
|
||||
Serial.print('\t');
|
||||
Serial.println(val_0 * f, 3);
|
||||
}
|
||||
// simulate other tasks...
|
||||
delay(2000);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
@ -0,0 +1,82 @@
|
||||
//
|
||||
// FILE: ADS_read_comparator_1.ino
|
||||
// AUTHOR: Rob.Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// PURPOSE: read analog inputs - straightforward.
|
||||
//
|
||||
|
||||
// test
|
||||
// connect 1 potmeter per port.
|
||||
//
|
||||
// GND ---[ x ]------ 5V
|
||||
// |
|
||||
//
|
||||
// measure at x (connect to AIN0).
|
||||
//
|
||||
//
|
||||
// GND ---[LED]---[ALERT_PIN]---[ R ]--- 5V
|
||||
//
|
||||
// Connect a LED (+ resistor) to ALERT PIN
|
||||
// and see it trigger at configured way by the comparator.
|
||||
//
|
||||
|
||||
|
||||
#include "ADS1X15.h"
|
||||
|
||||
ADS1115 ADS(0x48);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Serial.begin(115200);
|
||||
Serial.println(__FILE__);
|
||||
Serial.print("ADS1X15_LIB_VERSION: ");
|
||||
Serial.println(ADS1X15_LIB_VERSION);
|
||||
|
||||
ADS.begin();
|
||||
|
||||
// change if needed.
|
||||
ADS.setComparatorMode(1); // 0 = TRADITIONAL 1 = WINDOW
|
||||
|
||||
ADS.setComparatorPolarity(0); // 0 = LOW (default) 1 = HIGH
|
||||
|
||||
// note NON-LATCH gives only a short pulse
|
||||
ADS.setComparatorLatch(1); // 0 = NON LATCH 1 = LATCH
|
||||
|
||||
ADS.setComparatorQueConvert(0); // 0 = trigger alert after 1 conversion
|
||||
|
||||
// set the thresholds as a number...
|
||||
// ADS.setComparatorThresholdLow(5000); // change if needed
|
||||
// ADS.setComparatorThresholdHigh(20000); // change if needed
|
||||
|
||||
// set the threshold as a voltage by using the voltage factor.
|
||||
float f = ADS.toVoltage(1); // voltage factor
|
||||
ADS.setComparatorThresholdLow(1.234 / f); // convert volts to number needed
|
||||
ADS.setComparatorThresholdHigh(3.142 / f); // convert volts to number needed
|
||||
|
||||
Serial.println(ADS.getComparatorThresholdLow());
|
||||
Serial.println(ADS.getComparatorThresholdHigh());
|
||||
|
||||
}
|
||||
|
||||
void loop()
|
||||
{
|
||||
ADS.setGain(0);
|
||||
|
||||
int16_t val_0 = ADS.readADC(0);
|
||||
|
||||
float f = ADS.toVoltage(1); // voltage factor
|
||||
|
||||
Serial.print("\tAnalog0: ");
|
||||
Serial.print(val_0);
|
||||
Serial.print('\t');
|
||||
Serial.print(val_0 * f, 3);
|
||||
Serial.print('\t');
|
||||
Serial.print(ADS.getComparatorThresholdLow() * f, 3);
|
||||
Serial.print('\t');
|
||||
Serial.print(ADS.getComparatorThresholdHigh() * f, 3);
|
||||
Serial.println();
|
||||
|
||||
delay(100);
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
62
libraries/ADS1x15/keywords.txt
Normal file
62
libraries/ADS1x15/keywords.txt
Normal file
@ -0,0 +1,62 @@
|
||||
# Syntax Coloring Map For ADS1X15
|
||||
|
||||
# Datatypes (KEYWORD1)
|
||||
ADS1X13 KEYWORD1
|
||||
ADS1014 KEYWORD1
|
||||
ADS1015 KEYWORD1
|
||||
ADS1015 KEYWORD1
|
||||
ADS1113 KEYWORD1
|
||||
ADS1114 KEYWORD1
|
||||
ADS1115 KEYWORD1
|
||||
|
||||
|
||||
# Methods and Functions (KEYWORD2)
|
||||
begin KEYWORD2
|
||||
isBusy KEYWORD2
|
||||
isReady() KEYWORD2
|
||||
isConnected KEYWORD2
|
||||
|
||||
setGain KEYWORD2
|
||||
getGain KEYWORD2
|
||||
toVoltage KEYWORD2
|
||||
getMaxVoltage KEYWORD2
|
||||
setMode KEYWORD2
|
||||
getMode KEYWORD2
|
||||
setDataRate KEYWORD2
|
||||
getDataRate KEYWORD2
|
||||
|
||||
readADC KEYWORD2
|
||||
readADC_Differential_0_1 KEYWORD2
|
||||
readADC_Differential_0_3 KEYWORD2
|
||||
readADC_Differential_1_3 KEYWORD2
|
||||
readADC_Differential_2_3 KEYWORD2
|
||||
getValue KEYWORD2
|
||||
|
||||
setComparatorMode KEYWORD2
|
||||
getComparatorMode KEYWORD2
|
||||
setComparatorPolarity KEYWORD2
|
||||
getComparatorPolarity KEYWORD2
|
||||
setComparatorLatch KEYWORD2
|
||||
getComparatorLatch KEYWORD2
|
||||
setComparatorQueConvert KEYWORD2
|
||||
getComparatorQueConvert KEYWORD2
|
||||
setComparatorThresholdLow KEYWORD2
|
||||
getComparatorThresholdLow KEYWORD2
|
||||
setComparatorThresholdHigh KEYWORD2
|
||||
getComparatorThresholdHigh KEYWORD2
|
||||
|
||||
getError KEYWORD2
|
||||
|
||||
# ASYNC INTERFACE
|
||||
|
||||
requestADC KEYWORD2
|
||||
requestADC_Differential_0_1 KEYWORD2
|
||||
requestADC_Differential_0_3 KEYWORD2
|
||||
requestADC_Differential_1_3 KEYWORD2
|
||||
requestADC_Differential_2_3 KEYWORD2
|
||||
|
||||
|
||||
# Constants (LITERAL1)
|
||||
ADS1X15_LIB_VERSION LITERAL1
|
||||
ADS1X15_INVALID_VOLTAGE LITERAL1
|
||||
ADS1X15_INVALID_GAIN LITERAL1
|
21
libraries/ADS1x15/library.json
Normal file
21
libraries/ADS1x15/library.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "ADS1X15",
|
||||
"keywords": "ADS1013, ADS1014, ADS1015, ADS1113, ADS1114, ADS1115, I2C, ADC",
|
||||
"description": "Arduino library for ADS1015 - I2C 12 bit ADC and ADS1115 I2C 16 bit ADC",
|
||||
"authors":
|
||||
[
|
||||
{
|
||||
"name": "Rob Tillaart",
|
||||
"email": "Rob.Tillaart@gmail.com",
|
||||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/ADS1X15"
|
||||
},
|
||||
"version":"0.2.7",
|
||||
"frameworks": "*",
|
||||
"platforms": "*"
|
||||
}
|
11
libraries/ADS1x15/library.properties
Normal file
11
libraries/ADS1x15/library.properties
Normal file
@ -0,0 +1,11 @@
|
||||
name=ADS1X15
|
||||
version=0.2.7
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=Arduino library for ADS1015 - I2C 12 bit ADC and ADS1115 I2C 16 bit ADC
|
||||
paragraph=Should work for ADS1013, ADS1014, ADS1113 and ADS1114
|
||||
category=Sensors
|
||||
url=https://github.com/RobTillaart/ADS1X15
|
||||
architectures=*
|
||||
includes=ADS1X15.h
|
||||
depends=
|
81
libraries/ADS1x15/test/unit_test_001.cpp
Normal file
81
libraries/ADS1x15/test/unit_test_001.cpp
Normal file
@ -0,0 +1,81 @@
|
||||
//
|
||||
// FILE: unit_test_001.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.0
|
||||
// DATE: 2020-12-03
|
||||
// PURPOSE: unit tests for the SHT31 temperature and humidity sensor
|
||||
// https://github.com/RobTillaart/ADS1X15
|
||||
//
|
||||
|
||||
// supported assertions
|
||||
// ----------------------------
|
||||
// assertEqual(expected, actual)
|
||||
// assertNotEqual(expected, actual)
|
||||
// assertLess(expected, actual)
|
||||
// assertMore(expected, actual)
|
||||
// assertLessOrEqual(expected, actual)
|
||||
// assertMoreOrEqual(expected, actual)
|
||||
// assertTrue(actual)
|
||||
// assertFalse(actual)
|
||||
// assertNull(actual)
|
||||
|
||||
#include <ArduinoUnitTests.h>
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "ADS1X15.h"
|
||||
|
||||
|
||||
unittest_setup()
|
||||
{
|
||||
}
|
||||
|
||||
unittest_teardown()
|
||||
{
|
||||
}
|
||||
|
||||
unittest(test_begin)
|
||||
{
|
||||
ADS1115 ADS(0x48);
|
||||
assertTrue(ADS.begin());
|
||||
assertTrue(ADS.isConnected());
|
||||
assertTrue(ADS.isBusy());
|
||||
}
|
||||
|
||||
unittest(test_gain)
|
||||
{
|
||||
ADS1115 ADS(0x48);
|
||||
assertTrue(ADS.begin());
|
||||
|
||||
assertEqual(0, ADS.getGain());
|
||||
int gains[6] = { 0,1,2,4,8,16 };
|
||||
for (int i = 0; i < 6; i++)
|
||||
{
|
||||
ADS.setGain(gains[i]);
|
||||
assertEqual(gains[i], ADS.getGain());
|
||||
}
|
||||
|
||||
ADS.setGain(42);
|
||||
assertEqual(0, ADS.getGain());
|
||||
}
|
||||
|
||||
unittest(test_Voltage)
|
||||
{
|
||||
ADS1115 ADS(0x48);
|
||||
assertTrue(ADS.begin());
|
||||
|
||||
// should test all values?
|
||||
ADS.setGain(0);
|
||||
float volts = ADS.getMaxVoltage();
|
||||
float delta = abs(6.144 - volts);
|
||||
assertMoreOrEqual(0.001, delta);
|
||||
|
||||
ADS.setGain(16);
|
||||
volts = ADS.getMaxVoltage();
|
||||
delta = abs(0.256 - volts);
|
||||
assertMoreOrEqual(0.001, delta);
|
||||
}
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
// --------
|
7
libraries/ADT7470/.arduino-ci.yml
Normal file
7
libraries/ADT7470/.arduino-ci.yml
Normal file
@ -0,0 +1,7 @@
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
- uno
|
||||
- leonardo
|
||||
- due
|
||||
- zero
|
13
libraries/ADT7470/.github/workflows/arduino_test_runner.yml
vendored
Normal file
13
libraries/ADT7470/.github/workflows/arduino_test_runner.yml
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
---
|
||||
name: Arduino CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
arduino_ci:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Arduino-CI/action@master
|
||||
# Arduino-CI/action@v0.1.1
|
477
libraries/ADT7470/ADT7470.cpp
Normal file
477
libraries/ADT7470/ADT7470.cpp
Normal file
@ -0,0 +1,477 @@
|
||||
//
|
||||
// FILE: ADT7470.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.2
|
||||
// PURPOSE: Arduino library for I2C ADT7470 Fan Monitoring
|
||||
// URL: https://github.com/RobTillaart/ADT7470
|
||||
// http://forum.arduino.cc/index.php?topic=363218.0
|
||||
//
|
||||
// HISTORY:
|
||||
// 0.0.00 2015-12-02 initial version
|
||||
// 0.0.01 2015-12-03 first beta
|
||||
// 0.1.0 2020-07-15 major refactor - first public version
|
||||
// 0.1.1 2020-08 fixes after testing
|
||||
// 0.1.2 2020-12-09 arduino-ci
|
||||
|
||||
#include "ADT7470.h"
|
||||
|
||||
|
||||
// CONFIG REGISTER 1
|
||||
#define ADT7470_CONFIG_REGISTER_1 0x40
|
||||
// bits
|
||||
#define ADT7470_START 0x01
|
||||
#define ADT7470_TODIS 0x08
|
||||
#define ADT7470_LOCK 0x10
|
||||
#define ADT7470_FAST_TACH 0x20
|
||||
#define ADT7470_LOW_FREQ_DRIVE 0x40
|
||||
#define ADT7470_T05_STB 0x80 // full speed pin
|
||||
|
||||
// CONFIG REGISTER 2
|
||||
#define ADT7470_CONFIG_REGISTER_2 0x74
|
||||
// bits
|
||||
#define ADT7470_POWERDOWN 0x01
|
||||
|
||||
// OTHER REGISTERS
|
||||
#define ADT7470_DEVICEID_REGISTER 0x3D
|
||||
#define ADT7470_COMPANYID_REGISTER 0x3E
|
||||
#define ADT7470_REVISION_REGISTER 0x3F
|
||||
|
||||
// TEMPERATURE
|
||||
#define ADT7470_TEMP_BASE 0x20
|
||||
#define ADT7470_TEMP_MAX 0x78
|
||||
#define ADT7470_TEMP_LIMIT_BASE 0x44
|
||||
|
||||
// SPEED
|
||||
#define ADT7470_TACH_BASE 0x2A
|
||||
#define ADT7470_TACH_LOW_LIMIT_BASE 0x58
|
||||
#define ADT7470_TACH_HIGH_LIMIT_BASE 0x60
|
||||
#define ADT7470_FAN_PPR_REGISTER 0x43
|
||||
#define ADT7470_FAN_PWM_BASE 0x32
|
||||
// Page 21 invert PWM signal
|
||||
#define ADT7470_FAN_PWM_CONFIG_1 0x68
|
||||
#define ADT7470_FAN_PWM_CONFIG_2 0x69
|
||||
|
||||
|
||||
// INTERRUPTS
|
||||
#define ADT7470_IRQ_STATUS_1 0x41
|
||||
#define ADT7470_IRQ_STATUS_2 0x42
|
||||
#define ADT7470_IRQ_MASK_REG_1 0x72
|
||||
#define ADT7470_IRQ_MASK_REG_2 0x73
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PUBLIC INTERFACE
|
||||
//
|
||||
|
||||
ADT7470::ADT7470(uint8_t address)
|
||||
{
|
||||
// allowed 0x2C, 0x2E, 0x2F
|
||||
_address = address;
|
||||
}
|
||||
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
void ADT7470::begin(uint8_t sda, uint8_t scl)
|
||||
{
|
||||
Wire.begin(sda, scl);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ADT7470::begin()
|
||||
{
|
||||
Wire.begin();
|
||||
}
|
||||
|
||||
//
|
||||
// GENERIC
|
||||
//
|
||||
boolean ADT7470::isConnected()
|
||||
{
|
||||
return ((getDeviceID() == 0x70) && (getCompanyID() == 0x41));
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getRevision()
|
||||
{
|
||||
return getReg8(ADT7470_REVISION_REGISTER);
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getDeviceID()
|
||||
{
|
||||
return getReg8(ADT7470_DEVICEID_REGISTER);
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getCompanyID()
|
||||
{
|
||||
return getReg8(ADT7470_COMPANYID_REGISTER);
|
||||
}
|
||||
|
||||
void ADT7470::startMonitoring()
|
||||
{
|
||||
setRegMask(ADT7470_CONFIG_REGISTER_1, ADT7470_START);
|
||||
}
|
||||
|
||||
void ADT7470::stopMonitoring()
|
||||
{
|
||||
clrRegMask(ADT7470_CONFIG_REGISTER_1, ADT7470_START);
|
||||
}
|
||||
|
||||
void ADT7470::powerDown()
|
||||
{
|
||||
setRegMask(ADT7470_CONFIG_REGISTER_2, ADT7470_POWERDOWN);
|
||||
}
|
||||
|
||||
void ADT7470::powerUp()
|
||||
{
|
||||
clrRegMask(ADT7470_CONFIG_REGISTER_2, ADT7470_POWERDOWN);
|
||||
}
|
||||
|
||||
//
|
||||
// MEASURE TEMPERATURE
|
||||
//
|
||||
|
||||
// TODO:
|
||||
// make these calls async as waiting up to 2 seconds is an 'eternity'
|
||||
// void startConversion();
|
||||
// bool conversionReady();
|
||||
// int8_t getTemperature(uin8_t idx);
|
||||
int8_t ADT7470::getTemperature(uint8_t idx)
|
||||
{
|
||||
if (idx >= 10) return 0;
|
||||
// 1. Set Register 40 Bit[7] = 1. This starts the temperature measurements.
|
||||
setRegMask(ADT7470_CONFIG_REGISTER_1, ADT7470_T05_STB);
|
||||
// 2. Wait 200 ms for each TMP05/TMP06 in the loop.
|
||||
delay(2000); // way to long
|
||||
// 3. Set Register 40 Bit[7] = 0.
|
||||
clrRegMask(ADT7470_CONFIG_REGISTER_1, ADT7470_T05_STB);
|
||||
// 4. Read the temperature registers.
|
||||
return (int8_t) getReg8(ADT7470_TEMP_BASE + idx);
|
||||
}
|
||||
|
||||
int8_t ADT7470::getMaxTemperature()
|
||||
{
|
||||
return (int8_t)getReg8(ADT7470_TEMP_MAX);
|
||||
}
|
||||
|
||||
bool ADT7470::setTemperatureLimit(uint8_t idx, int8_t low, int8_t high)
|
||||
{
|
||||
if ((idx >= 10) || (low >= high)) return false;
|
||||
setReg8(ADT7470_TEMP_LIMIT_BASE + idx * 2, low);
|
||||
setReg8(ADT7470_TEMP_LIMIT_BASE + idx * 2 + 1, high);
|
||||
return true;
|
||||
}
|
||||
|
||||
int8_t ADT7470::getTemperatureLowLimit(uint8_t idx)
|
||||
{
|
||||
int8_t rv = getReg8(ADT7470_TEMP_LIMIT_BASE + 2 * idx);
|
||||
return rv;
|
||||
}
|
||||
|
||||
int8_t ADT7470::getTemperatureHighLimit(uint8_t idx)
|
||||
{
|
||||
int8_t rv = getReg8(ADT7470_TEMP_LIMIT_BASE + 2 * idx + 1);
|
||||
return rv;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//
|
||||
// SET FAN SPEED
|
||||
//
|
||||
bool ADT7470::setPWM(uint8_t idx, uint8_t val)
|
||||
{
|
||||
if (idx >= 4) return false;
|
||||
setReg8(ADT7470_FAN_PWM_BASE + idx, val);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getPWM(uint8_t idx)
|
||||
{
|
||||
if (idx >= 4) return 0;
|
||||
return getReg8(ADT7470_FAN_PWM_BASE + idx);
|
||||
}
|
||||
|
||||
bool ADT7470::setFanLowFreq(uint8_t val)
|
||||
{
|
||||
if (val > 7) return false;
|
||||
setRegMask(ADT7470_CONFIG_REGISTER_1, ADT7470_LOW_FREQ_DRIVE);
|
||||
// make sure all bits are 0.
|
||||
// Can be more efficient check previous value.
|
||||
// getReg8()
|
||||
// if equal co change
|
||||
// else clr bits & set
|
||||
// write them
|
||||
clrRegMask(ADT7470_CONFIG_REGISTER_2, (0x07 << 4)); // clr 3 bits
|
||||
setRegMask(ADT7470_CONFIG_REGISTER_2, (val << 4));
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ADT7470::setFanHighFreq(uint8_t val)
|
||||
{
|
||||
if (val > 7) return false;
|
||||
clrRegMask(ADT7470_CONFIG_REGISTER_1, ADT7470_LOW_FREQ_DRIVE);
|
||||
// make sure all bits are 0 first. // Can be more efficient check previous value.
|
||||
clrRegMask(ADT7470_CONFIG_REGISTER_2, (0x07 << 4)); // clr 3 bits
|
||||
setRegMask(ADT7470_CONFIG_REGISTER_2, (val << 4));
|
||||
return true;
|
||||
}
|
||||
|
||||
void ADT7470::setInvertPWM(uint8_t idx)
|
||||
{
|
||||
if (idx == 0) setReg8(ADT7470_FAN_PWM_CONFIG_1, 0x10); // bit 5
|
||||
if (idx == 1) setReg8(ADT7470_FAN_PWM_CONFIG_1, 0x80); // bit 4
|
||||
if (idx == 2) setReg8(ADT7470_FAN_PWM_CONFIG_2, 0x10);
|
||||
if (idx == 3) setReg8(ADT7470_FAN_PWM_CONFIG_2, 0x80);
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getInvertPWM(uint8_t idx)
|
||||
{
|
||||
if (idx == 0) return getReg8(ADT7470_FAN_PWM_CONFIG_1) & 0x10;
|
||||
if (idx == 1) return getReg8(ADT7470_FAN_PWM_CONFIG_1) & 0x80;
|
||||
if (idx == 2) return getReg8(ADT7470_FAN_PWM_CONFIG_2) & 0x10;
|
||||
if (idx == 3) return getReg8(ADT7470_FAN_PWM_CONFIG_2) & 0x80;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// MEASURE FAN SPEED
|
||||
//
|
||||
bool ADT7470::setPulsesPerRevolution(uint8_t idx, uint8_t val)
|
||||
{
|
||||
if (idx >= 4) return false;
|
||||
if ((val == 0) || (val > 4)) return false;
|
||||
uint8_t mask = 0x03 << (idx * 2);
|
||||
|
||||
uint8_t reg;
|
||||
_read(ADT7470_FAN_PPR_REGISTER, ®);
|
||||
reg &= ~mask;
|
||||
reg |= ((val - 1) << (idx * 2));
|
||||
_write(ADT7470_FAN_PPR_REGISTER, reg);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getPulsesPerRevolution(uint8_t idx)
|
||||
{
|
||||
if (idx >= 4) return 0;
|
||||
uint8_t reg = getReg8(ADT7470_FAN_PPR_REGISTER);
|
||||
return ((reg >> (idx * 2)) & 0x03) + 1;
|
||||
}
|
||||
|
||||
void ADT7470::setFastTach()
|
||||
{
|
||||
setRegMask(ADT7470_CONFIG_REGISTER_1, ADT7470_FAST_TACH);
|
||||
}
|
||||
|
||||
void ADT7470::setSlowTach()
|
||||
{
|
||||
clrRegMask(ADT7470_CONFIG_REGISTER_1, ADT7470_FAST_TACH);
|
||||
}
|
||||
|
||||
uint16_t ADT7470::getTach(uint8_t idx)
|
||||
{
|
||||
if (idx >= 4) return 0;
|
||||
return getReg16(ADT7470_TACH_BASE + idx * 2);
|
||||
}
|
||||
|
||||
uint32_t ADT7470::getRPM(uint8_t idx)
|
||||
{
|
||||
if (idx >= 4) return 0;
|
||||
uint32_t clock = 90000UL;
|
||||
uint16_t measurementsPerMinute = 60;
|
||||
uint16_t tach = getTach(idx);
|
||||
// P23 stalling tach or very slow < 100 ==> 0xFFFF
|
||||
if (tach == 0xFFFF) return 0;
|
||||
if (tach == 0) return 0; // explicit prevents divide by zero
|
||||
// formula P24 // tach/2 == integer rounding of division.
|
||||
return (clock * measurementsPerMinute + tach/2) / tach;
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool ADT7470::setTachLimits(uint8_t idx, uint16_t low, uint16_t high)
|
||||
{
|
||||
if ((idx >= 4) || (low >= high)) return false;
|
||||
setReg16(ADT7470_TACH_LOW_LIMIT_BASE + idx * 2, low);
|
||||
setReg16(ADT7470_TACH_HIGH_LIMIT_BASE + idx * 2, high);
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16_t ADT7470::getTachLowLimits(uint8_t idx)
|
||||
{
|
||||
uint16_t rv = getReg16(ADT7470_TACH_LOW_LIMIT_BASE + idx * 2);
|
||||
return rv;
|
||||
}
|
||||
|
||||
uint16_t ADT7470::getTachHighLimits(uint8_t idx)
|
||||
{
|
||||
uint16_t rv = getReg16(ADT7470_TACH_HIGH_LIMIT_BASE + idx * 2);
|
||||
return rv;
|
||||
}
|
||||
|
||||
//
|
||||
// INTERRUPTS
|
||||
//
|
||||
uint16_t ADT7470::getTemperatureIRQstatus()
|
||||
{
|
||||
// TODO - NORM bit not handled
|
||||
// uint8_t NORM = (getReg8(ADT7470_IRQ_STATUS_2) & 0x08) >> 3;
|
||||
|
||||
uint16_t val = 0;
|
||||
val = (getReg8(ADT7470_IRQ_STATUS_2) & 0x07) << 7;
|
||||
val |= (getReg8(ADT7470_IRQ_STATUS_1) & 0x7F);
|
||||
return val;
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getFanIRQstatus()
|
||||
{
|
||||
uint8_t val = (getReg8(ADT7470_IRQ_STATUS_2) & 0xF0) >> 4;
|
||||
return val;
|
||||
}
|
||||
|
||||
// TODO MERGE? setTemperatureIRQMask(idx, val); ?
|
||||
void ADT7470::setTemperatureIRQMask(uint8_t idx)
|
||||
{
|
||||
uint8_t reg = ADT7470_IRQ_MASK_REG_1;
|
||||
if (idx > 7)
|
||||
{
|
||||
reg = ADT7470_IRQ_MASK_REG_2;
|
||||
idx -= 7;
|
||||
}
|
||||
uint8_t val = getReg8(reg);
|
||||
val |= (1 << idx);
|
||||
setReg8(reg, val);
|
||||
}
|
||||
|
||||
void ADT7470::clrTemperatureIRQMask(uint8_t idx)
|
||||
{
|
||||
uint8_t reg = ADT7470_IRQ_MASK_REG_1;
|
||||
if (idx > 7)
|
||||
{
|
||||
reg = ADT7470_IRQ_MASK_REG_2;
|
||||
idx -= 7;
|
||||
}
|
||||
uint8_t val = getReg8(reg);
|
||||
val &= ~(1 << idx);
|
||||
setReg8(reg, val);
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getTemperatureIRQMask(uint8_t idx)
|
||||
{
|
||||
uint8_t reg = ADT7470_IRQ_MASK_REG_1;
|
||||
if (idx > 7)
|
||||
{
|
||||
reg = ADT7470_IRQ_MASK_REG_2;
|
||||
idx -= 7;
|
||||
}
|
||||
return getReg8(reg) & (1 << idx);
|
||||
}
|
||||
|
||||
void ADT7470::setFanIRQMask(uint8_t idx)
|
||||
{
|
||||
uint8_t val = getReg8(ADT7470_IRQ_MASK_REG_2);
|
||||
val |= (1 << (idx + 4));
|
||||
setReg8(ADT7470_IRQ_MASK_REG_2, val);
|
||||
}
|
||||
|
||||
void ADT7470::clrFanIRQMask(uint8_t idx)
|
||||
{
|
||||
uint8_t val = getReg8(ADT7470_IRQ_MASK_REG_2);
|
||||
val &= ~(1 << (idx + 4));
|
||||
setReg8(ADT7470_IRQ_MASK_REG_2, val);
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getFanIRQMask(uint8_t idx)
|
||||
{
|
||||
return getReg8(ADT7470_IRQ_MASK_REG_2) & (1 << (idx + 4));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// REGISTER OPERATORS
|
||||
//
|
||||
void ADT7470::setRegMask(uint8_t reg, uint8_t mask)
|
||||
{
|
||||
uint8_t t;
|
||||
_read(reg, &t, (uint8_t)1);
|
||||
t |= mask;
|
||||
_write(reg, t);
|
||||
}
|
||||
|
||||
void ADT7470::clrRegMask(uint8_t reg, uint8_t mask)
|
||||
{
|
||||
uint8_t t;
|
||||
_read(reg, &t, (uint8_t)1);
|
||||
t &= ~mask;
|
||||
_write(reg, t);
|
||||
}
|
||||
|
||||
uint8_t ADT7470::getReg8(uint8_t reg)
|
||||
{
|
||||
uint8_t val;
|
||||
_read(reg, &val);
|
||||
return val;
|
||||
}
|
||||
|
||||
void ADT7470::setReg8(uint8_t reg, uint8_t val)
|
||||
{
|
||||
_write(reg, val);
|
||||
}
|
||||
|
||||
uint16_t ADT7470::getReg16(uint8_t reg)
|
||||
{
|
||||
uint8_t h, l;
|
||||
_read(reg, &l);
|
||||
_read(reg + 1, &h);
|
||||
return (((uint16_t)h) << 8) | l;
|
||||
}
|
||||
|
||||
void ADT7470::setReg16(uint8_t reg, uint16_t val)
|
||||
{
|
||||
_write(reg + 1, val & 0xFF);
|
||||
_write(reg, val >> 8);
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE - LOW LEVEL I2C
|
||||
//
|
||||
int ADT7470::_write(const uint8_t reg, uint8_t value)
|
||||
{
|
||||
return _write(reg, &value, 1);
|
||||
}
|
||||
|
||||
int ADT7470::_write(const uint8_t reg, uint8_t *buffer, uint8_t length)
|
||||
{
|
||||
Wire.beginTransmission(_address);
|
||||
Wire.write(reg);
|
||||
for (uint8_t i = 0; i < length; i++) Wire.write(buffer[i]);
|
||||
int rv = Wire.endTransmission();
|
||||
return rv;
|
||||
}
|
||||
|
||||
int ADT7470::_read(const uint8_t reg, uint8_t *value)
|
||||
{
|
||||
return _read(reg, value, 1);
|
||||
}
|
||||
|
||||
int ADT7470::_read(const uint8_t reg, uint8_t *buffer, uint8_t length)
|
||||
{
|
||||
Wire.beginTransmission(_address);
|
||||
Wire.write(reg);
|
||||
int rv = Wire.endTransmission(false);
|
||||
if (rv != 0) return 0; // nothing read
|
||||
|
||||
uint8_t len = Wire.requestFrom(_address, length);
|
||||
uint8_t cnt = 0;
|
||||
uint32_t before = millis();
|
||||
while ((cnt < len) && ((millis() - before) < ADT7470_TIMEOUT))
|
||||
{
|
||||
if (Wire.available()) buffer[cnt++] = Wire.read();
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
127
libraries/ADT7470/ADT7470.h
Normal file
127
libraries/ADT7470/ADT7470.h
Normal file
@ -0,0 +1,127 @@
|
||||
#pragma once
|
||||
//
|
||||
// FILE: ADT7470.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.2
|
||||
// PURPOSE: Arduino library for I2C ADT7470 Fan Monitoring
|
||||
// URL: https://github.com/RobTillaart/ADT7470
|
||||
// http://forum.arduino.cc/index.php?topic=363218.0
|
||||
//
|
||||
// HISTORY:
|
||||
// see ADT7470.cpp file
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
|
||||
#define ADT7470_LIB_VERSION "0.1.1"
|
||||
|
||||
#ifndef ADT7470_TIMEOUT
|
||||
#define ADT7470_TIMEOUT 1000
|
||||
#endif
|
||||
#ifndef ADT7470_ADDR_HIGH
|
||||
#define ADT7470_ADDR_HIGH 0x2F
|
||||
#endif
|
||||
#ifndef ADT7470_ADDR_LOW
|
||||
#define ADT7470_ADDR_LOW 0x2C
|
||||
#endif
|
||||
#ifndef ADT7470_ADDR_FLOAT
|
||||
#define ADT7470_ADDR_FLOAT 0x2E
|
||||
#endif
|
||||
|
||||
class ADT7470
|
||||
{
|
||||
public:
|
||||
ADT7470(uint8_t address);
|
||||
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
void begin(uint8_t sda, uint8_t scl);
|
||||
#endif
|
||||
void begin();
|
||||
|
||||
// GENERIC
|
||||
boolean isConnected();
|
||||
uint8_t getRevision();
|
||||
uint8_t getDeviceID(); // should return 0x70
|
||||
uint8_t getCompanyID(); // should return 0x41
|
||||
void startMonitoring();
|
||||
void stopMonitoring();
|
||||
void powerDown();
|
||||
void powerUp();
|
||||
|
||||
|
||||
// MEASURE TEMPERATURE - not tested
|
||||
// Page 13 daisy chained specific TMP05 / TMP06 sensors
|
||||
int8_t getTemperature(uint8_t idx);
|
||||
int8_t getMaxTemperature();
|
||||
// Page 16
|
||||
bool setTemperatureLimit(uint8_t idx, int8_t low, int8_t high);
|
||||
int8_t getTemperatureLowLimit(uint8_t idx);
|
||||
int8_t getTemperatureHighLimit(uint8_t idx);
|
||||
|
||||
|
||||
// SET FAN SPEED
|
||||
// Page 25 idx = 0..3
|
||||
bool setPWM(uint8_t idx, uint8_t val);
|
||||
uint8_t getPWM(uint8_t idx);
|
||||
// Page 36 val = 0..7
|
||||
bool setFanLowFreq(uint8_t val = 0); // PWM freq..
|
||||
bool setFanHighFreq(uint8_t val = 0);
|
||||
// Page 21
|
||||
void setInvertPWM(uint8_t idx);
|
||||
uint8_t getInvertPWM(uint8_t idx);
|
||||
|
||||
|
||||
|
||||
// MEASURE FAN SPEED
|
||||
// Page 23-24 idx = 0..3 val = 1..4
|
||||
bool setPulsesPerRevolution(uint8_t idx, uint8_t val);
|
||||
// returns 1..4
|
||||
uint8_t getPulsesPerRevolution(uint8_t idx);
|
||||
// P30 FST_TCH fast = measurement/250 ms slow = measurement/1000ms.
|
||||
void setFastTach();
|
||||
void setSlowTach();
|
||||
uint16_t getTach(uint8_t idx);
|
||||
uint32_t getRPM(uint8_t idx);
|
||||
// Page 16 TACH/FAN ALARM
|
||||
bool setTachLimits(uint8_t idx, uint16_t low, uint16_t high);
|
||||
uint16_t getTachLowLimits(uint8_t idx);
|
||||
uint16_t getTachHighLimits(uint8_t idx);
|
||||
|
||||
|
||||
// INTERRUPTS
|
||||
// Page 17 - every bit set 0..10 represents one temp limit (high /low) exceeded
|
||||
// if it return 0 => no limits exceeded.
|
||||
uint16_t getTemperatureIRQstatus();
|
||||
uint8_t getFanIRQstatus();
|
||||
// idx = 0..9
|
||||
void setTemperatureIRQMask(uint8_t idx);
|
||||
void clrTemperatureIRQMask(uint8_t idx);
|
||||
uint8_t getTemperatureIRQMask(uint8_t idx);
|
||||
// idx = 0..3
|
||||
void setFanIRQMask(uint8_t idx);
|
||||
void clrFanIRQMask(uint8_t idx);
|
||||
uint8_t getFanIRQMask(uint8_t idx);
|
||||
|
||||
|
||||
// REGISTER OPERATORS
|
||||
// set/clr one or more bits.
|
||||
void setRegMask(uint8_t reg, uint8_t mask);
|
||||
void clrRegMask(uint8_t reg, uint8_t mask);
|
||||
// low level register interface
|
||||
uint8_t getReg8(uint8_t reg);
|
||||
void setReg8(uint8_t reg, uint8_t val);
|
||||
uint16_t getReg16(uint8_t reg);
|
||||
void setReg16(uint8_t reg, uint16_t val);
|
||||
|
||||
|
||||
private:
|
||||
// LOW LEVEL I2C
|
||||
int _write(const uint8_t reg, uint8_t value);
|
||||
int _write(const uint8_t reg, uint8_t *buffer, uint8_t length);
|
||||
int _read(const uint8_t reg, uint8_t *value);
|
||||
int _read(const uint8_t reg, uint8_t *buffer, uint8_t length);
|
||||
|
||||
uint8_t _address = 0;
|
||||
};
|
||||
|
||||
// -- END OF FILE --
|
21
libraries/ADT7470/LICENSE
Normal file
21
libraries/ADT7470/LICENSE
Normal file
@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2015-2021 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
107
libraries/ADT7470/README.md
Normal file
107
libraries/ADT7470/README.md
Normal file
@ -0,0 +1,107 @@
|
||||
|
||||
[![Arduino CI](https://github.com/RobTillaart/ADT7470/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
||||
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/ADT7470/blob/master/LICENSE)
|
||||
[![GitHub release](https://img.shields.io/github/release/RobTillaart/ADT7470.svg?maxAge=3600)](https://github.com/RobTillaart/ADT7470/releases)
|
||||
|
||||
# ADT7470 Library
|
||||
|
||||
Arduino library for I2C ADT7470 Fan Monitoring
|
||||
|
||||
## Description
|
||||
|
||||
The ADT7470 Fan Monitoring library offers an I2C device that can
|
||||
monitor and control up to four fans. Further this module can daisy
|
||||
chain up to 10 (specific TMP05/06) temperature sensors.
|
||||
|
||||
Please read datasheet carefully before working with the module.
|
||||
|
||||
**Experimental**
|
||||
This library was build in 2015 from datasheet (PDF) on request and
|
||||
is never tested by me. So it is experimental at best and if you have the
|
||||
hardware and are able to try this library I would really appreciate it
|
||||
as it is a quite unique module.
|
||||
|
||||
That said the library is supporting setting the fan speed and measure
|
||||
the RPM, so it should be usable e.g. for a climate controlled room or
|
||||
cabinet.
|
||||
|
||||
**Warning**
|
||||
Do not forget to put a diode over the Fan to prevent damage due to
|
||||
inductive pulse when switched off.
|
||||
|
||||
## ADT7470 Address Select Mode
|
||||
|
||||
(from datasheet)
|
||||
|
||||
| Pin 11 | (ADDR) State | Address |
|
||||
|:----:|:----:|:----:|
|
||||
| High (10 kΩ to VCC) | 010 1111 (0x5E left-justified or 0x2F right-justified) |
|
||||
| Low (10 kΩ to GND) | 010 1100 (0x58 left-justified or 0x2C right-justified) |
|
||||
| Floating (no pull-up) | 010 1110 (0x5C left-justified or 0x2E right-justified) |
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
The interface consists of:
|
||||
|
||||
- **ADT7470()** constructor
|
||||
- **begin()** initialize the I2C bus
|
||||
- **isConnected()** check if the module is connected to the I2C bus
|
||||
- **getRevision()** version of the firmware
|
||||
- **getDeviceID()** should return 0x70
|
||||
- **getCompanyID()** should return 0x41
|
||||
- **startMonitoring()**
|
||||
- **stopMonitoring()**
|
||||
- **powerDown()** energy save mode
|
||||
- **powerUp()** active mode
|
||||
- **getTemperature(idx)** idx = 0..9; if connected it returns the temperature
|
||||
of sensor idx. Temperature sensors are daisy chaned.
|
||||
- **getMaxTemperature()** get max temperature of connected temperature sensors.
|
||||
- **setTemperatureLimit(idx, low, high)** for ALARM function
|
||||
- **getTemperatureLowLimit(idx)**
|
||||
- **getTemperatureHighLimit(idx)**
|
||||
- **setPWM(idx, val)** set the speed of the fan at idx
|
||||
- **getPWM(idx)** read back the speed set.
|
||||
- **setFanLowFreq(val = 0)**
|
||||
- **setFanHighFreq(val = 0)**
|
||||
- **setInvertPWM(idx)**
|
||||
- **getInvertPWM(idx)**
|
||||
- **setPulsesPerRevolution(idx, val)** val should be 1..4 as a fan gives 1..4 pulses per revolution.
|
||||
This valus is needed to calculate a correct tach and RPM.
|
||||
- **getPulsesPerRevolution(idx)** read back PulsePerRevolution. returns 1..4.
|
||||
- **setFastTach()** Tach register is updated 4x per second.
|
||||
- **setSlowTach()** Tach register is updated 1x per second.
|
||||
- **getTach(idx)** get the raw pulses.
|
||||
- **getRPM(idx)** get a Revolutions Per Minute, based upon **getTach()**
|
||||
- **setTachLimits(idx, low, high)**
|
||||
- **getTachLowLimits(idx)**
|
||||
- **getTachHighLimits(idx)**
|
||||
- **getTemperatureIRQstatus()**
|
||||
- **setTemperatureIRQMask(idx)**
|
||||
- **clrTemperatureIRQMask(idx)**
|
||||
- **getTemperatureIRQMask(idx)**
|
||||
- **getFanIRQstatus()**
|
||||
- **setFanIRQMask(idx)**
|
||||
- **clrFanIRQMask(idx)**
|
||||
- **getFanIRQMask(idx)**
|
||||
|
||||
The descriptions are short and need to be extended.
|
||||
|
||||
## Todo / investigate / not implemented yet
|
||||
|
||||
- get the hardware to test
|
||||
- change pins from PWM to digital IO
|
||||
- temperature sensors (functions are prepared)
|
||||
- How to connect temp sensors (daisy chained)
|
||||
https://ez.analog.com/temperature_sensors/f/discussions/77540/adt7470-and-tmp05-daisy-chain-temeparure-sensing
|
||||
- FULLSPEED pin, must it be in the library?
|
||||
software version ==> fullspeed(idx)
|
||||
- automode
|
||||
- improve documentation, readme.md file.
|
||||
- ...
|
||||
|
||||
|
||||
## Operation
|
||||
|
||||
See examples
|
||||
|
BIN
libraries/ADT7470/documents/ADT7470.pdf
Normal file
BIN
libraries/ADT7470/documents/ADT7470.pdf
Normal file
Binary file not shown.
222
libraries/ADT7470/examples/adt7470_demo/adt7470_demo.ino
Normal file
222
libraries/ADT7470/examples/adt7470_demo/adt7470_demo.ino
Normal file
@ -0,0 +1,222 @@
|
||||
//
|
||||
// FILE: adt7470_demo.ino
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.1.1
|
||||
// PURPOSE: demo ADT7470 library
|
||||
// DATE: 2015-12-02
|
||||
|
||||
|
||||
#include <Wire.h>
|
||||
#include "ADT7470.h"
|
||||
|
||||
ADT7470 ADT(ADT7470_ADDR_FLOAT);
|
||||
|
||||
void setup()
|
||||
{
|
||||
Wire.begin();
|
||||
|
||||
Serial.begin(115200);
|
||||
Serial.print(F("\n\nStart "));
|
||||
Serial.println(__FILE__);
|
||||
Serial.println();
|
||||
|
||||
if (!ADT.isConnected())
|
||||
{
|
||||
Serial.println("Cannot connect ADT7470...\n");
|
||||
// while(1);
|
||||
}
|
||||
// else
|
||||
{
|
||||
testStart();
|
||||
testRevision();
|
||||
testTemp();
|
||||
testPWM();
|
||||
testTach();
|
||||
testFanSpeed();
|
||||
|
||||
|
||||
testStop();
|
||||
}
|
||||
Serial.println("Done");
|
||||
}
|
||||
|
||||
void testStart()
|
||||
{
|
||||
Serial.println(F("ADT7470 testStart"));
|
||||
ADT.powerUp();
|
||||
ADT.startMonitoring();
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
|
||||
void testRevision()
|
||||
{
|
||||
Serial.print("ADT7470_LIB_VERSION:\t");
|
||||
Serial.println(ADT7470_LIB_VERSION);
|
||||
|
||||
Serial.print("ADT7470 getRevision:\t");
|
||||
Serial.println(ADT.getRevision());
|
||||
Serial.print("ADT7470 getDeviceID:\t");
|
||||
Serial.println(ADT.getDeviceID());
|
||||
Serial.print("ADT7470 getCompanyID:\t");
|
||||
Serial.println(ADT.getCompanyID());
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void testTemp()
|
||||
{
|
||||
Serial.println(F("ADT7470 testTemp 0..9"));
|
||||
|
||||
Serial.print("temp:");
|
||||
for (uint8_t i = 0; i < 10; i++)
|
||||
{
|
||||
Serial.print("\t");
|
||||
Serial.print(ADT.getTemperature(i));
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print("max:\t");
|
||||
Serial.println(ADT.getMaxTemperature());
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void testPWM()
|
||||
{
|
||||
Serial.println(F("ADT7470 getPWM 0..3"));
|
||||
Serial.print(F("set:"));
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
uint8_t pwm = random(255);
|
||||
ADT.setPWM(i, pwm);
|
||||
Serial.print("\t");
|
||||
Serial.print(pwm);
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("get:"));
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
uint8_t pwm = ADT.getPWM(i);
|
||||
Serial.print("\t");
|
||||
Serial.print(pwm);
|
||||
}
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void testTach()
|
||||
{
|
||||
uint8_t ppr[4];
|
||||
Serial.println(F("ADT7470 testTach 0..3"));
|
||||
Serial.print(F("getPPR: "));
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
ppr[i] = ADT.getPulsesPerRevolution(i);
|
||||
Serial.print("\t");
|
||||
Serial.print(ppr[i]);
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.print(F("setPPR: "));
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
ADT.setPulsesPerRevolution(i, ppr[i]);
|
||||
bool b = (ppr[i] == ADT.getPulsesPerRevolution(i));
|
||||
Serial.print("\t");
|
||||
Serial.print(b ? "T" : "F"); // expect TTTT
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
ADT.setSlowTach();
|
||||
Serial.println(F("setSlowTach"));
|
||||
Serial.print(F("getTach:"));
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
uint16_t tach = ADT.getTach(i);
|
||||
Serial.print("\t");
|
||||
Serial.print(tach);
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print(F("getRPM :"));
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
uint32_t rpm = ADT.getRPM(i);
|
||||
Serial.print("\t");
|
||||
Serial.print(rpm);
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
ADT.setFastTach();
|
||||
Serial.println(F("setFastTach"));
|
||||
Serial.print(F("getTach:"));
|
||||
for (uint8_t i = 0; i < 4; i++)
|
||||
{
|
||||
uint16_t tach = ADT.getTach(i);
|
||||
Serial.print("\t");
|
||||
Serial.print(tach);
|
||||
}
|
||||
Serial.println();
|
||||
Serial.print(F("getRPM :"));
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
uint32_t rpm = ADT.getRPM(i);
|
||||
Serial.print("\t");
|
||||
Serial.print(rpm);
|
||||
}
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(10);
|
||||
}
|
||||
|
||||
|
||||
void testFanSpeed()
|
||||
{
|
||||
Serial.println(F("ADT7470 testFanSpeed"));
|
||||
Serial.print("low:\t");
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
ADT.setFanLowFreq(i);
|
||||
Serial.print(i);
|
||||
Serial.print("\t");
|
||||
delay(1000);
|
||||
}
|
||||
Serial.println();
|
||||
|
||||
Serial.print("high:\t");
|
||||
for (uint8_t i = 0; i < 8; i++)
|
||||
{
|
||||
ADT.setFanHighFreq(i);
|
||||
Serial.print(i);
|
||||
Serial.print("\t");
|
||||
delay(1000);
|
||||
}
|
||||
Serial.println();
|
||||
ADT.setFanHighFreq(2);
|
||||
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
delay(10);
|
||||
}
|
||||
|
||||
void testStop()
|
||||
{
|
||||
Serial.println(F("ADT7470 testStop"));
|
||||
ADT.stopMonitoring();
|
||||
ADT.powerDown();
|
||||
delay(2000);
|
||||
// TODO how to check if it is down - datasheet.
|
||||
}
|
||||
|
||||
|
||||
void loop()
|
||||
{
|
||||
}
|
||||
|
||||
// -- END OF FILE --
|
55
libraries/ADT7470/keywords.txt
Normal file
55
libraries/ADT7470/keywords.txt
Normal file
@ -0,0 +1,55 @@
|
||||
# Syntax Coloring Map For ADT7470
|
||||
|
||||
# Datatypes (KEYWORD1)
|
||||
ADT7470 KEYWORD1
|
||||
|
||||
# Methods and Functions (KEYWORD2)
|
||||
isConnected KEYWORD2
|
||||
getRevision KEYWORD2
|
||||
getDeviceID KEYWORD2
|
||||
getCompanyID KEYWORD2
|
||||
|
||||
startMonitoring KEYWORD2
|
||||
stopMonitoring KEYWORD2
|
||||
powerDown KEYWORD2
|
||||
powerUp KEYWORD2
|
||||
|
||||
getTemperature KEYWORD2
|
||||
getMaxTemperature KEYWORD2
|
||||
setTemperatureLimit KEYWORD2
|
||||
getTemperatureLowLimit KEYWORD2
|
||||
getTemperatureHighLimit KEYWORD2
|
||||
|
||||
setPWM KEYWORD2
|
||||
getPWM KEYWORD2
|
||||
setFanLowFreq KEYWORD2
|
||||
setFanHighFreq KEYWORD2
|
||||
setInvertPWM KEYWORD2
|
||||
getInvertPWM KEYWORD2
|
||||
|
||||
setPulsesPerRevolution KEYWORD2
|
||||
getPulsesPerRevolution KEYWORD2
|
||||
setFastTach KEYWORD2
|
||||
setSlowTach KEYWORD2
|
||||
getTach KEYWORD2
|
||||
getRPM KEYWORD2
|
||||
|
||||
setTachLimits KEYWORD2
|
||||
getTachLowLimits KEYWORD2
|
||||
getTachHighLimits KEYWORD2
|
||||
|
||||
getTemperatureIRQstatus KEYWORD2
|
||||
setTemperatureIRQMask KEYWORD2
|
||||
clrTemperatureIRQMask KEYWORD2
|
||||
getTemperatureIRQMask KEYWORD2
|
||||
getFanIRQstatus KEYWORD2
|
||||
setFanIRQMask KEYWORD2
|
||||
clrFanIRQMask KEYWORD2
|
||||
getFanIRQMask KEYWORD2
|
||||
|
||||
# Constants (LITERAL1)
|
||||
ADT7470_LIB_VERSION LITERAL1
|
||||
ADT7470_TIMEOUT LITERAL1
|
||||
ADT7470_ADDR_HIGH LITERAL1
|
||||
ADT7470_ADDR_LOW LITERAL1
|
||||
ADT7470_ADDR_FLOAT LITERAL1
|
21
libraries/ADT7470/library.json
Normal file
21
libraries/ADT7470/library.json
Normal file
@ -0,0 +1,21 @@
|
||||
{
|
||||
"name": "ADT7470",
|
||||
"keywords": "ADT7470, Fan, monitoring",
|
||||
"description": "Arduino library for I2C ADT7470 Fan Monitoring.",
|
||||
"authors":
|
||||
[
|
||||
{
|
||||
"name": "Rob Tillaart",
|
||||
"email": "Rob.Tillaart@gmail.com",
|
||||
"maintainer": true
|
||||
}
|
||||
],
|
||||
"repository":
|
||||
{
|
||||
"type": "git",
|
||||
"url": "https://github.com/RobTillaart/ADT7470.git"
|
||||
},
|
||||
"version":"0.1.2",
|
||||
"frameworks": "arduino",
|
||||
"platforms": "*"
|
||||
}
|
11
libraries/ADT7470/library.properties
Normal file
11
libraries/ADT7470/library.properties
Normal file
@ -0,0 +1,11 @@
|
||||
name=ADT7470
|
||||
version=0.1.2
|
||||
author=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
maintainer=Rob Tillaart <rob.tillaart@gmail.com>
|
||||
sentence=ADT7470 Library
|
||||
paragraph=Arduino library for I2C ADT7470 Fan Monitoring
|
||||
category=Device Control
|
||||
url=https://github.com/RobTillaart/ADT7470
|
||||
architectures=*
|
||||
includes=ADT7470.h
|
||||
depends=
|
48
libraries/ADT7470/test/unit_test_001.cpp
Normal file
48
libraries/ADT7470/test/unit_test_001.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
//
|
||||
// FILE: unit_test_001.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// DATE: 2020-12-09
|
||||
// PURPOSE: unit tests for the ADT7470 Fan Monitoring library
|
||||
// https://github.com/RobTillaart/ADT7470
|
||||
// https://github.com/Arduino-CI/arduino_ci/blob/master/REFERENCE.md
|
||||
//
|
||||
|
||||
// supported assertions
|
||||
// ----------------------------
|
||||
// assertEqual(expected, actual)
|
||||
// assertNotEqual(expected, actual)
|
||||
// assertLess(expected, actual)
|
||||
// assertMore(expected, actual)
|
||||
// assertLessOrEqual(expected, actual)
|
||||
// assertMoreOrEqual(expected, actual)
|
||||
// assertTrue(actual)
|
||||
// assertFalse(actual)
|
||||
// assertNull(actual)
|
||||
|
||||
#include <ArduinoUnitTests.h>
|
||||
|
||||
#include "ADT7470.h"
|
||||
|
||||
|
||||
unittest_setup()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unittest_teardown()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
unittest(test_constructor)
|
||||
{
|
||||
ADT7470 ADT(0x2C);
|
||||
ADT.begin();
|
||||
|
||||
assertFalse(ADT.isConnected());
|
||||
}
|
||||
|
||||
|
||||
unittest_main()
|
||||
|
||||
// --------
|
7
libraries/AM232X/.arduino-ci.yml
Normal file
7
libraries/AM232X/.arduino-ci.yml
Normal file
@ -0,0 +1,7 @@
|
||||
compile:
|
||||
# Choosing to run compilation tests on 2 different Arduino platforms
|
||||
platforms:
|
||||
- uno
|
||||
- leonardo
|
||||
- due
|
||||
- zero
|
14
libraries/AM232X/.github/workflows/arduino_test_runner.yml
vendored
Normal file
14
libraries/AM232X/.github/workflows/arduino_test_runner.yml
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Arduino CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
arduino_ci:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: Arduino-CI/action@master
|
||||
# Arduino-CI/action@v0.1.1
|
||||
# Arduino-CI/action@master
|
@ -1,46 +1,70 @@
|
||||
//
|
||||
// FILE: AM232X.cpp
|
||||
// AUTHOR: Rob Tillaart
|
||||
// VERSION: 0.2.3
|
||||
// VERSION: 0.2.4
|
||||
// PURPOSE: AM232X library for AM2320 for Arduino.
|
||||
//
|
||||
// HISTORY:
|
||||
// 0.1.0 2017-12-11 initial version
|
||||
// 0.1.1 2017-12-12 added CRC checking
|
||||
// 0.1.2 2017-12-12 get and set functions.
|
||||
// 0.1.3 2017-12-19 added ESP8266 - issue #86
|
||||
// tested by Viktor Balint
|
||||
// 0.1.4 2018-10-24 fixed temperature formula - #114
|
||||
// thanks to 9a4gl
|
||||
// 0.1.5 2020-03-25 refactor, add read() to begin()
|
||||
// 0.2.0 2020-05-03 made temperature + humidity private, add wrapper functions.
|
||||
// 0.2.1 2020-05-06 fix temperature function (thanks Chade)
|
||||
// 0.2.2 2020-05-12 added ESP32 support
|
||||
// 0.2.3 2020-05-27 update library.json
|
||||
//
|
||||
// 0.1.0 2017-12-11 initial version
|
||||
// 0.1.1 2017-12-12 added CRC checking
|
||||
// 0.1.2 2017-12-12 get and set functions.
|
||||
// 0.1.3 2017-12-19 added ESP8266 - issue #86
|
||||
// tested by Viktor Balint
|
||||
// 0.1.4 2018-10-24 fixed temperature formula - #114
|
||||
// thanks to 9a4gl
|
||||
// 0.1.5 2020-03-25 refactor, add read() to begin()
|
||||
// 0.2.0 2020-05-03 made temperature + humidity private, add wrapper functions.
|
||||
// 0.2.1 2020-05-06 fix temperature function (thanks Chade)
|
||||
// 0.2.2 2020-05-12 added ESP32 support
|
||||
// 0.2.3 2020-05-27 update library.json
|
||||
// 0.2.4 2020-12-09 arduino-ci
|
||||
// 0.3.0 2021-01-12 isConnected() + Wire0..Wire5 support
|
||||
|
||||
#include <AM232X.h>
|
||||
|
||||
#define AM232X_ADDRESS ((uint8_t)0x5C)
|
||||
#include "AM232X.h"
|
||||
|
||||
|
||||
#define AM232X_ADDRESS ((uint8_t)0x5C)
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PUBLIC
|
||||
//
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
void AM232X::begin(uint8_t sda, uint8_t scl)
|
||||
|
||||
AM232X::AM232X(TwoWire *wire)
|
||||
{
|
||||
Wire.begin(sda, scl);
|
||||
_wire = wire;
|
||||
}
|
||||
|
||||
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
bool AM232X::begin(uint8_t sda, uint8_t scl)
|
||||
{
|
||||
_wire = &Wire;
|
||||
_wire->begin(sda, scl);
|
||||
if (! isConnected()) return false;
|
||||
this->read();
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
void AM232X::begin()
|
||||
|
||||
bool AM232X::begin()
|
||||
{
|
||||
Wire.begin();
|
||||
_wire->begin();
|
||||
if (! isConnected()) return false;
|
||||
this->read();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool AM232X::isConnected()
|
||||
{
|
||||
_wire->beginTransmission(AM232X_ADDRESS);
|
||||
return ( _wire->endTransmission() == 0);
|
||||
}
|
||||
|
||||
|
||||
int AM232X::read()
|
||||
{
|
||||
// READ HUMIDITY AND TEMPERATURE REGISTERS
|
||||
@ -58,6 +82,7 @@ int AM232X::read()
|
||||
return AM232X_OK;
|
||||
}
|
||||
|
||||
|
||||
int AM232X::getModel()
|
||||
{
|
||||
int rv = _readRegister(0x08, 2);
|
||||
@ -66,6 +91,7 @@ int AM232X::getModel()
|
||||
return (bits[2] * 256) + bits[3];
|
||||
}
|
||||
|
||||
|
||||
int AM232X::getVersion()
|
||||
{
|
||||
int rv = _readRegister(0x0A, 1);
|
||||
@ -74,6 +100,7 @@ int AM232X::getVersion()
|
||||
return bits[2];
|
||||
}
|
||||
|
||||
|
||||
uint32_t AM232X::getDeviceID()
|
||||
{
|
||||
int rv = _readRegister(0x0B, 4);
|
||||
@ -85,6 +112,7 @@ uint32_t AM232X::getDeviceID()
|
||||
return _deviceID;
|
||||
}
|
||||
|
||||
|
||||
int AM232X::getStatus()
|
||||
{
|
||||
int rv = _readRegister(0x0F, 1);
|
||||
@ -93,6 +121,7 @@ int AM232X::getStatus()
|
||||
return bits[2];
|
||||
}
|
||||
|
||||
|
||||
int AM232X::getUserRegisterA()
|
||||
{
|
||||
int rv = _readRegister(0x10, 2);
|
||||
@ -101,6 +130,7 @@ int AM232X::getUserRegisterA()
|
||||
return (bits[2] * 256) + bits[3];
|
||||
}
|
||||
|
||||
|
||||
int AM232X::getUserRegisterB()
|
||||
{
|
||||
int rv = _readRegister(0x12, 2);
|
||||
@ -109,6 +139,7 @@ int AM232X::getUserRegisterB()
|
||||
return (bits[2] * 256) + bits[3];
|
||||
}
|
||||
|
||||
|
||||
int AM232X::setStatus(uint8_t value)
|
||||
{
|
||||
int rv = _writeRegister(0x0F, 1, value);
|
||||
@ -117,6 +148,7 @@ int AM232X::setStatus(uint8_t value)
|
||||
return AM232X_OK;
|
||||
}
|
||||
|
||||
|
||||
int AM232X::setUserRegisterA(int value)
|
||||
{
|
||||
int rv = _writeRegister(0x10, 2, value);
|
||||
@ -125,6 +157,7 @@ int AM232X::setUserRegisterA(int value)
|
||||
return AM232X_OK;
|
||||
}
|
||||
|
||||
|
||||
int AM232X::setUserRegisterB(int value)
|
||||
{
|
||||
int rv = _writeRegister(0x12, 2, value);
|
||||
@ -133,6 +166,7 @@ int AM232X::setUserRegisterB(int value)
|
||||
return AM232X_OK;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// PRIVATE
|
||||
@ -140,25 +174,25 @@ int AM232X::setUserRegisterB(int value)
|
||||
int AM232X::_readRegister(uint8_t reg, uint8_t count)
|
||||
{
|
||||
// wake up the sensor - see 8.2
|
||||
Wire.beginTransmission(AM232X_ADDRESS);
|
||||
int rv = Wire.endTransmission();
|
||||
_wire->beginTransmission(AM232X_ADDRESS);
|
||||
int rv = _wire->endTransmission();
|
||||
delayMicroseconds(1000); // TODO tune
|
||||
|
||||
// request the data
|
||||
Wire.beginTransmission(AM232X_ADDRESS);
|
||||
Wire.write(0x03);
|
||||
Wire.write(reg);
|
||||
Wire.write(count);
|
||||
rv = Wire.endTransmission();
|
||||
_wire->beginTransmission(AM232X_ADDRESS);
|
||||
_wire->write(0x03);
|
||||
_wire->write(reg);
|
||||
_wire->write(count);
|
||||
rv = _wire->endTransmission();
|
||||
if (rv < 0) return rv;
|
||||
|
||||
// request 4 extra, 2 for cmd + 2 for CRC
|
||||
uint8_t length = count + 4;
|
||||
int bytes = Wire.requestFrom(AM232X_ADDRESS, length);
|
||||
int bytes = _wire->requestFrom(AM232X_ADDRESS, length);
|
||||
|
||||
for (int i = 0; i < bytes; i++)
|
||||
{
|
||||
bits[i] = Wire.read();
|
||||
bits[i] = _wire->read();
|
||||
}
|
||||
// ANALYZE ERRORS
|
||||
// will not detect if we requested 1 byte as that will
|
||||
@ -186,11 +220,12 @@ int AM232X::_readRegister(uint8_t reg, uint8_t count)
|
||||
return AM232X_OK;
|
||||
}
|
||||
|
||||
|
||||
int AM232X::_writeRegister(uint8_t reg, uint8_t cnt, int16_t value)
|
||||
{
|
||||
// wake up the sensor - see 8.2
|
||||
Wire.beginTransmission(AM232X_ADDRESS);
|
||||
int rv = Wire.endTransmission();
|
||||
_wire->beginTransmission(AM232X_ADDRESS);
|
||||
int rv = _wire->endTransmission();
|
||||
delayMicroseconds(1000); // TODO tune
|
||||
|
||||
// prepare data to send
|
||||
@ -211,24 +246,24 @@ int AM232X::_writeRegister(uint8_t reg, uint8_t cnt, int16_t value)
|
||||
|
||||
// send data
|
||||
uint8_t length = cnt + 3; // 3 = cmd, startReg, #bytes
|
||||
Wire.beginTransmission(AM232X_ADDRESS);
|
||||
_wire->beginTransmission(AM232X_ADDRESS);
|
||||
for (int i=0; i< length; i++)
|
||||
{
|
||||
Wire.write(bits[i]);
|
||||
_wire->write(bits[i]);
|
||||
}
|
||||
// send the CRC
|
||||
uint16_t crc = crc16(bits, length);
|
||||
Wire.write(crc & 0xFF);
|
||||
Wire.write(crc >> 8);
|
||||
_wire->write(crc & 0xFF);
|
||||
_wire->write(crc >> 8);
|
||||
|
||||
rv = Wire.endTransmission();
|
||||
rv = _wire->endTransmission();
|
||||
if (rv < 0) return rv;
|
||||
|
||||
// wait for the answer
|
||||
int bytes = Wire.requestFrom(AM232X_ADDRESS, length);
|
||||
int bytes = _wire->requestFrom(AM232X_ADDRESS, length);
|
||||
for (int i = 0; i < bytes; i++)
|
||||
{
|
||||
bits[i] = Wire.read();
|
||||
bits[i] = _wire->read();
|
||||
}
|
||||
|
||||
// ANALYZE ERRORS
|
||||
@ -258,6 +293,7 @@ int AM232X::_writeRegister(uint8_t reg, uint8_t cnt, int16_t value)
|
||||
return AM232X_OK;
|
||||
}
|
||||
|
||||
|
||||
uint16_t AM232X::crc16(uint8_t *ptr, uint8_t len)
|
||||
{
|
||||
uint16_t crc =0xFFFF;
|
||||
|
@ -3,27 +3,41 @@
|
||||
// FILE: AM232X.h
|
||||
// AUTHOR: Rob Tillaart
|
||||
// PURPOSE: AM232X library for Arduino
|
||||
// VERSION: 0.2.3
|
||||
// VERSION: 0.3.0
|
||||
// HISTORY: See AM232X.cpp
|
||||
// URL: https://github.com/RobTillaart/AM232X
|
||||
//
|
||||
|
||||
#include "Wire.h"
|
||||
// Bottom view
|
||||
// +---+
|
||||
// VDD |o |
|
||||
// SDA |o |
|
||||
// GND |o |
|
||||
// SCL |o |
|
||||
// +---+
|
||||
|
||||
|
||||
#include "Arduino.h"
|
||||
#include "Wire.h"
|
||||
|
||||
|
||||
#define AM232X_LIB_VERSION (F("0.3.0"))
|
||||
|
||||
|
||||
|
||||
#define AM232X_OK 0
|
||||
#define AM232X_ERROR_UNKNOWN -10
|
||||
#define AM232X_ERROR_CONNECT -11
|
||||
#define AM232X_ERROR_FUNCTION -12
|
||||
#define AM232X_ERROR_ADDRESS -13
|
||||
#define AM232X_ERROR_REGISTER -14
|
||||
#define AM232X_ERROR_CRC_1 -15
|
||||
#define AM232X_ERROR_CRC_2 -16
|
||||
#define AM232X_ERROR_WRITE_DISABLED -17
|
||||
#define AM232X_ERROR_WRITE_COUNT -18
|
||||
#define AM232X_MISSING_BYTES -19
|
||||
|
||||
#define AM232X_LIB_VERSION "0.2.3"
|
||||
|
||||
#define AM232X_OK 0
|
||||
#define AM232X_ERROR_UNKNOWN -10
|
||||
#define AM232X_ERROR_CONNECT -11
|
||||
#define AM232X_ERROR_FUNCTION -12
|
||||
#define AM232X_ERROR_ADDRESS -13
|
||||
#define AM232X_ERROR_REGISTER -14
|
||||
#define AM232X_ERROR_CRC_1 -15
|
||||
#define AM232X_ERROR_CRC_2 -16
|
||||
#define AM232X_ERROR_WRITE_DISABLED -17
|
||||
#define AM232X_ERROR_WRITE_COUNT -18
|
||||
#define AM232X_MISSING_BYTES -19
|
||||
/*
|
||||
* from datasheet
|
||||
* 0x80: not support function code
|
||||
@ -36,36 +50,40 @@
|
||||
class AM232X
|
||||
{
|
||||
public:
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
void begin(uint8_t sda, uint8_t scl);
|
||||
#endif
|
||||
void begin();
|
||||
explicit AM232X(TwoWire *wire = &Wire);
|
||||
|
||||
int read();
|
||||
int getModel();
|
||||
int getVersion();
|
||||
#if defined (ESP8266) || defined(ESP32)
|
||||
bool begin(uint8_t sda, uint8_t scl);
|
||||
#endif
|
||||
bool begin();
|
||||
bool isConnected();
|
||||
|
||||
int read();
|
||||
int getModel();
|
||||
int getVersion();
|
||||
uint32_t getDeviceID();
|
||||
|
||||
int getStatus();
|
||||
int getUserRegisterA();
|
||||
int getUserRegisterB();
|
||||
int getStatus();
|
||||
int getUserRegisterA();
|
||||
int getUserRegisterB();
|
||||
|
||||
int setStatus(uint8_t value);
|
||||
int setUserRegisterA(int value);
|
||||
int setUserRegisterB(int value);
|
||||
int setStatus(uint8_t value);
|
||||
int setUserRegisterA(int value);
|
||||
int setUserRegisterB(int value);
|
||||
|
||||
inline float getHumidity() { return humidity; };
|
||||
inline float getHumidity() { return humidity; };
|
||||
inline float getTemperature() { return temperature; };
|
||||
|
||||
private:
|
||||
|
||||
uint8_t bits[8];
|
||||
float humidity;
|
||||
float temperature;
|
||||
|
||||
int _readRegister(uint8_t reg, uint8_t cnt);
|
||||
int _writeRegister(uint8_t reg, uint8_t cnt, int16_t value);
|
||||
uint8_t bits[8];
|
||||
float humidity;
|
||||
float temperature;
|
||||
|
||||
int _readRegister(uint8_t reg, uint8_t cnt);
|
||||
int _writeRegister(uint8_t reg, uint8_t cnt, int16_t value);
|
||||
uint16_t crc16(uint8_t *ptr, uint8_t len);
|
||||
|
||||
TwoWire* _wire;
|
||||
};
|
||||
|
||||
// -- END OF FILE --
|
||||
|
@ -1,6 +1,6 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2017-2020 Rob Tillaart
|
||||
Copyright (c) 2017-2021 Rob Tillaart
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -1,27 +1,88 @@
|
||||
|
||||
[![Arduino CI](https://github.com/RobTillaart/AM232X/workflows/Arduino%20CI/badge.svg)](https://github.com/marketplace/actions/arduino_ci)
|
||||
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://github.com/RobTillaart/AM232X/blob/master/LICENSE)
|
||||
[![GitHub release](https://img.shields.io/github/release/RobTillaart/AM232X.svg?maxAge=3600)](https://github.com/RobTillaart/AM232X/releases)
|
||||
|
||||
# AM232X
|
||||
|
||||
Arduino library for AM2320 AM2321 and AM2322 I2C temperature and humidity sensor
|
||||
|
||||
|
||||
## Description
|
||||
|
||||
AM232X is a sensor similar to the DHT12 with an I2C interface.
|
||||
Although in theory this could enable multiple sensors on one bus
|
||||
the AM232X has a fixed address 0x5C.
|
||||
the AM232X has a fixed address **0x5C** so
|
||||
|
||||
Typical parameters
|
||||
|
||||
| | range | accuracy | repeatability
|
||||
|:-------|:------:|:------:|:------:|
|
||||
| Temperature | -40 - 80 | 0.5°C | ±0.1 |
|
||||
| Humidity | 0.0 - 99.9 | 3% | ±0.1 |
|
||||
| Sample time | 2 seconds | | |
|
||||
|
||||
|
||||
```
|
||||
// Bottom view
|
||||
// +---+
|
||||
// VDD |o |
|
||||
// SDA |o |
|
||||
// GND |o |
|
||||
// SCL |o |
|
||||
// +---+
|
||||
```
|
||||
|
||||
|
||||
## Interface
|
||||
|
||||
### Constructor
|
||||
|
||||
- **AM232X(TwoWire \*wire = &Wire)** constructor, optionally set Wire0..WireN.
|
||||
- **bool begin(uint8_t sda, uint8_t scl)** for ESP32 alike devices, returns true if device is connected
|
||||
- **bool begin()** for AVR alike devices, returns true if device is connected
|
||||
- **bool isConnected()** returns true if device-address is found on I2C bus.
|
||||
|
||||
|
||||
### Base calls
|
||||
|
||||
- **int read()** fetches the values from the sensor
|
||||
- **float getHumidity()** returns the last read humidity
|
||||
- **float getTemperature()** returns the last read temperature
|
||||
|
||||
|
||||
### Misc
|
||||
|
||||
check datasheet for details.
|
||||
|
||||
- **int getModel()** idem
|
||||
- **int getVersion()** idem
|
||||
- **uint32_t getDeviceID()** idem
|
||||
- **int getStatus()**
|
||||
- **int getUserRegisterA()**
|
||||
- **int getUserRegisterB()**
|
||||
- **int setStatus(uint8_t value)**
|
||||
- **int setUserRegisterA(int value)**
|
||||
- **int setUserRegisterB(int value)**
|
||||
|
||||
|
||||
## Operation
|
||||
|
||||
See examples
|
||||
|
||||
In setup() you have to call the **begin()** to initialize
|
||||
the Wire library and do an initial **read()** to fill the
|
||||
variables temperature and humidity.
|
||||
To access these values one must use **getTemperature()** and **getHhumidity()**.
|
||||
To access these values one must use **getTemperature()** and **getHumidity()**.
|
||||
|
||||
|
||||
## Planned changes
|
||||
|
||||
Fix several TODO's in the code.
|
||||
|
||||
## Warning
|
||||
The library has several open ends so it is not suitable yet for
|
||||
any serious application.
|
||||
|
||||
See also LICENCE
|
||||
## Warning
|
||||
|
||||
The library has several open ends so use at own risk.
|
||||
|
||||
See also LICENSE
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user