HC32F460串口波特率使用的问题

        1、解决

        由于项目有个加密芯片要使用到9600波特率的串口进行通讯,因此在使用HC32F460的时候发现如果将波特率设置为9600后输出的数据与原数据不符合。

(1)将系统时钟设置为100MHz,串口时钟4分频或者16分频。

(2)系统时钟不变,为200Mhz,串口时钟16分频或者64分频。

(3)也可以调整PCLK1总线的分频系数

//系统时钟配置
void BSP_CLK_Init(void)
{
    stc_clk_sysclk_cfg_t    stcSysClkCfg;
    stc_clk_xtal_cfg_t      stcXtalCfg;
    stc_clk_mpll_cfg_t      stcMpllCfg;
    stc_sram_config_t       stcSramConfig;

    MEM_ZERO_STRUCT(stcSysClkCfg);
    MEM_ZERO_STRUCT(stcXtalCfg);
    MEM_ZERO_STRUCT(stcMpllCfg);
    MEM_ZERO_STRUCT(stcSramConfig);

    /* Set bus clk div. */
    stcSysClkCfg.enHclkDiv  = ClkSysclkDiv1;
    stcSysClkCfg.enExclkDiv = ClkSysclkDiv2; //PCLK1总线分频系数
    stcSysClkCfg.enPclk0Div = ClkSysclkDiv1;
    stcSysClkCfg.enPclk1Div = ClkSysclkDiv2;
    stcSysClkCfg.enPclk2Div = ClkSysclkDiv4;
    stcSysClkCfg.enPclk3Div = ClkSysclkDiv4;
    stcSysClkCfg.enPclk4Div = ClkSysclkDiv2;
    CLK_SysClkConfig(&stcSysClkCfg);

    /* Config Xtal and Enable Xtal */
    stcXtalCfg.enMode = ClkXtalModeOsc;
    stcXtalCfg.enDrv = ClkXtalLowDrv;
    stcXtalCfg.enFastStartup = Enable;
    CLK_XtalConfig(&stcXtalCfg);
    CLK_XtalCmd(Enable);

    /* sram init include read/write wait cycle setting */
    stcSramConfig.u8SramIdx = Sram12Idx | Sram3Idx | SramHsIdx | SramRetIdx;
    stcSramConfig.enSramRC = SramCycle2;
    stcSramConfig.enSramWC = SramCycle2;
    SRAM_Init(&stcSramConfig);

    /* flash read wait cycle setting */
    EFM_Unlock();
    EFM_SetLatency(EFM_LATENCY_5);
    EFM_Lock();
    //             外部晶振
    /* MPLL config (XTAL / pllmDiv * plln / PllpDiv = 100M). */
    stcMpllCfg.pllmDiv = 1ul;
    stcMpllCfg.plln    = 50ul;
    stcMpllCfg.PllpDiv = 4ul;  //此处若是2分频,时钟为200M
    stcMpllCfg.PllqDiv = 4ul;
    stcMpllCfg.PllrDiv = 4ul;
    CLK_SetPllSource(ClkPllSrcXTAL);
    CLK_MpllConfig(&stcMpllCfg);

    /* Enable MPLL. */
    CLK_MpllCmd(Enable);
    /* Wait MPLL ready. */
    while(Set != CLK_GetFlagStatus(ClkFlagMPLLRdy))
    {
        ;
    }
    /* Switch driver ability */
    PWC_HS2HP();
    /* Switch system clock source to MPLL. */
    CLK_SetSysClkSource(CLKSysSrcMPLL);
}
//串口配置
const stc_usart_uart_init_t stcInitCfg = {
    UsartIntClkCkOutput,
    UsartClkDiv_4,            //对串口时钟进行4分频
    UsartDataBits8,
    UsartDataLsbFirst,
    UsartOneStopBit,
    UsartParityNone,
    UsartSampleBit8,
    UsartStartBitFallEdge,
    UsartRtsEnable,
  };

        2、问题分析

首先怀疑波特率的问题。于是找到波特率的函数。

/* 设置波特率 */
    USART_SetBaudrate(USART2_CH, 9600);

这个函数的原型是 

en_result_t USART_SetBaudrate(M4_USART_TypeDef *USARTx,
                                uint32_t u32Baudrate)
{
    en_result_t enRet = ErrorInvalidParameter;

    /* Check USARTx pointer */
    if (IS_VALID_USART(USARTx))
    {
        //根据数据手册,这条代码是判断是否为智能卡模式,按照配置没跳进这里
        if(1ul == USARTx->CR3_f.SCEN)       
        {
            enRet = SetScBaudrate(USARTx, u32Baudrate);
        }
        //这里我们配置的是串口模式,也没进这里
        else if(1ul == USARTx->CR1_f.MS)
        {
            enRet = SetClkSyncBaudrate(USARTx, u32Baudrate);
        }
        else
        {
            enRet = SetUartBaudrate(USARTx, u32Baudrate);
        }
    }

    return enRet;
}

