STM32学习——入门到放弃篇_1

1、单片机启动

        启动过程,先运行启动文件,启动文件里面有一段汇编代码,先执行汇编代码,接着配置时钟,随即进入主函数。

        查看单片机主频

        

2、自己配置时钟树

stm32的RCC系统时钟配置 以及RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t PLLM, uint32_t PLLN, uint32_t PLLP, uint32_t PLLQ)的配置 - chaina_家长 - 博客园 (cnblogs.com)

void RCC_Init(void)
{
	RCC_ClocksTypeDef RCC_Clocks;
	ErrorStatus 			HSEStartUpStaus;
	
	   
	RCC_DeInit();			// 把RCC外设初始化成复位状态,这句是必须的
	RCC_ClockSecuritySystemCmd(ENABLE);			//使能系统安全
	
	RCC_HSEConfig(RCC_HSE_ON);							//打开HSE,外部高速时钟
	HSEStartUpStaus = RCC_WaitForHSEStartUp();	//等待HSE开启

	if (SUCCESS == HSEStartUpStaus)		//成功开始分频
	{
//----------------------------------------------------------------------//
    // 使能FLASH 预存取缓冲区
    FLASH_PrefetchBufferCmd(ENABLE);
 
			 // SYSCLK周期与闪存访问时间的比例设置,这里统一设置成2
			 // 设置成2的时候,SYSCLK低于48M也可以工作,如果设置成0或者1的时候,
			 // 如果配置的SYSCLK超出了范围的话,则会进入硬件错误,程序就死了
			 // 0:0 < SYSCLK <= 24M
			 // 1:24< SYSCLK <= 48M
			 // 2:48< SYSCLK <= 72M
    FLASH_SetLatency(FLASH_Latency_2);
//----------------------------------------------------------------------//
		
		// AHB预分频因子设置为1分频,HCLK = SYSCLK 
		RCC_HCLKConfig(RCC_SYSCLK_Div1);		
		
		// APB1预分频因子设置为2分频,PCLK1 = HCLK/2
		RCC_PCLK1Config(RCC_SYSCLK_Div2);		
		
		// APB2预分频因子设置为1分频,PCLK2 = HCLK
		RCC_PCLK2Config(RCC_SYSCLK_Div1);			
		
//-----------------设置各种频率主要就是在这里设置-------------------//
     // 设置PLL时钟来源为HSE,HSE=8MHz
//      PLLM:PLL_VCO input clock =(HSE or HSI /PLLM)
//    	PLLN:PLL_VCO output clock =(PLL_VCP input clock)*PLLN
//    	PLLP:System Clock =PLL_VCO output clock/PLLP
//    	PLLQ:配置SD卡读写,USB等功能,暂时不用
    RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);
//------------------------------------------------------------------//
		
		// 开启PLL 
    RCC_PLLCmd(ENABLE);
		
		// 等待 PLL稳定
    while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
    {
    }
		
    // 当PLL稳定之后,把PLL时钟切换为系统时钟SYSCLK
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		
		// 读取时钟切换状态位,确保PLLCLK被选为系统时钟
    while (RCC_GetSYSCLKSource() != 0x08)
    {
    }
	}
	else
	{ // 如果HSE开启失败,那么程序就会来到这里,用户可在这里添加出错的代码处理
		// 当HSE开启失败或者故障的时候,单片机会自动把HSI设置为系统时钟,
		// HSI是内部的高速时钟,8MHZ
		while (1)
		{
		}
	}

}

3、GPIO口使用

        3.1、输出模式

// 1、配置GPIO外设时钟
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC | 
	                      RCC_AHBPeriph_GPIOD | RCC_AHBPeriph_GPIOF |  RCC_AHBPeriph_DMA1, ENABLE);


GPIO_InitTypeDef GPIO_InitStructure;    //配置结构体

  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; //配置的引脚                           
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                      //配置模式,OUTPUT/INPUT
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                 //速度50MHz
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                   	//输出模式
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;                 			//是否需要上拉
  GPIO_Init(GPIOA, &GPIO_InitStructure);														//配置A组引脚	

GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7);//引脚设置高电平
//GPIO_ResetBits(GPIOA,GPIO_Pin_0);        //A组GPIO引脚0设置低电平
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)    //置低电平
void GPIO_setBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)    //置高电平

         3.2、输入模式

