GD32单片机的位带操作说明

4 篇文章 2 订阅
4 篇文章 0 订阅

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在使用国产单片机GD32系列单片机,使用固件库编程的时候,经常遇到程序中的位带操作,固件库对寄存器每个关键位都进行的定义,例如:对时钟配置寄存器 0 (RCU_CFG0)某一位操作的话,直接对该寄存器进行位带操作就可以对某位写1或0。下面详细讲解,让你不再烦恼。


一、位带操作

1. 位带操作就是对某一位或是某连续的位进行操作,如下:

#define BIT(x)                       ((uint32_t)((uint32_t)0x01U<<(x)))
#define BITS(start, end)             ((0xFFFFFFFFUL << (start)) & (0xFFFFFFFFUL >> (31U - (uint32_t)(end))))

第一个是对寄存器的某一位写1操作,使用1<<x位,其余位都为0。那具体怎么用呢?
还是对RCU_CFG0寄存器进行操作,比如对第17位进行操作
在这里插入图片描述
写1: RCU_CFG0 |= BIT(17);
写0: RCU_CFG0 &= ~ BIT(17);
如果操作多个不连续的位:
写1: RCU_CFG0 |= (BIT(17) | BIT(13) | BIT(13));
写0: RCU_CFG0 &= ~ (BIT(17) | BIT(13) | BIT(13));

2.连续的位操作

RCU_CFG0 &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0);
    RCU_CFG0 |= (RCU_PLLSRC_HXTAL_IRC48M | RCU_CFG0_PREDV0);

    /* CK_PLL = (CK_HXTAL/2) * 30 = 120 MHz */
    RCU_CFG0 &= ~(RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4 | RCU_CFG0_PLLMF_5);
    RCU_CFG0 |= RCU_PLL_MUL30;
 

比如上面这些大家应该熟悉不过了,都是采用了位带操作。拿最后一句来看,进入RCU_PLL_MUL30后:

#define RCU_PLL_MUL26                   (PLLMF_4 | CFG0_PLLMF(9))           /*!< PLL source clock multiply by 26 */
#define RCU_PLL_MUL27                   (PLLMF_4 | CFG0_PLLMF(10))          /*!< PLL source clock multiply by 27 */
#define RCU_PLL_MUL28                   (PLLMF_4 | CFG0_PLLMF(11))          /*!< PLL source clock multiply by 28 */
#define RCU_PLL_MUL29                   (PLLMF_4 | CFG0_PLLMF(12))          /*!< PLL source clock multiply by 29 */
#define RCU_PLL_MUL30                   (PLLMF_4 | CFG0_PLLMF(13))          /*!< PLL source clock multiply by 30 */
#define RCU_PLL_MUL31                   (PLLMF_4 | CFG0_PLLMF(14))          /*!< PLL source clock multiply by 31 */
#define RCU_PLL_MUL32                   (PLLMF_4 | CFG0_PLLMF(15))          /*!< PLL source clock multiply by 32 */
#define RCU_PLL_MUL33                   (PLLMF_5 | CFG0_PLLMF(0))           /*!< PLL source clock multiply by 33 */
#define RCU_PLL_MUL34                   (PLLMF_5 | CFG0_PLLMF(1))           /*!< PLL source clock multiply by 34 */
#define RCU_PLL_MUL35                   (PLLMF_5 | CFG0_PLLMF(2))           /*!< PLL source clock multiply by 35 */
#define RCU_PLL_MUL36                   (PLLMF_5 | CFG0_PLLMF(3))           /*!< PLL source clock multiply by 36 */
#define RCU_PLL_MUL37                   (PLLMF_5 | CFG0_PLLMF(4))           /*!< PLL source clock multiply by 37 */
#define RCU_PLL_MUL38                   (PLLMF_5 | CFG0_PLLMF(5))           /*!< PLL source clock multiply by 38 */
#define RCU_PLL_MUL39                   (PLLMF_5 | CFG0_PLLMF(6))           /*!< PLL source clock multiply by 39 */

可以看到有很多倍频的选择,以后都可能会用到,我们现在只看30倍频的配置方法:后面是两个语句的或运算,进入可以看到语句的定义

#define PLLMF_4                         RCU_CFG0_PLLMF_4                    /* bit 4 of PLLMF */
#define RCU_CFG0_PLLMF_4                BIT(27)                   /*!< bit 4 of PLLMF */
#define CFG0_PLLMF(13)              (BITS(18,21) & ((uint32_t)(13) << 18))

现在可以知道一个是对PLLMF的第四位置1和对RCU_CFG0的18到21位置1并与13<<18求与,结果就是
在这里插入图片描述
是不是现在理解变得很容易,不放心可以自己动手算一下。

3.其它位操作

#define REG32(addr)                  (*(volatile uint32_t *)(uint32_t)(addr))
#define REG16(addr)                  (*(volatile uint16_t *)(uint32_t)(addr))
#define REG8(addr)                   (*(volatile uint8_t *)(uint32_t)(addr))
#define GET_BITS(regval, start, end) (((regval) & BITS((start),(end))) >> (start))

前面三个是获取某个寄存器的值,返回32,16,8位值

 case SEL_PLL:
        /* PLL clock source selection, HXTAL, IRC48M or IRC8M/2 */
        pllsel = (RCU_CFG0 & RCU_CFG0_PLLSEL);

        if(RCU_PLLSRC_HXTAL_IRC48M == pllsel){
            /* PLL clock source is HXTAL or IRC48M */
            pllpresel = (RCU_CFG1 & RCU_CFG1_PLLPRESEL);
            
            if(RCU_PLLPRESRC_HXTAL == pllpresel){
                /* PLL clock source is HXTAL */
                ck_src = HXTAL_VALUE;
            }else{
                /* PLL clock source is IRC48 */
                ck_src = IRC48M_VALUE;
            }

比如在这段代码里: pllsel = (RCU_CFG0 & RCU_CFG0_PLLSEL);其中RCU_CFG0就是获取该寄存器的值再做与运算。

最后一个还不清楚具体怎么用,有知道的可以指教一下。

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亚特兰蒂斯MQ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值