IMX6ULL串口波特率设置

看了IMX6ULL的串口波特率配置,感觉太麻烦了,虽然官方有配置波特率的函数,但是写的很繁琐不好理解,所以自己写了一个自由配置波特率的函数
这是IMX6ULL求波特率的公式

RH(G783EFV8ZUXR~IV8E1WM.png
通过公式知道求波特率需要确定三个寄存器的值

  1. Ref Rreq   设置串口时钟频率寄存器的值
  2. UBMR     设置 UARTx_UBMR 寄存器的值
  3. UBIR    设置 UARTx_UBIR 寄存器的值

其中Ref Rreq的值80MHZ为定值,Baud Rate是我们自己设置的波特率,我们只需要求(UBMR + 1 / UBIR + 1)的值
相当于求一个只有一个方程的二元一次方程,化简得:
( U B M R + 1 U B I R + 1 ) = R e f R r e q B a u d R a t e ∗ 16 (\frac{UBMR + 1}{UBIR + 1})=\frac{Ref Rreq}{Baud Rate *16} (UBIR+1UBMR+1)=BaudRate16RefRreq
所以问题就转换成已知一个小数求它的最简分数(知道了最简分数就可以通过分子分母的值来确定 UBMR + 1UBIR + 1 的值)的算法。这个算法有很多,我选择的是一个比较容易理解的

简单来说就是:一个数有一个斜率与与之对应(斜率无穷大在这个问题中不存在),我们要做的是找到一个分子分母来接近或者等于这个斜率。比如我们以 1 为初始分子, 2 为初始分母,然后我们将给定的小数与 0.5 比较,如果小于给定的小数(0.5 这条直线的斜在给定小数直线的斜率的下方),我们就加大分子,使得它的斜率增加到大于给定小数的斜率;如果大于给定的小数,我们就加大分母,使得它的斜率减小到给定小数斜率的下方;如果等于给定的小数说明这就是我们要求的值。但是大多数情况下是不会等于的,所以这个算法就会一直进行下去,直到满足我们的精度要求(我这里精确到小数点后六位就停止)

但还需要注意一点:UARTx_UBMRUARTx_UBIR 的 bit 0-15 是有效位,所以计算的分子分母不能超过65535,如果超过就降低精度,然后重新计算

 /* 设置ubir和ubmr寄存器 */
target = (float)80000000 / (float)(bound * 16);
fractions_to_decimals(&fra, &dec, target);
UARTX->UBIR = ((int)dec - 1);
UARTX->UBMR = ((int)fra - 1);


/**************************************************************/


/** 将小数转换成分数 
  * fra    分子
  *	dec	   分母
  * target 给定的小数
  **/
void fractions_to_decimals(float *fra, float *dec, float target)
{
    float result = 0.0f;
    float d_value = 0.0f;

    /* 精度设置 */
    float precision_l = 0.000000f;
    float precision_r = 0.000001f;

    /* 循环计算,直到满足条件退出 */
    while (1)
    {
        result = *fra / *dec;

        /* 如果大于target,分母就加1,减小result的值 */
        if (result > target)
        {
            *dec = *dec + 1.0f;
            result = *fra / *dec;
        }

        /* 如果小于target,分子就加1,加大result的值 */
        if (result < target)
        {
            *fra = *fra + 1.0f;
            result = *fra / *dec;
        }

        /* 将分子分母的值限定在65535范围内 */
        if ((*fra > 65535.0f) || (*dec > 65535.0f))
        {
            /* 分子分母超过65535就将精度减小,在重新计算 */
            precision_r = precision_r * 10;
            *fra = 1.0f;
            *dec = 2.0f;
            continue;
        }

        /* 检测精度是否符合条件,如果满足就退出循环,不满足就继续 */
        d_value = (result - target);
        if (d_value >= precision_l && d_value <= precision_r)
        {
            break;
        }
    }
}

如果直接将代码上传到板子中,会发现板子启动就会死机,这是因为我们使用了浮点运算,所以我们还需要开启硬件浮点支持,具体实现原理可参考正点原子教程

/* 使能硬件浮动运算 */
void imx6ul_hardfpu_enable(void)
{
    uint32_t cpacr;
    uint32_t fpexc;

    /* 使能NEON和FPU */
    cpacr = __get_CPACR();
    cpacr = (cpacr & ~(CPACR_ASEDIS_Msk | CPACR_D32DIS_Msk)) | (3UL << CPACR_cp10_Pos) | (3UL << CPACR_cp11_Pos);
    __set_CPACR(cpacr);
    fpexc = __get_FPEXC();
    fpexc |= 0x40000000UL;
    __set_FPEXC(fpexc);
}

这样代码就可以正常运行了。除了支持 9600、115200 等标准的波特率外,还支持非标准的波特率,如图:
}TF9AGC`0ZKH5PDG(($NTKM.png

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值