// 1、配置GPIO外设时钟
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA | RCC_AHBPeriph_GPIOB | RCC_AHBPeriph_GPIOC | 
	                      RCC_AHBPeriph_GPIOD | RCC_AHBPeriph_GPIOF |  RCC_AHBPeriph_DMA1, ENABLE);

GPIO_InitTypeDef GPIO_InitStructure;

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_11|GPIO_Pin_15;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;    //根据电路图和芯片配置是否下拉
  GPIO_Init(GPIOA, &GPIO_InitStructure);

	if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0)    //读取电平

        3.3、转换功能

        通讯类的IIC、ADC等功能

4、NVIC配置 (嵌套中断控制器)

中断-NVIC与EXTI外设详解(超全面)-CSDN博客

void Hardware_NVIC_Init(void)		//设置中断优先级
{
	NVIC_InitTypeDef NVIC_InitStructure;

	//配置GPIA_Pin_0口中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn ;						//中断源	PA0中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;		//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;						//优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;							//是否启用中断
	NVIC_Init(&NVIC_InitStructure);
	
	//配置GPIA_Pin_1口中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn ;						//中断源	PA0中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;		//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;						//优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;							//是否启用中断
	NVIC_Init(&NVIC_InitStructure);
}

5、EXTI        外部中断

void EXTI0_Config(void)
{
    GPIO_InitTypeDef 		GPIO_InitStructure;   		 					//配置结构体
    EXTI_InitTypeDef 		EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA ,ENABLE);		//打开GPIOA时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);		//开启AFIO的时钟
	
	//配置EXTI中断相应的引脚
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;		//浮空输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  			//速度50MHz
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	
	//配置AFIO
	//连接PA0作为EXTI使用,相同的GPIO_Pin_x不能同时触发中断
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0 );
	
	//配置EXTI中断				//PA0 是EXTI_0
	EXTI_InitStructure.EXTI_Line = EXTI_Line0;							//中断线 PA0,PB0,PC0引脚共用EXTI_Line0中断线
	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;			//中断模式
	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;	//下降沿触发
	EXTI_InitStructure.EXTI_LineCmd = ENABLE;								//启用中断线
	EXTI_Init(&EXTI_InitStructure);
	
	EXTI_ClearFlag(EXTI_Line0 );								//清理中断标志位

	//配置GPIOA_Pin_0口中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn ;						//中断源,来自中断线EXTI_Line0
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;		//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;						//优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;							//是否启用中断
	NVIC_Init(&NVIC_InitStructure);
}

void EXTI0_IRQHandler(void)											//触发EXTI0_IRQ中断源的服务函数
{
	static int status = 1;
	if ( SET == EXTI_GetITStatus(EXTI_Line0) )	  //检测中断来自哪条中断线,
																								//因为有的中断线共用一个中断处理函数
	{
		if (status == 1){
			GPIO_ResetBits(GPIOB ,GPIO_Pin_9);
			GPIO_ResetBits(GPIOB ,GPIO_Pin_8);
			status = 0;
		}
		else
		{
			GPIO_SetBits(GPIOB ,GPIO_Pin_9);
			GPIO_SetBits(GPIOB ,GPIO_Pin_8);
			status = 1;
		}
		EXTI_ClearFlag( EXTI_Line0 );									//清理中断标志位
	}
}

6、串口USART

STM32中配置重映射的情况主要出现在需要对GPIO端口的功能进行改变或重新分配时。每个GPIO都有一组重映射寄存器,用于配置该GPIO端口的重映射方式。当默认引脚不满足某些特定配置要求,如电压、频率等时,可能需要通过重映射来改变引脚的物理位置或功能。

配置重映射的步骤如下:

  1. 使能AFIO时钟:在使用重映射功能之前,需要先配置AFIO的时钟以使其可用。
  2. 配置GPIO端口:将源GPIO端口配置为相应的复用功能,以便可以重映射到目标GPIO端口上。
  3. 配置重映射寄存器:设置重映射寄存器的值,以选择要映射的复用功能和目标GPIO端口。
  4. 配置目标GPIO端口:将目标GPIO端口配置为相应的复用功能以使用已重映射的信号。

