sensors/sensors.cpp
2024-11-22 16:09:13 +01:00

199 lines
5.7 KiB
C++

#include <stdio.h>
#include "pico/stdlib.h"
#include "hardware/i2c.h"
#include "hardware/pwm.h"
#include "hardware/clocks.h"
// I2C defines
// This example will use I2C0 on GPIO8 (SDA) and GPIO9 (SCL) running at 400KHz.
// Pins can be changed, see the GPIO function select table in the datasheet for information on GPIO assignments
#define I2C_PORT i2c0
#define I2C_SDA 8
#define I2C_SCL 9
#define CO2_PIN 5
void measure_freqs(void) {
uint f_pll_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_SYS_CLKSRC_PRIMARY);
uint f_pll_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_PLL_USB_CLKSRC_PRIMARY);
uint f_rosc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_ROSC_CLKSRC);
uint f_clk_sys = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_SYS);
uint f_clk_peri = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_PERI);
uint f_clk_usb = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_USB);
uint f_clk_adc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_ADC);
uint f_clk_rtc = frequency_count_khz(CLOCKS_FC0_SRC_VALUE_CLK_RTC);
printf("pll_sys = %dkHz\n", f_pll_sys);
printf("pll_usb = %dkHz\n", f_pll_usb);
printf("rosc = %dkHz\n", f_rosc);
printf("clk_sys = %dkHz\n", f_clk_sys);
printf("clk_peri = %dkHz\n", f_clk_peri);
printf("clk_usb = %dkHz\n", f_clk_usb);
printf("clk_adc = %dkHz\n", f_clk_adc);
printf("clk_rtc = %dkHz\n", f_clk_rtc);
// Can't measure clk_ref / xosc as it is the ref
}
float measure_co2(float *max, float *c) {
// Only the PWM B pins can be used as inputs.
assert(pwm_gpio_to_channel(CO2_PIN) == PWM_CHAN_B);
uint slice_num = pwm_gpio_to_slice_num(CO2_PIN);
// Count once for every 2000 cycles the PWM B input is high
pwm_config cfg = pwm_get_default_config();
// pwm_config_set_wrap(&cfg, 64000);
pwm_config_set_clkdiv_mode(&cfg, PWM_DIV_B_HIGH);
pwm_config_set_clkdiv(&cfg, 2000);
pwm_init(slice_num, &cfg, false);
pwm_set_counter(slice_num, 0);
gpio_set_function(CO2_PIN, GPIO_FUNC_PWM);
pwm_set_enabled(slice_num, true);
sleep_ms(1004);
pwm_set_enabled(slice_num, false);
float count = pwm_get_counter(slice_num);
float counting_rate = clock_get_hz(clk_sys) / 2000.0;
float max_possible_count = counting_rate * 1.002;
//return count;
*max = max_possible_count;
*c = count;
return 2000.0 * count / max_possible_count;
// co2 = 2000.0*(TH-2ms)/(TH+TL-4ms)
}
// I2C reserves some addresses for special purposes. We exclude these from the scan.
// These are any addresses of the form 000 0xxx or 111 1xxx
bool reserved_addr(uint8_t addr) {
return (addr & 0x78) == 0 || (addr & 0x78) == 0x78;
}
void i2cscan()
{
printf("\nI2C Bus Scan\n");
printf(" 0 1 2 3 4 5 6 7 8 9 A B C D E F\n");
for (int addr = 0; addr < (1 << 7); ++addr) {
if (addr % 16 == 0) {
printf("%02x ", addr);
}
// Perform a 1-byte dummy read from the probe address. If a slave
// acknowledges this address, the function returns the number of bytes
// transferred. If the address byte is ignored, the function returns
// -1.
// Skip over any reserved addresses.
int ret;
uint8_t rxdata;
if (reserved_addr(addr))
ret = PICO_ERROR_GENERIC;
else
ret = i2c_read_blocking(I2C_PORT, addr, &rxdata, 1, true);
printf(ret < 0 ? "." : "@");
printf(addr % 16 == 15 ? "\n" : " ");
}
}
int measure_i2c_co2(float *co2, float *temp, float *rh) {
uint8_t has_measurement[] = {0xE4, 0xB8};
uint8_t read_measurement[] = {0xEC, 0x05};
uint8_t data[9];
int count;
*co2 = 0;
*temp = 0;
*rh = 0;
if ((count = i2c_write_blocking(I2C_PORT, 0x62, has_measurement, 2, false)) != 2) {
*co2 = count;
return 1;
}
if ((count = i2c_read_blocking(I2C_PORT, 0x62, data, 3, false)) != 3 ||
(data[2] == 0 && data[1] == 0 && data[0] & 0x7 == 0)) {
*co2 = count;
printf(" data: %b %b %b", data[2], data[1], data[0]);
return 2;
}
if ((count = i2c_write_blocking(I2C_PORT, 0x62, read_measurement, 2, false)) != 2) {
*co2 = count;
return 3;
}
if ((count = i2c_read_blocking(I2C_PORT, 0x62, data, 9, false)) != 9) {
*co2 = count;
return 4;
}
*co2 = data[0] * 256.0 + data[1];
*temp = -45.0 + 175.0 * (data[3] * 256.0 + data[4]) / 0xFFFF;
*rh = 100 * (data[6] * 256.0 + data[7]) / 0xFFFF;
return 0;
}
int main()
{
stdio_usb_init();
// I2C Initialisation. Using it at 100Khz.
i2c_init(I2C_PORT, 400*1000);
gpio_set_function(I2C_SDA, GPIO_FUNC_I2C);
gpio_set_function(I2C_SCL, GPIO_FUNC_I2C);
// gpio_init(CO2_PIN);
// gpio_set_dir(CO2_PIN, GPIO_OUT);
gpio_pull_up(I2C_SDA);
gpio_pull_up(I2C_SCL);
// For more examples of I2C use see https://github.com/raspberrypi/pico-examples/tree/master/i2c
// get clock of RPI
int slice = pwm_gpio_to_slice_num(0);
pwm_config config = pwm_get_default_config();
//bi_decl(bi_2pins_with_func(PICO_DEFAULT_I2C_SDA_PIN,
//PICO_DEFAULT_I2C_SCL_PIN, GPIO_FUNC_I2C));
int w = i2c_write_blocking(I2C_PORT, 0x62, (const uint8_t*)"\x21\xb1", 2, false);
sleep_ms(5000);
printf("bytes written on init: %d\n", w);
bool on = false;
while (true) {
// measure_freqs();aa
float c, m;
float co2 = measure_co2(&m, &c);
// i2cscan();
printf("Hello CO2: %f %f / %f\n", co2, c, m);
/*
float temp1, h1;
float temp2, h2;
*/
float temp, rh;
int r = measure_i2c_co2(&co2, &temp, &rh);
printf(" %d -- ac. CO2: %f T: %f RH: %f\n", r, co2, temp, rh);
//gpio_put(CO2_PIN, on);
//printf("pin is %d\n", (int)on);
//on = !on;
sleep_ms(5000);
}
}