本帖最后由 warship 于 2018-7-16 19:56 编辑
在原子例程的sys.h中,使用宏定义建立了位带操作的基础,
使得操作IO端口可以像51一样实现位操作。
其实深入了解了位带操作的原理,几乎就可以实现对STM32所有外设寄存器的访问,
极端情况下,什么库函数版本,什么寄存器版本都可以不用,直接精准地操控所有寄存器的每一位的读写!!!
知道了STM32将所有外设寄存器的每一位都建立了位带别名区,
你只要再花一点点时间,彻底搞明白下面的三句宏定义,位带操作就都不在话下了:
#define
BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define
MEM_ADDR(addr) *((volatile unsigned long *)(addr))
#define
BIT_ADDR(addr, bitnum) MEM_ADDR(BITBAND(addr, bitnum))
************************************************************************************************
注:本文后文所探索的寄存器位段操作宏定义包含在另文所附范例(外部中断试验的工程包)中,并随时更新。
有需要研究探讨的网友,可移步下载http://www.openedv.com/forum.php ... d=274724&extra=
有道理,一般人可以不用研究,
但官方的库还是要讲究效率的,个人觉得。
但是没有关系,可以采取操作单一比特时用位带,两个以上时仍读写整个寄存器的混合编程方式。
我试着对原子寄存器版本中的系统时钟初始化函数局部使用位带操作进行改写。
原版是:
void Stm32_Clock_Init(u8 PLL)
{
unsigned char temp=0;
MYRCC_DeInit(); //复位并配置向量表
RCC->CR|=0x00010000; //外部高速时钟使能HSEON
while(!(RCC->CR>>17));//等待外部时钟就绪
RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
PLL-=2; //抵消2个单位(因为是从2开始的,设置0就是2)
RCC->CFGR|=PLL<<18; //设置PLL值 2~16
RCC->CFGR|=1<<16; //PLLSRC ON
FLASH->ACR|=0x32; //FLASH 2个延时周期
RCC->CR|=0x01000000; //PLLON
while(!(RCC->CR>>25));//等待PLL锁定
RCC->CFGR|=0x00000002;//PLL作为系统时钟
while(temp!=0x02) //等待PLL作为系统时钟设置成功
{
temp=RCC->CFGR>>2;
temp&=0x03;
}
}
说道寄存器位寻找,好像有一回我用位寻址设置和清除 TIMER的CEN,结果老是出错(大部分时候也对)。(关键有时候要单脉冲,有时候不需要单脉冲,就是想着需要单脉冲只要把单脉冲位赋值一次,后面就不管这个位,只要赋值cen就启动)。后来还是用CR1整体赋值就不出错了。也没时间查查为什么。
那可能是别名地址没有计算正确,
对照寄存器基址、偏移量和比特位,
编出一份别名地址宏定义的头文件后,
就是想出错也不容易的,哈哈。
一周热门 更多>