在keil5中实现STM32f407流水灯点亮

一、keil5中编写启动文件
在使用keil5时,如果没有提前选择好自带的启动文件,是需要我们自己写启动文件代码的,这里不针对讲解启动文件,只是放出代码供大家参考!

Stack_size EQU	0x200
	
	AREA my_stack,NOINIT,READWRITE,ALIGN=3
Stack_mem		
	SPACE Stack_size	
Stack_end	

	
	PRESERVE8		
	IMPORT 		main   ;导入我们将写的C代码函数
		
	AREA RESET,DATA,READONLY 
isr_addr
	DCD		Stack_end   
	DCD		__start		  
						
	SPACE 	0x400		
		
	AREA my_text,CODE,READONLY
__start		PROC			
	

二、编写C语言代码
1、在编写C语言代码之前,我们要先了解一下stm32f407开发板的原理图以及参考手册了解各个引脚所表示的含义;
2、既然是点亮我们的LED灯,首先我们得找到LED在开发板上的位置以及了解引脚的走线;
在keil5中实现STM32f407流水灯点亮_第1张图片
原理图中直接搜索LED,可以看到LED的结构,从图中我们可以的得到的结论是,四个LED灯左边全部连接在一个3.3V的VDD上,所以四个LED灯是共阳极,所以当我们右边的引脚得到低电平的时候,LED将被点亮!
在keil5中实现STM32f407流水灯点亮_第2张图片
搜索LED0可以看到在CPU上对应的引脚是PF9
依次类推分别可以得到
LED0 -> PF9
LED1 -> PF10
LED2 ->PE13
LED3 ->PE14

我们人在生活中需要心脏的跳动,机器也是一样的,所以,我们首先需要的是时钟使能
在keil5中实现STM32f407流水灯点亮_第3张图片
由图片可知,要PF、PE可以使用,我们首先得使RCC寄存器的第四位和第五位置1
偏移地址:0x10

寄存器地址 = 基址 + 偏移
在keil5中实现STM32f407流水灯点亮_第4张图片
由图可知,RCC的基址为0x40023800
我们还将使用到的有GPIOE、 GPIOF他们的基址分别为0x40021000、0x40021400
使能代码段:

volatile unsigned long  * pf_rcc = *(0x40023800 + 0x10) ;  //定义RCC寄存器的地址
unsigned long m;
m = *pf_rcc;
m |= 1<<4;            //将第四位置1(GPIOE使能)
m |= 1<<5;			  //将第五位置1(GPIOF使能)
*pf_rcc = m;

设置好时钟使能以后,我们在使用引脚的过程中,会选择端口模式
在keil5中实现STM32f407流水灯点亮_第5张图片
在这个过程中,我们是通过输出高低电平来控制灯的亮灭,所以这里选择的是输出模式;
此时由图可知:[2y][2y+1] = [1][0]
由以上图可以偏移地址为:0x00
选择输出模式代码段

	volatile unsigned long  * pf_mode = *(0x40021000 + 0x00) ;   //GPIOE_MODER的地址
	unsigned long m;
	m = *pf_mode;
	m &= ~(1<<27);     //2y+1位置0   -> PE13
	m |= 1<<26;		   //2y位置1 -> PE13

	m &= ~(1<<29);	   //2y+1位置0   -> PE14
	m |= 1<<28;	       //2y位置1 -> PE14
	*pf_mode = m;

	volatile unsigned long  * pf_mod = *(0x40021400 + 0x00) ;   //GPIOF_MODER的地址
	m = * pf_mod;
	m &= ~(1<<19);     //2y+1位置0   -> PF9
	m |= 1<<18;		   //2y位置1 -> PF9

	m &= ~(1<<21);     //2y+1位置0   -> PF10
	m |= 1<<20;		   //2y位置1 -> PF10
	 * pf_mod = m;
	

设置好模式以后,我们需要的是GPIO的输出类型
当我们的GPIO口输出高电平(1)的时候灯是灭的,输出低电平(0)的时候灯是亮的。

在keil5中实现STM32f407流水灯点亮_第6张图片

由此我们可以知道:
GPIOF_ODR[9] = 0; —> PF9 ->LED0得到是低电平 ->点亮
GPIOF_ODR[10] = 0; —> PF10 ->LED1得到是低电平 ->点亮
GPIOE_ODR[13] = 0; —> PE13 ->LED2得到是低电平 ->点亮
GPIOE_ODR[14] = 0; —> PE14 ->LED3得到是低电平 ->点亮

GPIOF_ODR[9] = 1; —> PF9 ->LED0得到是低电平 ->熄灭
GPIOF_ODR[10] = 1; —> PF10 ->LED1得到是低电平 ->熄灭
GPIOE_ODR[13] = 1; —> PE13 ->LED2得到是低电平 ->熄灭
GPIOE_ODR[14] = 1; —> PE14 ->LED3得到是低电平 ->熄灭

