你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

STM32寄存器配置、位操作的一些用法归纳

[复制链接]
mizhinian 发布时间:2019-11-27 23:31
对于STM32芯片的使用,之前一直用库函数来进行配置,最近发现直接配置寄存器有时候好像也挺容易的,而且可读性也不会很差。下面分享关于寄存器配置的一些笔记:

, D3 |3 w  C6 l3 w

* W' L& h0 z1 Z; z. _一、嵌入式中位操作一些常见用法1、一个32bit数据的位、字节读取操作
(1)获取单字节:
#define GET_LOW_BYTE0(x)    ((x >>  0) & 0x000000ff)    /* 获取第0个字节 */
* t0 k9 s1 [- }#define GET_LOW_BYTE1(x)    ((x >>  8) & 0x000000ff)    /* 获取第1个字节 */* A" U4 A4 a6 x4 {
#define GET_LOW_BYTE2(x)    ((x >> 16) & 0x000000ff)    /* 获取第2个字节 */* Y0 Z/ K/ ?8 w" M7 j9 K8 h2 _2 E
#define GET_LOW_BYTE3(x)    ((x >> 24) & 0x000000ff)    /* 获取第3个字节 */
示例:
001.png
002.png
(2)获取某一位:
#define GET_BIT(x, bit) ((x & (1 << bit)) >> bit)   /* 获取第bit位 */
示例:
003.png
004.png
) |2 `) f4 U+ g# q! v/ u/ \( ?
2、一个32bit数据的位、字节清零操作
(1)清零某个字节:
#define CLEAR_LOW_BYTE0(x)  (x &= 0xffffff00)   /* 清零第0个字节 */" ~( i0 W# J9 T5 V% l* ^. t, ~
#define CLEAR_LOW_BYTE1(x)  (x &= 0xffff00ff)   /* 清零第1个字节 */
) d$ j) z) ?9 q9 ?( w, b3 I#define CLEAR_LOW_BYTE2(x)  (x &= 0xff00ffff)   /* 清零第2个字节 */
' w) v. g! n, }. U- L5 G#define CLEAR_LOW_BYTE3(x)  (x &= 0x00ffffff)   /* 清零第3个字节 */
示例:
005.png
006.png
(2)清零某一位:
#define        CLEAR_BIT(x, bit)        (x &= ~(1 << bit))        /* 清零第bit位 */
示例:
=======007
=======008
: f0 t% W' E  b% a+ C. m$ @) v
3、一个32bit数据的位、字节置1操作
(1)置某个字节为1:
#define        SET_LOW_BYTE0(x)        (x |= 0x000000ff)        /* 第0个字节置1 */        #define        SET_LOW_BYTE1(x)        (x |= 0x0000ff00)        /* 第1个字节置1 */        #define        SET_LOW_BYTE2(x)        (x |= 0x00ff0000)        /* 第2个字节置1 */        #define        SET_LOW_BYTE3(x)        (x |= 0xff000000)        /* 第3个字节置1 */
示例:
009.png
010.png
(2)置位某一位:
#define        SET_BIT(x, bit)        (x |= (1 << bit))        /* 置位第bit位 */
011.png
012.png
. ?: C% K+ H) b2 I$ ]
4、判断某一位或某几位连续位的值
(1)判断某一位的值
举例说明:判断0x68第3位的值。
013.png
014.png
也就是说,要判断第几位的值,if里就左移几位(当然别过头了)。在嵌入式编程中,可通过这样的方式来判断寄存器的状态位是否被置位。
(2)判断某几位连续位的值
/* 获取第[n:m]位的值 */#define BIT_M_TO_N(x, m, n)  ((unsigned int)(x << (31-(n))) >> ((31 - (n)) + (m)))
示例:
015.png
016.png
这是一个查询连续状态位的例子,因为有些情况不止有0、1两种状态,可能会有多种状态,这种情况下就可以用这种方法来取出状态位,再去执行相应操作。
以上是对32bit数据的一些操作进行总结,其它位数的数据类似,可根据需要进行修改。

5 F8 ~1 K6 B9 |. j5 e7 t二、STM32寄存器配置
STM32有几套固件库,这些固件库函数以函数的形式进行1层或者多层封装(软件开发中很重要的思想之一:分层思想),但是到了最里面的一层就是对寄存器的配置。我们平时都比较喜欢固件库来开发,大概是因为固件库用起来比较简单,用固件库写出来的代码比较容易阅读。最近一段时间一直在配置寄存器,越发地发现使用寄存器来进行一些外设的配置也是很容易懂的。使用寄存器的方式编程无非就是往寄存器的某些位置1、清零以及对寄存器一些状态位进行判断、读取寄存器的内容等。
这些基本操作在上面的例子中已经有介绍,我们依旧以实例来巩固上面的知识点(以STM32F1xx为例):
(1)寄存器配置
看一下GPIO功能的端口输出数据寄存器  (GPIOx_ODR) (x=A..E)  :
017.png
假设我们要让PA10引脚输出高、输出低,可以这么做:
方法一:
GPIOA->ODR |= 1 << 10;      /* PA10输出高(置1操作) */GPIOA->ODR &= ~(1 << 10);  /* PA10输出低(清0操作) */
也可用我们上面的置位、清零的宏定义:
SET_BIT(GPIOA->ODR, 10);    /* PA10输出高(置1操作) */CLEAR_BIT(GPIOA->ODR, 10);  /* PA10输出低(清0操作) */
方法二:
GPIOA->ODR |= (uint16_t)0x0400;   /* PA10输出高(置1操作) */GPIOA->ODR &= ~(uint16_t)0x0400;  /* PA10输出低(清0操作) */
貌似第二种方法更麻烦?还得去细心地去构造一个数据。
但是,其实第二种方法其实是ST推荐我们用的方法,为什么这么说呢?因为ST官方已经把这些我们要用到的值给我们配好了,在stm32f10x.h中:
018.png
这个头文件中存放的就是外设寄存器的一些位配置。
所以我们的方法二等价于:
GPIOA->ODR |= GPIO_ODR_ODR10;   /* PA10输出高(置1操作) */GPIOA->ODR &= ~GPIO_ODR_ODR10;  /* PA10输出低(清0操作) */
两种方法都是很好的方法,但方法一似乎更好理解。
配置连续几位的方法也是一样的,就不介绍了。简单介绍配置不连续位的方法,以TIM1的CR1寄存器为例:
019.png
设置CEN位为1、设置CMS[1:0]位为01、设置CKD[1:0]位为10:
TIM1->CR1 |= (0x1 << 1)| (0x1 << 5) |(0x2 << 8);
这是组合的写法。当然,像上面一样拆开来写也是可以的。
(2)判断标志位
以状态寄存器(USART_SR) 为例:
020.png
判断RXNE是否被置位:
/* 数据寄存器非空,RXNE标志置位 */if (USART1->SR & (1 << 5)){        /* 其它代码 */        USART1->SR &= ~(1 << 5);  /* 清零RXNE标志 */}
或者:
/* 数据寄存器非空,RXNE标志置位 */if (USART1->SR & USART_SR_RXNE){        /* 其它代码 */        USART1->SR &= ~USART_SR_RXNE;  /* 清零RXNE标志 */}
END:以上笔记中如有错误,欢迎指出!谢谢
2 _+ S* S, [4 g/ l! S
021.png
022.png
1 收藏 6 评论8 发布时间:2019-11-27 23:31

举报

8个回答
aiherong 回答时间:2019-11-28 03:31:11
对位操作的提取不能单靠左右移位(运行速度会有影响),有时就得与或非运算,另外记下常用外设接口地址
' s, [! G0 [9 X- h# t8 H9 y# z对你决定走这条路有好处
李康1202 回答时间:2019-11-28 09:17:57
每次写寄存器都是翻着手册去写的
mizhinian 回答时间:2019-11-28 09:58:18
aiherong 发表于 2019-11-28 03:31' d) z# n6 ?4 q/ c# t# S* e
对位操作的提取不能单靠左右移位(运行速度会有影响),有时就得与或非运算,另外记下常用外设接口地址8 k3 {! v4 ]- ]+ U" q& B. \
对你 ...

/ I* b% P- T/ Z0 [9 D多谢!受教了
mizhinian 回答时间:2019-11-28 09:58:57
likang1202 发表于 2019-11-28 09:176 D* I: d9 X, S
每次写寄存器都是翻着手册去写的
6 R, h+ Q7 Y* |( o: w4 o
翻手册是个好习惯呀
子曰好人 回答时间:2019-11-28 10:05:34
楼主这个风格是在mac下写代码,在Windows下编译?
mizhinian 回答时间:2019-11-28 23:56:01
子曰好人 发表于 2019-11-28 10:05
- T' [% j6 M/ R' ~1 [4 I% d楼主这个风格是在mac下写代码,在Windows下编译?
3 q8 i* C  `% |' ]
哈哈 没那么闲  只不过是渲染一下代码  让代码好看些。在这可以渲染代码:http://carbon.now.sh/?bg=rgba(48%2C12%2C66%2C0.88)&t=lucario&wt=none&l=text%2Fx-csrc&ds=true&dsyoff=20px&dsblur=68px&wc=true&wa=true&pv=56px&ph=56px&ln=false&fm=Hack&fs=14px&lh=133%25&si=false&es=2x&wm=false
子曰好人 回答时间:2019-11-29 09:02:34
mizhinian 发表于 2019-11-28 23:568 G; P5 H  t2 g2 s% W9 u3 G: G
哈哈 没那么闲  只不过是渲染一下代码  让代码好看些。在这可以渲染代码:http://carbon.now.sh/?bg=rgb ...

0 s1 L/ I, P9 B% p% X5 |+ L9 H  c好吧,确实挺好看的,楼主有心了
lcz17569507 回答时间:2019-12-6 08:54:14
总结到位!支持!

所属标签

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版