论坛风格切换切换到宽版
  • 5295阅读
  • 26回复

初学单片机DIY了个温度计 [复制链接]

上一主题 下一主题
离线yyh
 
发帖
1403
只看楼主 倒序阅读 0楼 发表于: 2011-09-18
学了十来天的单片机,diy了个“模拟”温度计,ds18b20温度传感器
本主题包含附件,请 登录 后查看, 或者 注册 成为会员
离线关则勇
发帖
8862
只看该作者 1楼 发表于: 2011-09-18
很好啊!!努力
离线ding
发帖
3488
只看该作者 2楼 发表于: 2011-09-18
牛x的,我可没有你努力,我只会点个led灯
离线zgj
发帖
3883
只看该作者 3楼 发表于: 2011-09-18
io怎么分配的?不会是把所有的io都用光了吧?
离线yyh
发帖
1403
只看该作者 4楼 发表于: 2011-09-18
'
io怎么分配的?不会是把所有的io都用光了吧?
'
动态扫描,用了10+5根,本来想用100颗led的,但是后来想了下没多大意义,就检测下室温做着玩玩就可以了i/o口
离线汤圆
发帖
1157
只看该作者 5楼 发表于: 2011-09-18
玩时序 自己写液晶驱动吧
离线BH7KQK
发帖
3425
只看该作者 6楼 发表于: 2011-09-18
很好,很强大!
离线BG9CNF
发帖
988
只看该作者 7楼 发表于: 2011-09-18
支持单片机学习,下面就可以考虑用数码管和lcd了。
看你的板子,好像led限流是390欧姆的,不知道我看的对不对,一般的那种3毫米管子一般用的都比这个大好像。用470的有,常规点的用1k。
离线BG9CNF
发帖
988
只看该作者 8楼 发表于: 2011-09-18
给你个数码管的程序,看着你的电路改下端口

//*********************************************     c程序   *****************************************************************************//

#include "reg52.h"
#define uchar unsigned char
#define uint unsigned int
#define disdata p0       // 段码入口
sbit dq=p3^3;           // 温度输入口
uint temp;             // variable of temperature 定义一个变量
uchar flag1;           // 定义一个标志,标志温度是负还是正,1为负,0为正
sbit din=p0^7;         // 小数点控制
#define discan p2       //扫描口
uchar h;             // 定义变量

unsigned char code table[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};
//共阳数码管段码表       "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "灭" "-"
unsigned char code table1[]={0x40,0x79,0x24,0x30,0x19,0x12,0x02,0x78,0x00,0x10};//带小数点的编码
//共阳数码管带小数点段码表   "0" "1" "2" "3" "4" "5" "6" "7" "8" "9"
uchar data temp_data[2]={0x00,0x00};//读出温度暂放
uchar data dis_play[5]={0x00,0x00,0x00,0x00,0x00};//显示单元数据,共4个数据和一个运算暂用
uchar code ditab[16]={0x00,0x01,0x01,0x02,0x03,0x03,0x04,0x04,0x05,0x06,0x06,0x07,0x08,0x08,0x09,0x09};
//小数部分对应十进制   "0" "1" "2" "3" "4" "5" "6" "7" "8" "9" "a" "b" "c" "d" "e" "f"
uchar code scan_con[4]={0xef,0xdf,0xbf,0x7f};   //列扫描控制字
/***************************************/
/*     延时子程序             */
/***************************************/
void delay(uint i)     //delay  
  {
    while(i--);
  }
/************************************************/
/*       初始化ds18b2子函数*           */
/************************************************/
init_ds18b20(void)
{
  uchar x=0;
  dq = 1;           //dq复位
  delay(8);         //稍做延时
  dq = 0;           //单片机将dq拉低
  delay(80);         //精确延时 大于 480us
  dq = 1;           //拉高总线
  delay(14);
  x=dq;           //稍做延时后 如果x=0则初始化成功 x=1则初始化失败
  delay(20);
}

