Skip to content
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

Add additional C++ Example for AM2302-Sensor #450

Open
wants to merge 8 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
191 changes: 191 additions & 0 deletions gpio/AM2302_sensor/AM2302-Sensor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
/*
* AM2302-Sensor.cpp
*
* Author: Frank Häfele
lurch marked this conversation as resolved.
Show resolved Hide resolved
* 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) : _us_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);
// 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()};
_us_last_read = time_us_64();
if (status == AM2302_READ_OK) {
return true;
}
else {
return false;
}
}


int8_t AM2302::AM2302_Sensor::read() {
// check read frequency
if ( time_us_64() - _us_last_read < READ_FREQUENCY * 1000U) {
return AM2302_ERROR_READ_FREQ;
}
_us_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 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");
}
55 changes: 55 additions & 0 deletions gpio/AM2302_sensor/AM2302-Sensor.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
/*__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 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};

// define maximum sensor read frequency in milliseconds (2 s)
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;}

private:
unsigned long _us_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_data(uint8_t *buffer, uint8_t const size);
};
}

namespace AM2302_Tools {
void print_byte_as_bit(char value);
}

#endif
61 changes: 61 additions & 0 deletions gpio/AM2302_sensor/AM2302.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/**
* Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/

#include <cstdio>
#include "pico/stdlib.h"
#include "AM2302-Sensor.hpp"

const uint LED_PIN = 13U;
lurch marked this conversation as resolved.
Show resolved Hide resolved

// DHT Pin
const uint DHT_PIN = 15;

// create am2302 object
AM2302::AM2302_Sensor am2302{DHT_PIN};

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
if (!am2302.begin()) {
while(true) {
printf("ERROR: during sensor check! Pleae check sensor connectivity!\n");
sleep_ms(10000);
}
}
sleep_ms(3000);
while (true) {

gpio_put(LED_PIN, 1);
int8_t status = am2302.read();

gpio_put(LED_PIN, 0);

printf("Sensor-status: %d\n", status);

if (status == AM2302::AM2302_READ_OK) {
printf("Humidity = %.1f %%\tTemperature = %.1f degC\n",
am2302.get_Humidity(), am2302.get_Temperature());
}
else {
if (status == AM2302::AM2302_ERROR_CHECKSUM) {
printf("ERROR: Checksum not valid\n");
}
else if (status == AM2302::AM2302_ERROR_TIMEOUT) {
printf("ERROR: Timeout overflow\n");
}
else if (status == AM2302::AM2302_ERROR_READ_FREQ) {
printf("ERROR: Read frequency too high!\n");
}
}
printf("\n\n");
sleep_ms(2000);
}
}
8 changes: 8 additions & 0 deletions gpio/AM2302_sensor/CMakeLists.txt
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)
1 change: 1 addition & 0 deletions gpio/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
if (NOT PICO_NO_HARDWARE)
add_subdirectory(AM2302_sensor)
add_subdirectory(dht_sensor)
add_subdirectory(hello_7segment)
add_subdirectory(hello_gpio_irq)
Expand Down