-
Notifications
You must be signed in to change notification settings - Fork 949
Add additional C++ Example for AM2302-Sensor #450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
hasenradball
wants to merge
8
commits into
raspberrypi:develop
Choose a base branch
from
hasenradball:add_cpp_example_for_AM2302_sensor
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 5 commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
3117204
add c++ example for AM2302_sensor
hasenradball 8c3c1f2
remame and comment added for readfrequency variable
hasenradball 6e76c49
rework for LED PIN
hasenradball a287b8a
use default LED PIN
hasenradball 7d1e2c5
improve error handling; and use Sensor Array as example
hasenradball e0934ce
fix review findings
hasenradball ad7d09f
updated file Information and licence
hasenradball d4f1923
make get_sensorState() static
hasenradball File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,252 @@ | ||
/* | ||
* AM2302-Sensor.cpp | ||
* | ||
* Author: Frank Häfele | ||
* Date: 21.11.2023 | ||
* | ||
* Object: Measure Sensor Data of AM2302-Sensor | ||
* | ||
*/ | ||
#include "AM2302-Sensor.hpp" | ||
|
||
/** | ||
* @brief Construct a new am2302::am2302 sensor::am2302 sensor object | ||
* | ||
* @param pin Pin for AM2302 sensor | ||
*/ | ||
AM2302::AM2302_Sensor::AM2302_Sensor(uint8_t pin) : _millis_last_read{0}, _pin{pin} | ||
{} | ||
|
||
/** | ||
* @brief begin function setup pin and run sensor check. | ||
* | ||
* @return true if sensor check is successful. | ||
* @return false if sensor check failed. | ||
*/ | ||
bool AM2302::AM2302_Sensor::begin() { | ||
gpio_init(_pin); | ||
gpio_pull_up(_pin); | ||
// required delay() for a secure sensor check, | ||
// if you reset the mcu very fast one after another | ||
auto tic{time_us_64()}; | ||
while ( time_us_64() - tic < READ_FREQUENCY * 1000U ) { | ||
sleep_ms(1U); | ||
} | ||
auto status{read()}; | ||
_millis_last_read = time_us_64(); | ||
lurch marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (status == AM2302_READ_OK) { | ||
return true; | ||
} | ||
else { | ||
return false; | ||
} | ||
} | ||
|
||
/** | ||
* @brief read functionality | ||
* | ||
* @return sensor status | ||
*/ | ||
int8_t AM2302::AM2302_Sensor::read() { | ||
auto status{read_sensor()}; | ||
|
||
if (status == AM2302_READ_OK) { | ||
// return status immediately | ||
return status; | ||
} | ||
else if (status == AM2302_ERROR_READ_FREQ) { | ||
return status; | ||
} | ||
else if (status == AM2302_ERROR_TIMEOUT) { | ||
resetData(); | ||
return status; | ||
} | ||
else if (status == AM2302_ERROR_CHECKSUM) { | ||
// nothing to do | ||
return status; | ||
} | ||
return status; | ||
} | ||
|
||
/** | ||
* @brief initiate start sequence and read sensor data | ||
* | ||
* @return sensor status | ||
*/ | ||
int8_t AM2302::AM2302_Sensor::read_sensor() { | ||
// check read frequency | ||
if ( time_us_64() - _millis_last_read < READ_FREQUENCY * 1000U) { | ||
return AM2302_ERROR_READ_FREQ; | ||
} | ||
_millis_last_read = time_us_64(); | ||
// ***************************** | ||
// === send start sequence === | ||
// **************************** | ||
// start from HIGH ==> switch to LOW for min. of 1 ms | ||
// Set pin to Output | ||
gpio_set_dir(_pin, GPIO_OUT); | ||
// set Pin to LOW | ||
gpio_put(_pin, 0); | ||
// wait min. 1,0 ms | ||
sleep_us(1200U); | ||
// Set port to HIGH ==> INPUT_PULLUP with PullUp | ||
gpio_put(_pin, 1); | ||
gpio_set_dir(_pin, GPIO_IN); | ||
// delay_us(30.0); not needed | ||
|
||
// ****************************** | ||
// === wait for Acknowledge === | ||
// ****************************** | ||
// Acknowledge Sequence 80us LOW 80 us HIGH | ||
// wait for LOW (80 µs) | ||
await_state(0); | ||
// wait for HIGH (80 µs) | ||
await_state(1); | ||
|
||
// ***************************** | ||
// ==== Read Sensor Data ==== | ||
// ***************************** | ||
// ==> START of time critical code <== | ||
// read 40 bits from sensor into the buffer: | ||
// ==> HIGH state is 70 µs | ||
// ==> LOW state is 28 µs | ||
uint8_t _data[5U] = {0}; | ||
if (read_sensor_data(_data, 5U) == AM2302_ERROR_TIMEOUT) { | ||
return AM2302_ERROR_TIMEOUT; | ||
} | ||
// ==> END of time critical code <== | ||
|
||
// check checksum | ||
_checksum_ok = (_data[4] == ( (_data[0] + _data[1] + _data[2] + _data[3]) & 0xFF) ); | ||
|
||
/* | ||
// Code part to check the checksum | ||
// Due to older sensors have an bug an deliver wrong data | ||
auto d4 = _data[4]; | ||
auto cs = ( (_data[0] + _data[1] + _data[2] + _data[3]) & 0xFF) ; | ||
Serial.print("delivered Checksum: "); | ||
AM2302_Tools::print_byte_as_bit(d4); | ||
Serial.print("calculated Checksum: "); | ||
AM2302_Tools::print_byte_as_bit(cs); | ||
*/ | ||
|
||
if (_checksum_ok) { | ||
_hum = static_cast<uint16_t>((_data[0] << 8) | _data[1]); | ||
if (_data[2] & 0x80) { | ||
// negative temperature detected | ||
_data[2] &= 0x7f; | ||
_temp = -static_cast<int16_t>((_data[2] << 8) | _data[3]); | ||
} | ||
else { | ||
_temp = static_cast<int16_t>((_data[2] << 8) | _data[3]); | ||
} | ||
return AM2302_READ_OK; | ||
} | ||
else { | ||
return AM2302_ERROR_CHECKSUM; | ||
} | ||
} | ||
|
||
/** | ||
* @brief wait for a specific pin state | ||
* | ||
* @param state state to wait for | ||
* @return int8_t status | ||
*/ | ||
int8_t AM2302::AM2302_Sensor::await_state(uint8_t state) { | ||
uint8_t wait_counter{0}, state_counter{0}; | ||
// count wait for state time | ||
while ( (gpio_get(_pin) != state) ) { | ||
++wait_counter; | ||
sleep_us(1U); | ||
if (wait_counter >= READ_TIMEOUT) { | ||
return AM2302_ERROR_TIMEOUT; | ||
} | ||
} | ||
// count state time | ||
while ( (gpio_get(_pin) == state) ) { | ||
++state_counter; | ||
sleep_us(1U); | ||
if (state_counter >= READ_TIMEOUT) { | ||
return AM2302_ERROR_TIMEOUT; | ||
} | ||
} | ||
return (state_counter > wait_counter); | ||
} | ||
|
||
/** | ||
* @brief read sensor data | ||
* | ||
* @param buffer data buffer of 40 bit | ||
* @param size of buffer => 40 | ||
* @return int8_t | ||
*/ | ||
int8_t AM2302::AM2302_Sensor::read_sensor_data(uint8_t *buffer, uint8_t size) { | ||
for (uint8_t i = 0; i < size; ++i) { | ||
for (uint8_t bit = 0; bit < 8U; ++bit) { | ||
uint8_t wait_counter{0}, state_counter{0}; | ||
// count wait for state time | ||
while ( !gpio_get(_pin) ) { | ||
++wait_counter; | ||
sleep_us(1U); | ||
if (wait_counter >= READ_TIMEOUT) { | ||
return AM2302_ERROR_TIMEOUT; | ||
} | ||
} | ||
// count state time | ||
while ( gpio_get(_pin) ) { | ||
++state_counter; | ||
sleep_us(1U); | ||
if (state_counter >= READ_TIMEOUT) { | ||
return AM2302_ERROR_TIMEOUT; | ||
} | ||
} | ||
buffer[i] <<= 1; | ||
buffer[i] |= (state_counter > wait_counter); | ||
} | ||
} | ||
return AM2302_READ_OK; | ||
} | ||
|
||
/** | ||
* @brief get Sensor State in human readable manner | ||
* | ||
* @return sensor state | ||
*/ | ||
const char * AM2302::AM2302_Sensor::get_sensorState(int8_t state) const { | ||
if(state == AM2302_READ_OK) { | ||
return AM2302_STATE_OK; | ||
} | ||
else if(state == AM2302_ERROR_CHECKSUM) { | ||
return AM2302_STATE_ERR_CKSUM; | ||
} | ||
else if(state == AM2302_ERROR_TIMEOUT) { | ||
return AM2302_STATE_ERR_TIMEOUT; | ||
} | ||
else if(state == AM2302_ERROR_READ_FREQ) { | ||
return AM2302_STATE_ERR_READ_FREQ; | ||
} | ||
} | ||
|
||
/** | ||
* @brief reset temperature and humidity data | ||
* | ||
*/ | ||
void AM2302::AM2302_Sensor::resetData() { | ||
// reset tem to -255 and hum to 0 as indication | ||
_temp = -2550; | ||
_hum = 0; | ||
} | ||
|
||
/** | ||
* @brief helper function to print byte as bit | ||
* | ||
* @param value byte with 8 bits | ||
*/ | ||
void AM2302_Tools::print_byte_as_bit(char value) { | ||
for (int i = 7; i >= 0; --i) { | ||
char c = (value & (1 << i)) ? '1' : '0'; | ||
printf("%c", c); | ||
} | ||
printf("\n"); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/*__AM2302_SENSOR_H__ | ||
* AM2302-Sensor.h | ||
* | ||
* Author: Frank Häfele | ||
* Date: 21.11.2023 | ||
* | ||
* Object: Measure Sensor Data of AM2302-Sensor | ||
* | ||
*/ | ||
|
||
#ifndef __AM2302_SENSOR_H__ | ||
#define __AM2302_SENSOR_H__ | ||
#include <cstdint> | ||
#include <cstdio> | ||
#include "pico/stdlib.h" | ||
#include "hardware/gpio.h" | ||
|
||
namespace AM2302 { | ||
|
||
constexpr const char * AM2302_STATE_OK{"OK"}; | ||
constexpr const char * AM2302_STATE_ERR_CKSUM{"Error: Checksum"}; | ||
constexpr const char * AM2302_STATE_ERR_TIMEOUT{"Error: Timeout"}; | ||
constexpr const char * AM2302_STATE_ERR_READ_FREQ{"Error: Read Frequency"}; | ||
|
||
constexpr int8_t AM2302_READ_OK {0}; | ||
constexpr int8_t AM2302_ERROR_CHECKSUM {-1}; | ||
constexpr int8_t AM2302_ERROR_TIMEOUT {-2}; | ||
constexpr int8_t AM2302_ERROR_READ_FREQ {-3}; | ||
|
||
// define timeout in 100 µs | ||
constexpr uint8_t READ_TIMEOUT {100U}; | ||
constexpr uint16_t READ_FREQUENCY {2000U}; | ||
|
||
class AM2302_Sensor { | ||
|
||
public: | ||
explicit AM2302_Sensor(uint8_t pin); | ||
bool begin(); | ||
int8_t read(); | ||
float get_Temperature() const {return _temp * 0.1F;} | ||
float get_Humidity() const {return _hum * 0.1F;} | ||
const char * get_sensorState(int8_t state) const; | ||
|
||
private: | ||
unsigned long _millis_last_read; | ||
uint16_t _hum {0}; | ||
int16_t _temp {0}; | ||
uint8_t _pin; | ||
bool _checksum_ok {false}; | ||
int8_t await_state(uint8_t state); | ||
int8_t read_sensor(); | ||
int8_t read_sensor_data(uint8_t *buffer, uint8_t const size); | ||
void resetData(); | ||
}; | ||
} | ||
|
||
namespace AM2302_Tools { | ||
void print_byte_as_bit(char value); | ||
} | ||
|
||
#endif |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
/** | ||
* Author: Frank Häfele | ||
* | ||
* Date: 25.04.2024 | ||
* | ||
* Objective: Read one or multiple AM2302-Sensors | ||
*/ | ||
|
||
#include <cstdio> | ||
#include "pico/stdlib.h" | ||
#include "AM2302-Sensor.hpp" | ||
|
||
const uint LED_PIN = PICO_DEFAULT_LED_PIN; | ||
|
||
// DHT Pin | ||
const uint8_t SIZE = 3U; | ||
const uint8_t PINS[SIZE] = {13U, 14U, 15U}; | ||
|
||
// create am2302 object | ||
AM2302::AM2302_Sensor am2302[SIZE] = { | ||
AM2302::AM2302_Sensor{PINS[0]}, | ||
AM2302::AM2302_Sensor{PINS[1]}, | ||
AM2302::AM2302_Sensor{PINS[2]} | ||
}; | ||
|
||
int main() { | ||
stdio_init_all(); | ||
|
||
gpio_init(LED_PIN); | ||
gpio_set_dir(LED_PIN, GPIO_OUT); | ||
|
||
printf("\n\n === Pi Pico C++ Example - Read AM2302-Sensor === \n\n"); | ||
// setup pin and do a sensor check | ||
|
||
for (size_t i = 0; i < SIZE; ++i) { | ||
printf("Sensor available : %d\n", am2302[i].begin()); | ||
} | ||
printf("\n"); | ||
sleep_ms(3000); | ||
while (true) { | ||
|
||
gpio_put(LED_PIN, 1); | ||
printf("\n\tStatus :"); | ||
for (size_t i = 0; i < SIZE; ++i) { | ||
printf("\t%s", am2302[i].get_sensorState(am2302[i].read())); | ||
} | ||
printf("\n\tTemperature :"); | ||
gpio_put(LED_PIN, 0); | ||
|
||
for (size_t i = 0; i < SIZE; ++i) { | ||
printf("\t%5.2f", am2302[i].get_Temperature()); | ||
} | ||
printf("\n\tHumidity :"); | ||
for (size_t i = 0; i < SIZE; ++i) { | ||
printf("\t%5.2f", am2302[i].get_Humidity()); | ||
} | ||
printf("\n\n"); | ||
sleep_ms(10000); | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
add_executable(AM2302 AM2302.cpp AM2302-Sensor.cpp) | ||
|
||
target_link_libraries(AM2302 pico_stdlib) | ||
|
||
pico_add_extra_outputs(AM2302) | ||
|
||
# add url via pico_set_program_url | ||
example_auto_set_url(AM2302) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.