/*************************************************/
/*         读字节子函数               */
/*************************************************/
readonechar(void)
{
  uchar i = 0;
  uchar dat = 0;
  for (i=8;i>0;i--)
  {
    dq = 0;         // 给脉冲信号
    dat>>=1;         // 数据右移一位
    dq = 1;         // 给脉冲信号
    if(dq)           // dq为1
    dat|=0x80;       // 读出数据
    delay(4);         // 延时
  }
  return(dat);
}
/*************************************************/
/*           写字节子函数             */
/*************************************************/
writeonechar(unsigned char dat)
{
  uchar i = 0;
  for (i=8; i>0; i--)
  {
    dq = 0;
    dq = dat&0x01;   //写入一位数据
    delay(5);
    dq = 1;
    dat>>=1;     //右移一位数据
  }
}

/******************************************/
/*       发送温度转换命令           */
/******************************************/
void tmpchange(void)       // ds18b20 begin change  
{
init_ds18b20();         // 初始化ds18b20
delay(200);           // 延时
writeonechar(0xcc);       // 跳过序列号命令
writeonechar(0x44);       // 发送温度转换命令
}
/******************************************/
/*         读出温度函数           */
/******************************************/
uint tmp()             //get the temperature
{
// float tt;
init_ds18b20();         // 初始化ds18b2子函数
delay(1);
writeonechar(0xcc);       // 跳过rom命令
writeonechar(0xbe);       // 发送读取数据命令
temp_data[0]=readonechar(); // 连续读两个字节数据
temp_data[1]=readonechar();
temp=temp_data[1];
temp<<=8;                                
temp=temp|temp_data[0];   // 两字节合成一个整型变量。
// tt=temp*0.0625;       // 得到真实十进制温度值,因为ds18b20
                    // 可以精确到0.0625度,所以读回数据的最低位代表的是
                    // 0.0625度。
// temp=tt*10+0.5;       // 放大十倍,这样做的目的将小数点后第一位
                    // 也转换为可显示数字,同时进行一个四舍五入操作。
return temp;           // 返回温度值
}

/******************************************/
/*     温度数据显示处理函数         */
/******************************************/
void tem_deal(uint tem)
{
/*************温度数据处理*****************/
  if(tem>6348)               // 温度值正负判断
  {tem=65536-tem;flag1=1;}       // 负温度求补码,标志位置1
    dis_play[4]=tem&0x0f;       // 取小数部分的值
  dis_play[0]=ditab[dis_play[4]]; // 存入小数部分显示值
    dis_play[4]=tem>>4;         // 取中间八位,即整数部分的值
  dis_play[3]=dis_play[4]/100;   // 取百位数据暂存
  dis_play[1]=dis_play[4]%100;   // 取后两位数据暂存
  dis_play[2]=dis_play[1]/10;   // 取十位数据暂存
  dis_play[1]=dis_play[1]%10;   // 取个位数据暂存
  if(!dis_play[3])     // 最高位为0都不显示
  {
    dis_play[3]=0x0a;   // 先判断百位是否为0
  if(!dis_play[2])
  {
  dis_play[2]=0x0a; // 再判断十位是否为0
  }
  }
  if(flag1)
  {
    dis_play[3]=0x0b;   // 为负数时,最高位显示 "-"
  }
}
/******************温度数据显示********************/

