|
本帖最后由 nicksean 于 2012-4-1 21:15 编辑
最近在两个小项目中用了18B20测温,其中一个项目要输出1.8K的脉冲并且脉冲数可控,用于驱动步进电机驱动器移动指定的距离。脉冲输出用了定时器中断,最开始的做法是测温时关中断,但是发现输出的脉冲不稳定。我用小喇叭接脉冲输出端,可以听到很明显的中断。后来在一本书上《MSP430系列单片机系统工程设计与实践》受到启发,仔细看了18B20的读写时序。发现只需要在几个关键时间点上关中断就可以保证单总线的读写时序要求。
1 初始化总线时序
手册上只给出了单片机拉低总线的最短时间480us,注意,这里并未给出最大时间,所以在这480us 时间内不必关中断,即使被中断了,也只是延长了拉低时间而已。
下一段是单片机释放总线到18B20拉低总线作为响应的时间,15~60us。这段是要关中断了(其实如果中断函数执行时间非常短,比如3us,不关中断也是可以的)。
再下一段是等待18B20释放总线,同样不必关中断。
2 读总线
读总线的最小时间60us,其实只要单片机采样之后就可以开中断了,剩下的时间就没有那么严格的要求了
3 写总线
写总线的最小时间同样是60us,为了保证18B20能读到正确数据,这段时间都要关中断
综上所述,其实在总线操作过程中,关中断的最长时间是60us其余时间都不必关中断。这对于要进行数码管动态扫描这样实时性较高的应用还是可以满足要求的。
代码实现
//STC12C5A60S2 推挽输出, 11.0592MHz 单周期时钟
#ifndef NOP
#define NOP(x) _nop_()
#endif
#define _PIN_HI(port, bit) (_SET_BIT(port, bit))
#define _PINS_HI(port, bit) (_SET_BITS(port, bit))
#define _PIN_LO(port, bit) (_CLR_BIT(port, bit))
#define _PINS_LO(port, bit) (_CLR_BITS(port, bit))
#define _PIN_GT(port, bit) (NOP(), _GET_BIT(port, bit))
#define _PINS_GT(port, bit) (NOP(), _GET_BITS(port, bit))
#define _PIN_FLP(port, bit) (_FLP_BIT(port, bit))
#define _PINS_FLP(port, bit) (_FLP_BITS(port, bit))
#define _PxM0(port) __ID_COMBINE(port, M0)
#define _PxM1(port) __ID_COMBINE(port, M1)
//推挽输出
#define _PIN_OUT(port, bit) (_CLR_BIT(_PxM1(port), bit), _SET_BIT(_PxM0(port), bit))
#define _PINS_OUT(port, bits) (_CLR_BITS(_PxM1(port), bits), _SET_BITS(_PxM0(port), bits))
//高阻输入
#define _PIN_IN(port, bit) (_SET_BIT(_PxM1(port), bit), _CLR_BIT(_PxM0(port), bit))
#define _PINS_IN(port, bits) (_SET_BITS(_PxM1(port), bits), _CLR_BITS(_PxM0(port), bits))
//准双向(弱上拉,即普通51方式)
#define _PIN_IN_PH(port, bit) (_CLR_BIT(_PxM1(port), bit), _CLR_BIT(_PxM0(port), bit))
#define _PINS_IN_PH(port, bits) (_CLR_BITS(_PxM1(port), bits), _CLR_BITS(_PxM0(port), bits))
//开漏
#define _PIN_OUT_OD(port, bit) (_SET_BIT(_PxM1(port), bit), _SET_BIT(_PxM0(port), bit))
#define _PINS_OUT_OD(port, bits) (_SET_BIT(_PxM1(port), bits), _SET_BIT(_PxM0(port), bits))
//数组大小
#define _ARRAY_SIZE(a) ((sizeof(a)) / (sizeof(a[0])))
#define _18B20_ERROR_H (0x7F)
#define _18B20_ERROR_L (0x7E)
#define _CHANNEL_NUM 2 //这个定义的在同一个端口上连接18B20 的个数2个
#define _PORT_MASK 0x06 //这个定义的是在端口上哪几个位连接的18B20
void OneWire_Delay2us(BYTE n) //@11.0592MHz STC fast clock
{
while(n--)
{
NOP(); NOP(); NOP(); NOP(); NOP();
NOP();
};
}
void bitTest_n1Wire(BYTE in, SBYTE* pBuf)
{
BYTE ch;
BYTE chMsk;
if(pBuf)
{
for(ch = 0, chMsk = 0x01; chMsk && ch < _CHANNEL_NUM; chMsk <<= 1)
{
if(chMsk & _PORT_MASK) //说明是有效数据位
{
pBuf[ch] = (in & chMsk)? _18B20_ERROR_H : _18B20_ERROR_L;
++ch;
}
}
}
}
BYTE init_n1Wire()
{
BYTE ret = 0;
_PINS_LO(P1, _PORT_MASK);
_PINS_OUT(P1, _PORT_MASK);
OneWire_Delay2us(240); // >= 480 us
EA = 0;
_PINS_IN(P1, _PORT_MASK);
OneWire_Delay2us(30); //15~60 us
OneWire_Delay2us(10); //
ret = _PINS_GT(P1, _PORT_MASK);
EA = 1;
OneWire_Delay2us(240);
return ret;
}
BYTE bitRead_n1Wire()
{
BYTE ret = 0;
EA = 0;
_PINS_LO(P1, _PORT_MASK);
_PINS_OUT(P1, _PORT_MASK);
OneWire_Delay2us(1); // >= 1 us
_PINS_IN(P1, _PORT_MASK);
OneWire_Delay2us(3); // T rc
ret = _PINS_GT(P1, _PORT_MASK);
EA = 1;
OneWire_Delay2us(25); // total >= 60 us
return ret;
}
BYTE lineRead_n1Wire()
{
BYTE ret = 0;
EA = 0;
_PINS_IN(P1, _PORT_MASK);
OneWire_Delay2us(5); // >= 1 us
ret = _PINS_GT(P1, _PORT_MASK);
EA = 1;
return ret;
}
void bitWrite_n1Wire(BYTE bits)
{
EA = 0;
_PINS_LO(P1, _PORT_MASK);
_PINS_OUT(P1, _PORT_MASK);
OneWire_Delay2us(1); // >= 1 us
_CLR_BITS(P1, _PORT_MASK);
_SET_BITS(P1, bits & _PORT_MASK);
EA = 1;
OneWire_Delay2us(14); // >= 14 us, <= 120 us
_PINS_IN(P1, _PORT_MASK);
OneWire_Delay2us(7); // T rc
}
void writeByte_n1Wire(BYTE val)
{
BYTE msk;
for(msk = 0x01; msk; msk <<= 1)
{
bitWrite_n1Wire((val & msk)? _PORT_MASK : 0x00);
}
}
void readByte_n1Wire(BYTE* pBuf)
{
BYTE ch;
BYTE msk;
BYTE chMsk;
BYTE col;
if(!pBuf)
{
return;
}
for(msk = 0x01; msk; msk <<= 1) //列数据掩码
{
col = bitRead_n1Wire(); //读出一列数据,一列指的是多个单总线构成的单个位数据的集合
for(ch = 0, chMsk = 0x01; chMsk && ch < _CHANNEL_NUM; chMsk <<= 1)
{
if(chMsk & _PORT_MASK) //说明是有效数据位
{
pBuf[ch] |= (col & chMsk)? msk : 0;
++ch;
}
}
}
}
void measure_n1Wire()
{
init_n1Wire();
writeByte_n1Wire(0xCC);
writeByte_n1Wire(0x44);
}
void readTemperature_n1Wire(SWORD temperatures[_CHANNEL_NUM])
{
BYTE index;
BYTE init;
BYTE res[2][_CHANNEL_NUM] = {0}; // 2 means two values
init = lineRead_n1Wire();
bitTest_n1Wire(init, temperatures); //检测与地短路的情况,若短路,temperatures中的值为_18B20_ERROR_L否则为_18B20_ERROR_H
init = init_n1Wire();
writeByte_n1Wire(0xCC);
writeByte_n1Wire(0xBE);
readByte_n1Wire(res[0]); // low byte
readByte_n1Wire(res[1]); // high byte
for(index = 0; index < _CHANNEL_NUM; ++index)
{
if(temperatures[index] != _18B20_ERROR_L) //对地短路错误
{
if(res[0][index] == 0xFF && res[1][index] == 0xFF) //对正短路错误
{
temperatures[index] = _18B20_ERROR_H; //置错误标志
}
else
{
temperatures[index] = (SBYTE)((res[1][index] << 4) | (res[0][index] >> 4));
}
}
}
}
static volatile signed short idata s_tempBuf[_CHANNEL_NUM] = {0}; //保存温度测量值
void main()
{
unsigned short cntr1= 0;
unsigned short cntr2 = 0;
while(1)
{
++cntr1;
if(cntr1 == 0)
{
++cntr2;
if(cntr2 == 0)
{
measure_n1Wire();
}
else if(cntr2 == 0x7FFF)
{
readTemperature_n1Wire(s_tempBuf);
}
}
}
}
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
|