在之前的工程基础上,新建bsp_Usart.c和bsp_Usart.h,用于编写APM32E103VET6的串口测试程序。本测试程序主要测试USART1的查询发送和中断发送,中断接收只是做了简单的回显,通过注释相关代码,打开或关闭回显。其中在中断发送下,波特率到512000bps时,串口调试助手出现接收到的数据不全或者乱码,当然出现这个问题的原因有很多,应该是我程序的问题,也可能是USB转232的问题。在此,我因工作时间的关系未作深究,但是使用查询发送512000bps发送是正常的,原因等有空了再查,代码我会放在文末。目前,我仅测的是板载的232,至于485,只不过是传输介质的不同,但是485相较于232来说,布局布线,接口电路等要求更高,原本可能使用STM32芯片的电路使能正常工作的,但是替换为别的厂家的PIN To PIN芯片就有问题,这其中涉及到不同厂家芯片的兼容性,这是工作中真实遇到的。
1、串口配置代码
void bsp_InitUart( void )
{
UartVarInit();
bsp_Usart_Init();
}
static void UartVarInit( void )
{
#if UART1_FIFO_EN == 1
g_tUart1.uart_periph = USART1; /* 串口设备 */
g_tUart1.pTxBuf = g_TxBuf1; /* 发送缓冲区指针 */
g_tUart1.pRxBuf = g_RxBuf1; /* 接收缓冲区指针 */
g_tUart1.usTxBufSize = UART1_TX_BUF_SIZE; /* 发送缓冲区大小 */
g_tUart1.usRxBufSize = UART1_RX_BUF_SIZE; /* 接收缓冲区大小 */
g_tUart1.usTxWrite = 0; /* 发送FIFO写索引 */
g_tUart1.usTxRead = 0; /* 发送FIFO读索引 */
g_tUart1.usRxWrite = 0; /* 接收FIFO写索引 */
g_tUart1.usRxRead = 0; /* 接收FIFO读索引 */
g_tUart1.usRxCount = 0; /* 接收到的新数据个数 */
g_tUart1.usTxCount = 0; /* 待发送的数据个数 */
g_tUart1.SendBefore = 0; /* 发送数据前的回调函数 */
g_tUart1.SendOver = 0; /* 发送完毕后的回调函数 */
g_tUart1.ReciveNew = 0; /* 接收到新数据后的回调函数 */
g_tUart1.Sending = 0; /* 正在发送中标志 */
#endif
}
static void bsp_Usart_Init( void )
{
GPIO_Config_T s_GPIO_InitStruct;
#if UART1_FIFO_EN
/* ---使能外设时钟------ */
USART1_TX_GPIO_CLK_ENABLE();
USART1_RX_GPIO_CLK_ENABLE();
USART1_CLK_ENABLE();
RCM_EnableAPB2PeriphClock( RCM_APB2_PERIPH_AFIO );
/* ---配置TX引脚------ */
s_GPIO_InitStruct.pin = USART1_TX_PIN;
s_GPIO_InitStruct.mode = GPIO_MODE_AF_PP;
s_GPIO_InitStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config( USART1_TX_GPIO_PORT, &s_GPIO_InitStruct );
/* ---配置RX引脚------ */
s_GPIO_InitStruct.pin = USART1_RX_PIN;
s_GPIO_InitStruct.mode = GPIO_MODE_IN_PU;
s_GPIO_InitStruct.speed = GPIO_SPEED_50MHz;
GPIO_Config( USART1_RX_GPIO_PORT, &s_GPIO_InitStruct );
/* ---配置中断------ */
NVIC_EnableIRQRequest( USART1_IRQn, 2, 0 );
/* ---配置波特率、奇偶校验------ */
bsp_SetUartParameter( USART1, 500000, USART_PARITY_NONE, USART_WORD_LEN_8B, USART_STOP_BIT_1 );
/* ---使能接收中断---- */
USART_EnableInterrupt( USART1, USART_INT_RXBNE );
/* ---清中断标志位---- */
USART_ClearIntFlag( USART1, USART_INT_TXBE );
USART_ClearStatusFlag( USART1, USART_FLAG_TXC );
USART_ClearStatusFlag( USART1, USART_FLAG_RXBNE );
#endif
}
void bsp_SetUartParameter( USART_T* uart, uint32_t baudrate, USART_PARITY_T parity, USART_WORD_LEN_T wordlength, USART_STOP_BIT_T stopbits )
{
USART_Config_T s_UsartInitStruct = { 0 };
s_UsartInitStruct.baudRate = baudrate;
s_UsartInitStruct.hardwareFlow = USART_HARDWARE_FLOW_NONE;
s_UsartInitStruct.mode = USART_MODE_TX_RX;
s_UsartInitStruct.parity = parity;
s_UsartInitStruct.stopBits = stopbits;
s_UsartInitStruct.wordLength = wordlength;
USART_Config( uart, &s_UsartInitStruct );
USART_EnableInterrupt( uart, USART_INT_RXBNE );
USART_Enable( uart );
}
2、中断服务函数,代码借鉴了安富莱的串口代码并作了更改
static void USART1_IRQHandler( void )
{
uint32_t isrflags = USART1->STS;
uint32_t cr1its = USART1->CTRL1;
// uint32_t cr3its = USART1->CTRL3;
/* 处理接收中断 */
if ( ( isrflags & USART_FLAG_RXBNE ) != RESET )
{
/* 从串口接收数据寄存器读取数据存放到接收FIFO */
uint8_t ch;
ch = USART1->DATA_B.DATA;
g_tUart1.pRxBuf[g_tUart1.usRxWrite] = ch;
if ( ++g_tUart1.usRxWrite >= g_tUart1.usRxBufSize )
{
g_tUart1.usRxWrite = 0;
}
if ( g_tUart1.usRxCount < g_tUart1.usRxBufSize )
{
g_tUart1.usRxCount++;
}
if ( g_tUart1.ReciveNew )
{
g_tUart1.ReciveNew( ch );
}
//USART1->DATA_B.DATA = ch; //回显测试
}
else if( ( isrflags & USART_FLAG_IDLE ) != RESET )
{
USART1->STS;
USART1->DATA_B.DATA;
}
if( ( isrflags & USART_FLAG_PE ) != RESET )
{
USART1->STS;
USART1->DATA_B.DATA;
}
if( ( isrflags & USART_FLAG_FE ) != RESET )
{
USART1->STS;
USART1->DATA_B.DATA;
}
if( ( isrflags & USART_FLAG_NE ) != RESET )
{
USART1->STS;
USART1->DATA_B.DATA;
}
if( ( isrflags & USART_FLAG_OVRE ) != RESET )
{
USART1->STS;
USART1->DATA_B.DATA;
}
/* 处理发送缓冲区空中断 */
if ( ( ( isrflags & 0x80 ) != RESET ) && ( cr1its & 0x80 ) != RESET )
{
//if (_pUart->usTxRead == _pUart->usTxWrite)
if ( g_tUart1.usTxCount == 0 )
{
/* 发送缓冲区的数据已取完时, 禁止发送缓冲区空中断 (注意:此时最后1个数据还未真正发送完毕)*/
USART_DisableInterrupt( g_tUart1.uart_periph, USART_INT_TXBE );
/* 使能数据发送完毕中断 */
USART_EnableInterrupt( g_tUart1.uart_periph, USART_INT_TXC );
}
else
{
g_tUart1.Sending = 1;
/* 从发送FIFO取1个字节写入串口发送数据寄存器 */
USART1->DATA_B.DATA = g_tUart1.pTxBuf[g_tUart1.usTxRead];
if ( ++g_tUart1.usTxRead >= g_tUart1.usTxBufSize )
{
g_tUart1.usTxRead = 0;
}
g_tUart1.usTxCount--;
}
}
/* 数据bit位全部发送完毕的中断 */
if ( ( ( isrflags & 0x40 ) != RESET ) && ( ( cr1its & 0x40 ) != RESET ) )
{
//if (_pUart->usTxRead == _pUart->usTxWrite)
if ( g_tUart1.usTxCount == 0 )
{
/* 如果发送FIFO的数据全部发送完毕,禁止数据发送完毕中断 */
//CLEAR_BIT( _pUart->uart->CR1, USART_CR1_TCIE );
USART_DisableInterrupt( g_tUart1.uart_periph, USART_INT_TXC );
if ( g_tUart1.SendOver )
{
g_tUart1.SendOver();
}
g_tUart1.Sending = 0;
}
else
{
/* 正常情况下,不会进入此分支 */
/* 如果发送FIFO的数据还未完毕,则从发送FIFO取1个数据写入发送数据寄存器 */
USART1->DATA_B.DATA = g_tUart1.pTxBuf[g_tUart1.usTxRead];
if ( ++g_tUart1.usTxRead >= g_tUart1.usTxBufSize )
{
g_tUart1.usTxRead = 0;
}
g_tUart1.usTxCount--;
}
}
}
#endif /* UART0_FIFO_EN */
3、printf重定向代码,其中有两种方式实现打印输出,一种是串口查询发送,另一种是使用中断发送,可以通过注释相关代码,来实现测试查询发送和中断发送。
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;
void _sys_exit( int x )
{
x = x;
}
int fputc( int ch, FILE *f )
{
// USART_TxData( USART1, ch );
// while( USART_ReadStatusFlag( USART1, USART_FLAG_TXC ) == RESET ); //查询方式
comSendBuf( COM1, ( uint8_t * )&ch, 1 ); //中断方式
return ch;
}
4、主程序代码
int main( void )
{
NVIC_ConfigPriorityGroup( NVIC_PRIORITY_GROUP_4 );
SysInit();
while( 1 )
{
GPIOB->ODATA_B.ODATA9 ^= 1;
printf( "hello world\r\n" );
delay_ms( 1000 );
}
}
/**************************************************************
* [url=home.php?mod=space&uid=32621]@name[/url] SysInit
* [url=home.php?mod=space&uid=159083]@brief[/url] * @param None
* @retval
* [url=home.php?mod=space&uid=1315547]@author[/url] Zachary
* [url=home.php?mod=space&uid=34591]@data[/url] 2022-09-13
**************************************************************/
static void SysInit( void )
{
delay_init( 120 );
bsp_Gpio_Init();
bsp_InitUart();
}
5、串口测试截图,115200bps下实现1S打印hello world,上位机使用的是sscom。
6、中断发送下,512000bps以上波特率乱码截图,再次声明,本测试不代表这款芯片有问题,问题应该是出在我的程序和usb转232上。
目前,我仅测的是板载的232,至于485,只不过是传输介质的不同,但是485相较于232来说,布局布线,直接上TTL转USB,用好一点的芯片吧
最好是上示波器捕获一下时序图,看是串口输出有问题,还是接收芯片有问题,这样对串口的理解更加深透。