欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

STM32(一):各种方式点亮LED灯

程序员文章站 2022-06-09 08:25:35
...

STM32(一):各种方式点亮LED灯

led灯电路如上,所以PB0=0,绿灯亮,PB1=0,蓝灯亮,PB5=0,红灯亮

总共分三步    

  • 1.使能GPIOB的时钟
  • 2.将PB0,PB1,或PB5配置为输出引脚
  • 3.电平置零

1.   使能GPIOB的时钟


STM32(一):各种方式点亮LED灯STM32(一):各种方式点亮LED灯

STM32(一):各种方式点亮LED灯

           2.将PB0,PB1,或PB5配置为输出引脚


STM32(一):各种方式点亮LED灯

所以配置为B0001即可

3.电平置零

STM32(一):各种方式点亮LED灯

程序

 #ifndef STM32F10X_H
 #define STM32F10X_H
 
 #define uint16_t unsigned short
 #define uint32_t unsigned int
 
 /*片上外设基地址 */
 #define PERIPH_BASE ((uint32_t)0x40000000)


 /*总线基地址,GPIO 都挂载到 APB2 上 */
 #define APB2PERIPH_BASE (PERIPH_BASE + 0x10000)
 
 #define AHBPERIPH_BASE (PERIPH_BASE+0x18000)


 /*GPIOB 外设基地址*/
 #define GPIOB_BASE (APB2PERIPH_BASE + 0x0C00)


 /* GPIOB 寄存器地址,强制转换成指针 */
 #define GPIOB_CRL *(uint32_t*)(GPIOB_BASE+0x00)
 #define GPIOB_CRH *(uint32_t*)(GPIOB_BASE+0x04)
 #define GPIOB_IDR *(uint32_t*)(GPIOB_BASE+0x08)
 #define GPIOB_ODR *(uint32_t*)(GPIOB_BASE+0x0C)
 #define GPIOB_BSRR *(uint32_t*)(GPIOB_BASE+0x10)
 #define GPIOB_BRR *(uint32_t*)(GPIOB_BASE+0x14)
 #define GPIOB_LCKR *(uint32_t*)(GPIOB_BASE+0x18)
 /*RCC 外设基地址*/
 #define RCC_BASE 0x40021000
 /*RCC 的 AHB1 时钟使能寄存器地址,强制转换成指针*/
 #define RCC_APB2ENR *(uint32_t*)(RCC_BASE+0x18)
 
 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;




#define GPIOB   ((GPIO_TypeDef*)GPIOB_BASE)


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_TypeDef;


#define RCC     ((RCC_TypeDef*)RCC_BASE)




#endif //STM32F10X_H



#ifndef STM32F10X_GPIO_H
#define STM32F10X_GPIO_H


#include "stm32f10x.h"


#define GPIO_Pin_0    ((uint16_t)0x0001)  /*!< Ñ¡ÔñPin0 */    //(00000000 00000001)b
#define GPIO_Pin_1    ((uint16_t)0x0002)  /*!< Ñ¡ÔñPin1 */    //(00000000 00000010)b
#define GPIO_Pin_2    ((uint16_t)0x0004)  /*!< Ñ¡ÔñPin2 */    //(00000000 00000100)b
#define GPIO_Pin_3    ((uint16_t)0x0008)  /*!< Ñ¡ÔñPin3 */    //(00000000 00001000)b
#define GPIO_Pin_4    ((uint16_t)0x0010)  /*!< Ñ¡ÔñPin4 */    //(00000000 00010000)b
#define GPIO_Pin_5    ((uint16_t)0x0020)  /*!< Ñ¡ÔñPin5 */    //(00000000 00100000)b
#define GPIO_Pin_6    ((uint16_t)0x0040)  /*!< Ñ¡ÔñPin6 */    //(00000000 01000000)b
#define GPIO_Pin_7    ((uint16_t)0x0080)  /*!< Ñ¡ÔñPin7 */    //(00000000 10000000)b


#define GPIO_Pin_8    ((uint16_t)0x0100)  /*!< Ñ¡ÔñPin8 */    //(00000001 00000000)b
#define GPIO_Pin_9    ((uint16_t)0x0200)  /*!< Ñ¡ÔñPin9 */    //(00000010 00000000)b
#define GPIO_Pin_10   ((uint16_t)0x0400)  /*!< Ñ¡ÔñPin10 */   //(00000100 00000000)b
#define GPIO_Pin_11   ((uint16_t)0x0800)  /*!< Ñ¡ÔñPin11 */   //(00001000 00000000)b
#define GPIO_Pin_12   ((uint16_t)0x1000)  /*!< Ñ¡ÔñPin12 */   //(00010000 00000000)b
#define GPIO_Pin_13   ((uint16_t)0x2000)  /*!< Ñ¡ÔñPin13 */   //(00100000 00000000)b
#define GPIO_Pin_14   ((uint16_t)0x4000)  /*!< Ñ¡ÔñPin14 */   //(01000000 00000000)b
#define GPIO_Pin_15   ((uint16_t)0x8000)  /*!< Ñ¡ÔñPin15 */   //(10000000 00000000)b
#define GPIO_Pin_All  ((uint16_t)0xFFFF)  /*!< Ñ¡ÔñÈ«²¿Òý½Å*/ //(11111111 11111111)b