请注意,在进行重映射配置时,必须使能AFIO时钟。另外,虽然有时即使不开启重映射功能也能成功启用重映射引脚并使外设功能正常,但当重映射引脚和默认引脚都使能之后,外设会优先启用默认引脚。

因此,当需要改变GPIO端口的功能或当默认引脚不满足特定配置要求时,STM32就需要配置重映射。具体的配置步骤和注意事项可能因不同的STM32型号和具体应用场景而有所差异,建议查阅相关的STM32参考手册或技术文档以获取更详细和准确的信息。

stm32——串口配置一般步骤_stm32串口配置步骤-CSDN博客

//STM32F051C8TC芯片的RS485通讯
void RS485_initializes(void)
{
    USART_InitTypeDef USART_InitStructure;
	GPIO_InitTypeDef  GPIO_InitStructure;
  
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);       //打开时钟
    
    //重映射
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);        //配置引脚为转换功能
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_1);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_12;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    USART_OverSampling8Cmd(USART1,ENABLE);
	USART_InitStructure.USART_BaudRate = 6000000;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_Init(USART1, &USART_InitStructure);
  /*********************************************/
	USART_DECmd(USART1,ENABLE);														//485方向使能
	USART_SetDEAssertionTime(USART1,0x1F);				    //发数据时DE需要提前Tx为高电平,保证数据发送
	USART_DEPolarityConfig(USART1,USART_DEPolarity_High);	//DE极性设置,发送数据为高电平
	/*********************************************/
	
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);			//开启串口寄存器非空中断
	USART_Cmd(USART1, ENABLE);													//启动USART1
	USART_ClearFlag(USART1,USART_FLAG_TC);							//清楚发送完全标志位置


	//发数据
	unsigned short data = 0x20;
	USART_SendData(USART1 ,data);

        6.2、STM32F103C8T6芯片

        1、配置USART

void Hardware_USART_Init(void)
{
	GPIO_InitTypeDef 		GPIO_InitStructure;    							//GPIO配置结构体
	USART_InitTypeDef 	USART_InitStructure;								//USART配置结构体
	NVIC_InitTypeDef 		NVIC_InitStructure;									//USART中断优先级配置结构体
	
	//1、串口时钟使能,GPIO时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA ,ENABLE);	//打开GPIO时钟,打开USART时钟
	
	//2、串口复位
	USART_DeInit(USART1);	
/*****************************************************************
	//重映射(AFIO)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO ,ENABLE);
	GPIO_PinRemapConfig(GPIO_Remap_USART1 ,ENABLE);
	//USART1_TX   原GPIOA.9是Tx   重映射PB6
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; 						
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				//复用推挽输出
  GPIO_Init(GPIOB, &GPIO_InitStructure);								//初始化
  //USART1_RX	  原GPIOA.10Rx		重映射PB7
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;						
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空输入
  GPIO_Init(GPIOB, &GPIO_InitStructure);								//初始化
******************************************************************/	
	//3、配置GPIO为转换功能
	//USART1_TX   原GPIOA.9是Tx   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 						//PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);								//初始化GPIOA.9	
  //USART1_RX	  原GPIOA.10Rx		
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;						//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);								//初始化GPIOA.10
	
	
	//4、串口参数初始化
	USART_OverSampling8Cmd(USART1 ,ENABLE);									//启用8倍过采样
	USART_InitStructure.USART_BaudRate = 115200;									//波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;		//8位数据位
  USART_InitStructure.USART_StopBits = USART_StopBits_1;				//1位停止位
  USART_InitStructure.USART_Parity = USART_Parity_No;						//无奇偶校验位
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//没有硬件流
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
	USART_Init(USART1 ,&USART_InitStructure);											//串口初始化
	
	//5、开启中断并初始化NVIC(需要开启中断才需要)
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;							//中断源
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;			//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;						//优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//启用中断
	NVIC_Init(&NVIC_InitStructure);																//NVIC初始化
	
	//6、使能串口
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);				//开启串口寄存器非空中断
	USART_Cmd(USART1 ,ENABLE);																		//启动串口
	USART_ClearFlag(USART1,USART_FLAG_TC);												//清除发送完全标志位置
}

        2、发送数据

