电子产业
数字化服务平台

扫码下载
手机洽洽

  • 微信小程序

    让找料更便捷

  • 扫码下载手机洽洽

    随时找料

    即刻洽谈

    点击下载PC版
  • 华强电子网公众号

    电子元器件

    采购信息平台

  • 华强电子网移动端

    生意随身带

    随时随地找货

  • 华强商城公众号

    一站式电子元器件

    采购平台

  • 芯八哥公众号

    半导体行业观察第一站

AVR温度计DS18B20

来源:-- 作者:-- 浏览:424

标签:

摘要: #include <mega48.h> #include <delay.h> #include <nokia3310.h> #include <monobus.h> unsigned char data_H, data_L,wendu; unsigned int data_T;

#include <mega48.h> 
#include <delay.h> 
#include <nokia3310.h>
#include <monobus.h> 
unsigned char data_H, data_L,wendu; 
unsigned int  data_T;

 

void main(void) 
{   
  LCD_init();                       //lcd初始化          
  lcd_cls();                        //清屏,光标回位  
  while(1)  
       {   
         monobus_init();            //单总线复位
         write_monobus(0xCC);       //跳过ID码匹配,适用于一个DS18B20
        
         //可以使用8条语句代替上面的那条语句依次写入8个ID码,这样就是ID码匹配了
         //如果不知道18B20的ID码,可以在总线上接入单个18B20
         //然后参考下面的读取语句,依次读取18B20的8个ID码
         //记得使用CRC8校验一下是否正确
        
         write_monobus(0x44);       //启动温度转换
        
         delay_ms(500);             //等待转换
         monobus_init();            //单总线复位
         write_monobus(0xCC);       //跳过ID码匹配
         write_monobus(0xBE);       //通知DS18B20,准备读数据

         data_L=read_monobus();     //读取第一个数据(温度低字节)
         data_H=read_monobus();     //读取第二个数据(温度高字节)
        
         //可以继续读取第三个到第九个RAM数据
        
         lcd_cls();
        
         data_T=data_H*256+data_L;  //合并后得到原始温度数据
        
         if(data_H>15) data_T=(~data_T+1)/16; else data_T/=16; //计算实际温度
         wendu=data_T;
        
         lcd_gotoxy(16,3);
         lcd_putsf("T = ",4);       //显示字符串,字符串是保存在Flash的
         if(data_H>15) lcd_putchar('-');
         lcd_put(wendu);            //显示温度
         lcd_putchar(' ');          //空一个字符
         lcd_write(2);              //显示C前面上标的一个点
         lcd_write(0);              //空一小格
         lcd_putchar('C');  
         delay_ms(250);      
       } 
}  
/*
如果温度为正,则T的最高位的4位都为0,否则为1
负温度的计算:原始数据取反、加1、再乘以 0.0625
正温度的计算:原始数据乘以 0.0625
CVAVR自带了18B20的库,如果大家不喜欢上面我写的函数,也可以使用自带的
*/

//**********************************************************************************

//**********************************************************************************

//monobus.h文件,用于操作DS18B20/DS2401等单总线器件 
//假设软件设计要求的时钟频率是4MHz
//实际上硬件工作在2-8MHz下也很正常,就是说,下面代码的延时取值是很合适的  
//CVAVR本身自带单总线的库1wire.h,如果大家不喜欢下面的代码也可以使用它自带的函数(请看帮助文档)

#define monobus_1  DDRC.0=0  //设置 单片机 IO为输入,由于总线存在上拉电阻,所以此时电平是1
#define monobus_0  DDRC.0=1  //设置 单片机 IO为输出,配合默认的 PORTC.0=0 则输出0电平
#define monobus_in PINC.0    //检测总线(从机)的电平状态

void monobus_init(void)      //复位,不检测从机设备是否存在(只要没有虚焊就肯定存在的)
{
  monobus_0;
  delay_us(480);
  monobus_1; 
  delay_us(480);
}

void write_monobus(unsigned char data)     //向单总线的从机写入数据(先写低位再写高位,与SPI相反)
{
  unsigned char n=1;
  while(n)
  {
    monobus_0;
    delay_us(2);                           //拉低总线1-3us,通知从机准备收发数据
    if(data&n) monobus_1; else monobus_0;  //向总线写数据的某一位(1或者0)
    delay_us(75);                          //等待90us,保证从机有足够的时间进行采样(24-210us)
    monobus_1;                             //释放总线   
    delay_us(2);                           //释放总线时间要大于1us  
    n<<=1;
  }
}

