7、LED实验

1、工程文件夹介绍。
①USER:用户代码。
mainc主函数。
system_stm32f10x.c系统时钟相关配置(SystemInit函数定义)。
stm32f10x_it.c中断服务函数。
②HARDWARE:外设驱动。
led.c 发光二极管驱动。
beep.c 蜂鸣器驱动。

③SYSTEM:正点原子提供代码。
delay.c 滴答延迟函数。
sys.c IO口位操作。
usart.c 串口函数。
④CORE:内核代码。内核文件和启动文件。
⑤FWLib 固件库。ST提供的外设驱动库文件。
⑥README 说明文件。readme.txt。

2、GPIO相关寄存器。
GPIO端口对应的库函数以及相关定义在文件stm32f10x_gpio.c和stm32f10x_gpio.h中。
① GPIO重命名和宏定义。
GPIOA宏定义,GPIO结构体类型定义

typedef struct
{
  __IO uint32_t CRL;
  __IO uint32_t CRH;
  __IO uint32_t IDR;
  __IO uint32_t ODR;
  __IO uint32_t BSRR;
  __IO uint32_t BRR;
  __IO uint32_t LCKR;
} GPIO_TypeDef;    //定义GPIO结构体类型,每个GPIO有连续7个32位寄存器,

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)
	//GPIO_BASE是GPIOA的初始地址,强制转换为GPIO结构体指针类型,
	//代码中使用宏定义"GPIOA"代替GPIO结构体指针,GPIOA是结构体指针,
	//使用结构体成员变量时,结构形式可以是GPIOA->CRL或者(*GPIOA).CRH,
	//库函数常用GPIOA.CRL。

GPIO初始化结构体类型定义

typedef struct
{
  uint16_t GPIO_Pin;    //引脚号
  GPIOSpeed_TypeDef GPIO_Speed;    //引脚输出速度
  GPIOMode_TypeDef GPIO_Mode;    //引脚模式
}GPIO_InitTypeDef;    //定义结构体初始化类型

  GPIO_InitTypeDef GPIO_InitStructure;   //定义结构体初始化变量
  //使用结构体成员变量时,结构形式是GPIO_InitStructure.GPIO_Pin

//引脚号是16位无符号整型,宏定义如下:
#define GPIO_Pin_0		((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1		((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2		((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3		((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4		((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5		((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6		((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7		((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8		((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9		((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10		((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11		((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12		((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13		((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14		((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15		((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All	((uint16_t)0xFFFF)  /*!< All pins selected */

//引脚输出速度是枚举类型,定义如下:

typedef enum
{ 
  GPIO_Speed_10MHz = 1,
  GPIO_Speed_2MHz, 
  GPIO_Speed_50MHz
}GPIOSpeed_TypeDef;    //枚举元素(或枚举变量)之间用逗号隔开

//引脚模式时枚举类型,定义如下:

typedef enum
{ 
	GPIO_Mode_AIN = 0x0,    //模拟输入
	GPIO_Mode_IN_FLOATING = 0x04,    //浮空输入
	GPIO_Mode_IPD = 0x28,    //下拉输入
	GPIO_Mode_IPU = 0x48,    //上拉输入
	GPIO_Mode_Out_OD = 0x14,    //开漏输出
	GPIO_Mode_Out_PP = 0x10,    //推挽输出
	GPIO_Mode_AF_OD = 0x1C,    //开漏复用
	GPIO_Mode_AF_PP = 0x18    //推挽复用
}GPIOMode_TypeDef;    

②GPIO寄存器:
CRHCRL配置寄存器,两个32位,每4位控制一个引脚,32/4*2=16。
这里写图片描述
IDRODR数据寄存器,IDR输入数据寄存器、ODR输出数据寄存器。
BSRR 位置位清零寄存器,低16位设置1则置位对应的引脚,高16位设置为1则清零对应的引脚。
BRR 位清零寄存器,低16位设置1则清零对应的引脚。
LCKR 端口锁存寄存器,锁定CRH和CRL对应位。
③GPIO函数。
GPIO_Init(); //初始化
GPIO_ReadInputDataBit(); //读引脚
GPIO_Write(); //写ODR输出数据寄存器
GPIO_SetBits(); //写引脚为1
GPIO_ResetBits(); //写引脚为0

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStructure);
//配置IO模式和速度,第一个参数是GPIO结构体指针,取值范围GPIOA~GPIOG,
//第二个参数是GPIO结构体初始化指针,结构体初始化类型为GPIO_InitTypeDef。
GPIO_InitTypeDef GPIO_InitStructure;	//定义GPIO结构体初始化变量
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;	//引脚号为5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;	//模式为推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	//输出速度50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);	//初始化IO

uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//读取IO口的电平,第一个参数是GPIO结构体指针,第二个参数是引脚号,
//返回值是1(Bit_SET)或者0(Bit_RESET)。
GPIO_ReadInputDataBit(GPIOA, Pin_5);    //读GPIOA.5电平

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
//设置IO口的电平,第一个参数是GPIO结构体指针,第二个参数是16位无符号整型,
//用于设置GPIOx的所有引脚的电平
GPIO_Write(GPIOA, 3);	//设置GPIOA.0和GPIOA.1为1,其他位为0

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//设置引脚为1,第一个参数是GPIO结构体指针,第二个参数是16位无符号整型
GPIO_SetBits(GPIOA, GPIO_Pin_5);	//GPIOA.5设置为1

