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 小时前
立方星与微纳卫星综合电子微型化趋势下的抗辐射MCU选型综述
人工智能·单片机·嵌入式硬件·mcu·risc-v·抗辐射
xunyan62346 小时前
3-1 独立按键控制LED亮灭(SDCC + Notepad++ + STC-ISP/普中ISP)
单片机·嵌入式硬件·接口隔离原则
WD137298015577 小时前
WD5030L,为充电桩、工业设备、5G 基站、车载系统、消费电子提供电源,7-30V 的宽压输入
stm32·单片机·嵌入式硬件·5g·车载系统·51单片机
创界工坊工作室9 小时前
30-基于STM32的小麦烘干塔温度控制系统设计
stm32·单片机·嵌入式硬件·proteus
Zwawa10 小时前
先把轮子转稳,才不会烧心:编码器速度环 PID 怎么接回 PWM
c语言·单片机·嵌入式
单片机仿真设计11 小时前
【proteus仿真设计】基于 STM32 的开荒机器人遥控控制系统设计(仿真图+程序)
stm32·嵌入式硬件·机器人·proteus
smartpi_ai11 小时前
51 单片机写好了,大模型语音怎么接?17T 全驱动的现成方案、双板串口分工的边界与画板前的三项硬件确认
单片机·嵌入式硬件·学习
我先去打把游戏先11 小时前
NimBLE是什么-ESP32蓝牙协议栈详解
单片机·嵌入式硬件·ubuntu
木子n112 小时前
车载以太网与SOME/IP服务化通信实战-02.状态机与订阅:SOME/IP-SD的三态迁移、重传账与上电风暴
嵌入式硬件·网络协议·车载系统·车载以太网·some/ip
Gongsion12 小时前
30V输入耐压|1.5μA超低静态电流|200mA输出,CSM52系列:线性稳压器LDO,12V母线转3.3V/5V传感器、MCU弱电支路可靠稳压方案
单片机·嵌入式硬件·车载系统·无人机·智能家居