GD - GD32350R_EVAL - PWM实验和验证1

2024-08-31 14:36
文章标签 验证 实验 eval pwm gd gd32350r

本文主要是介绍GD - GD32350R_EVAL - PWM实验和验证1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • GD - GD32350R_EVAL - PWM实验和验证1
    • 概述
    • 笔记
    • 实验设计
    • 实验环境
    • GD32350R_EVAL 的硬件连接
    • 修改程序配置 - 只产生PWM波,不要CMP清除波形
    • TIMER0时钟设置
    • TIMER0的PWM设置参数设置
    • main()中PWM波形的开启代码
    • 示波器测量结果
    • 如果要产生4KHZ的PWM需要设置怎样的参数?
      • 尝试1 - 算一下时钟设置参数
      • 尝试1 - 产生代码,编译,验证
      • 错误分析原因
        • 可能1
        • 可能2
      • 尝试2 - 算一下PWM设置参数
      • 尝试2 - 产生代码,编译,验证
    • 总结
    • 疑问
    • @todo
    • 是否 “Clock division” 真的没用?
    • END

GD - GD32350R_EVAL - PWM实验和验证1

概述

看到 EmbeddedBuilder_v1.4.1.23782\examples\GD32F3x0\examples 有PWM的例子工程,想迁移到工程里面用。
想通过实验,来确定设置确定频率和占空比的方波,开始PWM, 调整占空比,停止PWM 这些知识点 应该怎么编程。

笔记

实验设计

在例子工程指定的PWM输出管脚和GND之间,连接示波器探头。
设置好PWM后,用按钮来关联PWM开始/占空比的调整/PWM结束,用示波器实时的测量PWM的频率和占空比。

实验环境

GD32350R_EVAL
DS1202ZE
EmbeddedBuilder
例子工程 EmbeddedBuilder_v1.4.1.23782\examples\GD32F3x0\examples\CMP\CMP_pwm_signal_control

GD32350R_EVAL 的硬件连接

CMP_pwm_signal_control 例子工程中使用PA8作为PWM输出。
查了一下原理图,PA8只引出到了输出端子上,不和其他元件连接,正好可以连接示波器探头。
现在选一下GND和PA8的连接端子,就可以开始连接示波器探头。

GD32F3x0_Demo_Suites_V2.3.0\GD32350R_EVAL_Demo_Suites\Docs\Schematic 有原理图和板子丝印。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
GND的端子用探头GND鳄鱼夹子夹住,离其他端子太近了,容易短路。
暂时用纸隔开。
问了厂家,是否探头GND端可以换成钩子配件。厂家说没有。
去x宝上找了一圈,厂家没骗人,其他家也没有卖的。
如果怕短路,又不想用纸隔开。只能先用杜邦线连上端子,再用探头GND端夹住。
最终,我用1 x 2.54 * 3P的插孔排,套在插针排上,这样用探头的GND夹子夹住就容易多了。
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

修改程序配置 - 只产生PWM波,不要CMP清除波形

官方例程自动停止PWM, 用的是光敏电阻,自己的实验用不到,去掉。
在这里插入图片描述

TIMER0时钟设置

在这里插入图片描述
时钟树配置后,给TIMER0的入口时钟CK_TIMER0 = 108MHZ

TIMER0的PWM设置参数设置

在这里插入图片描述

在这里插入图片描述
Prescaler Value(预分频值) = 107, 因为CK_TIMER0 = 108MHZ, 这里的值是108 MHZ / (107 + 1) = 1MHZ
也就是TIMER0分频后的实际时钟 CK_TIMER0_After_Prescaler = 1MHZ
Clock division = 1, 代表 CK_TIMER0_After_Prescaler 再分频 = CK_TIMER0_After_Prescaler_After_div = CK_TIMER0_After_Prescaler / Clock division = 1MHZ / 1 = 1MHZ

CK_TIMER0_After_Prescaler_After_div 就是最终被执行的TIMER0频率 = 1MHZ

Cunter auto reload value = 9999 代表时钟周期 = (9999 + 1) * (1 / 1MHZ)秒 = 10000 * 1 / 1000000 = 0.01秒 = 10ms
PWM的频率 = 1 / Cunter auto reload value = 1 / 0.01秒 = 100HZ

Compare value = 4999,意味着在一个PWM波周期内激活电平的占用时间 为 (4999 + 1)/ (Cunter auto reload value + 1) = 5000 / 10000 = 50%

