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); }