打印
[方案相关]

串口UART模式中断收发数据——华大HC32F460

[复制链接]
3282|19
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
l63t89|  楼主 | 2023-10-27 12:07 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式
一、基础知识
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允许

使用特权

评论回复
沙发
l63t89|  楼主 | 2023-10-27 12:07 | 只看该作者
代码实现
本样例主要展示USART外设配置为USART外设配置为UART模式时通过中断方式收发数据。

串口助手软件配置端口参数:

波特率:115200

数据位:8

校验位:None

停止位:1

使用特权

评论回复
板凳
l63t89|  楼主 | 2023-10-27 12:08 | 只看该作者
宏定义
/* 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;

使用特权

评论回复
地板
l63t89|  楼主 | 2023-10-27 12:08 | 只看该作者
串口初始化
/*串口初始化*/
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);//使能超时中断
}

使用特权

评论回复
5
l63t89|  楼主 | 2023-10-27 12:08 | 只看该作者
定时器初始化
/*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);
}

使用特权

评论回复
6
l63t89|  楼主 | 2023-10-27 12:09 | 只看该作者
时钟初始化
/*时钟初始化*/
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);
}

使用特权

评论回复
7
l63t89|  楼主 | 2023-10-27 12:09 | 只看该作者
相关中断回调函数
串口发送空中断,串口发送完成中断
串口接收中断,串口接收错误中断,串口接收超时中断
/*串口接收中断回调函数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);
}

使用特权

评论回复
8
l63t89|  楼主 | 2023-10-27 12:09 | 只看该作者
mian函数
static uint8_t u8RxData;

int32_t main(void)
{
    //时钟初始化
    ClkInit();
    //串口初始化
    UART_Init();
    //定时器0初始化
    Usart_Timer0_Init();
        
    while(1){
      ;
    }
        
}

使用特权

评论回复
9
l63t89|  楼主 | 2023-10-27 12:09 | 只看该作者
问题
1.有个坑
USART的波特率需将串口时钟频率降低。

使用特权

评论回复
10
l63t89|  楼主 | 2023-10-27 12:10 | 只看该作者

使用特权

评论回复
11
l63t89|  楼主 | 2023-10-27 12:10 | 只看该作者
在我的代码里,波特率设置的USART_SetBaudrate的SetUartBaudrate里

使用特权

评论回复
12
l63t89|  楼主 | 2023-10-27 12:10 | 只看该作者
如果只有一个B = u32Baudrate;就会跳过???????

所以我多写了一个B = u32Baudrate;

防止代码在此发生错误

使用特权

评论回复
13
l63t89|  楼主 | 2023-10-27 12:10 | 只看该作者
结果

使用特权

评论回复
14
tpgf| | 2023-11-7 09:34 | 只看该作者
我们为什么需要关心串口的基地址呢

使用特权

评论回复
15
只是个新人-| | 2023-11-7 09:48 | 只看该作者
厉害

使用特权

评论回复
16
观海| | 2023-11-7 10:34 | 只看该作者
没看明白楼主对两个赋值语句的解释

使用特权

评论回复
17
wowu| | 2023-11-7 20:57 | 只看该作者
st的有哪些方面的规定呢?会影响到哪方面的灵活性呀

使用特权

评论回复
18
guanjiaer| | 2023-11-7 21:51 | 只看该作者
l63t89 发表于 2023-10-27 12:10
如果只有一个B = u32Baudrate;就会跳过???????

所以我多写了一个B = u32Baudrate;

直接省略掉第一个赋值不就可以了吗

使用特权

评论回复
19
八层楼| | 2023-11-7 22:22 | 只看该作者
波特率不同误差率也不同 那么如何判定当前的误差率能可靠通讯呢

使用特权

评论回复
20
晓伍| | 2023-11-7 22:51 | 只看该作者
在什么情况下会发生接收超时的现象呢

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

90

主题

798

帖子

1

粉丝