ATTINY85制作的智能环境监测系统
本帖最后由 希岩 于 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就能工作。
把一部分程序贴出,还有效果图。最后是完整代码。
#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 intuint16;
typedef signed intsint16;
#define PIN4 4 // ATtiny PB4
#define PIN3 3 // ATtiny PB3
#define PIN1 1 // ATtiny PB1
#define DHTPIN PIN3 // DHT1连接引脚
OneWireds(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
#defineBright 0x80 //最大255
#defineX_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
#defineSDA_SCL_HIGH PORTB|=0x05
#defineSDA_SCL_LOWPORTB&=~0x05
#defineSDA_SCL_OUTDDRB|=0x05
#defineSDA_INTPUT DDRB&=~0x01
#defineSDA_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 charRead_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) //扫描
{
c =ch-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;
//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 = ds.read();
data = ds.read();
int16_t raw = (data << 8) | data;
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;
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='-'; //负数标记
temperature=0-temperature;
}
elseShow_Buff='+'; //'+'号
//定点小数显示格式
Show_Buff=(temperature/1000)%10+'0';
Show_Buff=(temperature/100)%10+'0';
Show_Buff='.'; // 小数点
Show_Buff=(temperature /10)%10+'0';
Show_Buff=temperature%10+'0';
Show_Buff=127; //这个是摄氏度符号 16*8
Show_Buff=0; //字符串结束标志
OLED_P8x16Str(4,0,Show_Buff);//温度数据
Show_Buff=(hum/10)%10+'0';
Show_Buff=hum%10+'0';
Show_Buff=128; //% 字符
Show_Buff=' ';
Show_Buff='R';
Show_Buff='H';
Show_Buff=0; //字符串结束标志
OLED_P8x16Str(76,0,Show_Buff);//湿度数据
Luxval=analogRead(A2); //connect sensor to Analog 2
(Luxval>999)?1000:Luxval;
Show_Buff=(Luxval/100)%10+'0';
Show_Buff=(Luxval/10)%10+'0';
Show_Buff=(Luxval)%10+'0';
Show_Buff='L';
Show_Buff='u';
Show_Buff='x';
Show_Buff=' ';
hic= dht.computeHeatIndex(temperature/100, hum, false)*10;// Compute heat index in Celsius (isFahreheit = false)
if(hic<0)
{
Show_Buff='-'; //负数标记
hic=0-hic;
}
elseShow_Buff=' '; //空格
//定点小数显示格式
Show_Buff=(hic/100)%10+'0';
Show_Buff=(hic/10)%10+'0';
Show_Buff='.'; // 小数点
Show_Buff=(temperature )%10+'0';
Show_Buff=127;//这个是摄氏度符号 16*8
Show_Buff=' ';
Show_Buff='I';
Show_Buff='X';
Show_Buff=0;
OLED_P8x16Str(0,2,Show_Buff);//光照强度数据+指示温度数据
//OLED_P8x16Str(0,2,"Hello World!");//第一行 -- 8x16的显示单元显示ASCII码
delay(200); //可以通过延时控制刷新率
}
楼主玩TINY还是玩的挺溜的,我之前用digispark折腾了好久:D kirbyklein 发表于 2018-11-23 10:47
楼主玩TINY还是玩的挺溜的,我之前用digispark折腾了好久
不是啊,我这玩ATTINY85才玩了两天。之前只接触过Attiny13a。digispark在arduino ide下不好使。 请问你这个是怎么烧写上去的?
之前我也买过这个模块驱动OLED来着,用IDE上传的确是个麻烦事,上传时显示红色提示的时候把模块与电脑断开连接,然后再插入才行。 arduino月色无声 发表于 2019-2-15 09:21
之前我也买过这个模块驱动OLED来着,用IDE上传的确是个麻烦事,上传时显示红色提示的时候把模块与电脑断开 ...
我不是用IDE上传的,而是用ISP下载
页:
[1]