ATTINY85制作的智能环境监测系统-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 7670|回复: 5

ATTINY85制作的智能环境监测系统

[复制链接]
发表于 2018-11-22 21:17 | 显示全部楼层 |阅读模式
本帖最后由 希岩 于 2018-11-22 21:20 编辑

   由于好奇,买了一个attiny85的单片机,本来说要做Digispark的,但倒腾了好久,终于在arduino IDE下装了这个的开发板插件,结果不能用ISP下载就很烦了,就是无法“导出已编译的二进制文件”,就不能用那个arduino IDE尽心开发,很是郁闷。
   后来找到了ATTINY的开发板,按照ATTINY添加了插件,就抛弃了Digispark。具体方法可以自己去查百度。就是添加attiny85的开发板,便可以编译attiny85程序了。开心。
   看了下ATTINY85,发现有SDA和SCL的引脚,以为有I2C呢,最后发现没有。其实就是USI的一种模式,USI没用过,这个东西能配置成TWI或者SPI。配置成TWI真是麻烦,去网上找库,扎到了TinyWire的库,这还是官方的,加载到Arduino IDE下居然不能用,我的OLED 128 32就是点不亮,换了这个库的好多版本都不行,花了我大半天,还是不行。我看了库里面配置I2C的程序,发现卡在start里了,不知道为什么,就是不好用。无奈,就用软件I2C吧,从网上找了一个51单片机驱动I2C oled的,就是用普通IO模拟的。
   移植完,调试一下,哎,可以了,很是开心。然后就用Arduino的DS18B20的库和DHT11的库带了两个传感器,一个是DS18B20,一个是DHT11温湿度传感器。还有一个引脚,手头有一个TEMT6000光照传感器,三个传感器加上,可以放宿舍了。
  首先准备材料:
1.0.91寸OLEd,点阵数128*32
2.DS8B20温度传感器;
3.DHT11温湿度传感器;
4.TEMT6000光强传感器。
5.最重要的ATTNY85控制器。  其中OLED的SDA接2脚,即PB2。SCL接0脚,即PB0。
DHT11接3脚,即PB3。
DS18B20接1脚,即PB1。
TEMT6000接A2脚,即PB4.

注意I2C加个上拉电阻。按照上述连接便接好了。程序用到了DHT11的库,DS18B20库, I2C用软件模拟的,OLED没有用Adafruit的库,那个太大了,放不下。
插上电,或者用锂电池供电也行,因为用的是内部8MHz RC振荡器。3.3V就能工作。
把一部分程序贴出,还有效果图。最后是完整代码。

[mw_shl_code=cpp,true]#include <OneWire.h>
#include "DHT.h"
// OneWire DS18S20, DS18B20, DS1822 Temperature Example
//
// http://www.pjrc.com/teensy/td_libs_OneWire.html
//
// The DallasTemperature library can do all this work for you!
// http://milesburton.com/Dallas_Temperature_Control_Library

#include "codetab.h"     //OLED显示字符数组

//数据类型宏定义
typedef unsigned char uint08;
typedef signed   char sint08;
typedef unsigned int  uint16;
typedef signed   int  sint16;
#define PIN4        4              // ATtiny PB4
#define PIN3        3             // ATtiny PB3
#define PIN1        1             // ATtiny PB1

#define DHTPIN PIN3    // DHT1连接引脚

OneWire  ds(PIN1);  // on pin 10 (a 4.7K resistor is necessary)
DHT dht(DHTPIN, DHT11);

#define TWI_ADDR   0x78              // 8 bit I2C address for IIC slave



#define  Bright     0x80   //最大255
#define  X_WIDTH    128


#define SCL 2    //PB2
#define SDA 0    //PB0

#define SDA_LOW       PORTB&=~0x01    //sda low
#define SDA_HIGH      PORTB|=0x01    //sda low
#define SCL_LOW       PORTB&=~0x04   //sda low
#define SCL_HIGH      PORTB|=0x04    //sda low
#define  SDA_SCL_HIGH PORTB|=0x05
#define  SDA_SCL_LOW  PORTB&=~0x05
#define  SDA_SCL_OUT  DDRB|=0x05
#define  SDA_INTPUT   DDRB&=~0x01
#define  SDA_READ     PINB&0x01

