1.位带操作
在51单片机中,可以很方便的对单个IO口进行写入操作,
51单片机中:
按位操作,真正操作的的是类似于我们STM32中的ODR寄存器或者IDR寄存器中的单个bit。
p1.1=0;拉低
p1.1=1;拉高
在STM32单片机中外设地址部分:
外设的基地址:0x4000 0000
外设地址范围:0x4000 0000–0x4010 0000
0x4000 0000–0x4010 0000包含了我们所有的外设
以上外设地址保存的位置,我们成为位带区域
位带别名区:
为了模仿51单片机的操作,引入了位带别名区,位带区中的1Byte(字)对应别名去的4Byte。
STM32的单片机是32位,那么处理器处理速度最快的的话,就是一次处理32位的数据最快的,
单片机中都是按照字节寻址,一个地址(32位)对应1个字节,在位带区中的一个字节,在别名区就是4个字节,就是因为字节对齐的原因。
位带区域 别名区域
0x4000 0000 (1字节) 0x4200 0000(4字节)
0x4000 0001 0x4200 0004
0x4000 0002 0x4200 0008
A端口基地址:
0x4000 0000+0x10000+0x0800=0x4001 0800
A端口的ODR寄存器:
0x4001 0800+0x0c=0x4001 080c
A端口的IDR寄存器:
0x4001 0800+0x08
#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)) //addr--ODR或者IDR的基地址 bitnum--第几个IO口
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //
分析部分:
((addr & 0xF0000000)为了获得外设的基地址--0x4000 0000
(addr & 0xF0000000)+0x200 0000--别名区的基地址--0x4200 0000
(addr &0xFFFFF)<<5或者(addr &0xFFFFF)*8*4 将位带区的地址膨胀到别名区,此时addr还是IDR或者ODR的基地址
(bitnum<<2)或者(bitnum*4)--具体操作的IO偏移的位置,在别名区需要乘以4
位带源码部分:
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(87页~92页).
//IO口操作宏定义
#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))
//IO口地址映射
#define GPIOA_ODR_Addr (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr (GPIOF_BASE+12) //0x40011A0C
#define GPIOG_ODR_Addr (GPIOG_BASE+12) //0x40011E0C
#define GPIOA_IDR_Addr (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr (GPIOG_BASE+8) //0x40011E08
//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n) BIT_ADDR(GPIOA_ODR_Addr,n) //输出
#define PAin(n) BIT_ADDR(GPIOA_IDR_Addr,n) //输入
#define PBout(n) BIT_ADDR(GPIOB_ODR_Addr,n) //输出
#define PBin(n) BIT_ADDR(GPIOB_IDR_Addr,n) //输入
#define PCout(n) BIT_ADDR(GPIOC_ODR_Addr,n) //输出
#define PCin(n) BIT_ADDR(GPIOC_IDR_Addr,n) //输入
#define PDout(n) BIT_ADDR(GPIOD_ODR_Addr,n) //输出
#define PDin(n) BIT_ADDR(GPIOD_IDR_Addr,n) //输入
#define PEout(n) BIT_ADDR(GPIOE_ODR_Addr,n) //输出
#define PEin(n) BIT_ADDR(GPIOE_IDR_Addr,n) //输入
#define PFout(n) BIT_ADDR(GPIOF_ODR_Addr,n) //输出
#define PFin(n) BIT_ADDR(GPIOF_IDR_Addr,n) //输入
#define PGout(n) BIT_ADDR(GPIOG_ODR_Addr,n) //输出
#define PGin(n) BIT_ADDR(GPIOG_IDR_Addr,n) //输入
2.看门狗(独立看门狗)
在由单片机构成的微型计算机系统中,由于单片机的工作常常会受到来自外界电磁场的干扰,造成各种寄存器和内存的数据混乱,会导致程序指针错误,不在程序区,取出错误的程序指令等,都有可能会陷入死循环,程序的正常运行被打断,由单片机控制的系统无法继续正常工作,导致整个系统的陷入停滞状态,发生不可预料的后果。
看门狗,又叫 watchdog,从本质上来说就是一个定时器电路,一般有一个输入和一个输出,其中输入叫做喂狗,输出一般连接到另外一个部分的复位端,一般是连接到单片机。 看门狗的功能是定期的查看芯片内部的情况,一旦发生错误就向芯片发出重启信号。看门狗命令在程序的中断中拥有最高的优先级。
功能描述:
计数器计数方向:从上到下(从阈值开始,到0结束)
0Xfff递减计数,到0,如果还是没有喂狗,那么程序就要复位。
正常情况下,程序完整的执行一次的时间,假如正常情况程序执行一次,需要200ms,那么看门狗的计数时长,就需要大于200ms,那么我们就可以设置看门狗的计数时长为大于200ms,但是别写大于太多,300ms 400ms。
独立看门狗整体框图
时钟分频
void IWDG_Init(u8 prer,u16 rlr) //prer--4 rlr --625
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //使能对寄存器IWDG_PR和IWDG_RLR的写操作
IWDG_SetPrescaler(prer); //设置IWDG预分频值:设置IWDG预分频值为64
IWDG_SetReload(rlr); //设置IWDG重装载值
IWDG_ReloadCounter(); //按照IWDG重装载寄存器的值重装载IWDG计数器
IWDG_Enable(); //使能IWDG
}
注意:
debug调试代码的话,一定要先将看门狗注释,否则会一直复位,导致调试失败