I’m very new to programming and I’m playing with a aht21 temp and humidity sensor with my duo. I’m working off the C sdk. I’ve been able to recognize the sensor and send the 3 byte trigger measurement command with WriteReg16 . The sensor returns 7 bytes of information and I need to read all of them. WiringX doesn’t seem to have a way to do this. If I try to use 7 individual wiringXI2CRead(), I just get the 1st byte over and over. Like I said I’m new to all of this so I hope this is easy. Thanks
I tried to do it with WiringX, but unless I am mistaken it can’t be done with WiringX. I ported some of my old MicroPython i2c bitbang code over to C and got it working. It can definitely be improved, but it works. I start it with a shell script to pinmux the pins I used as GPIO. Don’t forget your pullup resistors on the SDA and SCL lines. Have fun with it. (Oh ya, if you’re trying to copy my breadboard wiring a lot of those wires are leftovers from the Sharp Memory LCD. I didn’t feel like pulling them all out yet.)
aht21b.c
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <wiringx.h>
#include "aht21b.h"
unsigned char i2c_address = 0x38;
int dat = 10;
int clk = 11;
int dely = 10;
int delyhalf = 5;
unsigned char tri[3];
unsigned long int six[6];
unsigned char temp[1];
int main(){
float temperature_c,temperature_f,humidity;
init();
while(1){
i2c_address = i2c_address & 0xfe; //clear low bit to write
i2c_start();
write3(0xac,0x33,0x00); //trigger measurement
i2c_stop();
usleep(100000); //wait for measurement
//should check status here, but delay is long enough
i2c_address = i2c_address | 0x01; //set low bit to read
i2c_start();
for(int i=0;i<5;i++) //read first 5 bytes of measurement
six[i] = i2c_read();
six[5] = i2c_read_nack(); //read 6th byte with nack to end (skip crc)
i2c_stop();
//convert temperature
float i = ((six[3] & 0x0f) << 16) | (six[4] << 8) | six[5];
temperature_c = ((i / 1048576) * 200) -50;
temperature_f = ((temperature_c * 9) / 5) + 32;
printf("Temperature: %.1fF - %.1fC\n",temperature_f,temperature_c);
//convert humidity
i = ((six[1] << 16) | (six[2] << 8) | six[3]) >> 4;
humidity = (i / 1048576) * 100;
printf("Humidity: %.1f\n\n",humidity);
sleep(2);
}
}
void write3(unsigned char one,unsigned char two,unsigned char three){
tri[0] = one;
tri[1] = two;
tri[2] = three;
for(int i=0;i<3;i++)
i2c_write(tri[i]);
}
int init(void){
if(wiringXSetup("duo", NULL) == -1) {
wiringXGC();
return -1;
}
// shift address over to high bits and slide in write bit at 0
i2c_address = i2c_address << 1;
pinMode(dat,PINMODE_OUTPUT);
pinMode(clk,PINMODE_OUTPUT);
digitalWrite(dat, LOW); //dat == 0 when set as output
digitalWrite(clk, LOW); //clk == 0 when set as output
pinMode(dat,PINMODE_INPUT); //dat pin high
pinMode(clk,PINMODE_INPUT); //clk pin high
usleep(100000); //stabilization delay
}
//*************************
//* bitbang I2C functions *
//*************************
unsigned char i2c_write(unsigned char x){
unsigned char i;
usleep(dely);
for(i=0;i<8;i++){ //clock out data byte
pinMode(dat,PINMODE_OUTPUT); //set data bit low
if(x & 0x80) //if output bit is high
pinMode(dat,PINMODE_INPUT); //then set data bit high
i2c_clock(); //clock it out
x <<= 1; //shift next bit into position
}
//get ack
pinMode(dat,PINMODE_INPUT); //set data high
pinMode(clk,PINMODE_INPUT); //set clock high
usleep(delyhalf); //wait half a clock pulse
if(digitalRead(dat)) //sample the data bit
return(1); //if high then nack error
usleep(delyhalf); //ack good, wait other half of clock pulse
pinMode(clk,PINMODE_OUTPUT); //set clock low
usleep(dely);
pinMode(dat,PINMODE_INPUT); //set data high
return(0);
}
void i2c_start(void){ //send start condition
pinMode(dat,PINMODE_OUTPUT); //set data low
usleep(dely);
pinMode(clk,PINMODE_OUTPUT); //set clock low
usleep(dely);
i2c_write(i2c_address);
}
void i2c_stop(void){ //send stop condition
pinMode(dat,PINMODE_OUTPUT); //set data low
usleep(dely);
pinMode(clk,PINMODE_INPUT); //set clock high
usleep(dely); //stop delay
pinMode(dat,PINMODE_INPUT); //set data high
usleep(dely);
}
void i2c_clock(void){
pinMode(clk,PINMODE_INPUT); //set clock high
usleep(dely);
pinMode(clk,PINMODE_OUTPUT); //set clock low
usleep(dely);
}
void i2c_restart(void){ //send start condition
pinMode(dat,PINMODE_INPUT); //release data
usleep(dely);
pinMode(clk,PINMODE_INPUT);
usleep(dely);
pinMode(dat,PINMODE_OUTPUT);
usleep(dely);
pinMode(clk,PINMODE_OUTPUT);
usleep(dely);
}
unsigned char i2c_read(void){
unsigned char i,tmp = 0;
static unsigned char mbit = 0;
usleep(dely); //10uS delay
for(i=0;i<8;i++){
pinMode(dat,PINMODE_INPUT); //data pin high
usleep(dely); //minimum clock low time
pinMode(clk,PINMODE_INPUT); //clk high
usleep(delyhalf); //1/2 min clock high time
mbit = digitalRead(dat); //read the data bit
if(mbit) //store it in tmp
tmp = tmp | 0x01;
usleep(delyhalf); //last 1/2 min clock high time
if(i < 7)
tmp <<= 1; //shift left for next bit
pinMode(clk,PINMODE_OUTPUT); //clk low
usleep(dely); //minimum clock low time
}
pinMode(dat,PINMODE_OUTPUT);
digitalWrite(dat, 0); //clear data & send ACK
usleep(dely); //data settle time
i2c_clock(); //pulse the clock
pinMode(dat,PINMODE_INPUT); //release ACK
usleep(dely); //gap between next byte
return(tmp);
}
unsigned char i2c_read_nack(void){
unsigned char i,tmp = 0;
static unsigned char mbit;
usleep(dely);
for(i=0;i<8;i++){
pinMode(dat,PINMODE_INPUT); //data high
usleep(dely); //minimum clock low time
pinMode(clk,PINMODE_INPUT); //clk high
usleep(delyhalf); //1/2 min clock high time
mbit = digitalRead(dat); //read the data bit
if(mbit) //store it in tmp
tmp = tmp | 0x01;
usleep(delyhalf); //last 1/2 min clock high time
if(i < 7)
tmp <<= 1; //shift left for next bit
pinMode(clk,PINMODE_OUTPUT); //clk low
usleep(dely); //minimum clock low time
}
pinMode(dat,PINMODE_OUTPUT);
digitalWrite(dat,LOW); //clear data
pinMode(dat,PINMODE_INPUT); //send NACK
usleep(dely); //data settle time
i2c_clock(); //pulse the clock
return(tmp);
}
aht21b.h
void write3(unsigned char,unsigned char,unsigned char);
int init(void);
unsigned char i2c_read(void);
unsigned char i2c_read_nack(void);
unsigned char i2c_write(unsigned char);
void i2c_start(void);
void i2c_restart(void);
void i2c_stop(void);
void i2c_clock(void);
aht21b-script
duo-pinmux -w GP10/GP10
duo-pinmux -w GP11/GP11
./aht21b
Thanks. It totally answers my question, it’s too bad you can’t use wiringX to read the aht21. I’ll give you code a try. I should be able to get it running.
See if you think temperature readings seem a little bit high with the AHT21B. If you’ve read my web page about it, I was musing about whether it reads high (probably not), or the conversion isn’t quite right (maybe), or if it’s spot on and my thermostats are both off. But last night I had thermostat set to 70F - house seemed comfortable. And the AHT21B program said it was 72.9F! I don’t think so, but maybe. I might tinker with calibration later.
I got a DHT-11 sort of working on the Duo last night. According to its measurements the AHT21B is dead on. My Honeywell T4 Pro thermostat reads almost 3 degrees F too low. Guess I should open it up and see if there’s a calibration trimpot in there somewhere.
Getting DHT-11 working with no access to timers is a bit hard, and so far it’s not reliable. My crappy code gets stuck pretty often. Using C clock is too slow, as the DHT-11 uses timing of 26 to 28uS. Maybe I can fix it today. Maybe not.
I guess my other thermometers are reading low as well because I was getting readings that were a little high as well.
You got it working with your library?
Does this mean that wiringX library is broken?
I got the aht21 working on my rpi pico, I havn’t been able to get to work with the duo and wiring x. You cloud bitbang it with wiringx or write driver that controls the i2c peripheral on the chip directly . As far as that temp sensor, yes wiringx is broken. I haven’t explored using i2c tools and the linux system to control that sensor. It would be nice if we could get the source code for wiringx as I don’t think it would be that much of a change to get it to read 3 bytes in a row. In general I’ve found wiringx to be a disappointment if you want to do anything more than turn a gpio on and off.
I have found this: GitHub - wiringX/wiringX: Modular GPIO interface , but it doesn’t support duo…
Yeah, I’ve used that a lot to try and figure out how to use some features of wiringx, but we really need the code for the port to the duo.
Maybe we don’t even need that wiringx library
Check this doc @ page 20
Thats very interesting, I I wondered if wiringx was going thru the kernel space to access the peripherals or addressing the hardware it’s self? I did make a program to run ws2812 and I used the pwm directly and I still had trouble getting the speed I needed. I highly doubt going thru the kernel would have been fast enough. Either way I’ll have to look at it some more.
Did you get the WS2812s working? I wanted to try to control 4 of them on my board.
yes I did for the 64. it should work on pin GP2/PWM10 if I recall correctly.