上篇HC32F4A0开发板内容:HC32F4A0-Keil环境搭建与点灯 - 国产芯片交流 - 电子工程世界-论坛 (eeworld.com.cn)
根据官方手册可知,HC32F4A0SITB这款芯片具有10个串口资源,本次测试只用到了USART1。测试内容是,使用串口调试助手以1ms间隔向单片机发送数据,随后单片机上电,查看单片机串口是否会有问题,由于板载没有485,没办法将设备挂在总线上测试。曾经,485总线上有数据,设备上电时,串口初始化顺序问题,导致单片机串口卡死过,进了错误中断,因此想测试下,竟然没有485电路。
使用的是USART1,对用开发板的管脚是USART1_TX_PIN是PH15,USART1_RX_PIN是PH13;首先我们需要对串口进行管脚配置,其次是管脚功能复用,第三是串口参数配置,最后是中断配置。在手册中可以知道,PH15和PH13的通讯复用位FG1(Func32~63),那个表格太难看了,字太小了,然后再去看Func32~63这个表格,可以对应USART1_TX是Func32,USART1_RX是Func33;说实话这个看起来有点繁琐,不想其他手册,一目了然。不光如此,程序中还没有定义好,像ST或GD直接是一目了然,这个固件库直接是GPIO_FUNC_33,但凡名字换成USART1_AF_xx这种,我也不至于去查手册。
接着是串口中断配置,这个配置也是与ST或GD大不相同,hc32f4a0.h中定义了大量的中断号,我们可以随意使用,但也不是每个都能用,具体需要查看表格,下表是USART1的中断可使用的中断号表格。这里HC32F4A0这个单片机中断都是单独分开的,接收、发送、错误等中断都需要单独配置。
以下是USART1的串口配置代码,代码均有注释:
/**************************************************************
* [url=home.php?mod=space&uid=32621]@name[/url] bsp_Usart_Init
* [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] 2023-02-22
**************************************************************/
void bsp_Usart_Init( void )
{
stc_gpio_init_t Gpio_InitStruct;
stc_usart_uart_init_t Usart_InitStruct;
stc_irq_signin_config_t stcIrqSigninConfig;
LL_PERIPH_WE( LL_PERIPH_FCG | LL_PERIPH_GPIO | LL_PERIPH_INTC ); /* ---解保护--- */
Gpio_InitStruct.u16PinDir = PIN_DIR_OUT; /* --方向 输入或输出--- */
Gpio_InitStruct.u16PinDrv = PIN_HIGH_DRV; /* --驱动能力--- */
Gpio_InitStruct.u16PinAttr = PIN_ATTR_DIGITAL; /* --数字量或模拟量--- */
Gpio_InitStruct.u16PinOutputType = PIN_OUT_TYPE_CMOS; /* --正常CMOS电平输出或NMOS开漏输出--- */
Gpio_InitStruct.u16PinState = PIN_STAT_SET; /* --初始化后电平状态--- */
Gpio_InitStruct.u16PullUp = PIN_PU_ON; /* --上拉输出--- */
Gpio_InitStruct.u16ExtInt = PIN_EXTINT_OFF; /* --中断功能不开启--- */
Gpio_InitStruct.u16Invert = PIN_INVT_OFF; /* --反向功能不开启--- */
Gpio_InitStruct.u16Latch = PIN_LATCH_OFF; /* --输出锁存功能不开启--- */
GPIO_Init( USART1_TX_PORT, USART1_TX_PIN, &Gpio_InitStruct );
Gpio_InitStruct.u16PinDir = PIN_DIR_IN; /* --方向 输入或输出--- */
Gpio_InitStruct.u16PinDrv = PIN_HIGH_DRV; /* --驱动能力--- */
Gpio_InitStruct.u16PinAttr = PIN_ATTR_DIGITAL; /* --数字量或模拟量--- */
Gpio_InitStruct.u16PinOutputType = PIN_OUT_TYPE_CMOS; /* --正常CMOS电平输出或NMOS开漏输出--- */
Gpio_InitStruct.u16PinInputType = PIN_IN_TYPE_CMOS; /* --施密特输入或CMOS输入--- */
Gpio_InitStruct.u16PinState = PIN_STAT_SET; /* --初始化后电平状态--- */
Gpio_InitStruct.u16PullUp = PIN_PU_ON; /* --上拉输出--- */
Gpio_InitStruct.u16ExtInt = PIN_EXTINT_OFF; /* --中断功能不开启--- */
Gpio_InitStruct.u16Invert = PIN_INVT_OFF; /* --反向功能不开启--- */
Gpio_InitStruct.u16Latch = PIN_LATCH_OFF; /* --输出锁存功能不开启--- */
GPIO_Init( USART1_RX_PORT, USART1_RX_PIN, &Gpio_InitStruct );
/* Configure USART RX/TX pin. */
GPIO_SetFunc( USART1_RX_PORT, USART1_RX_PIN, GPIO_FUNC_33 );
GPIO_SetFunc( USART1_TX_PORT, USART1_TX_PIN, GPIO_FUNC_32 );
USART1_FCG_ENABLE(); /* ---使能串口1功能时钟--- */
USART_UART_StructInit( &Usart_InitStruct );
Usart_InitStruct.u32ClockSrc = USART_CLK_SRC_INTERNCLK; /* ---选择内部时钟--- */
Usart_InitStruct.u32ClockDiv = USART_CLK_DIV16; /* ---时钟64分频--- */
Usart_InitStruct.u32CKOutput = USART_CK_OUTPUT_DISABLE; /* ---不输出时钟--- */
Usart_InitStruct.u32Baudrate = 115200UL; /* ---波特率过高程序卡死时 请调整时钟分频因子--- */
Usart_InitStruct.u32Parity = USART_PARITY_NONE;
Usart_InitStruct.u32DataWidth = USART_DATA_WIDTH_8BIT;
Usart_InitStruct.u32StopBit = USART_STOPBIT_1BIT;
Usart_InitStruct.u32FirstBit = USART_FIRST_BIT_LSB; /* ---LSB先行--- */
Usart_InitStruct.u32HWFlowControl = USART_HW_FLOWCTRL_NONE;
Usart_InitStruct.u32StartBitPolarity = USART_START_BIT_LOW; /* ---起始位为低--- */
Usart_InitStruct.u32OverSampleBit = USART_OVER_SAMPLE_16BIT; /* ---16倍过采样--- */
if ( LL_OK != USART_UART_Init( CM_USART1, &Usart_InitStruct, NULL ) )
{
for ( ;; )
{
}
}
stcIrqSigninConfig.enIRQn = INT137_IRQn; /* ---中断向量号--- */
stcIrqSigninConfig.enIntSrc = INT_SRC_USART1_RI; /* ---中断类型--- */
stcIrqSigninConfig.pfnCallback = &USART1_RxCpltCallback; /* ---中断回调函数--- */
INTC_IrqSignIn( &stcIrqSigninConfig );
NVIC_ClearPendingIRQ( stcIrqSigninConfig.enIRQn ); /* ---清中断--- */
NVIC_SetPriority( stcIrqSigninConfig.enIRQn, 0UL ); /* ---设置中断优先级--- */
NVIC_EnableIRQ( stcIrqSigninConfig.enIRQn );
stcIrqSigninConfig.enIRQn = INT001_IRQn; /* ---中断向量号--- */
stcIrqSigninConfig.enIntSrc = INT_SRC_USART1_TI; /* ---中断类型--- */
stcIrqSigninConfig.pfnCallback = &USART1_TxCpltCallback; /* ---中断回调函数--- */
INTC_IrqSignIn( &stcIrqSigninConfig );
NVIC_ClearPendingIRQ( stcIrqSigninConfig.enIRQn ); /* ---清中断--- */
NVIC_SetPriority( stcIrqSigninConfig.enIRQn, 0UL ); /* ---设置中断优先级--- */
NVIC_EnableIRQ( stcIrqSigninConfig.enIRQn );
LL_PERIPH_WP( LL_PERIPH_FCG | LL_PERIPH_GPIO | LL_PERIPH_INTC ); /* ---上保护--- */
USART_FuncCmd( CM_USART1, ( USART_TX | USART_RX | USART_INT_RX ), ENABLE ); /* ---打开发送接收功能、中断接收功能--- */
USART_FuncCmd( CM_USART1, USART_INT_TX_EMPTY, DISABLE );
COM1_Info.pRxBuf = RxBuf;
COM1_Info.pTxBuf = TxBuf;
}
以下是串口中断接收回调函数代码:
/**************************************************************
* @Name USART1_RxCpltCallback
* @brief
* @param None
* @retval
* @author Zachary
* @Data 2023-02-20
**************************************************************/
static void USART1_RxCpltCallback( void )
{
uint8_t u8Data = 0x0;
if( USART_GetStatus( CM_USART1, USART_FLAG_RX_FULL ) != RESET )
{
u8Data = ( uint8_t )USART_ReadData( CM_USART1 );
COM1_Info.pRxBuf[COM1_Info.RxCnt] = u8Data;
USART_WriteData( CM_USART1, COM1_Info.pRxBuf[COM1_Info.RxCnt] );
COM1_Info.RxCnt++;
}
}
以下是串口中断发送回调函数代码:
/**************************************************************
* @Name USART1_TxCpltCallback
* @brief
* @param None
* @retval
* @author Zachary
* @Data 2023-02-21
**************************************************************/
static void USART1_TxCpltCallback( void )
{
if( USART_GetStatus( CM_USART1, USART_FLAG_TX_EMPTY ) != RESET )
{
if( COM1_Info.TxLen > 0x00 )
{
CM_USART1->DR = COM1_Info.pTxBuf[COM1_Info.TxCnt] & 0X01FF;
COM1_Info.TxCnt++;
COM1_Info.TxLen--;
}
else
{
COM1_Info.TxLen = 0x00;
COM1_Info.TxCnt = 0x00;
USART_FuncCmd( CM_USART1, USART_INT_TX_EMPTY, DISABLE );
}
}
}
/**************************************************************
* @Name USART1_SendData_UseIT
* @brief
* @param pBuf: [输入/出]
** pLen: [输入/出]
* @retval
* @author Zachary
* @Data 2023-02-23
**************************************************************/
void USART1_SendData_UseIT( uint8_t *pBuf, uint8_t pLen )
{
COM1_Info.TxCnt = 0x00;
COM1_Info.TxLen = pLen;
memcpy( COM1_Info.pTxBuf, pBuf, COM1_Info.TxLen );
CM_USART1->DR = pBuf[COM1_Info.TxCnt];
COM1_Info.TxCnt++;
COM1_Info.TxLen--;
USART_FuncCmd( CM_USART1, USART_INT_TX_EMPTY, ENABLE );
}
以下是主程序代码:
/**************************************************************
* @Name main
* @brief
* @param None
* @retval
* @author Zachary
* @Data 2022-02-13
**************************************************************/
int32_t main( void )
{
char SendBuf[] = "Hello World\n";
SysInit();
printf("This is HC32F4A0 USART1 test.\n");
USART1_SendData_UseIT( ( uint8_t * )SendBuf, strlen( SendBuf ) );
while( 1 )
{
LED10_TOGGLE();
LED11_TOGGLE();
delay_ms( 500 );
// printf("This is HC32F4A0 USART1 test.\n");
// USART1_SendData_UseIT( ( uint8_t * )SendBuf, strlen( SendBuf ) );
}
}
/**************************************************************
* @Name SysInit
* @brief
* @param None
* @retval
* @author Zachary
* @Data 2023-02-13
**************************************************************/
static void SysInit( void )
{
NVIC_SetPriorityGrouping( 0x00000003U ); /* ---设置为4位抢占优先级 */
bsp_SetSysClk();
CLK_GetClockFreq( &sysclk ); /* ---检查时钟是否正确--- */
delay_init( 240 ); /* ---系统滴答定时器初始化--- */
// delay_ms( 1000 );
bsp_Gpio_Init(); /* ---初始化Gpio--- */
bsp_Usart_Init();
}
以下是串口查询发送与中断发送测试图片,This is HC32F4A0 USART1 test.用的是查询发送,hello world用的是中断发送。
|