STM32 notes GPIO introduction and IO port operation STM32F0 uses C language bit field to realize imitation bit band operation

Article Directory

 

Introduction to GPIO

GPIO: Each device connected to the I/O bus has its own set of I/O addresses, the so-called I/O ports. Similar to P0~P3 of 51 single-chip microcomputer, but different from 51 single-chip microcomputer, for the GPIO of stm32, you need to set its working mode before use. . Each IO port of STM32 has 7 registers to control its working mode, and each register needs to be controlled by 32bit. In STM32, a group of GPIO has 16 IO ports.

Basic structure of port bits:

Insert picture description here

TTL Schottky trigger function: Turn a relatively slow-changing analog signal into a rectangular signal for easy reading later.
(There is a concept of threshold voltage, such as how much will turn on from low to high, and how much will turn off from high)

Way of working

There are 8 working modes for the IO port of stm32:
1. Input floating: read the corresponding external level, but when the pin is not input, it is equivalent to floating, the input level is unknown, the range is 0~VCC.
2. Input pull-up: Ensure that the level of the input terminal is high when there is no signal input. When the signal input is low, the level of the input terminal is also low.
3. Input pull-down: Ensure that the level of the input terminal is low when there is no signal input. When the signal input is high, the level of the input terminal is also high.
4. Analog input: The traditional input method converts the binary digital signal of 0, 1 into analog signal through digital-to-analog conversion, using ADC analog input, or saving power with low power consumption. Simply put, it is to convert the original high and low levels into a signal with a range of 0~VCC.
5. Open-drain output: IO port output 0 is grounded, output 1 is controlled by an external resistance to 0/1.
6. Push-pull output: low-level output is 0, high-level output is VCC
link: It is well explained by a triode The above two outputs
7. Multiplex push-pull output: used as serial port output.
8. Multiplexed open drain output: used in IIC.
The common points of the 7 and 8 outputs: it can be understood as the configuration when the GPIO port is used as the second function (that is, it is not used as a general-purpose IO port), push-pull and open-drain output for internal peripherals. Must be configured as a multiplex function output mode.

Each GPIO port is configured as one of 8 modes through CNF[1:0] and MODE[1:0].
STM32 IO port configuration table:
Insert picture description here
STM32 output mode configuration:

Insert picture description here

Related register introduction

Two 32-bit port configuration registers CRL and CRH in configuration mode; two 32-bit data registers IDR and ODR; one 32-bit set/reset register BSRR; one 16-bit reset register BRR; one 32-bit The latch register LCKR.

1. CRL and CRH (controlling the mode and output rate of each IO port)
Insert picture description here
The function of CRH is exactly the same as CRL, except that CRL controls the low 8-bit output port, while CRH controls the high 8-bit output port.

2.
IDR and ODR IDR: IDR is a port input data register, only the lower 16 bits are used. This register is read-only and can only be read in 16-bit format. Insert picture description here
Operating the IDR register in the firmware library to read IO port data is achieved through the GPIO_ReadInputDataBit function:

uint8_tGPIO_ReadInputDataBit(GPIO_TypeDef*GPIOx,uint16_tGPIO_Pin)
  • 1

For example, to read the level status of GPIOA.5, the method is:

GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);

  • 1
  • 2

The return value is 1 (Bit_SET) or 0 (Bit_RESET);

ODR: ODR is a port output data register, and only the lower 16 bits are used. This register is readable and writable, and the data read from this register can be used to judge the current output status of the IO port. And write data to this register, you can control the output level of a certain IO port.
Insert picture description here
Setting the value of the ODR register in the firmware library to control the output state of the IO port is achieved through the function GPIO_Write:

void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
  • 1

This function is generally used to set values ​​for multiple ports of a GPIO.

3. BSRR: The BSRR register is a port bit setting/clearing register. This register and the ODR register have similar functions, and both can be used to set the output bit of the GPIO port to be 1 or 0.
Insert picture description here
4. BRR: The BRR register is a port bit clear register. The function of this register is the same as the upper 16 bits of BSRR.

5. LCKR (not commonly used)

Insert picture description here

IO operation steps

1) Enable the IO port clock. The calling function is RCC_APB2PeriphClockCmd().

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOX,ENABLE);//GPIOX  使能时钟,X=A~E

  • 1
  • 2

2) Initialize the IO parameters. Call function GPIO_Init(); (determine the IO port for operation)

void GPIO_Init(GPIO_TypeDef*GPIOx,GPIO_InitTypeDef*GPIO_InitStruct);
  • 1