void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
//设置引脚为0,第一个参数是GPIO结构体指针,第二个参数是16为无符号整型
GPIO_ResetBits(GPIOA, GPIO_Pin_5);	//GPIOA.5设置为0

④GPIO操作步骤。
使能IO口时钟。 RCC_APB2ReriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE)
初始化IO口参数。 GPIO_Init(GPIOA, &GPIO_InitStructure)
操作IO口。 GPIO_SetBits(GPIOA, GPIO_Pin_5) 、GPIO_ResetBits(GPIOA, GPIO_Pin_5)

3、代码实现。
LED实验用到的固件库如下:
stm32f10x_gpio.c/.h //GPIO的操作需要使用
stm32f10x_rcc.c/.h //系统失踪配置等
misc.c/.h //NVIC配置等,SYSTEM文件会用到
stm32f10x_usart.c/usart.h //串口的配置等,SYSTEM文件会用到

//LED初始化
void LED_Init(void)	
{
	GPIO_InitTypeDef GPIO_InitStructure;    //定义GPIO初始化结构体变量
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE, ENABLE);    //使能GPIOB和GPIOE的时钟
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;    //引脚5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;    //模式推挽输出
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;    //速度50MHz
	GPIO_Init(GPIOB, &GPIO_InitStructure);    //初始化IO口模式
	GPIO_SetBits(GPIOB, GPIO_Pin_5);
		
	GPIO_Init(GPIOE, &GPIO_InitStructure);
	GPIO_SetBits(GPIOE, GPIO_Pin_5);	
}

//APB2时钟使能函数如下:
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
{
  //检查两个参数
  assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph));
  assert_param(IS_FUNCTIONAL_STATE(NewState));
  if (NewState != DISABLE)    //ENABLE时使能时钟,DISABLE时失能时钟
  {
    RCC->APB2ENR |= RCC_APB2Periph;
  }
  else
  {
    RCC->APB2ENR &= ~RCC_APB2Periph;
  }
}
//APB2时钟设置函数的第一个参数如下,是一些宏定义:
#define RCC_APB2Periph_AFIO              ((uint32_t)0x00000001)
#define RCC_APB2Periph_GPIOA             ((uint32_t)0x00000004)
#define RCC_APB2Periph_GPIOB             ((uint32_t)0x00000008)
#define RCC_APB2Periph_GPIOC             ((uint32_t)0x00000010)
#define RCC_APB2Periph_GPIOD             ((uint32_t)0x00000020)
#define RCC_APB2Periph_GPIOE             ((uint32_t)0x00000040)
#define RCC_APB2Periph_GPIOF             ((uint32_t)0x00000080)
#define RCC_APB2Periph_GPIOG             ((uint32_t)0x00000100)
#define RCC_APB2Periph_ADC1              ((uint32_t)0x00000200)
#define RCC_APB2Periph_ADC2              ((uint32_t)0x00000400)
#define RCC_APB2Periph_TIM1              ((uint32_t)0x00000800)
#define RCC_APB2Periph_SPI1              ((uint32_t)0x00001000)
#define RCC_APB2Periph_TIM8              ((uint32_t)0x00002000)
#define RCC_APB2Periph_USART1            ((uint32_t)0x00004000)
#define RCC_APB2Periph_ADC3              ((uint32_t)0x00008000)
#define RCC_APB2Periph_TIM15             ((uint32_t)0x00010000)
#define RCC_APB2Periph_TIM16             ((uint32_t)0x00020000)
#define RCC_APB2Periph_TIM17             ((uint32_t)0x00040000)
#define RCC_APB2Periph_TIM9              ((uint32_t)0x00080000)
#define RCC_APB2Periph_TIM10             ((uint32_t)0x00100000)
#define RCC_APB2Periph_TIM11             ((uint32_t)0x00200000)
//APB2时钟设置函数的第二个参数如下,是枚举类型:
typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState;

//GPIO初始化函数如下:
void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
    //定义五个变量,currentmode当前模式,current当前引脚,pos位置,tmpreg中间寄存器,pinmask引脚掩码
  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  uint32_t tmpreg = 0x00, pinmask = 0x00;
  //检查两个参数
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_MODE(GPIO_InitStruct->GPIO_Mode));
  assert_param(IS_GPIO_PIN(GPIO_InitStruct->GPIO_Pin));  
  //当前模式取GPIO_Mode_TypeDef枚举类型的低四位
  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
  //判断模式的第五位是否为1,
  //是1说明输出模式,需要判断输出频率并把输出频率设置到当前模式currentmode,
  //不是1说明书输入模式,频率设置的两位不需要操作,默认0即可。
  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)    
  { 
    //IO口为输出模式时,判断输出频率,并把输出频率设置到当前模式currentmode
    assert_param(IS_GPIO_SPEED(GPIO_InitStruct->GPIO_Speed));
    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
  }