//发送数据
void USART_Print(uint8_t *s)  //发送字符串函数
{
	while(*s)
	{
		//查USART1模块的发送数据寄存器是否还未准备好(即是否不为空),RESET未准备好
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
		USART_SendData(USART1,*s);
		s++;
	}
}

        3、中断方式接收数据

void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	volatile unsigned short temp;
	//1、读数据
	temp = USART_ReceiveData(USART1);					//收
	//USART_SendData(USART1,temp);							//发出去
	
	//2、清理FLAG
	USART_ClearITPendingBit(USART1,USART_IT_RXNE);
} 

7、DMA

STM32 | 串口DMA很难?其实就是如此简单!(超详细、附代码)_stm32串口dma很难?-CSDN博客

#include "hardware_usart.h"

#define USART1_MAX_TX_LEN 32		//发送缓存大小,最大USART1_MAX_TX_LEN
#define USART1_MAX_RX_LEN 32

unsigned int USART1_TX_BUF[USART1_MAX_TX_LEN];		//发送数据缓存区
unsigned int usart1_rx_buf[USART1_MAX_RX_LEN];	  //接收数据缓存区
unsigned int recv_msg[USART1_MAX_RX_LEN];					//复制接收数据去处理

void DMA_Config_Tx(void);
void DMA_Config_Rx(void);

void Hardware_USART_Init(void)
{
	GPIO_InitTypeDef 		GPIO_InitStructure;    							//GPIO配置结构体
	USART_InitTypeDef 	USART_InitStructure;								//USART配置结构体
	NVIC_InitTypeDef 		NVIC_InitStructure;									//USART中断优先级配置结构体
	
	//1、串口时钟使能,GPIO时钟使能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 ,ENABLE);	//打开USART时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO ,ENABLE);		//打开GPIO时钟,AFIO时钟
	
	//2、串口复位
	USART_DeInit(USART1);
	
	//3、配置GPIO为转换功能
	//USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 						//PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;				//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);								//初始化GPIOA.9	
  //USART1_RX	  GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;						//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;	//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);								//初始化GPIOA.10
	
	//4、串口参数初始化
	USART_OverSampling8Cmd(USART1 ,ENABLE);												//启用8倍过采样
	USART_InitStructure.USART_BaudRate = 115200;									//波特率
  USART_InitStructure.USART_WordLength = USART_WordLength_8b;		//8位数据位
  USART_InitStructure.USART_StopBits = USART_StopBits_1;				//1位停止位
  USART_InitStructure.USART_Parity = USART_Parity_No;						//无奇偶校验位
  USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;		//没有硬件流
  USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
	USART_Init(USART1 ,&USART_InitStructure);											//串口初始化
	
	//5、开启中断并初始化NVIC(需要开启中断才需要)
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;							//中断源
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 8;			//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;						//优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;								//启用中断
	NVIC_Init(&NVIC_InitStructure);																//NVIC初始化
	
	//6、使能串口
	USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);								//开启串口空闲中断
	USART_ClearFlag(USART1,USART_FLAG_TC);												//清除发送完成标志位置
	USART_Cmd(USART1 ,ENABLE);																		//启动串口
	
	//配置DMA
	DMA_Config_Tx();
	DMA_Config_Rx();
	USART_DMACmd(USART1 ,USART_DMAReq_Tx | USART_DMAReq_Rx ,ENABLE);		//启动串口DMA发送和接收

}

void DMA_Config_Tx(void)
{
	DMA_InitTypeDef  DMA_InitStructure;															//DMA配置结构体
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);							//打开DMA时钟
	
	DMA_DeInit( DMA1_Channel4 );																		//DMA通道4(USART1_Tx)复位
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;				//外设地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)USART1_TX_BUF;					//内存地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;							//指定数据传输方向,内存到外设
	DMA_InitStructure.DMA_BufferSize = USART1_MAX_TX_LEN;						//缓存区的大小 32字节
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//指定外设地址不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;					//内存寄存器地址增加
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;		//指定外设数据宽度(8位)
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;						//指定内存数据宽度
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;										//工作模式正常,搬完一次数据停在那需要手动再启动
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;						//DMA通道x软件优先级最高
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;										//DMA通道x不设置内存到内存传输
	
	DMA_ClearFlag(DMA1_FLAG_TC4);																		//清理DMA传输完成标志
	DMA_Init(DMA1_Channel4 ,&DMA_InitStructure);										//DMA通道x初始化
	DMA_Cmd(DMA1_Channel4 ,DISABLE);																//关闭DMA串口的发送通道
}

