199 lines
5.7 KiB
C++
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);
|
|
}
|
|
}
|