Among them, the two parameters are: configuration pin group (GPIO_TypeDef* GPIOx), configuration parameter (GPIO_InitTypeDef* GPIO_InitStruct).

3) Operate IO. (Firmware library operation, register operation, bit operation)

Detailed explanation of three operations of IO port

1. Firmware library operation

 GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP; //模式选择为推挽输出
 GPIO_InitStructure.GPIO_Pin=GPIO_Pin_5;//确定选位为第五个IO口
 GPIO_InitStructure.GPIO_Speed=  GPIO_Speed_50MHz;//速率选择为50M
 GPIO_Init(GPIOX,&GPIO_InitStructure);//初始化GPIOX
 
 GPIO_SetBits(GPIOX,GPIO_Pin_5);//设置该位为高电平
  GPIO_ResetBits(GPIOX,GPIO_Pin_5);//设置该位为低电平
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Eight modes are defined in the MDK through an enumerated type:

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; 


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

The IO port speed setting has three optional values, which are also defined by enumerated types in MDK:

typedef enum
{
GPIO_Speed_10MHz = 1,
GPIO_Speed_2MHz,
GPIO_Speed_50MHz
}GPIOSpeed_TypeDef; 


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

After the mode setting is completed, the IO port setting can be performed through other library functions:
control IDR:

uint_8t GPIO_ReadIputDataBit(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
  • 1

Control ODR:

void GPIO_Write(GPIO_TypeDef*GPIOx,uint16_t PortVal)
  • 1

Control BSRR and BRR:

void GPIO_SetBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)

void GPIO_ResetBits(GPIO_TypeDef*GPIOx,uint16_t GPIO_Pin)
  • 1
  • 2
  • 3

2. Register operation
Complete IO port initialization example:

void LED_Init(void)
 {     
  RCC->APB2ENR |= 1<<2;    //使能PTA时钟     
  RCC->APB2ENR |= 1<<5;    //使能PTD时钟     
  GPIOA->CRH&=0XFFFF FFF0; //清空PA8设置     
  GPIOA->CRH|=0X0000 0003; //设置PA8推挽输出     
  GPIOA->ODR|=1<<8;  //PA8输出高     
  GPIOD->CRL&=0XFFFF F0FF;//清空PD2设置     
  G)PIOD->CRL|=0X0000 0300;//设置PD2推挽输出     
  GPIOD->ODR|=1<<2;//PD2输出高 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

Generally, the form of controlling the IO port with the register is as above, which can be directly assigned, or can be controlled by AND (&), or (|), not (~).

3. Bit operation: by directly operating the address of the IO port to change the value of the IO port to achieve the purpose of operating IO.
Principle: Expand each bit into a 32-bit word (ie its address), which is called the "bit alias area" of this bit, as shown in the following figure:
Insert picture description here

There are two bit bands in STM32:

Insert picture description here
For a bit of the on-chip peripheral bit zone, record the address of the byte where it is located as A, and the bit sequence number is n (0<=n<=7), then the address of the bit in the alias area is:

AliasAddr= 0x42000000+((A‐0x40000000)*8+n)*4 =0x42000000+ (A‐0x40000000)*32 + n*4 

  • 1
  • 2

For a bit in the SRAM bit band area, record its byte address as A and the bit number as n (0<=n<=7), then the address of the bit in the alias area is:

AliasAddr= 0x42000000+((A‐0x40000000)*8+n)*4 =0x42000000+ (A‐0x40000000)*32 + n*4

  • 1
  • 2

"*4" means that a word is 4 bytes, and "*8" means that there are 8 bits in a byte.

Use (take the first of the 16 IO ports that control GPIOA as an example):

//IO口操作宏定义,获取相应地址
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 

#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C 
//IO口地址映射,即获取GPIOA_ODR的地址

#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出 
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入

PAin(1)=1//使得GPIOA的第一个IO口为高电平
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

Appendix: C language related

1. C language bit operation
Insert picture description here

2. Define is a preprocessing command in C language. It is used for macro definition, which can improve the readability of source code and provide convenience for programming. Common format: #define identifier string (no semicolon) "Identifier" is the defined macro name. "String" can be a constant, expression, format string, etc. (Similar to typedef)

3. In the process of MCU program development, a situation is often encountered, when a certain condition is met, a group of statements are compiled, and when the condition is not met, another group of statements is compiled. The most common form of conditional compilation commands is:

#ifdef 标识符
程序段 1
#else
程序段 2
#endif 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

