stm32 - GPIO

stm32 - GPIO

  • GPIO结构图
  • GPIO原理图
    • 输入
      • 上拉/下拉/浮空
      • 施密特触发器
      • 片上外设
    • 输出
      • 推挽/开漏/关闭输出方式
    • GPIO88种模式
      • 复用输出
  • GPIO寄存器
    • 端口配置寄存器_CRL
    • 端口输入数据寄存器_IDR
    • 端口输出数据寄存器_ODR
    • 端口位设置/清除寄存器_BSRR
    • 端口位清除寄存器_BRR
    • 端口配置锁定寄存器
  • 例子
    • 点灯
    • 流水灯
    • 蜂鸣器
    • 按键和灯
    • 蜂鸣器和光敏电阻

GPIO结构图

GPIO全都挂载在APB2总线上的
每个GPIOA 都有16个引脚
寄存器:输入寄存器和输出寄存器,输出寄存器引脚输出电平,输入寄存器从引脚读取当前电平
每个寄存器有32位,但是每个寄存器都只对应16个引脚,所以只使用寄存器中的低16 位
驱动器负责增大信号的驱动能力
在这里插入图片描述

GPIO原理图

在这里插入图片描述

输入

上拉/下拉/浮空

>

为了给输入一个默认的输入电平
为了避免引脚悬空导致输入数据的不稳定,需要加上上拉电阻或下拉电阻
上拉电阻:浮空引脚,保证引脚的高电平
下拉电阻:浮空引脚,保证引脚的低电平

上拉输入:高电平输入
下拉输入:低电平输入

施密特触发器

对输入电压进行整形,防止干扰
如果输入电压大于某一阈值,输出就会瞬间升为高电平
如果输入电压小于某一阈值,输出就会瞬间降为低电平

在这里插入图片描述

片上外设

  • 模拟输入 ADC等
  • 复用输入 数字量

输出

  • 输出寄存器:写某一位控制某一个引脚(用位设置和位清楚寄存器更好)
  • 片上外设

推挽/开漏/关闭输出方式

在这里插入图片描述

  • 推挽输出

高低电平均有强驱动能力
P-MOS和N-MOS均有效
输出数据寄存器为1时,上管导通PMOS导通,下管NMOS断开,输出直接接到VDD,输出高电平
输出数据寄存器为0时,上管导通PMOS断开,下管NMOS导通,输出直接接到VSS,输出低电平

  • 开漏输出

低电平有强驱动能力,高电平没有驱动能力
P-MOS无效,N-MOS有效
输出数据寄存器为1时,上管导通PMOS无效,下管NMOS断开,输出相当于断开,相当于高阻模式
输出数据寄存器为0时,上管导通PMOS无效,下管NMOS导通,输出直接接到VSS,输出低电平

开漏输出接外部的上拉5V电源

  • 关闭输出

引脚配置为输入模式的时候
两个MOS管均无效

GPIO88种模式

在这里插入图片描述

复用输出

由片上外设进行输出

GPIO寄存器

端口配置寄存器_CRL

GPIOX_CRL
一共32位,每4位对应一个IO的配置,可配置8个引脚

端口输入数据寄存器_IDR

GPIOX_IDR
32位,低16位对应16个引脚

端口输出数据寄存器_ODR

GPIOX_ODR
32位,低16位对应16个引脚

端口位设置/清除寄存器_BSRR

GPIOX_BSRR
32位,高16位用于进行位清除,低16位用于进行位设置

端口位清除寄存器_BRR

32位,低16位用于进行位清除

端口配置锁定寄存器

端口锁定

例子

点灯

main.cpp

#include "stm32f10x.h"
#include "Delay.h"int main()
{// 初始化APB2外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 配置GPIO - ODR/CLRGPIO_InitTypeDef GPIO_InitStructure;			// 配置结构体GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; 	// GPIO_Mode_Out_PP 推挽输出
//	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD; 	// GPIO_Mode_Out_OD 开漏输出 	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;			// GPIOA的0号引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 50MHZ GPIO_Init(GPIOA,&GPIO_InitStructure); // A0推挽输出//	GPIO_SetBits(GPIOA,GPIO_Pin_0); 	// 设置为高电平
//	GPIO_ResetBits(GPIOA,GPIO_Pin_0); 	// 设置为低电平
//	GPIO_Write();
//	GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); // Bit_RESET 低电平	
//	GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); // Bit_SET 高电平while (1){
//		GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); 	// Bit_RESET 低电平GPIO_ResetBits(GPIOA,GPIO_Pin_0);			// version2Delay_ms(500);
//		GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); 	// Bit_SET 高电平GPIO_SetBits(GPIOA,GPIO_Pin_0);				// version2Delay_ms(500);}
}

delay.c

