嵌入式学习 STM32F10系列通用

本篇文章主要供本人使用,使用的是标准库,如果能帮助你的尽管CV就好,持续更新!!!

正文开始

补充一个C语言语法

‘\’这个是续行符,后面不能跟任何东西(空格也不行)

一.GPIO构建库编程流程

        1.初始化时钟:

        调用RCC_APB2PeriphClockCmd 函数(在STM32f10x_rcc.h中)

        2.创建初始化GPIO结构体

        3.调用初始化函数 

//GPIO_XXX.h文件

//在STM32F10x.h中能找到GPIOX(X=A,B,C...)
#define  USART_GPIO_PORT_TX 			GPIOA

//在STM32F10x_gpio.h中能找到
#define  USART_GPIO_PIN_TX              GP0IO_Pin_9 

//在rcc头文件中拉取GPIOA的时钟线
#define  USART_GPIO_CLK                 RCC_APB2Periph_GPIOA 

//GPIO_XXX.c文件
void GPIO_Config()
{
    //首先我们创建GPIO结构体 
    GPIO_InitTypeDef   GPIO_Struct;
    GPIO_Struct.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽输出GPIO_Mode_AF_PP
	GPIO_Struct.GPIO_Pin = USART_GPIO_PIN_TX ;
	GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(USART_GPIO_PORT_TX,&GPIO_Struct);
}

 参数详情

GPIO结构体
typedef struct
{
  uint16_t GPIO_Pin;            

  GPIOSpeed_TypeDef GPIO_Speed;  

  GPIOMode_TypeDef GPIO_Mode;   

}GPIO_InitTypeDef;

1.GPIO_Mode:

 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 // 复用推挽输出

2.GPIO_Pin:

#define GPIO_Pin_0                 ((uint16_t)0x0001)  /*!< Pin 0 selected */
#define GPIO_Pin_1                 ((uint16_t)0x0002)  /*!< Pin 1 selected */
#define GPIO_Pin_2                 ((uint16_t)0x0004)  /*!< Pin 2 selected */
#define GPIO_Pin_3                 ((uint16_t)0x0008)  /*!< Pin 3 selected */
#define GPIO_Pin_4                 ((uint16_t)0x0010)  /*!< Pin 4 selected */
#define GPIO_Pin_5                 ((uint16_t)0x0020)  /*!< Pin 5 selected */
#define GPIO_Pin_6                 ((uint16_t)0x0040)  /*!< Pin 6 selected */
#define GPIO_Pin_7                 ((uint16_t)0x0080)  /*!< Pin 7 selected */
#define GPIO_Pin_8                 ((uint16_t)0x0100)  /*!< Pin 8 selected */
#define GPIO_Pin_9                 ((uint16_t)0x0200)  /*!< Pin 9 selected */
#define GPIO_Pin_10                ((uint16_t)0x0400)  /*!< Pin 10 selected */
#define GPIO_Pin_11                ((uint16_t)0x0800)  /*!< Pin 11 selected */
#define GPIO_Pin_12                ((uint16_t)0x1000)  /*!< Pin 12 selected */
#define GPIO_Pin_13                ((uint16_t)0x2000)  /*!< Pin 13 selected */
#define GPIO_Pin_14                ((uint16_t)0x4000)  /*!< Pin 14 selected */
#define GPIO_Pin_15                ((uint16_t)0x8000)  /*!< Pin 15 selected */
#define GPIO_Pin_All               ((uint16_t)0xFFFF)  /*!< All pins selected */

 3.GPIO_speed:

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

 GPIO赋值两个函数

// 给对应端口的引脚置1
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  
  GPIOx->BSRR = GPIO_Pin;
}


// 置零
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
  /* Check the parameters */
  assert_param(IS_GPIO_ALL_PERIPH(GPIOx));
  assert_param(IS_GPIO_PIN(GPIO_Pin));
  
  GPIOx->BRR = GPIO_Pin;
}

二.GPIO 初始化按键中断

1.按键时钟和GPIO口宏定义

#define KEY1_INT_GPIO_PIN   GPIO_pin_0
#define KEY1_INT_PORT       GPIOA
#define KEY1_INT_CLK        RCC_APB2Periph_GPIOA 

2.初始化按键GPIO

void KEY_GPIO_Config()
{
    GPIO_InitTypeDef KEY1_Initstruct;
    //gpio
	RCC_APB2PeriphResetCmd(KEY1_GPIO_clk,ENABLE);
	KEY1_Initstruct.GPIO_Pin  = KEY1_GPIO_Pin;
	KEY1_Initstruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(KEY1_GPIO_PORT,&KEY1_Initstruct);
}

3.初始化EXTI

