STM32 register mode turns on the LED water lamp

1, What is a register

Register is a high-speed storage unit with limited storage capacity in CPU, which can be used to temporarily store instructions, data and addresses.
In short, if our computer is compared to a building, and the register is every house in the building, the register address can be regarded as the house number, but the house number is a little special, which is composed of 0.1 bit stream.

GPIO

GPIO is the abbreviation of general input and output port, that is, the controllable pin of STM32. The GPIO pin of STM32 chip is connected with external devices to realize the functions of external communication, control and data acquisition.
All GPIO pins have basic input and output functions.

Working mode:

 typedef enum
 {
    GPIO_Mode_AIN = 0x0, // Analog input
    GPIO_Mode_IN_FLOATING = 0x04, // Floating input
    GPIO_Mode_IPD = 0x28, // Drop down input
    GPIO_Mode_IPU = 0x48, // Pull up input
    GPIO_Mode_Out_OD = 0x14, // Open drain output
    GPIO_Mode_Out_PP = 0x10, // Push pull output
    GPIO_Mode_AF_OD = 0x1C, // Multiplexed open drain output
    GPIO_Mode_AF_PP = 0x18 // Multiplexed push-pull output
 } GPIOMode_TypeDef;

When we turn on the LED, we need to set it to push-pull output mode.

See details: STM32 register introduction, address search, and direct operation register

2, Use the register to turn on the LED

1. Establish project template

stm32 provides a firmware library encapsulated in c language. We can directly call the corresponding library functions for what functions we want to achieve.
To use the ST firmware library, you can create a project template for us to call functions.
For detailed establishment process, please refer to: Establishment of stm32f103c8t6 engineering template

1.1 establishment of relevant documents
Create a new general folder to store all programs of the project, and then create six folders: CORE, HARDWARE, OBJ, FWLIB, SYSTEM and USER. Among them, HARDWARE folder is used to store peripheral HARDWARE code, OBJ is used to store generated debugging code, and FWLIB is various. c and. h files, as shown in the following figure:


CORE folder:

HARDWARE folder:

FWLib folder:


SYSTEM folder:

USER folder:

1.2 establishment of the project
Open Keil and create a new project in the USER folder. For the specific process, refer to:

Note that the chip model here is STM32F103C8 (selected according to its own chip);
In addition, you do not need to check Startup and CORE when selecting the running environment.



Add five custom folders in the Groups window:

Add corresponding files to each folder:





After adding, you can view it in the work bar:

1.3 configuration environment
Right click Target1 to enter Options for Target 'Target 1'

Click Target, you can see that the STM chip is STM32F103C8, and modify the crystal oscillator frequency value to 8

Click Output, where select folder for objects is the directory where the generated HEX is stored. Here, select and store it in the established OBJ folder. Create HEX File is used to generate executable code file (the HEX format file of MCU chip can be written by programmer, and the file extension is. HEX), which is used to download to the development board
of

Click the C/C + + option
a. First, set the definition to USE_STDPERIPH_DRIVER,STM32F10X_MD,
b. Then click Add Include Paths

The specific path is the path previously added to the project:

After adding, it is as follows:

So far, the establishment of the project has been basically completed.

  1. Configure GPIO ports
    GPIO is the abbreviation of general input and output port. In short, it is the controllable pin of STM32. The GPIO pin of STM32 chip is connected with external devices to realize the functions of external communication, control and data acquisition.
    There are three steps to initialize and set the GPIO port:
  • Clock configuration
  • Input / output mode setting
  • Maximum rate setting

2.1. Configure clock enable
Why configure the clock? In order to save power, the default clock is off. Before configuring any resources of STM32, the clock must be enabled first.

 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);  //Turn on GPIOB port clock

2.2. Initialize structure
A structure is provided in the library function to configure the input / output mode setting and maximum rate setting of GPIO port.
The structure defined is as follows:

// @file    stm32f10x_gpio.h
typedef struct
{
  uint16_t GPIO_Pin;           /*!< Select the GPIO pin to configure */

  GPIOSpeed_TypeDef GPIO_Speed;  /*!< Select the rate of the GPIO pin */

  GPIOMode_TypeDef GPIO_Mode;    /*!< Select the operating mode of GPIO pin */
}GPIO_InitTypeDef;