相关代码:

volatile unsigned long  * pf_odr = *(0x40021000 + 0x14) ;   //GPIOE_ODR的地址
unsigned long r;
r = *pf_odr;

r |= 1<<13;       //设置GPIOE_ODR[13]  = 1  ,此时PE13 -> LED2灯灭


r &= ~(1<<13);    //设置GPIOE_ODR[13]  = 0  ,此时PE13 -> LED2灯亮

*pf_odr = r;

其他的LED灯配置类似,可以自己先尝试着写一下完整的代码。
在设置过程中,我们还可以设置输出速率,感兴趣的可以自己去看一下相关文档自己写一下代码!

为了方便观看,就没写头文件,把所有的函数全部直接写在一起了!


#include

#define adda_base 0x40020000
#define adde_base 0x40021000
#define addf_base 0x40021400
#define addclock_base 0x40023800
#define offset_mode   0x00
#define offset_otype  0x04
#define offset_odr    0x14
#define offset_idr    0x10
#define offset_rcc	  0x30
#define addr  volatile unsigned long

#define pf_rcc   (addr *)(addclock_base + offset_rcc)
#define pf_modeF (addr *)(addf_base + offset_mode) 
#define pf_modeE (addr *)(adde_base + offset_mode)
#define pf_odrE  (addr *)(adde_base + offset_odr)
#define pf_odrF  (addr *)(addf_base + offset_odr)

void delay()     //延时函数、延时的时间可以自己改
{
	int i;
	for(i=0;i<1000000;i++);
	
}

void led_init(void)
{
	unsigned long r ;
	/* 使能GPIO分组时钟 */
	
	r = *pf_rcc;
	r |= 1<<5;       //使能GPIOF组时钟
	r |= 1<<4;		 //使能GPIOE组时钟
	*pf_rcc = r;
	
	/* 配置GPIO引脚模式 */

	r = *pf_modeF;
	r &= ~(1<<19);				//PF9配置为输出模式 GPIOF_MODER[19:18]  = 01
	r |= 1<<18;
	
	r &= ~(1<<21);				//PF10配置为输出模式 GPIOF_MODER[21:20] = 01
	r |= 1<<20;
	
	*pf_modeF = r;				


	r = *pf_modeE;
	r &= ~(1<<27);				//PF9配置为输出模式 GPIOF_MODER[19:18]  = 01
	r |= 1<<26;
	
	r &= ~(1<<29);				//PF10配置为输出模式 GPIOF_MODER[21:20] = 01
	r |= 1<<28;
	
	*pf_modeE = r;	
}

	void LED_UP_E(int x)          //控制E组LED灯的亮        
	{
		unsigned long r = 0;
		r = *pf_odrE;
		r &= ~(1<<x);			 
		*pf_odrE = r;
	}

	void LED_DOWN_E(int x)         //控制E组LED灯的灭
	{
		unsigned long r = 0;
		r = *pf_odrE;
		r |= 1<<x;			 
		*pf_odrE = r;
	}
	
	void LED_UP_F(int x)         //控制F组LED灯的亮    
	{
		unsigned long r = 0;
		r = *pf_odrF;
		r &= ~(1<<x);			 
		*pf_odrF = r;
	}

	void LED_DOWN_F(int x)         //控制F组LED灯的亮    
	{
		unsigned long r = 0;
		r = *pf_odrF;
		r |= 1<<x;			 
		*pf_odrF = r;
	}

int main()
{
	//使能
	 led_init();
	 while(1)
	 {
	 		//led0点亮
	 		LED_UP_F(9);
	 		//延时
	 		delay();
	 		//led0熄灭
	 		LED_DOWN_F(9);
	 		
			//led1点亮
	 		LED_UP_F(10);
	 		//延时
	 		delay();
	 		//led1熄灭
	 		LED_DOWN_F(10);
	
			//led2点亮
	 		LED_UP_E(13);
	 		//延时
	 		delay();
	 		//led2熄灭
	 		LED_DOWN_E(13);

			//led3点亮
	 		LED_UP_E(14);
	 		//延时
	 		delay();
	 		//led3熄灭
	 		LED_DOWN_E(14);
			delay();
			 
	 }
	
}

代码没有使用头文件,所以看起来有点乱,感兴趣的可以自己封装一下,这是一步一步看原理图学习的一个过程,中间有什么不对或者遗漏的地方还请见谅,学到后面的话我们可以使用STM32的官方库,如果有幸看到此篇文章,感谢你的观看,希望能帮到你!

你可能感兴趣的:(stm32)