STM32---点亮LED灯

一:编译第一个程序

int main()  //主函数
{
    
}

void SystemInit()  //在执行主函数前,会被调用。不进行实现。在启动文件中被调用
{
    
}
; Reset handler
Reset_Handler   PROC
                EXPORT  Reset_Handler             [WEAK]
                IMPORT  __main
                IMPORT  SystemInit
                LDR     R0, =SystemInit
                BLX     R0               
                LDR     R0, =__main
                BX      R0
                ENDP
启动文件:复位程序部分汇编代码

二:LED灯原理图

注意:其中PB0是绿灯

三:LED点亮--代码实现

(一)第一步:点亮LED灯PB0引脚绿灯,必须设置端口输出数据寄存器,使得其对应的引脚输出低电平,产生电压差。点亮绿灯

*(unsigned int*)(0x40010c0c) &= ~(1<<0);    

(二)第二步: 需要设置端口低寄存器,设置低八位0-7,设置为通用推挽输出模式,最大速度设置为10MHZ

*(unsigned int*)(0x40010c00) |= (1<<0);

开漏和推挽区别在于:
开漏:输出端相当于三极管的集电极,要得到高电平状态需要上拉电阻才行。 适合于做电流型的驱动,其吸收电流的能力相对强(一般20ma以内)。
推挽输出:可以输出高,低电平,连接数字器件。
开漏电路就是指以MOS FET的漏极为输出的电路。一般的用法是会在漏极外部的电路添加上拉电阻。完整的开漏电路应该由开漏器件和开漏上拉电阻组成。
推挽结构一般是指两个三极管分别受两互补信号的控制,总是在一个三极管导通的时候另一个截止
引入一句话:“复用输出当前的引脚功能功能有外设控制,并不由通用IO控制,因此你要通过操作GPIO来驱动LED的话,肯定是用通用的

  

速度可以随便选择

(三)第三步:设置外设GPIOB端口的时钟开启

*(unsigned int*)(0x40021018) |= (1<<3);

(四)全部代码

int main()
{
    *(unsigned int*)(0x40021018) |= (1<<3);
    
    *(unsigned int*)(0x40010c00) |= (1<<0);
    
    *(unsigned int*)(0x40010c0c) &= ~(1<<0);    
    
}

void SystemInit()
{
    
}

(五)实现状态

四:实现寄存器映射

(一)实现头文件

//用于存放STM32寄存器映射代码

//外设 perirhral
#define PERIRH_BASE         (unsigned int)0x40000000    //前面unsigned int表示的是地址是32位

#define APB1PERIRH_BASE    PERIRH_BASE
#define APB2PERIRH_BASE   (PERIRH_BASE+0x10000)
#define AHBPERIRH_BASE    (PERIRH_BASE+0x20000)

#define RCC_BASE            (AHBPERIRH_BASE+0x1000)
#define GPIOB_BASE          (APB2PERIRH_BASE+0x0c00)

#define RCC_APB2ENR         *(unsigned int*)(RCC_BASE+0x18)        //下面是实际要操作的IO口,使用*(unsigned int*)进行数据写入和读取
#define GPIOB_ODR           *(unsigned int*)(GPIOB_BASE+0x0c)
#define GPIOB_CRL           *(unsigned int*)(GPIOB_BASE+0x00)
#define GPIOB_CRH           *(unsigned int*)(GPIOB_BASE+0x04)

(二)对主函数改写

int main()
{
    //第三步:设置外设GPIOB端口的时钟开启
    RCC_APB2ENR |= (1<<3);
    
    //第二步: 需要设置端口低寄存器,设置低八位0-7,设置为通用推挽输出模式,最大速度设置为10MHZ//注意:配置模式是,需要先进行清零
    GPIOB_CRL &= ~(0x0f);    //清零
    GPIOB_CRL |= (1<<0);
    
    //第一步:点亮LED灯PB0引脚绿灯,必须设置端口输出数据寄存器,使得其对应的引脚输出低电平,产生电压差。点亮绿灯
    GPIOB_ODR &= ~(1<<0);    //只需要设置低16位即可
    
}

五:实现库函数初步 

(一)stm32F10x.h头文件,定义引脚

#ifndef _STM32F10X_H_
#define _STM32F10X_H_

#define PERIRH_BASE         (unsigned int)0x40000000    

