📄 main.c
字号:
/* main.c */
#include <STC12C2052AD.H>
#include "bltypes.h"
#include "uart.h"
//#include <stdio.h>
sbit I2C_SCL = P3^2;
sbit I2C_SDA = P3^3;
sbit I2C_INT = P3^4;
#define I2C_ADDR (0x60)
#define PACKET_START (0xFF)
#define MIN_PACKET_SIZE (3)
#define MAX_PACKET_SIZE (32)
#define UART_BUFFER_SIZE (64)
#define I2C_BUFFER_SIZE (16)
ubyte idata s_buf[UART_BUFFER_SIZE];
ubyte s_buf_pos = 0;
ubyte s_buf_cnt = 0;
ubyte s_buf_wr_pos = 0;
ubyte s_buf_wr_cnt = 0;
ubyte num_packets = 0;
ubyte idata i2c_buf[I2C_BUFFER_SIZE];
ubyte i2c_buf_pos = 0;
ubyte i2c_buf_cnt = 0;
bool i2c_start = false;
bool i2c_terminated = true;
static void ProcessSerialEvent(ubyte c);
static void ProcessTimerEvent(ubyte timer_id);
static void ProcessSerialEvent(ubyte c)
{
if(s_buf_cnt + s_buf_wr_cnt < UART_BUFFER_SIZE)
{
//s_buf[(s_buf_pos + s_buf_cnt) % MAX_PACKET_SIZE] = c;
//s_buf_cnt++;
if(s_buf_wr_cnt == 0)
{
if(c == PACKET_START)
{
s_buf[(s_buf_wr_pos + s_buf_wr_cnt) % UART_BUFFER_SIZE] = c;
s_buf_wr_cnt++;
}
}
else if(s_buf_wr_cnt == 1)
{
if(c >= MIN_PACKET_SIZE && c <= MAX_PACKET_SIZE)
{
s_buf[(s_buf_wr_pos + s_buf_wr_cnt) % UART_BUFFER_SIZE] = c;
s_buf_wr_cnt++;
}
else
{
s_buf_wr_cnt = 0;
}
}
else
{
s_buf[(s_buf_wr_pos + s_buf_wr_cnt) % UART_BUFFER_SIZE] = c;
s_buf_wr_cnt++;
if(s_buf_wr_cnt > s_buf[(s_buf_wr_pos + 1) % UART_BUFFER_SIZE])
{
s_buf_cnt+= s_buf_wr_cnt;
s_buf_wr_pos = (s_buf_wr_pos + s_buf_wr_cnt) % UART_BUFFER_SIZE;
s_buf_wr_cnt = 0;
num_packets++;
I2C_INT = 1;
}
}
}
else
{
s_buf_wr_cnt = 0;
}
}
static void InitI2c(void)
{
//Configure P3 as standard IO port.
P3M0 = 0;
P3M1 = 0;
//Release the I2C bus.
I2C_SCL = 1;
I2C_SDA = 1;
I2C_INT = 0;
//Initialise the local variant
num_packets = 0;
i2c_start = false;
i2c_terminated = true;
//Configure external interrupt 1 which connected to SDA
IT1 = 1; //Trigger type: edge trigger.
EX1 = 1; //Enable external interrupt 1
PX1 = 0; //High prior
}
static void I2cInterruptRoutine(void) interrupt 2 using 2
{
if(!I2C_SDA && I2C_SCL)
{
i2c_start = true;
i2c_terminated = false;
//Disable interrupt duration the i2c transfer
EX1 = 0; // Disable External interrupt 1
EA = 0; // Disable Interrupt
}
}
static ubyte i2cReceiveByte(uchar *c)
{
ubyte bits_read = 0;
uchar cc = 0;
bool old_scl, old_sda;
bool byte_ok = false;
ubyte shift = 0x80;
// Disable interrupt duration byte transfer
EA = 0;
old_scl = I2C_SCL;
old_sda = I2C_SDA;
//Release the CLOCK line to start/continue transfer
I2C_SCL = 1;
while(1)
{
if(I2C_SCL)
{
if(!old_scl)
{
old_scl = 1;
old_sda = I2C_SDA;
if(shift)
{
if(old_sda)
cc |= shift;
shift >>= 1;
bits_read++;
}
else
{
*c = cc;
}
}
else
{
if(I2C_SDA != old_sda)
{
/*
A HIGH to LOW transition on the SDA line while SCL is
HIGH is one such unique case. This situation indicates a
START condition.
A LOW to HIGH transition on the SDA line while SCL is
HIGH defines a STOP condition.
*/
if(old_sda) //HIGH to LOW: Repeated START condition
{
// Repeated START condition detected.
i2c_start = true;
}
i2c_terminated = true;
break;
}
}
}
else
{
if(old_scl)
{
if(byte_ok) //If byte transfer can be complete
{
//Release SDA, which are sending Acknowledge
I2C_SDA = 1;
//Hold the CLOCK line low to interrupts serviced
I2C_SCL = 0;
//Byte transfer complete
break;
}
if(shift)
{
//Release SDA
I2C_SDA = 1;
}
else
{
// Is first byte - Address byte?
if(i2c_start)
{
if((cc >> 1) == I2C_ADDR) //Match Slave Address?
{
// Send Acknowledge
I2C_SDA = 0;
bits_read++;
}
else
{
i2c_terminated = true;
}
// Address byte has received.
i2c_start = false;
}
else
{
// Send Acknowledge
I2C_SDA = 0;
bits_read++;
}
// Set byte completed flag, and wait for a Acknowledge cycle.
byte_ok = true;
}
old_scl = 0;
}
}
}
//Enable interrupt after a byte is complete.
EA = 1;
return bits_read;
}
static ubyte i2cSendByte(ubyte c)
{
bool old_scl;
bool byte_ok = false;
ubyte shift = 0x80;
ubyte bits_wrote = 0;
old_scl = I2C_SCL;
//Prepare the first data bit.
if(c & shift)
I2C_SDA = 1;
else
I2C_SDA = 0;
shift >>= 1;
// Disable interrupt where sending byte.
EA = 0;
//Release the CLOCK line to start/continue transfer
I2C_SCL = 1;
while(1)
{
if(I2C_SCL)
{
if(!old_scl)
{
//Read the Acknowledge bit.
if(byte_ok)
{
if(!I2C_SDA)
bits_wrote++;
}
else
{
bits_wrote++;
}
}
old_scl = 1;
}
else
{
if(old_scl)
{
if(byte_ok)
{
I2C_SCL = 0;
break;
}
if(shift)
{
if(c & shift)
I2C_SDA = 1;
else
I2C_SDA = 0;
shift >>= 1;
}
else
{
//Release SDA
I2C_SDA = 1;
byte_ok = true;
}
old_scl = 0;
}
}
}
// Enable interrupt when byte complete
EA = 1;
return bits_wrote;
}
static void i2cSendStop(void)
{
bool old_scl;
bool old_sda;
// Disable interrupt where sending stop.
EA = 0;
I2C_SCL = 1;
old_scl = I2C_SCL;
while(1)
{
if(I2C_SCL)
{
if(!old_scl)
{
I2C_SCL = 0;
I2C_SCL = 0;
I2C_SCL = 0;
I2C_SCL = 0;
I2C_SCL = 1;
old_scl = 1;
}
else
{
if(old_sda != I2C_SDA)
{
if(old_sda) //HIGH to LOW: Repeated START condition
{
i2c_start = true;
i2c_terminated = true;
}
else //LOW to HIGH: STOP condition
{
i2c_start = false;
i2c_terminated = true;
}
break;
}
}
old_sda = I2C_SDA;
break;
}
else
{
old_scl = 0;
}
}
// Enable interrupt when transfer complete.
EA = 1;
}
static void QueueI2cChar(uchar c)
{
// Force a character to be sent immediately.
while(i2c_buf_cnt + 1 >= I2C_BUFFER_SIZE)
{
if(UartPutChar(i2c_buf[i2c_buf_pos]))
{
i2c_buf_pos = (i2c_buf_pos + 1) % I2C_BUFFER_SIZE;
i2c_buf_cnt--;
}
}
// Queue the character to the i2c buffer
i2c_buf[(i2c_buf_pos + i2c_buf_cnt) % I2C_BUFFER_SIZE] = c;
i2c_buf_cnt = (i2c_buf_cnt + 1) % I2C_BUFFER_SIZE;
}
static void ProcessI2cTransfer(void)
{
ubyte i2c_addr;
ubyte c;
while(i2c_start)
{
//Receive address byte */
ubyte bits;
i2c_terminated = false;
bits = i2cReceiveByte(&i2c_addr);
if(bits == 9)
{
if(i2c_addr & 0x01) //Read mode
{
ubyte i;
ubyte bytes_wrote = 0;
if(num_packets)
{
ubyte pkt_size = s_buf[(s_buf_pos + 1) % UART_BUFFER_SIZE] + 1;
for(i = 1; i < pkt_size; i++)
{
ubyte bits = i2cSendByte(s_buf[(s_buf_pos + i) % UART_BUFFER_SIZE]);
if(bits >= 8)
bytes_wrote++;
if(bits <= 8)
break;
}
if(bytes_wrote == pkt_size - 1)
{
s_buf_pos = (s_buf_pos + pkt_size) % UART_BUFFER_SIZE;
s_buf_cnt -= pkt_size;
if((--num_packets) == 0)
I2C_INT = 0;
}
}
else
{
i2cSendByte(0);
}
if(!i2c_terminated)
i2cSendStop();
}
else //write mode
{
QueueI2cChar(PACKET_START);
while(1)
{
ubyte bits_read = i2cReceiveByte(&c);
if(bits_read == 9)
{
QueueI2cChar(c);
}
if(i2c_terminated)
{
break;
}
}
}
}
}
//Release the SCL line to enable I2C transfer
I2C_SCL = 1;
EX1 = 1;
//end i2c transfer
EA = 1; //Enable interrupt
}
void main(void)
{
InitUart();
InitI2c();
EA = 1;
while(1)
{
uchar c;
if(i2c_start)
{
ProcessI2cTransfer();
}
else if(UartGetChar(&c) > 0)
{
ProcessSerialEvent(c);
}
else if(i2c_buf_cnt > 0)
{
if(UartPutChar(i2c_buf[i2c_buf_pos]))
{
i2c_buf_pos = (i2c_buf_pos + 1) % I2C_BUFFER_SIZE;
i2c_buf_cnt--;
}
}
else
{
//Enter idle mode to save power.
PCON |= 1;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -