关于STM32 BSRR寄存器的问题

用GPIO作为八位数据的并口,之前是连续的GPIO口,比如说GPIOE的高八位或者低八位作为数据的并口,我可以这么写GPIOE->BSRR = 0XFF000000 | (data<<8),这样就可以把八位数据一次性赋值给对应的I/O。

但是现在把硬件上的GPIO分开了,也就是说PE0对应data数据的第0位,PG15对应data数据的第一位等等。那么现在就不能直接一下把八位数据分别给GPIO,需要一位一位的处理,这就出现了BSRR的寄存器用法。

官方手册是这么说的:

位 31:16 BRy: 端口 x 复位位 y (Port x reset bit y) (y = 0..15)
这些位为只写形式,只能在字、半字或字节模式下访问。读取这些位可返回值 0x0000。
0:不会对相应的 ODRx 位执行任何操作
1:对相应的 ODRx 位进行复位
注意: 如果同时对 BSx 和 BRx 置位,则 BSx 的优先级更高


位 15:0 BSy: 端口 x 置位位 y (Port x set bit y) (y= 0..15)
这些位为只写形式,只能在字、半字或字节模式下访问。读取这些位可返回值 0x0000。
0:不会对相应的 ODRx 位执行任何操作
1:对相应的 ODRx 位进行置位
第一个问题:这些位为只写形式,只能在字、半字或字节模式下访问?

起初我是这么理解的,配置BSRR寄存器必须只能是字、半字或字节的形式,其他的不行。然后我在网上查关于这个信息发现,所谓的访问模式是寄存器本身的属性与怎么配置没有关系!这里涉及到寄存器内存地址是否对齐的知识。那么到底我们给寄存器配置的是字节还是字或者半字呢,我认为应该和编译器有关系,如果强制转换成u8那应该是字节,u16,u32应该和编译器有关系。那么默认到底是什么呢,这个也不太清楚。。

第二个问题:高16位和低16位到底怎么操作才能达到我想要的效果呢?

我比较笨,这个问题困扰了我两天。因为一直理解错了,大错特错了。当你操作寄存器的时候,你总会担心把其他的位给冲掉而影响其他的GPIO正常工作,这说明我压根就不了解BSRR这个寄存器。官方已经写出了位31:16:0:不会对相应的 ODRx 位执行任何操作,1:对相应的 ODRx 位进行复位。首先是寄存器看着看着就错了。起初我是这么理解的我把BSRR看成了ODRx,因为一般的寄存器直接赋值会吧其他的位给冲掉,从而影响正常工作,所以我就这么写了GPIOE->BSRR |=(1 << 17)|((( data & 0x01 )>> 0 ) << 1);反正我也不懂啥意义,我先或了再说。可想而知肯定不对啊。主要的原因是,我并没有真正的去理解这个BSRR。

然后开始上网查资料,我发现BSRR寄存器到最后还是归结到ODR寄存器上面,这个时候就会知道我有多么的不走心了。官方下面就这么清楚的字写着,对相应的ODR寄存器进行置位或者复位,可是我还是走偏了,悔啊~~~

所以我把之前的想法推翻之后开始重新操作寄存器。

以下内容我在网上找的,总结的很好:

1.置高置低
需要置1的端口对应的位,在低16位里置1 ,高16位里0/1都可以,为0的时候,该对应的端口(ODRx)为不动作,如果是1的话那就要复位,但是如果低16位也是1,根据同时对BSx和BRx置位,则BSx的优先级更高。所以也还是对端口置1.

2.置GPIOB->BSRR低16位的某位为'1',则对应的I/O端口置'1';而置GPIOB->BSRR低16位的某位为'0',则对应的I/O端口不变。 

3.置GPIOB->BSRR高16位的某位为'1',则对应的I/O端口置'0';而置GPIOB->BSRR高16位的某位为'0',则对应的I/O端口不变。 
需要置0的端口对应的位,在高16位里置1, 低16位里只能是0,如果是1的话,该端口还是要被置1.
不改变的,都置0. 
然后写寄存器BSRR 

比如 要同时设置PB1 ,PB4,PB7,PB9为高电平,PB11,PB13,PB14,PB15为低电平,那么就可以这么设置:

GPIOB->BSRR = 0xE800 0292;

高16: 1  1  1  0 | 1  0  0  0 | 0  0  0  0 |0  0  0  0

低16: 0  0  0  0 | 0  0  1  0 | 1  0  0  1 |0  0  1  0

ODR:   0  0  0  x | 0  x  1  x | 1  x  x  1  |x  x  1  x

分析:1.同时高16位为0和低16位为0,对相应的端口不操作。

           2.对11.13.14.15口置0,则BSRR高16位中相应的I/O置1,低16相应位置0;

           3:对1.4.7.9口置1,则BSRR低16位中相应的I/O置1,高16位相应位置0;

           4.如果高16位相应位为1,低16位相应位1,则ODRx相应位为1;

弄清楚了BSRR寄存器的使用,我开始把八位数据data分别写入到GPIO如下:

GPIOA->BSRR =(1 << 17)|((( data & 0x01 )>> 0 ) << 1);//PA1-DB0

GPIOA->BSRR =(1 << 16)|((( data & 0x02 )>> 1 ) << 0);//PA0-DB1 
GPIOB->BSRR =(1 << 24)|((( data & 0x04 )>> 2 ) << 8);//PB8-DB2
GPIOB->BSRR =(1 << 23)|((( data & 0x08 )>> 3 ) << 7);//PB7-DB3
GPIOC->BSRR =(1 << 22)|((( data & 0x10 )>> 4 ) << 6);//PC6-DB4
GPIOC->BSRR =(1 << 21)|((( data & 0x20 )>> 5 ) << 5);//PC5-DB5    
GPIOD->BSRR =(1 << 31)|((( data & 0x40) >> 6 ) << 15);//PD15-DB6 
GPIOD->BSRR =(1 << 30)|((( data & 0x80 )>> 7 ) << 14);//PD14-DB7

经过在线仿真查看ODR寄存器对应的位值和输入的data的值是一样的,说明数据data的八位数据DB0-DB7是能够一一写入的。这样算不算成功呢?还得让各位大神帮忙给分析一下。。。

猜你喜欢

转载自blog.csdn.net/weixin_40049164/article/details/82622358