STM32F407VET6 学习笔记2:定时器、串口、自定义串口打印函数

news2024/10/5 21:18:48

今日继续学习使用嘉立创购买的 立创梁山派天空星,芯片是 STM32F407VET6

因为已经有学习基础了,所以学习进度十分快,这次也是直接一块学习配置定时器与串口了,文章也愈来愈对基础的解释越来越少了......

文章提供测试代码讲解、完整工程下载、测试效果图

 

本文学习目标:

配置串口发送功能,自定义串口print函数、定时器计数计时中断功能,定时器每隔1000ms使用串口发送一次数据

目录

串口通信的配置:

串口初始化:

串口中断服务函数:

自定义串口打印函数:

开发板硬件连接:

测试代码结果:

定时器的计时功能配置:

定时器初始化:

定时器时钟来源:

定时中断频率计算:

定时中断服务函数:

测试效果图:

测试工程下载:


串口通信的配置:

我个人认为,基础的串口通信主要有以下几方面重要:

1、串口的初始化:打开外设总线、引脚配置、波特率配置、中断优先级配置

2、串口中断服务函数的编写

3、串口发送简单,但接收逻辑要写清除比较难

(通常定义结构体、状态机思维接收、处理错误数据丢包等......)

但今日主要还是只关注  配置使用串口的发送功能 即可......

 

串口初始化:

整个函数基本步骤简单来讲就是:

开总线、配引脚、设串口参数、开接收中断、配中断优先级......

下面是初始化串口1   PA9 (TX) 、PA10 (RX)的例程代码:

void uart1_init(uint32_t __Baud)
{
	GPIO_InitTypeDef GPIO_InitStructure;	

	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);	

	GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);//IO口用作串口引脚要配置复用模式
	GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);

	GPIO_StructInit(&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin           = GPIO_Pin_9;//TX引脚
	GPIO_InitStructure.GPIO_Mode          = GPIO_Mode_AF;//IO口用作串口引脚要配置复用模式
	GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd          = GPIO_PuPd_UP;
	GPIO_Init(GPIOA,&GPIO_InitStructure);

	GPIO_StructInit(&GPIO_InitStructure);
	GPIO_InitStructure.GPIO_Pin           = GPIO_Pin_10;//RX引脚
	GPIO_InitStructure.GPIO_Mode          = GPIO_Mode_AF;
	GPIO_InitStructure.GPIO_Speed         = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_OType         = GPIO_OType_PP;
	GPIO_InitStructure.GPIO_PuPd          = GPIO_PuPd_UP;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
  
	USART_InitTypeDef USART_InitStructure;//定义配置串口的结构体变量

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//开启串口1的时钟

	USART_DeInit(USART1);//大概意思是解除此串口的其他配置

	USART_StructInit(&USART_InitStructure);
	USART_InitStructure.USART_BaudRate              = __Baud;//设置波特率
	USART_InitStructure.USART_WordLength            = USART_WordLength_8b;//字节长度为8bit
	USART_InitStructure.USART_StopBits              = USART_StopBits_1;//1个停止位
	USART_InitStructure.USART_Parity                = USART_Parity_No ;//没有校验位
	USART_InitStructure.USART_Mode                  = USART_Mode_Rx | USART_Mode_Tx;//将串口配置为收发模式
	USART_InitStructure.USART_HardwareFlowControl   = USART_HardwareFlowControl_None; //不提供流控 
	USART_Init(USART1,&USART_InitStructure);//将相关参数初始化给串口1
	
	USART_ClearFlag(USART1,USART_FLAG_RXNE);//初始配置时清除接受置位

	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//初始配置接受中断

	USART_Cmd(USART1,ENABLE);//开启串口1
	
	NVIC_InitTypeDef NVIC_InitStructure;//中断控制结构体变量定义

	NVIC_InitStructure.NVIC_IRQChannel                    = USART1_IRQn;//中断通道指定为USART1
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 0;//主优先级为0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority         = 1;//次优先级为1
	NVIC_InitStructure.NVIC_IRQChannelCmd                 = ENABLE;//确定使能
	NVIC_Init(&NVIC_InitStructure);//初始化配置此中断通道
		
}

 

串口中断服务函数:

/******** 串口1 中断服务函数 ***********/
void USART1_IRQHandler(void)
{
	if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET)//判断是不是真的有中断发生
	{
		//USART_SendData(USART1,USART_ReceiveData(USART1));//又将数据发回去(用于验证)
		
		
		USART_ClearITPendingBit(USART1, USART_IT_RXNE); //已经处理就清楚标志位 
	}  
}

 

