STM32 LED实验代码 笔记

最近开始接触STM32F107VCT6这款ARM Cortex-M3核心的处理器了,实验采用的开发板是神舟IV。神舟IV光盘所带的资料挺完整,演示代码分两个版本,IAR的EWARM和KEIL的MDK版本。 环境所需要的工具什么的都有了,破解版。


首先先搭建好环境,我目前安装的是MDK 4.12  装好后打开源码工程,如下:

这里值得一提的是stm32f10x库封装的很好,很给力。


首先,因为我们将要操作的是LED灯,板载了5个,1个用于电源指示,可供IO口控制的只有4个,分别是LED1,LED2,LED3,LED4,电路图如下:

这些LED等连接到了主控的PD端口,了解了这些将有利于理解下面的代码部分。


系统结构如下:


STM32F107x内存映射如下:


GPIO 映射如下:



代码中用到的外设地址资料如下:

从上面的内存映射图可知,SDRAM_BASE是从0x20000000开始,PERIPH_BASE是 0x40000000开始。

    跟上面的GPIO寄存器映射一致。


GPIOD 端口对应的内存地址为: 0x40000000 + 0x10000 + 0x1400 = 0x40011400。

所有的GPIO端口都处于APB2总线,所以我们的代码在操作LED灯之前先配置APB2。


以下是对代码的分析:

#include "stm32f10x.h" //这个头文件很重要,里面定义了一些宏,管脚,寄存器等。
#include <stdio.h>


/* 
	#define RCC_APB2Periph_GPIOD		((uint32_t)0x00000020)
	#define GPIOD						((GPIO_TypeDef *) GPIOD_BASE)
		#define GPIOD_BASE				(APB2PERIPH_BASE + 0x1400)
		#define APB2PERIPH_BASE			(PERIPH_BASE + 0x10000)
		#define PERIPH_BASE				((uint32_t)0x40000000)
	#define GPIO_Pin_3                 ((uint16_t)0x0008)  
	#define GPIO_Pin_4                 ((uint16_t)0x0010) 
	#define GPIO_Pin_5                 ((uint16_t)0x0020)  
	#define GPIO_Pin_7                 ((uint16_t)0x0080) 
*/


#define RCC_GPIO_LED                                 RCC_APB2Periph_GPIOD
#define GPIO_LED_PORT                                GPIOD    
#define GPIO_LED1                                    GPIO_Pin_2    
#define GPIO_LED2                                    GPIO_Pin_3    
#define GPIO_LED3                                    GPIO_Pin_4    
#define GPIO_LED4                                    GPIO_Pin_7
#define GPIO_LED_ALL                                 GPIO_LED1 |GPIO_LED2 |GPIO_LED3 |GPIO_LED4 

/* 
	操作一个GPIO口,需要配置管脚,速率,以及模式 
	从电路图上可以看出,点亮一个LED灯只需将管脚对应的IO口拉低,反之则关闭LED 
	IO端口以P[A,B,C,D,...,]命名,对应的IO口为PX[0~15],如: PD0 ~ PD15
*/
void LED_config(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;
  /* Enable GPIOB, GPIOC and AFIO clock */    
  /* RCC_APB2ENR 的第五位是PD端口的使能位 0x200000, 而且是处在APB2总线上*/
  RCC_APB2PeriphClockCmd(RCC_GPIO_LED | RCC_APB2Periph_AFIO , ENABLE);  //RCC_APB2Periph_AFIO
 
  /* LEDs pins configuration */
  /* STM32的GPIO端口在作为输出时,配置端口的时钟速率分别为 2、10、50MHz*/
  GPIO_InitStructure.GPIO_Pin = GPIO_LED_ALL; /* 将实验所用的管脚选中 */
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; /* 配置时钟频率为50MHz ,至于为什么要这么大,暂时还不懂,呵呵*/
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; /* 这个是配置输出模式为推挽输出,既能输出高电平,也能是低电平 */
  GPIO_Init(GPIO_LED_PORT, &GPIO_InitStructure); /* 函数内部配置了对应IO口的输入输出模式和时钟速率 */
}

