STM32F4xx系列标准库函数之串口初始化和打印

后续会开发 寄存器串口初始化和打印 目前使用的是标准库函数开发。

//更新说明 串口接收与DMA控制器结合(文章最下面会有代码 贴上)

开始直接上代码,代码里面有解释

#include "usart.h"



//------------------------------------------------修改以下宏定义可以配置相应的串口初始化----------------------------------------------------
#define USART_TX GPIO_Pin_9	//串口GPIO发送端口
#define USART_RX GPIO_Pin_10	//串口GPIO接收端口

#define USART_GPIO_TypeDef GPIOA	//串口对应的GPIO位置

#define USART_Pin_TX GPIO_PinSource9	//串口映射发送的GPIO
#define USART_Pin_RX GPIO_PinSource10 //串口映射读取的GPIO

#define USART_RCC RCC_APB2Periph_USART1	// 注意串口1/6 是APB2总线  其它是APB1总线
#define USART_GPIO_RCC RCC_AHB1Periph_GPIOA //串口对应的GPIO总线

#define USART_IRQ USART1_IRQn //串口 中断号
#define USART USART1	//串口号
//------------------------------------------------修改以上宏定义可以配置相应的串口初始化----------------------------------------------------
/*
函数功能:初始化串口1
函数参数:uint32_t USART_BaudRate 
函数返回值:无 
函数描述:无
*/
void Usart1_Init(uint32_t USART_BaudRate)
{
	GPIO_InitTypeDef GPIO_InitStruct;    //串口GPIO结构体定义
	USART_InitTypeDef USART_InitStruct; //串口结构体定义
	NVIC_InitTypeDef NVIC_InitStruct;	//总中断结构体定义
	
	RCC_APB2PeriphClockCmd(USART_RCC,ENABLE);	//使能串口外设的线   注意串口1/6 是APB2总线  其它是APB1总线
	RCC_AHB1PeriphClockCmd(USART_GPIO_RCC,ENABLE);	//使能串口对应的GPIO线
	
	GPIO_PinAFConfig(USART_GPIO_TypeDef,USART_Pin_TX,GPIO_AF_USART1);	//串口发送复用映射
	GPIO_PinAFConfig(USART_GPIO_TypeDef,USART_Pin_RX,GPIO_AF_USART1);	//串口接收复用映射
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
	GPIO_InitStruct.GPIO_Pin = USART_TX | USART_RX;
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_Init(USART_GPIO_TypeDef,&GPIO_InitStruct);	//串口 发送/接受端口初始化
	
	USART_InitStruct.USART_BaudRate = USART_BaudRate;
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	USART_InitStruct.USART_Parity = USART_Parity_No;
	USART_InitStruct.USART_StopBits = USART_StopBits_1;
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;
	USART_Init(USART,&USART_InitStruct); //串口初始化
	
	USART_Cmd(USART,ENABLE);
	
	USART_ReceiveData(USART);	//初始化时候读取一次避免 一开始就有中断
	
	USART_ITConfig(USART,USART_IT_RXNE,ENABLE); //读取中断配置
	
	NVIC_InitStruct.NVIC_IRQChannel = USART_IRQ;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 2;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
	NVIC_Init(&NVIC_InitStruct);	//串口总中断初始化
}


/*
函数功能:printf函数重定向
函数参数:无
函数返回值:无 
函数描述:无
*/
int fputc(int ch, FILE * f)
{
	USART->DR = (unsigned char)ch; //USART是上面宏定义的 哪个串口初始化就打印那个串口
	while((USART->SR & 0x80) == 0);	
	return ch;
}
//------------------------------------------------某个串口初始化和打印完成----------------------------------------------------

如上图是初始化串口1的函数。根据您所需的串口修改相应的宏,就可以初始化相应的串口,本人经过验证串口2也是可以适用的。代码里面给出注释了请认真阅读。

进过验证串口2也是可以的,若有不懂可私聊。

另外本人使用的是HSE晶振为8MHZ的,需要修改如下图,不然打印是乱码。

 