对于一个PWM波,频率,占空比都有了,就确定了一个PWM波。

main()中PWM波形的开启代码

产生代码。
在主程序中,注释掉CMP开始的实现。
在这里插入图片描述

示波器测量结果

在这里插入图片描述
测量结果如下:

  • 垂直幅度 = 3.3V
  • 水平周期 = 10ms
  • 水平频率 = 100HZ
  • 占空比 = 50.20%

和上面代码设置的PWM周期相比,基本一致。

如果要产生4KHZ的PWM需要设置怎样的参数?

在这里插入图片描述
假设现在要驱动4KHZ的无源蜂鸣器,参考官方给的例子。尝试设置一下参数,再用示波器量一下,看看对不对?
就在官方的这个工程上将参数改一下,能产生4KHZ PWM波就行,然后在自己的工程上再重新配置。

尝试1 - 算一下时钟设置参数

为了验证"clock divsion", 将其改为2
手工先算一下,如下

Prescaler value = 107 = 108MHZ / (107 + 1) = 1MHZ
(时钟分频 clock division = 2, 试一下)div = 2 => TIMER0实际执行时钟 = 1MHZ / 2 = 500KHZ = 0.5MHZ
TIMER0实际执行时钟的周期 = 1 / (0.5MHZ * 1000000) = (1 / 500,000)s = 0.000002s = 2us 一个TIMER0时钟周期 = 2us
4KHZ的周期 = (1 / 4000)s = 0.00025s = 250 us
那么4KHZ的PWM波的时钟(TIMER0实际执行时钟的周期)个数 = 250us / 2us = 125=> 自动重装值  = (125 - 1= 124
驱动无源蜂鸣器的PWM波占空比要求是50%, 那么PWM波的比较值 = 125个 * 50% = 62.5= 63个。=> CMP比较值 = (63 - 1) = 62

按照手算的,来填写TIMER0的图形化配置参数
在这里插入图片描述

尝试1 - 产生代码,编译,验证

在这里插入图片描述
实际测量的频率和设想的大了一倍,实际周期比预想的小了一倍,占空比还可以。
看看参数哪里算错了。

错误分析原因

可能1

感觉是“Clock division”理解的不对。
从实际测量值来看,“Clock division”是对自动重装值的"细分", 有点像电机驱动芯片的细分功能一样。
虽然从TIMER0时钟看,只要数125个时钟,就能产生500KHZ的PWM波。
但是为了使自动重装值能数的数更多,可以"细分"
如果计算出的重装值为(125 - 1), “细分” = 2的话,那么自动重装值就应该在计算值的基础上x“细分值” = (125 * 2 - 1) = 250 - 1 = 249
同理,CMP值 = CMP值 x “细分值” = (63 * 2 - 1) = 126 - 1 = 125
在这里插入图片描述

可能2

可能是GD家的工具有bug, “Clock division”的值根本就没用到…
因为通过观察,不理会“Clock division”, 算出的PWM值就扩大一倍的,就是是对的。

尝试2 - 算一下PWM设置参数

在尝试一的基础上 + 错误分析原因, 手工算一下PWM参数
手工先算一下,如下

Prescaler value = 107 = 108MHZ / (107 + 1) = 1MHZ
不理会“Clock division” !!!
TIMER0实际执行时钟的周期 = (1 / 1MHZ)s = (1 / 1000,000)s = 0.000001s = 1us 一个TIMER0时钟周期 = 1us
4KHZ的周期 = (1 / 4000)s = 0.00025s = 250 us
那么4KHZ的PWM波的时钟(TIMER0实际执行时钟的周期)个数 = 250us / 1us = 250个计数 => 自动重装值  = (250 - 1= 249
驱动无源蜂鸣器的PWM波占空比要求是50%, 那么PWM波的比较值 = 250个 * 50% = 125个计数 => CMP比较值 = (125 - 1) = 124

按照手算的,来填写TIMER0的图形化配置参数
在这里插入图片描述

尝试2 - 产生代码,编译,验证

在这里插入图片描述
这回对了。
频率,占空比都ok。

总结

和时序相关的操作,如果不用示波器实际看看,心里真没底,不知道弄得对不对。
其实就是官方根据特定开发板给出的例程,如果不拿对应的官方开发板跑起来 + 用示波器实际确认一下波形,也不能肯定官方例程就是对的(只能选择信任官方的例程)。

疑问

在Pinout配置TIMER0时,时钟源是禁止的。那禁止了时钟源,CK_TIMER0的时钟源是谁?
感觉GD家的软件现在还有不少疑似bug, 不过当前版本不影响用。
使用HAL库配置寄存器时,可以比使用固件库配置的更细致。
在这里插入图片描述

@todo

使用PWM时,可以不停止PWM波,直接可以改占空比。
官方这个例子是用软件来启动PWM, 用CMP从内部连接到TIMER0的PWM通道停止寄存器。
实际用PWM时,需要自己从逻辑上启停PWM/调整PWM占空比, 应该是在另外一个定时器中操作PWM。
将EmbeddedBuilder官方HAL库例子中,所有关于PWM的例子都看完,就知道PWM操作细节的玩法了。

是否 “Clock division” 真的没用?

将实验工程拷贝了一份,将 “Clock division” 改为4,重新编译,单步状态跑起来,用示波器看,还是4KHZ/50%占空比。
比较代码,确实有区别,可以看到“Clock division”为4,原始工程 “Clock division”为2,但是效果一样。。。
这如果是没有图形化配置,谁能知道寄存器配置还能有这区别?
在这里插入图片描述
从实验结果上看,“Clock division”是没用的,1/2/4效果都一样。不影响TIMERX时钟最终的执行频率。
只有CK_TIMEX和Prescaler Value(预分频值) 会影响TIMERX时钟最终的执行频率。

END

这篇关于GD - GD32350R_EVAL - PWM实验和验证1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1124179

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

C++ | Leetcode C++题解之第393题UTF-8编码验证

题目: 题解: class Solution {public:static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num &

C语言 | Leetcode C语言题解之第393题UTF-8编码验证

题目: 题解: static const int MASK1 = 1 << 7;static const int MASK2 = (1 << 7) + (1 << 6);bool isValid(int num) {return (num & MASK2) == MASK1;}int getBytes(int num) {if ((num & MASK1) == 0) {return

easyui同时验证账户格式和ajax是否存在

accountName: {validator: function (value, param) {if (!/^[a-zA-Z][a-zA-Z0-9_]{3,15}$/i.test(value)) {$.fn.validatebox.defaults.rules.accountName.message = '账户名称不合法(字母开头,允许4-16字节,允许字母数字下划线)';return fal

easyui 验证下拉菜单select

validatebox.js中添加以下方法: selectRequired: {validator: function (value) {if (value == "" || value.indexOf('请选择') >= 0 || value.indexOf('全部') >= 0) {return false;}else {return true;}},message: '该下拉框为必选项'}

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

web群集--nginx配置文件location匹配符的优先级顺序详解及验证

文章目录 前言优先级顺序优先级顺序(详解)1. 精确匹配(Exact Match)2. 正则表达式匹配(Regex Match)3. 前缀匹配(Prefix Match) 匹配规则的综合应用验证优先级 前言 location的作用 在 NGINX 中,location 指令用于定义如何处理特定的请求 URI。由于网站往往需要不同的处理方式来适应各种请求,NGINX 提供了多种匹

HNU-2023电路与电子学-实验3

写在前面: 一、实验目的 1.了解简易模型机的内部结构和工作原理。 2.分析模型机的功能,设计 8 重 3-1 多路复用器。 3.分析模型机的功能,设计 8 重 2-1 多路复用器。 4.分析模型机的工作原理,设计模型机控制信号产生逻辑。 二、实验内容 1.用 VERILOG 语言设计模型机的 8 重 3-1 多路复用器; 2.用 VERILOG 语言设计模型机的 8 重 2-1 多

UMI复现代码运行逻辑全流程(一)——eval_real.py(尚在更新)

一、文件夹功能解析 全文件夹如下 其中,核心文件作用为: diffusion_policy:扩散策略核心文件夹,包含了众多模型及基础库 example:标定及配置文件 scripts/scripts_real:测试脚本文件,区别在于前者倾向于单体运行,后者为整体运行 scripts_slam_pipeline:orb_slam3运行全部文件 umi:核心交互文件夹,作用在于构建真

React 笔记 父子组件传值 | 父组件调用子组件数据 | defaultProps | propsType合法性验证

1.通过props实现父组件像子组件传值 、方法、甚至整个父组件 传递整个父组件则   [变量名]={this} import Header from "./Header"render(){return(<Header msg={"我是props传递的数据"}/>)} import React,{Component} from "react";class Header extends