#include "stm32f10x.h"/*** @brief  微秒级延时* @param  xus 延时时长,范围:0~233015* @retval 无*/
void Delay_us(uint32_t xus)
{SysTick->LOAD = 72 * xus;				//设置定时器重装值SysTick->VAL = 0x00;					//清空当前计数值SysTick->CTRL = 0x00000005;				//设置时钟源为HCLK,启动定时器while(!(SysTick->CTRL & 0x00010000));	//等待计数到0SysTick->CTRL = 0x00000004;				//关闭定时器
}/*** @brief  毫秒级延时* @param  xms 延时时长,范围:0~4294967295* @retval 无*/
void Delay_ms(uint32_t xms)
{while(xms--){Delay_us(1000);}
}/*** @brief  秒级延时* @param  xs 延时时长,范围:0~4294967295* @retval 无*/
void Delay_s(uint32_t xs)
{while(xs--){Delay_ms(1000);}
} 

流水灯

#include "stm32f10x.h"
#include "Delay.h"int main()
{// 初始化APB2外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); /* ====== 流水灯 ====== */// 配置GPIO - ODR/CLR registerGPIO_InitTypeDef GPIO_InitStructure;			// 配置结构体GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; 	// GPIO_Mode_Out_PP 推挽输出	/** #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)* GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7* 等价于 0x0001 | 0x0002 ... 位之间并不冲突*/
//	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;			// GPIOA的0号引脚GPIO_InitStructure.GPIO_Pin=GPIO_Pin_All;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 50MHZ GPIO_Init(GPIOA,&GPIO_InitStructure); // A0推挽输出while (1){for (int i=0;i<8;i++){GPIO_Write(GPIOA,~(0x0001<<i));
//			GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);Delay_ms(100);}}
}

蜂鸣器

#include "stm32f10x.h"
#include "Delay.h"int main()
{// 初始化APB2外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // 配置GPIO - ODR/CLRGPIO_InitTypeDef GPIO_InitStructure;			// 配置结构体GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; 	// GPIO_Mode_Out_PP 推挽输出
//	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD; 	// GPIO_Mode_Out_OD 开漏输出 	GPIO_InitStructure.GPIO_Pin= GPIO_Pin_12;			// GPIOA的0号引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 50MHZ GPIO_Init(GPIOB,&GPIO_InitStructure); // A0推挽输出//	GPIO_SetBits(GPIOB,GPIO_Pin_12); 	// 设置为高电平
//	GPIO_ResetBits(GPIOB,GPIO_Pin_12); 	// 设置为低电平
//	GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_RESET); // Bit_RESET 低电平	
//	GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET); // Bit_SET 高电平while (1){
//		GPIO_WriteBit(GPIOB,GPIO_Pin_0,Bit_RESET); 	// Bit_RESET 低电平GPIO_ResetBits(GPIOB,GPIO_Pin_12);			// version2Delay_ms(500);
//		GPIO_WriteBit(GPIOB,GPIO_Pin_12,Bit_SET); 	// Bit_SET 高电平GPIO_SetBits(GPIOB,GPIO_Pin_12);				// version2Delay_ms(500);}}

按键和灯

main.c

#include "stm32f10x.h"
#include "Delay.h"
#include "LED.h"
#include "key.h"int main()
{uint8_t keyNum=0;LED_Init();Key_Init();while (1){keyNum=key_getNum();switch (keyNum){case 1: {LED_ON(1);LED_OFF(2);keyNum=0;break;}case 11: {LED_ON(2);LED_OFF(1);keyNum=0;break;}default: break;}/* turn 切换*/ 
//		if (keyNum==1)
//		{
//			LED_ON(1);
//		}
//		if (keyNum==11)
//		{
//			LED_OFF(1);
//		}
//		}
}

LED.h

#ifndef __LED_H__
#define __LED_H__void LED_Init();
void LED_ON(unsigned char pin_num);
void LED_OFF(unsigned char pin_num);
void LED_Turn(unsigned char pin_num);#endif

LED.c

#include "stm32f10x.h"
#include "LED.h"void LED_Init()
{// 初始化APB2外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); // 配置GPIO - ODR/CLRGPIO_InitTypeDef GPIO_InitStructure;			// 配置结构体GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; 	// GPIO_Mode_Out_PP 推挽输出
//	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD; 	// GPIO_Mode_Out_OD 开漏输出 	GPIO_InitStructure.GPIO_Pin= GPIO_Pin_1 | GPIO_Pin_2;			// GPIOA的0号引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 50MHZ GPIO_Init(GPIOA,&GPIO_InitStructure); // A0推挽输出// 默认输出高电平 不点灯GPIO_SetBits(GPIOA,GPIO_Pin_1 | GPIO_Pin_2);
}void LED_ON(unsigned char pin_num)
{switch (pin_num){case 0: {GPIO_ResetBits(GPIOA,GPIO_Pin_0);break;}case 1: {GPIO_ResetBits(GPIOA,GPIO_Pin_1);break;}case 2: {GPIO_ResetBits(GPIOA,GPIO_Pin_2);break;}case 3: {GPIO_ResetBits(GPIOA,GPIO_Pin_3);break;}case 4: {GPIO_ResetBits(GPIOA,GPIO_Pin_4);break;}case 5: {GPIO_ResetBits(GPIOA,GPIO_Pin_5);break;}case 6: {GPIO_ResetBits(GPIOA,GPIO_Pin_6);break;}case 7: {GPIO_ResetBits(GPIOA,GPIO_Pin_7);break;}		}
}void LED_OFF(unsigned char pin_num)
{switch (pin_num){case 0: {GPIO_SetBits(GPIOA,GPIO_Pin_0);break;}case 1: {GPIO_SetBits(GPIOA,GPIO_Pin_1);break;}case 2: {GPIO_SetBits(GPIOA,GPIO_Pin_2);break;}case 3: {GPIO_SetBits(GPIOA,GPIO_Pin_3);break;}case 4: {GPIO_SetBits(GPIOA,GPIO_Pin_4);break;}case 5: {GPIO_SetBits(GPIOA,GPIO_Pin_5);break;}case 6: {GPIO_SetBits(GPIOA,GPIO_Pin_6);break;}case 7: {GPIO_SetBits(GPIOA,GPIO_Pin_7);break;}		}
}void LED_Turn(unsigned char pin_num)
{switch (pin_num){case 0: {if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_0)==0){GPIO_SetBits(GPIOA,GPIO_Pin_0);}else if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_0)==1){GPIO_ResetBits(GPIOA,GPIO_Pin_0);}break;}case 1: {			if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1)==0){GPIO_SetBits(GPIOA,GPIO_Pin_1);}else if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_1)==1){GPIO_ResetBits(GPIOA,GPIO_Pin_1);}break;}case 2: {			if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_2)==0){GPIO_SetBits(GPIOA,GPIO_Pin_2);}else if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_2)==1){GPIO_ResetBits(GPIOA,GPIO_Pin_2);}break;}case 3: {			if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_3)==0){GPIO_SetBits(GPIOA,GPIO_Pin_3);}else if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_3)==1){GPIO_ResetBits(GPIOA,GPIO_Pin_3);}break;}case 4: {			if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)==0){GPIO_SetBits(GPIOA,GPIO_Pin_4);}else if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_4)==1){GPIO_ResetBits(GPIOA,GPIO_Pin_4);}break;}case 5: {			if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5)==0){GPIO_SetBits(GPIOA,GPIO_Pin_5);}else if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_5)==1){GPIO_ResetBits(GPIOA,GPIO_Pin_5);}break;}case 6: {			if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_6)==0){GPIO_SetBits(GPIOA,GPIO_Pin_6);}else if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_6)==1){GPIO_ResetBits(GPIOA,GPIO_Pin_6);}break;}case 7: {			if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_7)==0){GPIO_SetBits(GPIOA,GPIO_Pin_7);}else if (GPIO_ReadOutputDataBit(GPIOA,GPIO_Pin_7)==1){GPIO_ResetBits(GPIOA,GPIO_Pin_7);}break;}	}
}