This structure contains the information required to initialize GPIO, including pin number, working mode and output rate.
The idea of designing this structure is: before initializing GPIO, first define such a structure variable, configure the GPIO mode as required, assign values to each member of this structure, and then take this variable as the input parameter of "GPIO initialization function". This function can configure registers according to the contents of this variable value, So as to realize the initialization of GPIO.
2.3. Configure input / output mode
The configuration port bit is universal push-pull output, and the speed is 2M

    GPIO_InitTypeDef   GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;  			//The output mode is universal push-pull output
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4 ;             		//The selected output port is GPIO_ Pin_ four
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;				//The output speed is 2M
	
	GPIO_Init(GPIOA,&GPIO_InitStruct);

So far a GPIOB_Pin_4 after configuration, we can finally control an LED.
3. Main functions
3.1.led.h function

#ifndef _LED_H
#define _LED_H

#include "stm32f10x.h"
void LED_R_TOGGLE(void);
void LED_G_TOGGLE(void);
void LED_Y_TOGGLE(void);
void LED_Init(void);
#endif

3.2.led.c function

#include "led.h"
#include "delay.h"

void LED_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOC,ENABLE);  //Turn on the clock of the peripheral GPIOB
	
	GPIO_InitTypeDef   GPIO_InitStruct;
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;  			//The output mode is universal push-pull output
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4 ;             //The selected port is GPIO_ Pin_ four
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;				//The output speed is 2M
	GPIO_Init(GPIOA,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;  			//The output mode is universal push-pull output
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10 ;             //The selected port is GPIO_ Pin_ one
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;				//The output speed is 2M
	GPIO_Init(GPIOB,&GPIO_InitStruct);
	
	GPIO_InitStruct.GPIO_Mode=GPIO_Mode_Out_PP;  			//The output mode is universal push-pull output
	GPIO_InitStruct.GPIO_Pin=GPIO_Pin_14 ;             //The selected port is GPIO_ Pin_ fourteen
	GPIO_InitStruct.GPIO_Speed=GPIO_Speed_2MHz;				//The output speed is 2M
	GPIO_Init(GPIOC,&GPIO_InitStruct);
}

void LED_R_TOGGLE(void)
{
	GPIO_SetBits(GPIOA, GPIO_Pin_4);
	delay_ms(500);
	GPIO_ResetBits(GPIOA,GPIO_Pin_4);	
}
void LED_G_TOGGLE(void)
{
	GPIO_SetBits(GPIOB, GPIO_Pin_10);
	delay_ms(500);
	GPIO_ResetBits(GPIOB,GPIO_Pin_10);
}
void LED_Y_TOGGLE(void)
{
	GPIO_SetBits(GPIOC, GPIO_Pin_14);	
	delay_ms(500);
	GPIO_ResetBits(GPIOC,GPIO_Pin_14);
}

3.3.delay.h function

#ifndef __DELAY_H
#define __DELAY_H 			   
#include "sys.h"  
	 
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);

#endif

3.4.delay.c function
This experiment calls the delay function written by the punctual atom to realize that the three LED lights flash in turn after a delay of 1s. I won't introduce more here. If you are interested, you can try to write it yourself.

#include "delay.h"
// 	 
//If you need to use OS, include the following header file
#if SYSTEM_SUPPORT_OS
#include "includes.h" 					// ucos usage	  
#endif 

static u8  fac_us=0;							//Delay multiplier			   
static u16 fac_ms=0;							//MS delay multiplier, in ucos, represents the number of ms per beat
	
	
#if SYSTEM_SUPPORT_OS 							// If system_ SUPPORT_ The OS is defined, indicating that the OS is to be supported (not limited to UCOS)
#ifdef  	 OS_CRITICAL_METHOD 						// OS_CRITICAL_METHOD is defined to support UCOSII				
#define delay_osrunning 		 OSRunning 			// Whether the OS is running flag, 0, not running; 1. In operation
#define delay_ostickspersec 	 OS_TICKS_PER_SEC 	// OS clock beat, i.e. scheduling times per second
#define delay_osintnesting  	 OSIntNesting 		// Break nesting level, that is, the number of times to break nesting
#endif