根据数据手册这两个地方都没有进去,而进去了SetUartBaudrate函数

static en_result_t SetUartBaudrate(M4_USART_TypeDef *USARTx,
                                uint32_t u32Baudrate)
{
    uint32_t B = 0ul;
    uint32_t C = 0ul;
    uint32_t OVER8 = 0ul;
    float32_t DIV = 0.0f;
    uint64_t u64Tmp = 0u;
    uint32_t DIV_Integer = 0ul;
    uint32_t DIV_Fraction = 0xFFFFFFFFul;
    en_result_t enRet = ErrorInvalidParameter;

    /* 判断是否为串口 */
    if (IS_VALID_USART(USARTx))
    {
        /* 获取串口时钟 */
        C = UsartGetClk(USARTx);

        if (C > 0ul)
        {
            B = u32Baudrate;
            OVER8 = USARTx->CR1_f.OVER8;
            /* FBME = 0 Calculation formula */
            /* B = C / (8 * (2 - OVER8) * (DIV_Integer + 1)) */
            /* DIV_Integer = (C / (B * 8 * (2 - OVER8))) - 1 */
            DIV = ((float)C / ((float)B * 8.0f * (2.0f - (float)OVER8))) - 1.0f;
            DIV_Integer = (uint32_t)(DIV);

            if (!((DIV < 0.0f) || (DIV_Integer > 0xFFul)))
            {
                enRet = Ok;
                if ((DIV - (float32_t)DIV_Integer) > 0.00001f)
                {
                    /* FBME = 1 Calculation formula */
                    /* B = C * (128 + DIV_Fraction) / (8 * (2 - OVER8) * (DIV_Integer + 1) * 256) */
                    /* DIV_Fraction = ((8 * (2 - OVER8) * (DIV_Integer + 1) * 256 * B) / C) - 128 */
                    /* E = (C * (128 + DIV_Fraction) / (8 * (2 - OVER8) * (DIV_Integer + 1) * 256 * B)) - 1 */
                    /* DIV_Fraction = (((2 - OVER8) * (DIV_Integer + 1) * 2048 * B) / C) - 128 */
                    u64Tmp = (uint64_t)(((uint64_t)2ul - (uint64_t)OVER8) * ((uint64_t)DIV_Integer + 1ul) * (uint64_t)B);
                    DIV_Fraction = (uint32_t)(2048ul * u64Tmp / C - 128ul);
                    if (DIV_Fraction > 0x7Ful)
                    {
                        enRet = ErrorInvalidParameter;
                    }
                }

                if (Ok == enRet)
                {
                    USARTx->CR1_f.FBME = (DIV_Fraction > 0x7Ful) ? 0ul : 1ul;
                    USARTx->BRR_f.DIV_FRACTION = DIV_Fraction;
                    USARTx->BRR_f.DIV_INTEGER = DIV_Integer;
                }
            }
        }
    }

    return enRet;
}

如果时钟为200MHz,串口为64分频的的情况下计算出来的C值为1,562,500 

DIV计算的值为19.3450527,而如果串口时钟分频只有4分频,则结果如表1-1所示。

static uint32_t UsartGetClk(const M4_USART_TypeDef *USARTx)
{
    uint32_t u32PClk1 = 0ul;
    uint32_t u32UartClk = 0ul;

    /* Check USARTx pointer */
    DDL_ASSERT(IS_VALID_USART(USARTx));
    //             200000000    /    1<<1 = 100000000
    u32PClk1 = SystemCoreClock / (1ul << M4_SYSREG->CMU_SCFGR_f.PCLK1S);
    //             100000000 / 1<<2*3  = 1,562,500  (2ul * USARTx->PR_f.PSC=6,1<<6=64分频)
    u32UartClk = u32PClk1 / (1ul << (2ul * USARTx->PR_f.PSC));

    return u32UartClk;
}
表1-1
系统时钟(Hz)PCLK分频串口时钟分频DIV(DIV_INTEGER)是否大于0xFF
200M24325.52
200M21680.38
200M26419.34
100M21650.04
100M24162.76
//      1,562,500/(9600*8*(2-1))-1 = 19.3450527
DIV = ((float)C / ((float)B * 8.0f * (2.0f - (float)OVER8))) - 1.0f;
DIV_Integer = (uint32_t)(DIV);
//                         19.34>255(结果值取反if通过)
if (!((DIV < 0.0f) || (DIV_Integer > 0xFFul)))
{
    ....................
}

        那么问题来了,为什么会有一个0xFF的限制呢?我们首先看看波特率寄存器。以上计算出来的DIV_Integer会放USART_BRR寄存器中,USART_BRR寄存器8-15位放整数,0-6位放小数,由于整数部分只占了8位,所以不能超过0xFF。

  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值