void display()
{
char k;
  for(k=0;k<4;k++)               //4位led扫描控制
{
  disdata=table[dis_play[k]];       //数据显示
  if (k==1){din=0;}             //小数点显示
  discan=scan_con[3-k];           //位选
  delay(90);                 //延时
  discan=0xff;
}
}
/******************************************/
/*           主函数             */
/******************************************/
void main()
{
disdata=0xff;   //端口初始化
p3=0xff;
//开机显示"888.8";这段程序可以不要.
  for(h=0; h<4; h++)
  {  
      dis_play[h]=8;
  }
  for(h=0; h<50; h++)
  {    
    display(); //显示数据
      delay(1000); //延时
  }

  while(1)
      {
          tmpchange();     //温度转换
  tem_deal(tmp()); //显示温度值
  display();
      };
}
离线BG9CNF
发帖
988
只看该作者 9楼 发表于: 2011-09-18
这个是1602液晶屏的,程序都是ok的,放心用吧。以后需要什么基础类程序找我要,不收版权费的,哈哈。
#include <reg51.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit   dq=p3^3;                     //温度输入口
uint   h;
uint   temp;
unsigned char presence;
typedef bit bool ;
sbit rs = p2^0 ;
sbit rw = p2^1 ;
sbit ep = p2^2;
void delay(int) ;
void delaylcd(uchar) ;
void lcd_wcmd(uchar) ;
void lcd_sef_chr();   //lcd自定义字符程序
bool lcd_bz() ;
void lcd_pos(uchar) ;
void lcd_wdat(uchar) ;
void display(uchar,uchar *) ;
code uchar dis1[] = {" now temp is : "} ;
uchar data temp_data[2]={0x00,0x00};         //读出温度暂放
unsigned char data dis_buf1[16]; //lcd上排显示缓冲区
uchar data displayt[10];  
/*****************11us延时函数*************************/

void delay(int t)
{
for (;t>0;t--);
}

/****************ds18b20复位函数************************/
unsigned char ow_reset(void)
{

dq = 0; //pull dq line low
delay(29); // leave it low for 480μs
dq = 1; // allow line to return high
delay(3); // wait for presence
presence = dq; // get presence signal
delay(25); // wait for end of timeslot
return(presence); // presence signal returned
} // presence = 0, no part = 1

/****************ds18b20写命令函数************************/
//向1-wire 总线上写1个字节
void write_byte(uchar val)
{
uchar i;
for(i=8;i>0;i--)
{
  dq=1;_nop_();_nop_();             //从高拉倒低
  dq=0;_nop_();_nop_();_nop_();_nop_(); //5 us
  dq=val&0x01;                   //最低位移出
  delay(6);                     //66 us
  val=val/2;                   //右移1位
  }
  dq=1;
  delay(1);
}
/****************ds18b20读1字节函数************************/
//从总线上取1个字节
uchar read_byte(void)
{
uchar i;
uchar value=0;
for(i=8;i>0;i--)
{
dq=1;_nop_();_nop_();
value>>=1;
dq=0;_nop_();_nop_();_nop_();_nop_();       //4 us
dq=1;_nop_();_nop_();_nop_();_nop_();       //4 us
if(dq)value|=0x80;
delay(6);                         //66 us
}
dq=1;
return(value);
}
/****************读出温度函数************************/
read_temp()
{
ow_reset();             //总线复位
delay(200);
write_byte(0xcc);         //发命令
write_byte(0x44);         //发转换命令
ow_reset();
delay(1);
write_byte(0xcc);         //发命令
write_byte(0xbe);
temp_data[0]=read_byte();   //读温度值的第字节
temp_data[1]=read_byte();   //读温度值的高字节
temp_data[1]&=0x0f;
temp=temp_data[1];
temp<<=8;
temp=temp|temp_data[0];     // 两字节合成一个整型变量。
  //p0=temp;
//temp>>=4;             //去掉小数部分
//p1=temp;
return temp;           //返回温度值
}
//

work_temp(uint temp)
{
uint j,i,m,n;
//if(tem>6348)                 // 温度值正负判断
  // {tem=65536-tem;n=1;}         // 负温度求补码,标志位置1
  i=temp;
  i=i&0x000f;
  temp>>=4;
  displayt[0]='+'
  displayt[1]=temp/100+48;   // 取百位数据暂存
  j=temp%100;   // 取后两位数据暂存
  displayt[2]=j/10+48;     // 取十位数据暂存
  displayt[3]=j%10+48;     // 取个位数据暂存
  m=((0x08&i)>>3)*5000+((0x04&i)>>2)*2500+((0x02&i)>>1)*1200+(0x01&i)*625;
  displayt[5]=m/1000+48;
  //p1=m/10000;
  n=m%1000;
  displayt[6]=n/100+48;
  n%=100;
  displayt[7]=n/10+48;
  displayt[8]=n%10+48;
}


void delaylcd(uchar ms)
{     // 延时子程序
uchar i ;
while(ms--)
{
  for(i = 0 ; i<250;i++) ;
}
}

