在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20

前面两篇文章有点水,我也是这么认为的。所以这一篇我想写得好点:)


DS18B20是一个比较热门的器件,想当初学51,PIC,STC,STM32的时候都做过这个一线器件的实验,现在玩树莓派的gpio,自然的就想起了这个,wiringPi没有直接的一线器件相关的函数,所以我们就只有自己写。

先说下电路连接,我用的是一般接法。

在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第1张图片

原理等内容不再累述,直接进入根据时序图写程序的环节。

在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第2张图片

int oneWireReset(int pin)
{
    pinMode(pin,OUTPUT);
    digitalWrite(pin,HIGH);
    digitalWrite(pin,LOW);
    delayMicroseconds(480);
    digitalWrite(pin,HIGH);
    delayMicroseconds(30);
    pinMode(pin,INPUT);
    if(digitalRead(pin) == LOW)
    {
        ack = 1;
    }
    else
    {
        ack = 0;
    }
    delayMicroseconds(450);
    return ack;
}


在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第3张图片

void writeBit(int pin,int bit)
{
     pinMode(pin,OUTPUT);
     digitalWrite(pin,LOW);
     delayMicroseconds(15);
     digitalWrite(pin,bit);
     delayMicroseconds(45);
     digitalWrite(pin,HIGH);
}

再包装一下,写八个字节(就是写命令)

void oneWireSendComm(int pin,int byte)
{
    for(int i=0;i<8;i++)
    {
        int sta = byte & 0x01;
writeBit(pin,sta);
byte >>= 1;
    }
}


在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第4张图片


int readBit(int pin)
{
    int tmp;
    pinMode(pin,OUTPUT);
    digitalWrite(pin,HIGH);
    digitalWrite(pin,LOW);
    delayMicroseconds(15);
    digitalWrite(pin,HIGH);
    pinMode(pin,INPUT);
    tmp = digitalRead(pin);
    delayMicroseconds(45);
    return tmp;
}

包装一下,读取八个字节。

int oneWireReceive(int pin)
{
    int i,j,k;
    for(i=0;i<8;i++)
    {
        j = readBit(pin);
        k = (j << 7) | (k >> 1);
    }
    return k;
}


嗯,看上去很不错,随便画画窗体,先测试一下先。

大概流程如下:

        if(oneWireReset(7))//我接的GPIO4,
        {

oneWireSendComm(7,0xcc);//忽略ROM
        oneWireSendComm(7,0x44);//开始温度变换

}
        if(oneWireReset(7))
        {

oneWireSendComm(7,0xcc);//忽略ROM
        oneWireSendComm(7,0xbe);//读暂存
        int a = oneWireReceive(7);//读LSB
        int b = oneWireReceive(7);//读MSB

}

在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第5张图片


what?什么鬼?怎么也看不像啊,MSB:29339 = 0x729B  LSB: 7511038 = 0x729BFE。根本就不可能啊,程序有误,(bug排查ing...)


int oneWireReceive(int pin)
{
    int i,j,k;
    for(i=0;i<8;i++)
    {
        j = readBit(pin);
        k = (j << 7) | (k >> 1);
    }

k = k & 0x00FF;//把没有操作过的其余8bit排除掉
    return k;
}

这么修改过后其实我的程序还是没有正常的运行,然后就只能怀疑是总线通讯的问题了。这下怎么办?我们就只有借助工具的力量了,一台可以存储波形片段的示波器或者是一个逻辑分析仪。推荐逻辑分析仪。

在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第6张图片

嗯,初始化不错。

int oneWireReset(int pin)
{
    pinMode(pin,OUTPUT);//输出模式
    digitalWrite(pin,HIGH);//先高
    digitalWrite(pin,LOW);//再低
    delayMicroseconds(480);//延时
    digitalWrite(pin,HIGH);//输出高电平释放总线,为啥?看电路图,4.7k上拉电阻到高电平
    delayMicroseconds(30);//延时
    pinMode(pin,INPUT);//转为输入模式
    if(digitalRead(pin) == LOW)//检测18b20的相应(低电平)
    {

delayMicroseconds(450);
        return true;
    }
    else
    {
        return false;
    }
}


在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第7张图片

呃,接下来第一个命令的发送就出问题了,逻辑分析仪已经帮我们分析出来了,Invalid ROM command:[0x2C],我们不是发的0xCC么。仔细看波形,再分析相关发送的程序(箭头所指就是问题所在),高低电平转换太快,再协调一下延时参数的设置。

void writeBit(int pin,int bit)
{
     pinMode(pin,OUTPUT);
     digitalWrite(pin,LOW);
     delayMicroseconds(2);//调节了此延时
     digitalWrite(pin,bit);
     delayMicroseconds(30);//调节了此延时
     digitalWrite(pin,HIGH);
     delayMicroseconds(1);//让高低电平转换没有那么快

}

在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第8张图片

这下波形就对了。

在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第9张图片

然后这是读取暂存的波形,可以看到已经读出LSB:0xB2,MSB:0x01.这里我的读取函数也是有问题的,经修改如下:

int readBit(int pin)
{
    int tmp;
    pinMode(pin,OUTPUT);
    digitalWrite(pin,HIGH);
    digitalWrite(pin,LOW);
    delayMicroseconds(2);//调节了此延时
    digitalWrite(pin,HIGH);
    pinMode(pin,INPUT);
    delayMicroseconds(2);//这个小延时很关键,没有它很容易误读上两行的高电平
    tmp = digitalRead(pin);
    delayMicroseconds(40);//调节了此延时
    return tmp;
}


在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第10张图片


ok,现在就对了LSB: 191 = 0xBF,  MSB:  1 = 0x01。组合:0x01BF = 447

那么温度就是:447 * 0.0625 = 27.9375.


float tempchange(int lsb, int msb)
{
    float temp;
    int tem;


    if (msb >= 0xF0) //负温度
    {
        msb = 255 - msb;
        lsb = 256 - lsb;
        tem = -(msb * 16 * 16 + lsb);
    }
    else
    {
        tem = (msb * 16 * 16 + lsb); //正温度
    }


    temp = tem * 0.0625;
    return temp;
}

 

好了,现在我们已经可以正确读取温度值了。

在Ubuntu环境下用QT5开发树莓派的GPIO程序(使用wiringPi库)之三 DS18B20_第11张图片



程序下载;

https://github.com/partx/Qt_Raspi-GPIO.git

你可能感兴趣的:(树莓派)