打印
[点读笔/故事机应用]

测温程序 的一个实例(转)

[复制链接]
1736|14
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
CallReceiver|  楼主 | 2015-12-13 10:12 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
/********************************
  DS18B20测温程序
  文件名:main.c
  编译:WinAVR-20070122

  硬件环境:CA-M8X   打开的开关如下
            S6(1,2,5,6,7)   - 外部4MHz晶振和595接口
            J8(EN-SEG)      - 数码管显示允许
            S7(4)          - 连接PC1 与DS18B20数据口
            (在CA-M8X 上DS18B20为非总线供电)
  
  芯艺设计室 2004-2007  版权所有
  转载请保留本注释在内的全部内容
  Email: changfutong@sina.com
*******************************/
#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>

#include "seg.h"  //声明数码管显示接口函数

#define CLR_1WIRE_BUS DDRC|=_BV(PC1) //设置为输出,此时由于PORTC1是低所以输出低
#define SET_1WIRE_BUS DDRC&=~_BV(PC1)//设置为输入,此时由于PORTC1是低所以程高阻,又因为外部有上拉电阻所以相当于设置总线为高
#define GET_1WIRE_BUS PINC&_BV(PC1)

#define DS18B20_READ_ROM 0x33
#define DS18B20_MATCH_ROM 0X55
#define DS18B20_SKIP_ROM 0XCC
#define DS18B20_SEARCH_ROM 0XF0
#define DS18B20_ALARM_SEARCH_ROM 0XEC
#define DS18B20_WRITE_RAM 0X40
#define DS18B20_READ_RAM 0XBE
#define DS18B20_COPY_RAM 0X48
#define DS18B20_CONVERT_TEM 0X44
#define DS18B20_EECALL_EEPROM 0XB8
#define DS18B20_READ_POWER_SUPPLY 0XB4

//总线端口初始化
void BusInit(void)
{
  PORTC&=~_BV(PC1);//此口总保持低
  DDRC&=~_BV(PC1); //初始化为输入,用外部上拉电阻保持总线的高电平
}

//由于系统时钟为4MHz,一个_delay_loop_2正好延时一us
#define DelayUs(x) _delay_loop_2(x)

void DelayMs(uint16_t t)
{
  uint16_t i;
  for(i=0;i<t;i++)
    _delay_loop_2(250 * 4);
}

//单总线复位
uint8_t ds18b20_reset(void)
{
  uint8_t ret=0;
  CLR_1WIRE_BUS;
  DelayUs(500);  //拉低总线至少480us
  SET_1WIRE_BUS;
  DelayUs(100);//释放总线后等待15-60us
  if((GET_1WIRE_BUS)==0)//检测到DS18B20把总线拉低
    ret=1;        //复位成功
  DelayUs(1000);//等待器件释放总线
  return ret;
}

//单总线读一字节
uint8_t ds18b20_read(void)
{
  uint8_t data=0;
  uint8_t i=0;
  for(i=0;i<8;i++)
  {
    data>>=1;
    CLR_1WIRE_BUS;
    DelayUs(2);//此时>1us
    SET_1WIRE_BUS;
    DelayUs(4);//此时<15us
    if(GET_1WIRE_BUS)
      data|=0x80;
    DelayUs(60);//此时>60us
  }
  return(data);
}
//单总线写一字节
void ds18b20_write(uint8_t data)
{
  uint8_t i=0;
  for(i=0;i<8;i++)
  {
    if(data&0x01)
    {
      CLR_1WIRE_BUS;
      DelayUs(8);//8us
      SET_1WIRE_BUS;
      DelayUs(55);//55us
    }
    else
    {
      CLR_1WIRE_BUS;
      DelayUs(55);//55us
      SET_1WIRE_BUS;
      DelayUs(20);//8us
    }
    data>>=1;
  }
}

//执行转换
uint8_t Ds18b20Convert(uint8_t *t)
{
  //发送转换命令
  if(ds18b20_reset()==0)
    return 0;
  ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配,总线上只有一个器件时,或对总线所有器件操作
  ds18b20_write(DS18B20_CONVERT_TEM);//开始转换命令
  
  //等待转换完成,ds18b20默认转换精度为12位,此时最大转换时间为750ms
  DelayMs(1000);
  
  //读温度字节
  if(ds18b20_reset()==0)
    return 0;
  ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配
  ds18b20_write(DS18B20_READ_RAM); //读RAM命令
  t[0]=ds18b20_read();
  t[1]=ds18b20_read();
  
  return 1;
}

//根据DS18B20中读的温度字节,计算实际温度值
int8_t GetTemperature(uint8_t *t)
{
  int8_t ret;
  uint32_t  val;
  uint16_t tmp=(t[1]*256)+t[0];
  uint8_t sflag=0;

  if((t[1]&0xf8)==0xf8) //若负温度,从补码转换(取反加一)
  {
    sflag=1;
    tmp=~tmp;
    tmp++;
  }
  tmp&=0x07ff;    //确保前5位为0
  
  //乘0.0625操作,为此本函数只适用于DS18B20 12位转换(默认)时
  val=((uint32_t)tmp)*625;
  val/=10000;
  
  ret=(int8_t)val;
  
  if(sflag)
    ret|=0x80;//变负数
   
  return ret;
}

