STM32笔记2:建库操作之点亮LED

秉火系列视频之F429开发板————挑战者

侵删

/**新建工程模板
	建库之点亮LED灯
**/

#include "stm32f4xx.h"
//总线
#define PERIPH_BASE				((unsigned int)0x40000000)
#define AHB1PERIPH_BASE			 (PERIPH_BASE+0x00020000)			 
#define GPIOH_BASE				(AHBPERIPH_BASE+0x00001c00)			 


#define GPIOH_MODER				*(unsigned int*)(GPIOH_BASE+0x00)	 
#define GPIOH_ODR				*(unsigned int*)(GPIOH_BASE+0x14)	 
#define RCC_BASE				(AHB1PERIPH_BASE+0X00003800)
#define RCC_AHB1ENR			    *(unsigned int *)(RCC_BASE+0x30)		 

int main(void)
{
	RCCAHB1PERIPH_BASE |= (1<<7);
	 
	GPIOH_MODER &= ~(3<<2*10); 
	GPIOH_MODER |= (1<<2*10); 
	
	//PH10输出低电平
	GPIOH_ODR &= ~(1<<10); 
	while(1);
}

void  SystemInit(void)
{
	
}

下面是我的一堆乱七八糟的解析:

/**新建工程模板
	建库之点亮LED灯
**/

#include "stm32f4xx.h"
//总线
#define PERIPH_BASE				((unsigned int)0x40000000)
#define AHB1PERIPH_BASE			 (PERIPH_BASE+0x00020000)			//AHB1PERIPH_BASE基于总线偏移
#define GPIOH_BASE				(AHBPERIPH_BASE+0x00001c00)			//GPIOH_BASE基于AHB1总线偏移

#define GPIOH_MODER				*(unsigned int*)(GPIOH_BASE+0x00)	//GPIOH_MODER寄存器基于GPIOH基地址的偏移//(unsigned int*)(GPIOH_BASE+0x00)强制指针转换,意义:将该整数转化为一个地址
#define GPIOH_ODR				*(unsigned int*)(GPIOH_BASE+0x14)	//括号外的*号可以放在第16行,17,20行的寄存器前面//*GPIOH_ODR = (unsigned int*)(GPIOH_BASE+0x14)			
//外设基地址 :PERIPH_BASE    ->总线基地址:APB1PERIPH_BASE		->GPIO外设基地址: GPIOA_BASE	 ->寄存器基地址 :GPIOH_ODR 
#define RCC_BASE				(AHB1PERIPH_BASE+0X00003800)
#define RCC_AHB1ENR			    *(unsigned int *)(RCC_BASE+0x30)		//访问一个绝对地址把一个整型数强制转换为一个指针是合法的
																		//*(int *)(0x67a9) = 0xaa55; 或者这样写:
																		//int *ptr;		ptr = (int *)0x67a9;
int main(void)
{
	RCCAHB1PERIPH_BASE |= (1<<7);
	//STM32为了降低功耗,刚开始上电复位时,每个外设始终都是关闭的
	//PH10配置为输出
	//Q1:清零 ?ANS:与零与
	//Q2:置1 ? ANS:与1或	:如果是两位,则操作受原来该位数据影响(假如两位为10,想要变成01,那么单纯的10与01相或不能时结果变为01.),所以为了实现置1操作,先清零,再与1或。
	//总结:
	将寄存器的某一位eg:GPIOH_ODR清零,与该位与0相与GPIOH_ODR &= ~(1<<10),GPIOH_ODR置1,该位与1相或GPIOH_ODR |= (1<<10)。
	将寄存器的某两位eg:GPIOH_MODER变为00时,即清零型,			将该两位与11或之后再取反		
	//								  01时,即置1型,			将该两位清零GPIOH_MODER &= ~(3<<2*10),再与1左移X位的值相或。
	//								  10时,即置1型,			将该两位清零GPIOH_MODER &= ~(3<<2*10),再与1左移X位的值相或。
	//								  11时,即置1型,			将该两位清零GPIOH_MODER &= ~(3<<2*10),再与3左移X位的值相或。
	
	GPIOH_MODER &= ~(3<<2*10);
	GPIOH_MODER |= (1<<2*10);
	
	//PH10输出低电平
	GPIOH_ODR &= ~(1<<10); 
	while(1);
}

void  SystemInit(void)
{
	
}

// 逻辑左移时,最高位丢失,最低位补0;
// 逻辑右移时,最高位补0,最低位丢失;
// 算术左移时,依次左移一位,尾部补0,最高的符号位保持不变。
// 算术右移时,依次右移一位,尾部丢失,符号位右移后,原位置上复制一个符号位;
// 循环左移时,将最高位重新放置最低位
// 循环右移时,将最低位重新放置最高位
// 1010100010101  逻辑左移一位结果为  0101000101010
// 逻辑右移一位结果为 0101010001010
// 算术左移一位结果为 1101000101010
// 算术右移一位结果为 1101010001010
// 循环左移一位结果为 0101000101011
// 循环右移一位结果为 1101010001010

//关于双重指针的问题:

 *(unsigned int*)(0x4002 1C14) = 0xFFFF;
 0x4002 1C14 在我们看来是 GPIOH 端口 ODR 的地址,但是在编译器看来,这只是一
个普通的变量,是一个立即数,要想让编译器也认为是指针,我们得进行强制类型转换,
把它转换成指针,即(unsigned int *)0x4002 1C14,然后再对这个指针进行 * 操作

/* 控制 GPIOH 引脚 10 输出低电平(BSRR 寄存器的 BR10 置 1) */
*(unsigned int *)GPIOH_BSRR = (0x01<<(16+10));
 
/* 控制 GPIOH 引脚 10 输出高电平(BSRR 寄存器的 BS10 置 1) */
*(unsigned int *)GPIOH_BSRR = 0x01<<10;

unsigned int temp;
/* 控制 GPIOH 端口所有引脚的电平(读 IDR 寄存器) */
temp = *(unsigned int *)GPIOH_IDR;

使用 (unsigned int *) 把 GPIOH_BSRR 宏的数值强制转换成了地址,然后再用
“*”号做取指针操作,对该地址的赋值,从而实现了写寄存器的功能。同样,读寄存器也
是用取指针操作,把寄存器中的数据取到变量里,从而获取 STM32 外设的状态

猜你喜欢

转载自blog.csdn.net/qq_34471646/article/details/81100944
今日推荐