void KEY_EXTI_Config()
{
    EXTI_InitTypeDef EXTI_Initstruct;   EXTI结构体
  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);  打开EXTI时钟使能
	GPIO_EXTILineConfig(KEY1_GPIO_PORT, KEY1_GPIO_Pin);   让GPIO的终端线连接0线
	
	
	EXTI_Initstruct.EXTI_Line = EXTI_Line0;            //初始化零线
	EXTI_Initstruct.EXTI_Mode = EXTI_Mode_Interrupt;   //中断方式是外部中断
	EXTI_Initstruct.EXTI_Trigger = EXTI_Trigger_Rising; // 上升沿触发
	EXTI_Initstruct.EXTI_LineCmd = ENABLE;             // 外设中断使能
	EXTI_Init(&EXTI_Initstruct);
}

4.初始化NVIC

void NVIC_Config()
{
	NVIC_InitTypeDef NVIC_Initstruct;  //��misc.h ��
	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	NVIC_Initstruct.NVIC_IRQChannel = EXTI0_IRQn;
	NVIC_Initstruct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_Initstruct.NVIC_IRQChannelSubPriority = 1;	
	NVIC_Initstruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_Initstruct);
}

注意!!!

在it.c文件中写入中断触发需要执行的函数

我们外设的中断函数名字是已经写好的,我们需要在.s启动文件中找到对应的中断向量表

三.SYsTick 滴答定时器

他是一个24位递减的计数器,内嵌在NVIC中,Core-M3内核都有这个属于硬件中断我们通过调用他的systick_config()函数就可以初始化他了

1.系统定时器结构体

typedef struct
{
  /*******
  //状态与控制寄存器,可以通过这个寄存器的16位来判断上次的计数值是否为0
  //也就是是否完成了计数
  ********/
  __IO uint32_t CTRL;                         /*!< Offset: 0x00  SysTick Control and Status Register */
  
  //装载寄存器,存储的是初值
  __IO uint32_t LOAD;                         /*!< Offset: 0x04  SysTick Reload Value Register       */
  //当前值
  __IO uint32_t VAL;                          /*!< Offset: 0x08  SysTick Current Value Register      */
  __I  uint32_t CALIB;                        /*!< Offset: 0x0C  SysTick Calibration Register        */
} SysTick_Type;

2.系统定时器初始化

//TICKINT

static __INLINE uint32_t SysTick_Config(uint32_t ticks)
{ 
  //保护机制,系统定时器的值最大为24位
  if (ticks > SysTick_LOAD_RELOAD_Msk)  return (1);           
  //给重载寄存器赋初值                                                        
  SysTick->LOAD  = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; 
  //设置他的中断优先级
  NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1);  
  //给当前的值赋零
  SysTick->VAL   = 0;  
  //初始化状态和控制寄存器
  //CLKSOURCE 就是AHB还是 AHB/8 相当于是定时器的频率
  //ENABLE  使能
  //TICKINT 如果计数完了则会置1 抛异常
  SysTick->CTRL  = SysTick_CTRL_CLKSOURCE_Msk | 
                   SysTick_CTRL_TICKINT_Msk   | 
                   SysTick_CTRL_ENABLE_Msk;                  
  return (0);                                                 
}

3.头文件Sys_Tick.h

#ifndef __SYS_TICK_H
#define __SYS_TICK_H

void Sys_Tick_us(uint32_t us);
void Sys_Tick_ms(uint32_t ms);
#endif

毫秒和微妙函数

void Sys_Tick_us(uint32_t us)
{
	uint32_t i;
	SysTick_Config(72);
	
	for(i =0;i<us;i++)
	{
		while(!(SysTick->CTRL & (1<<16)));
	}
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}


void Sys_Tick_ms(uint32_t ms)
{

	uint32_t i;
	SysTick_Config(72000);
	
	for(i =0;i<ms;i++)
	{
		while(!(SysTick->CTRL & (1<<16)));
	}
	SysTick->CTRL &= ~SysTick_CTRL_ENABLE_Msk;
}Sys_Tick_us

四.串口通信

这里我是直接在画图板上总结好了这里直接扔截图过来

1.USART.h

define  DEBUG_USART1 1
#define  DEBUG_USART2 0
#define  DEBUG_USART3 0
#define  DEBUG_USART4 0
#define  DEBUG_USART5 0

//初始化USART
//1.在STM32.h文件中找USART1 
//2.在RCC.h文件中找时钟USART1的时钟
#if   DEBUG_USART1
#define  DEBUG_USARTx                   USART1   									//在STM32f10x.h中找
#define  DEBUG_USART_CLK                RCC_APB2Periph_USART1			//在rcc.h中找
#define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd		这就是个函数昂,之前误会了
#define  DEBUG_USART_BAUDRATE           115200
//GPIO_init

#define  USART_GPIO_PORT_TX 						GPIOA
#define  USART_GPIO_PIN_TX              GP0IO_Pin_9 
									//在rcc头文件中拉取GPIOA的时钟线
#define  USART_GPIO_CLK                 RCC_APB2Periph_GPIOA  
#define  DEBUG_USART_GPIO_APBxClkCmd    RCC_APB2PeriphClockCmd      ///这就是个函数昂,之前误会了
 