key.h

#ifndef __KEY_H__
#define __KEY_H__void Key_Init();
uint8_t key_getNum();
#endif

key.c

#include "stm32f10x.h"
#include "key.h"
#include "Delay.h"void Key_Init()
{// 初始化APB2外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);// 配置GPIO - ODR/CLRGPIO_InitTypeDef GPIO_InitStructure;			// 配置结构体GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; 	// GPIO_Mode_IPU 上拉输入 - 根据原理图(内部 上拉输入配置)GPIO_InitStructure.GPIO_Pin= GPIO_Pin_1 | GPIO_Pin_11;			// GPIOB的1,11号引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 50MHZ 仅与输入有关GPIO_Init(GPIOB,&GPIO_InitStructure); 			// B0推挽输出
}uint8_t key_getNum()
{uint8_t keyNum=0;/** GPIO_ReadInputDataBit 读取输入数据寄存器某一端口(引脚)的输入值,高低电平* GPIO_ReadInputData   读取整个输入数据寄存器* GPIO_ReadOutputDataBit 读取输出数据寄存器某一个位,输出模式下,用来看一下自己输出的是什么* GPIO_ReadOutputData 读取整个输出数据寄存器*/ // 输入数据if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0){Delay_ms(20);while (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_1)==0);Delay_ms(20);keyNum=1;}if (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0){Delay_ms(20);while (GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11)==0);Delay_ms(20);keyNum=11;}return keyNum;
}

蜂鸣器和光敏电阻

main.c