/*
#ifdef  USE_FULL_ASSERT   //如果定义了这个宏,出现断言错误,会调用assert_failed进行错误捕获。__FILE__ 会替换成当前文件,__LINE__ 是错误行
  #define assert_param(expr) ((expr) ? (void)0 : assert_failed((uint8_t *)__FILE__, __LINE__))
  void assert_failed(uint8_t* file, uint32_t line);
#else //如果没有定义这个宏,就什么都不做。
  #define assert_param(expr) ((void)0)
#endif 
*/
/*
stm32f10x_gpio.c 代码中实现
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
	//这个做法,我觉得挺好。在定义了USE_FULL_ASSERT时,能捕获错误。
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx)); 
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  
  //stm库将寄存器的操作封装成了C语言的结构操作,
  //GPIOx_BRR (bit reset register) 这个寄存器,是位复位寄存器,要将I/O管脚清0复位,只需要将对应的位赋值为1即可。
  //为了方便进行端口的位操作,STM32提供BRR BSRR之类的寄存器去操作ODR的对应位。也可以不这样去使用,直接操作 GPIOx_ODR 寄存器,
  //只是因为这个寄存器需要以字为单位进行访问。类似于51的方式。
  GPIOx->BRR = GPIO_Pin; 
}

//这个函数就是直接对端口进行操作
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)
{
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  
  GPIOx->ODR = PortVal;
}

//这个函数是将端口对应位置置位。
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  
  GPIOx->BSRR = GPIO_Pin; //置位/复位寄存器,高16位用于复位(清0),功能和BRR一样。低16位用于置位,对应的是PX0 ~ PX15
}
*/

void Led_Turn_on_all(void)
{
	/* Turn On All LEDs */
    GPIO_ResetBits(GPIO_LED_PORT, GPIO_LED_ALL); //
}

void Led_Turn_on_1(void)
{
	/* Turn On LED1 */
    GPIO_ResetBits(GPIO_LED_PORT, GPIO_LED1);
}

void Led_Turn_on_2(void)
{
	/* Turn On LED2 */
    GPIO_ResetBits(GPIO_LED_PORT, GPIO_LED2 );
}

void Led_Turn_on_3(void)
{
	/* Turn On LED3 */
    GPIO_ResetBits(GPIO_LED_PORT, GPIO_LED3);
}


void Led_Turn_on_4(void)
{
	/* Turn On LED3 */
    GPIO_ResetBits(GPIO_LED_PORT, GPIO_LED4);
}

void Led_Turn_off_all(void)
{
	/* Turn Off All LEDs */
    /* 将这些位拉高,就会关闭LED*/
    GPIO_SetBits(GPIO_LED_PORT, GPIO_LED_ALL);
}

void Led_Turn_on(u8 led)
{
    Led_Turn_off_all();

	/* Turn Off Select LED */
    switch(led)
    {
        case 0:
          Led_Turn_on_1();
          break;

        case 1:
          Led_Turn_on_2();
          break;

        case 2:
          Led_Turn_on_3();
          break;

        case 3:
          Led_Turn_on_4();
          break;
          
        default:
          Led_Turn_on_all();
          break;
    }
}

//这个函数是随便搞点循环进行延时操作
static void Delay_ARMJISHU(__IO uint32_t nCount)
{
  for (; nCount != 0; nCount--);
}

int main(void)
{
  u8 KeyNum = 0;

  LED_config();
  Led_Turn_on_all();
  Delay_ARMJISHU(6000000);
  Led_Turn_off_all();
  Delay_ARMJISHU(6000000);

  KeyNum=0;
  /* Main loop */
  while (1)
  {
      //Led_Turn_on_Hex(KeyNum);
      Led_Turn_off_all();
      Led_Turn_on(KeyNum%4); //从0~3不断变化
      KeyNum++;

      Delay_ARMJISHU(1000000);
  }  
}

//
#ifdef  USE_FULL_ASSERT
void assert_failed(uint8_t* file, uint32_t line)
{ 
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */

  /* Infinite loop */
  while (1)
  {
  }
}
#endif

按下 F7 进行编译,然后Ctrl + F5调试运行程序。开发板必须处在打开状态。


总结:

         1。操作GPIO端口,首先需要打开外设总线,这里是APB2总线。

         2。设置输入输出模式,速率。

         3。剩下的就是对GPIO进行输入输出的操作了。

         4。这里的所有操作都依赖于stm32f10x库,对于具体实现只是对寄存器操作的封装,以及内存地址的封装。

         5。这款主控对于IO的操作上与51有些区别,主要体现在端口位操作上,51没有类似于BSRR BRR可直接操作位的寄存器。


本人是新手,刚入手这板子,以上仅是个人学习的一些积累,错误在所难免。

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值