找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5974|回复: 0
收起左侧

利用AVR单片机设计的DS18B20测温程序

[复制链接]
ID:75926 发表于 2015-4-3 00:57 | 显示全部楼层 |阅读模式
  1. /********************************
  2.   DS18B20测温程序
  3.   文件名:main.c
  4.   编译:WinAVR-20070122

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

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

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

  22. #define DS18B20_READ_ROM 0x33
  23. #define DS18B20_MATCH_ROM 0X55
  24. #define DS18B20_SKIP_ROM 0XCC
  25. #define DS18B20_SEARCH_ROM 0XF0
  26. #define DS18B20_ALARM_SEARCH_ROM 0XEC
  27. #define DS18B20_WRITE_RAM 0X40
  28. #define DS18B20_READ_RAM 0XBE
  29. #define DS18B20_COPY_RAM 0X48
  30. #define DS18B20_CONVERT_TEM 0X44
  31. #define DS18B20_EECALL_EEPROM 0XB8
  32. #define DS18B20_READ_POWER_SUPPLY 0XB4

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

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

  41. void DelayMs(uint16_t t)
  42. {
  43.   uint16_t i;
  44.   for(i=0;i<t;i++)
  45.     _delay_loop_2(250 * 4);
  46. }

  47. //单总线复位
  48. uint8_t ds18b20_reset(void)
  49. {
  50.   uint8_t ret=0;
  51.   CLR_1WIRE_BUS;
  52.   DelayUs(500);  //拉低总线至少480us
  53.   SET_1WIRE_BUS;
  54.   DelayUs(100);//释放总线后等待15-60us
  55.   if((GET_1WIRE_BUS)==0)//检测到DS18B20把总线拉低
  56.     ret=1;        //复位成功
  57.   DelayUs(1000);//等待器件释放总线
  58.   return ret;
  59. }

  60. //单总线读一字节
  61. uint8_t ds18b20_read(void)
  62. {
  63.   uint8_t data=0;
  64.   uint8_t i=0;
  65.   for(i=0;i<8;i++)
  66.   {
  67.     data>>=1;
  68.     CLR_1WIRE_BUS;
  69.     DelayUs(2);//此时>1us
  70.     SET_1WIRE_BUS;
  71.     DelayUs(4);//此时<15us
  72.     if(GET_1WIRE_BUS)
  73.       data|=0x80;
  74.     DelayUs(60);//此时>60us
  75.   }
  76.   return(data);
  77. }
  78. //单总线写一字节
  79. void ds18b20_write(uint8_t data)
  80. {
  81.   uint8_t i=0;
  82.   for(i=0;i<8;i++)
  83.   {
  84.     if(data&0x01)
  85.     {
  86.       CLR_1WIRE_BUS;
  87.       DelayUs(8);//8us
  88.       SET_1WIRE_BUS;
  89.       DelayUs(55);//55us
  90.     }
  91.     else
  92.     {
  93.       CLR_1WIRE_BUS;
  94.       DelayUs(55);//55us
  95.       SET_1WIRE_BUS;
  96.       DelayUs(20);//8us
  97.     }
  98.     data>>=1;
  99.   }
  100. }

  101. //执行转换
  102. uint8_t Ds18b20Convert(uint8_t *t)
  103. {
  104.   //发送转换命令
  105.   if(ds18b20_reset()==0)
  106.     return 0;
  107.   ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配,总线上只有一个器件时,或对总线所有器件操作
  108.   ds18b20_write(DS18B20_CONVERT_TEM);//开始转换命令
  109.   
  110.   //等待转换完成,ds18b20默认转换精度为12位,此时最大转换时间为750ms
  111.   DelayMs(1000);
  112.   
  113.   //读温度字节
  114.   if(ds18b20_reset()==0)
  115.     return 0;
  116.   ds18b20_write(DS18B20_SKIP_ROM); //忽略地址匹配
  117.   ds18b20_write(DS18B20_READ_RAM); //读RAM命令
  118.   t[0]=ds18b20_read();
  119.   t[1]=ds18b20_read();
  120.   
  121.   return 1;
  122. }

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

  130.   if((t[1]&0xf8)==0xf8) //若负温度,从补码转换(取反加一)
  131.   {
  132.     sflag=1;
  133.     tmp=~tmp;
  134.     tmp++;
  135.   }
  136.   tmp&=0x07ff;    //确保前5位为0
  137.   
  138.   //乘0.0625操作,为此本函数只适用于DS18B20 12位转换(默认)时
  139.   val=((uint32_t)tmp)*625;
  140.   val/=10000;
  141.   
  142.   ret=(int8_t)val;
  143.   
  144.   if(sflag)
  145.     ret|=0x80;//变负数
  146.    
  147.   return ret;
  148. }

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

  158.   while(1)
  159.   {
  160.     if(Ds18b20Convert(tmp))//如果转换成功
  161.     {
  162.       tval=GetTemperature(tmp);//计算实际温度值
  163.       if(tval>=0)
  164.         SegNumberOut(tval,0);//十进制显示温度值
  165.       else
  166.         SegNumberOut(0,0);//数码管无法显示负数,只能显示0
  167.     }
  168.   }
  169.   return 0;
  170. }


  171. seg.c文件:


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

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

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

  188. #include "seg.h"

  189. #define SER_PORT  PORTD
  190. #define SER_DAT  PD4
  191. #define SER_RCK  PD5
  192. #define SER_SCK  PD6

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

  195. //向595 写一字节
  196. static void ser_out(uint8_t dat)
  197. {
  198.   uint8_t i;

  199.   for(i=0;i<8;i++)
  200.   {
  201.     if(dat&0x80)
  202.       SER_PORT|=_BV(SER_DAT);
  203.     else
  204.       SER_PORT&=~_BV(SER_DAT);
  205.       
  206.     //产生移位脉冲   
  207.     SER_PORT|=_BV(SER_SCK);
  208.     SER_PORT&=~_BV(SER_SCK);
  209.     dat<<=1;
  210.   }
  211. }
  212. //数码管显示数(0~255)
  213. //num :显示的数   hex:是否用十六进制显示
  214. void SegNumberOut(uint8_t num,uint8_t hex)
  215. {
  216.   uint8_t buf[2];//发送显示码缓冲区
  217.   uint8_t temp;
  218.   
  219.   if(hex) //十六进制
  220.   {
  221.     buf[0]=g_aDisplayBuf[num>>4];//高位
  222.     buf[1]=g_aDisplayBuf[num&0x0f];//低位
  223.   }
  224.   else//十进制
  225.   {
  226.     buf[1]=g_aDisplayBuf[num%10];
  227.     temp=num%100;
  228.     buf[0]=g_aDisplayBuf[temp/10];
  229.     temp=num/100;
  230.    
  231.     if(temp>0)
  232.       buf[1]|=0x80; //第一个数码管小数点表示百位1
  233.     if(temp>1)
  234.       buf[0]|=0x80;//两个数码管小数点表示百位2
  235.   }
  236.   
  237.   //串行发送数据
  238.   ser_out(buf[0]);
  239.   ser_out(buf[1]);

  240.   //产生锁存脉冲
  241.   SER_PORT|=_BV(SER_RCK);
  242.   SER_PORT&=~_BV(SER_RCK);
  243. }

  244. void SegInit(void)
  245. {
  246.   //595控制I/O初始化
  247.   DDRD=_BV(SER_DAT)|_BV(SER_SCK)|_BV(SER_RCK);  
  248.   SER_PORT&=~_BV(SER_SCK);
  249.   SER_PORT&=~_BV(SER_RCK);
  250. }
复制代码


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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