typedef enum
{ 
  GPIO_Speed_10MHz = 1,         // 10MHZ        (01)b
  GPIO_Speed_2MHz,              // 2MHZ         (10)b
  GPIO_Speed_50MHz              // 50MHZ        (11)b
}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 /* STM32F10X_GPIO_H */

#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)
  {
    tmpreg = GPIOx->CRH;
		
    for (pinpos = 0x00; pinpos < 0x08; pinpos++)
    {
      pos = (((uint32_t)0x01) << (pinpos + 0x08));
			
      currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
			
      if (currentpin == pos)
      {
        pos = pinpos << 2;
        
        pinmask = ((uint32_t)0x0F) << pos;
        tmpreg &= ~pinmask;
				
        tmpreg |= (currentmode << pos);
        
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
        {
          GPIOx->BRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
        if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
        {
          GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
        }
      }
    }
    GPIOx->CRH = tmpreg;
  }
}
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
 
void Delay(void);
 
 int main(void)
 {
	 
	 #if 0
	 //裸地址			:容易出错
	 *(unsigned int*)(0x40021018) |= (1<<3);	//开启GPIOB时钟
	 *(unsigned int*)(0x40010C00) &=0;
	 *(unsigned int*)(0x40010C00) |= 0x100000;	//输出和速度 PB0:0x1,PB1:0x10,PB5:0x100000
	 *(unsigned int*)(0x40010C0C) &= 0;//输出低电平 PB0-PB15
	 
	 #elif 0
	 //宏定义
	 RCC_APB2ENR |= (1<<3);
	 GPIOB_CRL &=0;
	 GPIOB_CRL |= 0x1;
	 GPIOB_ODR &= 0;
	 
	 #elif 0
	 //结构体
	 RCC->APB2ENR |= (1<<3);
	 GPIOB->CRL &=0;
	 GPIOB->CRL |= 0x10;
	 GPIOB->ODR &=0;
	 
	 #elif 1
	 //使用BSRR, BRR可以单独操纵一位
	 RCC->APB2ENR |= (1<<3);
	 GPIOB->CRL &=0;
	 GPIOB->CRL |= 0x10;
	 GPIO_SetBits(GPIOB,GPIO_Pin_1);
	 //GPIO_ResetBits( GPIOB,GPIO_Pin_1);
	 
	 #elif 0
	 //自定义库
	 GPIO_InitTypeDef  GPIO_InitStructure;
	 RCC->APB2ENR  |=(1<<3);
	 
	 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	 GPIO_Init(GPIOB, &GPIO_InitStructure);	
	 while(1)
	 {
		//绿灯
		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
		GPIO_Init(GPIOB, &GPIO_InitStructure);	
		GPIO_ResetBits( GPIOB,GPIO_Pin_0 );
		Delay();
		GPIO_SetBits(GPIOB,GPIO_Pin_0);
		Delay(); 
	 
	  //蓝灯
		GPIO_InitStructure.GPIO_Pin=GPIO_Pin_1;
		GPIO_Init(GPIOB, &GPIO_InitStructure);	
		GPIO_ResetBits( GPIOB,GPIO_Pin_1 );
		Delay();
		GPIO_SetBits(GPIOB,GPIO_Pin_1);
		Delay();
		 
		 //红灯
		GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;
		GPIO_Init(GPIOB, &GPIO_InitStructure);	
		GPIO_ResetBits( GPIOB,GPIO_Pin_5 );
		Delay();
		GPIO_SetBits(GPIOB,GPIO_Pin_5);
		Delay();
	 }
	 
	 
	 
	 #endif
 }
 
 
 void SystemInit(void)
{
	// 函数体为空,目的是为了骗过编译器不报错
}

//软件延时,不准
void Delay(void)
{
	uint32_t i=0;
	uint32_t j=0;
	uint32_t k=0;
	for(;i<60000;i++)
	{
		for(;j<60000;j++)
		{
			for(;k<1000;k++)
			{
				
			}
		}
	}
}

//还可以定义一些硬件相关的宏,以提高程序可移植性


其他

什么叫推挽输出?
1、可以输出高低电平,用于连接数字器件,高电平由VDD决定,低电平由
VSS决定。
2、推挽结构指两个三极管受两路互补的信号控制,总是在一个导通的时候
另外一个截止,优点开关效率效率高,电流大,驱动能力强。
3、输出高电平时,电流输出到负载,叫灌电流,可以理解成推,输出低电

平时,负载电流流向芯片,叫拉电流,即挽。

STM32(一):各种方式点亮LED灯


什么叫开漏输出?
1、只能输出低电平,不能输出高电平。
2、如果要输出高电平,则需要外接上拉。
3、开漏输出具有“线与”功能,一个为低,全部为低,多用于I2C和
SMBUS总线。

STM32(一):各种方式点亮LED灯