调整串口默认波特率为115200,主频>=36M时1024000,主频>=72M时2048000。

同时缩小默认收发缓冲区大小,并在用到时才分配。
提升速度,降低缓冲区要求,减少内存占用。
This commit is contained in:
大石头X2 2017-03-02 17:01:50 +08:00
parent cf0a6fe21b
commit 2a06ec612e
3 changed files with 98 additions and 87 deletions

View File

@ -28,66 +28,79 @@ SerialPort::~SerialPort()
void SerialPort::Init()
{
Index = COM_NONE;
RS485 = nullptr;
Error = 0;
State = nullptr;
Index = COM_NONE;
RS485 = nullptr;
Error = 0;
State = nullptr;
Remap = 0;
MinSize = 1;
Remap = 0;
MinSize = 1;
Pins[0] = Pins[1] = P0;
Ports[0] = Ports[1] = nullptr;
Pins[0] = Pins[1] = P0;
Ports[0] = Ports[1] = nullptr;
_dataBits = 8;
_parity = 0;
_stopBits = 1;
_dataBits = 8;
_parity = 0;
_stopBits = 1;
_taskidRx = 0;
_taskidRx = 0;
OnInit();
}
void SerialPort::Set(COM index, int baudRate)
{
Index = index;
_baudRate = baudRate;
Index = index;
_baudRate = baudRate;
// 根据系统时钟自动计算默认波特率
if (_baudRate <= 0)
{
int clock = Sys.Clock;
if (clock >= 72)
_baudRate = 2048000;
else if (clock >= 36)
_baudRate = 1024000;
else
_baudRate = 1152000;
}
// 计算字节间隔。字节速度一般是波特率转为字节后再除以2
//ByteTime = 15000000 / baudRate; // (1000000 /(baudRate/10)) * 1.5
//ByteTime = 1000000 / (baudRate >> 3 >> 1);
//ByteTime <<= 1;
if(baudRate > 9600)
ByteTime = 1;
if (baudRate > 9600)
ByteTime = 1;
else
ByteTime = 1000 / (baudRate / 10) + 1; // 小数部分忽略,直接加一
ByteTime = 1000 / (baudRate / 10) + 1; // 小数部分忽略,直接加一
// 设置名称
Buffer(Name, 4) = "COMx";
Buffer(Name, 4) = "COMx";
Name[3] = '0' + Index + 1;
Name[4] = 0;
// 根据端口实际情况决定打开状态
if(OnSet()) Opened = true;
if (OnSet()) Opened = true;
}
void SerialPort::Set(byte dataBits, byte parity, byte stopBits)
{
_dataBits = dataBits;
_parity = parity;
_stopBits = stopBits;
_dataBits = dataBits;
_parity = parity;
_stopBits = stopBits;
}
// 打开串口
bool SerialPort::OnOpen()
{
// 需要是才申请缓冲区
//if (Tx.Capacity() == 0) Tx.SetCapacity(64);
if (Rx.Capacity() == 0 && HasHandler()) Rx.SetCapacity(64);
// 清空缓冲区
if(Tx.Capacity() == 0) Tx.SetCapacity(256);
if(Rx.Capacity() == 0) Rx.SetCapacity(256);
Tx.Clear();
Rx.Clear();
debug_printf("Serial%d::Open(%d, %d, %d, %d) TX=P%c%d RX=P%c%d Cache(TX=%d, RX=%d)\r\n", Index + 1, _baudRate, _dataBits, _parity, _stopBits, _PIN_NAME(Pins[0]), _PIN_NAME(Pins[1]), Tx.Capacity(), Rx.Capacity());
debug_printf("Serial%d::Open(%d, %d, %d, %d) TX=P%c%d RX=P%c%d Cache(TX=%d, RX=%d)\r\n", Index + 1, _baudRate, _dataBits, _parity, _stopBits, _PIN_NAME(Pins[0]), _PIN_NAME(Pins[1]), Tx.Capacity(), Rx.Capacity());
OnOpen2();
@ -99,7 +112,7 @@ bool SerialPort::OnOpen()
// 关闭端口
void SerialPort::OnClose()
{
debug_printf("~Serial%d Close\r\n", Index + 1);
debug_printf("~Serial%d Close\r\n", Index + 1);
OnClose2();
}
@ -107,26 +120,33 @@ void SerialPort::OnClose()
// 向某个端口写入数据。如果size为0则把data当作字符串一直发送直到遇到\0为止
bool SerialPort::OnWrite(const Buffer& bs)
{
if(!Opened || !bs.Length()) return true;
/*#if defined(STM32F0) || defined(GD32F150)
Set485(true);
// 中断发送过于频繁,影响了接收中断,采用循环阻塞发送。后面考虑独立发送任务
for(int i=0; i<bs.Length(); i++)
{
SendData(bs[i], 3000);
}
Set485(false);
#else*/
if (!Opened || !bs.Length()) return true;
/*#if defined(STM32F0) || defined(GD32F150)
Set485(true);
// 中断发送过于频繁,影响了接收中断,采用循环阻塞发送。后面考虑独立发送任务
for(int i=0; i<bs.Length(); i++)
{
SendData(bs[i], 3000);
}
Set485(false);
#else*/
// 如果队列已满,则强制刷出
//if(Tx.Length() + bs.Length() > Tx.Capacity()) Flush(Sys.Clock / 40000);
// 用到时才初始化缓冲区
if (Tx.Capacity() == 0)
{
int size = 64;
while (size < bs.Length() && size < 1024) size <<= 1;
Tx.SetCapacity(size);
}
Tx.Write(bs);
// 打开串口发送
Set485(true);
//USART_ITConfig((USART_TypeDef*)State, USART_IT_TXE, ENABLE);
OnWrite2();
//#endif
//#endif
return true;
}
@ -137,7 +157,7 @@ bool SerialPort::Flush(int times)
// 打开串口发送
Set485(true);
while(!Tx.Empty() && times > 0) times = SendData(Tx.Dequeue(), times);
while (!Tx.Empty() && times > 0) times = SendData(Tx.Dequeue(), times);
Set485(false);
@ -150,7 +170,7 @@ uint SerialPort::OnRead(Buffer& bs)
int count = 0;
int len = Rx.Length();
// 如果没有数据,立刻返回,不要等待浪费时间
if(!len)
if (!len)
{
bs.SetLength(0);
@ -158,7 +178,7 @@ uint SerialPort::OnRead(Buffer& bs)
}
// 如果有数据变化,等一会
while(len != count && len < bs.Length())
while (len != count && len < bs.Length())
{
count = len;
// 按照115200波特率计算传输7200字节每秒每个毫秒7个字节大概150微秒差不多可以接收一个新字节
@ -167,7 +187,7 @@ uint SerialPort::OnRead(Buffer& bs)
len = Rx.Length();
}
// 如果数据大小不足,等下次吧
if(len < MinSize)
if (len < MinSize)
{
bs.SetLength(0);
@ -179,68 +199,68 @@ uint SerialPort::OnRead(Buffer& bs)
bs.SetLength(count);
// 如果还有数据,打开任务
if(!Rx.Empty()) Sys.SetTask(_taskidRx, true, 0);
if (!Rx.Empty()) Sys.SetTask(_taskidRx, true, 0);
return count;
}
void SerialPort::ReceiveTask()
{
auto sp = this;
auto sp = this;
//!!! 只要注释这一行,四位触摸开关就不会有串口溢出错误
if(sp->Rx.Length() == 0) return;
if (sp->Rx.Length() == 0) return;
// 从栈分配,节省内存
byte buf[0x200];
Buffer bs(buf, ArrayLength(buf));
int mx = sp->MaxSize;
if(mx > 0 && mx > bs.Length()) bs.SetLength(mx);
int mx = sp->MaxSize;
if (mx > 0 && mx > bs.Length()) bs.SetLength(mx);
uint len = sp->Read(bs);
if(len)
if (len)
{
len = sp->OnReceive(bs, nullptr);
// 如果有数据,则反馈回去
if(len) sp->Write(bs);
if (len) sp->Write(bs);
}
}
void SerialPort::SetBaudRate(int baudRate)
{
Set((COM)Index, baudRate);
Set((COM)Index, baudRate);
}
void SerialPort::ChangePower(int level)
{
// 串口进入低功耗时,直接关闭
if(level) Close();
if (level) Close();
}
void SerialPort::Register(TransportHandler handler, void* param)
{
ITransport::Register(handler, param);
if(handler)
if (handler)
{
// 建立一个未启用的任务,用于定时触发接收数据,收到数据时开启
if(!_taskidRx)
if (!_taskidRx)
{
//_taskidRx = Sys.AddTask([](void* p){ ((SerialPort*)p)->ReceiveTask(); }, this, -1, -1, "串口接收");
_taskidRx = Sys.AddTask(&SerialPort::ReceiveTask, this, -1, -1, "串口接收");
auto tsk = Task::Get(_taskidRx);
// 串口任务深度设为2允许重入解决接收任务内部调用发送然后又等待接收匹配的问题
//tsk->MaxDeepth = 2;
_task = tsk;
_task = tsk;
}
/*#if defined(STM32F0) || defined(GD32F150)
// 打开中断
byte irq = uart_irqs[Index];
Interrupt.SetPriority(irq, 0);
Interrupt.Activate(irq, OnHandler, this);
#endif*/
/*#if defined(STM32F0) || defined(GD32F150)
// 打开中断
byte irq = uart_irqs[Index];
Interrupt.SetPriority(irq, 0);
Interrupt.Activate(irq, OnHandler, this);
#endif*/
}
else
else
{
Sys.RemoveTask(_taskidRx);
}
@ -248,45 +268,45 @@ void SerialPort::Register(TransportHandler handler, void* param)
extern "C"
{
static SerialPort* _printf_sp;
static SerialPort* _printf_sp;
static bool isInFPutc;
}
SerialPort* SerialPort::GetMessagePort()
{
auto sp = _printf_sp;
auto sp = _printf_sp;
// 支持中途改变调试口
if(sp && Sys.MessagePort != sp->Index)
if (sp && Sys.MessagePort != sp->Index)
{
delete sp;
_printf_sp = nullptr;
_printf_sp = nullptr;
}
if(!sp)
if (!sp)
{
auto idx = (COM)Sys.MessagePort;
if(idx == COM_NONE) return nullptr;
auto idx = (COM)Sys.MessagePort;
if (idx == COM_NONE) return nullptr;
if(isInFPutc) return nullptr;
isInFPutc = true;
if (isInFPutc) return nullptr;
isInFPutc = true;
// 打开日志输出口,需要较大发送缓冲区
sp = _printf_sp = new SerialPort(idx);
sp->Tx.SetCapacity(512);
sp->Tx.SetCapacity(256);
sp->Open();
isInFPutc = false;
isInFPutc = false;
}
return sp;
}
void SerialPort::Set485(bool flag)
{
if(RS485)
if (RS485)
{
if(!flag) Sys.Sleep(1);
*RS485 = flag;
if(flag) Sys.Sleep(1);
if (!flag) Sys.Sleep(1);
*RS485 = flag;
if (flag) Sys.Sleep(1);
/*if(flag)
debug_printf("485 高\r\n");
else

View File

@ -6,8 +6,6 @@
#include "Power.h"
#include "Net\ITransport.h"
#define SERIAL_BAUDRATE 1024000
// 串口类
class SerialPort : public ITransport, public Power
{
@ -37,19 +35,19 @@ public:
Queue Rx;
SerialPort();
SerialPort(COM index, int baudRate = SERIAL_BAUDRATE);
SerialPort(COM index, int baudRate = 0);
// 析构时自动关闭
virtual ~SerialPort();
void Set(COM index, int baudRate = SERIAL_BAUDRATE);
void Set(COM index, int baudRate = 0);
void Set(byte dataBits, byte parity, byte stopBits);
int SendData(byte data, int times = 3000);
bool Flush(int times = 3000);
void SetBaudRate(int baudRate = SERIAL_BAUDRATE);
void SetBaudRate(int baudRate = 0);
virtual void Register(TransportHandler handler, void* param = nullptr);

View File

@ -38,17 +38,10 @@ public:
bool Write(const Buffer& bs, const void* opt);
// 接收数据
uint Read(Buffer& bs);
//Buffer Read();
// 注册回调函数
virtual void Register(TransportHandler handler, void* param = nullptr);
#if DEBUG
//virtual const String ToString() const { return String("ITransport"); }
#else
//virtual const String ToString() const { return String(""); }
#endif
protected:
virtual bool OnOpen() { return true; }
virtual void OnClose() { }