//--------------------------------------------------
void I2C_Init()
{
  pinMode(SDA, OUTPUT);
  pinMode(SCL, OUTPUT);
  digitalWrite(SCL, HIGH);
  digitalWrite(SDA, HIGH);
}
//--------------------------------------------------
void I2C_Start()
{
  SDA_SCL_OUT;
  SDA_SCL_HIGH;
  delayMicroseconds(5); //通信协议规定延时大于4.7us
  SDA_LOW;              //sda low
  delayMicroseconds(5);//通信协议规定延时大于4.7us
}
//--------------------------------------------------
void I2C_Stop()
{
SDA_SCL_OUT;
SDA_LOW;    //sda low
asm ("nop");
SCL_HIGH;    //scl high
delayMicroseconds(5);//通信协议规定延时大于4.7us
SDA_HIGH;
delayMicroseconds(5);//通信协议规定延时大于4.7us
}
//--------------------------------------------------
char test_ack()
{
SCL_HIGH;
delayMicroseconds(4);//通信协议规定延时大于4us
SDA_INTPUT;
if(SDA_READ)
{
  SCL_LOW;
  I2C_Stop();
  return 0;  
}else
{
  SCL_LOW;
  return 1;
}
}
//--------------------------------------------------
void Write_I2C_Byte(char I2C_Byte)
{
  unsigned char i;
  //int Ack_Bit;                    //ACK
  SDA_SCL_OUT;
  for(i=0;i<8;i++)
  { SCL_LOW;
    asm ("nop");
    if(I2C_Byte & 0x80) //1 or 0
       SDA_HIGH;
    else
       SDA_LOW;
    SCL_HIGH;
     asm ("nop");
    I2C_Byte<<=1; //loop
  }
  
  SCL_LOW;             //I2C SCL
  asm ("nop");
  SDA_HIGH;  //I2C SDA
  asm ("nop");  //SCL_LOW;
  asm ("nop");

}
//--------------------------------------------------
unsigned char  Read_I2C_Byte(char ack)
{
  unsigned char i;
  unsigned char I2C_Byte=0;
  SDA_SCL_OUT;
  SDA_INTPUT;
  for(i=0;i<8;i++)
  {
    SCL_HIGH;
    if(SDA_READ)   
            I2C_Byte=(I2C_Byte<<1)+1;   
        else   
            I2C_Byte=I2C_Byte<<1;  
      SCL_LOW;
  }
  if(ack) SDA_HIGH;
  else SDA_LOW;
  SCL_HIGH;             //I2C SCL
  SCL_LOW;
  return I2C_Byte;
}  

//-----------------------------------------------------------------
//TWI写入数据
/*写指令函数,第一个参数为指令,第二、三个参数选择是否需要通信开始和结束函数,=1有,=0没有*/
void USI_TWI_Write(uint08 data,uint08 dc)
{     
  I2C_Start();
  Write_I2C_Byte(TWI_ADDR);
  if(test_ack())
  {
    if(dc)Write_I2C_Byte(0x40);
    else Write_I2C_Byte(0x00);
  }
    if(test_ack())
    Write_I2C_Byte(data);
     test_ack();
     I2C_Stop();
}