#include "stm32f10x.h"
#include "Delay.h"
#include "LED.h"
#include "key.h"
#include "Buzzer.h"
#include "PhotoSensor.h"int main()
{uint8_t keyNum=0;Buzzer_Init(12);PhotoSensor_Init(13);while (1){/* === 蜂鸣器 ===*/
//		Buzzer_Turn(12);
//		Delay_ms(500);
//		Buzzer_Turn(12);
//		Delay_ms(500);/* === 光敏传感器 ===*/
//		PhotoSensor_Turn(13);
//		Delay_ms(500);
//		PhotoSensor_Turn(13);
//		Delay_ms(500);/* === 光敏传感器2 ,光敏传感器控制蜂鸣器 ===*/if (PhotoSensor_Get(13)==1){Buzzer_ON(12);}else{Buzzer_OFF(12);}}
}

Buzzer.h

#ifndef __BUZZER_H__
#define __BUZZER_H__void Buzzer_Init(unsigned char pin_num);
void Buzzer_ON(unsigned char pin_num);
void Buzzer_OFF(unsigned char pin_num);
void Buzzer_Turn(unsigned char pin_num);#endif

Buzzer.c

#include "stm32f10x.h"
#include "Buzzer.h"void Buzzer_Init(unsigned char pin_num)
{uint16_t GPIO_Pin_num=0;switch (pin_num){case 0: {GPIO_Pin_num=GPIO_Pin_0;break;}case 1: {GPIO_Pin_num=GPIO_Pin_1;break;}case 2: {GPIO_Pin_num=GPIO_Pin_2;break;}case 3: {GPIO_Pin_num=GPIO_Pin_3;break;}case 4: {GPIO_Pin_num=GPIO_Pin_4;break;}case 5: {GPIO_Pin_num=GPIO_Pin_5;break;}case 6: {GPIO_Pin_num=GPIO_Pin_6;break;}case 7: {GPIO_Pin_num=GPIO_Pin_7;break;}case 8: {GPIO_Pin_num=GPIO_Pin_8;break;}case 9: {GPIO_Pin_num=GPIO_Pin_9;break;}case 10: {GPIO_Pin_num=GPIO_Pin_10;break;}case 11: {GPIO_Pin_num=GPIO_Pin_11;break;}case 12: {GPIO_Pin_num=GPIO_Pin_12;break;}case 13: {GPIO_Pin_num=GPIO_Pin_13;break;}case 14: {GPIO_Pin_num=GPIO_Pin_14;break;}}// 初始化APB2外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // 配置GPIO - ODR/CLRGPIO_InitTypeDef GPIO_InitStructure;			// 配置结构体GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; 	// GPIO_Mode_Out_PP 推挽输出
//	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD; 	// GPIO_Mode_Out_OD 开漏输出 	GPIO_InitStructure.GPIO_Pin= GPIO_Pin_num;			// GPIOB的0号引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 50MHZ GPIO_Init(GPIOB,&GPIO_InitStructure); // A0推挽输出// 默认输出高电平 不点灯GPIO_SetBits(GPIOB,GPIO_Pin_num);
}void Buzzer_ON(unsigned char pin_num)
{switch (pin_num){case 0: {GPIO_ResetBits(GPIOB,GPIO_Pin_0);break;}case 1: {GPIO_ResetBits(GPIOB,GPIO_Pin_1);break;}case 2: {GPIO_ResetBits(GPIOB,GPIO_Pin_2);break;}case 3: {GPIO_ResetBits(GPIOB,GPIO_Pin_3);break;}case 4: {GPIO_ResetBits(GPIOB,GPIO_Pin_4);break;}case 5: {GPIO_ResetBits(GPIOB,GPIO_Pin_5);break;}case 6: {GPIO_ResetBits(GPIOB,GPIO_Pin_6);break;}case 7: {GPIO_ResetBits(GPIOB,GPIO_Pin_7);break;}case 8: {GPIO_ResetBits(GPIOB,GPIO_Pin_8);break;}case 9: {GPIO_ResetBits(GPIOB,GPIO_Pin_9);break;}case 10: {GPIO_ResetBits(GPIOB,GPIO_Pin_10);break;}case 11: {GPIO_ResetBits(GPIOB,GPIO_Pin_11);break;}case 12: {GPIO_ResetBits(GPIOB,GPIO_Pin_12);break;}case 13: {GPIO_ResetBits(GPIOB,GPIO_Pin_13);break;}case 14: {GPIO_ResetBits(GPIOB,GPIO_Pin_14);break;}case 15: {GPIO_ResetBits(GPIOB,GPIO_Pin_15);break;}		}
}void Buzzer_OFF(unsigned char pin_num)
{switch (pin_num){case 0: {GPIO_SetBits(GPIOB,GPIO_Pin_0);break;}case 1: {GPIO_SetBits(GPIOB,GPIO_Pin_1);break;}case 2: {GPIO_SetBits(GPIOB,GPIO_Pin_2);break;}case 3: {GPIO_SetBits(GPIOB,GPIO_Pin_3);break;}case 4: {GPIO_SetBits(GPIOB,GPIO_Pin_4);break;}case 5: {GPIO_SetBits(GPIOB,GPIO_Pin_5);break;}case 6: {GPIO_SetBits(GPIOB,GPIO_Pin_6);break;}case 7: {GPIO_SetBits(GPIOB,GPIO_Pin_7);break;}case 8: {GPIO_SetBits(GPIOB,GPIO_Pin_8);break;}case 9: {GPIO_SetBits(GPIOB,GPIO_Pin_9);break;}case 10: {GPIO_SetBits(GPIOB,GPIO_Pin_10);break;}case 11: {GPIO_SetBits(GPIOB,GPIO_Pin_11);break;}case 12: {GPIO_SetBits(GPIOB,GPIO_Pin_12);break;}case 13: {GPIO_SetBits(GPIOB,GPIO_Pin_13);break;}case 14: {GPIO_SetBits(GPIOB,GPIO_Pin_14);break;}case 15: {GPIO_SetBits(GPIOB,GPIO_Pin_15);break;}			}
}void Buzzer_Turn(unsigned char pin_num)
{// version 2uint16_t GPIO_Pin_num=0;switch (pin_num){case 0: {GPIO_Pin_num=GPIO_Pin_0;break;}case 1: {GPIO_Pin_num=GPIO_Pin_1;break;}case 2: {GPIO_Pin_num=GPIO_Pin_2;break;}case 3: {GPIO_Pin_num=GPIO_Pin_3;break;}case 4: {GPIO_Pin_num=GPIO_Pin_4;break;}case 5: {GPIO_Pin_num=GPIO_Pin_5;break;}case 6: {GPIO_Pin_num=GPIO_Pin_6;break;}case 7: {GPIO_Pin_num=GPIO_Pin_7;break;}case 8: {GPIO_Pin_num=GPIO_Pin_8;break;}case 9: {GPIO_Pin_num=GPIO_Pin_9;break;}case 10: {GPIO_Pin_num=GPIO_Pin_10;break;}case 11: {GPIO_Pin_num=GPIO_Pin_11;break;}case 12: {GPIO_Pin_num=GPIO_Pin_12;break;}case 13: {GPIO_Pin_num=GPIO_Pin_13;break;}case 14: {GPIO_Pin_num=GPIO_Pin_14;break;}}if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_num)==0){GPIO_SetBits(GPIOB,GPIO_Pin_num);}else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_num)==1){GPIO_ResetBits(GPIOB,GPIO_Pin_num);}// version 1
//	switch (pin_num)
//	{
//		case 0: {
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_0)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_0);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_0)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_0);
//			}
//			break;
//		}
//		case 1: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_1)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_1);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_1)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_1);
//			}
//			break;
//		}
//		case 2: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_2)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_2);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_2)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_2);
//			}
//			break;
//		}
//		case 3: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_3)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_3);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_3)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_3);
//			}
//			break;
//		}
//		case 4: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_4)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_4);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_4)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_4);
//			}
//			break;
//		}
//		case 5: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_5);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_5);
//			}
//			break;
//		}
//		case 6: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_6)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_6);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_6)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_6);
//			}
//			break;
//		}
//		case 7: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_7)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_7);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_7)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_7);
//			}
//			break;
//		}	
//	}
}

