请选择 进入手机版 | 继续访问电脑版

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

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

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

6 u/ h7 z' ?2 |; v一、嵌入式中位操作一些常见用法1、一个32bit数据的位、字节读取操作
(1)获取单字节:
#define GET_LOW_BYTE0(x)    ((x >>  0) & 0x000000ff)    /* 获取第0个字节 */( c7 s1 H. Y. F8 ]4 a$ }7 S' G
#define GET_LOW_BYTE1(x)    ((x >>  8) & 0x000000ff)    /* 获取第1个字节 */
* c; i# e9 @/ g7 e- P) X#define GET_LOW_BYTE2(x)    ((x >> 16) & 0x000000ff)    /* 获取第2个字节 */
8 h& c# {2 I# [+ D#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
& i/ ?$ p# {4 @; A
2、一个32bit数据的位、字节清零操作
(1)清零某个字节:
#define CLEAR_LOW_BYTE0(x)  (x &= 0xffffff00)   /* 清零第0个字节 */. J& Z! O1 ?# p% A" Q* a
#define CLEAR_LOW_BYTE1(x)  (x &= 0xffff00ff)   /* 清零第1个字节 */
; n; l; f; |5 ]6 f& \' ~#define CLEAR_LOW_BYTE2(x)  (x &= 0xff00ffff)   /* 清零第2个字节 */6 L* ]6 N; `( c9 W+ d. n1 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
4 o+ x6 `) W1 {1 l% C
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

5 W1 ^$ G( q2 d4 f4、判断某一位或某几位连续位的值
(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数据的一些操作进行总结,其它位数的数据类似,可根据需要进行修改。

1 ~- P/ I: R8 L1 w4 G: S二、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:以上笔记中如有错误,欢迎指出!谢谢

. f8 g, {8 S; t' Z- [. Z
021.png
022.png
1 收藏 6 评论8 发布时间:2019-11-27 23:31

举报

8个回答
aiherong 回答时间:2019-11-28 03:31:11
对位操作的提取不能单靠左右移位(运行速度会有影响),有时就得与或非运算,另外记下常用外设接口地址# {4 n9 D( U- n1 T( m4 x
对你决定走这条路有好处
李康1202 回答时间:2019-11-28 09:17:57
每次写寄存器都是翻着手册去写的
mizhinian 回答时间:2019-11-28 09:58:18
aiherong 发表于 2019-11-28 03:31
, x& V# E8 D; |7 ~; \对位操作的提取不能单靠左右移位(运行速度会有影响),有时就得与或非运算,另外记下常用外设接口地址+ X" m, X5 s: v' w* p0 z
对你 ...

" M8 v$ Y6 c- \0 G9 b; p多谢!受教了
mizhinian 回答时间:2019-11-28 09:58:57
likang1202 发表于 2019-11-28 09:17, Z( Z5 Z9 f' M6 V# ?8 \2 @
每次写寄存器都是翻着手册去写的

7 a2 ~* O: l; V+ z0 C翻手册是个好习惯呀
子曰好人 回答时间:2019-11-28 10:05:34
楼主这个风格是在mac下写代码,在Windows下编译?
mizhinian 回答时间:2019-11-28 23:56:01
子曰好人 发表于 2019-11-28 10:051 Q* F7 }# x9 M
楼主这个风格是在mac下写代码,在Windows下编译?
2 S' Q! z& t2 {  t
哈哈 没那么闲  只不过是渲染一下代码  让代码好看些。在这可以渲染代码: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:562 q5 q. q% O& q$ X7 ]
哈哈 没那么闲  只不过是渲染一下代码  让代码好看些。在这可以渲染代码:http://carbon.now.sh/?bg=rgb ...
' c9 _9 k; n  u( `# i9 A2 J
好吧,确实挺好看的,楼主有心了
lcz17569507 回答时间:2019-12-6 08:54:14
总结到位!支持!

所属标签

相似分享

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版