//--------------------------------------------------------------------------------
/*********************OLED 设置坐标************************************/
void Set_Pos(uint08 x, uint08 y)
{
  USI_TWI_Write(0xb0+y,0);
  USI_TWI_Write(((x&0xf0)>>4)|0x10,0);
  USI_TWI_Write(x&0x0f,0);
}
/*********************OLED全屏************************************/
void OLED_Fill(uint08 dat)
{
  uint08 y,x;
  for(y=0;y<4;y++)
  {
    USI_TWI_Write(0xb0+y,0);
    USI_TWI_Write(0x01,0);
    USI_TWI_Write(0x10,0);
    for(x=0;x<X_WIDTH;x++)
    USI_TWI_Write(dat,1);
  }
}
/*********************OLED初始化************************************/
void OLED_Init(void)
{
  delay(500);//初始化之前的延时很重要!

  USI_TWI_Write(0xae,0);//--turn off oled panel
  USI_TWI_Write(0x40,0);//---set low column address
  USI_TWI_Write(0xB0,0);//---set high column address
  USI_TWI_Write(0xC8,0);//--set offset
  USI_TWI_Write(0x81,0);//--set contrast control register
  USI_TWI_Write(Bright,0); // Set SEG Output Current Brightness
  USI_TWI_Write(0xa1,0);//--Set SEG/Column Mapping     0xa0左右反置 0xa1正常
  USI_TWI_Write(0xa6,0);//--set normal display
  USI_TWI_Write(0xa8,0);//--set multiplex ratio(1 to 64)
  USI_TWI_Write(0x1f,0);//--1/64 duty
  USI_TWI_Write(0xd3,0);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
  USI_TWI_Write(0x00,0);//-not offset
  USI_TWI_Write(0xd5,0);//--set display clock divide ratio/oscillator frequency
  USI_TWI_Write(0xf0,0);//--set divide ratio, Set Clock as 100 Frames/Sec
  USI_TWI_Write(0xd9,0);//--set pre-charge period
  USI_TWI_Write(0x22,0);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
  USI_TWI_Write(0xda,0);//--set com pins hardware configuration
  USI_TWI_Write(0x02,0);
  USI_TWI_Write(0xdb,0);//--set vcomh
  USI_TWI_Write(0x49,0);//Set VCOM Deselect Level
  USI_TWI_Write(0x8d,0);//--set Charge Pump enable/disable
  USI_TWI_Write(0x14,0);//--set(0x10) disable
  USI_TWI_Write(0xaf,0);//--turn on oled panel
  OLED_Fill(0x00);      //初始清屏

}
/*********功能描述:显示8*16一组标准ASCII字符串*********************************/
//   显示的坐标(x,y),y为页范围0~3
//char sign[] = {"a AM PREDATOR BBdDDS"};
void OLED_P8x16Str(uint08 x,uint08 y,uint08 ch[])
{
  uint08 c=0,i=0,j=0,temp;
  while (ch[j])                          //扫描
  {
    c =ch[j]-32;
    if(x>120){x=0;y+=2;}
    Set_Pos(x,y);
    for(i=0;i<8;i++)
    {
      temp = pgm_read_word_near(F8X16+c*16+i);
      USI_TWI_Write(temp,1);
    }
    Set_Pos(x,y+1);
    for(i=0;i<8;i++)
    {temp = pgm_read_word_near(F8X16+c*16+i+8);
    USI_TWI_Write(temp,1);
    }
    x+=8;
    j++;
  }
}

//----------------------------------------------------------------------------
//根据DS18B20中读的温度字节,计算实际温度值
sint16 Start_Temperature(void)
{  

  ds.reset();
  ds.write(0xCC);           //忽略地址匹配
  ds.write(0x44, 1);        // start conversion, with parasite power on at the end

}
//----------------------------------------------------------------------------
//注意开始转换到获取数据要超过750ms时间
sint16 Get_Temperature(void)
{
  byte data[2];
//  delay(750);     // maybe 750ms is enough, maybe not
  // we might do a ds.depower() here, but the reset will take care of it.
  ds.reset();
  ds.write(0xCC);        //忽略地址匹配   
  ds.write(0xBE);         // Read Scratchpad
  data[0] = ds.read();
  data[1] = ds.read();
  int16_t raw = (data[1] << 8) | data[0];
  return ((long)raw*100/16);   //取整
}
//------------------------------------------------------------------------
void setup()
{
  OSCCAL = 0x8A;                 //时钟矫正至8Mhz
  //PRR =  0x00;                       //复位功耗抑制寄存器,TWI唤醒
  //pinMode(LED1_PIN,OUTPUT);
  // config TinyWire library for I2C master functionality
  //TinyWire.begin();
  I2C_Init();                                   //软件I2C初始化
  OLED_Init();                                  //OLED初始化
  OLED_Fill(0xFF);
  dht.begin();                                //dht11开始启动
  Start_Temperature();
  delay (1000);
  OLED_Fill(0x00);//清屏
}
//------------------------------------------------------------------------
  uint08 Show_Buff[17];
  int temperature;   
  byte hum;     //湿度20%-90%
  int Luxval;
  int hic;
  
