动易网站模板制作方法,网络广告营销典型案例,网站页面设计软件,沈阳专业网站建设公司目录
1. 串口GPIO配置
2. 串口波特率配置
3. 串口接收超时配置
4. 串口中断注册
5. 串口初始化
6. 串口数据接收处理
7. DMA接收配置和处理 1. 串口GPIO配置
端口号和Pin脚号跟STM32没什么区别。
串口复用功能跟STM32大不一样。
如下图#xff0c;选自HC32F448 表 2…目录
1. 串口GPIO配置
2. 串口波特率配置
3. 串口接收超时配置
4. 串口中断注册
5. 串口初始化
6. 串口数据接收处理
7. DMA接收配置和处理 1. 串口GPIO配置
端口号和Pin脚号跟STM32没什么区别。
串口复用功能跟STM32大不一样。
如下图选自HC32F448 表 2-1 引脚功能表。
1每个管脚都有对应的管脚名称、中断号以及功能号
2调试口默认为TRACE/JTAG功能号若要使能普通GPIO功能则要关闭调试功能
3非调试口默认功能号为Func0即普通GPIO功能。Func2到Func11为定时器或时钟功能Func12为EXMC/TIMA功能
4Func32~63为通用复用功能-分为两组对于同一组的IO可以配置为UART/I2C/SPI/CAN 4组功能且Rx/Tx可以互换。而不是像STM32那样每个IO的复用功能是固定的对应通讯线必须一一选对。 如下硬件选择了PB0和PA7作为串口通讯脚可以在FG1任意选择一个可用串口使用。
#define USART_RX_PORT (GPIO_PORT_B) /* PB0: USART2_RX */
#define USART_RX_PIN (GPIO_PIN_00)
#define USART_RX_GPIO_FUNC (GPIO_FUNC_37)
#define USART_TX_PORT (GPIO_PORT_A) /* PA7: USART2_TX */
#define USART_TX_PIN (GPIO_PIN_07)
#define USART_TX_GPIO_FUNC (GPIO_FUNC_36)static void UartGpioConfig(void)
{GPIO_SetFunc(USART_RX_PORT, USART_RX_PIN, USART_RX_GPIO_FUNC);GPIO_SetFunc(USART_TX_PORT, USART_TX_PIN, USART_TX_GPIO_FUNC);
}
2. 串口波特率配置
static void UartBaudConfig(void)
{USART_FCG_ENABLE();stc_usart_uart_init_t stcUartInit;(void)USART_UART_StructInit(stcUartInit);stcUartInit.u32ClockDiv USART_CLK_DIV64;stcUartInit.u32CKOutput USART_CK_OUTPUT_ENABLE;stcUartInit.u32Baudrate USART_BAUDRATE;stcUartInit.u32OverSampleBit USART_OVER_SAMPLE_8BIT;USART_UART_Init(USART_UNIT, stcUartInit, NULL);
}3. 串口接收超时配置
小华HC32F4串口支持的中断与STM32大有不同
1HC32 接收数据寄存器满中断在收到1个字节时就会触发。等同于STM32的RXNE。名字不同
2HC32 TIMEOUT中断等同于STM32的空闲中断 IDLE 。HC32通过关联定时器直接配置超时时间比STM32更加简便。 定时器Timer0被专门用来做串口的计时器板子用的串口2所以定时器要配置Timer0_1 B 。 //串口接收超时设置·关联定时器
#define USART_TIMEOUT_BITS (5000U)
#define TMR0_UNIT (CM_TMR0_1)
#define TMR0_CH (TMR0_CH_B)
#define TMR0_FCG_ENABLE() (FCG_Fcg2PeriphClockCmd(FCG2_PERIPH_TMR0_1, ENABLE))/** TMR0_Config()* 配置串口接收超时
*/
static void TMR0_Config(void)
{uint16_t u16Div;uint16_t u16Delay;uint16_t u16CompareValue;stc_tmr0_init_t stcTmr0Init;TMR0_FCG_ENABLE();/* Initialize TMR0 base function. */stcTmr0Init.u32ClockSrc TMR0_CLK_SRC_XTAL32;stcTmr0Init.u32ClockDiv TMR0_CLK_DIV8;stcTmr0Init.u32Func TMR0_FUNC_CMP;if (TMR0_CLK_DIV1 stcTmr0Init.u32ClockDiv) {u16Delay 7U;} else if (TMR0_CLK_DIV2 stcTmr0Init.u32ClockDiv) {u16Delay 5U;} else if ((TMR0_CLK_DIV4 stcTmr0Init.u32ClockDiv) || \(TMR0_CLK_DIV8 stcTmr0Init.u32ClockDiv) || \(TMR0_CLK_DIV16 stcTmr0Init.u32ClockDiv)) {u16Delay 3U;} else {u16Delay 2U;}u16Div (uint16_t)1U (stcTmr0Init.u32ClockDiv TMR0_BCONR_CKDIVA_POS);u16CompareValue ((USART_TIMEOUT_BITS u16Div - 1U) / u16Div) - u16Delay;stcTmr0Init.u16CompareValue u16CompareValue;(void)TMR0_Init(TMR0_UNIT, TMR0_CH, stcTmr0Init);TMR0_HWStartCondCmd(TMR0_UNIT, TMR0_CH, ENABLE);TMR0_HWClearCondCmd(TMR0_UNIT, TMR0_CH, ENABLE);
}
4. 串口中断注册
#define USART_RX_ERR_IRQn (INT005_IRQn)
#define USART_RX_ERR_INT_SRC (INT_SRC_USART2_EI)
#define USART_RX_FULL_IRQn (INT006_IRQn)
#define USART_RX_FULL_INT_SRC (INT_SRC_USART2_RI)
#define USART1_RX_TIMEOUT_IRQn (INT007_IRQn)
#define USART1_RX_TIMEOUT_INT_SRC (INT_SRC_USART2_RTO)static void USART_RxFull_IrqCallback(void);
static void USART_RxError_IrqCallback(void);
static void USART_RxTimeout_IrqCallback(void);static void RegisterIrq(void)
{stc_irq_signin_config_t stcIrqSigninConfig;/* Register RX full IRQ handler. */stcIrqSigninConfig.enIRQn USART_RX_FULL_IRQn;stcIrqSigninConfig.enIntSrc USART_RX_FULL_INT_SRC;stcIrqSigninConfig.pfnCallback USART_RxFull_IrqCallback;(void)INTC_IrqSignIn(stcIrqSigninConfig);NVIC_ClearPendingIRQ(stcIrqSigninConfig.enIRQn);NVIC_SetPriority(stcIrqSigninConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);NVIC_EnableIRQ(stcIrqSigninConfig.enIRQn);/* Register RX error IRQ handler. */stcIrqSigninConfig.enIRQn USART_RX_ERR_IRQn;stcIrqSigninConfig.enIntSrc USART_RX_ERR_INT_SRC;stcIrqSigninConfig.pfnCallback USART_RxError_IrqCallback;(void)INTC_IrqSignIn(stcIrqSigninConfig);NVIC_ClearPendingIRQ(stcIrqSigninConfig.enIRQn);NVIC_SetPriority(stcIrqSigninConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);NVIC_EnableIRQ(stcIrqSigninConfig.enIRQn);/* Register RX timeout IRQ handler. */stcIrqSigninConfig.enIRQn USART1_RX_TIMEOUT_IRQn;stcIrqSigninConfig.enIntSrc USART1_RX_TIMEOUT_INT_SRC;stcIrqSigninConfig.pfnCallback USART_RxTimeout_IrqCallback;(void)INTC_IrqSignIn(stcIrqSigninConfig);NVIC_ClearPendingIRQ(stcIrqSigninConfig.enIRQn);NVIC_SetPriority(stcIrqSigninConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);NVIC_EnableIRQ(stcIrqSigninConfig.enIRQn);
}
5. 串口初始化
LL_PERIPH_WE() 为打开相应寄存器的写使能
LL_PERIPH_WP() 为关闭相应寄存器的写使能
void UART_Init(void)
{LL_PERIPH_WE(LL_PERIPH_ALL);UartGpioConfig();UartBaudConfig();TMR0_Config();RegisterIrq();LL_PERIPH_WP(LL_PERIPH_ALL);USART_FuncCmd(USART_UNIT, ( USART_TX | USART_RX | USART_INT_RX | USART_RX_TIMEOUT | USART_INT_RX_TIMEOUT), ENABLE);
}
6. 串口数据接收处理
USART_RxFull_IrqCallback 中断 只负责接收和缓存单字节数据以及递增数据长度 通过读数据清除标志位
USART_RxTimeout_IrqCallback 中断 处理超时中断超时中断触发后必须要关闭定时器和清除标志位
USART_RxError_IrqCallback 中断 处理异常错误
static void USART_RxFull_IrqCallback(void)
{uint8_t u8Data (uint8_t)USART_ReadData(USART_UNIT);if(gps_len RX_FRAME_LEN_MAX)gps_buf[gps_len] u8Data;
}static void USART_RxError_IrqCallback(void)
{(void)USART_ReadData(USART_UNIT);USART_ClearStatus(USART_UNIT, (USART_FLAG_PARITY_ERR | USART_FLAG_FRAME_ERR | USART_FLAG_OVERRUN));
}static void USART_RxTimeout_IrqCallback(void)
{TMR0_Stop(TMR0_UNIT, TMR0_CH);USART_ClearStatus(USART_UNIT, USART_FLAG_RX_TIMEOUT);GpsRxCallBack(gps_buf, gps_len);gps_len 0;
}
对于GPS、Wifi这类不频繁的数据交互用到超时中断和接收寄存器满就可以处理数据了。
对于4G/蓝牙等有持续大量数据交互的模块就需要用到DMA了。
7. 串口数据发送
static int32_t UartSendByte(CM_USART_TypeDef *UART, uint8_t ch)
{uint32_t u32TxEmpty 0UL;__IO uint32_t u32TmpCount 0UL;uint32_t u32Timeout HCLK_VALUE/USART_BAUDRATE;int32_t i32Ret LL_ERR_INVD_PARAM;/* Wait TX data register empty */while ((u32TmpCount u32Timeout) (0UL u32TxEmpty)) {u32TxEmpty READ_REG32_BIT(UART-SR, USART_SR_TXE);u32TmpCount;}if (0UL ! u32TxEmpty) {WRITE_REG16(UART-TDR, ch);i32Ret LL_OK;} else {i32Ret LL_ERR_TIMEOUT;}return i32Ret;
}
8. DMA接收配置和处理
DMA配置方式与STM32基本相同
1设置DMA源地址和源地址增长类型设置目的地址和目的地址增长类型
DMA接收属于串口数据寄存器到内存即源地址固定目的地址递增
DMA发送属于内存到串口数据寄存器即源地址递增目的地址固定
2设置位宽、传输大小、传输块数 所不同的是HC32有一个可配置的自动运行系统AOS。
可以配置AOS源和AOS目标.
AOS源可以是DMA传输完成、UART接收数据、定时器上溢和下溢、event电平变化等等。
AOS目标可以是DMA传输、定时器计数、ADC模数转换、event事件等等 如下是DMA初始化配置的参考代码配置了串口DMA接收和串口DMA发送
//DMA单元
#define RX_DMA_UNIT (CM_DMA1)
//DMA通道号·通道号越小优先级越高
#define RX_DMA_CH (DMA_CH0)
//DMA单元时钟
#define RX_DMA_FCG_ENABLE() (FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_DMA1, ENABLE))
//AOS系统的目标·触发DMA1通道0传输
#define RX_DMA_TRIG_SEL (AOS_DMA1_0)
//AOS系统的触发源·接收数据寄存器满中断
#define RX_DMA_TRIG_EVT_SRC (EVT_SRC_USART1_RI)
//AOS系统的目标·DMA完成中断
#define RX_DMA_RECONF_TRIG_SEL (AOS_DMA_RC)
//AOS系统的触发源·AOS_STRG中断源
#define RX_DMA_RECONF_TRIG_EVT_SRC (EVT_SRC_AOS_STRG)
//DMA传输完成中断·通道号1
#define RX_DMA_TC_INT (DMA_INT_TC_CH0)
//DMA传输完成标志·通道号2
#define RX_DMA_TC_FLAG (DMA_FLAG_TC_CH0)
//DMA传输完成中断号
#define RX_DMA_TC_IRQn (INT000_IRQn)
//DMA传输完成中断源
#define RX_DMA_TC_INT_SRC (INT_SRC_DMA1_TC0)//串口DMA发送配置
#define TX_DMA_UNIT (CM_DMA2)
#define TX_DMA_CH (DMA_CH0)
#define TX_DMA_FCG_ENABLE() (FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_DMA2, ENABLE))
#define TX_DMA_TRIG_SEL (AOS_DMA2_0)
#define TX_DMA_TRIG_EVT_SRC (EVT_SRC_USART1_TI)
#define TX_DMA_TC_INT (DMA_INT_TC_CH0)
#define TX_DMA_TC_FLAG (DMA_FLAG_TC_CH0)
#define TX_DMA_TC_IRQn (INT001_IRQn)
#define TX_DMA_TC_INT_SRC (INT_SRC_DMA2_TC0)/******************************************************************************** Local variable definitions (static)******************************************************************************/
static __IO en_flag_status_t m_enTxEnd SET;
static uint8_t m_4gRxBuf[RX_FRAME_LEN_MAX];
static uint8_t *m_auTxBuf NULL;/******************************************************************************** Local function definitions (static)******************************************************************************/
static void RX_DMA_TC_IrqCallback(void);
static void TX_DMA_TC_IrqCallback(void);/** DMA_Config()* 配置串口DMA接收和DMA发送
*/
static int32_t DMA_Config(void)
{int32_t i32Ret;stc_dma_init_t stcDmaInit;stc_dma_llp_init_t stcDmaLlpInit;stc_irq_signin_config_t stcIrqSignConfig;static stc_dma_llp_descriptor_t stcLlpDesc;//使能DMA和FCG时钟RX_DMA_FCG_ENABLE();TX_DMA_FCG_ENABLE();FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_AOS, ENABLE);/* USART_RX_DMA */(void)DMA_StructInit(stcDmaInit);stcDmaInit.u32IntEn DMA_INT_ENABLE;//DMA interrupt enablestcDmaInit.u32BlockSize 1UL;//DMA block sizestcDmaInit.u32TransCount ARRAY_SZ(m_4gRxBuf);//DMAbuf大小stcDmaInit.u32DataWidth DMA_DATAWIDTH_8BIT;//DMAbuf位宽stcDmaInit.u32DestAddr (uint32_t)m_4gRxBuf;//DMAbuf地址stcDmaInit.u32SrcAddr (uint32_t)(USART_UNIT-RDR);//由外设到内存的 外设地址 - 串口数据寄存器stcDmaInit.u32SrcAddrInc DMA_SRC_ADDR_FIX;//由外设到内存的 源地址模式 固定stcDmaInit.u32DestAddrInc DMA_DEST_ADDR_INC;//由外设到内存的 目标地址模式 自动递增i32Ret DMA_Init(RX_DMA_UNIT, RX_DMA_CH, stcDmaInit);if (LL_OK i32Ret) {(void)DMA_LlpStructInit(stcDmaLlpInit);stcDmaLlpInit.u32State DMA_LLP_ENABLE;stcDmaLlpInit.u32Mode DMA_LLP_WAIT;stcDmaLlpInit.u32Addr (uint32_t)stcLlpDesc;(void)DMA_LlpInit(RX_DMA_UNIT, RX_DMA_CH, stcDmaLlpInit);//初始化DMA链表指针stcLlpDesc.SARx stcDmaInit.u32SrcAddr;stcLlpDesc.DARx stcDmaInit.u32DestAddr;stcLlpDesc.DTCTLx (stcDmaInit.u32TransCount DMA_DTCTL_CNT_POS) | (stcDmaInit.u32BlockSize DMA_DTCTL_BLKSIZE_POS);;stcLlpDesc.LLPx (uint32_t)stcLlpDesc;stcLlpDesc.CHCTLx stcDmaInit.u32SrcAddrInc | stcDmaInit.u32DestAddrInc | stcDmaInit.u32DataWidth | \stcDmaInit.u32IntEn | stcDmaLlpInit.u32State | stcDmaLlpInit.u32Mode;DMA_ReconfigLlpCmd(RX_DMA_UNIT, RX_DMA_CH, ENABLE);DMA_ReconfigCmd(RX_DMA_UNIT, ENABLE);AOS_SetTriggerEventSrc(RX_DMA_RECONF_TRIG_SEL, RX_DMA_RECONF_TRIG_EVT_SRC);stcIrqSignConfig.enIntSrc RX_DMA_TC_INT_SRC;stcIrqSignConfig.enIRQn RX_DMA_TC_IRQn;stcIrqSignConfig.pfnCallback RX_DMA_TC_IrqCallback;(void)INTC_IrqSignIn(stcIrqSignConfig);NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);AOS_SetTriggerEventSrc(RX_DMA_TRIG_SEL, RX_DMA_TRIG_EVT_SRC);DMA_Cmd(RX_DMA_UNIT, ENABLE);DMA_TransCompleteIntCmd(RX_DMA_UNIT, RX_DMA_TC_INT, ENABLE);(void)DMA_ChCmd(RX_DMA_UNIT, RX_DMA_CH, ENABLE);}(void)DMA_StructInit(stcDmaInit);stcDmaInit.u32IntEn DMA_INT_ENABLE;stcDmaInit.u32BlockSize 1UL;stcDmaInit.u32TransCount ARRAY_SZ(m_4gRxBuf);stcDmaInit.u32DataWidth DMA_DATAWIDTH_8BIT;stcDmaInit.u32DestAddr (uint32_t)(USART_UNIT-TDR);stcDmaInit.u32SrcAddr (uint32_t)m_4gRxBuf;stcDmaInit.u32SrcAddrInc DMA_SRC_ADDR_INC;stcDmaInit.u32DestAddrInc DMA_DEST_ADDR_FIX;i32Ret DMA_Init(TX_DMA_UNIT, TX_DMA_CH, stcDmaInit);if (LL_OK i32Ret){stcIrqSignConfig.enIntSrc TX_DMA_TC_INT_SRC;stcIrqSignConfig.enIRQn TX_DMA_TC_IRQn;stcIrqSignConfig.pfnCallback TX_DMA_TC_IrqCallback;(void)INTC_IrqSignIn(stcIrqSignConfig);NVIC_ClearPendingIRQ(stcIrqSignConfig.enIRQn);NVIC_SetPriority(stcIrqSignConfig.enIRQn, DDL_IRQ_PRIO_DEFAULT);NVIC_EnableIRQ(stcIrqSignConfig.enIRQn);AOS_SetTriggerEventSrc(TX_DMA_TRIG_SEL, TX_DMA_TRIG_EVT_SRC);DMA_Cmd(TX_DMA_UNIT, ENABLE);DMA_TransCompleteIntCmd(TX_DMA_UNIT, TX_DMA_TC_INT, ENABLE);}return i32Ret;
}
如下是DMA接收处理代码
1USART_RxTimeout_IrqCallback
重启AOS系统
关闭串口超时定时器清除串口超时标志位。
处理DMA接收数据。
2RX_DMA_TC_IrqCallback
即接收完成中断
硬件上需要清除中断标志位
3USART_TxComplete_IrqCallback
即串口发送完成中断
硬件上需要清除标志位一般要失能发送中断
//串口接收超时中断
static void USART_RxTimeout_IrqCallback(void)
{uint16_t unLen RX_FRAME_LEN_MAX - (uint16_t)DMA_GetTransCount(RX_DMA_UNIT, RX_DMA_CH);AOS_SW_Trigger();TMR0_Stop(TMR0_UNIT, TMR0_CH);USART_ClearStatus(USART_UNIT, USART_FLAG_RX_TIMEOUT);if(unLen ! 0 unLen ! RX_FRAME_LEN_MAX)DtuRxCallBack(m_4gRxBuf, unLen);
}//串口DMA接收·传输完成中断
static void RX_DMA_TC_IrqCallback(void)
{DtuRxCallBack(m_4gRxBuf, RX_FRAME_LEN_MAX);DMA_ClearTransCompleteStatus(RX_DMA_UNIT, RX_DMA_TC_FLAG);
}//串口发送完成中断
static void USART_TxComplete_IrqCallback(void)
{m_enTxEnd SET;DtuTxCallBack(m_auTxBuf);USART_FuncCmd(USART_UNIT, (USART_TX | USART_INT_TX_CPLT), DISABLE);USART_ClearStatus(USART_UNIT, USART_FLAG_TX_CPLT);
}//串口接收错误中断
static void USART_RxError_IrqCallback(void)
{(void)USART_ReadData(USART_UNIT);USART_ClearStatus(USART_UNIT, (USART_FLAG_PARITY_ERR | USART_FLAG_FRAME_ERR | USART_FLAG_OVERRUN));
}//串口DMA发送·传输完成中断
static void TX_DMA_TC_IrqCallback(void)
{USART_FuncCmd(USART_UNIT, USART_INT_TX_CPLT, ENABLE);DMA_ClearTransCompleteStatus(TX_DMA_UNIT, TX_DMA_TC_FLAG);
}9. DMA发送
//串口DMA发送
void DtuDMASend(uint8_t *pBuf, uint16_t u16TxLen)
{
#if 0 //串口发送数据打印printf(Tx: );for(uint16_t i 0; i u16TxLen; i){printf(%02X,pBuf[i]);}printf(\r\n);
#endif//等待上一包发完while(m_enTxEnd RESET);m_enTxEnd RESET;m_auTxBuf pBuf;//启动DMA传输DMA_SetSrcAddr(TX_DMA_UNIT, TX_DMA_CH, (uint32_t)pBuf);DMA_SetTransCount(TX_DMA_UNIT, TX_DMA_CH, u16TxLen);(void)DMA_ChCmd(TX_DMA_UNIT, TX_DMA_CH, ENABLE);USART_FuncCmd(USART_UNIT, USART_TX, ENABLE);
}