/********************************
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为非总线供电)
*******************************/
#include #include #include #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 } //单总线复位 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 #include #include #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); }
上一篇:读/写atmega8515内部EEPROM的例子
下一篇:开关稳压芯片LM2576ADJ做数控电源程序
推荐阅读最新更新时间:2024-11-08 18:03