void loop()
{
   temperature =Get_Temperature();
   Start_Temperature();    //
   hum= dht.readHumidity();

   if(temperature<0)
   {
    Show_Buff[0]='-';      //负数标记
    temperature=0-temperature;
   }
   else  Show_Buff[0]='+';      //'+'号
      
     //定点小数显示格式  
     Show_Buff[1]=(temperature/1000)%10+'0';
     Show_Buff[2]=(temperature/100)%10+'0';
     Show_Buff[3]='.';      // 小数点
     Show_Buff[4]=(temperature /10)%10+'0';
     Show_Buff[5]=temperature%10+'0';
     Show_Buff[6]=127;       //这个是摄氏度符号 16*8
     Show_Buff[7]=0;          //字符串结束标志
     OLED_P8x16Str(4,0,Show_Buff);//温度数据
     
     Show_Buff[0]=(hum/10)%10+'0';
     Show_Buff[1]=hum%10+'0';
     Show_Buff[2]=128;     //% 字符
     Show_Buff[3]=' ';   
     Show_Buff[4]='R';   
     Show_Buff[5]='H';  
     Show_Buff[6]=0;   //字符串结束标志
     OLED_P8x16Str(76,0,Show_Buff);//湿度数据

      Luxval=analogRead(A2);      //connect sensor to Analog 2
      (Luxval>999)?1000uxval;

     Show_Buff[0]=(Luxval/100)%10+'0';
     Show_Buff[1]=(Luxval/10)%10+'0';
     Show_Buff[2]=(Luxval)%10+'0';
     Show_Buff[3]='L';
     Show_Buff[4]='u';
     Show_Buff[5]='x';
     Show_Buff[6]=' ';
      
     hic= dht.computeHeatIndex(temperature/100, hum, false)*10;  // Compute heat index in Celsius (isFahreheit = false)
    if(hic<0)
    {
     Show_Buff[7]='-';      //负数标记
     hic=0-hic;
    }
   else  Show_Buff[7]=' ';      //空格
      
     //定点小数显示格式  
     Show_Buff[8]=(hic/100)%10+'0';
     Show_Buff[9]=(hic/10)%10+'0';
     Show_Buff[10]='.';      // 小数点
     Show_Buff[11]=(temperature )%10+'0';
     Show_Buff[12]=127;//这个是摄氏度符号 16*8
     Show_Buff[13]=' ';
     Show_Buff[14]='I';      
     Show_Buff[15]='X';  
    Show_Buff[16]=0;
     
     OLED_P8x16Str(0,2,Show_Buff);//光照强度数据+指示温度数据
   
    //OLED_P8x16Str(0,2,"Hello World!");//第一行 -- 8x16的显示单元显示ASCII码


    delay(200);      //可以通过延时控制刷新率

}



[/mw_shl_code]




2018-11-22_205612.png

效果

效果

效果2

效果2

DTH_DS18B20_OLED.zip

14.41 KB, 下载次数: 74

完整代码

发表于 2018-11-23 10:47 | 显示全部楼层
楼主玩TINY还是玩的挺溜的,我之前用digispark折腾了好久
 楼主| 发表于 2018-11-23 11:55 | 显示全部楼层
kirbyklein 发表于 2018-11-23 10:47
楼主玩TINY还是玩的挺溜的,我之前用digispark折腾了好久

不是啊,我这玩ATTINY85才玩了两天。之前只接触过Attiny13a。digispark在arduino ide下不好使。
发表于 2019-1-26 13:00 | 显示全部楼层
请问你这个是怎么烧写上去的?
发表于 2019-2-15 09:21 | 显示全部楼层
之前我也买过这个模块驱动OLED来着,用IDE上传的确是个麻烦事,上传时显示红色提示的时候把模块与电脑断开连接,然后再插入才行。
 楼主| 发表于 2019-2-19 12:26 | 显示全部楼层
arduino月色无声 发表于 2019-2-15 09:21
之前我也买过这个模块驱动OLED来着,用IDE上传的确是个麻烦事,上传时显示红色提示的时候把模块与电脑断开 ...

我不是用IDE上传的,而是用ISP下载
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-11-28 09:43 , Processed in 0.077492 second(s), 18 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表