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;
}
系统时钟(Hz) | PCLK分频 | 串口时钟分频 | DIV(DIV_INTEGER) | 是否大于0xFF |
200M | 2 | 4 | 325.52 | 是 |
200M | 2 | 16 | 80.38 | 否 |
200M | 2 | 64 | 19.34 | 否 |
100M | 2 | 1 | 650.04 | 是 |
100M | 2 | 4 | 162.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。