STM32F103 register mode turns on the LED water flow lamp

Keywords: Single-Chip Microcomputer stm32 ARM

Experimental requirements: build the circuit with STM32 minimum system core board (STM32F103C8T6) + panel board + 3 red, green and blue LEDs, use GPIOB, GPIOC and GPIOD to control the LED lights, flash in turn, and the interval is 1 second. 1) Write the program design idea, including the register address and detailed parameters of GPIOx port; 2) It is programmed with assembly language and C language.

catalogue

1, Experimental principle

1. Register mapping

2. Three steps for initialization and setting of GPIO port

3. Design ideas

2, Experimental steps

1. Understanding registers

2. Find register address

3. Initial preparation

4. Code

5. Compile to generate HEX file

6. Hardware connection

3, Experimental results

4, Experimental summary

5, References

1, Experimental principle

1. Register mapping

Each register occupies 32 bits. The initial content of register operation is to find the starting address of the register. This step can be completed by searching the data manual, so how to use this manual?

You know, the mapping address of the register is divided into three steps. First, find the base address of the GPIOB, then find the address offset of the port input register, and finally find the corresponding port input data.

2. Three steps for initialization and setting of GPIO port

(1) Clock configuration

In order to reduce power consumption, first configure the clock enable. The information of the configured clock can be obtained by referring to the manual (name of clock control)   The word is called RCC).

In order to configure the clock enable, first know the address of the clock enable register, then look up the manual and assign the bit of the corresponding function to 1, that is, turn on the GPIOB clock

(2) Input / output mode setting

In order to output high level and low level, the LED water lamp needs to be configured as output. Find the address of the corresponding register through     From the reading materials, we can know that there are four modes of register output. According to the function of LED water lamp, it is set as general     Push-pull output (it can output high and low levels and connect digital devices; push-pull structure generally refers to that two triodes receive two complementary signals respectively       No. is always controlled when one triode is on and the other is off. The high and low levels are determined by the power supply of the IC.)

(3) Maximum rate setting

For STM32F103 series chips, the fastest configuration is 50Mhz, but the speed is not the faster the better. The higher the speed configuration, the greater the noise and the greater the power consumption, so the appropriate speed should be configured here.

3. Design ideas

The design idea of water lamp is: control register output 1, turn on the LED lamp, after a period of time, control the LED lamp off, and then add a circular statement to show the effect of water lamp.

2, Experimental steps

According to the above experimental principles, start the formal experiment.

1. Understanding registers

(1) GPIO register

Here we use GPIO registers, which can be divided into many classes according to function:

Each GPIO port has two 32-bit configuration registers (GPIOx_CRL,GPIOx_CRH, also known as control registers),  

Two 32-bit data registers (GPIOx_IDR,GPIOx_ODR),

A 32-bit / reset register (GPIOx_BSRR),

A 16 bit reset register (GPIOx_BRR) and a 32-bit lock register (GPIOx_LCKR).

Here we use the port configuration low register (GPIOx_CRL)

(2)GPIO_CRL

The CRL of STM32 controls the low 8-bit MODE of each IO port (A-G). The bits of each IO port occupy 4 bits of the CRL. The high two bits are CNF and the low two bits are MODE. In fact, the role of CRH is exactly the same as that of CRL, except that CRH controls the high 8 bits and CRL controls the low 8 bits.

2. Find register address

In order to configure the port of the register and realize various functions, we need to find the address of the port first.

Here, we find the port address by looking up the STM32F103 Chinese tutorial and reference manual.

This is not the only complex way to assign values to ports, but it is more helpful for us to understand the principle of registers.

Here are some common examples.

(1) First find the starting address of GPIOB port, which is 0x4001 and 0c00

(2) Find the port configuration of GPIO register. The offset address of low register is 0X00

 

  Thus, the address of gpiob - > CRL is 0X4001 0C00

(3) Find that the address of the clock enable register is bit 3 of RCC_APB2ENR register, which controls the opening and closing of GPIOB clock, and set 1 to control the opening of clock

  (4) Locate port configuration low register (GPIOx_CRL)