----------------------------------------------补充------------------------------------------------------

使用我的串口打印,要在keil里面配置一下,还有要包含头文件stdio.h

如图

后续来了 寄存器开发版本 基于stm32f4xx主控的  

/*
函数功能:串口对应IO口初始化
函数参数:无
函数返回值:无
函数描述:无
*/
void Usart_Gpio_Init(void)
{
	RCC->AHB1ENR |= (0X01 << 0); //GPIOA线时钟使能
	
	GPIOA->MODER &= ~((0x3 << 18) | (0x3 << 20));         //配置GPIOA模式选择
	GPIOA->MODER |= ((0x2 << 18) | (0x2 << 20));         //PA9 PA10选择复用功能
	
	GPIOA->OTYPER &= ~(0x1 << 9);         //配置GPIOA输出类型选择 PA9配置推挽输出
	
	GPIOA->OSPEEDR &= ~((0x3 << 18));         //配置GPIOA输出速度选择
	GPIOA->OSPEEDR |= (0x3 << 18);         //PA9 输出速度 100MHZ/80MHZ
	
	GPIOA->PUPDR &= ~(0x3 << 20);         //配置GPIOA上下拉选择
	GPIOA->PUPDR |=  (0x2 << 20);         //PA10输入下拉
	
	GPIOA->ODR &= (unsigned short int)0x00;         //初始化串口让输出寄存器为零

	GPIOA->AFR[1] &= ~((0xf << 4) | (0xf << 8));         //配置PA9 PA10复用选择 AFx
	GPIOA->AFR[1] |= ((0x7 << 4) | (0x7 << 8));         //PA9 PA10选择复用功能
}


/*
函数功能:初始化串口1
函数参数:uint32_t USART_BaudRate
函数返回值:无
函数描述:无
*/
void Usart1_Init(uint32_t USART_BaudRate)
{
	float USARTDIV;
	int DIV_Mantissa,DIV_Fraction;
	
	RCC->APB2ENR |= (0X01 << 4); //USART1时钟使能
	
	Usart_Gpio_Init();
	
	USART1->CR1 &= ~((0X01 << 15) | (0X01 << 13) | (0X01 << 12) | (0X01 << 10) | (0X01 << 3) | (0X01 << 2));//配置USART1控制寄存器选择
	USART1->CR1 |= ((0X01 << 3) | (0X01 << 2));//配置USART1控制寄存器
	
	USART1->CR2 &= ~((0X01 << 13) | (0X01 << 12));//配置USART1控制寄存器选择 //配置USART1控制寄存器	
	
	USARTDIV = (5250000.0 / USART_BaudRate);
	DIV_Mantissa = USARTDIV;
	DIV_Fraction = (USARTDIV - DIV_Mantissa) * 16;
	
	USART1->BRR &= (0X0000); //串口波特率选择
	USART1->BRR |= (DIV_Mantissa << 4 | DIV_Fraction); //串口波特率选择	
	
	//以下是接收中断使用配置
	USART1->CR1 |= (0X01 << 5);//RXNE中断使能
	
	NVIC_SetPriority(USART1_IRQn,NVIC_EncodePriority(USART1_IRQn,2,2));
	NVIC_EnableIRQ(USART1_IRQn); //使能中断USART1
	

	USART1->CR1 |= (0X01 << 13); //使能串口1
}


/*
函数功能:printf函数重定向
函数参数:无
函数返回值:无 
函数描述:无
*/
int fputc(int ch, FILE * f)
{
	USART1->DR = (unsigned char)ch;  
	while(!(USART1->SR & (0x01 << 7)));	
	return ch;
}

fpuct()是printf函数底层用的函数 让printf函数打印输出到串口需要修改 fputc函数的指向

//更新的 串口与DMA结合  这与上面的代码无关

#include "usart.h"




