zoukankan      html  css  js  c++  java
  • STM32---喜提点灯

    一:编译第一个程序

    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()
    {
        
    }
  • 相关阅读:
    Java 运动模糊
    Efounds笔试
    Algorithms code
    Java 画图
    Java 笔记
    Java 对二值化图片识别连通域
    工厂模式
    数据库克隆
    SQL优化
    微信调起jssdk一闪而过
  • 原文地址:https://www.cnblogs.com/ssyfj/p/11520223.html
Copyright © 2011-2022 走看看