⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 main.c

📁 keil c51 UART --IC 源程序
💻 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 + -