void DMA_Config_Rx(void)
{
	DMA_InitTypeDef  DMA_InitStructure;															//DMA配置结构体
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);							//打开DMA时钟
	
	DMA_DeInit( DMA1_Channel5 );																		//DMA通道5(USART1_Rx)复位
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;			//外设地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)usart1_rx_buf;				//内存地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;							//数据传输方向,外设到内存
	DMA_InitStructure.DMA_BufferSize = USART1_MAX_RX_LEN;						//DMA通道缓存区的大小  32字节
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设寄存器地址不变
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;					//内存寄存器地址增加
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;		//指定外设数据宽度(8位)
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;						//指定内存数据宽度(8位)
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;										//工作模式正常
	DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh;					//DMA通道x软件优先级最高
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;										//DMA通道x不设置内存到内存传输
	
	DMA_ClearFlag(DMA1_FLAG_TC5);																		//清理DMA传输完成标志
	DMA_Init(DMA1_Channel5 ,&DMA_InitStructure);										//DMA通道x初始化
	DMA_Cmd(DMA1_Channel5 ,ENABLE);																	//开启DMA1的5通道
}

//USART使用DMA发送数据
void USART_DMA_Tx_Data(unsigned char *buffer)
{	
	//1、清理标志位TC
	//DMA_ClearFlag( DMA1_FLAG_TC4 );				//先清理DMA通道4的传输完成标志位
	//2、关闭DMA1的4通道
	DMA_Cmd(DMA1_Channel4 ,DISABLE);			//因为传输数量寄存器配置需要通道关闭才能配置
	//3、配置需要发送的数据
	DMA1_Channel4->CMAR = (uint32_t)buffer;
	//4、重新设置长度
	DMA1_Channel4->CCR &= ~(1<<0);								//关闭通道
	DMA1_Channel4->CNDTR = USART1_MAX_TX_LEN;			//重新配置传输数量寄存器
	DMA1_Channel4->CCR |= 1<<0;										//开启通道
	
	//5、检测DMA传输完成标志位
	while( SET != DMA_GetFlagStatus(DMA1_FLAG_TC4));		//等待DMA传输完成
	USART_ClearFlag(USART1 ,USART_FLAG_TC);							//清理串口发送完成标志位
	DMA_ClearFlag(DMA1_FLAG_TC4);												//清理DMA传输完成标志
	
}

//接收数据
void USART1_IRQHandler(void)                	//串口1中断服务程序
{
	uint8_t temp;
	if ( SET != USART_GetITStatus(USART1 ,USART_FLAG_IDLE))			//触发串口空闲中断,发生返回RESET
	{
		//1、关闭通道、拷贝数据
		DMA_Cmd(DMA1_Channel5 ,DISABLE);													//关闭DMA通道
		//2、重新设置DMA长度
		DMA1_Channel5->CCR &= ~(1<<0);								//关闭通道
		DMA1_Channel5->CNDTR = USART1_MAX_RX_LEN;			//重新配置传输数量寄存器
		DMA1_Channel5->CCR |= 1<<0;										//开启通道
		//3、清除DMA传输完成标志和串口空闲中断标志
		temp = USART1->SR;
		temp = USART1->DR;
		DMA_ClearFlag( DMA1_FLAG_TC5 );

		USART_DMA_Tx_Data((unsigned char *)usart1_rx_buf);		//接收的数据发送出去
	}
} 

8、TIM

STM32高级定时器TIM1生成互补PWM_stm32 tim1 互补pwm-CSDN博客
STM32之定时器配置-CSDN博客
        8.1、TIM+更新中断

