Samtidig anser jag att alla delay() är av ondo - men ibland kan man inte undvika dom.
Nåväl, jag har gjort som följer:
Kod: Markera allt
typedef struct
{
BYTE Temp_LSB;
BYTE Temp_MSB;
BYTE Th_Reg;
BYTE Tl_Reg;
BYTE Config;
BYTE Res_2;
BYTE Count_Remain;
BYTE Count_Per_Degree;
BYTE CRC;
} T_OW_SCRATCHPAD;
typedef struct
{
BYTE Presence;
BYTE Timer;
BYTE Shift;
BYTE Index;
BYTE Tx_Bit_Cnt;
BYTE Rx_Bit_Cnt;
BYTE Tx_Buffer[sizeof(T_OW_SCRATCHPAD)];
union
{
BYTE Buffer[sizeof(T_OW_SCRATCHPAD)];
T_OW_SCRATCHPAD Pad;
} Rx;
BYTE Sequence;
short Temp;
BYTE Done;
} T_ONE_WIRE;
T_ONE_WIRE OW;
#define OW_SKIP_ROM 0xCC
#define OW_CONVERT 0x44
#define OW_READ_SCRATCHPAD 0xBE
void Initiate_OW(void)
{
OW.Timer = false;
OW.Index = 0;
OW.Rx_Bit_Cnt = 0;
OW.Tx_Bit_Cnt = 0;
OW_nTx = false;
OW.Sequence = 0;
OW.Done = false;
}
const BYTE DsCRC[] = {
0, 94, 188, 226, 97, 63, 221, 131, 194, 156, 126, 32, 163, 253, 31, 65,
157, 195, 33, 127, 252, 162, 64, 30, 95, 1, 227, 189, 62, 96, 130, 220,
35, 125, 159, 193, 66, 28, 254, 160, 225, 191, 93, 3, 128, 222, 60, 98,
190, 224, 2, 92, 223, 129, 99, 61, 124, 34, 192, 158, 29, 67, 161, 255,
70, 24, 250, 164, 39, 121, 155, 197, 132, 218, 56, 102, 229, 187, 89, 7,
219, 133, 103, 57, 186, 228, 6, 88, 25, 71, 165, 251, 120, 38, 196, 154,
101, 59, 217, 135, 4, 90, 184, 230, 167, 249, 27, 69, 198, 152, 122, 36,
248, 166, 68, 26, 153, 199, 37, 123, 58, 100, 134, 216, 91, 5, 231, 185,
140, 210, 48, 110, 237, 179, 81, 15, 78, 16, 242, 172, 47, 113, 147, 205,
17, 79, 173, 243, 112, 46, 204, 146, 211, 141, 111, 49, 178, 236, 14, 80,
175, 241, 19, 77, 206, 144, 114, 44, 109, 51, 209, 143, 12, 82, 176, 238,
50, 108, 142, 208, 83, 13, 239, 177, 240, 174, 76, 18, 145, 207, 45, 115,
202, 148, 118, 40, 171, 245, 23, 73, 8, 86, 180, 234, 105, 55, 213, 139,
87, 9, 235, 181, 54, 104, 138, 212, 149, 203, 41, 119, 244, 170, 72, 22,
233, 183, 85, 11, 136, 214, 52, 106, 43, 117, 151, 201, 74, 20, 246, 168,
116, 42, 200, 150, 21, 75, 169, 247, 182, 232, 10, 84, 215, 137, 107, 53};
void OW_Sequence(void)
{
BYTE X, Y;
short Z, W;
if(OW.Tx_Bit_Cnt)
{ // If anything needs to be send
if(!(OW.Tx_Bit_Cnt & 0x07))
{
OW.Shift = OW.Tx_Buffer[OW.Index++];
}
if(OW.Shift & 0x01) OW_Write_Bit(true);
else OW_Write_Bit(false);
OW.Shift >>= 1;
if(!--OW.Tx_Bit_Cnt)
{
OW.Index = 0;
}
}
else if(OW.Rx_Bit_Cnt)
{ // If anything needs to be recieved
OW.Rx_Bit_Cnt--;
OW.Shift >>= 1;
if(OW_Read_Bit()) OW.Shift |= 0x80;
if(!(OW.Rx_Bit_Cnt & 0x07))
{
OW.Rx.Buffer[OW.Index++] = OW.Shift;
}
if(!OW.Rx_Bit_Cnt)
{
OW.Index = 0;
}
}
else if(!OW.Timer) switch(OW.Sequence)
{ // If nothing is to be transmitted or recieved AND the timer is zero
case 0: // Reset Communication is done, now address all 1-Wire devices and order a convert
if(OW_Reset())
{
LED_Blue = true;
OW.Sequence++;
}
else
{
OW.Timer = 250; // 2,5 sek min. before next attempt
OW.Presence = false;
}
break;
case 1:
OW.Tx_Buffer[0] = OW_SKIP_ROM; // The convert command needs to gp to all
OW.Tx_Buffer[1] = OW_CONVERT; // Start the convert
OW.Timer = 120; // Give it 1,2 sec
OW.Tx_Bit_Cnt = 16;
OW.Sequence++; // Take me to the next step
break;
case 2:
if(OW_Reset())
{
OW.Tx_Buffer[0] = OW_SKIP_ROM; // The convert command needs to go to all
OW.Tx_Buffer[1] = OW_READ_SCRATCHPAD; // Start the convert
OW.Tx_Bit_Cnt = 16; // Send these datas
OW.Rx_Bit_Cnt = sizeof(T_OW_SCRATCHPAD) * 8; // Then recieve scratchpad
OW.Sequence++; // Next step
}
else
{ // Sorry, no presence, start all over again
OW.Timer = 250;
OW.Sequence = 0;
OW.Presence = false;
}
break;
case 3:
X = 0;
for(Y = 0; Y < sizeof(T_OW_SCRATCHPAD);Y++) X = DsCRC[X ^ OW.Rx.Buffer[Y]];
if(!X)
{
// CRC is OK
OW.Temp = (OW.Rx.Pad.Temp_LSB | (OW.Rx.Pad.Temp_MSB << 8)) * 5; // Pack it to a short
OW.Sequence = 0;
OW.Presence = true;
OW.Done = true;
}
else
{
OW.Presence = false;
OW.Timer = 250;
}
OW.Sequence = 0;
break;
}
}
BYTE OW_Reset(void)
{
WORD Ctr;
BYTE Result;
OW.Timer = 1;
while(OW.Timer);
OW_nTx = true;
OW.Timer = 1;
while(OW.Timer);
OW_nTx = false;
OW.Timer = 1;
for(Ctr = 0; Ctr < 20; Ctr++);
Result = !OW_Rx;
while(OW.Timer);
return(Result);
}
void OW_Write_Bit(BYTE Data)
{
BYTE Ctr, Later;
if(Data) Ctr = 1; // If a '1', short time
else Ctr = 50; // If a '0', long time
Later = 120 - Ctr;
OW_nTx = true; // Lower the DQ on 1-wire
while(Ctr) Ctr--;
OW_nTx = false; // Release DQ
while(Later) Later--;
}
BYTE OW_Read_Bit(void)
{
BYTE Ctr, Result;
Ctr = 1;
OW_nTx = true;
while(Ctr) Ctr--;
OW_nTx = false;
Ctr = 3;
while(Ctr) Ctr--;
if(OW_Rx) Ctr = Result;
else Result = false;
Ctr = 110; // Secure that the sequence time is long enough
while(Ctr) Ctr--; // Secure that the sequence time is long enough
return(Result);
}
OW.Timer räknas ner med en timerinterrupt, i detta fall på 100Hz. I den ISR finns: if(OW.Timer) OW.Timer--;
Jag använder en transistor som pull-down samt en transistor som ingångssteg, detta för att ha en viss isolering mellan µC och ledningarna. Använder inte parasitmatning.
Sedan är jag allergisk mot att en väntan behöver låsa allt upp, alltså lägger jag en rad i main-loop:
if(OW.Sequence) OW_Sequence(); // If running, repeat this
Och för att starta en omvandling och avläsning:
OW_Sequence(); // Run it now!
Denna startas när en timer har gått ut, i detta fall en timer som bestämmer hur ofta PI-regleringen ska reglera.
På detta vis kommer det att vara en bit per kall som exekveras, behövs det väntas en viss tid ställer man den tid i OW.Timer.
Vill man ha en kontinuerlig omvandling kan man lägga in OW_Sequence() i en ISR som inte går för snabb, t.ex. samma som räknar ner OW.Timer.
Rutinen medger enbart att man har en sensor på bussen, den kan utökas med en identifiering, sekvensen blir då en bit mer avancerat men till detta är den enkel och smidig.