//测试主函数
int main(void)
{
  uint8_t tmp[2];//保存温度字节
  int8_t tval;    //保存温度值
  
  SegInit();//数码管初始化
  SegNumberOut(0,0);//显示 0
  BusInit();  //单总线I/O口初始化

  while(1)
  {
    if(Ds18b20Convert(tmp))//如果转换成功
    {
      tval=GetTemperature(tmp);//计算实际温度值
      if(tval>=0)
        SegNumberOut(tval,0);//十进制显示温度值
      else
        SegNumberOut(0,0);//数码管无法显示负数,只能显示0
    }
  }
  return 0;
}


seg.c文件:


/********************************
  74HC95驱动的数码管显示模块
  文件名:seg.c
  编译:WinAVR-20070122

  硬件环境:CA-M8X   打开的开关如下
            S6(1,2,5,6,7)   - 外部4MHz晶振和595接口
            J8(EN-SEG)      - 数码管显示允许
  
  芯艺设计室 2004-2007  版权所有
  转载请保留本注释在内的全部内容
  WEB: http://www.chipart.cn
  Email: changfutong@sina.com
*******************************/

#include <avr/io.h>
#include <util/delay.h>
#include <stdint.h>

#include "seg.h"

#define SER_PORT  PORTD
#define SER_DAT  PD4
#define SER_RCK  PD5
#define SER_SCK  PD6

//显示码(可从chipart.cn下载生成工具)
static uint8_t g_aDisplayBuf[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

//向595 写一字节
static void ser_out(uint8_t dat)
{
  uint8_t i;

  for(i=0;i<8;i++)
  {
    if(dat&0x80)
      SER_PORT|=_BV(SER_DAT);
    else
      SER_PORT&=~_BV(SER_DAT);
      
    //产生移位脉冲   
    SER_PORT|=_BV(SER_SCK);
    SER_PORT&=~_BV(SER_SCK);
    dat<<=1;
  }
}
//数码管显示数(0~255)
//num :显示的数   hex:是否用十六进制显示
void SegNumberOut(uint8_t num,uint8_t hex)
{
  uint8_t buf[2];//发送显示码缓冲区
  uint8_t temp;
  
  if(hex) //十六进制
  {
    buf[0]=g_aDisplayBuf[num>>4];//高位
    buf[1]=g_aDisplayBuf[num&0x0f];//低位
  }
  else//十进制
  {
    buf[1]=g_aDisplayBuf[num%10];
    temp=num%100;
    buf[0]=g_aDisplayBuf[temp/10];
    temp=num/100;
   
    if(temp>0)
      buf[1]|=0x80; //第一个数码管小数点表示百位1
    if(temp>1)
      buf[0]|=0x80;//两个数码管小数点表示百位2
  }
  
  //串行发送数据
  ser_out(buf[0]);
  ser_out(buf[1]);

  //产生锁存脉冲
  SER_PORT|=_BV(SER_RCK);
  SER_PORT&=~_BV(SER_RCK);
}

void SegInit(void)
{
  //595控制I/O初始化
  DDRD=_BV(SER_DAT)|_BV(SER_SCK)|_BV(SER_RCK);  
  SER_PORT&=~_BV(SER_SCK);
  SER_PORT&=~_BV(SER_RCK);
}
沙发
毁灭2012| | 2015-12-13 10:17 | 只看该作者
看看,收藏了,感觉很实用,以后或许可以少写点代码了

使用特权

评论回复
板凳
会飞の鱼| | 2015-12-13 10:22 | 只看该作者
要是有电路看看,或者实例图片就好啦。

使用特权

评论回复
地板
sourceInsight| | 2015-12-13 19:27 | 只看该作者
数码管显示接口函数//这个还是很值得借鉴的。。

使用特权

评论回复
5
bbapple| | 2016-1-12 15:10 | 只看该作者
还要用锁存脉冲啊!!!!

使用特权

评论回复
6
boy1990| | 2016-1-12 15:50 | 只看该作者
   串行发送数据的时候只需要设置两个输出就可以了。

使用特权

评论回复
7
sourceInsight| | 2016-1-12 16:24 | 只看该作者
这 数码管显示数(0~255),感觉还不错啊。。。

使用特权

评论回复
8
zhouhuanの| | 2016-1-12 16:50 | 只看该作者
//串行发送数据   ser_out(buf[0]);   ser_out(buf[1]);

使用特权

评论回复
9
hfdy01| | 2016-1-12 19:30 | 只看该作者
是这样:buf[1]|=0x80; //第一个数码管小数点表示百位1

使用特权

评论回复
10
hfdy01| | 2016-1-12 19:36 | 只看该作者
这个应该用的是十六进制,对吧?

使用特权

评论回复
11
feiqi1| | 2016-1-13 15:34 | 只看该作者
看看,开始转换命令的时候的程序感觉有点问题啊,看不懂!!!!

使用特权

评论回复
12
rreedd00| | 2016-1-13 15:44 | 只看该作者
feiqi1 发表于 2016-1-13 15:34
看看,开始转换命令的时候的程序感觉有点问题啊,看不懂!!!!

  ds18b20_write(DS18B20_CONVERT_TEM);//开始转换命令,是说的这个吗?

使用特权

评论回复
13
androidbus| | 2016-1-13 16:07 | 只看该作者
不错啊,   74HC95驱动的数码管显示模块。。。

使用特权

评论回复
14
CallReceiver|  楼主 | 2017-12-5 22:57 | 只看该作者
嗯,预料中的结果,先结贴吧,多谢大家啦

使用特权

评论回复
15
sopc12| | 2017-12-6 17:07 | 只看该作者
谢谢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

64

主题

1695

帖子

1

粉丝