/*
函数功能:初始化串口对应的管脚
函数参数:无
函数返回值:无
函数描述:初始化完管脚后 初始化串口
*/
void UsartPinInit(void)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //开始GPIOA时钟
	
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;  //复用
	GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;	//推挽
	GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10	;	//PA9 PA10
	GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;	//无上下拉
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;	//100MHZ
	
	GPIO_Init(GPIOA,&GPIO_InitStruct); 
	
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //让PA9复用成串口功能
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //让PA10复用成串口功能
}

/*
函数功能:初始化串口
函数参数:无
函数返回值:无
函数描述:使用DMA模式 
*/
void Usart1Init(uint32_t USART_BaudRate)
{
	USART_InitTypeDef USART_InitStruct;
	NVIC_InitTypeDef NVIC_InitStruct;
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
	
	UsartPinInit();
	
	USART_InitStruct.USART_BaudRate = USART_BaudRate; //波特率
	USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无固件
	USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;	//发送读取模式
	USART_InitStruct.USART_Parity = USART_Parity_No; //无校验位
	USART_InitStruct.USART_StopBits = USART_StopBits_1;	//停止位1
	USART_InitStruct.USART_WordLength = USART_WordLength_8b;	//发送的数据长度 8位
	
	USART_Init(USART1,&USART_InitStruct);
	
	USART_Cmd(USART1,ENABLE);
	
	NVIC_InitStruct.NVIC_IRQChannel = DMA2_Stream2_IRQn;
	NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStruct.NVIC_IRQChannelSubPriority = 2;
	
	NVIC_Init(&NVIC_InitStruct);
	
	USART_DMACmd(USART1,USART_DMAReq_Rx,ENABLE);
}

/*
函数功能:重定向printf
函数参数:无
函数返回值:无
函数描述:无
*/
#include <stdio.h>
int fputc(int ch, FILE *stream)
{
	USART_SendData(USART1,(uint16_t)ch);
	while(!USART_GetFlagStatus(USART1,USART_FLAG_TXE));
	return ch;
}












DMA初始化

#include "dma.h"



/*
函数功能:DMA2初始化
函数参数:无
函数返回值:无
函数描述:DMA2 通道4 不用缓冲FIFO
*/
void Dma2Init(uint32_t DMA_Memory0BaseAddr,uint32_t DMA_PeripheralBaseAddr,uint32_t DMA_BufferSize)
{
	DMA_InitTypeDef DMA_InitStruct;
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
	
	DMA_InitStruct.DMA_BufferSize = DMA_BufferSize;
	DMA_InitStruct.DMA_Channel = DMA_Channel_4;
	DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralToMemory;
	DMA_InitStruct.DMA_FIFOMode = DMA_FIFOMode_Disable;
	DMA_InitStruct.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
	DMA_InitStruct.DMA_Memory0BaseAddr = DMA_Memory0BaseAddr;
	DMA_InitStruct.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	DMA_InitStruct.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStruct.DMA_Mode = DMA_Mode_Circular;
	DMA_InitStruct.DMA_PeripheralBaseAddr = DMA_PeripheralBaseAddr;
	DMA_InitStruct.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStruct.DMA_Priority = DMA_Priority_VeryHigh;
	
	DMA_Init(DMA2_Stream2,&DMA_InitStruct);
	
	DMA_ITConfig(DMA2_Stream2,DMA_IT_TC,ENABLE);
	
	DMA_Cmd(DMA2_Stream2,ENABLE);
}

















DMA中断服务函数配置

接收到了 20个数据就进入中断

#include <stdio.h>
void DMA2_Stream2_IRQHandler(void)
{
	if(DMA_GetITStatus(DMA2_Stream2,DMA_IT_TCIF2))
	{
		printf("12\r\n");
		DMA_ClearITPendingBit(DMA2_Stream2,DMA_IT_TCIF2);
	}
  //TimingDelay_Decrement();
}



unsigned char usart_dat[20];
int main(void)
{
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
	
	Dma2Init((uint32_t)usart_dat,(uint32_t)&USART1->DR,20);
	Usart1Init(115200);
	
	printf("ok\r\n");
	

  /* Infinite loop */
  while (1)
  {
	
  }
}

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值