//Support UCOSIII
#ifdef  	 CPU_CFG_CRITICAL_METHOD 					// CPU_CFG_CRITICAL_METHOD is defined to support UCOSIII	
#define delay_osrunning 		 OSRunning 			// Whether the OS is running flag, 0, not running; 1. In operation
#define delay_ostickspersec 	 OSCfg_TickRate_Hz 	// OS clock beat, i.e. scheduling times per second
#define delay_osintnesting  	 OSIntNestingCtr 		// Break nesting level, that is, the number of times to break nesting
#endif

//In case of us level delay, turn off task scheduling (to prevent interrupting us level delay)
void delay_osschedlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD    				// Use UCOSIII
	OS_ERR err; 
	OSSchedLock(&err);							//In ucosiiii mode, scheduling is prohibited to prevent interruption and delay
#else 											// Otherwise, UCOSII
	OSSchedLock();								//In UCOSII mode, scheduling is prohibited to prevent interruption and delay
#endif
}

//Resume task scheduling in case of us level delay
void delay_osschedunlock(void)
{	
#ifdef CPU_CFG_CRITICAL_METHOD    				// Use UCOSIII
	OS_ERR err; 
	OSSchedUnlock(&err);						//UCOSIII mode, resume scheduling
#else 											// Otherwise, UCOSII
	OSSchedUnlock();							//UCOSII mode, resume scheduling
#endif
}

//Call the delay function of the OS
//ticks: delayed beats
void delay_ostimedly(u32 ticks)
{
#ifdef CPU_CFG_CRITICAL_METHOD
	OS_ERR err; 
	OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err);	//Ucosiiii delay adopts periodic mode
#else
	OSTimeDly(ticks);							//UCOSII delay
#endif 
}
 
//systick interrupt service function, which is used when using ucos
void SysTick_Handler(void)
{	
	if(delay_osrunning==1)						//When the OS starts running, it performs normal scheduling processing
	{
		OSIntEnter();							//Entry interrupt
		OSTimeTick();       					//Call ucos clock service program               
		OSIntExit();       	 					//Trigger task switching soft interrupt
	}
}
#endif
		   
//Initialization delay function
//When using OS, this function initializes the clock beat of OS
//SYSTICK's clock is fixed to 1 / 8 of HCLK's clock
//SYSCLK: system clock
void delay_init()
{
#if SYSTEM_SUPPORT_OS   							// If necessary, support OS
	u32 reload;
#endif
	SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);	//Select external clock HCLK/8
	fac_us=SystemCoreClock/8000000;				//Is 1 / 8 of the system clock  
#if SYSTEM_SUPPORT_OS   							// If necessary, support OS
	reload=SystemCoreClock/8000000;				//The number of counts per second is in M  
	reload*=1000000/delay_ostickspersec;		//According to delay_ostickspersec sets the overflow time
												//reload is a 24 bit register with a maximum value of 16777216. At 72M, it is about 1.86s	
	fac_ms=1000/delay_ostickspersec;			//Represents the minimum unit that the OS can delay	   

	SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk;   	//Enable SYSTICK interrupt
	SysTick->LOAD=reload; 						//Every 1/delay_ostickspersec is interrupted once per second	
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;   	//Turn on SYSTICK    

#else
	fac_ms=(u16)fac_us*1000;					//Under non OS, it represents the number of systick clocks required for each ms   
#endif
}								    