photosensor.h

#ifndef __PHOTOSENSOR_H__
#define __PHOTOSENSOR_H__void PhotoSensor_Init(unsigned char pin_num);
void PhotoSensor_ON(unsigned char pin_num);
void PhotoSensor_OFF(unsigned char pin_num);
void PhotoSensor_Turn(unsigned char pin_num);
uint8_t PhotoSensor_Get(unsigned char pin_num);#endif

photosensor.c

#include "stm32f10x.h"
#include "PhotoSensor.h"void PhotoSensor_Init(unsigned char pin_num)
{uint16_t GPIO_Pin_num=0;switch (pin_num){case 0: {GPIO_Pin_num=GPIO_Pin_0;break;}case 1: {GPIO_Pin_num=GPIO_Pin_1;break;}case 2: {GPIO_Pin_num=GPIO_Pin_2;break;}case 3: {GPIO_Pin_num=GPIO_Pin_3;break;}case 4: {GPIO_Pin_num=GPIO_Pin_4;break;}case 5: {GPIO_Pin_num=GPIO_Pin_5;break;}case 6: {GPIO_Pin_num=GPIO_Pin_6;break;}case 7: {GPIO_Pin_num=GPIO_Pin_7;break;}case 8: {GPIO_Pin_num=GPIO_Pin_8;break;}case 9: {GPIO_Pin_num=GPIO_Pin_9;break;}case 10: {GPIO_Pin_num=GPIO_Pin_10;break;}case 11: {GPIO_Pin_num=GPIO_Pin_11;break;}case 12: {GPIO_Pin_num=GPIO_Pin_12;break;}case 13: {GPIO_Pin_num=GPIO_Pin_13;break;}case 14: {GPIO_Pin_num=GPIO_Pin_14;break;}}// 初始化APB2外设时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); // 配置GPIO - ODR/CLRGPIO_InitTypeDef GPIO_InitStructure;			// 配置结构体GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IPU; 	// 上拉输入	GPIO_InitStructure.GPIO_Pin= GPIO_Pin_num;			// GPIOB的0号引脚GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz; // 50MHZ GPIO_Init(GPIOB,&GPIO_InitStructure);}void PhotoSensor_ON(unsigned char pin_num)
{switch (pin_num){case 0: {GPIO_ResetBits(GPIOB,GPIO_Pin_0);break;}case 1: {GPIO_ResetBits(GPIOB,GPIO_Pin_1);break;}case 2: {GPIO_ResetBits(GPIOB,GPIO_Pin_2);break;}case 3: {GPIO_ResetBits(GPIOB,GPIO_Pin_3);break;}case 4: {GPIO_ResetBits(GPIOB,GPIO_Pin_4);break;}case 5: {GPIO_ResetBits(GPIOB,GPIO_Pin_5);break;}case 6: {GPIO_ResetBits(GPIOB,GPIO_Pin_6);break;}case 7: {GPIO_ResetBits(GPIOB,GPIO_Pin_7);break;}case 8: {GPIO_ResetBits(GPIOB,GPIO_Pin_8);break;}case 9: {GPIO_ResetBits(GPIOB,GPIO_Pin_9);break;}case 10: {GPIO_ResetBits(GPIOB,GPIO_Pin_10);break;}case 11: {GPIO_ResetBits(GPIOB,GPIO_Pin_11);break;}case 12: {GPIO_ResetBits(GPIOB,GPIO_Pin_12);break;}case 13: {GPIO_ResetBits(GPIOB,GPIO_Pin_13);break;}case 14: {GPIO_ResetBits(GPIOB,GPIO_Pin_14);break;}case 15: {GPIO_ResetBits(GPIOB,GPIO_Pin_15);break;}		}
}void PhotoSensor_OFF(unsigned char pin_num)
{switch (pin_num){case 0: {GPIO_SetBits(GPIOB,GPIO_Pin_0);break;}case 1: {GPIO_SetBits(GPIOB,GPIO_Pin_1);break;}case 2: {GPIO_SetBits(GPIOB,GPIO_Pin_2);break;}case 3: {GPIO_SetBits(GPIOB,GPIO_Pin_3);break;}case 4: {GPIO_SetBits(GPIOB,GPIO_Pin_4);break;}case 5: {GPIO_SetBits(GPIOB,GPIO_Pin_5);break;}case 6: {GPIO_SetBits(GPIOB,GPIO_Pin_6);break;}case 7: {GPIO_SetBits(GPIOB,GPIO_Pin_7);break;}case 8: {GPIO_SetBits(GPIOB,GPIO_Pin_8);break;}case 9: {GPIO_SetBits(GPIOB,GPIO_Pin_9);break;}case 10: {GPIO_SetBits(GPIOB,GPIO_Pin_10);break;}case 11: {GPIO_SetBits(GPIOB,GPIO_Pin_11);break;}case 12: {GPIO_SetBits(GPIOB,GPIO_Pin_12);break;}case 13: {GPIO_SetBits(GPIOB,GPIO_Pin_13);break;}case 14: {GPIO_SetBits(GPIOB,GPIO_Pin_14);break;}case 15: {GPIO_SetBits(GPIOB,GPIO_Pin_15);break;}			}
}void PhotoSensor_Turn(unsigned char pin_num)
{// version 2uint16_t GPIO_Pin_num=0;switch (pin_num){case 0: {GPIO_Pin_num=GPIO_Pin_0;break;}case 1: {GPIO_Pin_num=GPIO_Pin_1;break;}case 2: {GPIO_Pin_num=GPIO_Pin_2;break;}case 3: {GPIO_Pin_num=GPIO_Pin_3;break;}case 4: {GPIO_Pin_num=GPIO_Pin_4;break;}case 5: {GPIO_Pin_num=GPIO_Pin_5;break;}case 6: {GPIO_Pin_num=GPIO_Pin_6;break;}case 7: {GPIO_Pin_num=GPIO_Pin_7;break;}case 8: {GPIO_Pin_num=GPIO_Pin_8;break;}case 9: {GPIO_Pin_num=GPIO_Pin_9;break;}case 10: {GPIO_Pin_num=GPIO_Pin_10;break;}case 11: {GPIO_Pin_num=GPIO_Pin_11;break;}case 12: {GPIO_Pin_num=GPIO_Pin_12;break;}case 13: {GPIO_Pin_num=GPIO_Pin_13;break;}case 14: {GPIO_Pin_num=GPIO_Pin_14;break;}}if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_num)==0){GPIO_SetBits(GPIOB,GPIO_Pin_num);}else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_num)==1){GPIO_ResetBits(GPIOB,GPIO_Pin_num);}// version 1
//	switch (pin_num)
//	{
//		case 0: {
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_0)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_0);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_0)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_0);
//			}
//			break;
//		}
//		case 1: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_1)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_1);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_1)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_1);
//			}
//			break;
//		}
//		case 2: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_2)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_2);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_2)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_2);
//			}
//			break;
//		}
//		case 3: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_3)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_3);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_3)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_3);
//			}
//			break;
//		}
//		case 4: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_4)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_4);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_4)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_4);
//			}
//			break;
//		}
//		case 5: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_5);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_5)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_5);
//			}
//			break;
//		}
//		case 6: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_6)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_6);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_6)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_6);
//			}
//			break;
//		}
//		case 7: {			
//			if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_7)==0)
//			{
//				GPIO_SetBits(GPIOB,GPIO_Pin_7);
//			}
//			else if (GPIO_ReadOutputDataBit(GPIOB,GPIO_Pin_7)==1)
//			{
//				GPIO_ResetBits(GPIOB,GPIO_Pin_7);
//			}
//			break;
//		}	
//	}
}uint8_t PhotoSensor_Get(unsigned char pin_num)
{uint16_t GPIO_Pin_num=0;switch (pin_num){case 0: {GPIO_Pin_num=GPIO_Pin_0;break;}case 1: {GPIO_Pin_num=GPIO_Pin_1;break;}case 2: {GPIO_Pin_num=GPIO_Pin_2;break;}case 3: {GPIO_Pin_num=GPIO_Pin_3;break;}case 4: {GPIO_Pin_num=GPIO_Pin_4;break;}case 5: {GPIO_Pin_num=GPIO_Pin_5;break;}case 6: {GPIO_Pin_num=GPIO_Pin_6;break;}case 7: {GPIO_Pin_num=GPIO_Pin_7;break;}case 8: {GPIO_Pin_num=GPIO_Pin_8;break;}case 9: {GPIO_Pin_num=GPIO_Pin_9;break;}case 10: {GPIO_Pin_num=GPIO_Pin_10;break;}case 11: {GPIO_Pin_num=GPIO_Pin_11;break;}case 12: {GPIO_Pin_num=GPIO_Pin_12;break;}case 13: {GPIO_Pin_num=GPIO_Pin_13;break;}case 14: {GPIO_Pin_num=GPIO_Pin_14;break;}}return GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_num);
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/147458.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