The CNF bit is used to configure the input / output mode. Here, the general push-pull output mode is selected according to the function, which is realized through the following code

GPIOC_CRH &= ~(0x0F<<(4*5));
GPIOC_CRH |= (1<<(4*5));

The MODE bit is used to configure the speed. Here, the maximum speed 2MHz is selected

(5) Locate port output register (GPIOx_ODR)

The port output register is a pin level output register, which needs to be controlled to turn on and off the LED.

3. Initial preparation

  (1) Establish project template

In order to better learn stm32, it is necessary to call library functions and establish project templates. Create a new general folder to store all programs of the project, and then create six folders: CORE, HARDWARE, OBJ, FWLIB, SYSTEM and USER.

The 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

The information is available here Punctual atom openedv data download address , I downloaded the rct6 data of the mini board, as follows

  What I need to do now is to transfer the files in the data to the corresponding folder I have created

  The contents of each folder are as follows

  • CORE

  • HARDWARE 
  • STM32F10x_FWLib

  • SYSTEM

  •  USER

  (2) Build project

Open keil software

Click New uVision Project in Project in the keil menu bar to create a new Project and save it to the USER folder

  Select STM32F103C8 for the device and click OK

  Note that in the pop-up manage runtime environment window, click cancel

  Right click Target 1 and select Manage Project Items

In the upper right corner of the second column, create the name of the group

  Add files in each group. The files are in several folders of the project created in the previous step, as follows

  • CORE

  •  HARDWARE

  • SYSTEM

  •  USER

  •  FWLIB

  You can see the added groups

  (3) Disposition

Right click Target1 and select Options for Target 'Target 1'

 

  In the Target column, modify the crystal oscillator frequency value to 8

In the Output column, click Select Folder for Objects, select the directory where the generated hex file is stored, select it to be stored in the OBJ folder created earlier, and then check Create HEX File to generate hex files and download them to the development board

In the column of C/C + +, fill in the column of Define with USE_STDPERIPH_DRIVER,STM32F10X_MD, and then add paths in Include Paths, as shown in the figure

Add the first few folders to the entry path, and then click OK   Here, the new project template is basically completed.

  (4) Configure GPIO ports

Configure the GPIO port according to the three steps of GPIO port initialization and setting mentioned in the experimental principle

The first is the clock setting

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

Then the input / output setting and maximum rate setting. The output mode selected here is universal push-pull output, and the maximum rate 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);

4. Code

(1)led.h

#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

 (2)led.c

#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)delay.h

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

#endif

(4)delay.c

#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 

(5)main.c

#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
	}
}

5. Compile to generate HEX file

Compile successfully, generate HEX file

6. Hardware connection

(1) Use bread board to build circuit

According to the chip manual, build the circuit on the bread board. The connection method is as follows

(2) Install serial driver

Install the usb serial port driver on the computer, and a new serial port device (COM3) can be searched in the device manager

(3) Burn

Run the burning software mcuisp to configure  

  • Click search serial port to automatically search serial port, and select baud rate of 256000 in bps
  • Lower left corner setting: DTR low level reset, RTS high level into BootLoader
  • Read the device information. At this time, if the information in the interface appears, it indicates that the serial port and MCU are successfully connected.
  • Select hex file
  • Click start programming to download the program

  The HEX file is successfully burned into the chip.

3, Experimental results

  It can be seen that the effect of running water light, red light, green light and yellow light flash in turn

4, Experimental summary

This experiment was very challenging for me. At first, I didn't have a clue, but later, I solved many problems by constantly consulting materials and asking my classmates. In the process of hands-on practice, I also learned and understood the basic knowledge about stm32. While understanding the register principle, I also learned the three steps of GPIO port initialization and setting, which is very helpful for me to learn this course.

5, References

https://blog.csdn.net/big_blingbling/article/details/81427764

https://blog.csdn.net/weixin_42827999/article/details/101699674

https://blog.csdn.net/geek_monkey/article/details/86291377

Posted by Stegs on Sun, 24 Oct 2021 07:53:58 -0700