// 定义发送缓冲区大小,可以根据系统RAM的大小的数据量来定义
#define U0TX_BUF_SIZE 1024
// 定义发送缓冲区
char u0tx_buf[U0TX_BUF_SIZE];
// 定义串口发射忙标志,当串口正在发送数据且发送缓冲区不空时为1
char u0tx_busy_bit;
// 缓冲区中数据长度
unsigned int u0tx_length;
// 发送缓冲区数据指针,指向下一个发送的数据
unsigned int u0tx_buf_pointer;
// 准备发送数据
// data是要发送的数据
// length数据的长度
char u0tx_send_packet( char *data, int length )
{
int i;
// u0tx_busy_bit为1时表示串口正在使用,正在使用则退出,
// 避免后续的数据覆盖正在发送的数据
if( u0tx_busy_bit==1 )
{
// 返回0x01表示未能进入串口发送操作
return 0x01;
}
// 把要发送的数据转移到发送缓冲区
for( i=0; i<length; i++ )
u0tx_buf[i] = data[i];
// 数据准备完毕,把u0tx_busy_bit置1,表示正在使用串口
u0tx_busy_bit = 1;
// 设置发送缓冲区中数据的长度
u0tx_length = length;
// 把数据缓冲区的指针指到第一个数据
u0tx_buf_pointer = 0;
// 为了保证程序的可移植性,这里封装了一个串口发送中断触发标志,
// 设置这个标志后,立即进入串口发送中断服务程序
set_u0tx_Int_flag();
// 返回0x00表示成功进行了一次串口发送操作
return 0x00;
}
// 串口发送中断服务程序,逐一把发送缓冲区中的数据发送出去
__interrupt void u0tx_Int_handler( void )
{
// 检查数据是否发送完毕,还有数据则发送另一个字节数据
if( u0tx_buf_pointer < u0tx_length )
{
// 把数据缓冲区指针指向的数据移到发送寄存器
TXBUF0 = u0tx_buf[u0tx_buf_pointer];
// 调整数据缓冲区指针,指向下一个数据
u0tx_buf_pointer++;
}
else
// 数据发送完毕,把u0tx_busy_bit置0
u0tx_busy_bit = 0;
}
在接收端,由于没有使用FIFO功能,同样要在内存中划出一块内存作为接收缓冲区,由接收中断服务程序把数据存入接收缓冲区。这个接收缓冲区是一个先入先出的环形队列,要根据CPU的运行速度和数据流量的大小来设置,太大会浪费内存资源,太小则会出现追尾现象,造成数据丢失。具体代码如下:
#define U0RX_BUF_SIZE 128
// 定义接收缓冲区
char u0rx_buf[U0RX_BUF_SIZE];
// 串口接收缓冲区有数据标志,当接收缓冲区不空时为1
char u0rx_Flag;
// 数据有效标志,因为使用的流通信协议,且包括全范围值,所有要用标志指出数据是否可用
char u0rx_data_valid_flag;
// 接收缓冲区入队列指针,指向下一个存储单元
unsigned int u0rx_in_pointer;
// 接收缓冲区出队列指针,指向下一个存储单元
unsigned int u0rx_out_pointer;
// 串口接收中断服务程序,把接收的数据逐一存入接收缓冲区中
// 在这里使用的是覆盖旧数据模式,可以根据情况加入丢弃新数据的代码
__interrupt void u0rx_Int_handler( void )
{
// 把接收到的数据存入接收缓冲区
u0rx_buf[ u0rx_in_pointer ] = RXBUF0;
// 入队列指针加1,指向下一个存储单元
u0rx_in_pointer ++;
// 如果入队列指针超出了缓冲区尾地址,则指向首地址
if( u0rx_in_pointer>=U0_RX_BUFF_SIZE )
u0rx_in_pointer = 0;
// 标志置1,表示接收缓冲区中有数据
RX0_Flag = 1;
}
// 从串口接收缓冲区中读取一个字节数据
char u0rx_get_data(void)
{
// 临时变量,保存从接收缓冲区中读取的数据
char c;
// 如果出队列指针不等于入队列指针且有效,表示接收缓冲区在有数据,否则为空
if( (u0rx_out_pointer != u0rx_in_pointer) && (u0rx_out_pointer < U0RX_BUFF_SIZE) )
{
// 读取一个字节的数据
c = u0rx_buf[u0rx_out_pointer];
// 出队列指针加1,指向下一个存储单元
u0rx_out_pointer ++;
// 如果出队列指针超出了缓冲区尾地址,则指向首地址
if( u0rx_out_pointer>=U0_RX_BUFF_SIZE )
u0rx_out_pointer = 0;
// 数据有效标志置1
u0rx_data_valid_flag = 1;
// 如果出队列指针等于入队列指针,表示接收缓冲区已空
if( u0rx_out_pointer==u0rx_in_pointer )
u0rx_Flag = 0;
// 返回读取的数据
return c;
}
else
{
// 标志置1,表示接收缓冲区为空
u0rx_Flag = 0;
// 数据有效标志清零
u0rx_data_valid_flag = 0;
// 返回0xff,无意义
return 0xff;
}
}
这部分代码主要是针对无操作系统的单片机软件编写的,但我用的是流通信协议,所以在C#中也经常这样使用。
这是我这几年使用串口的一点心得,如有不当之处欢迎留言。
联系客服