目录
一、基础知识
USART1基地址为:0x4001_D000
USART2基地址为:0x4001_D400
USART3基地址为:0x4002_1000
USART4基地址为:0x4002_1400
引脚映射:华大HC32F460与STM32F10x的区别在于:HC32F460有64个引脚支持Fun32~63功能选择,即我们说的重映射,Fun32~63主要为串行通信功能(包含USART,SPI, I2C, I2S, CAN);分为了Fun_Grp1、Fun_Grp2。具体可看<数据手册-引脚功能表>。而STM32F10x的GPIO引脚重映射是有规定的,所以华大的用起来比较灵活。
接收超时定时器通道选择
TIMEOUT 计数器采用Timer0 模块的计数器,具体对应关系如下:
USART1:Timer0 Unit1 A 通道
USART2:Timer0 Unit1 B 通道
USART3:Timer0 Unit2 A 通道
USART4:Timer0 Unit2 B 通道
USART串口通信的基本参数配置为一致,也是最常用的模式
UsartIntClkCkOutput:时钟为内部时钟输出
UsartClkDiv_16:16分频
UsartDataBits8:8位数据位
UsartDataLsbFirst:低位在前
UsartOneStopBit:1位停止位
UsartParityNone:无奇偶校验
UsartSamleBit8:8位采样
UsartStartBitFallEdge:起始位检测下降沿
UsartRtsEnable:RTS允许
二、代码实现
本样例主要展示USART外设配置为USART外设配置为UART模式时通过中断方式收发数据。
串口助手软件配置端口参数:
波特率:115200
数据位:8
校验位:None
停止位:1
宏定义
/* USART channel definition */
#define USART_CH (M4_USART4)
/* USART baudrate definition */
#define USART_BAUDRATE (115200ul)
/* USART Interrupt Number */
#define USART_RX_IRQn (Int000_IRQn)
#define USART_ERR_IRQn (Int001_IRQn)
#define USART_RTO_IRQn (Int002_IRQn)
#define USART_TX_IRQn (Int003_IRQn)
#define USART_CMP_IRQn (Int004_IRQn)
/* USART RX Port/Pin definition */
#define USART_RX_PORT (PortE)
#define USART_RX_PIN (Pin14)
#define USART_RX_FUNC (Func_Usart4_Rx)
#define USART_TX_PORT (PortE)
#define USART_TX_PIN (Pin15)
#define USART_TX_FUNC (Func_Usart4_Tx)
/* USART interrupt number */
#define USART_RI_NUM (INT_USART4_RI)
#define USART_EI_NUM (INT_USART4_EI)
#define USART_RTO_NUM (INT_USART4_RTO)
#define USART_TI_NUM (INT_USART4_TI)
#define USART_TCI_NUM (INT_USART4_TCI)
#define set Ok
#define reset Error
#define ENCODER_LEN 6
static uint16_t u16RxData;
串口初始化
/*串口初始化*/
void UART_Init(void)
{
en_result_t enRet = Ok;
stc_irq_regi_conf_t stcIrqRegiCfg;
/*配置串口使用的时钟和基本通信配置*/
const stc_usart_uart_init_t stcInitCfg = {
UsartIntClkCkOutput,
UsartClkDiv_16,//时钟分频
UsartDataBits8,
UsartDataLsbFirst,
UsartOneStopBit,
UsartParityNone,
UsartSamleBit8,
UsartStartBitFallEdge,
UsartRtsEnable,
};
/*打开时钟*/
PWC_Fcg1PeriphClockCmd(PWC_FCG1_PERIPH_USART4, Enable);
/*配置相应的IO作为串口的RX引脚*/
PORT_SetFunc(USART_TX_PORT, USART_TX_PIN, USART_TX_FUNC, Disable);
PORT_SetFunc(USART_RX_PORT, USART_RX_PIN, USART_RX_FUNC, Disable);
/*初始化串口配置*/
enRet = USART_UART_Init(USART_CH, &stcInitCfg);
while (enRet != Ok);
/*串口波特率设置*/
enRet = USART_SetBaudrate(USART_CH, USART_BAUDRATE);
while (enRet != Ok);
/*设置串口接收中断*/
stcIrqRegiCfg.enIRQn = USART_RX_IRQn;
stcIrqRegiCfg.pfnCallback = &Usart4RxIrqCallback;
stcIrqRegiCfg.enIntSrc = USART_RI_NUM;
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
/*设置串口接收错误中断*/
stcIrqRegiCfg.enIRQn = USART_ERR_IRQn; /* 中断号,可通过参考手册查阅对应的中断号 */
stcIrqRegiCfg.pfnCallback = &Usart4ErrIrqCallback; /* 中断回调函数 */
stcIrqRegiCfg.enIntSrc = USART_EI_NUM; /* 错误中断向量号,可通过参考手册查阅对应的中断号*/
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);/* 配置中断优先级 */
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn); /*先清一下这个中断的标志位(置零)*/
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn); /*在使能这个中断*/
/*设置接收超时中断*/
stcIrqRegiCfg.enIRQn = USART_RTO_IRQn; /* 中断号,可通过参考手册查阅对应的中断号 */
stcIrqRegiCfg.pfnCallback = &Usart4TimeoutIrqCallback; /* 中断回调函数 */
stcIrqRegiCfg.enIntSrc = INT_USART4_RTO; /* 错误中断向量号,可通过参考手册查阅对应的中断号*/
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT); /* 配置中断优先级 */
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn); /*先清一下这个中断的标志位(置零)*/
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn); /*在使能这个中断*/
/*设置串口发送中断*/
stcIrqRegiCfg.enIRQn = USART_TX_IRQn; /* 中断号,可通过参考手册查阅对应的中断号 */
stcIrqRegiCfg.pfnCallback = &UsartTxIrqCallback; /* 中断回调函数 */
stcIrqRegiCfg.enIntSrc = USART_TI_NUM; /* 错误中断向量号,可通过参考手册查阅对应的中断号*/
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT); /* 配置中断优先级 */
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn); /*先清一下这个中断的标志位(置零)*/
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn); /*在使能这个中断*/
/*设置串口发送完成中断*/
stcIrqRegiCfg.enIRQn = USART_CMP_IRQn; /* 中断号,可通过参考手册查阅对应的中断号 */
stcIrqRegiCfg.pfnCallback = &UsartTxCmpltIrqCallback; /* 中断回调函数 */
stcIrqRegiCfg.enIntSrc = USART_TCI_NUM; /* 错误中断向量号,可通过参考手册查阅对应的中断号*/
enIrqRegistration(&stcIrqRegiCfg);
NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT); /* 配置中断优先级 */
NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn); /*先清一下这个中断的标志位(置零)*/
NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn); /*在使能这个中断*/
USART_FuncCmd(USART_CH, UsartTx, Enable);//使能发送
USART_FuncCmd(USART_CH, UsartRx, Enable);//使能接收
USART_FuncCmd(USART_CH, UsartRxInt, Enable);//使能接收中断
USART_FuncCmd(USART_CH, UsartTimeOut, Enable);//使能超时
USART_FuncCmd(USART_CH, UsartTimeOutInt, Enable);//使能超时中断
}
定时器初始化
/*usart timer0初始化*/
static void Usart_Timer0_Init(void)
{
stc_clk_freq_t stcClkTmp;
stc_tim0_base_init_t stcTimerCfg;
stc_tim0_trigger_init_t StcTimer0TrigInit;
MEM_ZERO_STRUCT(stcClkTmp);
MEM_ZERO_STRUCT(stcTimerCfg);
MEM_ZERO_STRUCT(StcTimer0TrigInit);
/* Timer0 peripheral enable */
PWC_Fcg2PeriphClockCmd(PWC_FCG2_PERIPH_TIM02, Enable);
/* Clear CNTAR register for channel A */
// TIMER0_WriteCntReg(LCD_TMR_UNIT, Tim0_ChannelA, 0u);
TIMER0_WriteCntReg(M4_TMR02, Tim0_ChannelB, 0u);
/* Config register for channel A */
stcTimerCfg.Tim0_CounterMode = Tim0_Async;
stcTimerCfg.Tim0_AsyncClockSource = Tim0_XTAL32;
stcTimerCfg.Tim0_ClockDivision = Tim0_ClkDiv8;
stcTimerCfg.Tim0_CmpValue = 32000u;
TIMER0_BaseInit(M4_TMR02, Tim0_ChannelB, &stcTimerCfg);
/* Clear compare flag */
TIMER0_ClearFlag(M4_TMR02, Tim0_ChannelB);
/* Config timer0 hardware trigger */
StcTimer0TrigInit.Tim0_InTrigEnable = false;
StcTimer0TrigInit.Tim0_InTrigClear = true;
StcTimer0TrigInit.Tim0_InTrigStart = true;
StcTimer0TrigInit.Tim0_InTrigStop = false;
TIMER0_HardTriggerInit(M4_TMR02, Tim0_ChannelB, &StcTimer0TrigInit);
}
时钟初始化
/*时钟初始化*/
static void ClkInit(void)
{
stc_clk_xtal_cfg_t stcXtalCfg;
stc_clk_mpll_cfg_t stcMpllCfg;
en_clk_sys_source_t enSysClkSrc;
stc_clk_sysclk_cfg_t stcSysClkCfg;
MEM_ZERO_STRUCT(enSysClkSrc);
MEM_ZERO_STRUCT(stcSysClkCfg);
MEM_ZERO_STRUCT(stcXtalCfg);
MEM_ZERO_STRUCT(stcMpllCfg);
/* Set bus clk div. */
stcSysClkCfg.enHclkDiv = ClkSysclkDiv1; /* Max 168MHz */
stcSysClkCfg.enExclkDiv = ClkSysclkDiv2; /* Max 84MHz */
stcSysClkCfg.enPclk0Div = ClkSysclkDiv1; /* Max 168MHz */
stcSysClkCfg.enPclk1Div = ClkSysclkDiv2; /* Max 84MHz */
stcSysClkCfg.enPclk2Div = ClkSysclkDiv4; /* Max 60MHz */
stcSysClkCfg.enPclk3Div = ClkSysclkDiv4; /* Max 42MHz */
stcSysClkCfg.enPclk4Div = ClkSysclkDiv2; /* Max 84MHz */
CLK_SysClkConfig(&stcSysClkCfg);
/* Switch system clock source to MPLL. */
/* Use Xtal as MPLL source. */
stcXtalCfg.enMode = ClkXtalModeOsc;
stcXtalCfg.enDrv = ClkXtalLowDrv;
stcXtalCfg.enFastStartup = Enable;
CLK_XtalConfig(&stcXtalCfg);
CLK_XtalCmd(Enable);
/* MPLL config. */
stcMpllCfg.pllmDiv = 1ul;
stcMpllCfg.plln = 50ul;
stcMpllCfg.PllpDiv = 4ul;
stcMpllCfg.PllqDiv = 4ul;
stcMpllCfg.PllrDiv = 4ul;
CLK_SetPllSource(ClkPllSrcXTAL);
CLK_MpllConfig(&stcMpllCfg);
/* flash read wait cycle setting */
EFM_Unlock();
EFM_SetLatency(EFM_LATENCY_5);
EFM_Lock();
/* Enable MPLL. */
CLK_MpllCmd(Enable);
/* Wait MPLL ready. */
while (Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
{
}
/* Switch system clock source to MPLL. */
CLK_SetSysClkSource(CLKSysSrcMPLL);
}
相关中断回调函数
串口发送空中断,串口发送完成中断
串口接收中断,串口接收错误中断,串口接收超时中断
/*串口接收中断回调函数RX*/
static void Usart4RxIrqCallback(void)
{
if (Set == USART_GetStatus(USART_CH, UsartRxNoEmpty)){
u16RxData = USART_RecData(USART_CH);//取出数据
buffer = u16RxData;
USART_FuncCmd(USART_CH, UsartTx, Enable);
USART_SendData(USART_CH, buffer);
}
}
/*串口接收错误中断回调函数RX ERR*/
static void Usart4ErrIrqCallback(void)
{
if (Set == USART_GetStatus(USART_CH, UsartFrameErr))
USART_ClearStatus(USART_CH, UsartFrameErr);
if (Set == USART_GetStatus(USART_CH, UsartParityErr))
USART_ClearStatus(USART_CH, UsartParityErr);
if (Set == USART_GetStatus(USART_CH, UsartOverrunErr))
USART_ClearStatus(USART_CH, UsartOverrunErr);
if (Set == USART_GetStatus(USART_CH, UsartRxNoEmpty))
USART_ClearStatus(USART_CH, UsartRxNoEmpty);
if (Set == USART_GetStatus(USART_CH, UsartTxComplete))
USART_ClearStatus(USART_CH, UsartTxComplete);
if (Set == USART_GetStatus(USART_CH, UsartTxEmpty))
USART_ClearStatus(USART_CH, UsartTxEmpty);
if (Set == USART_GetStatus(USART_CH, UsartRxTimeOut))
USART_ClearStatus(USART_CH, UsartRxTimeOut);
if (Set == USART_GetStatus(USART_CH, UsartRxMpb))
USART_ClearStatus(USART_CH, UsartRxMpb);
}
/*串口接收超时中断回调RX TIMEOUT*/
static void Usart4TimeoutIrqCallback(void)
{
TIMER0_Cmd(M4_TMR02, Tim0_ChannelB,Disable);
USART_ClearStatus(USART_CH, UsartRxTimeOut);
}
/*串口发送中断回调函数TX*/
static void UsartTxIrqCallback(void)
{
USART_SendData(USART_CH, u16RxData);
USART_FuncCmd(USART_CH, UsartTxEmptyInt, Disable);
USART_FuncCmd(USART_CH, UsartTxCmpltInt, Enable);
}
/*串口发送完成中断回调函数TX CAM*/
static void UsartTxCmpltIrqCallback(void)
{
USART_FuncCmd(USART_CH,UsartTx,Disable);
USART_FuncCmd(USART_CH,UsartTxCmpltInt,Disable);
}
mian函数
static uint8_t u8RxData;
int32_t main(void)
{
//时钟初始化
ClkInit();
//串口初始化
UART_Init();
//定时器0初始化
Usart_Timer0_Init();
while(1){
;
}
}
三、问题
1.有个坑
USART的波特率需将串口时钟频率降低。
在我的代码里,波特率设置的USART_SetBaudrate的SetUartBaudrate里
如果只有一个B = u32Baudrate;就会跳过???????
所以我多写了一个B = u32Baudrate;
防止代码在此发生错误