SmartOS/SerialPort.cpp

285 lines
6.2 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Sys.h"
#include <stdio.h>
#include "Port.h"
#include "SerialPort.h"
// 默认波特率
#define USART_DEFAULT_BAUDRATE 115200
static USART_TypeDef* g_Uart_Ports[] = UARTS;
static const Pin g_Uart_Pins[] = UART_PINS;
static const Pin g_Uart_Pins_Map[] = UART_PINS_FULLREMAP;
static int SERIALPORT_IRQns[] = {
USART1_IRQn, USART2_IRQn,
#ifdef STM32F10X
USART3_IRQn, UART4_IRQn, UART5_IRQn
#endif
};
SerialPort::SerialPort(int com, int baudRate, int parity, int dataBits, int stopBits)
{
_com = com;
_baudRate = baudRate;
_parity = parity;
_dataBits = dataBits;
_stopBits = stopBits;
_port = g_Uart_Ports[com];
}
// 析构时自动关闭
SerialPort::~SerialPort()
{
Close();
if(RS485) delete RS485;
RS485 = NULL;
}
// 打开串口
void SerialPort::Open()
{
if(Opened) return;
USART_InitTypeDef p;
Pin rx;
Pin tx;
GetPins(&tx, &rx);
USART_DeInit(_port);
// 检查重映射
#ifdef STM32F1XX
if(IsRemap)
{
switch (_com) {
case 0: AFIO->MAPR |= AFIO_MAPR_USART1_REMAP; break;
case 1: AFIO->MAPR |= AFIO_MAPR_USART2_REMAP; break;
case 2: AFIO->MAPR |= AFIO_MAPR_USART3_REMAP_FULLREMAP; break;
}
}
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE );
#endif
// 打开 UART 时钟。必须先打开串口时钟,才配置引脚
#ifdef STM32F0XX
switch(_com)
{
case COM1: RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); break;//开启时钟
case COM2: RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); break;
default: break;
}
#else
if (_com) { // COM2-5 on APB1
RCC->APB1ENR |= RCC_APB1ENR_USART2EN >> 1 << _com;
} else { // COM1 on APB2
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
}
#endif
//串口引脚初始化
_tx = new AlternatePort(tx, false, 10);
_rx = new InputPort(rx);
_tx->Restore = true;
_rx->Restore = true;
#ifdef STM32F0XX
GPIO_PinAFConfig(_GROUP(tx), _PIN(tx), GPIO_AF_1);//将IO口映射为USART接口
GPIO_PinAFConfig(_GROUP(rx), _PIN(rx), GPIO_AF_1);
#endif
USART_StructInit(&p);
p.USART_BaudRate = _baudRate;
p.USART_WordLength = _dataBits;
p.USART_StopBits = _stopBits;
p.USART_Parity = _parity;
USART_Init(_port, &p);
USART_ITConfig(_port, USART_IT_RXNE, ENABLE);//串口接收中断配置
Interrupt.SetPriority(SERIALPORT_IRQns[_com], 1);
USART_Cmd(_port, ENABLE);//使能串口
if(RS485) *RS485 = false;
Opened = true;
}
// 关闭端口
void SerialPort::Close()
{
if(!Opened) return;
// 清空接收委托
Register(0);
Pin tx, rx;
GetPins(&tx, &rx);
USART_DeInit(_port);
if(_tx) delete _tx;
if(_rx) delete _rx;
// 检查重映射
#ifdef STM32F1XX
if(IsRemap)
{
switch (_com) {
case 0: AFIO->MAPR &= ~AFIO_MAPR_USART1_REMAP; break;
case 1: AFIO->MAPR &= ~AFIO_MAPR_USART2_REMAP; break;
case 2: AFIO->MAPR &= ~AFIO_MAPR_USART3_REMAP_FULLREMAP; break;
}
}
#endif
Opened = false;
}
// 发送单一字节数据
void TUsart_SendData(USART_TypeDef* port, char* data)
{
while(USART_GetFlagStatus(port, USART_FLAG_TXE) == RESET);//等待发送完毕
USART_SendData(port, (ushort)*data);
}
// 向某个端口写入数据。如果size为0则把data当作字符串一直发送直到遇到\0为止
void SerialPort::Write(const string data, int size)
{
int i;
string byte = data;
Open();
if(RS485) *RS485 = true;
if(size > 0)
{
for(i=0; i<size; i++) TUsart_SendData(_port, byte++);
}
else
{
while(*byte) TUsart_SendData(_port, byte++);
}
if(RS485) *RS485 = false;
}
// 从某个端口读取数据
int SerialPort::Read(string data, uint size)
{
Open();
return 0;
}
// 刷出某个端口中的数据
void SerialPort::Flush()
{
USART_TypeDef* port = g_Uart_Ports[_com];
while(USART_GetFlagStatus(port, USART_FLAG_TXE) == RESET);//等待发送完毕
}
void SerialPort::Register(SerialPortReadHandler handler)
{
if(handler)
{
_Received = handler;
Interrupt.Activate(SERIALPORT_IRQns[_com], OnReceive, this);
}
else
{
_Received = 0;
Interrupt.Deactivate(SERIALPORT_IRQns[_com]);
}
}
// 真正的串口中断函数
void SerialPort::OnReceive(ushort num, void* param)
{
SerialPort* sp = (SerialPort*)param;
if(sp && sp->_Received)
{
if(USART_GetITStatus(sp->_port, USART_IT_RXNE) != RESET)
{
#ifdef STM32F10X
byte data = (byte)sp->_port->DR;
#else
byte data = (byte)sp->_port->RDR;
#endif
sp->_Received(data);
}
}
}
// 获取引脚
void SerialPort::GetPins(Pin* txPin, Pin* rxPin)
{
*rxPin = *txPin = P0;
const Pin* p = g_Uart_Pins;
if(IsRemap) p = g_Uart_Pins_Map;
int n = _com << 2;
*txPin = p[n];
*rxPin = p[n + 1];
}
extern "C"
{
#define CR1_UE_Set ((uint16_t)0x2000) /*!< USART Enable Mask */
SerialPort* _printf_sp;
/* 重载fputc可以让用户程序使用printf函数 */
int fputc(int ch, FILE *f)
{
if(!Sys.Inited) return ch;
int _com = Sys.MessagePort;
if(_com == COM_NONE) return ch;
USART_TypeDef* port = g_Uart_Ports[_com];
// 检查并打开串口
if((port->CR1 & CR1_UE_Set) != CR1_UE_Set && _printf_sp == NULL)
{
if(_printf_sp != NULL) delete _printf_sp;
_printf_sp = new SerialPort(_com);
_printf_sp->Open();
}
TUsart_SendData(port, (char*)&ch);
return ch;
}
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval : None
*/
void assert_failed(uint8_t* file, uint32_t line)
{
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
if(_printf_sp) printf("Assert Failed! Line %d, %s\r\n", line, file);
/* Infinite loop */
while (1) { }
}
#endif