本帖最后由 ZMan 于 2021-11-28 16:57 编辑
网上都说是延时问题,但是怎么改都不行。
单片机主控芯片为stm8s105c6t6,外部时钟是12M
#include "ds18b20.h" void Alarm_for_No_DS18B20(void) { //单总线上没有发现DS18B20则报警,该动作据具体应用具体处理 } unsigned char DS18B20_Start(void) //复位ds18b20芯片 { unsigned char i,succ=0xff; DS18B20_PIN_SET_OUT(); //置为输出口 DS18B20_WR0(); //总线产生下降沿,初始化开始 for(i=0; i<30; i++)delay_us(25); //总线保持低电平在480 - 960微秒之间 ;i<20;(25us) DS18B20_WR1(); //总线拉高 DS18B20_PIN_SET_IN(); //置为输入,主机释放总线,准备接收DS18B20的应答脉冲 i=0; while(R_DS18B20()) //等待DS18B20发出应答脉冲 { delay_us(5); //5 if(++i>12) //DS18B20检测到总线上升沿后等待15-60us { succ=0x00; //如果等待大于约60us,报告复位失败 break; } } i=0; while(!R_DS18B20()) //DS18B20发出存在脉冲,持续60-240us { delay_us(5); //5 if(++i>48) //如果等带大于约240us,报告复位失败 { succ=0x00; break; } } delay_ms(20); return succ; } void DS18B20_SendU8(unsigned char d8)//向DS18B20写一字节函数 { unsigned char i; DS18B20_PIN_SET_OUT(); //置为输出口 for(i=0; i<8; i++) { DS18B20_WR0(); //总线拉低,启动“写时间片” delay_us(2); //大于1微妙 if(d8&0x01)DS18B20_WR1(); delay_us (32); //延时至少60微秒,使写入有效 delay_us (30); DS18B20_WR1(); //总线拉高,释放总线,准备启动下一个“写时间片” d8>>=1; delay_us (1); } DS18B20_PIN_SET_IN(); //主机释放总线 } unsigned char DS18B20_ReadU8(void)//从DS18B20读1个字节函数 { unsigned char i,d8; for(i=0; i<8; i++) { d8>>=1; DS18B20_PIN_SET_OUT();//置为输出口 DS18B20_WR0(); //总线拉低,启动读“时间片” delay_us(2); //大于1微妙 DS18B20_WR1(); //主机释放总线,接下来(2~15)us内读有效 DS18B20_PIN_SET_IN(); //引脚设定为输入口,准备读取 delay_us(2); //延时2个us后进行读 if(R_DS18B20())d8|=0x80;//从总线拉低时算起,约15微秒内读取总线数据 delay_us(32); //60us后读完成 delay_us(30); DS18B20_WR1(); //总线拉高,主机释放总线,准备启动下一个“写时间片” } DS18B20_PIN_SET_IN(); //主机释放总线 return(d8); } void Init_DS18B20(void) //初始化DS18B20 { unsigned char i; i=DS18B20_Start(); //复位 if(!i) //单总线上没有发现DS18B20则报警 { Alarm_for_No_DS18B20(); return; } DS18B20_SendU8 (SKIP_ROM); //跳过rom匹配 DS18B20_SendU8 (WRITE_RAM); //设置写模式 DS18B20_SendU8 (0x64); //设置温度上限100摄氏度 DS18B20_SendU8 (0x8a); //设置温度下线-10摄氏度 DS18B20_SendU8 (0x7f); //12bit(默认) } //-------------------------------------------------------------------------------------- unsigned int Read_DS18B20(void) //读取并计算要输出的温度 { unsigned char i; unsigned char tl; unsigned int th; // unsigned char t; // unsigned char temp; i=DS18B20_Start(); //复位 if(!i) //单总线上没有发现DS18B20则报警 { Alarm_for_No_DS18B20(); return 0; } delay_ms(1); DS18B20_SendU8(SKIP_ROM); //发跳过序列号检测命令 DS18B20_SendU8(CONVERT_TEM); //命令Ds18b20开始转换温度 i=0; delay_ms(1); while(!R_DS18B20()) //当温度转换正在进行时,主机读总线将收到0,转换结束为1 { delay_ms(3); if(++i>250) break; //至多转换时间为750ms } DS18B20_Start(); //初始化 delay_ms(1); DS18B20_SendU8(SKIP_ROM); //发跳过序列号检测命令 DS18B20_SendU8(READ_RAM); //发读取温度数据命令 tl = DS18B20_ReadU8(); //先读低8位温度数据 th = DS18B20_ReadU8()<<8; //再读高8位温度数据 return (th|tl)*10>>4; //温度放大了10倍,*0.0625=1/16=>>4 // temp = DS18B20_ReadU8(); //先读低八位 // t = (((temp & 0xF0) >> 4) + (temp & 0x0F) * 0.0625); // temp = DS18B20_ReadU8(); //再读高八位 // t += ((temp & 0x0F) << 4); // // return t; }
void delay_us(uint16_t nCount) { nCount *= 3; while(--nCount); } void delay_ms(uint16_t nCount) { while(nCount--) { delay_us(1000); } }
|