自定义串口打印函数:

这是个很有意思的自定义打印函数,可以让你的任意串口打印都能像用printf函数一样方便:

注意需要添加以下头文件:

#include "stdarg.h"      //自定义printf需要使用
#include "stdio.h"       //1.61328125kb

//选择串口发送数据--自定义Printf
void UsartPrintf (USART_TypeDef *USARTx, char *fmt,...)
{
 
	unsigned char UsartPrintfBuf[296];                                  //最大长度296
	va_list ap;
	unsigned char *pStr = UsartPrintfBuf;
	
	va_start(ap, fmt);
	vsnprintf((char *)UsartPrintfBuf, sizeof(UsartPrintfBuf), fmt, ap);	//格式化
	va_end(ap);
	
	while(*pStr != 0)
	{
		USART_SendData(USARTx, *pStr++);
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
	}
}

 

开发板硬件连接:

这里需要注意UART1的TX与RX引脚就在背面:不用处心积虑寻找PA9与PA10了哈:

注意与usb转串口模块连接时tx接rx,rx接tx就行了:

测试代码结果:

 这里也是使用自己写的不靠谱串口助手上位机软件测试代码接收成功了:

 

 

定时器的计时功能配置:

个人总结定时器无非几个重要功能:计数计时、输出PWM、捕获脉冲计数

配置计时器的时候需要注意以下几点:

定时器接的时钟频率、定时器分频、最大重载值、计数模式、中断优先级

GD32F407VET6一共有14个定时器,可以分为五种类型,高级定时器0/7、通用定时器(L0)1-4、通用定时器(L1)8/11、通用定时器(L2)9/10/12/13和基本定时器5/6。不同类型的定时器所拥有的功能数量不同,一般高级定时器的功能最多,通用定时器次之,基本定时器功能最少。具体功能对照可以查看用户手册的第349页。 

 

定时器初始化:

//接受两个整数参数:Period和Prescaler。Period是定时器的周期值,而Prescaler是预分频值。
void Timer_init(int Period,int Prescaler)
{
	//定义了两个结构体变量,用于配置定时器和NVIC(嵌套向量中断控制器)
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	//启用TIM3的时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);
	
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分频设置为1(即不分频)
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//计数器模式设置为向上计数
	TIM_TimeBaseStructure.TIM_Period = Period;//周期和预分频值分别设置为函数的参数值。
	TIM_TimeBaseStructure.TIM_Prescaler = Prescaler;
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);//使用TIM_TimeBaseInit函数将这些配置应用到TIM3上。
	
	//启用了TIM3的更新中断。当定时器的计数值达到周期值时,会产生一个更新中断。
	TIM_ITConfig(TIM3,TIM_IT_Update, ENABLE);
	
	//配置了NVIC以处理TIM3的中断。设置了中断通道为TIM3_IRQn,启用了该中断,并设置了抢占优先级和子优先级。
	NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;
	NVIC_Init(&NVIC_InitStructure);
	
	//启动了TIM3定时器
	TIM_Cmd(TIM3,ENABLE);
}	

 

定时器时钟来源:

这在数据手册18页:

可以看到14个定时器的时钟来源主要分为两部分,第一部分来源于CK_APB1,第二部分来源于CK_APB2。然后经过时钟配置寄存器(RCU_CFG1)决定是APB频率的2倍还是4倍,但这个频率不能超过AHB(max = 168MHZ)。

这里使用TIMER3,就要先使能TIMER5的时钟,又因为TIMER3时钟来源于CK_APB1,CK_APB1的时钟在system_stm32f4xx.c中定义

从图可以看到APB1的时钟等于AHB的时钟4分频,

AHB的时钟等于系统时钟SYSCLK 也就是168Mhz

那么APB1的时钟就是168/4=42Mhz

APB1的时钟再经过CK_APB1的2倍频传给定时器,即84Mhz

定时中断频率计算:

预分频器可以将定时器的时钟(TIMER_CK)频率按1到65536之间的任意值分频,分频后的时钟PSC_CLK驱动计数器计数。分频系数受预分频器TIMERx_PSC控制。这个控制寄存器带有缓冲器,它能够在运行时被改变。新的预分频器的参数在下一次更新事件到来时被采用。