unsigned char read_monobus(void)           //读单总线的从机数据(先传输低位后传输高位,与SPI相反)
{
  unsigned char data_18b20=0; 
  unsigned char n=1;
  while(n)
  {
    monobus_0;
    delay_us(2);                           //拉低总线1-3us,通知从机准备收发数据
    monobus_1;                             //释放总线
    delay_us(5);                           //从机在1-25us内会向总线输出数据的某一位(1或者0)
    if(monobus_in) data_18b20+=n;          //读取总线数据
    delay_us(55);                          //等待从机释放总线
    n<<=1;
  }
  return data_18b20;

//**********************************************************************************

//**********************************************************************************

/************************************************************* 
使用者只需把这个nokia3310.h的文件复制到工程目录即可 
使用nokia3310库函数时,请先定义3310与MCU的连接 
本例子3310LCD与 单片机 的连接如下 
RESET   PB1 
D/C     PB2 
SDIN    PB3 
SCLK    PB5 
SCE     GND                                    
英文字库,5*8点阵,每一个字符占用5个字节,共94个可显示字符数据**/    
                              
#define RESET     PORTB.1       //RESET=0时,LCD复位 
#define DC        PORTB.2       //DC=0_指令,DC=1_数据   
#define SDIN      PORTB.3 
#define SCLK      PORTB.5

#define RESET_DDRn DDRB.1       //RESET=0时,LCD复位 
#define DC_DDRn    DDRB.2       //DC=0_指令,DC=1_数据   
#define SDIN_DDRn  DDRB.3 
#define SCLK_DDRn  DDRB.5

flash unsigned char data[]={      
0x00, 0x00, 0x00, 0x00, 0x00,   // sp 
0x00, 0x00, 0x2f, 0x00, 0x00,   // ! 
0x00, 0x07, 0x00, 0x07, 0x00,   // " 
0x14, 0x7f, 0x14, 0x7f, 0x14,   // # 
0x24, 0x2a, 0x7f, 0x2a, 0x12,   // $ 
0x62, 0x64, 0x08, 0x13, 0x23,   // % 
0x36, 0x49, 0x55, 0x22, 0x50,   // & 
0x00, 0x05, 0x03, 0x00, 0x00,   // ’ 
0x00, 0x1c, 0x22, 0x41, 0x00,   // ( 
0x00, 0x41, 0x22, 0x1c, 0x00,   // ) 
0x14, 0x08, 0x3E, 0x08, 0x14,   // * 
0x08, 0x08, 0x3E, 0x08, 0x08,   // + 
0x00, 0x00, 0xA0, 0x60, 0x00,   // , 
0x08, 0x08, 0x08, 0x08, 0x08,   // - 
0x00, 0x60, 0x60, 0x00, 0x00,   // . 
0x20, 0x10, 0x08, 0x04, 0x02,   // / 
0x3E, 0x51, 0x49, 0x45, 0x3E,   // 0 
0x00, 0x42, 0x7F, 0x40, 0x00,   // 1 
0x42, 0x61, 0x51, 0x49, 0x46,   // 2 
0x21, 0x41, 0x45, 0x4B, 0x31,   // 3 
0x18, 0x14, 0x12, 0x7F, 0x10,   // 4 
0x27, 0x45, 0x45, 0x45, 0x39,   // 5 
0x3C, 0x4A, 0x49, 0x49, 0x30,   // 6 
0x01, 0x71, 0x09, 0x05, 0x03,   // 7 
0x36, 0x49, 0x49, 0x49, 0x36,   // 8 
0x06, 0x49, 0x49, 0x29, 0x1E,   // 9 
0x00, 0x36, 0x36, 0x00, 0x00,   // : 
0x00, 0x56, 0x36, 0x00, 0x00,   // ; 
0x08, 0x14, 0x22, 0x41, 0x00,   // < 
0x14, 0x14, 0x14, 0x14, 0x14,   // = 
0x00, 0x41, 0x22, 0x14, 0x08,   // > 
0x02, 0x01, 0x51, 0x09, 0x06,   // ? 
0x32, 0x49, 0x59, 0x51, 0x3E,   // @ 
0x7C, 0x12, 0x11, 0x12, 0x7C,   // A 
0x7F, 0x49, 0x49, 0x49, 0x36,   // B 
0x3E, 0x41, 0x41, 0x41, 0x22,   // C 
0x7F, 0x41, 0x41, 0x22, 0x1C,   // D 
0x7F, 0x49, 0x49, 0x49, 0x41,   // E 
0x7F, 0x09, 0x09, 0x09, 0x01,   // F 
0x3E, 0x41, 0x49, 0x49, 0x7A,   // G 
0x7F, 0x08, 0x08, 0x08, 0x7F,   // H 
0x00, 0x41, 0x7F, 0x41, 0x00,   // I 
0x20, 0x40, 0x41, 0x3F, 0x01,   // J 
0x7F, 0x08, 0x14, 0x22, 0x41,   // K 
0x7F, 0x40, 0x40, 0x40, 0x40,   // L 
0x7F, 0x02, 0x0C, 0x02, 0x7F,   // M 
0x7F, 0x04, 0x08, 0x10, 0x7F,   // N 
0x3E, 0x41, 0x41, 0x41, 0x3E,   // O 
0x7F, 0x09, 0x09, 0x09, 0x06,   // P 
0x3E, 0x41, 0x51, 0x21, 0x5E,   // Q 
0x7F, 0x09, 0x19, 0x29, 0x46,   // R 
0x46, 0x49, 0x49, 0x49, 0x31,   // S 
0x01, 0x01, 0x7F, 0x01, 0x01,   // T 
0x3F, 0x40, 0x40, 0x40, 0x3F,   // U 
0x1F, 0x20, 0x40, 0x20, 0x1F,   // V 
0x3F, 0x40, 0x38, 0x40, 0x3F,   // W 
0x63, 0x14, 0x08, 0x14, 0x63,   // X 
0x07, 0x08, 0x70, 0x08, 0x07,   // Y 
0x61, 0x51, 0x49, 0x45, 0x43,   // Z 
0x00, 0x7F, 0x41, 0x41, 0x00,   // [ 
0x55, 0x2A, 0x55, 0x2A, 0x55,   // 55 
0x00, 0x41, 0x41, 0x7F, 0x00,   // ] 
0x04, 0x02, 0x01, 0x02, 0x04,   // ^ 
0x40, 0x40, 0x40, 0x40, 0x40,   // _ 
0x00, 0x01, 0x02, 0x04, 0x00,   // ’ 
0x20, 0x54, 0x54, 0x54, 0x78,   // a 
0x7F, 0x48, 0x44, 0x44, 0x38,   // b 
0x38, 0x44, 0x44, 0x44, 0x20,   // c 
0x38, 0x44, 0x44, 0x48, 0x7F,   // d 
0x38, 0x54, 0x54, 0x54, 0x18,   // e 
0x08, 0x7E, 0x09, 0x01, 0x02,   // f 
0x18, 0xA4, 0xA4, 0xA4, 0x7C,   // g 
0x7F, 0x08, 0x04, 0x04, 0x78,   // h 
0x00, 0x44, 0x7D, 0x40, 0x00,   // i 
0x40, 0x80, 0x84, 0x7D, 0x00,   // j 
0x7F, 0x10, 0x28, 0x44, 0x00,   // k 
0x00, 0x41, 0x7F, 0x40, 0x00,   // l 
0x7C, 0x04, 0x18, 0x04, 0x78,   // m 
0x7C, 0x08, 0x04, 0x04, 0x78,   // n 
0x38, 0x44, 0x44, 0x44, 0x38,   // o 
0xFC, 0x24, 0x24, 0x24, 0x18,   // p 
0x18, 0x24, 0x24, 0x18, 0xFC,   // q 
0x7C, 0x08, 0x04, 0x04, 0x08,   // r 
0x48, 0x54, 0x54, 0x54, 0x20,   // s 
0x04, 0x3F, 0x44, 0x40, 0x20,   // t 
0x3C, 0x40, 0x40, 0x20, 0x7C,   // u 
0x1C, 0x20, 0x40, 0x20, 0x1C,   // v 
0x3C, 0x40, 0x30, 0x40, 0x3C,   // w 
0x44, 0x28, 0x10, 0x28, 0x44,   // x 
0x1C, 0xA0, 0xA0, 0xA0, 0x7C,   // y 
0x44, 0x64, 0x54, 0x4C, 0x44,   // z 
0x00, 0x08, 0x36, 0x41, 0x00,   // { 
0x00, 0x00, 0x7F, 0x00, 0x00,   // | 
0x00, 0x41, 0x36, 0x08, 0x00,   // } 
0x08, 0x10, 0x08, 0x04, 0x08    // ~ 
}; 

//======================================================================================= 

void lcd_write(unsigned char data) //写LCD函数 
{               
  unsigned char n=8; 
  while(n>0) 
  {   
    n--; 
    SDIN=data<<7-n>>7;   //先发送数据高位MSB,后发送数据低位LSB 
    SCLK=0; SCLK=1;      //产生一个时钟 
  } 
}   
/*上面的是模拟SPI发送数据函数,下面的是硬件SPI发送数据函数 
void lcd_write(unsigned char data) 
{  
  SPCR=80; 
  SPDR=data;             //开始发送数据 
  while((SPSR>>7)==0);   //等待发送接收结束 
}        */ 

//======================================================================================= 
void lcd_cls(void)       //nokia3310清屏,光标复位 

  unsigned int  i=0;  
  DC=0; 
  lcd_write(128);        //光标回到0列 
  lcd_write(64);         //光标回到0行 
  DC=1;                  //准备写数据 
  for(i=0;i<504;i++)     //写504个0数据,就是清屏 
  lcd_write(0); 
}  