//CRL寄存器的设置
  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)    //引脚有低八位需要设置
  {
    tmpreg = GPIOx->CRL;    //CRL寄存器赋值给中间寄存器tmpreg
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)    //引脚号从0到7
    {
      pos = ((uint32_t)0x01) << pinpos;    //位置等于左移引脚号的位置
      //引脚号为0,左移0位,pos=0x0001
      //引脚号为1,左移1位,pos=0x0002
      currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;    
      //引脚号与位置后赋值给当前引脚currentpin
      if (currentpin == pos)    //当前引脚等于位置
      {
        pos = pinpos << 2;    //位置pos等于引脚号乘以4,引脚号等于0,位置等于0,设置CRL的低四位
        pinmask = ((uint32_t)0x0F) << pos;    //置一CRL对应的控制位,赋值给pinmask引脚掩码
        tmpreg &= ~pinmask;    //pinmask取反并与中间寄存器tmpreg,赋值给中间寄存器tmpreg
        tmpreg |= (currentmode << pos);    //当前模式左移0、4...等赋值给中间寄存器
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)    //输入下拉,操作清零寄存器进行清零,即对应ODR=0
        {
          GPIOx->BRR = (((uint32_t)0x01) << pinpos);
        }
        else
        {  
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)    //输入上拉,操作置位清零寄存器进行置一,对应ODR=1
          {
            GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
          }
        }
      }
    }
    GPIOx->CRL = tmpreg;    //for循环结束,中间寄存器赋值给CRL
  }
//CRH寄存器设置
  if (GPIO_InitStruct->GPIO_Pin > 0x00FF)    
  {
    tmpreg = GPIOx->CRH;    //CRH寄存器赋值给中间寄存器
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)    //引脚号0到7循环
    {
      pos = (((uint32_t)0x01) << (pinpos + 0x08));    //位置等于引脚号加八左移
	//引脚号0,左移8位,pos=0x0100
	//引脚号1,左移9位,pos=0x0200
      currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);    //引脚号与位置后赋值给当前引脚,操作的是pin8-pin15
      if (currentpin == pos)    //当前位置等于位置
      {
        pos = pinpos << 2;    //位置pos等于引脚号乘以4,引脚号等于0,位置等于0,设置CRH的低四位
        pinmask = ((uint32_t)0x0F) << pos;    //置一对应的控制位,赋值给引脚掩码
        tmpreg &= ~pinmask;    //引脚掩码取反后与中间寄存器,并赋值给中间寄存器
        //当前模式左移0、4...赋值给CRH
        tmpreg |= (currentmode << pos);
        //输入下拉,清零寄存器设置8、9...15位
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
        //输入上拉,置位清零寄存器设置8、9...15位
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
        {
          GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
      }
    }    //for循环结束,中间寄存器赋值给CRH
    GPIOx->CRH = tmpreg;
  }
}
//2018.9.9 LED实验工程,库函数版本page168
#include "led.h"
#include "delay.h"
#include "sys.h"

int main(void)
{
	delay_init();
	LED_Init();
	
	while(1)
	{
		//方法一:通过库函数操作引脚,设置LED的状态
//		GPIO_SetBits(GPIOB, GPIO_Pin_5);
//		GPIO_ResetBits(GPIOE, GPIO_Pin_5);
//		delay_ms(500);
//		GPIO_ResetBits(GPIOB, GPIO_Pin_5);
//		GPIO_SetBits(GPIOE, GPIO_Pin_5);
//		delay_ms(500);
		
		//方法二:通过位操作引脚,设置LED的状态
//		LED0 = 0;
//		LED1 = 1;
//		delay_ms(500);
//		LED0 = 1;
//		LED1 = 0;
//		delay_ms(500);
		
		//方法三:通过寄存器操作引脚,设置LED的状态
		GPIOB->BRR = GPIO_Pin_5;
		GPIOE->BSRR = GPIO_Pin_5;
		delay_ms(1000);
		GPIOB->BSRR = GPIO_Pin_5;
		GPIOE->BRR = GPIO_Pin_5;
		delay_ms(500);
	}
}

编译程序,build output提示program size:
代码占用FLASH大小为:Code+RO-data,所用SRAM大小为RW-data+ZI-data。
Code:程序所占FLASH的大小。
RO-data:read-only-data表示程序的常量,如const类型,占用FLASH。
RW-data:read write-data被初始化的全局变量,占用SRAM。
ZI-data:zero init-data未被初始化的全局变量,占用SRAM。
需要注意:程序的大小不是.hex文件的大小,而是编译后Code和RO-data之和。

4、软件仿真。
简单的代码可以进行软件仿真,步骤如下:
①设置MDK软件仿真,魔术棒–debug选择use simulator,如下图:
这里写图片描述
②点击debug,点击analysis windows,点击setup,如下图:
这里写图片描述
这里写图片描述
(PORTB&0x00000020)>>5:GPIOB.5右移5位,GPIOB.5是…0010 0000,右移5位后即…0001,结果为1则…0001,结果为1,则…0000。
③软件仿真结果如下:
这里写图片描述
这里写图片描述
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值