STM32F4VGT6-DISCOVERY:uart1驱动

对于这款板子,官方并没有提供串口例程,只能自行添加。

一、PA9/PA10复用成串口1功能不可用

驱动测试代码如下:

main.c:

cpp 复制代码
#include "main.h"
#include <stdio.h>

void usart1_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    //(1)串口时钟和 GPIO 时钟使能
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//GPIO口时钟使能, 引脚PA9,PA10可以复用为串口功能
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口UART1时钟使能, 串口1是挂载在 APB2总线下的外设

    //(2)配置GPIO引脚为复用功能[PA9+PA10]
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//电平翻转速度100MHz
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽复用输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
    GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 PA9,PA10

    //(3)配置串口1参数
    USART_InitStructure.USART_BaudRate = 115200;//波特率
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不使用硬件流控制
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
    USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8个数据位
    USART_Init(USART1, &USART_InitStructure); //初始化串口1

    //(4) 开启中断并且初始化 NVIC,使能相应中断[接收一个byte触发中断一次]
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级 3
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应优先级 3
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化NVIC寄存器

    //(5) 使能串口1
    USART_Cmd(USART1, ENABLE);
}

//串口1中断服务函数
void USART1_IRQHandler(void)
{
    char res;
    //检查标志位
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        res = USART_ReceiveData(USART1);//收到数据后读出来
        USART_SendData(USART1,res);//读到数据后立刻发送出去
        //清空标志位
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    }
}

int main(void)
{
    usart1_init();
    while(1)
    {
        ;
    }

    return 0;
}

固件烧录后,连接PC端串口工具,串口收发功能不可用。原因:PA9/PA10设计给板载USB使用,打开原理如下:

所以,只能换一组GPIO,换成PB6/PB7(原理图上可确认没有其他外设使用),测试代码如下:

cpp 复制代码
#if 0
void usart1_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	//(1)串口时钟和 GPIO 时钟使能
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);//GPIO口时钟使能, 引脚PA9,PA10可以复用为串口功能
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口UART1时钟使能, 串口1是挂载在 APB2总线下的外设

	//(2)配置GPIO引脚为复用功能[PA9+PA10]
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9|GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//电平翻转速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化 PA9,PA10

	//(3)配置串口1参数
	USART_InitStructure.USART_BaudRate = 115200;//波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不使用硬件流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8个数据位
	USART_Init(USART1, &USART_InitStructure); //初始化串口1

	//(4) 开启中断并且初始化 NVIC,使能相应中断[接收一个byte触发中断一次]
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应优先级 3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器

	//(5) 使能串口1
	USART_Cmd(USART1, ENABLE);
}

//串口1中断服务函数
void USART1_IRQHandler(void)
{
	char res;
	//检查标志位
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
		res = USART_ReceiveData(USART1);//收到数据后读出来
		USART_SendData(USART1,res);//读到数据后立刻发送出去

		//清空标志位
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

#else
void usart1_init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	//(1)串口时钟和 GPIO 时钟使能
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能GPIOB时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口UART1时钟使能, 串口1是挂载在 APB2总线下的外设

	//(2)配置GPIO引脚为复用功能[PB6+PB7]
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//电平翻转速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化 PA9,PA10

	//(3)配置串口1参数
	USART_InitStructure.USART_BaudRate = 115200;//波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不使用硬件流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8个数据位
	USART_Init(USART1, &USART_InitStructure); //初始化串口1

	//(4) 开启中断并且初始化 NVIC,使能相应中断[接收一个byte触发中断一次]
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应优先级 3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器

	//(5) 使能串口1
	USART_Cmd(USART1, ENABLE);
}

//串口1中断服务函数
void USART1_IRQHandler(void)
{
	char res;
	STM_EVAL_LEDOn(LED4);

	//检查标志位
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
		res = USART_ReceiveData(USART1);//收到数据后读出来
		STM_EVAL_LEDOn(LED5);
		USART_SendData(USART1,res);//读到数据后立刻发送出去

		//清空标志位
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}
#endif

int main(void)
{
	usart1_init();
	while(1)
	{
		;
	}

	return 0;
}

板子实物图连接如下:

串口工具测试如下:

二、串口标准输入输出重定向打印实现

直接重写标准输入输出函数的底层接口即可,如下:

|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| //重写printf底层函数接口 int fputc(int c, FILE *stream) { USART1->DR=c; //发送一个字符 while(!(USART1->SR&1<<7)){} return c; } //重写scanf底层函数接口 int fgetc(FILE *stream) { while(!(USART1->SR&1<<5)){} return USART1->DR; } |

烧录固件,并按reset键,观察串口调试助手上的打印:使用ST-LINK的方式进行烧录

串口助手:

三、完整代码

usart.c

cpp 复制代码
/* Includes ------------------------------------------------------------------*/
#include "stm32f4xx.h"
#include <stdio.h>

void usart1_init(uint32_t BaudRate)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	//(1)串口时钟和 GPIO 时钟使能
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE); //使能GPIOB时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//串口UART1时钟使能, 串口1是挂载在 APB2总线下的外设

	//(2)配置GPIO引脚为复用功能[PB6+PB7]
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_USART1);
	GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_USART1);

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//电平翻转速度100MHz
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽复用输出
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
	GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化 PA9,PA10

	//(3)配置串口1参数
	USART_InitStructure.USART_BaudRate = BaudRate;//波特率
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//不使用硬件流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8个数据位
	USART_Init(USART1, &USART_InitStructure); //初始化串口1

	//(4) 开启中断并且初始化 NVIC,使能相应中断[接收一个byte触发中断一次]
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
	NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级 3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//响应优先级 3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化NVIC寄存器

	//(5) 使能串口1
	USART_Cmd(USART1, ENABLE);
}

//串口1中断服务函数
void USART1_IRQHandler(void)
{
	char res;

	//检查标志位
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
	{
		res = USART_ReceiveData(USART1);//收到数据后读出来

		USART_SendData(USART1,res);//读到数据后立刻发送出去

		//清空标志位
		USART_ClearITPendingBit(USART1, USART_IT_RXNE);
	}
}

//重写printf底层函数接口
int fputc(int c, FILE *stream)
{
	  USART1->DR=c; //发送一个字符
	  while(!(USART1->SR&1<<7)){}
		return c;
}

//重写scanf底层函数接口
int fgetc(FILE *stream)
{
	while(!(USART1->SR&1<<5)){}
    return USART1->DR;
}

/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/

usart.h

cpp 复制代码
#ifndef __USART__H__
#define __USART__H__

void usart1_init(uint32_t BaudRate);

#endif /* __USART__H__ */

main.c

cpp 复制代码
#include "usart.h"
#include <stdio.h>

int main(void)
{
	usart1_init(115200);
	printf("hello world!\n");
	while(1)
	{
		;
	}

	return 0;
}

注:这款Discovery开发板是基于标准外设库函数来开发的,因此工程中要把串口相关的库函数文件添加进来,如下:

相关推荐
山木嵌入式6 小时前
【STM32实战】轻量级任务调度器实现
stm32·单片机·rtos·任务调度器·裸机开发
guygg887 小时前
基于霍尔传感器的BLDC控制源码
单片机·嵌入式硬件
ytttr8737 小时前
DSP 28335 CAN总线通信程序
开发语言·stm32·单片机
一枝小雨9 小时前
RISC-V架构sp寄存器 & RISC-V架构下FreeRTOS任务上下文保存与恢复
单片机·架构·嵌入式·risc-v·rtos·内核原理
BW.SU10 小时前
PackagingTool 嵌入式资源打包合并工具
单片机·二进制·嵌入式开发·资源合并软件·图片打包
长安第一美人11 小时前
工业级实时监控系统开发:PHP+ZMQ+JS 前后端分离架构全解析
前端·嵌入式硬件·架构·交互·rk3588·zmq后端
田甲11 小时前
STM32开发环境迁移实践:从 CubeMX 生成 CMake 工程到 VS Code 编译与调试
stm32·单片机·嵌入式硬件
hoiii18711 小时前
在 STM32F1上读取 BMX055 三轴加速度
stm32·单片机·嵌入式硬件
嵌入式小站11 小时前
STM32 零基础可移植教程 04:按键输入,为什么按下去读到的是 0 或 1
chrome·stm32·嵌入式硬件
三佛科技-1873661339712 小时前
BP8522D贴片SOP7,5V150mA高集成度无VCC电容降压型恒压芯片解析
单片机·嵌入式硬件