ElementUI之CUD+表单验证

&#x1f3ac; 艳艳耶✌️&#xff1a;个人主页 &#x1f525; 个人专栏 &#xff1a;《Spring与Mybatis集成整合》《Vue.js使用》 ⛺️ 生活的理想&#xff0c;为了不断更新自己 ! 1.前言 首先&#xff0c;Vue是一种流行的JavaScript框架&#xff0c;它提供了一种简洁易用的方…

UGUI交互组件Button

一.初识Button对象 从菜单中创建Button对象&#xff0c;Button的文本由子节点Text对象显示&#xff0c;Button对象的组件除了基础组件外&#xff0c;还有Image用来显示Button常规态的图片&#xff0c;还有Button组件用来控制点击过渡效果和点击事件的响应。 二.Button组件的属…

POJ 3109 Inner Vertices 离散化+树状数组

一、题目大意 围棋棋盘&#xff0c;如果某个坐标上下左右的四个方向都存在棋子&#xff0c;那么ans1&#xff0c;根据输入的棋子数量&#xff0c;求出ans的数量。 二、解题思路 题目中有说到如果程序不会结束&#xff0c;那么输出-1&#xff0c;这其实是无源之水&#xff0c…

【vue3】shallowReactive与shallowRef;readonly与shallowReadonly;toRaw与markRaw