#if SYSTEM_SUPPORT_OS   							// If necessary, support OS
//Delay nus
//nus is the number of us to delay		    								   
void delay_us(u32 nus)
{		
	u32 ticks;
	u32 told,tnow,tcnt=0;
	u32 reload=SysTick->LOAD;					//Value of LOAD	    	 
	ticks=nus*fac_us; 							//Number of beats required	  		 
	tcnt=0;
	delay_osschedlock();						//Prevent OS scheduling and interrupt us delay
	told=SysTick->VAL;        					//Counter value when entering
	while(1)
	{
		tnow=SysTick->VAL;	
		if(tnow!=told)
		{	    
			if(tnow<told)tcnt+=told-tnow;		//Note that SYSTICK is a decrement counter
			else tcnt+=reload-tnow+told;	    
			told=tnow;
			if(tcnt>=ticks)break;				//If the time exceeds / equals the time to be delayed, exit
		}  
	};
	delay_osschedunlock();						//Resume OS scheduling									    
}
//Delay nms
//nms: number of ms to delay
void delay_ms(u16 nms)
{	
	if(delay_osrunning&&delay_osintnesting==0)	//If the OS is already running and is not in an interrupt (task scheduling cannot be performed in an interrupt)	    
	{		 
		if(nms>=fac_ms)							//The delay time is greater than the minimum time period of the OS 
		{ 
   			delay_ostimedly(nms/fac_ms);		//OS delay
		}
		nms%=fac_ms;							//The OS can no longer provide such a small delay, so it adopts the ordinary delay mode    
	}
	delay_us((u32)(nms*1000));					//Common mode delay  
}
#else / / when OS is not used
//Delay nus
//nus is the number of us to delay		    								   
void delay_us(u32 nus)
{		
	u32 temp;	    	 
	SysTick->LOAD=nus*fac_us; 					//Time loading	  		 
	SysTick->VAL=0x00;        					//Clear counter
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//Start counting down	  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		//Waiting time arrives   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//Turn off counter
	SysTick->VAL =0X00;      					 //Clear counter	 
}
//Delay nms
//Note the range of nms
//Systick - > load is a 24 bit register, so the maximum delay is:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK is in Hz and NMS is in ms
//For 72M, NMS < = 1864 
void delay_ms(u16 nms)
{	 		  	  
	u32 temp;		   
	SysTick->LOAD=(u32)nms*fac_ms;				//Time loading (systick - > load is 24bit)
	SysTick->VAL =0x00;							//Clear counter
	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;	//Start counting down  
	do
	{
		temp=SysTick->CTRL;
	}while((temp&0x01)&&!(temp&(1<<16)));		//Waiting time arrives   
	SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;	//Turn off counter
	SysTick->VAL =0X00;       					//Clear counter	  	    
} 
#endif 

3.5.main.c function

#include  "stm32f10x.h"
#include "delay.h"
#include "led.h"
int main(void)
{			  
	LED_Init();	
	delay_init();	                //Use the system tick timer and delay initialization
	
	while(1)						//Cycle on
	{
		LED_R_TOGGLE();
		delay_ms(500);				//Delay 1s after the red light is on
		LED_G_TOGGLE();
		delay_ms(500);				//Delay 1 s after the green light is on
		LED_Y_TOGGLE();
		delay_ms(500);				//Delay 1s after the yellow light is on
	}
}
  1. Create HEX File
    Click the compile button in the upper left corner to debug and compile, and an error will pop up:

The reason for the search error is:
The default encoding mode of MDK5 is C89, which does not support the programming definition of string spaces in C++ / C. It needs to be supported after changing to C99 coding mode.
Solution: check C99 Mode of C/C + + in the configuration


You can also see the generated. hex file stored in the created OBJ folder

  1. Build circuit
    In this experiment, c8t6 is used on the bread board to control the flashing of red, green and yellow lights in turn. Therefore, it is necessary to be familiar with the use of bread board. For a brief introduction to the use of bread board, please refer to: Introduction to bread board
    The built circuit diagram is as follows:

    Be careful not to insert the pin incorrectly, otherwise the experiment will not succeed

  2. Download program with serial port
    The USB to serial port driver chip for STM32 development board used in the experiment is CH340. To use the serial port, you must first install the USB to serial port driver - CH340 version in the computer. See the download link above.

If the USB to serial driver is successfully installed, there is no problem with the connection between the USB cable and the board. The serial port can be identified in computer - > Management - > Device Manager - > port.

Use the USB cable to connect the USB to serial port interface between the computer and the development board: USB TO UART to power up the development board.
Open the mcuisp software and configure it as follows:
① Search the serial port and set the baud rate to 115200 (try not to set it too high)
② Select the HEX file to download
③ Execute after verification and programming
④ DTR low level resets and RTS high level enters bootloader
⑤ Start programming. If it is always connected, press the reset key of the development board

The prompt after successful download after compilation is shown in the figure below, indicating that the HEX file has been successfully burned into the chip.

7. Experimental results

4, Summary
This experiment mainly carried out the LED register lighting experiment. Before, it had been written with library functions and had not used registers. This time, I really felt its cumbersome use, especially the GPIO address. I also needed to consult the manual, which was very poor in readability and encountered many difficulties in the programming process. However, I also learned the addressing principle of registers by consulting materials, Although cumbersome, it feels good to communicate with the computer more intuitively.

5, Reference articles
STM32F103 register mode turns on the LED water flow lamp

Tags: Ubuntu

Posted on Sun, 24 Oct 2021 09:53:01 -0400 by nogray