//======================================================================================= 
         
void lcd_init(void)      //nokia3310初始化函数 
{  
  RESET_DDRn =1;         //设置4个驱动LCD的IO脚为输出
  DC_DDRn    =1;
  SDIN_DDRn  =1;
  SCLK_DDRn  =1;
  RESET=0;     
  RESET=1;               //复位结束 
  DC=0;                  //准备写指令 
  lcd_write(32+1);       //进入扩展指令
  lcd_write(128+38);     //设置Vop,相当于亮度  
  lcd_write(4+3);        //设置温度系数,相当于对比度   
  lcd_write(16+3);       //设置偏置,这句要与不要的实际效果好像一样
  lcd_write(32+0);       //进入基本指令
  lcd_write(12);         //使能芯片活动/垂直寻址
}  

//======================================================================================= 

//光标定位,x(0-83)是列地址,y(0-5)是行地址     
void lcd_gotoxy(unsigned char x,unsigned char y) 

  DC=0; 
  lcd_write(x+128); 
  lcd_write(y+64); 

//======================================================================================= 
     
void lcd_putchar(unsigned char character) //显示ASCII值的字符 

  unsigned char i=0; 
  unsigned int No; 
  No=character-32;       //字模数据是由空格开始,空格字符的ASCII的值就是32 
  No=No*5;               //每个字符的字模是5个字节 
  DC=1;  
  while(i<5)             //一个字符的字模是5个字节,就是5*8点阵 
     { 
       lcd_write(data[No]);   
       i++; 
       No++; 
     } 
  lcd_write(0);          //每个字符之间空一列 
}   