假期第六篇&#xff0c;对于基础的知识点&#xff0c;我感觉自己还是很薄弱的。 趁着假期&#xff0c;再去复习一遍 1、shallowReactive与shallowRef shallowReactive&#xff1a;只处理对象最外层属性的响应式&#xff08;浅响应式&#xff09; shallowRef&#xff1a;只处理…

WSL2安装历程

WLS2安装 1、系统检查 安装WSL2必须运行 Windows 10 版本 2004 及更高版本&#xff08;内部版本 19041 及更高版本&#xff09;或 Windows 11。 查看 Windows 版本及内部版本号&#xff0c;选择 Win R&#xff0c;然后键入winver。 2、家庭版升级企业版 下载HEU_KMS_Activ…

【Python】函数(function)和方法(method)的区别

这里先说结论&#xff0c;为了满足心急的小伙伴&#xff1a;method与function的最大区别就是参数有无进行绑定。 自定义类Test&#xff1a; 首先先来一个自定义类&#xff1a; class Test:def Func_normal(arg):print(Func_normal:,arg)staticmethoddef Func_static(arg):pri…

Lua多脚本执行

--全局变量 a 1 b "123"for i 1,2 doc "Holens" endprint(c) print("*************************************1")--本地变量&#xff08;局部变量&#xff09; for i 1,2 dolocal d "Holens2"print(d) end print(d)function F1( ..…

短期风速预测|LSTM|ELM|批处理(matlab代码)

目录 1 主要内容 LSTM-长短时记忆 ELM-极限学习机 2 部分代码 3 程序结果 4 程序链接 1 主要内容 该程序是预测类的基础性代码&#xff0c;程序对河北某地区的气象数据进行详细统计&#xff0c;程序最终得到pm2.5的预测结果&#xff0c;通过更改数据很容易得到风速预测结…