分频器的分频公式为:PSC_CLK = TIMER_CK/ (TIMERx_PSC +1)

计数器溢出频率:   

CK CNT_OV= CK CNT   /    (ARR+1)

                     =  CK PSC  /    (PSC +1)  /  (ARR +1)          单位:Hz

由上文知CK PSC =  84Mhz

因此,为了达到1000ms溢出的速率,我们可以将period(即ARR)设为10000,将Prescaler(即PSC)设为8400

定时中断服务函数:

 


//定时器TIM3中断服务函数:
void TIM3_IRQHandler(void)
{
	if(TIM_GetITStatus(TIM3, TIM_IT_Update) == SET)
	{ // {}中为中断处理
		i++;
	  UsartPrintf(USART1," %d seconds past \r\n",i);	//开机打印测试字符串
	}
	TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
}

测试效果图:

测试工程下载:

https://download.csdn.net/download/qq_64257614/89276407

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1649566.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

springboot项目组合定时器schedule注解实现定时任务

springboot项目组合定时器schedule注解实现定时任务! 创建好springboot项目后,需要在启动类上增加注解开启定时器任务 下图所示: 增加这个注解,启动项目, package com.example.scheduledemo.util;import org.springf…

Baidu Comate——您的智能编码伙伴

文章目录 1.Baidu Comate智能编码助手简介2.Baidu Comate安装使用3.查看Comate插件功能4.Baidu Comate基础功能介绍✨注释生成代码✨实时续写✨函数注释✨行间注释✨代码解释✨单元测试生成✨代码优化✨技术问答 5.使用体验结语 1.Baidu Comate智能编码助手简介 ✨Baidu Comat…

ASP.NET MVC企业级程序设计 (入住退房,删除)

