在使用C++编程对串口操作时,经常有用到serialport.read(),serialport.print()之类的函数,而且系统自带接收buf,不用考虑数据漏失的问题,那么在C语言环境下,怎么做呢?特别是51或STM32编程,或者要将C++代码转换成C代码时对这一块也不好移植,下面提供一个API,方便大家使用。
首先看接口文件,也就是头文件:
serialpoortAPI.h
#ifndef __SERIALPORT_H__
#define __SERIALPORT_H__
#define _SS_MAX_RX_BUFF 96
#define INT_TYPE 0
#define STRING_TYPE 1
void UartBegin(unsigned int bps,void (*uart_init)(unsigned int),void (*uart_send)(unsigned char));
void SerialPrint(void const *send_data,int type);
void SerialPrintln(void const *send_data,int type);
void SerialWrite(char send_data);
int SerialRead(void);
int SerialAvailable(void);
int SerialInt(unsigned char rec_data);
void ClearRxBuf(void);
#endif
头文件里提供了对串口的基本操作,在设置好之后,直接调用就好了。注意_SS_MAX_RX_BUFF设置的是接收缓存的buf,如果一帧数据量比较大,建议设置大一点。
然后就是实现文件了,serialpoortAPI.c
变量定义:
//serialportAPI
#include<stdio.h>
#include <stdlib.h>
#include "serialportAPI.h"
static char _receive_buffer[_SS_MAX_RX_BUFF];
static volatile unsigned char _receive_buffer_tail = 0;
static volatile unsigned char _receive_buffer_head = 0;
unsigned char _buffer_overflow = 0;//溢出标志位
static void (*UartInit)(unsigned int);
static void (*UartSend)(unsigned char);
这里定义了一个数据接收缓存buf,还有_receive_buffer_tail和_receive_buffer_head,分别对应_receive_buffer的可用数据的终点和起点,如果起点和终点发生了相逢,就发生了溢出,设置标志位_buffer_overflow。
注意这里有两个函数指针,分别为数据初始化UartInit 和数据发送UartSend , 这两个函数需要在外面使用到,在函数初始化时需要对这两个函数指针赋值:
void UartBegin(unsigned int bps,void (*uart_init)(unsigned int),void (*uart_send)(unsigned char))
{
UartInit = uart_init;
UartSend = uart_send;
UartInit(bps);
}
下面实现函数的发送部分功能,实现方法比较简单:
//发送
//调用的时候如果是整数,传入的必须是int型,并加上&符
void SerialPrint(void const *send_data,int type)
{
if(type == STRING_TYPE)
{
char *data_temp = (char *)send_data;//强制类型转换
while(*data_temp != '\0')
{
UartSend(*data_temp++);
}
}
else if(type == INT_TYPE)
{
char str[7];
char *index = str;
int data_temp = (int)(*(int *)send_data);
sprintf(index, "%d" , data_temp);
while(*index != '\0')
{
UartSend(*index++);
}
}
}
//带换行的发送
//调用的时候如果是整数,传入的必须是int型,并加上&符
void SerialPrintln(void const *send_data,int type)
{
SerialPrint(send_data,type);
UartSend('\r');
UartSend('\n');
}
void SerialWrite(char send_data)
{
UartSend(send_data);
}
int SerialRead(void)
{
unsigned char d;
// Empty buffer?
if (_receive_buffer_head == _receive_buffer_tail)
return -1;
// Read from "head"
d = _receive_buffer[_receive_buffer_head]; // grab next byte
_receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF;
return (int)d;
}
然后是接收部分,这里需要将下面的函数放在外面串口中断中运行:
//call by UART interrupt
int SerialInt(unsigned char rec_data)
{
// if buffer full, set the overflow flag and return
if ((_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF != _receive_buffer_head)
{
// save new data in buffer: tail points to where byte goes
_receive_buffer[_receive_buffer_tail] = rec_data; // save new byte
_receive_buffer_tail = (_receive_buffer_tail + 1) % _SS_MAX_RX_BUFF;
}
else
{
_buffer_overflow = 1;
}
return 1;
}
然后就是几个常用的接收函数:
int SerialRead(void)
{
unsigned char d;
// Empty buffer?
if (_receive_buffer_head == _receive_buffer_tail)
return -1;
// Read from "head"
d = _receive_buffer[_receive_buffer_head]; // grab next byte
_receive_buffer_head = (_receive_buffer_head + 1) % _SS_MAX_RX_BUFF;
return (int)d;
}
int SerialAvailable(void)
{
return (_receive_buffer_tail + _SS_MAX_RX_BUFF - _receive_buffer_head) % _SS_MAX_RX_BUFF;
}
在使用时一般是先使用SerialAvailable()判断有没有数据,然后用SerialRead()读取,可以看到,很多操作是基于_receive_buffer_tail和_receive_buffer_head这两个值的。
最后就是清除接收缓存的操作,也很简单,只要设置_receive_buffer_tail和_receive_buffer_head这两个值就好了
void ClearRxBuf(void)
{
_receive_buffer_tail = 0;
_receive_buffer_head = 0;
_buffer_overflow = 0;
}