bool lcd_bz()
{     // 测试lcd忙碌状态
bool result ;
rs = 0 ;
rw = 1 ;
ep = 1 ;
result = (bool)(p0 & 0x80) ;
ep = 0 ;
return result ;
}

void lcd_wcmd(uchar cmd)
{     // 写入指令数据到lcd
  while(lcd_bz()) ;
rs = 0 ;
rw = 0 ;
ep = 0 ;
p0 = cmd ;
ep = 1 ;
ep = 0 ;
}

void lcd_pos(uchar pos)
{     //设定显示位置
  lcd_wcmd(pos | 0x80) ;
}

void lcd_wdat(uchar dat)
{     //写入字符显示数据到lcd
  while(lcd_bz()) ;
rs = 1 ;
rw = 0 ;
ep = 0 ;
p0 = dat ;
ep = 1 ;
ep = 0 ;
}

void lcd_init()
{     //lcd初始化设定
lcd_wcmd(0x38) ;   //function set
delaylcd(1) ;
lcd_wcmd(0x38) ;   //function set
delaylcd(1) ;
lcd_wcmd(0x08) ;   //display on/off
delaylcd(1) ;
lcd_wcmd(0x01) ;   //清除lcd的显示内容
delaylcd(1) ;
lcd_wcmd(0x06) ;   //entry mode set
delaylcd(1) ;
lcd_wcmd(0x0c) ;   //entry mode set
delaylcd(1) ;
}

/*---------------
函数名称:display()
功能 :在lcd上显示数组的数据
说明 :先写显示地址,后写显示数据
调用 :lcd_wcmd(), lcd_pos()
入口参数:pos 写入的位置,q指向要写入的数据所在的数组
返回值 :无
----------------*/
void display(uchar pos, uchar *q)
{
uchar i ;
  delaylcd(1) ;
lcd_pos(pos) ;
for(i=0 ;i<16;i++)
{
  lcd_wdat(*q) ;
  q++ ;
  delaylcd(10) ;
}
}

void lcd_sef_chr()//自定义字符
{
lcd_wcmd(0x40); //"01 000 000" 第1行地址 (d7d6为地址设定命令形式 d5d4d3为字符存放位置(0--7),d2d1d0为字符行地址(0--7))
  lcd_wdat(0x07); //"xxx 11111" 第1行数据(d7d6d5为xxx,表示为任意数(一般用000),d4d3d2d1d0为字符行数据(1-点亮,0-熄灭)
lcd_wcmd(0x41); //"01 000 001" 第2行地址
  lcd_wdat(0x05); //"xxx 10001" 第2行数据
lcd_wcmd(0x42); //"01 000 010" 第3行地址
  lcd_wdat(0x07); //"xxx 10101" 第3行数据
lcd_wcmd(0x43); //"01 000 011" 第4行地址
  lcd_wdat(0x00); //"xxx 10001" 第4行数据
lcd_wcmd(0x44); //"01 000 100" 第5行地址
  lcd_wdat(0x00); //"xxx 11111" 第5行数据
lcd_wcmd(0x45); //"01 000 101" 第6行地址
  lcd_wdat(0x00); //"xxx 01010" 第6行数据
lcd_wcmd(0x46); //"01 000 110" 第7行地址
  lcd_wdat(0x00); //"xxx 11111" 第7行数据
lcd_wcmd(0x47); //"01 000 111" 第8行地址
  lcd_wdat(0x00); //"xxx 00000" 第8行数据

}
main()
{   lcd_init() ;   // 初始化lcd  
delaylcd(10) ;
  delay(10) ;
  lcd_wcmd(0x01) ;   //清除lcd的显示内容
    ow_reset();             //开机先转换一次
    write_byte(0xcc);         //skip rom
    write_byte(0x44);         //发转换命令
  //lcd_wcmd(0x07) ;   //entry mode set
delay(1) ;
  lcd_sef_chr();     //写入自定义字符号

while(1)           //"1234567890123456"
{
  display(0x00,dis1) ;
  work_temp(read_temp());   //处理温度数据
    lcd_pos(0x41) ; lcd_wdat('+');
  lcd_pos(0x42) ; lcd_wdat(displayt[1]);
  lcd_pos(0x43) ; lcd_wdat(displayt[2]);
  lcd_pos(0x44) ; lcd_wdat(displayt[3]);
  lcd_pos(0x45) ; lcd_wdat('.');
  lcd_pos(0x46) ; lcd_wdat(displayt[5]);
  lcd_pos(0x47) ; lcd_wdat(displayt[6]);
  lcd_pos(0x48) ; lcd_wdat(displayt[7]);
  lcd_pos(0x49) ; lcd_wdat(displayt[8]);
  lcd_pos(0x4a);
    lcd_wdat(dis_buf1[0]);
  lcd_pos(0x4b);
    lcd_wdat('c');
}
}
离线BH7KVE
发帖
1334
只看该作者 10楼 发表于: 2011-09-18
活学活用,不错!
c是个好东西,记得汇编入门用了几个月时间,才能点数码管
离线BG4FQD
发帖
3407
只看该作者 11楼 发表于: 2011-09-18
lz 学习神速,
干脆用你这些二极管自己焊一个数码管出来,嘿嘿

