前段时间动手做了一个关于ds18b20的小型项目(学校的电子设计大赛),自以为对ds18b20这个模块比较了解了。不过前几天因为专业课,要求在学校发的
最小系统板(基于stc12c5a60s2)
上实现某些功能,所以先对ds18b20这个模块进行了调试。
参考了之前做ds18b20这个模块的keil代码,感觉差别不大,修改了lcd1602和onewire总线相关定义端口并进行了编译和烧录,但是发现lcd1602的显示内容异常。
所以对之前的代码进行了检查,发现没有问题。后来请教了交流群的大佬发现,
stc12c5a60s2是增强型单片机,它是1T的
,而我的keil代码(包括网上大部分的例程)都是针对89系列单片机而写的,
传统51单片机内核是12T的(包括89系列在内)
。
T指的是
指令周期
与时钟周期的比例。
例如
传统51内核是12T的,每12个时钟周期构成一个指令周期。
那么问题就可以用一句话来概述了:
STC12C5A60S2是1T的芯片,运行速度比89C52快,延时函数需要进行调整。
DS18B20是一个对时序控制极其严苛的系统,所以延时控制非常重要!!时序顺序非常重要!!
清楚认识的以上事实后,针对于上述问题,理清思路:
1. 要解决精确延时问题;
2. 要搞清楚DS18B20交互方法;
3. 要搞清楚DS18B20时序结构;
注意:以下代码是在89系列单片机代码基础上做时序调整的。
1.ds18b20初始化操作:
2.ds18b20写操作:
3. ds18b20读操作:
因为作者的ds18b20模块代码是通过调用onewire单总线模块化写法,所以下面就在onewire.h文件里面进行修改
#include <8051.h>
#include <intrins.h>
#define uchar unsigned char
#define _nop_() __asm nop __endasm
//引脚定义
#define OneWire_DQ P1_1
/**
* @brief 单总线初始化
* @param 无
* @retval 从机响应位,0为响应,1为未响应
*/
uchar OneWire_Init(void)
{
uchar i;
uchar AckBit;
OneWire_DQ=1;
OneWire_DQ=0;
i = 247;while (--i); //Delay 500us
OneWire_DQ=1;
i = 32;while (--i); //Delay 70us
AckBit=OneWire_DQ;
i = 247;while (--i); //Delay 500us
return AckBit;
}
/**
* @brief 单总线发送一位
* @param Bit 要发送的位
* @retval 无
*/
void OneWire_SendBit(unsigned char Bit)
{
uchar i;
OneWire_DQ=0;
i = 4;while (--i); //Delay 10us
OneWire_DQ=Bit;
i = 24;while (--i); //Delay 50us
OneWire_DQ=1;
}
/**
* @brief 单总线接收一位
* @param 无
* @retval 读取的位
*/
uchar OneWire_ReceiveBit(void)
{
uchar i;
uchar Bit;
OneWire_DQ=0;
i = 2;while (--i); //Delay 5us
OneWire_DQ=1;
i = 2;while (--i); //Delay 5us
Bit=OneWire_DQ;
i = 24;while (--i); //Delay 50us
return Bit;
}
/**
* @brief 单总线发送一个字节
* @param Byte 要发送的字节
* @retval 无
*/
void OneWire_SendByte(unsigned char Byte)
{
uchar i;
for(i=0;i<8;i++)
{
OneWire_SendBit(Byte&(0x01<<i));
}
}
/**
* @brief 单总线接收一个字节
* @param 无
* @retval 接收的一个字节
*/
uchar OneWire_ReceiveByte(void)
{
uchar i;
uchar Byte=0x00;
for(i=0;i<8;i++)
{
if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
}
return Byte;
}
原代码
#include <8051.h>
#include <intrins.h>
#define uchar unsigned char
#define _nop_() __asm nop __endasm
//引脚定义
#define OneWire_DQ P1_1
//延时函数//
void DelayXus(uchar n)
{
while (n--)
{
_nop_();
_nop_();
}
}
/**
* @brief 单总线初始化
* @param 无
* @retval 从机响应位,0为响应,1为未响应
*/
unsigned char OneWire_Init(void)
{
uchar i;
uchar AckBit;
OneWire_DQ=1;
OneWire_DQ=0;
DelayXus(500); //Delay 500us
OneWire_DQ=1;
DelayXus(70); //Delay 70us
AckBit=OneWire_DQ;
DelayXus(500); //Delay 500us
return AckBit;
}
/**
* @brief 单总线发送一位
* @param Bit 要发送的位
* @retval 无
*/
void OneWire_SendBit(unsigned char Bit)
{
uchar i;
OneWire_DQ=0;
DelayXus(10); //Delay 10us
OneWire_DQ=Bit;
DelayXus(50); //Delay 50us
OneWire_DQ=1;
}
/**
* @brief 单总线接收一位
* @param 无
* @retval 读取的位
*/
unsigned char OneWire_ReceiveBit(void)
{
uchar i;
uchar Bit;
OneWire_DQ=0;
DelayXus(5); //Delay 5us
OneWire_DQ=1;
DelayXus(5); //Delay 5us
Bit=OneWire_DQ;
DelayXus(50); //Delay 50us
return Bit;
}
/**
* @brief 单总线发送一个字节
* @param Byte 要发送的字节
* @retval 无
*/
void OneWire_SendByte(unsigned char Byte)
{
uchar i;
for(i=0;i<8;i++)
{
OneWire_SendBit(Byte&(0x01<<i));
}
}
/**
* @brief 单总线接收一个字节
* @param 无
* @retval 接收的一个字节
*/
unsigned char OneWire_ReceiveByte(void)
{
uchar i;
uchar Byte=0x00;
for(i=0;i<8;i++)
{
if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
}
return Byte;
}
修改后的代码
ds18b20模块主要的onewire.h文件里面用到delay函数,所以修改代码部分主要在onewire.h文件里面