#define APB1PERIRH_BASE  PERIRH_BASE
#define APB2PERIRH_BASE (PERIRH_BASE+0x10000)
#define AHBPERIRH_BASE  (PERIRH_BASE+0x20000)

#define RCC_BASE                (AHBPERIRH_BASE+0x1000)
#define GPIOB_BASE            (APB2PERIRH_BASE+0x0c00)

#define RCC_APB2ENR         *(unsigned int*)(RCC_BASE+0x18)       

#define GPIOB_CRL                *(unsigned int*)(GPIOB_BASE+0x00)
#define GPIOB_CRH                *(unsigned int*)(GPIOB_BASE+0x04)
#define GPIOB_IDR                *(unsigned int*)(GPIOB_BASE+0x08)
#define GPIOB_ODR                *(unsigned int*)(GPIOB_BASE+0x0c)
#define GPIOB_BSRR            *(unsigned int*)(GPIOB_BASE+0x10)
#define GPIOB_BRR                *(unsigned int*)(GPIOB_BASE+0x14)
#define GPIOB_LCKR            *(unsigned int*)(GPIOB_BASE+0x18)
    
typedef unsigned int uint32_t;
typedef unsigned short uint16_t;

typedef struct
{
    uint32_t CRL;
    uint32_t CRH;
    uint32_t IDR;
    uint32_t ODR;
    uint32_t BSRR;
    uint32_t BRR;
    uint32_t LCKR;
}GPIO_TypeDef;  

typedef struct
{
    uint32_t CR;
    uint32_t CFGR;
    uint32_t CIR;
    uint32_t APB2RSTR;
    uint32_t APB1RSTR;
    uint32_t AHBENR;
    uint32_t APB2ENR;
    uint32_t APB1ENR;
    uint32_t BDCR;
    uint32_t CSR;
}RCC_Def;

#define GPIOB ((GPIO_TypeDef*)GPIOB_BASE)
#define RCC ((RCC_Def*)RCC_BASE)

#endif

(二)stmF10x_gpio.h头文件用于实现GPIO类型口的相关声明和定义

#ifndef _STM32F10X_GPIO_H_
#define _STM32F10X_GPIO_H_

#include "stm32F10x.h"

#define GPIO_PIN_0 ((uint16_t)0x0001)
#define GPIO_PIN_1 ((uint16_t)0x0002)
#define GPIO_PIN_2 ((uint16_t)0x0004)
#define GPIO_PIN_3 ((uint16_t)0x0008)
#define GPIO_PIN_4 ((uint16_t)0x0010)
#define GPIO_PIN_5 ((uint16_t)0x0020)
#define GPIO_PIN_6 ((uint16_t)0x0040)
#define GPIO_PIN_7 ((uint16_t)0x0080)

#define GPIO_PIN_8 ((uint16_t)0x0100)
#define GPIO_PIN_9 ((uint16_t)0x0200)
#define GPIO_PIN_10 ((uint16_t)0x0400)
#define GPIO_PIN_11 ((uint16_t)0x0800)
#define GPIO_PIN_12 ((uint16_t)0x1000)
#define GPIO_PIN_13 ((uint16_t)0x2000)
#define GPIO_PIN_14 ((uint16_t)0x4000)
#define GPIO_PIN_15 ((uint16_t)0x8000)
#define GPIO_PIN_ALL ((uint16_t)0xFFFF)

typedef enum
{
    GPIO_Speed_10MHZ = 1,
    GPIO_Speed_2MHZ,
    GPIO_Speed_50MHZ
}GPIOSpeed_Typedef;

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

typedef struct
{
    uint16_t GPIO_Pin;
    uint16_t GPIO_Speed;
    uint16_t GPIO_Mode;
}GPIO_InitTypeDef;

void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin);
void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct);

#endif

(三)stmF10x_gpio.c实现头文件中的函数

#include "stm32F10x_gpio.h"

void GPIO_SetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
    GPIOx->BSRR |= GPIO_Pin;
}

void GPIO_ResetBits(GPIO_TypeDef* GPIOx,uint16_t GPIO_Pin)
{
    GPIOx->BRR |= GPIO_Pin;
}


