|
|
//****************************************************************************
// 232I2C.C ©1999 Nick McCurdy
// Bit-banger program to drive the pins of an 89C2051 as a I2C <> RS232
// two-way serial interface converter
// Revisions:
// Added code to allow upper or lower case commands 09.13.2001
//
// Stuff to do:
// Add support for 10 bit extended addressing.
// Add support for extended response bytes.
//
//****************************************************************************
//#include <reg51.h>
#include <AT892051.H>
#include "handy.h"
//****************************************************************************
// Globals.
//****************************************************************************
// Character string buffer length.
#define MSGLEN 15
// Counter value for 1 mS interrupt @ 11.059 MHz crystal freq
#define TIMER1MSEC 64613
typedef unsigned char BYTE;
int binval;
BYTE idata rbuf[MSGLEN];
BYTE idata tbuf[MSGLEN];
BYTE idata temp[5];
BYTE idata ticks = 200;
BYTE idata rbin, rbout, tbin, tbout;
BYTE idata I2Address, I2Databyte, I2Command, MSByte, LSByte;
BYTE idata * so;
bit rfull, tempty, tdone;
BYTE code ormsg[]={"Over-run\r\n"};
BYTE code olmsg[]={"On-Line\r\n"};
BYTE code bcmsg[]={"Bad Command\r\n"};
BYTE code crlf[]={"\r\n"};
BYTE code negs[]={"-"};
BYTE code half[]={".5"};
BYTE code *ctable[] = {
"RP", /* READ POT */
"WP", /* WRITE POT */
"RT", /* READ TEMP */
"WT", /* WRITE TEMP */
"" /* End of List */
};
#define READPOT 0
#define WRITEPOT 1
#define READTEMP 2
#define WRITETEMP 3
#define NUMCMNDS 5
// I/O Pins
// Pins for 2051
sbit TICK = P3 ^ 7; // 2 mSec Period Sq Wave 11
sbit SDA = P3 ^ 4; // I2C data 8
sbit SCL = P3 ^ 5; // I2C clock 9
#define C2051 1
#ifdef C2051
sbit RLED = P1 ^ 7; // READ LED 19
sbit WLED = P1 ^ 6; // WRITE LED 18
sbit BLINK= P1 ^ 5; // BLINKIE LIGHT (Gotta have it) 17
sbit TLED= P1 ^ 4; // THERMOMETER MODE LED 16
#else
sbit RLED = P0 ^ 7; // READ LED 39
sbit WLED = P0 ^ 6; // WRITE LED 38
sbit BLINK= P0 ^ 5; // BLINKIE LIGHT (Gotta have it) 37
sbit TLED= P0 ^ 4; // THERMOMETER MODE LED 36
#endif
//****************************************************************************
// Function List
//****************************************************************************
void main(void);
void init(void);
void CodeMessage(BYTE code *);
void DataMessage(BYTE idata *);
void ProcessMessage(void);
void SendSerialData(BYTE idata *);
void WaitforSo(void);
void Reset_msg(void);
void I2Start(void);
void I2Stop(void);
bit I2Clock(void);
void I2Ack(void);
bit I2Nack(void);
void I2SendByte(BYTE);
BYTE I2GetByte(void);
void waste_time(void);
BYTE Ahtob( BYTE idata*);
void tohex( BYTE b, BYTE idata*);
void scpy( BYTE idata *, BYTE idata *, BYTE);
bit ishex( BYTE );
BYTE slen( BYTE idata *);
BYTE Strpos( BYTE, BYTE idata *);
bit scomp(BYTE idata *, BYTE code *);
void btoa(BYTE, BYTE idata *);
void Reverse(BYTE idata *);
void toup(BYTE idata *);
int ReadLM75(void);
//****************************************************************************
// Main Loop of program.
// Wait for RS232 serial command, parse as needed and execute.
//****************************************************************************
void main(void){
init();
CodeMessage(olmsg);
while (1){
while (rfull != TRUE){
}
ProcessMessage();
}
}
//****************************************************************************
// Do something !
//****************************************************************************
void ProcessMessage(void){
BYTE p;
//scpy(cmnd, rbuf, 0);
p = 0;
scpy(temp, rbuf, 2);
toup(temp);
while (scomp(temp, ctable[p]) && (p < NUMCMNDS)){
p++;
}
if (p == NUMCMNDS){
Reset_msg();
CodeMessage(bcmsg);
return;
}
scpy(temp, &rbuf[3], 2);
I2Address = Ahtob(temp);
scpy(temp, &rbuf[6], 2);
I2Command = Ahtob(temp);
//scpy(temp, cmnd, 2); ????
switch (p){
case READPOT:
RLED = 0;
WLED = 1;
TLED = 1;
I2Start();
I2SendByte(I2Address);
I2Nack();
I2SendByte(I2Command);
I2Nack();
I2Databyte = I2GetByte();
I2Ack();
I2Stop();
tohex(I2Databyte, temp);
DataMessage(temp);
CodeMessage(crlf);
break;
case WRITEPOT:
RLED = 1;
WLED = 0;
TLED = 1;
I2Start();
I2SendByte(I2Address);
I2Nack();
I2SendByte(I2Command);
I2Nack();
scpy(temp, &rbuf[9], 2);
I2Databyte = Ahtob(temp);
I2SendByte(I2Databyte);
I2Ack();
I2Stop();
break;
case READTEMP:
WLED = 1;
RLED = 0;
TLED = 0;
ReadLM75();
break;
case WRITETEMP:
WLED = 0;
RLED = 1;
TLED = 0;
scpy(temp, &rbuf[10], 2);
I2Databyte = Ahtob(temp);
I2SendByte(I2Databyte);
scpy(temp, &rbuf[12], 2);
I2Databyte = Ahtob(temp);
I2SendByte(I2Databyte);
I2Ack();
I2Stop();
break;
default:
CodeMessage(bcmsg);
Reset_msg();
return;
}
Reset_msg();
}
//****************************************************************************
// Initialize the serial port and other stuff that needs it.
//****************************************************************************
void init(void){
// Serial Poop
ES = DISABLE; /* IE.4 - Disable serial port interrupt */
SCON = SCON_M1; /* set serial port operating mode */
PCON = SMOD_CLR; /* Clears the SMOD bit */
RI = BIT_CLR; /* SCON.0 - Clear received data flag */
TI = BIT_CLR; /* SCON.1 - Clear transmit data flag */
P3 |= 0x03; /* Set TxD and RxD to Mark State */
// Timer 1 Poop
ET1 = DISABLE; /* IE.3 - Disable timer 1 interrupt */
TR1 = DISABLE; /* TCON.6 stop timer */
TMOD &= 0x0F; /* clear timer 1 */
TMOD |= 0x20; /* Mode 2 for timer 1. */
TH1 = BAUD9600; /* Set baud rate count */
//TCON = BIT0 | BIT6;/* TCON.6&1: start timer 1, edge trig */
TR1 = ENABLE;
// Timer 0 Poop
TR0 = DISABLE; // Stop timer 0
TMOD &= 0xF0; // Clear timer 0
TMOD |= 0x01; // Mode 1 for timer 0
TH0 = TIMER1MSEC >> 8;
TL0 = TIMER1MSEC & 0x00FF;
ET0 = ENABLE; // Enable timer 0 interrupts
TR0 = ENABLE; // Enable timer 0
// Misc Poop
//P0 = 0x55;
tempty = TRUE;
tdone = TRUE;
rfull = 0;
rbout = 0;
rbin = 0;
tbin = 0;
tbout = 0;
// Interrupt Poop
ES = ENABLE;
EA = ENABLE;
}
//****************************************************************************
// External Interrupt 0
//****************************************************************************
void irq_ext0(void) interrupt 0{
}
//****************************************************************************
// Timer 0 Interrupt
//****************************************************************************
void irq_timer0(void) interrupt 1{
TR0 = DISABLE;
TH0 = TIMER1MSEC >> 8;
TL0 = TIMER1MSEC & 0x00FF;
TR0 = ENABLE;
TICK = ~TICK;
ticks -=1;
if (ticks == 0){
ticks = 200;
BLINK = ~BLINK;
}
}
//****************************************************************************
// External Interrupt 1
//****************************************************************************
void irq_ext1(void) interrupt 2 {
}
//****************************************************************************
// Timer 1 Interrupt
//****************************************************************************
void irq_timer1(void) interrupt 3 {
}
//****************************************************************************
// Serial Port Interrupt
//****************************************************************************
void serial_interrupt () interrupt 4 {
BYTE data c;
// Check for receive interrupt.
if ( RI ){
CLR_BIT( RI ); /* clear rcvd data flag */
c = SBUF; /* get character */
if ( !rfull ) { /* is there a msg in buffer? */
if ( rbin < MSGLEN ) { /* is there room? */
rbuf[rbin] = c;
if ( isend( rbuf[rbin] ) ){
rbuf[rbin] = NUL; /* overwrite termination */
if ( rbin ) {
rfull = TRUE;
}
}
else
rbin++;
}
else {
//CodeMessage(ormsg);
Reset_msg(); /* buffer overrun */
return;
//CodeMessage(ormsg);
}
}
}
if ( TI ) {
CLR_BIT( TI ); // clear transmit Interrupt flag if there's more data to send, send it.
if ( so && *so ) {
SBUF = *so++;
}
else {
tdone = TRUE;
so = NUL;
}
}
}
//****************************************************************************
// CodeMessage: Copies CODE space data to ram buffer for transmission by SBUF
//****************************************************************************
void CodeMessage (BYTE code *msg)
{
tbin = 0;
while (*msg != 0){
tbuf[tbin++] = *msg++;
}
tbuf[tbin] = NUL;
if (tdone){
so = tbuf;
SendSerialData(so++);
WaitforSo();
//Reset_msg();
}
}
//****************************************************************************
// DataMessage: Copies DATA space data to ram buffer for transmission by SBUF
//****************************************************************************
void DataMessage (BYTE idata *msg)
{
tbin = 0;
while (*msg != 0){
tbuf[tbin++] = *msg++;
}
tbuf[tbin] = NUL;
if (tdone){
so = tbuf;
SendSerialData(so++);
WaitforSo();
//Reset_msg();
}
}
//****************************************************************************
// SendSerialData
//****************************************************************************
void SendSerialData (BYTE idata *msg){
if (tdone == TRUE) {
tdone = FALSE;
SBUF = *msg;
}
}
//****************************************************************************
// WaitforSo (Wait for serial output to complete)
//****************************************************************************
void WaitforSo(void) {
BYTE i;
while ( tdone != TRUE ) {
for (i=0; i<128;i++);
}
}
//****************************************************************************
// Clear The Receive Buffer
//****************************************************************************
void Reset_msg(void){
*rbuf = NUL;
rbin = NUL; /* no data */
rfull = FALSE; /* no message pending */
}
//****************************************************************************
// Send Start Condition
//****************************************************************************
void I2Start(void){
SDA = 1;
SCL = 1;
SDA = 0;
//waste_time();
SCL = 0;
}
//****************************************************************************
// Send Stop Condition
//****************************************************************************
void I2Stop(void){
SDA = 0;
SCL = 1;
//waste_time();
SDA = 1;
}
//****************************************************************************
// Clock in one BIT of data
//****************************************************************************
bit I2Clock(void){
bit sda_value;
//waste_time();
SCL = 1;
sda_value = SDA;
//waste_time();
SCL = 0;
//waste_time();
return(sda_value);
}
//****************************************************************************
// Send Acknowledge Condition
//****************************************************************************
void I2Ack(void){
SDA = 0;
I2Clock();
SDA = 1;
}
//****************************************************************************
// Send Not-Acknowledge Condition. Sets the SDA high so the receiver can pull
// it low. Added return value to allow ACK poll during EEPOT NV Write
//****************************************************************************
bit I2Nack(void){
bit retval;
SDA = 1;
retval = I2Clock();
return retval;
}
//****************************************************************************
// Clock OUT one BYTE of data
//****************************************************************************
void I2SendByte(BYTE b){
BYTE count;
for (count = 0; count <= 7; count ++) {
if ((b & 0x80) == 0 )
SDA = 0;
else
SDA = 1;
b = b << 1;
I2Clock();
}
}
//****************************************************************************
// Clock IN one BYTE of data
//****************************************************************************
BYTE I2GetByte(void){
BYTE count, d;
for (count = 0; count <= 7; count++) {
SDA = 1;
d = d << 1;
d |= (BYTE) I2Clock();
}
return (d);
}
/******************************************************
** Procedure: tohex ( BYTE, BYTE * )
**
** Description:
** -----------
** Converts the byte into a two digit ASCII hex string
** in buffer 'p'.
**
******************************************************/
void tohex( BYTE b, BYTE idata *p )
{
/* first digit */
p[0] = b >> 4;
if ( p[0] < 10 )
p[0] += 0x30; /* 0 - 9 */
else
p[0] = (p[0] - 9) | 0x40; /* A - F */
/* second digit */
p[1] = b & 0x0F;
if( p[1] < 10 )
p[1] += 0x30; /* 0 - 9 */
else
p[1] = (p[1] - 9) | 0x40; /* A - F */
p[2] = NUL; /* terminate string */
}
/******************************************************
** Procedure: Ahtob ( BYTE * )
**
** Description:
** -----------
** Converts a two digit ASCII Hex string in buffer 'p'
** to a byte, and returns that byte.
**
******************************************************/
BYTE Ahtob( BYTE idata *p )
{
BYTE data b;
/* Most Significant digit */
if ( p[0] > 64 )
b = p[0] - 55; /* Convert A - F to binary */
else
b = p[0] - 0x30; /* Convert 0 - 9 to binary */
b <<= 4;
/* Least Significant digit */
if ( p[1] > 64 )
b |= p[1] - 55; /* Convert A - F to binary */
else
b |= p[1] - 0x30; /* Convert 0 - 9 to binary */
return(b);
}
/******************************************************
** Procedure: void scpy( BYTE *, BYTE * )
**
** Description:
** -----------
** Copies string s2 to location s1, up to and including
** the NUL character.
**
******************************************************/
void scpy( BYTE idata *s1, BYTE idata *s2, BYTE L )
{
BYTE i;
if (L == 0){
do {
*s1++ = *s2;
}
while ( *s2++ );
}
else {
for (i = 0; i<L; i++){
*s1++ = *s2++;
}
*s1 = NUL;
}
}
/******************************************************
** Procedure: void slen( BYTE * )
**
** Description:
** -----------
** Counts the number of bytes in string 's', minus
** the NUL.
** Stops at the first NUL character.
**
******************************************************/
BYTE slen( BYTE idata *s )
{
BYTE data c = 0;
while ( s[c] ) {
c++;
}
return( c );
}
/******************************************************
** Procedure: ishex ( BYTE )
**
** Description:
** -----------
** Returns TRUE if 'c' is an ASCII hex character:
** 0 - 9, A - F, or a - f.
**
*****************************************************/
bit ishex( BYTE c )
{
if ( isnum(c) )
return( TRUE ); /* 0 - 9 */
if ( (c > 0x40) && (c < 0x47) ) /* A - F */
return( TRUE );
if ( (c > 0x60) && (c < 0x67) ) /* a - f */
return( TRUE );
return( FALSE );
}
/******************************************************
** Procedure: Strpos ( BYTE, BYTE * )
**
** Description:
** -----------
** Search string 'p' for the first occurance of 'b'.
** Returns the index of 'b' in the string, or -1 if
** not found.
**
******************************************************/
BYTE Strpos( BYTE b, BYTE idata *p )
{
BYTE i = 0;
while ( p[i] != b ) {
if ( isend( p[i] ) )
return( -1 );
i++;
}
return( i );
}
//****************************************************************************
// Compares two strings returns a 0 for match and 1 for no match.
//****************************************************************************
bit scomp(BYTE idata *p1, BYTE code *p2){
while( *p1 == *p2){
if (*p1 == NUL) return 0;
p1++, p2++;
}
return 1;
}
/******************************************************
** Procedure: void btoa( BYTE, BYTE * )
**
** Description:
** -----------
** Converts byte 'n' to an ASCII string in location 's'.
** This only works for unsigned numbers 0 - 255.
**
******************************************************/
void btoa( BYTE n, BYTE idata *s )
{
BYTE data i = 0;
do { /* generate digits in reverse order */
s[i++] = n % 10 + 0x30;
}
while( (n /= 10) > 0 );
s[i] = NUL;
/* reverse the digit order */
Reverse( s );
}
/******************************************************
** Procedure: void Reverse( BYTE data * )
**
** Description:
** -----------
** Reversed the order of the characters in string 's'.
**
******************************************************/
void Reverse( BYTE idata *s )
{
BYTE data c, i, j;
j = slen( s ) - 1;
for (i = 0 ; i < j; i++, j--) {
c = s[i];
s[i] = s[j];
s[j] = c;
}
}
//****************************************************************************
// Reads and returns the value of the selected register in the addressed LM75
//****************************************************************************
int ReadLM75(void){
I2Address << 1;
I2Address &= 0xFE;
I2Address |= 0x90;
I2Start();
I2SendByte(I2Address);
I2Ack();
I2SendByte(I2Command);
I2Ack();
I2Start();
I2Address |= 0x01;
I2SendByte(I2Address);
I2Ack();
MSByte = I2GetByte();
I2Nack();
if (I2Command != 1){
LSByte = I2GetByte();
I2Nack();
}
else{
LSByte = MSByte;
MSByte = 0;
}
I2Stop();
binval = MSByte;
binval = binval << 8;
binval = binval + LSByte;
binval = binval >> 7;
MSByte = binval >> 8;
LSByte = binval & 0xFF;
if (MSByte & 1){
CodeMessage(negs);
LSByte = ~LSByte;
LSByte++;
}
MSByte = LSByte; // Save the LSB
LSByte /= 2;
btoa(LSByte, temp);
DataMessage(temp);
if (MSByte & 1){
CodeMessage(half);
}
CodeMessage(crlf);
return binval;
}
//****************************************************************************
// Converts characters to upper case
//****************************************************************************
void toup(BYTE idata *r)
{
BYTE i;
for (i=0; i<2; i++){
r[i] = r[i] & 0x5F;
//DataMessage(r);
}
|