//===================================================================================== 

void lcd_put(unsigned char byte_data) //以十进制显示一个字符变量
{
  lcd_putchar(byte_data/100+48);      //百位数转化为ASCII值再显示
  lcd_putchar(byte_data/10%10+48);    //十位数转化为ASCII值再显示
  lcd_putchar(byte_data%10+48);       //个位数转化为ASCII再再显示
}

//=====================================================================================

void lcd_puthex(unsigned char byte_data)   //以十六进制显示一个字节变量
{
  unsigned char temp_data;
 
  temp_data=byte_data>>4;                             //求高4位
  if(temp_data<10) temp_data+=48; else temp_data+=55; //转化为ASCII值
  lcd_putchar(temp_data);                             //显示
 
  temp_data=byte_data&15;                             //求低4位
  if(temp_data<10) temp_data+=48; else temp_data+=55; //转化为ASCII值
  lcd_putchar(temp_data);                             //显示
}

//===================================================================================== 

void lcd_putsf(flash unsigned char *string , unsigned char n) //显示FLASH里面的字符串 
{         
  unsigned char i=0; 
  while(i<n) 
       {   
         lcd_putchar( string[ i ] );    //顺序显示字符 
         i++;                          
       } 
}

//**********************************************************************************

//**********************************************************************************

常用的CRC校验有CRC8、CRC16、CRC32等,DS18B20数字温度器件就是采用CRC8的校验方式,下面是CVAVR集成的CRC8校验函数

#include <mega48.h>
#include <1wire.h>
unsigned char a[]={0x28,0x6D,0x00,0x85,0x00,0x00,0x00,0xCF};
unsigned char crc8;
main()

  while(1)
       {
         crc8=w1_dow_crc8(a,7); //求数组a的前7个数的CRC8校验码
       }
}

上面的例子中,数组a的8个数据就是我的DS18B20的ID码,0x28是器件的家族码,0x6D,0x00,0x85,0x00,0x00,0x00这6个数就是ID码,0xCF是前面7个数的校验码

用AVR Studio调试上面的程序就可以看到,crc8的结果就是0xCF了

也可以自己写函数,功能与上面的一样

unsigned char crc8(unsigned char *ptr, unsigned char len) 
{
  unsigned char i;
  unsigned char crc=0;
  while(len--!=0) 
   {
     for(i=1; i!=0; i*=2)
      {
        if((crc&1)!=0) {crc/=2; crc^=0x8C;}
        else crc/=2;
        if((*ptr&i)!=0) crc^=0x8C;    
       } 
     ptr++;
    }
return(crc);
}

型号 厂商 价格
EPCOS 爱普科斯 /
STM32F103RCT6 ST ¥461.23
STM32F103C8T6 ST ¥84
STM32F103VET6 ST ¥426.57
STM32F103RET6 ST ¥780.82
STM8S003F3P6 ST ¥10.62
STM32F103VCT6 ST ¥275.84
STM32F103CBT6 ST ¥130.66
STM32F030C8T6 ST ¥18.11
N76E003AT20 NUVOTON ¥9.67