C语言模拟C++方式读取串口操作实现

来源:互联网 发布:淘宝店开不下去了 编辑:程序博客网 时间:2024/05/22 15:43

在使用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 1void 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 interruptint 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;}



1 0