When the identifier has been defined (usually defined by the #define command), program segment 1 is compiled, otherwise program segment 2 is compiled. The #else part can also be absent.

4. In C language, extern can be placed in front of a variable or function to indicate that the definition of the variable or function is in another file, prompting the compiler to look for its definition in other modules when it encounters this variable or function. Such as:

extern u16 USART_RX_STA; 
  • 1

At this time, in other files there will be:

u16 USART_RX_STA;
  • 1

But if there are multiple files that need to operate on the application variables at the same time, and the variables may be modified, it will affect the use of other modules.

5. Structure
Declare the structure type:

Struct 结构体名{
成员列表;
}变量名列表; 

例:
struct U_TYPE {
int BaudRate
int WordLength;
}usart1,usart2; 

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

The reference method of structure member variables is: structure variable name. member name

usart1.BaudRate//引用usart1中的成员BaudRate
  • 1

When there are too many variables defined, or a few variables are used to describe a certain object, the structure can make the function more readable.

Offset address and absolute address

The offset address is very simple to calculate the absolute address. For example, to calculate the absolute address of the CRH register of the GPIOC port. You can check the starting address of GPIOC first. From Figure 8-6, you can determine that the starting address of GPIOC is 0x40011000, and the offset address of the CRH register is 0x04. Therefore, the absolute address of the CRH register of GPIOC is calculated, that is, 0x40011000+0x04. It can be obtained as 0x40011004.

 

During the recent development, I used the STM32F030F4P6 single-chip microcomputer. It has only 20 pins and is very cheap, but it has complete functions; timers, external interrupts, serial ports, IIC, SPI, DMA, WWDG, etc., have all applications, very Suitable for small equipment. However, there is a problem that it is a Cortex-M0 core, unlike M3 and M4 cores, it can support bit-band operation (that is, bit-by-bit operation, like 80C51 single-chip microcomputer). This is for program porting or development. A little trouble came, so I used the bit segment operation of the C language structure to implement a bit band operation, but the efficiency may be slightly inferior to the real bit band operation, but the code is compatible, basically Applied to any processor. Hope to help everyone.

2. Basic knowledge of bit band operation #

 There is a lot of information on the real bitband operation on the Internet, and it is written in great detail. Here I just briefly talk about my understanding. In addition, not understanding the real bit-band operation will not affect the understanding of this article, because this article has nothing to do with the bit-band operation, it's just imitating, and can't be taken seriously. If you don't want to know the real bit band operation, this section can be ignored directly.

If we don’t use bitband operation, when we manipulate a secondary data, we have to move 32 bits (STM32 is 32 bits). To make an inappropriate analogy, this is equivalent to sitting on a train with 32 cars. , But a train has only one door. If we want to view the information of passengers in this train, or passengers want to get off, they must enter and exit through that door, as shown in Figure 1.

Figure 1 32 trains with only one door

 And if we have a seat belt operation, it is equivalent to installing 32 doors on this 32-carriage train. In this way, we can quickly check which passenger’s information or which passenger wants to get off. Get off at the designated door. As shown in Figure 2 below.

Figure 2 32 trains with 32 doors

With 32 doors, the speed is much faster, but the hardware cost is definitely going to rise. This is why the STM32F030 series does not have bit-band operation, because it is low in cost.

3. C speech structure body segment operation #

This section mainly describes the basic knowledge of C language structure. If you have a C language master, please ignore this section. In the C language, there is a bit field for the declaration of a structure, which can be controlled. The members of this structure occupy several bits. Regarding its use, there are the following codes:

Copy code

 1 typedef struct _16_Bits_Struct
 2 {
 3 u16 bit0: 1;//occupies one byte
 4     u16 bit1 : 1;
 5     u16 bit2 : 1;
 6 u16 bit3: 1;
 7     u16 bit4 : 1;
 8 u16 bit5: 1;
 9 u16 bit6: 1;
10 u16 bit7: 1;
11     u16 bit8 : 1;
12     u16 bit9 : 1;
13     u16 bit10 : 1;
14 u16 bit11: 2;//occupies two bytes
15 u16 bit12: 3;//occupies three bytes
16 } _16_Bits_Struct;

Copy code

The above _16_Bits_Struct structure type occupies a total of 2 bytes, that is, 16 bits, but the number of bits occupied by its 13 member variables is not all the same. The number after the ":" can determine how many bits it occupies. The code is as follows, operating a bit of this structure type.

Copy code

 1     _16_Bits_Struct _16_bits;
 2     unsigned short _16bits_data;
 3 memset(&_16_bits, 0, sizeof(_16_Bits_Struct));//clear its memory to 0
 4 
 5     _16_bits.bit2 = 1;
 6     _16_bits.bit5 = 1;
 7     _16_bits.bit8 = 5;
 8 
 9     _16bits_data = *((unsigned short*)(&_16_bits));
10 
11     printf("_16bits_data = %0xH\n", _16bits_data);

Copy code

The output is:

It can be seen from the result that in the structure, from bit0 to bit12, from low to high. In line 7 of the above code, although 5 is written to bit8, because it only occupies one bit, only the lowest bit of 5(D)=0101(B) is taken, which is 1. So the final result is 124H, and its memory structure is shown in Figure 3 below.

Figure 3 Structure memory structure diagram 

4. STM32F030 imitation position band operation #

With the basis of the above structure body position segment operation, it is very close to realize the bit band operation of imitating STM32F030. I plan to make the simplest one, to realize the operation of a certain pin of GPIO to achieve the function of turning on and off the LED.

From the reference manual of STM32F030, find the output register ODR of GPIO, and see its basic information as shown in Figure 4 below. This register is readable and writable (RW), so we only need to write one bit of this register Enter 1, then this pin will output 1, and write 0 to output 0 (Of course, the prerequisite is that you configure it to output mode and enable its clock).

Figure 4 ODR register structure diagram of GPIO

How do I manipulate this register only one bit at a time, let's look at the following code to explain.

Copy code

 1 typedef struct _16_Bits_Struct
 2 {
 3 u16 bit0: 1;
 4     u16 bit1 : 1;
 5     u16 bit2 : 1;
 6 u16 bit3: 1;
 7     u16 bit4 : 1;
 8 u16 bit5: 1;
 9 u16 bit6: 1;
10 u16 bit7: 1;
11     u16 bit8 : 1;
12     u16 bit9 : 1;
13     u16 bit10 : 1;
14     u16 bit11 : 1;
15     u16 bit12 : 1;
16 u16 bit13: 1;
17     u16 bit14 : 1;
18     u16 bit15 : 1;
19 } Bits_16_TypeDef;
20 #define LED_GPIO_CLK   RCC_AHBPeriph_GPIOA 
21 #define LED_PORT       GPIOA
22 #define LED_PIN        GPIO_Pin_4
23 //Use the bit segment operation of the structure, compatible with the bit band operation of Cortex-M3.
24 #define LED_PORT_OUT    ((Bits_16_TypeDef *)(&(LED_PORT->ODR)))
25 #define LED             (LED_PORT_OUT->bit4) 

Copy code

 My hardware connection is: LED is connected to pin 4 of GPIOA. Lines 1 to 19 have been explained in the previous structure knowledge, and 20 to 22 are just some macro definitions for better code transplantation, but don't need it. Line 24 is more important: first take out the address of GPIOA->ODR, and then force it into Bits_16_TypeDef *  type (note that it is a pointer type). After being converted to this type, ODR has the characteristics of bit fields, so bit operations can be performed on it. Line 25 defines the LED connected to PA.4 as the 4th bit of GPIOA->ODR.

With such an operation, it is easy to want our LED to turn on and off. The code is as follows.

1 LED = 0; // LED 亮
2 LED = 1; // LED 灭

 Depending on the hardware connection, the effect may be reversed. Seeing this, do you think it's easy to operate?

The complete code is as follows:

led.c

led.h

mytype.h

 

 

I. Introduction

I usually use STM32F1 and F4. Many programs refer to Punctual Atom tutorials. The code includes the header file and their sys.h. This mainly implements the bitband operation of stm32. What is the bitband? The blogger did not go deep. Research, but can directly read and write a bit of the GPIO port, for example:

PAout(1) = 1;//GPIOA Pin1 output high level

 if(PAin(2)==1);//Determine whether GPIOA Pin2 is high

It is clear and intuitive to use, but recently I used STM32F0 and found that F0 has no bit bands. Naturally, the bit band operations in the punctual atom sys.h cannot be transplanted to F0. Is that no way? Baidu found that bit fields can be used To realize the imitation bit band operation, let's write a STMF0 sys.h, not much nonsense, just look at the following code. 

 

Two, code implementation

The code is divided into three steps. You can create a new header file named sys.h and place it in it:

(1) Because the GPIOX->ODR and GPIOX->IDR registers are both valid in the lower 16 bits, first define a structure bit field with a size of 2 bytes (16 bits), and each bit represents an IO port. And use volatile to prevent optimization by the compiler. If you don’t add volatile, like PAout(0)=1;PAout(1)=1; originally set to 1, it may be optimized to GPIOA->ODR=0x03, set to 1 together Yes, this is a fatal error, and it will make mistakes when simulating I2C and SPI timing.

//定义GPIO结构体位域
typedef struct
{
   volatile unsigned short bit0 : 1;
   volatile unsigned short bit1 : 1;
   volatile unsigned short bit2 : 1;
   volatile unsigned short bit3 : 1;
   volatile unsigned short bit4 : 1;
   volatile unsigned short bit5 : 1;
   volatile unsigned short bit6 : 1;
   volatile unsigned short bit7 : 1;
   volatile unsigned short bit8 : 1;
   volatile unsigned short bit9 : 1;
   volatile unsigned short bit10 : 1;
   volatile unsigned short bit11 : 1;
   volatile unsigned short bit12 : 1;
   volatile unsigned short bit13 : 1;
   volatile unsigned short bit14 : 1;
   volatile unsigned short bit15 : 1;
 
} GPIO_Bit_TypeDef;

 

(2) Forcibly convert the register address & (GPIOX->ODR) and & (GPIOX->IDR) into GPIO_Bit_TypeDef* pointers, and replace them with the identifier PORTX_OUT or PORTX_IN using the macro definition

#define PORTA_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOA->ODR)))
#define PORTA_IN     ((GPIO_Bit_TypeDef *)(&(GPIOA->IDR)))
#define PORTB_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOB->ODR)))
#define PORTB_IN     ((GPIO_Bit_TypeDef *)(&(GPIOB->IDR)))
#define PORTC_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOC->ODR)))
#define PORTC_IN     ((GPIO_Bit_TypeDef *)(&(GPIOC->IDR)))
#define PORTD_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOD->ODR)))
#define PORTD_IN     ((GPIO_Bit_TypeDef *)(&(GPIOD->IDR)))
#define PORTE_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOE->ODR)))
#define PORTE_IN     ((GPIO_Bit_TypeDef *)(&(GPIOE->IDR)))
#define PORTF_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOF->ODR)))
#define PORTF_IN     ((GPIO_Bit_TypeDef *)(&(GPIOF->IDR)))
#define PORTG_OUT    ((GPIO_Bit_TypeDef *)(&(GPIOG->ODR)))
#define PORTG_IN     ((GPIO_Bit_TypeDef *)(&(GPIOG->IDR)))

 

(3) Use macro function and ## string splicing to realize IO port operation. The function name is consistent with the one in punctual atom sys.h, which is convenient for other programs to be transplanted. Here is a mention of "##" splicing, which is a special macro symbol, ## means splicing left and right strings together

For example: #define GPIO(io) GPIO##io then GPIO(A) will be replaced with GPIOA

Here, if the input n is 4, it will become bit4, and if n is 8, it will become bit8

#define PAout(n) (PORTA_OUT->bit##n)
#define PAin(n)  (PORTA_IN->bit##n)
#define PBout(n) (PORTB_OUT->bit##n)
#define PBin(n)  (PORTB_IN->bit##n)
#define PCout(n) (PORTC_OUT->bit##n)
#define PCin(n)  (PORTC_IN->bit##n)
#define PDout(n) (PORTD_OUT->bit##n)
#define PDin(n)  (PORTD_IN->bit##n)
#define PEout(n) (PORTE_OUT->bit##n)
#define PEin(n)  (PORTE_IN->bit##n)
#define PFout(n) (PORTF_OUT->bit##n)
#define PFin(n)  (PORTF_IN->bit##n)
#define PGout(n) (PORTG_OUT->bit##n)
#define PGin(n)  (PORTG_IN->bit##n)

 

Three, routine

It is very simple to use in practice. It is the same as on F1 and F4. Take lighting as an example. After initializing GPIO, just assign it directly.

#define LED PAout(4)
void LED_Init(void);
 
//点灯测试
int main(void)
{
	LED_Init();
	delay_init();
  while (1)
  {
		LED=1;
		delay_ms(500);
		LED=0;
		delay_ms(500);
  }
}
 
void LED_Init(void)
{
 GPIO_InitTypeDef  GPIO_InitStructure;
 	
 RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);	 //使能PA端口时钟	
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				 //LED0-->PB.5 端口配置
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; 		 //输出
 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		 //IO口速度为50MHz
 GPIO_InitStructure.GPIO_OType= GPIO_OType_PP;//推挽
 GPIO_InitStructure.GPIO_PuPd= GPIO_PuPd_NOPULL;//无上下拉
 GPIO_Init(GPIOA, &GPIO_InitStructure);	
	//
 GPIO_SetBits(GPIOA,GPIO_Pin_4);						 //PA.4 输出高
 
}

 

 

 

 

 

 

 

 

 

 

 

 

Guess you like

Origin blog.csdn.net/qq_36958104/article/details/111983036