目录 效果图 实现过程 控制器代码 DAL BLL Index 效果图 实现过程 控制器代码 using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc;namespace MvcApplication1.Controllers {public class HomeController …

python环境下labelImg图片标注工具的使用

labelimg GitHub地址 python环境下labelImg图片标注工具的使用 1. 写在开头2. 如何使用2.1安装2.2 启动2.2.1 先启动后设置标注的目录2.2.2 指定标注的目录和预设置的标签 2.3 设置自动保存和显示类别。2.4 保存文件类型2.5 [快捷键](https://github.com/HumanSignal/labelImg…

矩阵快速幂

要想知道矩阵快速幂,我们先了解一下什么叫快速幂和矩阵乘法 一、快速幂 快速幂算法是用来快速计算指数表达式的值的,例如 210000000,普通的计算方法 2*2*2*2…10000000次,如果一个数字的计算都要计算那么多次的话,那么这个程序一…

c++多线程2小时速成

简介 c多线程基础需要掌握这三个标准库的使用&#xff1a;std::thread,std::mutex, andstd::async。 1. Hello, world #include <iostream> #include <thread>void hello() { std::cout << "Hello Concurrent World!\n"; }int main() {std::th…

5.合并两个有序数组

文章目录 题目简介题目解答解法一 &#xff1a;合并后排序解法二&#xff1a;双指针排序 题目链接 大家好&#xff0c;我是晓星航。今天为大家带来的是 合并两个有序数组 相关的讲解&#xff01;&#x1f600; 题目简介 题目解答 解法一 &#xff1a;合并后排序 假设我们要合…

【C++】从零开始认识多态

送给大家一句话&#xff1a; 一个犹豫不决的灵魂&#xff0c;奋起抗击无穷的忧患&#xff0c;而内心又矛盾重重&#xff0c;真实生活就是如此。 ​​​​ – 詹姆斯・乔伊斯 《尤利西斯》 _φ(*&#xffe3;ω&#xffe3;)&#xff89;_φ(*&#xffe3;ω&#xffe3;)&…

期权买方要保证金吗?期权交易保证金怎么计算?

今天期权懂带你了解期权买方要保证金吗&#xff1f;期权交易保证金怎么计算&#xff1f;期权保证金其实就是你在购买期权合约时&#xff0c;作为卖方要付出的那一小笔钱。简单说&#xff0c;就是为了防止你违约&#xff0c;给交易双方一个保障的“小押金”。 期权买方要保证金吗…

软考中级-软件设计师(八)算法设计与分析 考点最精简

一、算法设计与分析的基本概念 1.1算法 算法&#xff08;Algorithm&#xff09;是对特定问题求解步骤的一种描述&#xff0c;有5个重要特性&#xff1a; 有穷性&#xff1a;一个算法必须总是在执行又穷步骤后结束&#xff0c;且每一步都可在又穷时间内完成 确定性算法中每一…

如何做好一个活动策划?

活动策划的关键要素是什么&#xff1f; 首先&#xff0c;要明确一个概念:做活动就是走钢丝&#xff0c;没有保险的高空走钢丝!因为&#xff0c;活动没有“彩排”&#xff0c;只有现场"直播”! 无论什么类型的活动&#xff0c;人数是50人还是2000人&#xff0c;也不论预算…

Parts2Whole革新:多参照图定制人像,创新自定义肖像生成框架!

DeepVisionary 每日深度学习前沿科技推送&顶会论文分享&#xff0c;与你一起了解前沿深度学习信息&#xff01; Parts2Whole革新&#xff1a;多参照图定制人像&#xff0c;创新自定义肖像生成框架&#xff01; 引言&#xff1a;探索多条件人像生成的新篇章 在数字内容创作…

用户管理中心——数据库设计用户注册逻辑设计

用户管理中心——数据库设计&用户注册逻辑设计 规整项目目录1. 数据库自动生成器的使用实现基本的数据库操作&#xff08;操作user表&#xff09; 2. 注册逻辑的设计(1) 写注册逻辑(2) 实现(3) 测试代码 3. 遇到的问题 规整项目目录 utils–存放工具类&#xff0c;比如加密…

贪心算法应用例题

最优装载问题 #include <stdio.h> #include <algorithm>//排序int main() {int data[] { 8,20,5,80,3,420,14,330,70 };//物体重量int max 500;//船容最大总重量int count sizeof(data) / sizeof(data[0]);//物体数量std::sort(data, data count);//排序,排完数…

OpenHarmony 实战开发—— refreshlayout 组件开发学习指南~

1. RefreshLayout_harmonyos 功能介绍 1.1. 组件介绍&#xff1a; RefreshLayout_harmonyos 是一款下拉刷新组件 1.2. 手机模拟器上运行效果&#xff1a; 2. RefreshLayout_harmonyos 使用方法 2.1 在目录 build.gradle 下 implementation project(":refreshlayout_ha…

【YoloDeployCsharp】基于.NET Framework的YOLO深度学习模型部署测试平台

YoloDeployCsharp|基于.NET Framework的YOLO深度学习模型部署测试平台 1. 项目介绍2. 支持模型3. 时间测试4. 总结 1. 项目介绍 基于.NET Framework 4.8 开发的深度学习模型部署测试平台&#xff0c;提供了YOLO框架的主流系列模型&#xff0c;包括YOLOv8~v9&#xff0c;以及其系…

Linux 手动部署JDK21 环境

1、下载包&#xff08;我下载的是tar) https://www.oracle.com/cn/java/technologies/downloads/#java21 完成后进行上传 2、检查已有JDK&#xff0c;并删除&#xff08;我原有是jdk8&#xff09; rpm -qa | grep -i java | xargs -n1 rpm -e --nodeps3、清理掉 profile中的j…

PXE 批量安装部署

目录 一、PEX批量部署优点 二、PXE&#xff1a;预启动执行环境 三、搭建PXE远程服务器 要想全自动安装 接下来请看步骤&#xff1a; 一、PEX批量部署优点 规模化&#xff1a;同时装配多台服务器自动化&#xff1a;安装系统 配置各种服务远程实现&#xff1a;不需要光盘&…

代码随想录算法训练营DAY43|C++动态规划Part5|1049.最后一块石头的重量II、494.目标和、474.一和零

文章目录 1049.最后一块石头的重量II思路CPP代码 ⭐️494.目标和回溯算法抽象成01背包问题CPP代码本题总结 474.一和零思路CPP代码 1049.最后一块石头的重量II 力扣题目链接 文章链接&#xff1a;1049.最后一块石头的重量II 视频链接&#xff1a;这个背包最多能装多少&#xff…

Material Studio 计算分子静电力、电荷密度以及差分电荷密度

1.先打开Material Studio导入要计算的分子cif文件或者mol文件&#xff0c;直接Flie-Import 2.高斯几何优化一下结构&#xff0c;参数按照我的设置就行&#xff0c;一般通用&#xff0c;后面出问题再调整 3.点完Run后会跳出很多计算过程&#xff0c;不用管&#xff0c;等他计算完…