#define  USART_GPIO_PORT_RX 						GPIOA
#define  USART_GPIO_PIN_RX              GPIO_Pin_10

#define  DEBUG_USART_IRQ                USART1_IRQn   		//中断源
#define  DEBUG_USART_IRQHandler         USART1_IRQHandler //中断执行函数

#elif DEBUG_USART2
#define  DEBUG_USARTx                   USART2
#define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
#define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
#define  DEBUG_USART_BAUDRATE           115200

#elif DEBUG_USART3
#define  DEBUG_USARTx                   USART3
#define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
#define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
#define  DEBUG_USART_BAUDRATE           115200

#elif DEBUG_USART4
#define  DEBUG_USARTx                   USART4
#define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
#define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
#define  DEBUG_USART_BAUDRATE           115200

#elif DEBUG_USART5
#define  DEBUG_USARTx                   USART4
#define  DEBUG_USART_CLK                RCC_APB2Periph_USART1
#define  DEBUG_USART_APBxClkCmd         RCC_APB2PeriphClockCmd
#define  DEBUG_USART_BAUDRATE           115200
#endif

void NVIC_Config_init();
void USART_Config();
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data);

void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array,uint8_t num);
void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str);
#endif

这里我是用了条件编译,但是其他的串口信息还未更改,大家自行更改就行

2.NVIC初始化USART的中断优先级

void NVIC_Config_init()
{
	NVIC_InitTypeDef NVIC_Struct;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
	
	NVIC_Struct.NVIC_IRQChannel = USART1_IRQn;
	NVIC_Struct.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_Struct.NVIC_IRQChannelSubPriority = 1;
	NVIC_Struct.NVIC_IRQChannelCmd = ENABLE;	
	
	NVIC_Init(&NVIC_Struct);
}

3.配置USART.config

void USART_Config()
{
	
	USART_InitTypeDef Usart_Struct;
	GPIO_InitTypeDef GPIO_Struct;
	
	//NVIC
	NVIC_Config();
	//初始化时钟
	DEBUG_USART_GPIO_APBxClkCmd(RCC_APB2Periph_GPIOA ,ENABLE);
	DEBUG_USART_APBxClkCmd(RCC_APB2Periph_USART1,ENABLE);
	
	//Usart 
	Usart_Struct.USART_BaudRate 					 = DEBUG_USART_BAUDRATE;  //波特率
	Usart_Struct.USART_WordLength 				 = USART_WordLength_8b;   //字宽
	Usart_Struct.USART_StopBits 					 = USART_StopBits_1;			//停止位
	Usart_Struct.USART_Parity 						 = USART_Parity_No;				//校验位
	Usart_Struct.USART_HardwareFlowControl =  USART_HardwareFlowControl_None; //流控制
	Usart_Struct.USART_Mode = (USART_Mode_Rx |USART_Mode_Tx);
	USART_Init(DEBUG_USARTx, &Usart_Struct);
	
	
	//GPIO
	GPIO_Struct.GPIO_Mode = GPIO_Mode_AF_PP;  //这里需要更改
	GPIO_Struct.GPIO_Pin = USART_GPIO_PIN_TX ;
	GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(USART_GPIO_PORT_TX,&GPIO_Struct);
	
	GPIO_Struct.GPIO_Mode = GPIO_Mode_AF_PP;  //这里需要更改
	GPIO_Struct.GPIO_Pin = USART_GPIO_PIN_RX ;
	GPIO_Struct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(USART_GPIO_PORT_RX,&GPIO_Struct);
	
	
	// 使能串口接收中断
	USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE);	//少了
	
	// 使能串口
	USART_Cmd(DEBUG_USARTx, ENABLE);	//少了
}

4.串口的收发函数

//字节
void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t data)
{
	USART_SendData(pUSARTx, data);
	while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET );
}
//数组
void Usart_SendArray(USART_TypeDef* pUSARTx, uint8_t *array,uint8_t num)
{
	uint8_t i;
	for( i=0; i<num; i++ )
  {
		Usart_SendByte(pUSARTx, array[i]);
	}
	while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}

/* 发送字符串 */
void Usart_SendStr(USART_TypeDef* pUSARTx, uint8_t *str)
{
	uint8_t i=0;
	do
  {
		Usart_SendByte(pUSARTx, *(str+i));
		i++;
	}while(*(str+i) != '\0');
	while( USART_GetFlagStatus(pUSARTx, USART_FLAG_TC) == RESET );
}

5.fgutc和fputc

//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
		/* 发送一个字节数据到串口 */
		USART_SendData(DEBUG_USARTx, (uint8_t) ch);
		
		/* 等待发送完毕 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);		
	
		return (ch);
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
		/* 等待串口输入数据 */
		while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);

		return (int)USART_ReceiveData(DEBUG_USARTx);
}

2024年11月3日23:53分

---------------------------------------------------------------------------------------------------------------------------------

猜你喜欢

转载自blog.csdn.net/Path_of_programm/article/details/143472977