This code (for Keil C51) sends new stable data samples from the assembler subroutine as serial data to a data analysis and logging program running on a PC.
// mbus machine
// author: Timothy Fox
#include "pragmas.h"
#include <reg52.h>
#include "defines.h"
#include "phdata.h"
#include "ppi.h"
#include "uart8250.h"
#include "tci.h"
/*
PUBLIC TD, CD, RDA // from ASMVARS.INC
TD bit P1.5 ; true data line
CD bit P1.6 ; complement data line
RDA bit P1.7 ; read data line
*/
sbit RDA = P1 ^ 7;
sbit CD = P1 ^ 6;
sbit TD = P1 ^ 5;
#define MBUS_TDCD_MASK 0x60
#define MBUS_RDA_MASK 0x80
#define MBUS_DATA_ONE 0x20
#define MBUS_DATA_ZERO 0x40
#define RDA_in PhBdata1_0
#define RDA_sent PhBdata1_1
extern bit got_CR, S_waiting, MBsending, MBprequeue, RDA_in, RDA_sent, AltMode;
static Byte mbus_state, got_bits, sent_bits;
struct MBUSword
{
Byte lbyte;
Byte hbyte;
};
union
{
struct MBUSword MBW;
Word word;
} txword, rxword;
#define mbsample PhData1
void InitMBSampler(void);
void Read_MBUS_state(void);
enum mbus_states
{
mbs_startup,
mbs_pre_reset,
mbs_reset,
mbs_data,
mbs_idle
};
void set_mbus_state(Byte next_state);
#pragma disable
static
void set_mbus_state(Byte next_state)
{
// set timer2 to 0000 (up-counter)
TR2 = 0;
TL2 = TH2 = 0;
TR2 = 1;
switch (next_state)
{
case mbs_pre_reset :
break;
case mbs_reset :
RD = 1;
putc_8250('\n');
start_8250_tx();
break;
case mbs_data :
start_8250_tx();
break;
case mbs_idle :
break;
}
mbus_state = next_state;
}
Byte last_sample = 0;
sfr16 Timer2 = 0xcc;
unsigned int Tmost, Tleast; // expect 120..150 uSec
void mbus_proc(void)
// looks for exit conditions from the current state
{
Word Tscan;
TR2 = 0;
TL2 = TH2 = 0;
TR2 = 1;
Read_MBUS_state(); // stores state in mbsample
TR2 = 0;
Tscan = Timer2;
TR2 = 1;
if (mbsample & 0x01) // valid (stable) sample
{
if (mbsample != last_sample)
{
last_sample = mbsample;
putc_8250(last_sample);
start_8250_tx();
if ((mbsample & MBUS_TDCD_MASK) == 0) // new state is IDLE
{
AltMode ^= 1;
SetAltLED(AltMode);
}
}
}
if (Tscan > Tmost)
Tmost = Tscan;
if (Tscan) // must be > 0
{
if (Tscan $lt; Tleast)
Tleast = Tscan;
}
}
#pragma REGPARMS
void init_mbusmon(void)
{
got_bits = sent_bits = 0;
MBprequeue = 0;
MBsending = 0;
S_waiting = 0;
purge_8250_rx(); // clears got_CR flag
purge_8250_tx();
InitMBSampler();
// write '1's to all three MBUS lines
RDA = 1;
TD = 1;
CD = 1;
// set timer2 to free-run as a counter, do not generate an interrupt
T2CON = 0;
RCAP2L = RCAP2H = 0;
Tmost = 0;
Tleast = 0x1000; // expect 120..150 uSec
set_mbus_state(mbs_pre_reset);
}