我学了100天也做不出这东西来。
离线yyh
发帖
1403
只看该作者 12楼 发表于: 2011-09-18
led的我已经做好了,做这个就是感觉好玩,数字采集转换,模拟点显示,用了不少的if语句,动态扫描就是借鉴的led显示的驱动原理,程序中开启了一个定时器,一个外部中断,运行10s后 pcon=0x02,让单片机休眠,待机电流在2ua,利用中断唤醒,最近段时间一睡觉进入半睡眠状态时大脑里就条件反射的跑起了c程序,经常半夜醒来。
离线yyh
发帖
1403
只看该作者 13楼 发表于: 2011-09-18
最近写了一个单片机驱动电子管数码辉光管的程序,就是还没有多余的管子和管座来实验,以前没玩单片机的时候,硬是花了一个星期的时间(白天要上班),用了好几片74芯片来搭接驱动,这些天发现用单片机来驱动非常的简单,就一片stc单片机和几只c2482高耐压三极管就ok了,甚至时间不准还可以修整定时器溢出来弄,包括升压驱动辉光管我也打算用定时器的溢出脉冲来驱动开关三极管带动小变压器升压,单片机真是个好东西。
离线BG4FQD
发帖
3407
只看该作者 14楼 发表于: 2011-09-18
lz 底子好,

现在什么地方还能用到 电子管数码辉光管,我很小的时候见过学校的钟是这东西的
离线yyh
发帖
1403
只看该作者 15楼 发表于: 2011-09-18
上个08年做的辉光管钟
'
lz 底子好,
现在什么地方还能用到 电子管数码辉光管,我很小的时候见过学校的钟是这东西的
'
曾经做的辉光电子钟,花了不少精力和时间来弄。没有制版,用的洞洞板,现在打算用单片机来从头做一个来玩玩,采用动态扫描了,以前用的静态显示。
本主题包含附件,请 登录 后查看, 或者 注册 成为会员
离线yyh
发帖
1403
只看该作者 16楼 发表于: 2011-09-18
'
支持单片机学习,下面就可以考虑用数码管和lcd了。
看你的板子,好像led限流是390欧姆的,不知道我看的对不对,一般的那种3毫米管子一般用的都比这个大好像。用470的有,常规点的用1k。
'
对的,用390的亮度比较高,利用了单片机的休眠功能,只是测试的时候总电流会达到20毫安的样子。
发帖
689
只看该作者 17楼 发表于: 2011-09-19
想看背面。
离线BG3AIE
发帖
9608
只看该作者 18楼 发表于: 2011-09-19
时钟还是这个好玩
本主题包含附件,请 登录 后查看, 或者 注册 成为会员
离线BG9CNF
发帖
988
只看该作者 19楼 发表于: 2011-09-19
'
时钟还是这个好玩
'
这个超级帅,如果是oled的屏就更爽了