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

今日继续学习使用嘉立创购买的 立创梁山派天空星,芯片是 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;//字节长度为8bitUSART_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);//将相关参数初始化给串口1USART_ClearFlag(USART1,USART_FLAG_RXNE);//初始配置时清除接受置位USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//初始配置接受中断USART_Cmd(USART1,ENABLE);//开启串口1NVIC_InitTypeDef NVIC_InitStructure;//中断控制结构体变量定义NVIC_InitStructure.NVIC_IRQChannel                    = USART1_IRQn;//中断通道指定为USART1NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority  = 0;//主优先级为0NVIC_InitStructure.NVIC_IRQChannelSubPriority         = 1;//次优先级为1NVIC_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];                                  //最大长度296va_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://xiahunao.cn/news/3015551.html

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

相关文章

什么是企业出海?

本文节选自Odoo亚太金牌服务机构【开源智造】所编写的《企业数字化百科大全》如需获取完整的知识内容,请至开源智造官网免费获取。感谢网友一键三连:点赞、转发、收藏,您的支持是我们最大的前进动力! 企业出海是什么意思&#xff…

idea Maven 插件 项目多环境打包配置

背景 不同环境的配置文件不一样,打包方式也有差异 1. 准备配置文件 这里 local 为本地开发环境 可改为 dev 名称自定义 test 为测试环境 prod 为生产环境 根据项目业务自行定义 application.yml 配置: spring:profiles:#对应pom中的配置active: spring.…

指代消解类方法梳理

概念: MLM:带遮罩的语言模型 NSP:单句预测,任务包括两个输入序列 SBO:分词边界目标 1.spanBERT,2019 spanBERT是对bert从分词到文本跨度的优化,主要有两方面的优化:&#xff08…

node报错——解决Error: error:0308010C:digital envelope routines::unsupported——亲测可用

今天在打包vue2项目时,遇到一个报错: 最关键的代码如下: Error: error:0308010C:digital envelope routines::unsupportedat new Hash (node:internal/crypto/hash:80:19)百度后发现是node版本的问题。 在昨天我确实操作了一下node&…

【Vue】pinia

pinia 官网:https://pinia.vuejs.org/zh/ 搭建 pinia 环境 第一步:npm install pinia --save 第二步:操作src/main.ts import { createApp } from vue import App from ./App.vue/* 引入createPinia,用于创建pinia */ import { createP…

idea提示 CreateProcess error=206, 文件名或扩展名太长有哪些具体的解决方法

背景: 项目启动后提示CreateProcess error206,通常我本地是将shorten command line改成如下就可以解决,但是今天遇到一个,无论这里怎么设置都是启动提示扩展名太长,经过一番处理问题终于解决,特此记录一下。…

基于51单片机的电子钟秒表LCD1602仿真设计( proteus仿真+程序+设计报告+原理图+讲解视频)

基于51单片机的电子钟秒表LCD1602仿真设计( proteus仿真程序设计报告原理图讲解视频) 这里写目录标题 1. 主要功能:2. 讲解视频:3. 仿真4. 程序代码5. 设计报告6. 原理图7. 设计资料内容清单&&下载链接 仿真图proteus7.8及以上 程序…

Compose 状态管理

文章目录 Compose 状态管理概述使用MutableStaterememberStatelessComposable & StatefulComposable状态提升rememberSaveable支持parceable不支持parceable 使用ViewModelViewModelProvider.Factory 使用Flow Compose 状态管理 概述 当应用程序的状态发生变化时&#xf…

第五章 TypeScript泛型的介绍和使用