void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
{
  uint32_t currentmode = 0x00, currentpin = 0x00, pinpos = 0x00, pos = 0x00;
  uint32_t tmpreg = 0x00, pinmask = 0x00;
  
/*---------------------- GPIO 模式配置 --------------------------*/
  // 把输入参数GPIO_Mode的低四位暂存在currentmode
  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x0F);
    
  // bit4是1表示输出,bit4是0则是输入 
  // 判断bit4是1还是0,即首选判断是输入还是输出模式
  if ((((uint32_t)GPIO_InitStruct->GPIO_Mode) & ((uint32_t)0x10)) != 0x00)
  { 
    // 输出模式则要设置输出速度
    currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
  }
/*-------------GPIO CRL 寄存器配置 CRL寄存器控制着低8位IO- -------*/
  // 配置端口低8位,即Pin0~Pin7
  if (((uint32_t)GPIO_InitStruct->GPIO_Pin & ((uint32_t)0x00FF)) != 0x00)
  {
    // 先备份CRL寄存器的值
    tmpreg = GPIOx->CRL;
        
    // 循环,从Pin0开始配对,找出具体的Pin
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
     // pos的值为1左移pinpos位
      pos = ((uint32_t)0x01) << pinpos;
      
      // 令pos与输入参数GPIO_PIN作位与运算,为下面的判断作准备
      currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
            
      //若currentpin=pos,则找到使用的引脚
      if (currentpin == pos)
      {
        // pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
        pos = pinpos << 2;
       //把控制这个引脚的4个寄存器位清零,其它寄存器位不变
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
                
        // 向寄存器写入将要配置的引脚的模式
        tmpreg |= (currentmode << pos);  
                
        // 判断是否为下拉输入模式
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          // 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
          GPIOx->BRR = (((uint32_t)0x01) << pinpos);
        }                
        else
        {
          // 判断是否为上拉输入模式
          if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
          {
            // 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
            GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
          }
        }
      }
    }
        // 把前面处理后的暂存值写入到CRL寄存器之中
    GPIOx->CRL = tmpreg;
  }
/*-------------GPIO CRH 寄存器配置 CRH寄存器控制着高8位IO- -----------*/
  // 配置端口高8位,即Pin8~Pin15
  if (GPIO_InitStruct->GPIO_Pin > 0x00FF)
  {
        // // 先备份CRH寄存器的值
    tmpreg = GPIOx->CRH;
        
    // 循环,从Pin8开始配对,找出具体的Pin
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = (((uint32_t)0x01) << (pinpos + 0x08));
            
      // pos与输入参数GPIO_PIN作位与运算
      currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
            
     //若currentpin=pos,则找到使用的引脚
      if (currentpin == pos)
      {
        //pinpos的值左移两位(乘以4),因为寄存器中4个寄存器位配置一个引脚
        pos = pinpos << 2;
        
        //把控制这个引脚的4个寄存器位清零,其它寄存器位不变
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
                
        // 向寄存器写入将要配置的引脚的模式
        tmpreg |= (currentmode << pos);
        
        // 判断是否为下拉输入模式
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          // 下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
          GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
         // 判断是否为上拉输入模式
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
        {
          // 上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
          GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
      }
    }
    // 把前面处理后的暂存值写入到CRH寄存器之中
    GPIOx->CRH = tmpreg;
  }
}

(四)主函数

#include "stm32F10x.h"
#include "stm32F10x_gpio.h"

#define LED_G_GPIO_CLK_ENABLE RCC->APB2ENR |= (1<<3)
#define LED_G_GPIO_PORT GPIOB
#define LED_G_GPIO_PIN    GPIO_PIN_0

void delay(uint32_t count)
{
        for(;count!=0;count--);
}

int main()
{
    GPIO_InitTypeDef GPIO_InitStructure;
    
    LED_G_GPIO_CLK_ENABLE;    //开启时钟
    
    GPIO_InitStructure.GPIO_Pin = LED_G_GPIO_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHZ;
    
    GPIO_Init(LED_G_GPIO_PORT,&GPIO_InitStructure);
    
    while(1)
    {
        GPIO_SetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);
        delay(0xFFFF);
        GPIO_ResetBits(LED_G_GPIO_PORT,LED_G_GPIO_PIN);
        delay(0xFFFF);
    }
    
}

void SystemInit()
{
    
}

 

转载于:https://www.cnblogs.com/ssyfj/p/11520223.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值