void TIMER_INIT(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	NVIC_InitTypeDef 				 NVIC_InitStructure;
	
	TIM_DeInit(TIM3);													//复位定时器
	
	/*1、使能TIM2时钟*/
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

	/*配置定时2参数  溢出时间 = [ ( TIM_Period + 1 ) * ( TIM_Prescaler + 1 ) / ( SystemCoreClock ) ] ( s )*/
	TIM_TimeBaseStructure.TIM_Prescaler = 71;/*PSC预分频器,72分频,1MHz*/
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Down;/*向上计数模式*/
	TIM_TimeBaseStructure.TIM_Period = 499;/*设定计数器的计数值(周期),计数1000次,0.5ms*/
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;/*时钟分频因子*/
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;/*重载周期,高级定时器特有*/
	TIM_TimeBaseInit(TIM3 ,&TIM_TimeBaseStructure);						/*初始化定时器*/
	
	TIM_ITConfig(TIM3 ,TIM_IT_Update ,ENABLE);								/*启动定时器更新中断*/

	
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

	//TIM_Cmd(TIM3 ,ENABLE);										/*开启定时器*/
	TIM1->CR1 |= 1<<0 ;
}


void TIM3_IRQHandler(void)
{
	static unsigned  char flag = 0;
	if ( RESET == TIM_GetITStatus( TIM3 ,TIM_IT_Update) ) 
	{
		if (flag == 40){
			flag = 0;
		}
		flag++;
		if (flag <= 5){
			GPIO_SetBits(GPIOB ,GPIO_Pin_8);		/*输出高电平*/
		}else{
			GPIO_ResetBits(GPIOB ,GPIO_Pin_8);		/*输出低电平*/
		}
		TIM_ClearITPendingBit( TIM3 ,TIM_IT_Update);
	}
}

        8.2、        TIM+PWM
 

void TIMER_INIT(void)
{
	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
	GPIO_InitTypeDef 				 GPIO_InitStructure;
	TIM_OCInitTypeDef  			 TIM_OCInitStructure;
	
	//TIM_DeInit(TIM1);													//复位定时器
	
	/*1、使能TIM1时钟  GPIOA时钟(TIM1_CH2对应PA9)*/
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1 | RCC_APB2Periph_GPIOB ,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO ,ENABLE);
	/*2、配置GPIOA_Pin_9*/
	GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9 ; 							//配置的引脚                           
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;   			//配置模式,复用推挽输出
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  			//速度50MHz
  GPIO_Init(GPIOA, &GPIO_InitStructure);									//配置A组引脚
	
	/*配置TIM1_CH2N*/
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_14 ; 							//配置的引脚                           
  GPIO_Init(GPIOB, &GPIO_InitStructure);									//配置B组引脚

	/*3、配置定时1参数(定时)  溢出时间 = [ ( TIM_Period + 1 ) * ( TIM_Prescaler + 1 ) / ( SystemCoreClock ) ] ( s )*/
	TIM_TimeBaseStructure.TIM_Prescaler = 71;/*PSC预分频器,72分频,1MHz*/
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;/*向上计数模式*/
	TIM_TimeBaseStructure.TIM_Period = 19999;/*设定计数器的计数值(周期),计数1000次,1ms*/
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;/*时钟分频因子*/
	TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;/*重载周期,高级定时器特有*/
	
	TIM_TimeBaseInit(TIM1 ,&TIM_TimeBaseStructure);						/*初始化定时器*/
	
	/*4、PWM输出定时器1配置,(通道2)*/
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;				/*从0递增,小于CCR值为有效.(PWM2于之相反)*/
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;			/*使能PWM输出    PA9引脚*/
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable;		/*开起互补PWM输出  PB14引脚*/
	TIM_OCInitStructure.TIM_Pulse = 1999;  /*配置2ms/20ms = 10%=(CCR+1/ARR+1),  CCR=?,ARR=周期*/
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;					/*输出极性,高电平*/
	TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;					/*互补输出,有效时为低电平*/
	TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;				/*输出比较空闲时电平(低电平)*/
	TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;			
	
	TIM_OC2Init(TIM1 ,&TIM_OCInitStructure);													/*初始化配置的PWM*/     

	TIM_Cmd(TIM1 ,ENABLE);										/*开启定时器*/
	//TIM1->CR1 |= 1<<0 ;
	/**/
	TIM_CtrlPWMOutputs( TIM1 ,ENABLE);					/*开启PWM输出*/
}

  • 23
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值