文章目录 一、泛型初识泛型泛型用法 二、断言 一、泛型 初识泛型 一个函数,需要参数是 number 数据类型,返回值也是 number 数据类型 function fn(arg: number): number { // 代码忽略不计 }又一个函数,需要参数是 string 类型&#xff0…

docker安装Debian:11 freeswitch1.10.5

文章目录 一、生成一个镜像二、切换一个镜像源为阿里源三、安装一些相关依赖和freeswitch3.1第一步:安装freeswitch-mod和下载所需的依赖项3.2 设置密钥3.3 安装freeswitch所需的依赖项3.4 报错3.4.1 报错13.4.2 报错23.4.3 报错3 四、运行4.1 通话三十秒自动挂断 一…

Linux 第二十二章

🐶博主主页:ᰔᩚ. 一怀明月ꦿ ❤️‍🔥专栏系列:线性代数,C初学者入门训练,题解C,C的使用文章,「初学」C,linux 🔥座右铭:“不要等到什么都没有了…

嵌入式学习<1>:建立工程、GPIO

嵌入式学习_part1 本部分笔记用于学习记录,笔记源头 >>b站江科大_STM32入门教程 建立工程、GPIO 开发环境:keil MDK、STM32F103C8T6 1 )建立工程 (1)基于寄存器开发、基于标准库 或者 基于HAL库开发; &…

10种软件架构模式解析

1. 单体应用架构(Monolithic Architecture) 👌单体应用架构是最基本的架构模式,它将整个应用作为一个单独的部署单元。所有功能和模块都集成在一个应用中,易于开发和部署,但随着应用的增长,可维…

java.lang.NoSuchMethodException: com.ruoyi.web.controller.test.bean.HeadTeacher

软件开发过程中使用Java反射机制时遇到了下面的问题 com.ruoyi.web.controller.test.bean.HeadTeacher4b9af9a9 com.ruoyi.web.controller.test.bean.HeadTeacher4b9af9a9java.lang.NoSuchMethodException: com.ruoyi.web.controller.test.bean.HeadTeacher.<init>(java…

python判断大图中包含小图并输出位置总结

python判断大图中包含小图并输出位置总结 没啥可说的&#xff0c;项目遇到了就直接上代码&#xff0c;可以减轻劳动力&#xff0c;花最少得时间实现应用功能。 import cv2 # 读取大图片和小图片的路径 img_big cv2.imread(big_image.png) img_small cv2.imread(small_image…

【方法】如何创建RAR格式压缩文件?

为了方便存储或者传输文件&#xff0c;我们经常会把文件打包成不同格式的压缩包&#xff0c;那如果想创建的是RAR格式的压缩包&#xff0c;要如何做呢&#xff1f; RAR是WinRAR软件独有的压缩格式&#xff0c;所以我们可以通过WinRAR软件来创建RAR格式压缩包。下面分享两种创建…

视频素材哪个app好?8个视频素材库免费使用

视频内容已成为现代传播中不可或缺的一部分&#xff0c;具备卓越的视频素材对于提升任何媒体作品的质量和吸引力尤为关键。这里列举的一系列精挑细选的全球视频素材网站&#xff0c;旨在为您的商业广告、社交媒体更新或任何其他类型的视觉项目提供最佳支持。 1. 蛙学府&#x…

FileLink跨网文件交换,推动企业高效协作|半导体行业解决方案

随着信息技术的迅猛发展&#xff0c;全球信息产业已经迎来了前所未有的繁荣与变革。在这场科技革命中&#xff0c;半导体作为信息产业的基础与核心&#xff0c;其重要性日益凸显&#xff0c;半导体的应用场景和市场需求将进一步扩大。 然而&#xff0c;在这一繁荣的背后&#x…

OceanBase学习1:分布式数据库与集中式数据库的差异

目录 1. 传统集中式数据库 2. 数据库中间件的分库分表 3. 分布式数据库的基本特点及对比分析 4. OceanBase和传统数据库的对比 5. 小结 1. 传统集中式数据库 优点 成熟稳定:经过近40年的发展&#xff0c;应用到各行各业&#xff0c;产品技术非常成熟稳定行业适配性强:适配…

微软开发新模型;YouTube 推出新AI功能;可折叠iPhone 或发布?

微软或开发新模型与 Google、OpenAI 竞争 The Information 报道&#xff0c;微软正在训练一种新的 AI 大模型「MAI-1」&#xff0c;规模上足以与 Google、Anthropic 乃至 OpenAI 的先进模型抗衡。 据报道&#xff0c;这个 MAI-1 模型由微软聘请的 Inflection 前 CEO Mustafa S…