【计算机组成原理】读书笔记第五期:通过汇编语言了解程序的实际构成

目录 写在开头 汇编语言和本地代码的关系 汇编语言的源代码 伪指令 汇编的基本语法 常见的汇编指令 mov push和pop 函数的使用机制 函数的调用 函数参数的传递与返回值 全局变量 局部变量 程序的流程控制 循环语句 条件分支 通过汇编语言了解程序运行方式的必…

德国自动驾驶卡车公司【Fernride】完成1900万美元A轮融资

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 猛兽财经获悉&#xff0c;总部位于德国沃尔夫斯堡的自动驾驶卡车公司【Fernride】今日宣布已完成1900万美元A轮融资&#xff0c;本轮融资完成后Fernride的融资金额已经达到了达到5000万美元。 本轮融资由Deep Tech and Cli…

推荐算法——Apriori算法原理

0、前言&#xff1a; 首先名字别读错&#xff1a;an pu ruo ao rui 【拼音发音】Apriori是一种推荐算法推荐系统&#xff1a;从海量数据中&#xff0c;帮助用户进行信息的过滤和选择。主要推荐方法有&#xff1a;基于内容的推荐、协同过滤推荐、基于关联规则的推荐、基于知识的…

多线程(pthread库)

POSIX线程库 引言 前面我们提到了Linux中并无真正意义上的线程 从OS角度来看&#xff0c;这意味着它并不会提供直接创建线程的系统调用&#xff0c;它最多给我们提供创建轻量级进程LWP的接口 但是从用户的角度来看&#xff0c;用户只认识线程啊&#xff01; 因此&#xff0c;…

wxWidgets(1):在Ubuntu 环境中搭建wxWidgets 库环境,安装库和CodeBlocks的IDE,可以运行demo界面了,继续学习中

1&#xff0c;选择使用 wxWidgets 框架 选择这个主要是因为完全的开源&#xff0c;不想折腾 Qt的库&#xff0c;而且打包的文件比较大。 网络上面有很多的对比&#xff0c;而且使用QT的人比较多。 但是我觉得wxwidgets 更加偏向 c 语法本身&#xff0c;也有助学习C。 没有太多…

【算法分析与设计】回溯法(上)

目录 一、学习要点1.1 回溯法1.2 问题的解空间1.3 0-1背包问题的解空间1.4 旅行售货员问题的解空间1.5 生成问题状态的基本方法 二、回溯法的基本思想三、回溯算法的适用条件四、递归回溯五、迭代回溯六、子集树与排列树七、装载问题八、批处理作业调度问题 一、学习要点 理解回…

Kotlin前置检测判断check,require,requireNotNull

Kotlin前置检测判断check&#xff0c;require&#xff0c;requireNotNull &#xff08;1&#xff09;check fun main(args: Array<String>) {val b falsecheck(b) {println("check $b")}println("end") } check监测到值非真时候&#xff0c;抛出一…

【数据结构与算法】通过双向链表和HashMap实现LRU缓存 详解

这个双向链表采用的是有伪头节点和伪尾节点的 与上一篇文章中单链表的实现不同&#xff0c;区别于在实例化这个链表时就初始化了的伪头节点和伪尾节点&#xff0c;并相互指向&#xff0c;在第一次添加节点时&#xff0c;不需要再考虑空指针指向问题了。 /*** 通过链表与HashMa…

Python 无废话-基础知识元组Tuple详讲

“元组 Tuple”是一个有序、不可变的序列集合&#xff0c;元组的元素可以包含任意类型的数据&#xff0c;如整数、浮点数、字符串等&#xff0c;用()表示&#xff0c;如下示例&#xff1a; 元组特征 1) 元组中的各个元素&#xff0c;可以具有不相同的数据类型&#xff0c;如 T…

Python-Flask:编写自动化连接demo脚本:v1.0.0

主函数&#xff1a; # _*_ Coding : UTF-8 _*_ # Time : 13:14 # Author : YYZ # File : Flask # Project : Python_Project_爬虫 import jsonfrom flask import Flask,request,jsonify import sshapi Flask(__name__)# methods: 指定请求方式 接口解析参数host host_info[…

05. 机器学习入门 - 动态规划

文章目录 从一个案例开始动态规划 Hi, 你好。我是茶桁。 咱们之前的课程就给大家讲了什么是人工智能&#xff0c;也说了每个人的定义都不太一样。关于人工智能的不同观点和方法&#xff0c;其实是一个很复杂的领域&#xff0c;我们无法用一个或者两个概念确定什么是人工智能&a…

在visual studio里配置Qt插件并运行Qt工程

Qt插件&#xff0c;也叫qt-vsaddin&#xff0c;它以*.vsix后缀名结尾。从visual studio 2010版本开始&#xff0c;VS支持Qt框架的开发&#xff0c;Qt以插件方式集成到VS里。这里在visual studio 2019里配置Qt 5.14.2插件&#xff0c;并配置Qt环境。 1 下载VS2019 下载VS2019,官…